/* Color Puzzle - atelier
   Dark workshop aesthetic: ink background, glass tubes, enamel bricks.
   Everything sizes off --brick so the board scales with one variable. */

:root {
  color-scheme: dark;

  --ink: #05080f;
  --ink-2: #0a1020;
  --panel: #101a2e;
  --panel-2: #16233c;
  --line: rgba(148, 178, 226, 0.14);
  --line-strong: rgba(148, 178, 226, 0.3);
  --text: #e6edf7;
  --muted: #8ba0c0;
  --dim: #5f7592;
  --accent: #22d3ee;
  --accent-2: #ec4899;
  --good: #34d399;
  --warn: #fbbf24;
  --bad: #fb4570;

  --font-display: "Bahnschrift", "Avenir Next Condensed", "Futura", "Trebuchet MS", "DejaVu Sans Condensed", sans-serif;
  --font-body: "Avenir Next", "Segoe UI", Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
  --font-num: "JetBrains Mono", "SF Mono", "DejaVu Sans Mono", ui-monospace, monospace;

  /* --brick is the width of a tube's contents; a brick is a flat rectangle,
     wider than tall, so a tube reads as a stacked bar rather than a tower of
     lozenges. Sized off the smaller of width and height, because a board that
     fits the width but not the fold is a board nobody sees. */
  --brick: clamp(18px, min(6.6vw, 8vh), 44px);
  --row: calc(var(--brick) * 0.58);   /* replaced at runtime by fitBoard */
  --tube-pad: 3px;
  --tube-gap: 2px;
  --row-gap: 17px;   /* room for the tube number above each row */
  --col-gap: 8px;
  --board-pad: 10px;
  --radius: 3px;
}

* { box-sizing: border-box; }

