/* ==========================================================================
   Russian Hand - UI layer additions (src/ui/UIController.js and friends)
   Mobile-first. Loaded after style.css (UIController also links it itself if the page does not).
   Components that only exist because of the UI layer (modal a11y, confirm dialog, connection banner,
   toast kinds, match summary, meld/joker states). Layout, drag feedback, the wide-layout hand and
   prefers-reduced-motion live in style.css.
   ========================================================================== */

/* The hidden attribute must win over component display rules (e.g. .btn-action { display: inline-flex }). */
[hidden] {
  display: none !important;
}

/* ---- Modals: closed dialogs leave the tab order / accessibility tree; dialogs get real tap targets ---- */
.modal {
  visibility: hidden;
  transition: opacity 0.25s ease, visibility 0s linear 0.25s;
}

.modal.active {
  visibility: visible;
  transition-delay: 0s;
}

.modal-close {
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 10px;
}

/* Round summary / match over cannot be dismissed with the backdrop, Escape or the close button. */
.modal-persistent .modal-close {
  display: none;
}

.modal :focus-visible,
.net-banner :focus-visible {
  outline: 2px solid var(--gold-accent, #f59e0b);
  outline-offset: 2px;
}

.modal-actions-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: center;
  margin-top: 14px;
}

.modal-actions-bar .btn-action {
  flex: 1 1 140px;
  min-height: 44px;
  justify-content: center;
}

/* ---- In-app confirm dialog (replaces window.confirm) ---- */
.ui-confirm {
  z-index: 320;
}

.ui-confirm-content {
  max-width: 420px;
}

.ui-confirm-message {
  margin-bottom: 4px;
  line-height: 1.6;
  overflow-wrap: anywhere;
}

/* ---- Connection banner ---- */
.net-banner {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 99998;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 10px;
  padding: calc(6px + env(safe-area-inset-top, 0px)) 14px 6px;
  font-size: 0.85rem;
  font-weight: 700;
  color: #fff;
  background: rgba(15, 23, 42, 0.97);
  border-bottom: 2px solid rgba(245, 158, 11, 0.25);
  animation: netBannerIn 0.25s ease;
}

