body { font-family: system-ui, sans-serif; margin: 1.5rem; max-width: 1280px; }
  h1 { margin: 0 0 0.4rem 0; font-weight: 700; font-size: 1.75rem; letter-spacing: -0.01em; }
  .sub { color: #666; margin-top: 0; }
  .row { display: flex; gap: 1.5rem; flex-wrap: wrap; align-items: flex-start; }
  .card {
    border: 1px solid #e3e3e3;
    border-radius: 10px;
    padding: 1rem;
    margin-bottom: 1rem;
    background: #fff;
    box-shadow: 0 1px 3px rgba(0,0,0,0.06);
  }
  .card h2 { margin: 0 0 0.6rem 0; font-size: 1.25rem; font-weight: 600; }
  /* spacing + alignment utilities (replaces ad-hoc inline styles) */
  .stack-tight { display: flex; gap: 0.3rem; align-items: center; flex-wrap: wrap; }
  .stack-row   { display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; }
  .stack-wide  { display: flex; gap: 1.5rem; align-items: center; flex-wrap: wrap; font-size: 0.95rem; }
  .no-margin   { margin: 0; }
  .mt-half     { margin-top: 0.6rem; }
  .mt-3-4      { margin-top: 0.8rem; }
  .mb-0        { margin-bottom: 0; }
  .mb-half     { margin: 0 0 0.6rem 0; }
  .col-form    { flex: 1 1 380px; min-width: 320px; }
  .col-board   { flex: 2 1 700px; min-width: 400px; }
  .coord-input { width: 6rem; }
  .share-input { width: min(34rem, 100%); padding: 0.2rem 0.35rem; }
  .btn-pad     { padding: 0.5rem 1rem; }
  .dim         { color: #666; }
  .accent      { color: #2c7fb8; }
  .num         { font-size: 1.1rem; font-weight: 600; }
  .plot-container { position: relative; }
  .board-svg      { display: block; background: #eaf4fb; touch-action: none; user-select: none; }
  /* Broom cursor on the ice. Handle points RIGHT toward the end line; the
     brush sits on the LEFT (where the user is aiming = hotspot at 4,16).
     Brush height is computed server-side from the upcoming throw's
     EFFECTIVE angle-noise sigma:
        sigma = SKILL_PRESETS[skill].sigma_angle_deg × PLAYER_NOISE_SCALE[position]
        brush_height_px = clamp(round(sigma * 20), 4, 30)
     so the cursor reflects both the room's skill AND who's currently
     throwing (lead is wider than skip for the same skill). Groove bonus
     isn't applied because aim_y isn't known until the user clicks; the
     brush therefore shows the WORST-CASE spread for the next throw.
     SVG is embedded as a data URI; '#' in hex colours must be URL-encoded
     as %23. */
  .ice-broom-cursor {
    cursor: var(--ice-broom-cursor, crosshair);
  }
  /* Two-column desktop layout: controls left, portrait ice right */
  .game-layout {
    display: flex;
    gap: 1rem;
    align-items: stretch;
    height: calc(100vh - 3rem);
    max-width: 1100px;
    margin: 0 auto;
  }
  .game-col-controls {
    flex: 1 1 0;
    min-width: 0;
    overflow-y: auto;
    height: 100%;
  }
  .game-col-controls .card { margin-bottom: 0.5rem; padding: 0.6rem; }
  .game-col-ice {
    flex: 0 0 auto;
    height: 100%;
  }
  .game-col-ice .card {
    height: 100%;
    display: flex;
    align-items: center;
    padding: 0.5rem;
    margin: 0;
  }
  .throw-history-scroll { max-height: 3.2rem; overflow-y: auto; }
  /* Portrait ice sized by viewport height — scoped to the ice column */
  .game-col-ice .board-svg { display: block; width: auto; height: 100%; aspect-ratio: 4.75 / 9.734; background: #eaf4fb; touch-action: none; user-select: none; }
  .game-col-ice .plot-container { width: auto; height: 100%; }
  @media (max-width: 900px) {
    /* Narrow screens: stack columns, ice on top sized by width */
    /* Release the desktop one-screen viewport lock so the stacked page scrolls */
    html, body { height: auto; overflow: auto; }
    .game-col-controls { height: auto; overflow-y: visible; }
    .game-layout {
      flex-direction: column-reverse;
      height: auto;
    }
    .game-col-ice {
      height: auto;
      width: 100%;
    }
    .game-col-ice .card {
      height: auto;
    }
    /* Selectors must match the .game-col-ice scoping above (the unscoped
       forms lose on specificity), and width must DERIVE from aspect-ratio,
       never be set with the height: the board JS (pixelFromIce) fills both
       axes, so a non-sheet-aspect element draws a stretched board/path. */
    .game-col-ice .plot-container {
      width: auto;
      height: min(62vh, calc((100vw - 3rem) * 9.734 / 4.75));
      aspect-ratio: 4.75 / 9.734;
      margin: 0 auto;
    }
    .game-col-ice .board-svg {
      width: 100%;
      height: 100%;
    }
  }
  .click-markers  { position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; }
  .chip-strip     { display: flex; flex-wrap: wrap; gap: 0.25rem; margin-bottom: 0.6rem; }
  .text-left      { text-align: left; }
  .status-strip   { display: flex; flex-wrap: wrap; gap: 0.4rem 1.2rem; align-items: center;
                    padding: 0.5rem 0; margin-bottom: 0.8rem; border-bottom: 1px dashed #eee;
                    font-size: 0.95rem; }
  .status-strip select { padding: 0.1rem 0.3rem; }
  .weight-control { display: grid; gap: 0.15rem; min-width: min(32rem, 100%); }
  .weight-control input[type=range] { width: 100%; }
  .weight-ticks { display: flex; justify-content: space-between; gap: 0.35rem; color: #777; font-size: 0.72rem; }
  .weight-ticks span { max-width: 4.2rem; text-align: center; line-height: 1.05; overflow-wrap: anywhere; }
  .hint-strip { display: flex; flex-wrap: wrap; gap: 0.4rem 0.8rem; align-items: center;
                padding: 0.35rem 0; font-size: 0.88rem; }
  .hint-btn { font-size: 0.85rem; }
  @keyframes hint-pulse-anim {
    0%, 100% { opacity: 0.9; }
    50% { opacity: 0.4; }
  }
  .hint-pulse { animation: hint-pulse-anim 1.2s ease-in-out infinite; }
  .debug-box      { margin-top: 1rem; }
  .debug-box summary { cursor: pointer; }
  .coord-label    { min-width: 2.5rem; }
  details.collapsible-card > summary { cursor: pointer; list-style: none; }
  details.collapsible-card > summary::after { content: " ▾"; color: #888; }
  details.collapsible-card[open] > summary::after { content: " ▴"; }
  form.inline { display: grid; grid-template-columns: auto 1fr; gap: 0.4rem 0.8rem; align-items: center; }
  form.inline input { width: 100%; box-sizing: border-box; padding: 0.2rem 0.4rem; }
  form.inline button { grid-column: 1 / span 2; margin-top: 0.6rem; padding: 0.4rem; font-weight: 600; }
  table { border-collapse: collapse; font-size: 0.85rem; }
  th, td { border-bottom: 1px solid #eee; padding: 0.25rem 0.6rem; text-align: right; }
  th { background: #fafafa; text-align: right; }
  td.team-0, th.team-0 { color: #d62728; }
  td.team-1, th.team-1 { color: #b8930d; }
  td.id { text-align: center; font-weight: 600; }
  img.plot { max-width: 100%; border: 1px solid #ddd; border-radius: 6px; }
  svg.plot { max-width: 100%; border: 1px solid #ddd; border-radius: 6px; box-sizing: border-box; }
  .meta { color: #666; font-size: 0.9rem; }
  fieldset { border: 1px solid #eee; padding: 0.5rem 0.8rem; margin: 0.6rem 0; }
  legend { color: #666; font-size: 0.85rem; padding: 0 0.3rem; }
  .turn-picker { display: flex; align-items: center; gap: 0.6rem; }
  .turn-option { display: inline-flex; align-items: center; gap: 0.2rem; cursor: pointer; padding: 0.2rem 0.4rem; border: 1px solid #ccc; border-radius: 4px; }
  .turn-option:has(input:checked) { background: #e8f1fb; border-color: #6aa5d8; }
  .turn-option input { margin: 0; }
  .turn-option .arrow { font-size: 1.4rem; line-height: 1; }
  .turn-note { color: #888; font-size: 0.8rem; }
  button.primary { background: #2c7fb8; color: #fff; border: 1px solid #1e5f8b; border-radius: 4px; cursor: pointer; }
  button.primary:hover { background: #1e5f8b; }
  button.neutral { background: #eee; color: #333; border: 1px solid #bbb; border-radius: 4px; cursor: pointer; }
  button.neutral:hover { background: #ddd; }
  button:disabled { opacity: 0.65; cursor: wait; }
  .particle-chip {
    min-width: 2rem;
    padding: 0.2rem 0.45rem;
    font-size: 0.85rem;
    border: 1px solid #bbb;
    background: #fafafa;
    color: #444;
    border-radius: 4px;
    cursor: pointer;
  }
  .particle-chip:hover { background: #eef6fc; border-color: #6aa5d8; }
  .particle-chip.active { background: #2c7fb8; color: #fff; border-color: #1e5f8b; font-weight: 600; }
  .status { display: flex; flex-wrap: wrap; gap: 0.45rem 0.8rem; align-items: center; }
  .pill { border: 1px solid #ddd; border-radius: 999px; padding: 0.15rem 0.5rem; background: #fafafa; }
  .team-label-0 { color: #d62728; font-weight: 700; }
  .team-label-1 { color: #b8930d; font-weight: 700; }
  .disabled-note { color: #8a5a00; background: #fff7e6; border: 1px solid #f0d79a; border-radius: 6px; padding: 0.55rem 0.7rem; }
  .ai-panel { border: 1px solid #b7d5eb; background: #f4f9fd; border-radius: 6px; padding: 0.7rem 0.8rem; }
  .ai-meter { width: min(28rem, 100%); height: 0.6rem; appearance: none; }
  .ai-meter::-webkit-progress-bar { background: #e7eef3; border-radius: 999px; }
  .ai-meter::-webkit-progress-value { background: #2c7fb8; border-radius: 999px; }
  .ai-meter::-moz-progress-bar { background: #2c7fb8; border-radius: 999px; }
  .scoreboard { overflow-x: auto; }
  table.club-scoreboard { border-collapse: separate; border-spacing: 0; min-width: auto; font-size: 0.95rem; }
  .club-scoreboard th, .club-scoreboard td {
    border: 1px solid #ddd;
    min-width: 2.1rem;
    height: 1.1rem;
    padding: 0.05rem 0.35rem;
    text-align: center;
  }
  .club-scoreboard th.team-name { min-width: 5rem; text-align: left; background: #fafafa; }
  .club-scoreboard .score-row th, .club-scoreboard .score-row td {
    background: #222;
    color: #fff;
    font-weight: 800;
  }
  .club-scoreboard .end-cell { font-weight: 800; font-size: 0.95rem; }
  .club-scoreboard .total { min-width: 3rem; background: #f5f5f5; font-weight: 800; }

  /* Mobile tweaks: tighter chrome, bigger tap targets, full-width buttons. */
  @media (max-width: 640px) {
    body { margin: 0.5rem; max-width: none; }
    h1 { font-size: 1.4rem; }
    .card { padding: 0.7rem; }
    .card h2 { font-size: 1.1rem; }
    .sub { font-size: 0.9rem; }

    /* Status strip: buttons share the row at full width on mobile */
    .status-strip {
      gap: 0.5rem 0.8rem;
      padding: 0.4rem 0;
    }
    .status-strip > button {
      flex: 1;
      min-height: 2.75rem;
    }
    .status-strip > #aim_status {
      flex-basis: 100%;
    }

    /* Bigger particle chips and pills for finger-friendly taps */
    .particle-chip {
      min-width: 2.6rem; min-height: 2.6rem;
      font-size: 1rem; padding: 0.5rem 0.7rem;
    }
    .pill { padding: 0.3rem 0.6rem; }

    /* Throw-this-shot row stacks; button gets full width */
    #candidate_action_row { gap: 0.5rem 0.8rem; }
    #candidate_action_row > form {
      margin-left: 0 !important;
      flex-basis: 100%;
    }
    #candidate_action_row > form > button { width: 100%; min-height: 2.75rem; }

    /* Replay button full-width */
    #replay_throw { width: 100%; min-height: 2.75rem; }

    /* History/Players details: smaller table cells so they fit */
    table { font-size: 0.8rem; }
    th, td { padding: 0.2rem 0.35rem; }
  }

/* Game page full-viewport layout (was inline in index.html, after this link
   so it overrides the body rule above; kept last to preserve that order). */
html, body { margin: 0; padding: 0.5rem; max-width: none; box-sizing: border-box; }
/* The one-screen viewport lock is desktop-only; on narrow screens the page
   must scroll (see the max-width:900px block, which would otherwise be beaten
   by source order since this rule comes later with equal specificity). */
@media (min-width: 901px) { html, body { height: 100vh; overflow: hidden; } }