/* display:grid/flex on .overlay and .panel would otherwise beat the attribute */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  height: 100vh;   /* repli si svh non supporté (vieux iOS) -> pas de height:auto */
  height: 100svh;  /* iOS/Chrome modernes: hauteur hors barre d'adresse, le jeu tient toujours */
  overflow: hidden;
  background:
    radial-gradient(120% 80% at 50% -10%, #14213a 0%, transparent 60%),
    radial-gradient(90% 60% at 100% 100%, #1a1030 0%, transparent 55%),
    var(--ink);
  color: var(--text);
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
  overscroll-behavior: none;
}

body {
  display: flex;
  flex-direction: column;
  min-height: 0;
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
}

.grain {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 5;
  opacity: 0.05;
  mix-blend-mode: soft-light;
  background-image: 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='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ---------- header ---------- */

.top {
  display: flex;
  flex-wrap: wrap;
  gap: 14px 20px;
  align-items: center;
  justify-content: space-between;
  padding: clamp(8px, 2vw, 18px) clamp(12px, 4vw, 34px) 4px;
}

/* La marque prend toute la largeur pour que les deux icônes se calent à
   droite et que le bandeau de difficulté occupe sa propre ligne. */
.brand { display: flex; align-items: center; gap: 12px; flex: 1 1 100%; }

.top-actions { display: flex; gap: 6px; margin-left: auto; }

/* Deux boutons de chrome permanent, donc dessinés plutôt que typographiés:
   aucun glyphe unicode de graphique ou de réglages ne rend pareil d'un
   téléphone à l'autre. */
.icon-btn {
  appearance: none;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: rgba(20, 32, 54, 0.6);
  color: var(--muted);
  cursor: pointer;
  transition: color 0.18s, border-color 0.18s, background 0.18s;
}
.icon-btn:hover,
.icon-btn:focus-visible { color: var(--ink); border-color: var(--accent); background: rgba(34, 211, 238, 0.12); }
.icon-btn svg { width: 18px; height: 18px; fill: currentColor; }
.icon-btn svg.stroke { fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }

/* Le statut n'est plus affiché mais reste annoncé: sans le plateau sous les
   yeux, c'est le seul retour qu'un lecteur d'écran reçoit. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.brand-mark {
  display: flex;
  gap: 3px;
  padding: 6px 7px;
  border-radius: 12px;
  background: linear-gradient(180deg, #16233c, #0c1424);
  border: 1px solid var(--line);
  box-shadow: 0 8px 22px rgba(0, 0, 0, 0.5);
}
.brand-mark i { width: 5px; height: 22px; border-radius: 3px; display: block; }
.brand-mark i:nth-child(1) { background: #00e5ff; box-shadow: 0 0 8px rgba(0, 229, 255, 0.6); }
.brand-mark i:nth-child(2) { background: #ff2d95; box-shadow: 0 0 8px rgba(255, 45, 149, 0.6); }
.brand-mark i:nth-child(3) { background: #ffe500; box-shadow: 0 0 8px rgba(255, 229, 0, 0.6); }

.brand-text h1 {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(20px, 4.6vw, 28px);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.brand-text p {
  margin: 2px 0 0;
  font-size: 12px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}

.levels { display: flex; flex-wrap: wrap; gap: 6px; }

.chip {
  appearance: none;
  border: 1px solid var(--line);
  background: rgba(20, 32, 54, 0.6);
  color: var(--muted);
  font-family: var(--font-body);
  font-size: 12px;
  letter-spacing: 0.06em;
  padding: 7px 12px;
  border-radius: 999px;
  cursor: pointer;
  transition: color 0.18s, border-color 0.18s, background 0.18s, transform 0.12s;
}
.chip:hover { color: var(--text); border-color: var(--line-strong); transform: translateY(-1px); }
.chip:focus-visible {
  outline: none;
  color: var(--text);
  border-color: rgba(34, 211, 238, 0.85);
  box-shadow: 0 0 0 3px rgba(34, 211, 238, 0.4);
}
.chip[aria-pressed="true"] {
  color: var(--ink);
  background: linear-gradient(180deg, #7ff0ff, var(--accent));
  border-color: transparent;
  font-weight: 600;
}

/* ---------- scoreboard ---------- */

.stage {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(6px, 1.4vw, 16px);
  padding: 6px clamp(10px, 3vw, 28px) 12px;
  min-height: 0;
}

.scoreboard {
  position: relative;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1px;
  width: min(480px, 100%);
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: 16px;
  overflow: hidden;
}

.metric {
  background: linear-gradient(180deg, rgba(22, 35, 60, 0.9), rgba(11, 18, 32, 0.9));
  padding: 10px 8px 12px;
  text-align: center;
}
.metric-label {
  display: block;
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}
.metric strong {
  display: block;
  margin-top: 4px;
  font-family: var(--font-num);
  font-size: clamp(18px, 4.4vw, 24px);
  font-variant-numeric: tabular-nums;
}
.metric-main strong { color: var(--accent); }

.delta {
  margin: -10px 0 -6px;
  font-family: var(--font-num);
  font-size: 11px;
  letter-spacing: 0.04em;
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--panel-2);
  border: 1px solid var(--line);
  color: var(--muted);
  opacity: 0;
  transform: translateY(-4px);
  transition: opacity 0.2s, transform 0.2s;
}
.delta.show { opacity: 1; transform: translateY(0); }
.delta.gb { color: var(--good); border-color: rgba(52, 211, 153, 0.5); }
.delta.over { color: var(--warn); border-color: rgba(251, 191, 36, 0.45); }

/* ---------- board ---------- */

.board-wrap {
  position: relative;
  width: 100%;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.board {
  /* Hug the tubes instead of stretching: a board floating in a wide empty
     panel reads as a layout accident. */
  display: inline-grid;
  grid-template-columns: repeat(var(--cols, 6), minmax(0, auto));
  justify-content: center;
  /* Row gap sized off the brick so the tube numbers underneath always have
     room, at every viewport. */
  gap: var(--row-gap) var(--col-gap);
  padding: var(--row-gap) var(--board-pad) var(--board-pad);
  border-radius: 26px;
  background:
    linear-gradient(180deg, rgba(24, 38, 64, 0.55), rgba(8, 13, 24, 0.75));
  border: 1px solid var(--line);
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.55), inset 0 1px 0 rgba(255, 255, 255, 0.05);
}

.tube {
  --slots: 4;
  position: relative;
  width: calc(var(--brick) + var(--tube-pad) * 2);
  height: calc(
    var(--row) * var(--slots) + var(--tube-gap) * (var(--slots) - 1) + var(--tube-pad) * 2
  );
  padding: var(--tube-pad);
  /* Plain column, not column-reverse: the stack fills from the top so the
     open end, the one bricks leave and enter through, sits at the bottom
     where the hand is. */
  display: flex;
  flex-direction: column;
  gap: var(--tube-gap);
  border-radius: 7px;
  background: linear-gradient(180deg, rgba(0, 2, 8, 0.82), rgba(0, 2, 8, 0.55));
  border: 1px solid rgba(150, 180, 225, 0.22);
  box-shadow:
    inset 0 3px 8px rgba(0, 0, 0, 0.72),
    inset 0 -1px 0 rgba(255, 255, 255, 0.08),
    0 8px 20px rgba(0, 0, 0, 0.45);
  cursor: pointer;
  transition: transform 0.16s cubic-bezier(0.2, 0.9, 0.25, 1), box-shadow 0.18s, border-color 0.18s;
  -webkit-tap-highlight-color: transparent;
  /* Promeut chaque tube en couche GPU: le translateY du survol devient un
     simple compositing au lieu de forcer un reflow du plateau (mesuré: 242
     layouts -> 1 pendant un balayage de la souris). Supprime le lag au survol. */
  will-change: transform;
}
.tube::after {
  content: attr(data-index);
  position: absolute;
  left: 50%;
  top: -15px;
  transform: translateX(-50%);
  font-family: var(--font-num);
  font-size: 11px;
  color: rgba(139, 160, 192, 0.55);
}
.tube:hover { border-color: var(--line-strong); transform: translateY(-2px); }
.tube:focus-visible {
  outline: none;
  border-color: rgba(34, 211, 238, 0.85);
  box-shadow: 0 0 0 3px rgba(34, 211, 238, 0.45), inset 0 2px 6px rgba(0, 0, 0, 0.5);
}
.tube.selected {
  border-color: rgba(255, 255, 255, 0.9);
  box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.35), inset 0 3px 8px rgba(0, 0, 0, 0.6);
}
.tube.target {
  border-color: rgba(52, 211, 153, 0.85);
  box-shadow: 0 0 0 3px rgba(52, 211, 153, 0.3), 0 0 18px -4px rgba(52, 211, 153, 0.7),
    inset 0 3px 8px rgba(0, 0, 0, 0.6);
}
.tube.hinted { animation: pulse 1.1s ease-in-out 3; }
.tube.nope { animation: nope 0.32s ease; }
.tube.done {
  border-color: var(--c-halo, rgba(255, 255, 255, 0.35));
  box-shadow: 0 0 0 2px var(--c-halo, rgba(255, 255, 255, 0.2)), inset 0 3px 8px rgba(0, 0, 0, 0.6);
}
.tube.done .brick {
  box-shadow:
    inset 0 2px 0 rgba(255, 255, 255, 0.65),
    inset 0 -5px 10px rgba(0, 0, 0, 0.28),
    0 0 20px -1px var(--c-glow);
}

