/*
 * Carbles menu surfaces - the main menu and every setup screen behind it.
 *
 * These deliberately wear the sibling Yahtzee project's scorecard idiom, so the two games read as
 * one family: a bordered card with a filled caption strip along the top, and inside it a body of
 * rounded pill rows packed two-up, each pill carrying tinted 3px left/right "bracket" edges and a
 * fill that together say what state it is in. In the scorecard those states are scored / scratched
 * / still open; here they are the states a menu row has - offered, chosen, or unavailable - and the
 * bracket is what changes, so hover, focus and selection are shape-and-colour rather than colour
 * alone (§11/§12).
 *
 * Two local custom properties do that work, exactly as the scorecard's do: every pill reads
 * --bracket and --state-fill, and the state rules below only ever reset those two, so a new state
 * is one declaration rather than a re-specified pill. Everything resolves through skins.css
 * tokens - no literal colours here, so all four skins follow automatically (§11).
 *
 * Loaded globally by each host's index.html rather than as scoped component CSS, because the same
 * classes are used by pages in three different projects (Carbles.Components, Carbles.Web,
 * Carbles.Mobile) and scoped CSS cannot cross that boundary.
 */

/* --------------------------------------------------------------------------
   Page frame
   -------------------------------------------------------------------------- */

.menu {
  box-sizing: border-box;
  max-width: 44rem;
  margin: 0 auto;
  padding: 1.5rem 1rem 2.5rem;
}

.menu__title {
  margin: 0 0 0.25rem;
  font-size: 1.6rem;
  line-height: 1.2;
}

.menu__lede {
  margin: 0 0 1.25rem;
  color: var(--color-text-muted);
}

/* --------------------------------------------------------------------------
   Card
   -------------------------------------------------------------------------- */

.menu-card {
  box-sizing: border-box;
  background-color: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 12px;
  overflow: hidden;
  margin-bottom: 1rem;
}

.menu-card__caption {
  margin: 0;
  padding: 0.55rem 0.75rem;
  font-size: 0.95rem;
  font-weight: 700;
  text-align: left;
  background-color: var(--color-surface-alt);
  border-bottom: 1px solid var(--color-border);
}

.menu-card__body {
  display: grid;
  gap: 0.4rem;
  padding: 0.5rem;
}

/* The mode list packs two-up on anything wider than a phone, like the scorecard's category rows.
   minmax(0, …) lets a track shrink below its content so a long description wraps inside its pill
   instead of forcing the card wider than the viewport (reflow at 320px, §12 1.4.10). */
@media (min-width: 34rem) {
  .menu-card__body--two-up {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }
}

/* --------------------------------------------------------------------------
   Pill rows
   -------------------------------------------------------------------------- */

.menu-row {
  /* Reset by the state rules below; "offered" is the resting state of most of a menu. */
  --bracket: var(--color-text-muted);
  --state-fill: var(--color-surface-alt);
  box-sizing: border-box;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
  min-height: 44px; /* comfortable touch target (§12 2.5.8) */
  margin: 0;
  padding: 0.45rem 0.6rem;
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--bracket);
  border-right: 3px solid var(--bracket);
  border-radius: 10px;
  background-color: var(--state-fill);
  color: var(--color-text);
  text-align: left;
}

/* A row that goes somewhere: the whole pill is the target, and its brackets light up in the skin's
   accent under the pointer or the keyboard. */
.menu-row--action {
  display: flex;
  cursor: pointer;
  text-decoration: none;
  font: inherit;
  width: 100%;
}

.menu-row--action:hover,
.menu-row--action:focus-visible {
  --bracket: var(--color-accent);
  --state-fill: color-mix(in srgb, var(--color-accent) 10%, var(--color-surface-alt));
}

.menu-row--action:focus-visible {
  outline: 3px solid var(--color-focus-ring);
  outline-offset: 2px;
}

/* Unavailable here and now (the LAN mode in a browser tab): flat brackets and no fill, so it reads
   as a row that is present but not offered rather than one that failed. */
.menu-row--disabled {
  --bracket: var(--color-border);
  --state-fill: var(--color-surface);
  color: var(--color-text-muted);
  cursor: not-allowed;
}

/* Stacked layout for a row whose content is a block (a mode's heading over its description) rather
   than a label beside a control. */
.menu-row--stacked {
  flex-direction: column;
  align-items: stretch;
  gap: 0.15rem;
  padding: 0.7rem 0.75rem;
}

.menu-row__heading {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  margin: 0;
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.2;
}

/* The scorecard puts a category glyph beside every row name; a Carbles mode gets a marble in a
   player colour instead - decorative, since the heading beside it already names the row. */