.net-banner--busy { border-bottom-color: #3b82f6; }
.net-banner--warn { border-bottom-color: #f59e0b; }
.net-banner--ok { border-bottom-color: #10b981; }
.net-banner--error {
  border-bottom-color: #ef4444;
  background: rgba(127, 29, 29, 0.97);
}

.net-banner-dot {
  width: 10px;
  height: 10px;
  flex-shrink: 0;
  border-radius: 50%;
  background: currentColor;
  animation: netDotPulse 1.2s ease-in-out infinite;
}

.net-banner--ok .net-banner-dot,
.net-banner--error .net-banner-dot {
  animation: none;
}

.net-banner-text {
  text-align: center;
  overflow-wrap: anywhere;
}

.net-banner-action {
  min-height: 40px;
  padding: 4px 14px;
  border-radius: 8px;
  border: 1px solid rgba(255, 255, 255, 0.4);
  background: rgba(255, 255, 255, 0.12);
  color: #fff;
  font: inherit;
  cursor: pointer;
}

.net-banner-action:active {
  background: rgba(255, 255, 255, 0.28);
}

@keyframes netBannerIn {
  from { opacity: 0; transform: translateY(-100%); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes netDotPulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.3; }
}

/* ---- Toasts ---- */
.game-toast .toast-text {
  overflow-wrap: anywhere;
}

.game-toast.error {
  background: linear-gradient(135deg, rgba(239, 68, 68, 0.95) 0%, rgba(185, 28, 28, 0.95) 100%);
  border-color: #f87171;
  box-shadow: 0 10px 28px rgba(239, 68, 68, 0.45), 0 0 22px rgba(239, 68, 68, 0.6);
}

.game-toast.success {
  background: linear-gradient(135deg, rgba(16, 185, 129, 0.95) 0%, rgba(4, 120, 87, 0.95) 100%);
  border-color: #34d399;
  box-shadow: 0 10px 28px rgba(16, 185, 129, 0.4);
}

/* ---- Round summary and match over ---- */
.summary-subtitle {
  color: var(--text-muted, #94a3b8);
  font-size: 0.85rem;
}

/* Wide result tables scroll sideways on phones instead of squeezing every column. */
.summary-table-wrap {
  max-width: 100%;
  overflow-x: auto;
}

.summary-table .ready-mark {
  font-size: 0.8rem;
}

.champion-banner {
  margin: 12px 0;
  padding: 12px 14px;
  border-radius: 12px;
  text-align: center;
  font-size: 1.05rem;
  font-weight: 800;
  color: #0f172a;
  background: linear-gradient(135deg, #fbbf24, #f59e0b);
  overflow-wrap: anywhere;
}

.standings-title {
  margin: 14px 0 4px;
  font-size: 0.9rem;
  color: var(--gold-accent, #f59e0b);
}

.summary-wait-note,
.next-round-ready,
.next-round-countdown {
  margin: 6px 0 0;
  text-align: center;
  font-size: 0.85rem;
  color: var(--text-muted, #94a3b8);
}

.next-round-countdown {
  min-height: 1.2em;
}

/* ---- Settings dialog ---- */
.settings-note {
  margin-bottom: 12px;
  padding: 8px 10px;
  border-radius: 8px;
  font-size: 0.8rem;
  color: var(--gold-accent, #f59e0b);
  background: rgba(245, 158, 11, 0.12);
}

.form-control:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

/* ---- Table melds ---- */
.table-meld-group.layoff-candidate {
  border-color: var(--gold-accent, #f59e0b);
  box-shadow: 0 0 0 2px rgba(245, 158, 11, 0.45), 0 6px 18px rgba(0, 0, 0, 0.4);
}

.table-meld-group.meld-invalid {
  border-color: #ef4444;
}

.table-meld-group.meld-invalid .meld-type-tag {
  background: rgba(239, 68, 68, 0.25);
  color: #fecaca;
}

/* Inside a meld box on a phone: close to a fingertip without doubling the box height. */
.meld-actions-bar .btn-micro {
  min-height: 40px;
}

/* A table Joker prints the card it stands for in its visible corner (tooltips do not exist on touch). */
.joker-card .card-corner.joker-rep {
  padding: 1px 3px;
  border-radius: 4px;
  background: #fff;
  box-shadow: 0 0 0 1px var(--joker-purple, #7e22ce);
}

.joker-card .card-corner.joker-rep.red { color: var(--red-suit, #dc2626); }
.joker-card .card-corner.joker-rep.black { color: var(--black-suit, #0f172a); }

.exposed-meld-card.joker-card .card-corner.joker-rep .card-rank {
  font-size: 0.72rem !important;
  letter-spacing: 0;
}

.exposed-meld-card.joker-card .card-corner.joker-rep .card-suit {
  font-size: 0.62rem !important;
}

/* A card whose fields failed validation (never expected from a healthy server). */
.card.unknown-card {
  align-items: center;
  justify-content: center;
  color: #475569;
  background: repeating-linear-gradient(45deg, #e2e8f0, #e2e8f0 6px, #cbd5e1 6px, #cbd5e1 12px);
}

/* ---- Player badges ---- */
.player-badge.is-offline {
  opacity: 0.7;
  filter: grayscale(0.6);
}

.badge-offline-tag {
  margin-inline-start: 4px;
  padding: 0 5px;
  border-radius: 6px;
  font-size: 0.6rem;
  font-weight: 700;
  color: #fecaca;
  background: rgba(239, 68, 68, 0.25);
}

@media (hover: hover) and (pointer: fine) {
  .net-banner-action:hover {
    background: rgba(255, 255, 255, 0.24);
  }
}

/* ---- Main Menu first: while it is open the table does not exist for sight, focus or screen readers ----
   display:none (not visibility) also removes it from style, layout and animation work: nothing behind the menu costs
   a frame. Script clicks on its buttons (the menu footer drives them) still work. */
body.menu-open .app-header,
body.menu-open .game-viewport,
body.menu-open .bottom-control-bar,
body.menu-open .leather-armrest {
  display: none;
}

/* ---- The player's Google photo on their own badge (same round frame as the emoji avatars) ---- */
img.badge-avatar {
  display: block;
  object-fit: cover;
  background: #0d2c1c;
}

/* ---- Leave Table (hamburger menu on phones, header on desktop) ---- */
.btn-leave-table {
  min-height: 44px;
  color: #fecaca;
  background: rgba(127, 29, 29, 0.35);
  border-color: rgba(248, 113, 113, 0.55);
}

.btn-leave-table:active {
  transform: scale(0.97);
}

@media (hover: hover) and (pointer: fine) {
  .btn-leave-table:hover {
    background: rgba(185, 28, 28, 0.5);
  }
}

/* ---- Motion: cards fly in from the stock, new melds settle onto the felt, your turn lights the table ----
   Only transform/opacity animate. Each keyframe set has just a `from` frame, so the card or meld ends exactly in the
   position the layout gave it (the hand fan uses transform too). UIController adds the classes for ~700 ms. */
@keyframes handCardFlyIn {
  from {
    opacity: 0;
    transform: translate(var(--fly-x, 0px), var(--fly-y, 48px)) scale(0.5) rotate(-10deg);
  }
}

@keyframes meldSettleIn {
  from {
    opacity: 0;
    transform: translateY(18px) scale(0.9);
  }
}

.card.just-drawn {
  z-index: 6;
  animation: handCardFlyIn 0.34s cubic-bezier(0.2, 0.8, 0.25, 1) backwards;
}

.table-meld-group.just-placed {
  animation: meldSettleIn 0.36s cubic-bezier(0.2, 0.8, 0.25, 1) backwards;
}

.game-viewport.your-turn {
  box-shadow: inset 0 0 0 2px rgba(245, 158, 11, 0.5), inset 0 0 26px rgba(245, 158, 11, 0.16);
  transition: box-shadow 0.25s ease;
}

@media (prefers-reduced-motion: reduce) {
  .card.just-drawn,
  .table-meld-group.just-placed {
    animation: none;
  }
}

/* ---- What the finished match earned (XP and chips saved by the server) ---- */
.rewards-block {
  margin-top: 14px;
  padding: 12px 14px;
  text-align: center;
  border: 1px solid rgba(245, 158, 11, 0.4);
  border-radius: 14px;
  background: rgba(245, 158, 11, 0.08);
}

.rewards-title {
  margin: 0 0 8px;
  font-size: 1rem;
  color: #fbbf24;
}

.rewards-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
}

.reward-chip {
  padding: 6px 12px;
  font-weight: 800;
  color: #fde68a;
  border: 1px solid rgba(245, 158, 11, 0.5);
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.35);
}

.reward-levelup {
  margin: 10px 0 0;
  font-weight: 800;
  color: #34d399;
}

.rewards-note {
  margin: 0;
  color: #94a3b8;
}

.reward-stake {
  color: #fecaca;
  border-color: rgba(248, 113, 113, 0.5);
}

/* The player's own badge opens their profile. */
#player-badge-0 {
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

#player-badge-0:focus-visible {
  outline: 2px solid #f59e0b;
  outline-offset: 2px;
}