.brick {
  height: var(--row);
  border-radius: var(--radius);
  /* Three stops, not two: the light band across the top reads as a glazed
     surface and keeps saturated colors from flattening into blocks. */
  /* The gloss is a thin band, not half the brick: the point is to read the
     hue at a glance, and a wide white ramp desaturates exactly the colors
     that are supposed to be shouting. */
  background: linear-gradient(180deg, var(--c-light) 0%, var(--c) 26%, var(--c) 80%, var(--c-deep) 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.5),
    inset 0 -2px 5px rgba(0, 0, 0, 0.24),
    0 0 14px -1px var(--c-glow),
    0 1px 2px rgba(0, 0, 0, 0.5);
  display: grid;
  place-items: center;
  font-family: var(--font-num);
  font-size: calc(var(--row) * 0.66);
  font-weight: 800;
  letter-spacing: 0.02em;
  color: var(--c-ink);
  transition: box-shadow 0.16s, filter 0.16s;
}
.brick.lifted {
  /* Selection is a highlight, not a hop: the brick that would move lights up
     in place. Moving it twice, once to say "picked" and once to actually
     pour, reads as noise. */
  box-shadow:
    inset 0 0 0 2px rgba(255, 255, 255, 0.95),
    0 0 18px -2px var(--c-glow);
  filter: saturate(1.15) brightness(1.06);
}
.brick .tag { opacity: 0; transition: opacity 0.15s; }
/* Le réglage et la place disponible doivent être d'accord: sans la seconde
   classe (posée par fitBoard quand la brique est assez grande) la lettre
   reste cachée même si le joueur l'a activée, plutôt que de s'afficher en
   bouillie sur une brique minuscule. */
body.labels.labels-fit .brick .tag { opacity: 1; }
.brick.hidden { visibility: hidden; }

@keyframes pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(236, 72, 153, 0); }
  50% { box-shadow: 0 0 0 4px rgba(236, 72, 153, 0.35); }
}
@keyframes nope {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-5px); }
  75% { transform: translateX(5px); }
}

.flight { position: absolute; inset: 0; pointer-events: none; z-index: 4; }
.flying {
  position: fixed;
  z-index: 30;
  will-change: transform;
  border-radius: var(--radius);
  background: linear-gradient(180deg, var(--c-light) 0%, var(--c) 22%, var(--c) 74%, var(--c-deep) 100%);
  box-shadow:
    inset 0 2px 0 rgba(255, 255, 255, 0.55),
    0 0 24px 0 var(--c-glow),
    0 12px 26px rgba(0, 0, 0, 0.55);
  display: grid;
  place-items: center;
  font-family: var(--font-num);
  font-weight: 800;
  color: var(--c-ink);
}

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

.controls {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  width: min(760px, 100%);
}

.btn {
  appearance: none;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  border: 1px solid var(--line);
  background: linear-gradient(180deg, rgba(26, 40, 66, 0.9), rgba(13, 21, 36, 0.9));
  color: var(--text);
  font-family: var(--font-body);
  font-size: 13px;
  letter-spacing: 0.04em;
  padding: 10px 14px;
  border-radius: 12px;
  cursor: pointer;
  transition: transform 0.12s, border-color 0.18s, background 0.18s, opacity 0.18s;
}
.btn .ico { font-size: 14px; opacity: 0.85; }
.btn:hover { transform: translateY(-1px); border-color: var(--line-strong); }
.btn:active { transform: translateY(1px); }
.btn:focus-visible {
  outline: none;
  border-color: rgba(34, 211, 238, 0.85);
  box-shadow: 0 0 0 3px rgba(34, 211, 238, 0.4);
}
.btn:disabled { opacity: 0.4; cursor: not-allowed; transform: none; }
.btn[aria-pressed="true"] { border-color: rgba(34, 211, 238, 0.6); color: #b6f4ff; }
.btn-accent {
  background: linear-gradient(180deg, #7ff0ff, var(--accent));
  color: #05131a;
  border-color: transparent;
  font-weight: 650;
}

/* ---------- panel / footer / overlay ---------- */

/* Panneau modal, comme l'écran de fin: il flotte au-dessus du plateau au lieu
   de le pousser et de le re-layouter. */
.panel {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: grid;
  place-items: center;
  padding: 20px;
  background: rgba(3, 6, 12, 0.72);
  backdrop-filter: blur(6px);
  animation: fade 0.25s ease;
}
.panel-card {
  width: min(460px, 100%);
  max-height: 84vh;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line-strong);
  border-radius: 18px;
  background: linear-gradient(180deg, rgba(19, 30, 51, 0.96), rgba(9, 15, 27, 0.96));
  overflow: hidden;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6);
}
.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 16px;
  border-bottom: 1px solid var(--line);
}
.panel-head h2 {
  margin: 0;
  font-family: var(--font-display);
  font-size: 14px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}