.menu-marble {
  display: inline-block;
  flex: none;
  width: 0.85rem;
  height: 0.85rem;
  border-radius: 50%;
  border: 1px solid rgba(0, 0, 0, 0.35);
  background-color: var(--menu-marble-color, var(--color-text-muted));
}

.menu-marble--red {
  --menu-marble-color: var(--color-player-red);
}

.menu-marble--blue {
  --menu-marble-color: var(--color-player-blue);
}

.menu-marble--green {
  --menu-marble-color: var(--color-player-green);
}

.menu-marble--yellow {
  --menu-marble-color: var(--color-player-yellow);
}

.menu-row__hint,
.menu-hint {
  margin: 0;
  color: var(--color-text-muted);
  font-size: 0.85rem;
  line-height: 1.35;
}

/* The label half of a control row. Fixed minimum so the controls beside them line up down the
   card, but allowed to shrink on a narrow screen rather than squeezing the control out. */
.menu-row__label {
  flex: 0 0 auto;
  min-width: 6.5rem;
  font-weight: 600;
}

.menu-row__control {
  flex: 1 1 8rem;
  min-width: 0;
  padding: 0.45rem 0.55rem;
  border-radius: 8px;
  border: 1px solid var(--color-border);
  background-color: var(--color-surface);
  color: var(--color-text);
  font: inherit;
}

.menu-row__control:focus-visible {
  outline: 3px solid var(--color-focus-ring);
  outline-offset: 1px;
}

.menu-row__value {
  margin-left: auto;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
}

.menu-row__remove {
  flex: none;
  background: none;
  border: none;
  border-radius: 8px;
  color: var(--color-danger);
  cursor: pointer;
  font: inherit;
  padding: 0.25rem 0.4rem;
}

/* A row whose control is a set of choices. fieldset's default chrome is stripped so it wears the
   pill like any other row; the legend stays as the group's accessible name (§12 1.3.1). */
.menu-row--choices {
  flex-wrap: wrap;
}

.menu-row--choices > legend {
  float: left; /* a legend is not a flex item in every engine - float keeps it on the first line */
  width: 100%;
  padding: 0;
  margin-bottom: 0.35rem;
  font-weight: 600;
}

.menu-choices {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  width: 100%;
}

/* One choice: a small pill echoing the row it sits in, checked state carried by the accent
   bracket *and* the native radio inside it, never by colour alone (§12 1.4.1). */
.menu-choice {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  min-height: 36px;
  padding: 0.25rem 0.6rem;
  border: 1px solid var(--color-border);
  border-radius: 999px;
  background-color: var(--color-surface);
  cursor: pointer;
}

.menu-choice:has(input:checked) {
  border-color: var(--color-accent);
  background-color: color-mix(in srgb, var(--color-accent) 14%, var(--color-surface));
  font-weight: 700;
}

.menu-choice:has(input:focus-visible) {
  outline: 3px solid var(--color-focus-ring);
  outline-offset: 2px;
}

/* --------------------------------------------------------------------------
   Summary rows, lists, messages and actions
   -------------------------------------------------------------------------- */

/* The scorecard's subtotal/total rows: label left, value right, no pill around either. */
.menu-summary {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
  min-width: 0;
  padding: 0.15rem 0.35rem;
  color: var(--color-text-muted);
  font-weight: 600;
}

.menu-list {
  list-style: none;
  display: grid;
  gap: 0.4rem;
  margin: 0;
  padding: 0;
}

.menu-code {
  font-size: 1.5rem;
  font-weight: 800;
  letter-spacing: 0.18em;
  font-variant-numeric: tabular-nums;
}

.menu-error {
  margin: 0.75rem 0 0;
  color: var(--color-danger);
  font-weight: 600;
}

.menu-status {
  margin: 0.75rem 0 0;
  color: var(--color-text-muted);
}

.menu-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  margin-top: 1.25rem;
}

.btn-accent,
.btn-secondary {
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
  padding: 0.55rem 1.1rem;
  min-height: 44px; /* touch target (§12 2.5.8) */
  min-width: 44px;
  font: inherit;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
}

.btn-accent {
  background-color: var(--color-accent);
  color: var(--color-accent-text);
  border: 1px solid transparent;
}

.btn-accent:hover:not(:disabled) {
  background-color: color-mix(in srgb, var(--color-accent) 85%, var(--color-text));
}

.btn-secondary {
  background-color: var(--color-surface-alt);
  color: var(--color-text);
  border: 1px solid var(--color-border);
}

.btn-secondary:hover:not(:disabled) {
  border-color: var(--color-accent);
}

.btn-accent:focus-visible,
.btn-secondary:focus-visible {
  outline: 3px solid var(--color-focus-ring);
  outline-offset: 2px;
}

.btn-accent:disabled,
.btn-secondary:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

