/* ========== BUTTONS ========== */
.btn {
  padding: 0.65rem 1.4rem;
  border-radius: 12px;
  border: 1px solid rgba(227, 181, 74, 0.55);
  background: rgba(255, 255, 255, 0.04);
  color: var(--gold-strong);
  font-size: 1rem;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s, transform 0.1s, box-shadow 0.15s;
  min-height: 44px;
  min-width: 44px;
}

.btn:hover { background: rgba(227, 181, 74, 0.14); }
.btn:active { transform: scale(0.97); }

.btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
  pointer-events: none;
}

.btn-primary {
  background: var(--gold);
  color: #1b1405;
  border-color: var(--gold);
  font-weight: 800;
  box-shadow: 0 6px 16px rgba(227, 181, 74, 0.25);
}

.btn-primary:hover,
.btn-primary:active { background: var(--gold-strong); }

/* Build 24: one call-to-action size, as in the app: 52px tall, the label at
   17px (never smaller than the body text around it); 48px at the table. */
.btn-primary { min-height: 52px; font-size: 1.0625rem; font-weight: 700; }
.center-panel .btn, .dialog-actions .btn { min-height: 48px; }

.btn-secondary {
  border-color: var(--panel-border);
  color: var(--text);
}

.btn-secondary:hover { background: rgba(255, 255, 255, 0.08); }

.btn-danger {
  background: #b3372b;
  border-color: #d2503f;
  color: #fff;
}

.btn-danger:hover { background: #c4412f; }

.btn-danger-outline {
  border-color: rgba(239, 125, 111, 0.6);
  color: var(--bad);
}

.btn-danger-outline:hover { background: rgba(239, 125, 111, 0.12); }

/* ========== TOASTS / ERRORS ========== */
.toast {
  position: fixed;
  /* Above the fixed hand rail (--hand-h is measured by public/clearance.js). */
  bottom: calc(var(--hand-h) + var(--space-3));
  left: 50%;
  transform: translateX(-50%);
  color: white;
  padding: 0.75rem 1.5rem;
  border-radius: 8px;
  font-size: 0.9rem;
  z-index: 1000;
  animation: toastIn 0.3s ease, toastOut 0.3s ease 2.7s forwards;
  box-shadow: 0 4px 16px rgba(0,0,0,0.6);
  font-weight: 500;
  text-align: center;
  pointer-events: none;
}

.toast.toast-success {
  background: #1b5e20;
  border: 1px solid #4caf50;
  box-shadow: 0 4px 16px rgba(0,0,0,0.6), 0 0 10px rgba(76,175,80,0.4);
}

.toast.toast-error {
  background: #b71c1c;
  border: 1px solid #e53935;
  box-shadow: 0 4px 16px rgba(0,0,0,0.6), 0 0 10px rgba(229,57,53,0.4);
}

.toast.toast-info {
  background: #0d47a1;
  border: 1px solid #2196f3;
  box-shadow: 0 4px 16px rgba(0,0,0,0.6), 0 0 10px rgba(33,150,243,0.4);
}

@keyframes toastIn {
  from { opacity: 0; transform: translateX(-50%) translateY(10px); }
  to { opacity: 1; transform: translateX(-50%) translateY(0); }
}

@keyframes toastOut {
  from { opacity: 1; }
  to { opacity: 0; }
}

/* ========== RECONNECTING BANNER ========== */
.reconnecting-banner {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  background: #ffc107;
  color: #333;
  text-align: center;
  padding: 0.5rem;
  font-weight: bold;
  z-index: 1001;
  animation: pulse 1s ease-in-out infinite alternate;
}

@keyframes pulse {
  from { opacity: 0.7; }
  to { opacity: 1; }
}

/* ========== MOVED BANNER (build 29, public/moved.js) ========== */
/* "Pinochle has a new address": a slim bar fixed to the top of the old website address, with Take Me There and Not
   Now. It makes its own room: moved.js sets --moved-banner-h to the bar's height and body.has-moved-banner pushes
   the page down by it (and shortens #app by the same amount, so a page that fitted still fits). At a table the bar
   steps aside and gives the room back: it never sits over the cards. Same tokens as the rest of the page, which has
   one (dark) look; the top padding keeps it clear of a notch. */
.moved-banner {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: var(--z-banner);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding:
    calc(var(--space-2) + env(safe-area-inset-top, 0px))
    calc(var(--space-3) + env(safe-area-inset-right, 0px))
    var(--space-2)
    calc(var(--space-3) + env(safe-area-inset-left, 0px));
  background: var(--panel-2);
  border-bottom: 1px solid rgba(227, 181, 74, 0.55);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.35);
  color: var(--text);
}
.moved-banner-text { font-size: 0.875rem; line-height: 1.35; }
.moved-banner-text strong { color: var(--gold-strong); font-weight: 700; overflow-wrap: anywhere; }
.moved-banner-actions { display: flex; gap: var(--space-2); }
.moved-banner .btn { flex: 1 1 0; min-height: 44px; padding: 0.4rem 0.9rem; font-size: 0.9375rem; box-shadow: none; }
@media (min-width: 640px) {
  .moved-banner { flex-direction: row; align-items: center; justify-content: center; gap: var(--space-4); }
  .moved-banner-text { max-width: 44rem; }
  .moved-banner .btn { flex: 0 0 auto; }
}
body.has-moved-banner { padding-top: var(--moved-banner-h, 0px); }
body.has-moved-banner #app {
  min-height: calc(100vh - var(--moved-banner-h, 0px));
  min-height: calc(100dvh - var(--moved-banner-h, 0px));
}
body.at-table .moved-banner { display: none; }
body.at-table.has-moved-banner { padding-top: 0; }
body.at-table.has-moved-banner #app { min-height: 100dvh; }