.panel-body { padding: 14px 16px 18px; display: grid; gap: 10px; overflow-y: auto; }

.stat-row { display: flex; justify-content: space-between; gap: 12px; font-size: 13px; }
.stat-row span { color: var(--muted); }
.stat-row b { font-family: var(--font-num); font-weight: 600; }

.bar { height: 6px; border-radius: 999px; background: rgba(148, 178, 226, 0.14); overflow: hidden; }
.bar i { display: block; height: 100%; background: linear-gradient(90deg, var(--accent), var(--accent-2)); }

.history-list { display: grid; gap: 4px; margin-top: 2px; }
.history-row {
  display: grid;
  grid-template-columns: 1fr auto auto auto;
  gap: 8px;
  align-items: center;
  font-family: var(--font-num);
  font-size: 11px;
  color: var(--muted);
  padding: 4px 0;
  border-bottom: 1px solid rgba(148, 178, 226, 0.08);
}
.history-row .mark { color: var(--muted); }
.history-row .mark.perfect { color: var(--good); font-weight: 700; }
.empty-hint { margin: 4px 0 0; font-size: 12px; color: var(--muted); }

.pairs { display: flex; flex-wrap: wrap; gap: 6px; }
.pair {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 8px;
  border-radius: 999px;
  border: 1px solid var(--line);
  font-family: var(--font-num);
  font-size: 12px;
}
.dot { width: 10px; height: 10px; border-radius: 50%; display: inline-block; }

/* ---------- réglages ---------- */

/* Texte puis contrôle, toujours empilés: sinon un texte long fait passer le
   bouton sous le texte et un texte court le laisse à côté, d'un réglage à
   l'autre l'alignement sautait. */
.settings-row {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
}
.settings-text { margin: 0; font-size: 12px; line-height: 1.5; color: var(--muted); }
.settings-toggle { flex: 0 0 auto; }
.plus-row .settings-text strong { color: var(--fg); }
.plus-buy {
  background: linear-gradient(180deg, var(--accent), var(--accent-2));
  color: #04121b;
  font-weight: 700;
  border: none;
}
.plus-buy:disabled { opacity: 0.6; }

.link {
  appearance: none;
  background: none;
  border: 0;
  color: var(--muted);
  font-family: var(--font-body);
  font-size: 12px;
  letter-spacing: 0.08em;
  text-decoration: underline dotted;
  cursor: pointer;
}
.link:hover { color: var(--text); }
.link:focus-visible { outline: 2px solid rgba(34, 211, 238, 0.85); outline-offset: 2px; }