/* Deliberately no colour transition on any of the above. Skins swap by re-resolving these tokens,
   and a row easing between two skins' fills spends that time on a blend belonging to neither -
   which the accessibility scan reads, correctly, as text on a background it does not have the
   contrast for (§12 1.4.3). Nothing here is worth a frame of that.  */

/* --------------------------------------------------------------------------
   Main menu mode tiles

   The main menu wears the sibling Yahtzee project's setup screen: one card whose body is a
   two-up grid of tiles, each a bracketed pill grown tall enough to carry its glyph above its
   name. Same shape and same states as .menu-row above - it is the scorecard pill again, just
   stacked and sized for a landing screen rather than a list.
   -------------------------------------------------------------------------- */

.setup-menu {
  box-sizing: border-box;
  width: 100%;
  max-width: 44rem;
  /* Fills the content area so the card sits in the middle of the screen rather than riding at the
     top of it, as Yahtzee's does. min-height rather than height, so a viewport too short for the
     card scrolls instead of clipping it. */
  min-height: 100%;
  margin: 0 auto;
  padding: 1rem;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.75rem;
}

.setup-menu-card {
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  min-height: 0;
  background-color: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 12px;
  overflow: hidden;
}

/* The card's caption strip, carrying the screen's only heading. */
.setup-menu-title {
  margin: 0;
  padding: 0.55rem 0.75rem;
  font-size: 1rem;
  font-weight: 700;
  background-color: var(--color-surface-alt);
  border-bottom: 1px solid var(--color-border);
}

.setup-modes {
  min-height: 0;
  list-style: none;
  margin: 0;
  padding: 0.5rem;
  display: grid;
  /* minmax(0, ...) on both axes so tiles shrink with the card rather than pushing it past the
     viewport - reflow at 320px (§12 1.4.10). */
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  grid-auto-rows: minmax(0, auto);
  gap: 0.5rem;
}

.setup-mode {
  display: flex;
  min-width: 0;
  min-height: 0;
}

/* An odd number of options - the WiFi tile is absent where LAN play is impossible - would leave
   the last one alone in its column; let it span so the grid still divides the card evenly. */
.setup-mode:last-child:nth-child(odd) {
  grid-column: 1 / -1;
}

.mode-tile {
  --bracket: var(--color-accent);
  box-sizing: border-box;
  flex: 1;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
  padding: 0.7rem 0.6rem;
  overflow: hidden;
  text-align: center;
  text-decoration: none;
  font: inherit;
  cursor: pointer;
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--bracket);
  border-right: 3px solid var(--bracket);
  border-radius: 10px;
  background-color: var(--color-surface-alt);
  color: var(--color-text);
}

.mode-tile:hover,
.mode-tile:focus-visible {
  background-color: color-mix(in srgb, var(--color-accent) 10%, var(--color-surface-alt));
}

.mode-tile:focus-visible {
  outline: 3px solid var(--color-focus-ring);
  outline-offset: 2px;
}

.mode-icon {
  display: inline-flex;
  flex: none;
  color: var(--color-accent);
}

.mode-tile-mark .mode-svg {
  display: block;
  width: clamp(2.25rem, 7vh, 3.5rem);
  height: clamp(2.25rem, 7vh, 3.5rem);
}

.mode-tile-name {
  font-weight: 700;
  font-size: clamp(0.95rem, 2.2vh, 1.15rem);
  line-height: 1.15;
}

.mode-tile-desc {
  font-size: clamp(0.72rem, 1.6vh, 0.85rem);
  line-height: 1.25;
  color: var(--color-text-muted);
}

/* Very short or very narrow viewports: the glyph and the name carry the tile on their own, and
   the same words are on the setup screen one tap away. */
@media (max-height: 420px), (max-width: 360px) {
  .mode-tile-desc {
    display: none;
  }
}

/* --------------------------------------------------------------------------
   Settings dialog

   Opened from the Carbles brand in the top bar (AppShell). Structure follows the sibling Yahtzee
   project's settings modal: a centred panel over a dimmed backdrop, a header row carrying the
   title and the Close/Back button, and one titled section per group of controls.
   -------------------------------------------------------------------------- */

.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  background-color: rgb(0 0 0 / 0.6);
}

/* Sentinels either side of the panel: focus reaching one is sent back inside, which is what keeps
   Tab from walking out of a modal dialog (§12 2.1.2). */
.focus-sentinel {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}

.modal {
  box-sizing: border-box;
  width: min(32rem, 100%);
  max-height: min(85vh, 48rem);
  overflow-y: auto;
  padding: 1rem 1.25rem 1.5rem;
  background-color: var(--color-surface);
  color: var(--color-text);
  border: 1px solid var(--color-border);
  border-radius: 12px;
  box-shadow: 0 8px 32px rgb(0 0 0 / 0.45);
}