/* "Bring your profile here?" on the new address (public/moved.js): a modal question before anything is applied or
   sent. Two buttons, both 44 px or more, the safe one never smaller than the other. */
.moved-dialog-backdrop {
  position: fixed;
  inset: 0;
  z-index: var(--z-banner);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: calc(var(--space-4) + env(safe-area-inset-top, 0px)) calc(var(--space-4) + env(safe-area-inset-right, 0px)) calc(var(--space-4) + env(safe-area-inset-bottom, 0px)) calc(var(--space-4) + env(safe-area-inset-left, 0px));
  background: rgba(0, 0, 0, 0.66);
}
.moved-dialog {
  width: 100%;
  max-width: 24rem;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-5) var(--space-4) var(--space-4);
  border-radius: var(--radius-xl);
  background: var(--panel-2);
  border: 1px solid rgba(227, 181, 74, 0.45);
  box-shadow: var(--shadow-lg);
  color: var(--text);
}
.moved-dialog:focus { outline: none; }
.moved-dialog-title { font-size: 1.25rem; line-height: 1.25; font-weight: 800; color: var(--gold-strong); }
.moved-dialog-text { font-size: 0.9375rem; line-height: 1.45; color: var(--text); }
.moved-dialog-actions { display: flex; flex-direction: column; gap: var(--space-2); margin-top: var(--space-2); }
.moved-dialog .btn { min-height: 48px; width: 100%; }

/* ========== MELD CHEAT SHEET MODAL ========== */
.meld-guide-modal,
.rules-modal {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.75);
  backdrop-filter: blur(4px);
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  overscroll-behavior: contain;
}

.meld-guide-content {
  background: #1a472a;
  border: 2px solid var(--gold);
  border-radius: 12px;
  max-width: 480px;
  width: 100%;
  max-height: 85vh;
  overflow-y: auto;
  overscroll-behavior: contain;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6);
  padding: 16px;
}

.meld-guide-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-bottom: 1px solid rgba(218, 165, 32, 0.3);
  padding-bottom: 8px;
  margin-bottom: 12px;
}

.meld-guide-header h3 {
  margin: 0;
  color: var(--gold);
  font-size: 1.1rem;
}