.overlay {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: grid;
  place-items: center;
  background: rgba(3, 6, 12, 0.72);
  backdrop-filter: blur(6px);
  animation: fade 0.25s ease;
}
@keyframes fade { from { opacity: 0; } }
.card {
  position: relative;
  width: min(420px, 90vw);
  max-height: min(94svh, 640px);
  overflow-y: auto;
  padding: 26px 24px 20px;
  border-radius: 22px;
  text-align: center;
  background: linear-gradient(180deg, #17253f, #0b1322);
  border: 1px solid var(--line-strong);
  box-shadow: 0 40px 90px rgba(0, 0, 0, 0.6);
}
.overlay-close {
  position: absolute;
  top: 10px;
  right: 12px;
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: rgba(148, 178, 226, 0.08);
  color: var(--muted);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.overlay-close:hover { background: rgba(148, 178, 226, 0.16); color: var(--fg); }
.overlay-close:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--accent); }
.card-kicker {
  margin: 0;
  font-size: 11px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--accent);
}
.card h2 {
  margin: 6px 0 4px;
  font-family: var(--font-display);
  font-size: 34px;
  letter-spacing: 0.06em;
}
.card p { margin: 0; color: var(--muted); font-size: 14px; }
.card-actions { display: flex; flex-direction: column; gap: 10px; margin-top: 20px; }
.btn-x {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  padding: 11px 16px;
  border-radius: 12px;
  border: 1px solid rgba(255, 255, 255, 0.16);
  background: #000;
  color: #fff;
  font-family: inherit;
  font-weight: 600;
  font-size: 14px;
  cursor: pointer;
  transition: background 0.15s, transform 0.12s;
}
.btn-x:hover,
.btn-x:focus-visible { background: #141414; transform: translateY(-1px); outline: none; }
.card-actions-row { display: flex; gap: 8px; justify-content: center; }
.card-actions-row .btn { flex: 1 1 0; justify-content: center; }
.win-badge {
  font-size: 46px;
  line-height: 1;
  margin: 2px 0 6px;
  animation: winpop 0.5s cubic-bezier(0.2, 1.35, 0.4, 1) both;
}
@keyframes winpop {
  from { transform: scale(0.4); opacity: 0; }
  to { transform: scale(1); opacity: 1; }
}

.card .win-time {
  margin: 4px 0 0;
  font-family: var(--font-num);
  font-size: 12px;
  color: var(--muted);
}

.score {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
  display: grid;
  gap: 7px;
}
.score-total {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 6px;
}
.score-total strong {
  font-family: var(--font-display);
  font-size: 34px;
  letter-spacing: 0.04em;
  color: var(--accent);
}
.score-total span {
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}
.score-split {
  display: flex;
  justify-content: center;
  gap: 16px;
  font-size: 12px;
  color: var(--muted);
  font-family: var(--font-num);
}
.score-split b { color: var(--text); font-weight: 700; }
.card .score-note {
  margin: 0;
  font-size: 11px;
  color: var(--dim);
  line-height: 1.35;
}
.card .score-rank {
  margin: 0;
  font-size: 13px;
  color: var(--text);
  font-weight: 600;
}
.card .score-perfect { margin: 0; font-size: 11px; color: var(--muted); }

.histogram {
  display: grid;
  gap: 3px;
  max-height: 104px;
  overflow-y: auto;
  padding: 4px 2px;
}
.histogram-row {
  display: grid;
  grid-template-columns: 24px 1fr 26px;
  align-items: center;
  gap: 6px;
  font-family: var(--font-num);
  font-size: 10px;
  color: var(--dim);
}
.histogram-row.you { color: var(--text); font-weight: 700; }
.histogram-track {
  height: 8px;
  border-radius: 999px;
  background: rgba(148, 178, 226, 0.14);
  overflow: hidden;
}
.histogram-fill {
  display: block;
  height: 100%;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
}
.histogram-row.you .histogram-fill { background: linear-gradient(90deg, #fff, var(--accent)); }
.histogram-count { text-align: right; }

.card .offline-note {
  margin: 14px 0 0;
  padding: 8px 10px;
  border-radius: 10px;
  background: rgba(251, 191, 36, 0.1);
  border: 1px solid rgba(251, 191, 36, 0.35);
  color: var(--warn);
  font-size: 12px;
}

/* ---------- règles : démonstration ---------- */

.rules-card { width: min(460px, 92vw); }
.card .rules-text { margin-top: 10px; font-size: 13px; line-height: 1.5; }

.rules-demo {
  display: grid;
  gap: 10px;
  margin: 16px 0 4px;
}
/* Les mêmes classes .tube/.brick que le plateau, mais une taille fixe: la
   démonstration ne doit rien à fitBoard() ni à la grille en cours. */
.rules-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(8px, 3vw, 16px);
  --brick: 30px;
  --row: 18px;
}
.tube-demo { cursor: default; }
.tube-demo:hover { transform: none; border-color: var(--line); }
/* La démo montre le jeu tel qu'il est par défaut, sans lettres: le
   nouveau joueur n'a pas encore activé le repère, on ne l'introduit pas ici. */
.rules-demo .brick .tag { opacity: 0; }

.rules-arrow {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  width: clamp(64px, 22vw, 96px);
  text-align: center;
}
.rules-arrow-glyph { font-family: var(--font-num); font-size: 20px; line-height: 1; font-weight: 700; }
.rules-arrow-text { font-size: 10px; line-height: 1.3; color: var(--muted); }
.rules-arrow.ok .rules-arrow-glyph { color: var(--good); }
.rules-arrow.bad .rules-arrow-glyph { color: var(--bad); }

.confetti {
  position: fixed;
  top: -12px;
  width: 8px;
  height: 14px;
  z-index: 18;
  pointer-events: none;
  border-radius: 2px;
}

@media (max-width: 900px) {
  /* Phone layout is an app, not a page: the viewport is the frame, the board
     takes whatever the chrome leaves, and nothing scrolls. The hard height
     cap itself now lives in the base html/body rule, at every width, since
     any chrome (the panel, the "mes stats" history) can grow past a
     desktop's generous min-height too. */
  :root { --row-gap: 15px; --col-gap: 6px; --board-pad: 8px; }
}

@media (max-width: 640px) {
  /* The board takes the width it can get: on a phone the limit is the screen
     edge, not a design grid. */
  :root { --brick: clamp(18px, min(12.4vw, 9vh), 46px); }

  /* Everything above the board earns its height or loses it. */
  .brand-text p { display: none; }
  .brand-text h1 { font-size: 19px; letter-spacing: 0.1em; }
  .brand-mark { padding: 4px 5px; }
  .brand-mark i { height: 17px; width: 4px; }
  .top { gap: 8px 12px; }

  /* One scrolling row instead of two wrapped ones. */
  .levels {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    -ms-overflow-style: none;
    max-width: 100%;
    padding-bottom: 2px;
    -webkit-overflow-scrolling: touch;
  }
  .levels::-webkit-scrollbar { display: none; }
  .chip { flex: 0 0 auto; padding: 6px 10px; font-size: 11px; }

  .scoreboard { grid-template-columns: repeat(4, minmax(0, 1fr)); border-radius: 12px; }
  .metric { padding: 6px 2px 8px; }
  .metric-label { font-size: 8px; letter-spacing: 0.08em; }
  .metric strong { font-size: 17px; margin-top: 2px; }
  .delta { margin: -6px 0 -4px; font-size: 10px; padding: 2px 8px; }


  .controls { gap: 6px; }
  .btn { flex: 1 1 auto; justify-content: center; padding: 8px 6px; font-size: 11px; gap: 4px; }
  .btn .ico { font-size: 12px; }

}

/* Short screens: a landscape phone has width to spare and almost no height,
   so the chrome shrinks and the board takes what is left. */
@media (max-height: 700px) {
  :root { --brick: clamp(16px, min(11vw, 8vh), 40px); }
  .delta { display: none; }
  .stage { gap: 5px; padding-bottom: 5px; padding-top: 3px; }
  .controls { gap: 5px; }
  .metric { padding: 4px 2px 5px; }
  .metric strong { font-size: 15px; }
}

@media (max-height: 480px) {
  :root { --brick: clamp(14px, min(6.2vw, 13vh), 36px); }
  .brand-text p { display: none; }
  .brand-text h1 { font-size: 16px; }
  .icon-btn { width: 28px; height: 28px; border-radius: 8px; }
  .icon-btn svg { width: 15px; height: 15px; }
  .top { padding: 3px clamp(8px, 2vw, 20px) 0; }
  .levels { padding-bottom: 0; }
  .scoreboard { width: min(420px, 100%); }
  .metric-label { font-size: 7px; }
  .metric strong { font-size: 13px; }
  .btn { padding: 6px 8px; font-size: 10px; }
  .stage { gap: 4px; padding-top: 2px; padding-bottom: 4px; }
  .board { gap: 4px; padding: calc(var(--brick) * 0.55) 8px 6px; }
  .controls { gap: 5px; }
  .scoreboard { border-radius: 10px; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; }
}

/* L'identifiant d'appareil, dans les réglages. Sélectionnable: la politique
   de confidentialité demande au joueur de le recopier pour toute demande de
   suppression, donc il doit pouvoir être copié sans le retaper. */
.device-id {
  display: block;
  margin-top: 6px;
  padding: 6px 8px;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.06);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
  letter-spacing: 0.02em;
  color: var(--dim);
  word-break: break-all;
  user-select: all;
}

/* Bouton de partage: distinct du cyan de "Nouvelle grille" pour ne pas se
   confondre, et proéminent parce que c'est le geste viral. */
/* Le partage est l'action heros de l'ecran de fin: plein, vert, pleine largeur,
   impossible a rater. Le reste (rejouer / nouvelle) passe en second, plus sobre. */
.btn-share {
  width: 100%;
  justify-content: center;
  padding: 14px 18px;
  font-size: 15px;
  font-weight: 700;
  color: #04121b;
  border: none;
  background: linear-gradient(180deg, #4ade80, #21c45d);
  box-shadow: 0 10px 24px rgba(34, 197, 94, 0.32);
}
.btn-share .ico { filter: none; }
.btn-share:hover,
.btn-share:focus-visible {
  background: linear-gradient(180deg, #5cf08e, #25d365);
  color: #04121b;
  transform: translateY(-1px);
}

/* Retour de copie quand le partage natif n'est pas disponible (desktop). */
.toast {
  position: fixed;
  left: 50%;
  bottom: calc(env(safe-area-inset-bottom) + 22px);
  transform: translate(-50%, 12px);
  z-index: 20;
  max-width: min(360px, 88vw);
  padding: 10px 16px;
  border-radius: 999px;
  background: rgba(12, 20, 36, 0.96);
  border: 1px solid var(--line-strong);
  color: var(--text);
  font-size: 13px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
  opacity: 0;
  transition: opacity 0.2s, transform 0.2s;
  pointer-events: none;
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }

/* Web bridé à une grille par jour: on cache le choix de mode, la nouvelle
   grille et le bouton du jour (redondant), et on remplace la nouvelle grille
   de fin par un message. L'atelier local et l'application ne portent pas cette
   classe, donc restent illimités. */
body.daily-only .levels,
body.daily-only #new,
body.daily-only #daily,
body.daily-only #winNext { display: none; }
.daily-done {
  margin-top: 22px;
  padding-top: 18px;
  border-top: 1px solid rgba(255, 255, 255, .09);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  text-align: center;
}
.daily-done[hidden] { display: none; } /* `display:flex` sinon écrase l'attribut hidden */
.dd-title {
  margin: 0;
  font-family: var(--font-display, "Bahnschrift", "Avenir Next Condensed", sans-serif);
  font-size: 16px;
  font-weight: 700;
  letter-spacing: .01em;
  color: var(--text);
}
.dd-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 11px;
  width: 100%;
  padding: 12px 18px;
  border-radius: 13px;
  text-decoration: none;
  background: #0c0c0e;
  border: 1px solid rgba(255, 255, 255, .16);
  color: #fff;
  transition: border-color .15s, transform .08s;
}
.dd-cta:hover, .dd-cta:focus-visible { border-color: rgba(255, 255, 255, .34); }
.dd-cta:active { transform: translateY(1px); }
.dd-cta svg { display: block; flex: none; }
.dd-cta-txt { display: flex; flex-direction: column; line-height: 1.15; text-align: left; }
.dd-cta-txt b { font-size: 15px; font-weight: 700; }
.dd-cta-txt small { font-size: 11px; color: var(--muted); letter-spacing: .03em; margin-top: 1px; }
.dd-note { margin: 0; font-size: 12.5px; color: var(--muted); }

/* ==================================================================
   RÉHABILLAGE DU CHROME (v2) - n'affecte QUE le fond, l'en-tête, le
   scoreboard et la barre d'outils. Le plateau, les tubes et les
   briques (leurs couleurs, glow, lettres, animations) ne sont PAS
   touchés: le chrome se fait discret pour que les briques brillent.
   ================================================================== */
:root{ --ui-accent:#e7c076; --ui-accent-deep:#c99f52; --ui-ink:#231b0c; }

html, body{
  background:
    radial-gradient(120% 66% at 50% 24%, #0f131c 0%, transparent 60%),
    linear-gradient(180deg, #0b0e15, #06080d 72%);
}

/* en-tête plus calme, sous-titre retiré, wordmark plus tracké */
.top{ padding: clamp(10px,2vw,18px) clamp(14px,4vw,34px) 6px; }
.brand-mark{ background:linear-gradient(180deg,#121826,#0a0e18); box-shadow:0 6px 16px rgba(0,0,0,.5); }
.brand-text h1{ letter-spacing:.22em; }
.brand-text p{ display:none; }
.icon-btn{ background:rgba(255,255,255,.03); }
.icon-btn:hover, .icon-btn:focus-visible{ color:var(--text); border-color:var(--line-strong); background:rgba(255,255,255,.06); }

/* scoreboard = 3 tuiles focus (Coups / Optimum / Temps). Série -> pop-up stats. */
.scoreboard{ grid-template-columns:repeat(3,minmax(0,1fr)); width:min(430px,100%); background:transparent; border:0; gap:10px; }
.scoreboard .metric:nth-child(4){ display:none; }
.metric{ background:rgba(255,255,255,.03); border:1px solid var(--line); border-radius:14px; }
.metric-main strong{ color:var(--text); }
.scoreboard .metric:nth-child(2) strong{ color:var(--ui-accent); }

/* barre d'outils = focus. Indice, Du jour, Écran test masqués (#daily reste
   dans le DOM pour le menu, juste caché). Reste: Annuler, Rejouer. */
#hint, #daily, #new, #previewWin{ display:none !important; }
.controls .btn{ background:rgba(255,255,255,.03); border:1px solid var(--line); }
.controls .btn:hover{ border-color:var(--line-strong); }
.btn-accent{ background:linear-gradient(180deg,var(--ui-accent),var(--ui-accent-deep)); color:var(--ui-ink); border:0; font-weight:700; }

/* pastilles de difficulté au ton neutre (accent chaud au lieu du cyan) */
.chip[aria-pressed="true"]{ background:linear-gradient(180deg,#f0e0b4,var(--ui-accent)); color:var(--ui-ink); }

/* perf: le grain en soft-light plein écran recompose à chaque frame par-dessus
   les tubes (couche GPU) et fait ramer les animations. Overlay simple, pas de
   blend -> compositing bien moins cher. */
.grain{ mix-blend-mode:normal; opacity:.03; }

/* ---- bande "Défi du jour" (mode daily / web mono-page) ---- */
.daily-band{ display:none; }
body.daily-only .daily-band{ display:flex; align-items:center; gap:12px; width:min(480px,100%); margin-bottom:2px; }
.db-streak{ appearance:none; display:inline-flex; align-items:center; gap:5px; height:38px; padding:0 11px; border-radius:11px;
  background:rgba(231,192,118,.09); border:1px solid rgba(231,192,118,.42); color:var(--ui-accent);
  font-family:var(--font-num); font-weight:600; font-size:14px; cursor:pointer; }
.db-streak svg{ width:15px; height:15px; fill:currentColor; }
.db-mid{ flex:1; text-align:center; line-height:1.05; }
.db-title{ display:block; font-family:var(--font-display); text-transform:uppercase; font-weight:700;
  letter-spacing:.10em; font-size:clamp(22px,5.6vw,34px); color:var(--ui-accent);
  text-shadow:0 0 24px rgba(231,192,118,.25); }
.db-num{ display:block; font-family:var(--font-num); font-size:12px; letter-spacing:.05em; color:var(--muted); margin-top:4px; text-transform:capitalize; }
.db-num b{ color:var(--text); font-weight:600; }
.db-store{ display:inline-flex; align-items:center; gap:7px; height:38px; padding:0 12px; border-radius:11px; text-decoration:none;
  background:#0c0c0e; border:1px solid rgba(255,255,255,.14); color:#eef1f6; font-size:12px; font-weight:600; white-space:nowrap;
  transition:border-color .15s; }
.db-store:hover{ border-color:rgba(255,255,255,.3); }
@media(max-width:560px){
  body.daily-only .daily-band{ flex-wrap:wrap; justify-content:space-between; }
  .db-mid{ order:-1; flex:1 1 100%; margin-bottom:4px; }
  .db-store-txt{ display:none; }
}

/* ---- correctifs QA (itération 2) ---- */
/* badge Play lisible partout (le texte ne disparaît plus sur mobile) */
.db-store-txt{ display:inline !important; }
body.daily-only .daily-band{ width:min(520px,100%); }
/* "DÉFI DU JOUR" tient sur une ligne */
.db-title{ white-space:nowrap; font-size:clamp(18px,4.4vw,30px); }
@media(max-width:560px){ .db-store{ font-size:11.5px; padding:0 9px; } .db-title{ font-size:20px; } }
/* en-tête serré à 320px: plus de rognage de l'icône Réglages */
@media(max-width:360px){ .top{ padding-left:8px; padding-right:8px; } .top-actions{ gap:4px; } .icon-btn{ width:31px; height:31px; } }

/* web (daily-only) = mono-page: le bouton retour-menu "‹" est un détour inutile
   (le menu n'existe que dans l'appli multi-mode). On le cache sur le web. */
body.daily-only #toMenuBtn{ display:none; }

/* ---- correctifs layout (13 août): centrage titre + resserrage vertical ---- */

/* Titre du jour TOUJOURS sur sa propre ligne (centré, pleine largeur), avec la
   série (gauche) et le badge Google Play (droite) sur une 2e ligne. Un titre
   large (EN "Daily challenge" 319px, DE "Tägliche Challenge" 390px) ne peut donc
   JAMAIS chevaucher le badge, quelle que soit la taille de l'écran: le titre
   occupe toute la largeur, il est centré, et rien ne le pousse. Robuste au
   resize (l'ancien centrage en absolu chevauchait dès que le titre dépassait la
   place entre les deux côtés). */
body.daily-only .daily-band{ display:flex !important; flex-wrap:wrap;
  align-items:center; justify-content:space-between; column-gap:12px; row-gap:8px; }
.db-streak, .db-store{ flex:none; }
.db-store svg{ display:block; }
.db-mid{ order:-1; flex:1 1 100%; text-align:center; }

/* Resserrage: le plateau flottait au centre d'un grand vide (board-wrap grandit
   via flex:1 mais les briques sont plafonnées en taille sur grand écran => 38px
   de blanc au-dessus ET en-dessous des tubes). On fait hug les tubes par
   board-wrap, et on centre tout le bloc dans la scène => distance plateau <-> barre
   d'outils / titre bornée au petit gap, plus de dérive. */
body.daily-only .stage{ justify-content:center; }

/* ---- sélecteur de langue (Réglages) ---- */
.settings-row-inline{ display:flex; align-items:center; justify-content:space-between; gap:12px; }
.settings-row-inline .settings-text{ margin:0; }
.lang-select{
  appearance:none; -webkit-appearance:none;
  background:#0c0c0e url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%239aa3b5' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E") no-repeat right 11px center;
  color:#eef1f6; border:1px solid rgba(255,255,255,.16); border-radius:10px;
  font:inherit; font-size:14px; padding:9px 32px 9px 12px; cursor:pointer; min-width:150px;
}
.lang-select:hover{ border-color:rgba(255,255,255,.32); }
.lang-select:focus-visible{ outline:2px solid var(--ui-accent); outline-offset:1px; }

/* ---- perf (itér. 2): retrait du backdrop-filter blur des overlays ----
   blur(6px) re-floute tout l'arrière-plan à CHAQUE frame tant qu'un overlay est
   ouvert. À la victoire, les confettis animent derrière => le GPU re-floute en
   continu = le lag ressenti. On retire le blur et on assombrit le fond (0.72 ->
   0.86): à l'oeil quasi identique, coût divisé. */
.overlay, .panel{ backdrop-filter:none !important; -webkit-backdrop-filter:none !important;
  background:rgba(3,6,12,0.86) !important; }

/* ---- écran COURT (Firefox laisse moins de hauteur, 1280x720, etc.): le chrome
   statique (titre du jour, scoreboard, gaps) mangeait trop de vertical, le
   plateau 4x3 ne rentrait plus et s'effondrait à 18px. On resserre le chrome
   par paliers de HAUTEUR pour garder de la place au plateau (4 colonnes intactes). */
@media (max-height: 820px) {
  body.daily-only .stage { gap: 6px; padding-top: 3px; padding-bottom: 6px; }
  body.daily-only .daily-band { row-gap: 4px; margin-bottom: 0; }
  body.daily-only .db-title { font-size: clamp(18px, 4.4vw, 24px); }
  body.daily-only .scoreboard .metric { padding: 6px 8px 8px; }
  body.daily-only .scoreboard .metric strong { font-size: clamp(17px, 4vw, 20px); }
  .top { padding-top: 6px; padding-bottom: 2px; }
}
@media (max-height: 770px) {
  body.daily-only .stage { gap: 4px; padding-top: 2px; padding-bottom: 4px; }
  body.daily-only .db-title { font-size: 18px; }
  body.daily-only .db-num { font-size: 11px; margin-top: 2px; }
  body.daily-only .daily-band { row-gap: 3px; }
  body.daily-only .scoreboard .metric { padding: 4px 6px 5px; }
  body.daily-only .scoreboard .metric strong { font-size: 16px; }
  body.daily-only .scoreboard .metric-label { font-size: 9px; }
  body.daily-only .db-streak, body.daily-only .db-store { height: 32px; }
  .top { padding-top: 4px; }
  /* Réduit aussi l'overhead vertical DU PLATEAU (espace au-dessus des rangées +
     bord): le nombre de tube reste lisible, mais le plateau 4x3 rentre sur les
     écrans très courts au lieu de s'effondrer. */
  body.daily-only { --row-gap: 11px; --board-pad: 6px; }
}
/* Écran vraiment ras (paysage mobile, mini-fenêtre): dernier cran. */
@media (max-height: 640px) {
  body.daily-only { --row-gap: 8px; --board-pad: 5px; }
  body.daily-only .stage { gap: 3px; }
  body.daily-only .daily-band { row-gap: 2px; }
}