.settings-header {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin: -1rem -1.25rem 0.75rem;
  padding: 1rem 1.25rem 0.75rem;
  background-color: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
}

.settings-header h2 {
  margin: 0;
  font-size: 1.2rem;
}

.settings-section {
  padding: 0.75rem 0;
  border-top: 1px solid var(--color-border);
}

.settings-section:first-of-type {
  border-top: none;
}

.settings-section__title {
  margin: 0;
  font-size: 1rem;
}

.settings-section__hint {
  margin: 0.1rem 0 0.6rem;
  font-size: 0.85rem;
  color: var(--color-text-muted);
}

/* The build the app is running, at the foot of the dialog. Sharing the section border keeps it
   part of the list rather than an afterthought stuck underneath it, but it is a fact rather
   than a setting, so it is muted and carries no title. */
.settings-version {
  margin: 0;
  padding: 0.75rem 0 0;
  border-top: 1px solid var(--color-border);
  font-size: 0.85rem;
  color: var(--color-text-muted);
}

/* --------------------------------------------------------------------------
   Settings controls
   -------------------------------------------------------------------------- */

.setting-toggle {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: 0.25rem 0.6rem;
}

.setting-toggle__input {
  width: 1.15rem;
  height: 1.15rem;
  accent-color: var(--color-accent);
}

.setting-toggle__label {
  font-weight: 600;
  cursor: pointer;
}

.setting-toggle__desc {
  grid-column: 1 / -1;
  margin: 0;
  font-size: 0.85rem;
  line-height: 1.35;
  color: var(--color-text-muted);
}

.seat-colours__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.3rem 0;
}

.seat-colours__label {
  font-weight: 600;
}

.seat-colours__options {
  display: flex;
  gap: 0.4rem;
}

/* A swatch is the marble it stands for. The chosen one is marked by a ring *and* a size step, so
   the selection is never carried by colour alone (§12 1.4.1). */
.seat-colours__swatch {
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: 2px solid var(--color-border);
  border-radius: 50%;
  background-color: var(--swatch-colour);
  cursor: pointer;
}

.seat-colours__swatch--active {
  border-color: var(--color-text);
  box-shadow: 0 0 0 3px var(--color-surface), 0 0 0 5px var(--color-text);
}

.seat-colours__swatch:focus-visible {
  outline: 3px solid var(--color-focus-ring);
  outline-offset: 2px;
}

.seat-colours__swatch--red { --swatch-colour: var(--color-player-red); }
.seat-colours__swatch--blue { --swatch-colour: var(--color-player-blue); }
.seat-colours__swatch--green { --swatch-colour: var(--color-player-green); }
.seat-colours__swatch--yellow { --swatch-colour: var(--color-player-yellow); }

.seat-colours__reset {
  margin-top: 0.6rem;
}

/* --------------------------------------------------------------------------
   How to Play
   -------------------------------------------------------------------------- */

.how-to-play__lede {
  margin: 0 0 0.75rem;
  color: var(--color-text-muted);
}

.how-to-play__list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.how-to-play__topic {
  border-top: 1px solid var(--color-border);
}

.how-to-play__summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  width: 100%;
  min-height: 44px; /* comfortable touch target (§12 2.5.8) */
  padding: 0.6rem 0.2rem;
  border: none;
  background: none;
  color: inherit;
  font: inherit;
  font-weight: 600;
  text-align: left;
  cursor: pointer;
}

.how-to-play__summary:focus-visible {
  outline: 3px solid var(--color-focus-ring);
  outline-offset: -2px;
}

/* A chevron that turns as the topic opens - the open state is shape as well as position, so it
   does not depend on the panel below being in view. */
.how-to-play__chevron {
  flex: none;
  width: 0.6rem;
  height: 0.6rem;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(-45deg);
  transition: transform 120ms ease;
}

.how-to-play__chevron--open {
  transform: rotate(45deg);
}

.how-to-play__points {
  margin: 0 0 0.75rem;
  padding-left: 1.1rem;
  display: grid;
  gap: 0.4rem;
  font-size: 0.9rem;
  line-height: 1.4;
  color: var(--color-text-muted);
}

/* --------------------------------------------------------------------------
   Quit / player-left dialogs
   -------------------------------------------------------------------------- */

.quit-game-modal h2,
.player-left-modal h2 {
  margin: 0 0 0.5rem;
  font-size: 1.2rem;
}

.quit-game-modal__lead,
.player-left-modal__lead {
  margin: 0 0 1.25rem;
  line-height: 1.4;
  color: var(--color-text-muted);
}

/* Wraps rather than shrinking: two full-width buttons stacked on a narrow phone beat two clipped
   ones side by side, and the destructive choice is never the one under the thumb by accident. */
.quit-game-modal__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
}

.quit-game-modal__actions > * {
  flex: 1 1 8rem;
}