.meld-guide-close {
  /* A 44 px hit area round the ✕ (R-017), as the app's Done. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  margin: -8px -10px -8px 0;
  padding: 0;
  border-radius: 10px;
  background: transparent;
  border: none;
  color: var(--text);
  font-size: 1.2rem;
  cursor: pointer;
  opacity: 0.7;
}

.meld-guide-close:hover {
  opacity: 1;
}

.meld-guide-section {
  margin-bottom: 14px;
}

.meld-guide-section h4 {
  margin: 0 0 6px 0;
  color: #e8a830;
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.meld-guide-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.82rem;
}

.meld-guide-table td {
  padding: 4px 6px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.meld-guide-table td:last-child {
  text-align: right;
  color: var(--gold);
  white-space: nowrap;
}

/* ========== MELD CHART (public/meld-chart.js) ========== */
.meld-chart { max-width: 520px; padding: 18px 18px 14px; }
.meld-chart .meld-guide-header h3 { font-size: 1.25rem; letter-spacing: 0.3px; }
.meld-chart-sub { margin: 0 0 12px; font-size: 0.85rem; color: var(--text-dim); display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.meld-chart-group { margin-bottom: 16px; }
.meld-chart-group h4 { margin: 0 0 2px; color: var(--gold); font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.8px; }
.meld-chart-note { margin: 0 0 6px; font-size: 0.78rem; color: var(--text-dim); }
.meld-chart-table { width: 100%; table-layout: fixed; border-collapse: separate; border-spacing: 0; font-variant-numeric: tabular-nums; }
.meld-chart-table thead th { font-size: var(--text-micro, 0.6875rem); font-weight: 600; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.4px; text-align: right; padding: 0 6px 4px; }
.meld-chart-table thead th:first-child { width: 46%; }
.meld-chart-table tbody th { text-align: left; font-weight: 600; padding: 8px 6px 8px 0; }
.meld-chart-table tbody td { text-align: right; padding: 8px 6px; font-size: 0.92rem; color: var(--text); }
.meld-chart-table tbody tr + tr > * { border-top: 1px solid rgba(255, 255, 255, 0.08); }
.meld-chart-table td.mc-single { color: var(--gold-strong); font-weight: 700; font-size: 1.05rem; }
.mc-name { font-size: 0.95rem; color: var(--text); }
.mc-detail { font-weight: 400; font-size: 0.75rem; color: var(--text-dim); }
.mc-cards { display: flex; gap: 3px; margin-top: 4px; flex-wrap: wrap; }
.mc-chip {
  display: inline-flex; align-items: center; gap: 1px;
  min-width: 26px; height: 22px; padding: 0 5px; border-radius: 5px;
  background: #fbf8f0; color: #1b1b1b; font-size: 0.74rem; font-weight: 700; line-height: 1;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
}
.mc-chip b { font-size: 0.82rem; }
.mc-chip.suit-H, .mc-chip.suit-D { color: #c62828; }
.mc-chip.is-trump { outline: 2px solid var(--gold); outline-offset: -1px; }
/* A deep gold on the cream chip: 5.0:1 (N-021; #b8860b was 3.07:1, and the
   felt's #e3b54a would be 1.8:1 on cream). */
.mc-chip.is-trump:not([class*="suit-"]) b { color: #8a6500; }
body.four-color-deck .mc-chip.suit-D { color: #1565c0; }
body.four-color-deck .mc-chip.suit-C { color: #1b7a2b; }
.meld-chart-notes { margin: 4px 0 0; padding: 10px 12px 10px 26px; border-radius: 10px; background: rgba(255, 255, 255, 0.05); font-size: 0.8rem; color: var(--text-dim); line-height: 1.45; }
.meld-chart-notes li + li { margin-top: 4px; }
.meld-chart-link { display: block; margin: 10px auto 0; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
@media (max-width: 420px) {
  .meld-chart { padding: 14px 12px 12px; }
  .meld-chart-table thead th { font-size: var(--text-micro, 0.6875rem); padding: 0 3px 4px; }
  .meld-chart-table tbody td { padding: 8px 3px; font-size: 0.85rem; }
  .meld-chart-table td.mc-single { font-size: 0.95rem; }
  .mc-chip { min-width: 22px; height: 20px; padding: 0 3px; font-size: var(--text-micro, 0.6875rem); }
}

/* ========== SEND FEEDBACK (showFeedbackDialog) ========== */
.feedback-sub { margin: 0 0 12px; font-size: 0.85rem; color: var(--text-dim); }
.feedback-kinds { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 10px; }
.feedback-kind { border: 1px solid rgba(255, 255, 255, 0.18); background: transparent; color: var(--text); border-radius: 999px; padding: 6px 12px; min-height: 44px; font-size: 0.82rem; cursor: pointer; }
.feedback-kind.is-on { border-color: var(--gold); background: rgba(227, 181, 74, 0.16); color: var(--gold-strong); font-weight: 600; }
.feedback-text, .feedback-contact { width: 100%; box-sizing: border-box; border-radius: 8px; border: 1px solid rgba(255, 255, 255, 0.18); background: rgba(0, 0, 0, 0.3); color: var(--text); font: inherit; font-size: 0.95rem; padding: 10px 12px; margin-bottom: 8px; }
.feedback-text { resize: vertical; min-height: 110px; }
.feedback-text:focus, .feedback-contact:focus { outline: 2px solid var(--gold); outline-offset: 0; }
.feedback-count { margin: 0 0 6px; min-height: 1em; font-size: 0.78rem; color: var(--text-dim); text-align: right; }
.feedback-count.is-over { color: var(--bad); text-align: left; font-weight: 600; }
.feedback-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 4px; }
.feedback-status { margin: 8px 0 0; min-height: 1em; font-size: 0.82rem; color: var(--text-dim); }
.landing-feedback { display: block; margin: 16px auto 8px; }

/* ========== REDUCED MOTION (F-M7) ========== */
/* Disable all infinite pulses/bounces for users who prefer reduced motion.
   Target the consuming selectors (not just keyframes) and use !important so
   the inline animation style on .trick-complete-indicator (render.js) is
   overridden without a JS change. */
@media (prefers-reduced-motion: reduce) {
  .player-zone.current-player .seat-plate, /* seat-turn */
  .table-swap-hint,                 /* prompt-pulse */
  .table-seat.table-seat-selected,  /* pulse-seat */
  .reconnecting-banner,             /* pulse */
  .trick-complete-indicator         /* pulse (inline style) */ {
    animation: none !important;
  }
}

/* ========== TAP HIGHLIGHT & FOCUS VISIBILITY (F-M11) ========== */
button,
a,
.card,
.table-seat,
.icon-btn,
.menu-item,
.table-talk-send-btn,
.teach-toggle,
.trick-history-title,
.btn-sub-bot,
.btn-leave-lobby {
  -webkit-tap-highlight-color: transparent;
}

:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}
/* Focus a dialog put on its first control after a tap: no ring (R-078). */
.is-quiet-focus:focus-visible { outline: none; }

/* ========== MOBILE RESPONSIVE (extracted per-component from the style.css mega-block) ========== */
@media (max-width: 600px), (max-height: 500px) {
  .btn {
    padding: 0.5rem 1rem;
    font-size: 0.9rem;
    min-height: 44px;
    width: 100%;
  }
  .btn-primary { font-size: 1.0625rem; min-height: 52px; }
  .center-panel .btn, .dialog-actions .btn { min-height: 48px; }

}

/* ========== RULES & STRATEGY (same chrome as the meld chart) ========== */
.rules-content { max-width: 560px; line-height: 1.45; }
.rules-content .rules-section { margin-bottom: 14px; }
.rules-content h4 { margin: 0 0 4px; color: var(--gold); font-size: 1rem; }
.rules-content p { margin: 0 0 6px; }
.rules-content ul { margin: 0; padding-left: 1.2em; }
.rules-content li { margin: 3px 0; }
.rules-content .rules-strategy { border-top: 1px solid rgba(218, 165, 32, 0.3); padding-top: 10px; }
.rules-content .rules-footer { margin-top: 8px; font-style: italic; opacity: 0.8; }
.teach-more { margin-top: 8px; opacity: 0.85; font-size: 0.9em; }

/* ========== BUILD 5 EXTRAS: review, stats, summary links ========== */
.review-links {
  display: flex;
  gap: 1.25rem;
  justify-content: center;
  flex-wrap: wrap;
  margin-top: 10px;
}
.review-links:empty { display: none; }
.review-step-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 6px; }
.review-step-count { opacity: 0.7; font-size: 0.9em; }
.review-slider { width: 100%; margin: 4px 0 10px; }
.review-step-body { min-height: 9rem; }
.review-hand { margin-bottom: 10px; }
.review-who { font-weight: 600; margin-bottom: 3px; }
.review-cards { display: flex; flex-wrap: wrap; gap: 3px; }
.review-card {
  display: inline-block;
  min-width: 2.2em;
  padding: 1px 4px;
  border-radius: 4px;
  background: #fffdf8;
  color: #111;
  font-weight: 700;
  text-align: center;
  line-height: 1.5;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15);
}
.review-card.is-red { color: var(--red); }
.review-list { margin: 0 0 8px; padding-left: 1.2em; }
.review-list li { margin: 2px 0; }
.four-color-deck .review-card.suit-D { color: #1565c0; }
/* Share a Hand (build 28, docs/SHARE_HAND.md): the preview of the picture, 4:5, with the page's own sizes. */
.share-hand-stage { display: flex; justify-content: center; min-height: 6rem; margin-bottom: 10px; }
.share-hand-picture {
  display: block;
  width: 100%;
  max-width: 360px;
  height: auto;
  aspect-ratio: 4 / 5;
  border-radius: 12px;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.35);
}
.share-hand-making { margin: 2rem 0; opacity: 0.75; text-align: center; }
.share-hand-text { text-align: center; margin: 4px 0 12px; }
.share-hand-actions { justify-content: center; flex-wrap: wrap; }
.share-hand-caption { text-align: center; margin-top: 12px; }
.four-color-deck .review-card.suit-C { color: #2e7d32; }
.stats-table { width: 100%; }
.stats-table td:last-child { text-align: right; }
.toolbar-undo { font-weight: 600; }
/* The review keeps one height from step to step, so Back / Next stay under
   the thumb; a long step (the deal) scrolls inside. */
.review-modal .meld-guide-content {
  height: min(85vh, 760px);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.review-modal .meld-guide-body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.review-modal .review-step-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.review-modal .dialog-actions { margin-top: 10px; flex-shrink: 0; }

/* ========== SETTINGS (website) ==========
   One sheet of labelled switches, grouped like the app's Settings. */
.settings-sheet { width: min(440px, 100%); max-height: min(86vh, 720px); overflow-y: auto; }
.settings-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.settings-head h3 { margin: 0; color: var(--text); font-size: 1.2rem; }
.settings-done { flex: none; width: auto; min-height: 36px; padding: 4px 16px; margin: 0; }
.settings-group { margin-top: 14px; }
.settings-group h4 {
  margin: 0 0 6px;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.settings-group > .settings-row + .settings-row { border-top: 1px solid var(--panel-border); }
.settings-group { border-radius: 14px; }
.settings-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  min-height: 52px;
  padding: 8px 12px;
  background: rgba(255, 255, 255, 0.03);
  border: 0;
  color: var(--text);
  font: inherit;
  text-align: left;
}
.settings-group h4 + .settings-row { border-radius: 12px 12px 0 0; }
.settings-group > .settings-row:last-child { border-radius: 0 0 12px 12px; }
.settings-group h4 + .settings-row:last-child { border-radius: 12px; }
button.settings-row { cursor: pointer; }
button.settings-row:hover { background: rgba(255, 255, 255, 0.06); }
.settings-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.settings-label { font-weight: 600; }
.settings-caption { font-size: 0.78rem; color: var(--text-dim); }
.settings-value { color: var(--text-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 55%; }
/* A value that is a short list wraps to a second line, never cut (N-019). */
.settings-value.is-wrap { white-space: normal; overflow: visible; text-overflow: clip; text-align: right; }
.settings-toggle {
  flex: none;
  position: relative;
  width: 44px;
  height: 26px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.16);
  transition: background 0.2s ease;
}
.settings-thumb {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: #fff;
  transition: transform 0.2s ease;
}
.settings-switch[aria-checked="true"] .settings-toggle { background: var(--gold); }
.settings-switch[aria-checked="true"] .settings-thumb { transform: translateX(18px); }
/* A switch that does nothing here (Teach Me for someone watching): dimmed, with its reason as the caption. */
.settings-switch:disabled { opacity: 0.6; cursor: default; }
.settings-switch:disabled:hover { background: rgba(255, 255, 255, 0.04); }
.settings-seg {
  display: inline-flex;
  flex: none;
  padding: 2px;
  border-radius: 10px;
  background: rgba(0, 0, 0, 0.3);
}
.settings-seg button {
  min-height: 44px;
  padding: 4px 10px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--text-dim);
  font: inherit;
  font-size: 0.85rem;
  cursor: pointer;
}
.settings-seg button.is-on { background: var(--gold); color: #1a1a1a; font-weight: 700; }
@media (prefers-reduced-motion: reduce) {
  .settings-toggle, .settings-thumb { transition: none; }
}

.menu-divider { height: 1px; margin: 4px 8px; background: var(--panel-border); }

/* Luke: a wider space between two suits of the same color in the hand, so
   diamonds aren't read as hearts or clubs as spades (hand.js adds it only
   when the colors match and four-color suits are off). */
.suit-gap.same-color { flex: 0 1 36px; min-width: 16px; }
@media (max-width: 600px) {
  .suit-gap.same-color { flex-basis: 18px; min-width: 10px; }
}

/* Teach Me: the card Luke's computer would play (never chosen for you). */
.hand .card.coach-suggested {
  outline: 3px dashed var(--gold);
  outline-offset: -3px;
}
.hand .card.coach-suggested::after {
  content: '🎓';
  position: absolute;
  top: -12px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 14px;
  line-height: 1;
  pointer-events: none;
}

/* Build 28 (ISSUES row 114): a card held for your turn. A quiet raise (40 percent of the chosen card's
   22 px, so 9 px) and a thin gold outline inside the edge; no glow, no Play button, and nothing plays by
   itself. Every card can be held alike, so nothing here says which could be played (docs/TABLE_LAYOUT.md,
   "holding a card before your turn"). The chosen card's own rules win when it is both. */
.hand .card.holdable { cursor: pointer; touch-action: manipulation; }
.hand .card.held:not(.selected) {
  transform: translateY(-9px);
  outline: 1.5px solid #E3B54A;
  outline-offset: -1.5px;
  transition: transform 0.15s var(--ease-out), outline-color 0.15s;
}
@media (prefers-reduced-motion: reduce) {
  .hand .card.held { transition: none !important; }
}

/* Play with anyone (build 12): public tables on the landing page. */
.landing-public .public-list { display: flex; flex-direction: column; gap: 8px; margin: 10px 0 4px; }
.public-row { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; justify-content: space-between; padding: 8px 10px; border-radius: 10px; background: var(--panel2, rgba(255,255,255,0.05)); }
/* Build 28: width auto too. On a phone the mobile rule `.btn { width: 100% }` made every button in a row (Cancel, Join, Add, Invite) as wide as the row, and the name beside it a letter wide. */
.public-row .btn { flex: none; width: auto; margin-left: auto; }
/* At large text the button drops under the words instead of squeezing them to a letter a line (checked at 200%). */
.public-row-text { min-width: 0; flex: 1 1 8em; overflow-wrap: anywhere; }
.friends-body .public-row-text { text-align: left; }
.public-tag { font-size: 0.72rem; padding: 1px 6px; border-radius: 99px; border: 1px solid var(--gold); color: var(--gold); }
.terms-card ul { padding-left: 1.2em; margin: 8px 0; }
.terms-card li { margin: 4px 0; }
.blocked-list { display: flex; flex-direction: column; gap: 6px; }

/* Friends (build 13). */
.friends-body { display: flex; flex-direction: column; gap: 8px; }
.friends-code { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.friend-code { font-family: ui-monospace, Menlo, monospace; font-size: 1.15rem; letter-spacing: 0.12em; color: var(--gold); }
.friend-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--text-dim); margin-right: 6px; opacity: 0.5; }
.friend-dot.is-online { background: #4cd964; opacity: 1; }
.friend-invite { position: fixed; left: 50%; bottom: 16px; transform: translateX(-50%); z-index: 3000; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; justify-content: center; max-width: calc(100vw - 32px); padding: 10px 14px; border-radius: 12px; background: var(--panel, #1f2a22); border: 1px solid var(--gold); box-shadow: 0 6px 24px rgba(0,0,0,0.4); }

/* Build 28 (rows 103 and 112): the one Invite button, a pill with its state in words and a caption under the name
   (public/invite-state.js; the app's InviteButton draws the same states). 44 px target; never dimmed to look disabled. */
.invite-pill { display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-height: 44px; min-width: 44px; padding: 0 14px; border-radius: 22px; white-space: nowrap; }
.invite-pill[data-state="invited"], .invite-pill[data-state="limited"] { background: rgba(227, 181, 74, 0.16); border-color: var(--gold); }
.invite-pill[data-state="sending"] { border-color: rgba(227, 181, 74, 0.35); cursor: progress; }
.invite-pill[data-state="failed"] { color: var(--bad); border-color: var(--bad); }
.invite-pill[data-state="here"] { border-color: transparent; background: none; color: var(--text-dim); cursor: default; }
.invite-check { font-weight: 800; }
.invite-spinner { width: 12px; height: 12px; border-radius: 50%; border: 2px solid rgba(227, 181, 74, 0.35); border-top-color: var(--gold); animation: invite-spin 0.8s linear infinite; }
@keyframes invite-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .invite-spinner { animation: none; border-top-color: rgba(227, 181, 74, 0.35); } }
.invite-caption { color: var(--gold); }
.invite-caption[data-state="failed"] { color: var(--bad); }
.friends-requested { color: var(--text-dim); font-weight: 600; min-height: 44px; display: inline-flex; align-items: center; }
.friend-invite.is-pulsing { animation: invite-pulse 0.9s ease-out 1; }
@keyframes invite-pulse { 0% { box-shadow: 0 0 0 0 rgba(227, 181, 74, 0.7); } 100% { box-shadow: 0 0 0 14px rgba(227, 181, 74, 0); } }
@media (prefers-reduced-motion: reduce) { .friend-invite.is-pulsing { animation: none; } }
.invite-dialog .public-row + .public-row { margin-top: 6px; }

/* Avatar picker (build 19) */
.avatar-sheet { max-height: 85vh; display: flex; flex-direction: column; }
.avatar-tabs { display: flex; gap: 6px; overflow-x: auto; padding: 4px 0 10px; flex: none; }
.avatar-tabs button { flex: none; min-height: 44px; padding: 0 14px; border-radius: 22px; border: 1px solid var(--panel-border); background: rgba(255, 255, 255, 0.04); color: var(--text); font: inherit; cursor: pointer; }
.avatar-tabs button.is-on { background: var(--gold); color: #10241a; border-color: var(--gold); font-weight: 700; }
.avatar-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(48px, 1fr)); gap: 6px; overflow-y: auto; padding: 2px; min-height: 0; }
.avatar-cell { min-width: 44px; min-height: 44px; font-size: 1.6rem; line-height: 1; border-radius: 12px; border: 2px solid transparent; background: rgba(255, 255, 255, 0.05); cursor: pointer; }
.avatar-cell:hover { background: rgba(255, 255, 255, 0.12); }
.avatar-cell.is-on { border-color: var(--gold); background: rgba(255, 255, 255, 0.14); }
.avatar-btn { margin-top: 6px; }

/* Rules & Strategy: Family / Book / Tournament fill the row, as in the app (R-079). */
.rules-content .rules-set-picker { display: flex; align-self: stretch; width: 100%; box-sizing: border-box; }
.rules-content .rules-set-picker button { flex: 1 1 0; }

/* ---- Tap targets, 44 px everywhere (DESIGN_REVIEW_B24_PASS2 N-007, N-008)
   Controls that sit in a tight row keep their look and take a 44 px hit
   area through padding with a matching negative margin, so nothing around
   them moves. ---- */
.bid-signal-select { min-height: 44px; }
button.meld-seat-head { min-height: 44px; margin-block: -10px; }
.promote-seat-select { min-height: 44px; }
.status-dialog-close { min-height: 44px; min-width: 44px; }
.chat-msg-menu-btn,
.chat-msg-menu-btn:is(:hover, :focus-visible) { width: 44px; height: 44px; margin: -13px -11px -13px -7px; }
.trick-history-title { min-height: 44px; }
details > summary { min-height: 44px; box-sizing: border-box; padding-block: 12px; cursor: pointer; }
/* The table's buttons, chips and tabs: 44 px tall (the app's are 44). */
.meld-board .meld-actions .btn,
.hand-play-btn,
.chat-chip,
.sheet-tips .chat-switch,
.settings-done,
.seat-action,
.room-head .room-code-value { min-height: 44px; }
.player-play-btn { min-height: 44px; margin-block: -4px; }
@media (max-width: 600px), (max-height: 500px) { .player-play-btn { margin-block: -7px; } }
/* The meld board's Us / Them tabs: 44 px targets in the board's 34 px row. */
.meld-page-tab { min-height: 44px; margin-block: -5px; }
/* A plate that opens that seat's meld is a button: 44 px tall. */
.seat-plate[role="button"] { min-height: 44px; }
/* Your own avatar in the lobby (tap to change it): a 44 px circle; the
   negative margin keeps the seat row as it was. */
button.seat-avatar.is-mine { width: 44px; height: 44px; margin: -4px; }
button.seat-avatar.is-mine::after { content: none; }
