:root {
  --bg: #0f1729;
  --bg-soft: #1a2438;
  --card: #223049;
  --line: #32415e;
  --text: #eef2f9;
  --muted: #93a2bd;
  --accent: #4f9cf9;
  --ok: #2fbf71;
  --ok-soft: #163d2b;
  --bad: #ef4d5a;
  --bad-soft: #451c22;
  --gold: #f5c451;
  --find: #d182ff;
  --radius: 16px;
  --tap: 60px;
}

/* `display: flex` d'une règle à nous l'emporte sur le `display: none` que le
   navigateur donne à l'attribut `hidden` : une boîte cachée resterait
   visible. La règle suivante le rend inconditionnel. */
[hidden] { display: none !important; }

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

body {
  margin: 0;
  /* La pile emoji est nommée explicitement : sans elle, certains
     navigateurs ne vont pas la chercher et affichent un carré vide. */
  font: 16px/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif,
        "Noto Color Emoji", "Apple Color Emoji", "Segoe UI Emoji";
  background: var(--bg);
  color: var(--text);
  overscroll-behavior: none;
}

.screen { display: none; padding: 20px 18px 40px; max-width: 720px; margin: 0 auto; }
.screen.active { display: block; }

.title { font-size: 30px; font-weight: 800; margin: 20px 0 6px; letter-spacing: -.02em; }
.title.small { font-size: 20px; margin: 0; }
.subtitle { color: var(--muted); margin: 0 0 24px; }

.btn {
  font: inherit; font-weight: 650; color: var(--text);
  background: var(--card); border: 2px solid var(--line);
  border-radius: var(--radius); padding: 14px 20px; cursor: pointer;
  transition: transform .08s ease, background .15s ease, border-color .15s ease;
  min-height: var(--tap);
}
.btn:active { transform: scale(.97); }
.btn.primary { background: var(--accent); border-color: var(--accent); color: #071426; }
.btn.ghost { background: transparent; }
.btn.small { min-height: 44px; padding: 10px 16px; font-size: 14px; }
.btn.icon { min-height: 44px; width: 44px; padding: 0; font-size: 20px; line-height: 1;
            border: none; background: transparent; color: var(--muted); }
#sound-toggle { background: var(--card); border-radius: 10px; }

.row { display: flex; gap: 12px; margin-top: 16px; }
.row.center { justify-content: center; }

/* ---------------------------------------------------------- profils */
.profile-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 14px; }
.profile-card {
  background: var(--card); border: 2px solid var(--line); border-radius: var(--radius);
  padding: 20px 14px; text-align: center; cursor: pointer; font: inherit; color: inherit;
}
.profile-card:active { transform: scale(.97); }
.profile-card .emoji { font-size: 44px; display: block; line-height: 1.1; }
.profile-card .name { font-weight: 700; margin-top: 6px; font-size: 18px; }
.profile-card .meta { color: var(--muted); font-size: 13px; margin-top: 2px; }
.profile-card.add { border-style: dashed; color: var(--muted); }

.new-profile { margin-top: 22px; background: var(--bg-soft); padding: 18px; border-radius: var(--radius); }
.new-profile input {
  font: inherit; font-size: 20px; width: 100%; padding: 14px;
  background: var(--card); color: var(--text);
  border: 2px solid var(--line); border-radius: 12px;
}
.emoji-picker { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
.emoji-picker button {
  font-size: 26px; background: var(--card); border: 2px solid transparent;
  border-radius: 12px; width: 50px; height: 50px; cursor: pointer;
}
.emoji-picker button[aria-pressed="true"] { border-color: var(--accent); }

/* La connexion : la vignette qu'on vient de choisir, puis son mot de passe. */
.login-who { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.login-who .avatar { width: 44px; height: 44px; flex: none; }
.login-who .name { font-size: 20px; font-weight: 750; }
.new-profile label { display: block; color: var(--muted); font-size: 14px;
                     font-weight: 650; margin-bottom: 6px; }
.login-error { color: var(--bad); font-weight: 650; margin-top: 14px; }
.quitter { margin-top: 18px; gap: 10px; }

/* ---------------------------------------------------------- accueil */
.home-head { display: flex; justify-content: space-between; align-items: center; gap: 12px; }
.who { font: inherit; font-size: 20px; font-weight: 700; background: none; border: none; color: var(--text); cursor: pointer; padding: 8px 0; }
.lang-switch { display: flex; gap: 6px; }
.lang-switch button {
  font: inherit; font-size: 13px; font-weight: 700; padding: 8px 12px; cursor: pointer;
  background: var(--card); color: var(--muted); border: 2px solid transparent; border-radius: 10px;
}
.lang-switch button[aria-pressed="true"] { border-color: var(--accent); color: var(--text); }

.kpis { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; margin: 20px 0; }
@media (min-width: 620px) { .kpis { grid-template-columns: repeat(4, 1fr); } }
.kpi { background: var(--card); border-radius: 14px; padding: 14px 10px; text-align: center; }
.kpi .v { font-size: 26px; font-weight: 800; line-height: 1.1; }
.kpi .l { font-size: 12px; color: var(--muted); margin-top: 4px; }
.kpi.gold .v { color: var(--gold); }

.zones { display: flex; flex-direction: column; gap: 10px; }
.zone { background: var(--bg-soft); border-radius: 14px; padding: 12px 14px; }
.zone.locked { opacity: .45; }
.zone-top { display: flex; justify-content: space-between; font-size: 14px; font-weight: 650; }
.zone-top .n { color: var(--muted); font-weight: 500; }
.bar { height: 8px; background: var(--card); border-radius: 99px; margin-top: 8px; overflow: hidden; }
.bar > i { display: block; height: 100%; background: linear-gradient(90deg, var(--accent), var(--ok)); border-radius: 99px; transition: width .6s cubic-bezier(.2,.8,.2,1); }

.modes { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 18px; }
.mode-btn {
  font: inherit; font-weight: 650; font-size: 15px; color: var(--text); text-align: left;
  background: var(--card); border: 2px solid transparent; border-radius: 14px;
  padding: 12px 14px; cursor: pointer; min-height: 62px;
}
.mode-btn[aria-pressed="true"] { border-color: var(--accent); }
.mode-btn small { display: block; font-size: 12px; color: var(--muted); font-weight: 600; margin-top: 2px; }
.mode-btn[disabled] { opacity: .45; cursor: default; }

.btn.play { width: 100%; margin: 22px 0; font-size: 22px; padding: 22px; background: var(--ok); border-color: var(--ok); color: #04220f; }
.play-sub { display: block; font-size: 13px; font-weight: 600; opacity: .75; }

.worst { margin-top: 6px; }
.worst h3, .badges h3 { font-size: 14px; color: var(--muted); margin: 18px 0 8px; font-weight: 650; }
.worst-list { display: flex; gap: 10px; flex-wrap: wrap; }
.worst-item { display: flex; align-items: center; gap: 8px; background: var(--card); border-radius: 12px; padding: 8px 12px; font-size: 14px; }
.worst-item img { width: 30px; border-radius: 3px; }

.badges { display: block; margin-bottom: 24px; }
.badge-count { color: var(--muted); font-weight: 600; }
.badge-list { display: flex; flex-wrap: wrap; gap: 8px; }
.badge { background: var(--card); border-radius: 12px; padding: 8px 12px; font-size: 13px; }

/* ---------------------------------------------------------- jeu */
.play-head { display: flex; align-items: center; gap: 14px; }
.progress { flex: 1; height: 10px; background: var(--card); border-radius: 99px; overflow: hidden; }
.progress-bar { height: 100%; width: 0; background: var(--accent); border-radius: 99px; transition: width .35s ease; }
.qcount { font-size: 13px; color: var(--muted); font-variant-numeric: tabular-nums; min-width: 42px; }
.streak { font-size: 20px; font-weight: 800; min-width: 60px; text-align: right; }
.streak.hot { color: var(--gold); }
.streak.pop { animation: pop .4s ease; }

.prompt { display: flex; flex-direction: column; align-items: center; margin: 26px 0 30px; }
.prompt img {
  width: min(78vw, 340px); aspect-ratio: 3/2; object-fit: contain;
  border-radius: 10px; background: var(--bg-soft);
  box-shadow: 0 10px 30px rgba(0,0,0,.45);
}
.prompt img.pop { animation: pop .45s cubic-bezier(.3,1.6,.5,1); }
.prompt .name-prompt { font-size: 34px; font-weight: 800; text-align: center; line-height: 1.15; }
.prompt .name-prompt small { display: block; font-size: 18px; color: var(--muted); font-weight: 600; margin-top: 4px; }
.new-tag { margin-top: 14px; background: var(--gold); color: #2b1d00; font-weight: 800; font-size: 13px; padding: 5px 12px; border-radius: 99px; }

.options { display: grid; gap: 12px; grid-template-columns: 1fr; }
.options.flags { grid-template-columns: 1fr 1fr; }
.opt {
  font: inherit; font-weight: 650; font-size: 19px; color: var(--text);
  background: var(--card); border: 2px solid var(--line); border-radius: var(--radius);
  padding: 16px; cursor: pointer; text-align: center; min-height: var(--tap);
  transition: transform .08s, background .2s, border-color .2s;
}
.opt small { display: block; font-size: 14px; color: var(--muted); font-weight: 600; margin-top: 2px; }
.opt img { width: 100%; aspect-ratio: 3/2; object-fit: contain; border-radius: 6px; }
.opt:active { transform: scale(.97); }
.opt.right { background: var(--ok-soft); border-color: var(--ok); }
.opt.wrong { background: var(--bad-soft); border-color: var(--bad); animation: shake .4s; }
.opt[disabled] { cursor: default; }

/* Pendant l'affichage de la correction, on réserve la place de la fiche :
   sinon elle recouvre la bonne réponse, qui est précisément ce qu'il faut
   regarder à ce moment-là. */
#screen-play.with-feedback { padding-bottom: 280px; }

.feedback {
  position: fixed; inset: auto 0 0 0; background: var(--bg-soft);
  border-top: 2px solid var(--line); border-radius: 22px 22px 0 0;
  padding: 20px 18px calc(20px + env(safe-area-inset-bottom));
  animation: slide-up .28s cubic-bezier(.2,.9,.3,1); z-index: 5;
}
.feedback .fb-head { display: flex; gap: 14px; align-items: center; }
.feedback img { width: 92px; border-radius: 6px; flex: none; }
.feedback .fb-name { font-size: 24px; font-weight: 800; }
.feedback .fb-sub { color: var(--muted); font-size: 15px; }
.feedback .btn { width: 100%; margin-top: 16px; }

/* ---------------------------------------------------------- bilan */
.summary-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(100px,1fr)); gap: 12px; margin: 20px 0; }
.summary-misses .miss { display: flex; align-items: center; gap: 10px; padding: 8px 0; border-bottom: 1px solid var(--line); }
.summary-misses img { width: 40px; border-radius: 4px; }

/* ---------------------------------------------------------- pays */
.item-list { margin-top: 16px; }
.item-group { font-size: 13px; color: var(--muted); font-weight: 700; margin: 18px 0 8px; text-transform: uppercase; letter-spacing: .05em; }
.item-row { display: flex; align-items: center; gap: 12px; padding: 8px 0; border-bottom: 1px solid var(--line); }
.item-row img { width: 38px; border-radius: 3px; flex: none; }
.item-row .iname { flex: 1; font-size: 15px; }
.item-row .iname small { color: var(--muted); display: block; font-size: 13px; }
.item-row .irate { font-variant-numeric: tabular-nums; font-weight: 700; font-size: 14px; }
.item-row .ibar { width: 60px; height: 6px; background: var(--card); border-radius: 99px; overflow: hidden; flex: none; }
.item-row .ibar > i { display: block; height: 100%; background: var(--ok); }
.item-row.unseen { opacity: .5; }
.item-row .tag { font-size: 11px; color: var(--muted); border: 1px solid var(--line); border-radius: 6px; padding: 2px 6px; }

#confetti { position: fixed; inset: 0; pointer-events: none; z-index: 10; }

@keyframes pop { 0% { transform: scale(1); } 45% { transform: scale(1.14); } 100% { transform: scale(1); } }
@keyframes shake { 10%,90% { transform: translateX(-2px); } 20%,80% { transform: translateX(4px); }
                   30%,50%,70% { transform: translateX(-7px); } 40%,60% { transform: translateX(7px); } }
@keyframes slide-up { from { transform: translateY(100%); } to { transform: translateY(0); } }

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

/* ---------------------------------------------------------- carte */
.map-wrap { margin-top: 8px; }
.map-hint { text-align: center; color: var(--muted); font-size: 14px; margin-bottom: 10px; }
.map-holder { position: relative; background: #0b1220; border-radius: 14px; overflow: hidden;
              border: 2px solid var(--line); }
.map-holder svg { display: block; width: 100%; height: auto; cursor: crosshair; }
#ocean { fill: #0b1626; }
#countries path { fill: #2c3d5c; stroke: #16233a; stroke-width: .7; vector-effect: non-scaling-stroke; }
#countries path.target { fill: var(--ok); }
#countries path.mastered { fill: var(--ok); }
#countries path.learning { fill: var(--gold); }
#countries path.unseen { fill: #2c3d5c; }
.map-marker { fill: none; stroke-width: 3; vector-effect: non-scaling-stroke; }
.map-marker.click { stroke: var(--bad); }
.map-marker.truth { stroke: #fff; }
.map-line { stroke: #fff; stroke-width: 2; stroke-dasharray: 5 4; vector-effect: non-scaling-stroke; }

.progress-map { margin-top: 22px; }
.progress-map h3 { font-size: 14px; color: var(--muted); margin: 0 0 8px; font-weight: 650; }
.progress-map .map-holder { border-radius: 12px; }
.map-legend { display: flex; gap: 14px; margin-top: 8px; font-size: 12px; color: var(--muted); }
.map-legend i { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 5px; }

/* ---------------------------------------------------------- annonces */
.head-right { display: flex; align-items: center; gap: 8px; }
.toast {
  position: fixed; left: 50%; top: 22%; transform: translateX(-50%);
  background: var(--bg-soft); border: 2px solid var(--gold); border-radius: 18px;
  padding: 18px 26px; text-align: center; z-index: 20; max-width: 86vw;
  box-shadow: 0 18px 50px rgba(0,0,0,.55); animation: toast-in .4s cubic-bezier(.2,1.4,.4,1);
}
.toast .t-emoji { font-size: 44px; line-height: 1; }
.toast .t-title { font-size: 20px; font-weight: 800; margin-top: 6px; }
.toast .t-sub { color: var(--muted); font-size: 14px; margin-top: 2px; }
@keyframes toast-in { from { opacity: 0; transform: translateX(-50%) scale(.85); }
                      to { opacity: 1; transform: translateX(-50%) scale(1); } }

.worst-item { cursor: pointer; border: 2px solid transparent; }
.worst-item:active { transform: scale(.97); }
.worst-retry { margin-top: 10px; }
.opt kbd { display: none; }
@media (min-width: 700px) {
  .opt kbd { display: inline-block; font: inherit; font-size: 12px; color: var(--muted);
             border: 1px solid var(--line); border-radius: 5px; padding: 0 5px; margin-right: 8px; }
}

/* ---------------------------------------------------------- lisibilité des scores */
.profile-card .emoji.plus { font-size: 40px; font-weight: 300; }

.badge.locked { opacity: .5; }
.badge small { display: block; font-size: 11px; color: var(--muted); margin-top: 2px; }
.badge { max-width: 190px; }

.worst-item .wl { font-variant-numeric: tabular-nums; font-size: 13px; color: var(--muted); }
.worst-item .wl span { opacity: .6; }

.rule {
  color: var(--muted); font-size: 13px; line-height: 1.5;
  background: var(--bg-soft); border-radius: 12px; padding: 12px 14px; margin: 14px 0 4px;
}
.item-row .cstate { display: flex; flex-direction: column; align-items: flex-end; gap: 5px; flex: none; }
.pill { font-size: 11px; font-weight: 700; padding: 3px 8px; border-radius: 99px;
        background: var(--card); color: var(--muted); white-space: nowrap; }
.pill.ok { background: var(--ok-soft); color: #6ee7a6; }
.pill.go { background: #2a3350; color: var(--text); }
.item-row.unseen { opacity: .55; }
.item-row .irate { min-width: 52px; text-align: right; }
.item-row .irate span { color: var(--muted); font-weight: 500; }
.item-row .iname .tag { margin-left: 6px; }

/* ---------------------------------------------------------- suivi */
.bottom-actions { margin-top: 0; }
.bottom-actions .btn { flex: 1; }

.mistakes h3, .session-list h3 { font-size: 14px; color: var(--muted); margin: 18px 0 8px; font-weight: 650; }
.mistake {
  display: flex; align-items: center; gap: 12px; background: var(--bg-soft);
  border-radius: 12px; padding: 10px 12px; margin-bottom: 8px;
}
.mistake img { width: 44px; border-radius: 4px; flex: none; }
.mistake .m-txt { font-size: 14px; line-height: 1.45; }
.mistake .m-wrong { color: var(--bad); font-weight: 700; }
.mistake .m-right { color: #6ee7a6; font-weight: 700; }
.mistake .m-n { margin-left: auto; color: var(--muted); font-size: 13px; white-space: nowrap; }

.session-row {
  display: flex; align-items: center; gap: 12px; width: 100%; text-align: left;
  font: inherit; color: inherit; background: var(--card); border: none;
  border-radius: 12px; padding: 12px 14px; margin-bottom: 8px; cursor: pointer;
}
.session-row:active { transform: scale(.99); }
.session-row .s-date { font-size: 14px; font-weight: 650; }
.session-row .s-mode { font-size: 12px; color: var(--muted); }
.session-row .s-score { margin-left: auto; font-size: 18px; font-weight: 800;
                        font-variant-numeric: tabular-nums; }
.session-row .s-score small { font-size: 12px; color: var(--muted); font-weight: 600; }
.session-row.good .s-score { color: #6ee7a6; }
.session-row.bad .s-score { color: var(--bad); }

.session-detail .ans { display: flex; align-items: center; gap: 10px; padding: 9px 4px;
                       border-bottom: 1px solid var(--line); font-size: 14px; }
.session-detail .ans img { width: 36px; border-radius: 3px; flex: none; }
.session-detail .ans .mark { width: 22px; font-size: 16px; flex: none; text-align: center; }
.session-detail .ans .a-name { flex: 1; }
.session-detail .ans .a-name em { display: block; font-style: normal; font-size: 12px; color: var(--bad); }
.session-detail .ans .a-ms { color: var(--muted); font-size: 12px; font-variant-numeric: tabular-nums; }
.empty { color: var(--muted); font-size: 14px; padding: 20px 0; text-align: center; }

.filters { display: flex; gap: 8px; flex-wrap: wrap; margin: 12px 0 4px; }
.filters button {
  font: inherit; font-size: 13px; font-weight: 650; color: var(--muted);
  background: var(--card); border: 2px solid transparent; border-radius: 10px;
  padding: 8px 12px; cursor: pointer; min-height: 40px;
}
.filters button[aria-pressed="true"] { border-color: var(--accent); color: var(--text); }
.filters button span { opacity: .6; margin-left: 4px; }

/* ---------------------------------------------------------- icônes dessinées */
.ic { width: 1em; height: 1em; display: block; }
.profile-card .avatar .ic { width: 52px; height: 52px; margin: 0 auto; }
.profile-card.add .avatar .ic { width: 34px; height: 34px; color: var(--muted); }
.who .ic { width: 26px; height: 26px; }
.who { display: flex; align-items: center; gap: 8px; }
.emoji-picker button .ic { width: 32px; height: 32px; margin: 0 auto; }
.badge .ic { width: 22px; height: 22px; float: left; margin: 1px 8px 0 0; }
.streak .ic { width: 20px; height: 20px; display: inline-block; vertical-align: -3px; }
.zone-top .ic { width: 14px; height: 14px; display: inline-block; vertical-align: -2px;
                margin-right: 4px; color: var(--muted); }
.toast .t-emoji .ic { width: 46px; height: 46px; margin: 0 auto; }
.mode-btn .ic { width: 14px; height: 14px; display: inline-block; vertical-align: -2px;
                margin-right: 4px; color: var(--muted); }

.pill .ic { width: 11px; height: 11px; display: inline-block; vertical-align: -1px;
            margin: 0 3px; }
.session-detail .ans .mark .ic { width: 15px; height: 15px; margin: 0 auto; }
.session-detail .ans .mark.ok { color: #6ee7a6; }
.session-detail .ans .mark.ko { color: var(--bad); }

/* ---------------------------------------------------------- musique */
.music { display: flex; align-items: center; gap: 10px; margin-top: 16px;
         background: var(--bg-soft); border-radius: 14px; padding: 10px 12px; }
.music .m-label { font-size: 13px; color: var(--muted); font-weight: 650; flex: none; }
.music select {
  font: inherit; font-size: 14px; font-weight: 650; color: var(--text);
  background: var(--card); border: 2px solid var(--line); border-radius: 10px;
  padding: 9px 10px; flex: 1; min-height: 44px;
}
.music input[type="range"] { flex: 1; min-width: 70px; accent-color: var(--accent); }
.music .btn.icon { flex: none; background: var(--card); border-radius: 10px; }
.music .ic { width: 18px; height: 18px; }

/* ---------------------------------------------------------- état par mode */
.kpi .l.sub { font-size: 11px; opacity: .75; margin-top: 1px; }

.mode-filter { margin-top: 12px; }
.mode-filter select {
  font: inherit; font-size: 14px; font-weight: 650; color: var(--text); width: 100%;
  background: var(--card); border: 2px solid var(--line); border-radius: 10px;
  padding: 10px; min-height: 44px;
}
.item-row .cdots { display: flex; gap: 4px; flex: none; }
.cdots .dot, .dot-legend .dot, .map-legend .dot, .study-row .dot {
  width: 8px; height: 8px; border-radius: 50%; background: #3a4a66; display: block;
}
.cdots .dot.learning, .dot-legend .dot.learning, .map-legend .dot.learning,
.study-row .dot.learning { background: var(--gold); }
.cdots .dot.mastered, .dot-legend .dot.mastered, .map-legend .dot.mastered,
.study-row .dot.mastered { background: var(--ok); }
.dot-legend { display: flex; flex-wrap: wrap; gap: 12px; margin: 10px 0 2px;
              font-size: 11px; color: var(--muted); }
.dot-legend span { display: flex; align-items: center; gap: 5px; }

/* ---------------------------------------------------------- navigation carte */
.map-holder { touch-action: none; }
.map-tools { position: absolute; right: 8px; bottom: 8px; display: flex;
             flex-direction: column; gap: 6px; z-index: 2; }
.map-tools .btn.icon {
  width: 40px; height: 40px; min-height: 40px; background: rgba(15,23,41,.85);
  border: 1px solid var(--line); border-radius: 10px; color: var(--text);
  display: flex; align-items: center; justify-content: center;
}
.map-tools .ic { width: 20px; height: 20px; }
.map-holder svg { cursor: grab; }
.map-holder.dragging svg { cursor: grabbing; }

/* ---------------------------------------------------------- récompenses */
.fam { background: var(--bg-soft); border-radius: 12px; padding: 10px 12px; margin-bottom: 8px; }
.fam-head { display: flex; align-items: center; gap: 8px; font-size: 13px;
            font-weight: 650; color: var(--text); }
.fam-head .ic { width: 18px; height: 18px; flex: none; }
.fam-head span { flex: 1; }
.fam-head b { color: var(--muted); font-weight: 600; font-size: 12px; }
.tiers { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
.tier {
  font-size: 12px; font-weight: 700; padding: 4px 9px; border-radius: 8px;
  background: var(--card); color: #55688a; border: 1.5px solid transparent;
  font-variant-numeric: tabular-nums;
}
.tier.on { background: var(--ok-soft); color: #6ee7a6; }
.tier.next { border-color: var(--accent); color: var(--text); }
.tier-left { display: block; font-size: 11px; color: var(--muted); margin-top: 6px; }
.tier-left.done { color: #6ee7a6; }

.worst-item .wn small { display: block; font-size: 11px; color: var(--muted); }
.worst-item { align-items: flex-start; }

/* ---------------------------------------------------------- choix du jeu */
/* Trois colonnes sur un écran d'ordinateur, une seule quand la fenêtre est
   étroite : dix-huit vignettes en une colonne feraient deux mètres. */
#screen-subjects { max-width: 1000px; }
.subject-grid { display: grid; gap: 14px;
                grid-template-columns: repeat(auto-fill, minmax(290px, 1fr)); }
.game-section + .game-section { margin-top: 26px; }
.cat-title { font-size: 13px; font-weight: 750; letter-spacing: .05em;
             text-transform: uppercase; color: var(--muted); margin: 0 0 10px; }
.recent-games { margin-bottom: 28px; }
.recent-row { display: flex; gap: 10px; flex-wrap: wrap; }
.recent-card {
  display: flex; align-items: center; gap: 10px; font: inherit; color: inherit;
  background: var(--bg-soft); border: 2px solid var(--line); border-radius: 99px;
  padding: 5px 18px 5px 5px; cursor: pointer; transition: border-color .15s ease;
}
.recent-card:hover { border-color: var(--accent); }
.recent-card .art, .recent-card .art .ic { width: 40px; height: 40px; flex: none; }
.recent-card .r-name { font-weight: 700; }
.subject-card {
  display: flex; align-items: center; gap: 16px; width: 100%; text-align: left;
  font: inherit; color: inherit; background: var(--card);
  border: 2px solid var(--line); border-radius: var(--radius);
  padding: 16px; cursor: pointer;
  transition: transform .08s ease, border-color .15s ease;
}
.subject-card:hover { border-color: var(--accent); }
.subject-card:active { transform: scale(.99); }
.subject-card .art { width: 68px; height: 68px; flex: none; }
.subject-card .art .ic { width: 68px; height: 68px; }
a.subject-card { text-decoration: none; }
.subject-card .art .logo { display: block; width: 68px; height: 68px; border-radius: 14px; }
.subject-card .s-name { display: block; font-size: 19px; font-weight: 750; }
.subject-card .s-sub { display: block; font-size: 13px; color: var(--muted); margin-top: 2px; }
.subject-card .s-prog { font-size: 13px; color: var(--muted); margin-top: 8px;
                        display: flex; gap: 14px; flex-wrap: wrap; }
.subject-card .s-prog b { color: var(--text); font-variant-numeric: tabular-nums; }
.subject-card[disabled] { opacity: .5; cursor: default; }
.subject-card[disabled]:hover { border-color: var(--line); }
.soon { font-size: 11px; font-weight: 700; background: var(--bg-soft);
        color: var(--muted); border-radius: 99px; padding: 3px 9px; }
.home-head #back-subjects { flex: none; }

/* ---------------------------------------------------------- départements */
.num-prompt {
  font-size: 92px; font-weight: 800; letter-spacing: -.03em; line-height: 1;
  color: var(--text); font-variant-numeric: tabular-nums;
  background: var(--bg-soft); border-radius: 20px; padding: 18px 34px;
}
.name-prompt small { display: block; font-size: 18px; color: var(--muted);
                     font-weight: 600; margin-top: 4px; }
.num-opt { font-size: 26px; font-weight: 800; font-variant-numeric: tabular-nums; }
#departments path { fill: #2c3d5c; stroke: #16233a; stroke-width: .5;
                    vector-effect: non-scaling-stroke; }
#departments path.target { fill: var(--ok); }
#departments path.mastered { fill: var(--ok); }
#departments path.learning { fill: var(--gold); }

.num-chip {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 38px; height: 26px; padding: 0 7px; flex: none;
  background: var(--card); border: 1px solid var(--line); border-radius: 7px;
  font-size: 14px; font-weight: 700; color: var(--text);
  font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------- calcul */
.calc-prompt {
  font-size: 58px; font-weight: 800; letter-spacing: -.01em; line-height: 1.1;
  color: var(--text); font-variant-numeric: tabular-nums; text-align: center;
  background: var(--bg-soft); border-radius: 20px; padding: 22px 34px;
}
.options.answer-input { grid-template-columns: 1fr auto; align-items: stretch; }
#answer-field {
  font: inherit; font-size: 38px; font-weight: 800; text-align: center;
  color: var(--text); background: var(--card);
  border: 2px solid var(--line); border-radius: var(--radius); padding: 10px 16px;
  font-variant-numeric: tabular-nums; min-height: var(--tap); width: 100%;
}
#answer-field:focus { outline: none; border-color: var(--accent); }
#answer-field.right { border-color: var(--ok); background: var(--ok-soft); }
#answer-field.wrong { border-color: var(--bad); background: var(--bad-soft);
                      animation: shake .4s; }
#answer-field::placeholder { color: #47597a; font-weight: 600; }
.options.truefalse { grid-template-columns: 1fr 1fr; }
.opt.tf { display: flex; align-items: center; justify-content: center; gap: 10px;
          font-size: 22px; }
.opt.tf .ic { width: 24px; height: 24px; }
.opt.tf.yes { color: #6ee7a6; }
.opt.tf.no { color: #ff9aa2; }
.fb-visual { width: 92px; }

/* ------------------------------------------------------ administration */
.title.small { font-size: 22px; margin: 0; }
.admin-titre { color: var(--muted); font-size: 14px; font-weight: 700;
               text-transform: uppercase; letter-spacing: .05em;
               margin: 22px 0 8px; }
.admin-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
             padding: 10px 0; border-bottom: 1px solid var(--line); }
.admin-row .avatar { width: 34px; height: 34px; flex: none; }
.admin-who { flex: 1; min-width: 140px; }
.admin-who small { display: block; color: var(--muted); font-size: 13px; }
.admin-actions { display: flex; gap: 6px; flex-wrap: wrap; }
.admin-form { flex-basis: 100%; display: flex; gap: 8px; align-items: center;
              flex-wrap: wrap; padding: 8px 0 2px; }
.admin-input { font: inherit; background: var(--card); color: var(--text);
               border: 2px solid var(--line); border-radius: 10px;
               padding: 8px 12px; min-width: 200px; }
.admin-msg { color: var(--muted); font-size: 14px; }
.admin-msg.ok { color: var(--ok); }
.admin-vide { color: var(--muted); }
.tag { font-size: 11px; font-weight: 700; color: var(--muted);
       border: 1px solid var(--line); border-radius: 6px; padding: 2px 6px;
       margin-left: 6px; text-transform: uppercase; letter-spacing: .04em; }
.tag.admin { color: var(--gold); border-color: var(--gold); }

/* ------------------------------------------------------ scores */
#open-scores { margin-top: 18px; }
.score-subjects { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px;
                  margin: 12px 0 18px; }
@media (min-width: 620px) { .score-subjects { grid-template-columns: repeat(4, 1fr); } }
.score-subject {
  display: flex; align-items: center; gap: 8px; text-align: left;
  font: inherit; font-size: 13px; font-weight: 650; color: var(--muted);
  background: var(--card); border: 2px solid transparent; border-radius: 12px;
  padding: 6px 10px; cursor: pointer; min-height: 48px;
}
.score-subject:hover { color: var(--text); }
.score-subject[aria-pressed="true"] { border-color: var(--accent); color: var(--text); }
.score-subject .art .ic { width: 32px; height: 32px; }
.score-list { display: flex; flex-direction: column; gap: 8px; }
.score-row {
  display: flex; align-items: center; gap: 12px; width: 100%; text-align: left;
  font: inherit; color: inherit; background: var(--bg-soft);
  border: 2px solid transparent; border-radius: 14px; padding: 10px 14px;
  cursor: pointer;
}
.score-row:hover { border-color: var(--line); }
.score-row.me { border-color: var(--accent); }
.score-rank { width: 26px; flex: none; text-align: center; font-size: 20px;
              font-weight: 800; color: var(--muted); font-variant-numeric: tabular-nums; }
.score-row:first-child .score-rank { color: var(--gold); }
.score-row .avatar .ic { width: 38px; height: 38px; }
.score-who { flex: 1; min-width: 0; }
.score-who small { display: block; color: var(--muted); font-size: 12px; }
.score-main { flex: none; text-align: right; }
.score-main b { display: block; font-size: 22px; font-weight: 800; line-height: 1.1;
                font-variant-numeric: tabular-nums; }
.score-main b span { font-size: 13px; color: var(--muted); font-weight: 600; }
.score-main small { color: var(--muted); font-size: 11px; }

.player-who { display: flex; align-items: center; gap: 10px; flex: 1; }
.player-who .ic { width: 34px; height: 34px; }
.player-subject { background: var(--bg-soft); border-radius: 14px; padding: 12px 14px;
                  margin-top: 14px; }
.ps-head { display: flex; align-items: center; gap: 10px; font-size: 17px; }
.ps-head .art .ic { width: 36px; height: 36px; }
.player-subject .kpis { margin: 12px 0 8px; }
.player-subject .kpi { background: var(--card); }
.player-subject .kpi .sur { font-size: 14px; color: var(--muted); }
.ps-line { color: var(--muted); font-size: 13px; margin: 4px 0 0; }
.ps-line b { color: var(--text); }
.player-subject .tier .ic { width: 14px; height: 14px; display: inline-block;
                           vertical-align: -2px; margin-right: 4px; }

/* ---------------------------------------------------------- additions */
/* Les boîtes de dix : dix cases, deux moitiés de cinq séparées par un
   intervalle — c'est ce qui rend le complément visible sans compter. La
   taille des cases suit le nombre de boîtes à montrer, de deux à dix. */
.sum-view { display: flex; flex-direction: column; align-items: center;
            gap: 12px; --cell: 32px; }
.sum-line { display: flex; align-items: center; justify-content: center;
            gap: 18px; flex-wrap: wrap; }
.term { display: flex; flex-direction: column; align-items: center; gap: 10px; }
.term-n { font-size: 44px; font-weight: 800; line-height: 1;
          font-variant-numeric: tabular-nums; }
.boxes { display: flex; gap: 9px; flex-wrap: wrap; justify-content: center;
         max-width: calc(var(--cell) * 20); }
/* Passé six boîtes, les deux nombres ne tiennent plus côte à côte : on les
   empile, comme une addition posée. */
.sum-line.stack { flex-direction: column; gap: 10px; }
.tenbox {
  display: grid; grid-template-columns: repeat(5, var(--cell));
  gap: calc(var(--cell) * .38) calc(var(--cell) * .16);
  padding: calc(var(--cell) * .22); background: #fdfdfd;
  border: 2px solid var(--accent); border-radius: 10px;
}
.tenbox.full { border-color: var(--ok); }
.tenbox.done { animation: pop .5s; box-shadow: 0 0 0 4px rgba(47, 191, 113, .35); }
.tenbox.spent { opacity: .3; }
.cell { width: var(--cell); height: var(--cell); border-radius: 5px;
        background: #dfe7f3; display: grid; place-items: center; }
.dot { width: calc(var(--cell) * .78); height: calc(var(--cell) * .78);
       border-radius: 50%; background: var(--gold); position: relative;
       z-index: 2; }
.dot.moving { background: var(--ok);
              box-shadow: 0 0 0 4px rgba(47, 191, 113, .35); }
.sum-op { font-size: 34px; font-weight: 800; color: var(--muted); }
.sum-total { font-size: 48px; font-weight: 800; color: var(--ok);
             font-variant-numeric: tabular-nums; }
.sum-steps { font-size: 26px; font-weight: 750; color: var(--gold);
             min-height: 32px; font-variant-numeric: tabular-nums; }
.sum-end { display: flex; align-items: center; gap: 14px; }

/* ---------------------------------------------------- le compte est bon */
.cd-head { display: flex; flex-direction: column; align-items: center; gap: 10px;
           width: 100%; }
.cd-target { font-size: 66px; font-weight: 800; line-height: 1; color: var(--gold);
             font-variant-numeric: tabular-nums; }
.cd-hint { color: var(--muted); font-size: 15px; font-weight: 600; }
.cd-clock { display: flex; align-items: center; gap: 10px;
            width: min(420px, 100%); }
.cd-bar { flex: 1; height: 9px; background: var(--bg-soft); border-radius: 99px;
          overflow: hidden; }
.cd-bar i { display: block; height: 100%; background: var(--accent);
            border-radius: 99px; transition: width .25s linear; }
/* « 10:00 » doit tenir sans pousser la barre. */
.cd-time { font-variant-numeric: tabular-nums; font-weight: 750;
           color: var(--muted); min-width: 58px; text-align: right; }
.cd-clock.low .cd-bar i, .cd-clock.low .cd-time { background: var(--bad);
                                                  color: var(--bad); }
.cd-clock.low .cd-time { background: none; }

.options.board { display: block; }
.cd-plates { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; }
.plate {
  font: inherit; font-size: 26px; font-weight: 800; min-width: 78px;
  padding: 12px 14px; border-radius: 14px; cursor: pointer; color: var(--text);
  background: var(--card); border: 2px solid var(--line);
  font-variant-numeric: tabular-nums;
}
/* Une plaque obtenue par un calcul se distingue de celles du tirage. */
.plate.made { border-color: var(--accent); }
.plate.sel { border-color: var(--gold); color: var(--gold); }
.plate.used { opacity: .22; cursor: default; }
.plate.fresh { animation: pop .45s; }
.cd-ops { display: flex; gap: 10px; justify-content: center; margin-top: 12px; }
.cd-ops button {
  font: inherit; font-size: 26px; font-weight: 800; width: 64px; height: 54px;
  border-radius: 12px; cursor: pointer; color: var(--text);
  background: var(--card); border: 2px solid var(--line);
}
.cd-ops button.sel { border-color: var(--gold); color: var(--gold); }
.cd-line { display: flex; gap: 10px; margin-top: 14px; }
#cd-input {
  flex: 1; font: inherit; font-size: 26px; font-weight: 800; text-align: center;
  color: var(--text); background: var(--card); border: 2px solid var(--line);
  border-radius: var(--radius); padding: 8px 14px; min-height: var(--tap);
  font-variant-numeric: tabular-nums; min-width: 0;
}
#cd-input:focus { outline: none; border-color: var(--accent); }
#cd-input::placeholder { color: #47597a; font-weight: 600; }
.cd-line .btn { flex: none; padding: 10px 16px; }
.cd-steps { margin-top: 14px; display: flex; flex-direction: column; gap: 3px;
            align-items: center; }
.cd-step { font-size: 19px; font-weight: 700; color: var(--muted);
           font-variant-numeric: tabular-nums; }
.cd-step:last-child { color: var(--text); }
.cd-msg { min-height: 22px; margin-top: 8px; text-align: center;
          font-weight: 650; color: var(--bad); }
.cd-msg.good { color: var(--ok); }

/* ---------------------------------------------------------- vitesse */
.chrono {
  font-size: 15px; font-weight: 750; font-variant-numeric: tabular-nums;
  min-width: 46px; text-align: right; color: var(--muted);
}
.chrono.fast { color: #6ee7a6; }
.chrono.ok { color: var(--gold); }
.chrono.slow { color: #ff9aa2; }

.speed { margin-top: 22px; }
.speed h3 { font-size: 14px; color: var(--muted); margin: 0 0 8px; font-weight: 650; }
.speed-kpis { grid-template-columns: repeat(4, 1fr); margin: 0 0 12px; }
.speed-kpis .kpi { padding: 10px 6px; }
.speed-kpis .kpi .v { font-size: 20px; }
.speed-kpis .kpi.good .v { color: #6ee7a6; }
.chart { position: relative; background: var(--bg-soft); border-radius: 14px;
         padding: 10px 12px; }
.chart svg { display: block; width: 100%; height: 96px; }
.chart-axis { position: absolute; top: 10px; right: 12px; bottom: 10px;
              display: flex; flex-direction: column; justify-content: space-between;
              font-size: 11px; color: var(--muted); pointer-events: none; }
.chart-note { font-size: 11px; color: var(--muted); line-height: 1.45; margin: 8px 2px 0; }

.num-prompt.small { font-size: 34px; padding: 10px 16px; border-radius: 12px; flex: none; }

/* ---------------------------------------------------------- horloge */
.clock { display: block; width: 100%; height: auto; }
.clock.big { width: min(62vw, 260px); margin: 0 auto; }
.opt .clock { max-width: 150px; margin: 0 auto; }

.opt { position: relative; }
.opt kbd.kbd-over { position: absolute; top: 6px; left: 8px; margin: 0; }

/* ---------------------------------------------------------- étude */
.screen.wide { max-width: 1180px; }
#study-search {
  font: inherit; font-size: 14px; color: var(--text); background: var(--card);
  border: 2px solid var(--line); border-radius: 10px; padding: 8px 12px;
  min-width: 160px; max-width: 260px;
}
#study-search:focus { outline: none; border-color: var(--accent); }

.progress-map { position: relative; }
/* Une icône seule ne disait pas ce qu'elle faisait : le libellé
   l'accompagne. Le bouton se posait sur le bord de la carte, ce qui ne
   marchait que pour les matières qui en ont une — il suit désormais « Jouer »
   partout, aussi large et moins haut que lui. */
#open-study {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; margin: -8px 0 22px; padding: 12px 20px; min-height: 46px;
  background: var(--card); border: 2px solid var(--line);
  border-radius: var(--radius); font-size: 16px; font-weight: 650;
  color: var(--text);
}
#open-study:hover { border-color: var(--accent); }
#open-study .ic { width: 20px; height: 20px; color: var(--accent); }

.stars { display: inline-flex; gap: 2px; vertical-align: -2px; margin-left: 4px; }
.stars .ic { width: 13px; height: 13px; color: var(--gold); }

.study-grid { display: grid; grid-template-columns: 1fr; gap: 16px; margin-top: 14px; }
@media (min-width: 860px) { .study-grid { grid-template-columns: 1.6fr 1fr; } }
.study-map .map-holder { min-height: 320px; }
.study-map svg { cursor: pointer; }
.study-side { display: flex; flex-direction: column; gap: 12px; min-width: 0; }

.study-card { background: var(--bg-soft); border-radius: 14px; padding: 14px; }
.study-card.empty-card { color: var(--muted); font-size: 14px; }
.study-card .sc-head { display: flex; gap: 12px; align-items: center; }
.study-card .sc-head img { width: 132px; border-radius: 6px; flex: none; }
.study-card .sc-head .num-chip { min-width: 76px; height: 52px; font-size: 26px;
                                 border-radius: 10px; }
.study-card .sc-name { font-size: 21px; font-weight: 800; line-height: 1.15; }
.study-card .sc-sub { color: var(--muted); font-size: 14px; }
.study-card .sc-line { font-size: 14px; margin-top: 6px; }
.study-card .sc-line b { font-weight: 700; }
.study-card h4 { font-size: 12px; color: var(--muted); font-weight: 650;
                 margin: 12px 0 6px; }
.sc-conf { display: flex; flex-wrap: wrap; gap: 8px; }
.sc-conf button {
  display: flex; align-items: center; gap: 7px; font: inherit; font-size: 13px;
  color: var(--text); background: var(--card); border: 1px solid var(--line);
  border-radius: 10px; padding: 5px 9px; cursor: pointer;
}
/* C'est ici que la comparaison se joue : deux drapeaux qu'on confond ne se
   distinguent pas en vignette. */
.sc-conf img { width: 44px; border-radius: 4px; }
.sc-conf .num-chip { min-width: 42px; height: 28px; }

.study-list { overflow-y: auto; max-height: 460px; display: flex;
              flex-direction: column; gap: 3px; }
.study-row {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  font: inherit; font-size: 14px; color: inherit; background: none; border: none;
  border-radius: 9px; padding: 7px 8px; cursor: pointer;
}
.study-row:hover { background: var(--card); }
.study-row[aria-current="true"] { background: var(--card);
                                  box-shadow: inset 0 0 0 2px var(--accent); }
.study-row img { width: 45px; border-radius: 4px; flex: none; }
.study-row .num-chip { min-width: 45px; height: 30px; font-size: 15px; }
.study-row .sr-name { flex: 1; min-width: 0; overflow: hidden;
                      text-overflow: ellipsis; white-space: nowrap; }
.study-row .dot { width: 8px; height: 8px; border-radius: 50%; flex: none;
                  background: #3a4a66; }
.study-row .dot.learning { background: var(--gold); }
.study-row .dot.mastered { background: var(--ok); }
.study-row.off-map .sr-name { font-style: italic; }
.study-group { font-size: 11px; color: var(--muted); font-weight: 700;
               text-transform: uppercase; letter-spacing: .05em;
               margin: 10px 0 2px; padding: 0 8px; }
.study-revise { width: 100%; margin-top: 16px; }

/* La recherche a sa propre couleur : le jaune servait déjà à « en cours ».
   La sélection vient après, pour rester visible parmi les résultats. */
#countries path.hit, #departments path.hit { fill: var(--find); }
#countries path.picked, #departments path.picked { fill: var(--accent); }

/* Ce qui n'apparaît pas sur la carte — départements d'outre-mer, micro-États
   trop petits pour être visés — se retrouve juste en dessous. */
.off-map-row { display: flex; flex-wrap: wrap; gap: 7px; align-items: center;
               margin-top: 10px; }
.off-map-row .om-label { font-size: 12px; color: var(--muted); font-weight: 650; }
.off-map-row button {
  display: flex; align-items: center; gap: 6px; font: inherit; font-size: 13px;
  color: var(--text); background: var(--card); border: 1px solid var(--line);
  border-radius: 9px; padding: 4px 9px; cursor: pointer;
}
.off-map-row button[aria-current="true"] { border-color: var(--accent); }
.off-map-row img { width: 24px; border-radius: 3px; }

.map-legend .dot.hit, .study-row .dot.hit { background: var(--find); }
.map-legend .found { color: var(--find); font-weight: 650; }

/* ---------------------------------------------------------- braille */

/* Les six positions sont toujours dessinées : un point seul en bas à droite
   ne se distingue pas d'un point seul en bas à gauche sans repère. Franches
   pendant les deux premières étapes, elles s'effacent ensuite — retirer
   l'aide est une étape d'apprentissage, comme retirer les boîtes de dix. */
.bword { display: inline-flex; align-items: center; gap: .28em; }
.bcell { display: block; width: 34px; height: auto; flex: none; }
.bd.on { fill: var(--gold); }
.bd.off { fill: var(--muted); opacity: .16; }
.bd.off.guide { fill: none; stroke: var(--line); stroke-width: 4; opacity: 1; }

.prompt .bword.big { gap: .22em; flex-wrap: wrap; justify-content: center;
                     max-width: 100%; }
/* Une cellule seule est l'énoncé tout entier : elle se lit de loin. Un mot
   long tient sur la ligne en rapetissant plutôt qu'en débordant. */
.prompt .bword.big .bcell { width: min(26vw, 118px); }
.prompt .bword.big:has(.bcell:nth-child(3)) .bcell { width: min(18vw, 84px); }
.prompt .bword.big:has(.bcell:nth-child(5)) .bcell { width: min(13vw, 62px); }
.prompt .bword.big:has(.bcell:nth-child(7)) .bcell { width: min(11vw, 48px); }
.bw-task { font-size: 13px; color: var(--muted); font-weight: 700;
           text-transform: uppercase; letter-spacing: .05em; margin-bottom: 6px; }

.opt .bword { justify-content: center; }
.opt .bword .bcell { width: min(13vw, 52px); }
.bword.tiny .bcell { width: 18px; }
.bword.mid .bcell { width: 30px; }
.feedback .bword.mid .bcell { width: 42px; }
.miss .bword, .worst-item .bword { flex: none; }

/* Composer plutôt que reconnaître. La cellule en cours est encadrée : au
   clavier, rien d'autre ne dit où le prochain point va se poser. */
.options.braille-write { grid-template-columns: 1fr; justify-items: center; }
.bw-board {
  display: flex; flex-wrap: wrap; justify-content: center; gap: 10px;
  padding: 14px; border-radius: var(--radius); background: var(--bg-soft);
  border: 2px solid var(--line); cursor: pointer;
}
.bw-board:focus { outline: none; border-color: var(--accent); }
.bw-board.right { border-color: var(--ok); background: var(--ok-soft); }
.bw-board.wrong { border-color: var(--bad); background: var(--bad-soft); }
.bw-cell { border-radius: 12px; padding: 4px; border: 2px solid transparent; }
.bw-cell.here { border-color: var(--accent); background: rgba(79,156,249,.08); }
.bw-cell .bcell { width: min(16vw, 62px); }
/* Un point vide est tracé sans remplissage : sans `pointer-events`, son
   intérieur ne reçoit pas le clic et seul le contour répondrait. */
.bw-cell .bd { cursor: pointer; pointer-events: all; }
.bw-cell .bd.off:hover { opacity: .55; }
.bw-hint { color: var(--muted); font-size: 13px; text-align: center;
           margin-top: 12px; }
#bw-ok { margin-top: 12px; min-width: 200px; }

/* ------------------------------------------------- la planche braille */

/* Le tableau des quatre lignes joue ici le rôle du planisphère : une vue
   d'ensemble où l'on clique, synchronisée avec la liste et la fiche. Montré
   ainsi, il dit d'un coup d'œil ce qu'aucune liste alphabétique ne dirait —
   la deuxième ligne est la première plus un point. */
.board-holder { background: var(--bg-soft); border-radius: 14px; padding: 14px;
                overflow-x: auto; touch-action: auto; }
/* La règle `display: flex` des outils de carte l'emporterait sur `hidden`. */
.board { display: flex; flex-direction: column; gap: 14px; }
.board-row { display: flex; flex-direction: column; gap: 5px; }
.br-label { font-size: 11px; color: var(--muted); font-weight: 700;
            text-transform: uppercase; letter-spacing: .05em; }
.br-cells { display: flex; gap: 6px; align-items: flex-end; }
.br-sign { opacity: .55; padding-right: 4px; }
.br-sign .bcell { width: 26px; }
.br-cell {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  font: inherit; font-size: 13px; font-weight: 700; color: var(--muted);
  background: none; border: 2px solid transparent; border-radius: 10px;
  padding: 4px 3px; cursor: pointer; flex: 1 1 0; min-width: 0;
}
.br-cell:hover { background: var(--card); }
.br-cell[aria-current="true"] { border-color: var(--accent); background: var(--card); }
.br-cell.hit { background: rgba(209,130,255,.16); }
.br-cell.learning span { color: var(--gold); }
.br-cell.mastered span { color: var(--ok); }
.br-cell .bcell { width: 100%; max-width: 34px; }
/* Le point que la ligne vient d'ajouter : c'est là que se voit la règle. */
.bd.on.add { fill: var(--accent); }

.study-name { background: var(--bg-soft); border-radius: 14px; padding: 12px 14px;
              margin-bottom: 12px; }
.sn-label { font-size: 11px; color: var(--muted); font-weight: 700;
            text-transform: uppercase; letter-spacing: .05em; margin-bottom: 8px; }
.sn-note { color: var(--muted); font-size: 12px; margin-top: 6px; }

.sandbox { background: var(--bg-soft); border-radius: 14px; padding: 12px 14px;
           margin-top: 12px; }
.sandbox label { display: block; font-size: 11px; color: var(--muted);
                 font-weight: 700; text-transform: uppercase;
                 letter-spacing: .05em; margin-bottom: 8px; }
#sandbox-in {
  font: inherit; font-size: 17px; color: var(--text); background: var(--card);
  border: 2px solid var(--line); border-radius: 10px; padding: 9px 12px;
  width: 100%;
}
#sandbox-in:focus { outline: none; border-color: var(--accent); }
.sandbox-out { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 10px;
               min-height: 44px; }

/* ------------------------------------------------- l'introduction */

.intro-overlay {
  position: fixed; inset: 0; z-index: 40; display: flex; align-items: center;
  justify-content: center; padding: 20px; background: rgba(8,13,24,.82);
}
.intro-card {
  position: relative;
  background: var(--bg-soft); border: 2px solid var(--line);
  border-radius: 20px; padding: 22px; max-width: 640px; width: 100%;
  max-height: 92vh; overflow-y: auto;
}
.intro-close { position: absolute; top: 12px; right: 12px; width: 34px;
               height: 34px; min-height: 34px; padding: 0; }
.intro-close .ic { width: 15px; height: 15px; }
.intro-title { font-size: 22px; font-weight: 800; margin: 0 0 16px; }
.intro-body { display: flex; flex-direction: column; gap: 10px;
              align-items: center; }
.intro-row { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; }
.intro-row > .bcell { width: 112px; }
.ir-cell { display: flex; flex-direction: column; align-items: center; gap: 2px;
           font-size: 13px; font-weight: 700; color: var(--muted); }
.ir-cell .bcell { width: min(10vw, 48px); }
.intro-text { color: var(--text); font-size: 15px; line-height: 1.55;
              margin: 18px 0 0; }
.intro-nav { display: flex; align-items: center; justify-content: space-between;
             gap: 12px; margin-top: 18px; }
.intro-nav .btn { min-width: 110px; }
.intro-dots { display: flex; gap: 6px; }
.intro-dots i { width: 8px; height: 8px; border-radius: 50%; background: #3a4a66; }
.intro-dots i.on { background: var(--accent); }

#study-howto { flex: none; white-space: nowrap; }
#screen-study .play-head { flex-wrap: wrap; }
#screen-study .play-head .title { flex: 1; }

/* Le message secret du bilan : le jeu écrit enfin quelque chose *à* l'enfant,
   au lieu de l'interroger. */
.secret { background: var(--bg-soft); border-radius: 14px; padding: 14px;
          margin: 18px 0; text-align: center; }
.secret h3 { font-size: 12px; color: var(--muted); font-weight: 700;
             text-transform: uppercase; letter-spacing: .05em; margin: 0 0 10px; }
.secret-cells { display: flex; flex-wrap: wrap; gap: 16px; justify-content: center;
                margin-bottom: 12px; }
.secret-text { font-size: 22px; font-weight: 800; color: var(--gold); }

/* La légende des positions, en tête de la planche. Les ronds vides ne se
   laissent pas deviner : il faut dire une fois ce qu'ils sont, et le montrer
   sur une lettre. */
.board-key { display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
             padding-bottom: 12px; margin-bottom: 2px;
             border-bottom: 1px solid var(--line); }
.bk-cell { display: flex; flex-direction: column; align-items: center; gap: 3px;
           font-size: 12px; font-weight: 700; color: var(--muted); flex: none; }
.bk-cell .bcell { width: 52px; }
.board-key p { flex: 1; min-width: 200px; margin: 0; font-size: 13px;
               line-height: 1.5; color: var(--muted); }

/* ---------------------------------------------------------- morse */

/* Tout est à l'échelle : la largeur d'un rythme vient de sa durée, et
   `--mu` — la durée d'un point — est la seule chose que la CSS règle. Quatre
   propositions se dessinent donc forcément à la même échelle, ce qui est
   exactement le sujet : deux rythmes ne se distinguent que par leur durée. */
.mcode { display: block; height: auto; max-width: 100%; flex: none; }
.ms.dit { fill: var(--gold); }
.ms.dah { fill: var(--accent); }
/* L'écart entre deux lettres vaut trois unités — le silence qui les sépare
   vraiment, contre une seule à l'intérieur d'une lettre. C'est lui qui rend
   le code lisible, autant le montrer. */
.mword { display: inline-flex; align-items: center; flex-wrap: wrap;
         gap: calc(var(--mu) * 3); --mu: 6px; }

/* L'échelle est posée par le navigateur, une par question ; ces valeurs ne
   servent que si elle manque. */
.prompt .mword.big { --mu: 20px; justify-content: center; max-width: 100%;
                     row-gap: calc(var(--mu) * 5); min-height: 44px; }
.opt .mword { --mu: 11px; justify-content: center; }
.mword.tiny { --mu: 3px; }
.mword.mid { --mu: 7px; }
.feedback .mword.mid { --mu: 9px; }

/* ------------------------------------------------- l'arbre du morse */

/* La position d'une lettre dans l'arbre *est* son code : un point descend à
   gauche, un trait à droite. C'est la seule façon de montrer d'un coup d'œil
   pourquoi e est un point et q quatre signes. */
.mtree { display: block; width: 100%; height: auto; }
.mt-edge { stroke: #2f4160; stroke-width: 2.5; stroke-linecap: round; }
.mt-edge.dit { stroke-dasharray: 3 5; }
.mt-edge.on { stroke: var(--accent); stroke-width: 4; }
.mt-node circle { fill: var(--card); stroke: #33455f; stroke-width: 2; }
.mt-node text { fill: var(--muted); font: 700 19px system-ui, sans-serif; }
.mt-node[data-code=""] circle { fill: none; stroke-dasharray: 3 4; opacity: .55; }
.mt-node.learning circle { stroke: var(--gold); }
.mt-node.learning text { fill: var(--gold); }
.mt-node.mastered circle { stroke: var(--ok); }
.mt-node.mastered text { fill: var(--ok); }
.mt-node[data-code]:not([data-code=""]) { cursor: pointer; }
.mt-node.on circle { fill: #21406b; }
.mt-node.on text { fill: var(--text); }
.mt-node[aria-current="true"] circle { stroke: var(--accent); stroke-width: 4; }
.mt-node.hit circle { fill: rgba(209,130,255,.3); }
.md-row .br-cell { gap: 5px; }
.md-row .mword { --mu: 3.4px; }
/* Seize feuilles dans une boîte de dialogue : les lettres ont besoin d'un
   peu plus de corps que sur la planche, qui a toute la largeur. */
.intro-tree { width: 100%; }
.intro-tree .mt-node text { font-size: 28px; }
.intro-tree .mt-node circle { r: 20; }
/* Deux groupes de signes côte à côte : l'écart entre eux doit rester plus
   grand que le silence qui sépare deux lettres, sinon le volet dit le
   contraire de ce qu'il explique. */
.intro-row.mrow { gap: 44px; align-items: flex-end; }
.intro-row.mrow .ir-cell .mword.big { --mu: 9px; }
.intro-row.mrow .ir-cell .mword.mid { --mu: 6px; }

/* ------------------------------------------------- le banc d'essai */

/* Ce qui compte comme court et comme long ne se règle pas d'avance : ce qui
   le rend indolore, c'est de **voir** la frontière. Pendant l'appui la barre
   se remplit et bascule sous les yeux de « point » à « trait », et l'enfant
   s'y adapte en trois essais. */
.bench-grid { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.bench-target { display: flex; align-items: center; gap: 12px; flex: 1;
                min-width: 180px; background: var(--card); border-radius: 12px;
                padding: 10px 14px; }
.bench-target .mword { --mu: 7px; }
.bt-letter { font-size: 30px; font-weight: 800; line-height: 1; }
.bt-code { color: var(--muted); font-size: 14px; font-weight: 700;
           letter-spacing: .12em; }
.bench-key {
  position: relative; overflow: hidden; flex: none; width: 190px;
  min-height: 62px; font: inherit; font-size: 17px; font-weight: 700;
  color: var(--text); background: var(--card); border: 2px solid var(--accent);
  border-radius: 14px; cursor: pointer; touch-action: none;
  user-select: none; -webkit-user-select: none;
}
.bk-fill { position: absolute; inset: 0 auto 0 0; width: 0;
           background: rgba(245,196,81,.30); transition: none; }
.bk-fill.dah { background: rgba(79,156,249,.34); }
.bk-label { position: relative; }
.bench-out { display: flex; align-items: center; gap: 12px; min-height: 40px;
             margin-top: 12px; padding: 8px 14px; border-radius: 12px;
             border: 2px solid var(--line); }
.bench-out.right { border-color: var(--ok); background: var(--ok-soft); }
.bench-out.wrong { border-color: var(--bad); background: var(--bad-soft); }
.bench-out .mword { --mu: 7px; }
.bo-code { color: var(--muted); font-weight: 700; letter-spacing: .12em; }
.bo-empty { color: var(--muted); }
.bench-hint { color: var(--muted); font-size: 12px; margin-top: 10px; }
.bench-tune { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0;
              font-size: 12px; color: var(--muted); }
.bench-tune b { color: var(--text); }
.bt-press { background: var(--card); border-radius: 7px; padding: 2px 8px;
            font-variant-numeric: tabular-nums; }
.bt-press.dit { color: var(--gold); }
.bt-press.dah { color: var(--accent); }
.bt-score { margin-left: auto; font-weight: 700; color: var(--text); }
.sandbox.bench .row { gap: 8px; }

/* Écouter : le morse n'a jamais été fait pour les yeux. */
.play-morse { display: inline-flex; align-items: center; gap: 7px; flex: none; }
.play-morse .ic { width: 15px; height: 15px; color: var(--accent); }
.play-morse:disabled { opacity: .45; cursor: default; }
.play-morse.playing { border-color: var(--accent); }
.play-morse.playing .ic { animation: pulse 1s ease-in-out infinite; }
@keyframes pulse { 50% { opacity: .35; } }
.sandbox-line { display: flex; gap: 10px; align-items: stretch; }
.sandbox-line #sandbox-in { flex: 1; min-width: 0; }
.sandbox-line .play-morse { min-height: 0; padding: 9px 16px; }
.study-card .sc-line .play-morse { margin-top: 4px; }

/* ---------------------------------------------------------- casse-têtes */
/* L'accueil d'un casse-tête : la semaine en grand, puis une carte par
   taille — la grille en cours d'abord, les niveaux en étoiles ensuite. */
.pz-title { display: flex; align-items: center; gap: 16px; margin: 18px 0 14px; }
.pz-title .art, .pz-title .art .ic { width: 64px; height: 64px; flex: none; }
.pz-name { display: block; font-size: 28px; font-weight: 800; letter-spacing: -.01em; }
.pz-sub { display: block; color: var(--muted); font-size: 14px; }
.pz-week { display: flex; align-items: center; gap: 12px; font-size: 20px; font-weight: 750;
           background: var(--bg-soft); border-radius: var(--radius); padding: 12px 16px;
           margin-bottom: 18px; }
.pz-week .ic { width: 34px; height: 34px; flex: none; }
.pz-week.empty { color: var(--muted); font-weight: 600; }
.pz-variants { display: grid; gap: 14px; }
.pz-variant { background: var(--card); border: 2px solid var(--line);
              border-radius: var(--radius); padding: 14px 16px; }
.pz-v-head { display: flex; align-items: center; gap: 12px; }
.pz-thumb, .pz-thumb .ic { width: 44px; height: 44px; flex: none; }
.pz-v-name { font-size: 22px; font-weight: 800; }
.pz-v-week { margin-left: auto; color: var(--muted); font-size: 13px; }
.pz-resume { display: block; width: 100%; margin-top: 12px; text-align: left;
             background: var(--ok); border-color: var(--ok); color: #04220f; }
.pz-resume-top { display: flex; align-items: center; gap: 10px; font-size: 19px; }
.pz-resume-top .ic { width: 20px; height: 20px; }
.pz-resume .pz-stars { margin-left: auto; }
.pz-resume .bar { display: block; background: rgba(4, 34, 15, .25); }
.pz-resume .bar > i { background: #04220f; }
.pz-levels { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-top: 12px; }
.pz-levels-label { color: var(--muted); font-size: 13px; font-weight: 650; margin-right: 4px; }
.pz-level { font: inherit; display: flex; gap: 2px; align-items: center; cursor: pointer;
            background: var(--bg-soft); border: 2px solid var(--line); border-radius: 12px;
            padding: 10px 12px; min-height: 50px; }
.pz-level:hover, .pz-level:focus-visible { border-color: var(--accent); outline: none; }
.pz-level.last { border-color: var(--accent); }
.pz-star .ic { width: 20px; height: 20px; display: block; }
.pz-star { color: #3a4a66; }
.pz-star.on { color: var(--gold); }
.pz-stars { display: inline-flex; gap: 1px; vertical-align: middle; }
.pz-confirm { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-top: 12px;
              font-weight: 650; }
.pz-confirm[hidden] { display: none; }
.pz-confirm .btn { display: inline-flex; align-items: center; gap: 6px; }
.pz-confirm .ic { width: 16px; height: 16px; }
.pz-howto { font-size: 20px; font-weight: 800; }
.pz-howto[hidden] { display: none; }

/* La grille en cours. Du papier sur le fond sombre : un chiffre posé se lit
   mieux en encre sur blanc, et c'est l'allure qu'a un Sudoku partout. */
#screen-puzzle-play { max-width: 940px; }
.pz-play-title { flex: 1; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.pz-hint { display: inline-flex; align-items: center; gap: 8px; }
.pz-hint .ic { width: 20px; height: 20px; }
.pz-board { display: flex; flex-wrap: wrap; gap: 24px; align-items: flex-start;
            justify-content: center; margin-top: 20px; }
.pz-grid {
  --paper: #fdfdfd; --thin: #b4c0d4; --strong: #1c2a44;
  container-type: inline-size; display: grid; grid-template-columns: repeat(var(--n), 1fr);
  /* Des rangées égales : sans quoi une rangée encore vide s'aplatit. */
  grid-template-rows: repeat(var(--n), 1fr);
  width: min(100%, calc(var(--n) * var(--cell, 60px))); aspect-ratio: 1;
  background: var(--paper); border: 3px solid var(--strong); border-radius: 8px;
  overflow: hidden; outline: none; user-select: none;
}
.pz-grid:focus-visible { box-shadow: 0 0 0 4px rgba(79, 156, 249, .55); }
.pz-board.pencil .pz-grid { border-color: #c99a1e; }
.pz-cell {
  position: relative; display: grid; place-items: center; cursor: pointer;
  border-right: 1px solid var(--thin); border-bottom: 1px solid var(--thin);
  color: #2563eb; font-weight: 650; line-height: 1;
  font-size: calc(100cqw / var(--n) * .56);
}
.pz-cell.lc { border-right: 0; }
.pz-cell.lr { border-bottom: 0; }
.pz-cell.wr { border-right: 3px solid var(--strong); }
.pz-cell.wb { border-bottom: 3px solid var(--strong); }
.pz-cell.given { color: #0f1729; font-weight: 800; cursor: default; }
.pz-cell.rel { background: #eaf1fb; }
.pz-cell.same { background: #cfe0fb; }
.pz-cell.sel { background: #a9ccff; }
.pz-cell.bad { color: #dc2626; background: #fde2e2; }
.pz-cell.sel.bad { background: #f9c2c2; }
.pz-cell.typing .pz-v { color: #64748b; }
.pz-notes { position: absolute; inset: 7%; display: grid; pointer-events: none;
            grid-template-columns: repeat(var(--cols), 1fr); color: #475569;
            font-size: calc(100cqw / var(--n) * .2); font-weight: 700; }
.pz-notes i { font-style: normal; display: grid; place-items: center; }
.pz-cell.hint-zone { background: #fff1bd; }
.pz-cell.hint-cell { box-shadow: inset 0 0 0 4px #f5c451; }
.pz-cell.hint-wrong { animation: pz-shake .45s ease 2; background: #fde2e2; }
.pz-cell.hint-fill { animation: pz-pop .5s ease; background: #d9f7e6; }
@keyframes pz-shake { 25% { transform: translateX(-4px); } 75% { transform: translateX(4px); } }
@keyframes pz-pop { 50% { transform: scale(1.12); } }
.pz-board.locked .pz-cell { cursor: default; }

.pz-palette { display: flex; flex-direction: column; gap: 12px; }
.pz-digits { display: grid; grid-template-columns: repeat(var(--k), 58px); gap: 8px; }
.pz-actions { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }
.pz-actions.three { grid-template-columns: repeat(3, 1fr); }
.pz-palette button {
  font: inherit; font-size: 23px; font-weight: 800; height: 58px; cursor: pointer;
  display: grid; place-items: center; color: var(--text); background: var(--card);
  border: 2px solid var(--line); border-radius: 12px;
}
.pz-palette button:hover { border-color: var(--accent); }
.pz-palette button[aria-pressed="true"] { background: var(--gold); border-color: var(--gold);
                                          color: #1b1300; }
.pz-palette button:disabled { opacity: .4; cursor: default; border-color: var(--line); }
.pz-palette .ic { width: 26px; height: 26px; }
/* Un nombre déjà posé pâlit sans se refuser : on peut vouloir le déplacer. */
.pz-palette button.spent { opacity: .3; }
.pz-digits [data-act="enter"] { grid-column: span 2; color: var(--ok); }
/* La palette du plateau à colorer : un gros bouton par état, puis les
   actions. Sa largeur est celle de trois boutons de la grille à chiffres. */
.pz-tile-palette { width: 190px; }
.pz-tools { display: grid; grid-template-columns: repeat(var(--k), 1fr); gap: 8px; }
.pz-tools button { height: 76px; }
.pz-tools .ic { width: 44px; height: 44px; }

.pz-done { text-align: center; margin: 22px auto 0; max-width: 520px; padding: 22px;
           background: var(--bg-soft); border-radius: var(--radius); }
.pz-done[hidden] { display: none; }
.pz-bravo { font-size: 34px; font-weight: 850; color: var(--gold); }
.pz-count { font-size: 20px; font-weight: 700; margin-top: 4px; }

/* La règle, montrée sur une petite grille. */
.pz-demo { --cell: 58px; margin: 0 auto; pointer-events: none; }
.pz-demo .pz-cell.hl { background: #cfe0fb; }
.pz-demo .pz-cell.found .pz-v { color: #16a34a; }
.pz-demo .pz-cell.pop .pz-v { animation: pz-appear 1.6s ease-in-out infinite; }
@keyframes pz-appear { 0%, 30% { opacity: 0; transform: scale(.4); }
                       60%, 100% { opacity: 1; transform: scale(1); } }

/* ------------------------------------------------------- carrés magiques */
/* Autour de la grille, ce qui fait le jeu : la somme magique en or, en haut
   à gauche ; la somme de chaque rangée au bout, à droite, de chaque colonne
   en dessous, et celle de chaque diagonale au coin où elle aboutit. Une somme
   juste passe au vert, une somme que plus rien ne rattrape au rouge. */
.mg-frame {
  display: grid; gap: 8px 10px; max-width: 100%;
  grid-template-columns: minmax(0, calc(var(--n) * var(--cell))) 58px;
  grid-template-areas: "target anti" "grid rows" "cols main";
}
.mg-frame > .pz-grid, .mg-slot { grid-area: grid; }
.mg-target { grid-area: target; display: flex; align-items: center; gap: 10px;
             color: var(--muted); font-size: 14px; font-weight: 650; white-space: nowrap; }
.mg-target b { min-width: 58px; height: 42px; padding: 0 12px; border-radius: 21px;
               display: grid; place-items: center; background: var(--gold); color: #1b1300;
               font-size: 24px; font-weight: 850; }
.mg-rows { grid-area: rows; display: grid; grid-template-rows: repeat(var(--n), 1fr);
           padding-block: 3px; }
.mg-cols { grid-area: cols; display: grid; grid-template-columns: repeat(var(--n), 1fr);
           padding-inline: 3px; }
.mg-anti { grid-area: anti; }
.mg-main { grid-area: main; }
.mg-sum {
  position: relative; display: grid; place-items: center; align-self: center;
  justify-self: center; min-width: 52px; height: 40px; padding: 0 6px; cursor: default;
  background: var(--bg-soft); border: 2px solid var(--line); border-radius: 12px;
  color: var(--text); font-size: 20px; font-weight: 800;
}
.mg-sum b { grid-area: 1 / 1; }
.mg-sum.ok { background: var(--ok); border-color: var(--ok); color: #04220f; }
.mg-sum.over { background: var(--bad-soft); border-color: var(--bad); color: #ffc9ce; }
.mg-sum.hint { box-shadow: 0 0 0 3px var(--gold); }
/* Un trait vers le coin de la grille dit quelle diagonale la somme compte. */
.mg-anti::after, .mg-main::after {
  content: ""; position: absolute; left: -9px; width: 12px; height: 3px;
  border-radius: 2px; background: var(--line);
}
.mg-anti::after { bottom: -5px; transform: rotate(-45deg); }
.mg-main::after { top: -5px; transform: rotate(45deg); }
.mg-sum.ok::after { background: var(--ok); }
.pz-cell.mg-line { background: #e3f6ec; }

/* La règle : un carré plus petit, et des sommes qui ne montrent que ce que
   le volet raconte. */
.mg-demo { --cell: 56px; margin: 0 auto; }
.mg-demo .mg-target b { min-width: 46px; height: 34px; font-size: 19px; }
.mg-demo .mg-sum { min-width: 44px; height: 32px; font-size: 16px; }
.mg-demo .mg-sum.off { visibility: hidden; }
.mg-demo .mg-sum.turn { animation: mg-turn 1.6s ease-in-out infinite; }
.mg-demo .mg-sum.turn .was { animation: mg-out 1.6s ease-in-out infinite; }
.mg-demo .mg-sum.turn .now { animation: mg-in 1.6s ease-in-out infinite; }
@keyframes mg-turn { 0%, 45% { background: var(--bg-soft); border-color: var(--line); color: var(--text); }
                     60%, 100% { background: var(--ok); border-color: var(--ok); color: #04220f; } }
@keyframes mg-out { 0%, 40% { opacity: 1; } 55%, 100% { opacity: 0; } }
@keyframes mg-in { 0%, 40% { opacity: 0; } 55%, 100% { opacity: 1; } }
.mg-demo-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
               gap: 22px; }
.mg-demo-palette { pointer-events: none; }
.mg-demo-palette .pz-digits { grid-template-columns: repeat(3, 44px); gap: 6px; }
.mg-demo-palette button { height: 44px; font-size: 19px; }

/* ---------------------------------------------------------------- takuzu */
/* Deux couleurs, et deux formes pour qui les distingue mal : le rouge est un
   rond, le bleu un carré. Le bleu est plus sombre que le rouge, pour qu'ils
   se séparent aussi par la clarté ; les deux tiennent plus de 3 : 1 sur le
   papier. */
.tk-token { display: block; width: 76%; height: 76%; }
.tk-red { fill: #e5484d; }
.tk-blue { fill: #2458c6; }
.tk-token.pop { animation: tk-pop .2s ease-out; }
@keyframes tk-pop { from { transform: scale(.55); } }
/* Une case donnée est posée sur un papier plus gris : elle ne bouge pas. */
.pz-tiles .pz-cell.given { background: #e3e9f2; }
.pz-tiles .pz-cell.sel { background: #cfe0fb; }
.pz-tiles .pz-cell.given.sel { background: #bcd2f5; }
/* Une faute : ni rouge ni bleue — un cadre ambre et des rayures sur la case,
   qui barrent le jeton sans le cacher. */
.pz-tiles .pz-cell.bad { background: #ffe7b0; box-shadow: inset 0 0 0 3px #d97706; }
.pz-tiles .pz-cell.bad::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: repeating-linear-gradient(-45deg, transparent 0 7px, rgba(255, 255, 255, .6) 7px 11px);
}
/* L'indice : la ligne en jaune, jusque sur les cases données, et ce qui
   donne la case cerclé de brun. */
.pz-tiles .pz-cell.hint-zone { background: #fff1bd; }
.pz-tiles .pz-cell.hint-cause { box-shadow: inset 0 0 0 4px #a16207; }
.pz-tiles .pz-cell.hint-cell { box-shadow: inset 0 0 0 5px #f5c451; }

/* La palette : un rond et un carré, et la touche qui les pose. */
.pz-tools button { position: relative; }
.tk-key { position: absolute; right: 7px; bottom: 3px; font-size: 14px; font-weight: 800;
          color: var(--muted); }

/* La règle. */
.pz-demo.pz-tiles { --cell: 58px; }
.pz-demo .pz-cell.pop .tk-token { animation: pz-appear 1.6s ease-in-out infinite; }
.pz-demo .pz-cell > span { grid-area: 1 / 1; display: grid; place-items: center;
                           width: 100%; height: 100%; }
.pz-demo .tk-was { animation: tk-out 2.4s ease-in-out infinite; }
.pz-demo .tk-now { animation: tk-in 2.4s ease-in-out infinite; }
.pz-demo .pz-cell.swap::after {
  content: ""; position: absolute; inset: 0; box-shadow: inset 0 0 0 3px #d97706;
  background: repeating-linear-gradient(-45deg, rgba(255, 231, 176, .5) 0 7px, rgba(255, 255, 255, .6) 7px 11px);
  animation: tk-out 2.4s ease-in-out infinite;
}
@keyframes tk-out { 0%, 45% { opacity: 1; } 55%, 100% { opacity: 0; } }
@keyframes tk-in { 0%, 45% { opacity: 0; } 55%, 100% { opacity: 1; } }
/* Le tour des états sous un clic : vide, rouge, bleu. */
.pz-demo .tk-c1 { animation: tk-c1 3s steps(1) infinite; }
.pz-demo .tk-c2 { animation: tk-c2 3s steps(1) infinite; }
@keyframes tk-c1 { 0% { opacity: 0; } 33% { opacity: 1; } 66% { opacity: 0; } }
@keyframes tk-c2 { 0% { opacity: 0; } 66% { opacity: 1; } }
/* Le calque centre ses volets : la rangée prend toute la largeur, sans quoi
   la grille, dont la largeur se dit en pourcentage, s'y recroqueville. */
.tk-demo-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
               gap: 22px; align-self: stretch; }
.tk-demo-row > .pz-grid { flex: none; margin: 0; }
.tk-demo-palette { pointer-events: none; width: 140px; }
.tk-demo-palette .pz-tools button { height: 60px; }
.tk-demo-palette .ic { width: 36px; height: 36px; }

/* ------------------------------------------------------------- futoshiki */
/* Des couloirs entre les cases, où vivent les signes : grands, loin des
   notes, jamais à cheval sur une case. `--g` est la largeur d'un couloir en
   part de la grille, `--c` celle d'une case ; la case, le chiffre et les
   notes se mesurent sur elle plutôt que sur un n-ième de la grille. */
.ft-grid {
  --c: calc((1 - (var(--n) - 1) * var(--g)) / var(--n));
  gap: calc(var(--g) * 100%);
  background: #d5deec;
}
/* Le papier de la case cède à ses états — choisie, éclairée, en faute. */
:where(.ft-grid) .pz-cell { background: var(--paper); border: 0; border-radius: 7px; }
.ft-grid .pz-cell { font-size: calc(100cqw * var(--c) * .58); }
.ft-grid .pz-notes { font-size: calc(100cqw * var(--c) * .22); }

/* Le chevron, dans le couloir de droite ou dans celui du dessous : sa pointe
   montre la plus petite case. */
.ft-sign { position: absolute; pointer-events: none; color: #1c2a44; }
.ft-sign svg { display: block; width: 100%; height: 100%; overflow: visible; }
.ft-sign path { fill: none; stroke: currentColor; stroke-width: max(2.5px, calc(100cqw * var(--c) * .075));
                stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.ft-h { left: 100%; top: 22%; height: 56%; width: calc(100% * var(--g) / var(--c)); }
.ft-v { top: 100%; left: 22%; width: 56%; height: calc(100% * var(--g) / var(--c)); }
/* Un signe que ses deux cases contredisent passe en rouge, plus épais. */
.ft-sign.bad { color: #dc2626; }
.ft-sign.bad path { stroke-width: max(3.5px, calc(100cqw * var(--c) * .095)); }
/* L'indice : les signes qui donnent la case, en ambre, qui battent. */
.ft-sign.hint { color: #d97706; animation: ft-pulse 1.1s ease-in-out infinite; }
.ft-sign.hint path { stroke-width: max(3.5px, calc(100cqw * var(--c) * .095)); }
@keyframes ft-pulse { 50% { transform: scale(1.25); } }

/* La règle. */
.ft-grid.pz-demo { --cell: 72px; }
.pz-demo .pz-cell.stair .pz-v { animation: ft-stair 3.6s ease-in-out infinite both;
                                animation-delay: calc(var(--k) * .5s); }
@keyframes ft-stair { 0%, 6% { opacity: 0; transform: scale(.4); }
                      18%, 80% { opacity: 1; transform: scale(1); }
                      92%, 100% { opacity: 0; transform: scale(1); } }

/* -------------------------------------------------------------- logimage */
/* Autour de la grille, les indices : ceux des colonnes au-dessus, empilés
   vers elle, ceux des rangées à gauche, serrés contre elle. Grands et gras,
   en clair sur le fond sombre, même en 15 × 15 ; les chiffres ont tous la
   même largeur, pour que les colonnes d'indices restent droites. */
.ng-frame {
  --ink: #1c2a44; --clue: clamp(17px, calc(var(--cell) * .5), 26px);
  display: grid; gap: 6px; max-width: 100%;
  grid-template-columns: auto minmax(0, calc(var(--n) * var(--cell)));
  grid-template-areas: "corner cols" "rows grid";
}
.ng-frame > .pz-grid, .ng-slot { grid-area: grid; }
.ng-corner { grid-area: corner; }
.ng-cols { grid-area: cols; display: grid; grid-template-columns: repeat(var(--n), 1fr);
           padding-inline: 3px; }
.ng-rows { grid-area: rows; display: grid; grid-template-rows: repeat(var(--rows, var(--n)), 1fr);
           padding-block: 3px; }
.ng-clue {
  display: flex; align-items: center; justify-content: flex-end; gap: .5em;
  padding: 0 8px; border-radius: 8px; color: var(--text);
  font-size: var(--clue); font-weight: 800; line-height: 1.12; font-variant-numeric: tabular-nums;
  transition: color .2s, background .2s;
}
.ng-cols .ng-clue { flex-direction: column; justify-content: flex-end; gap: 0; padding: 6px 0; }
/* La ligne de la case choisie ; une ligne juste se grise, une ligne que plus
   rien ne rattrape — trop de noires, un bloc trop long — rougit. */
.ng-clue.on { background: rgba(79, 156, 249, .2); }
.ng-clue.done { color: #58668a; }
.ng-clue.bad { color: #ff8f8f; }
.ng-clue.hint { background: rgba(245, 196, 81, .25); box-shadow: inset 0 0 0 2px var(--gold); }

/* Les cases. Le noir est un calque sous la case choisie, pour que l'éclairage
   de la ligne, le cadre de la case et l'indice restent visibles. */
.ng-grid .pz-cell.ng-rel { background: #e9f0fa; }
.ng-grid .pz-cell.sel { background: #cfe0fb; }
.ng-grid .pz-cell.hint-zone { background: #fff1bd; }
.ng-grid .pz-cell.ng-gr { border-right: 2px solid #6a7a96; }
.ng-grid .pz-cell.ng-gb { border-bottom: 2px solid #6a7a96; }
.ng-grid .pz-cell.ng-fill::before {
  content: ""; position: absolute; inset: 0; background: var(--ink);
  transition: background .35s ease calc(var(--k) * 1s / (2 * var(--n)));
}
.ng-grid .pz-cell.ng-new::before { animation: ng-pop .16s ease-out; }
@keyframes ng-pop { from { transform: scale(.55); } }
.ng-grid .pz-cell::after { content: ""; position: absolute; inset: 0; pointer-events: none; }
.ng-grid .pz-cell.sel::after { box-shadow: inset 0 0 0 3px #2f7fd8; }
.ng-grid .pz-cell.hint-cell::after { box-shadow: inset 0 0 0 5px #f5c451; }
.ng-grid .pz-cell.hint-wrong::after { box-shadow: inset 0 0 0 5px #dc2626; }
.ng-x { display: block; width: 64%; height: 64%; position: relative; }
.ng-x path { fill: none; stroke: #7d8aa1; stroke-width: 1.6; stroke-linecap: round; }

/* La palette : une case noircie sur son papier, une croix. */
.ng-tool-fill { display: block; width: 42px; height: 42px; padding: 8px; border-radius: 6px;
                background: linear-gradient(var(--ink, #1c2a44), var(--ink, #1c2a44)) content-box, #fdfdfd; }
.pz-tools .ng-x { width: 42px; height: 42px; }
.pz-tools .ng-x path { stroke: var(--text); stroke-width: 1.4; }

/* La récompense : le quadrillage, les croix et les indices s'effacent,
   l'image prend sa couleur en diagonale, et son nom prend la place de la
   palette. */
.ng-frame.ng-solved .ng-clue { opacity: .2; transition: opacity .6s; }
.ng-frame.ng-solved .ng-grid .pz-cell { background: var(--paper); border-color: transparent; }
/* Le noir couvre alors le trait de sa case : pas de fil blanc entre deux
   pixels. */
.ng-frame.ng-solved .ng-grid .pz-cell.ng-fill::before { inset: 0 -2px -2px 0; }
.ng-frame.ng-solved .ng-grid .pz-cell::after,
.ng-frame.ng-solved .ng-grid .ng-x { opacity: 0; transition: opacity .4s; }
.ng-frame.ng-solved .ng-grid { border-color: var(--paper); }
.ng-name {
  --ink: var(--gold); align-self: center; width: 250px; padding: 18px 12px;
  background: var(--bg-soft); border: 4px solid var(--ink); border-radius: var(--radius);
  color: var(--text); font-size: 28px; font-weight: 850; line-height: 1.15; text-align: center;
  animation: ng-name .55s cubic-bezier(.3, 1.6, .5, 1) .7s both;
}
.ng-name::first-letter { text-transform: uppercase; }
@keyframes ng-name { from { opacity: 0; transform: scale(.5); } }

/* La règle. La grille de démonstration garde la taille de case de son
   cadre ; une ligne seule n'est pas carrée. */
.ng-demo { --clue: 22px; margin: 0 auto; pointer-events: none; }
.ng-demo .pz-grid.pz-demo { --cell: inherit; margin: 0; }
.ng-line .pz-grid.pz-demo { aspect-ratio: auto; grid-template-rows: repeat(var(--rows), var(--cell)); }
.ng-demo .pz-cell.ng-show::before { animation: ng-show 2.8s ease-in-out infinite both;
                                    animation-delay: calc(var(--k) * .3s); }
@keyframes ng-show { 0%, 12% { opacity: 0; transform: scale(.5); }
                     28%, 82% { opacity: 1; transform: none; }
                     96%, 100% { opacity: 0; } }
/* Le grand bloc glisse d'un bord à l'autre ; le milieu ne bouge pas. */
.ng-demo .ng-slide-a::before, .ng-demo .ng-slide-b::before {
  content: ""; position: absolute; inset: 0; background: var(--ink);
}
.ng-demo .ng-slide-a::before { animation: ng-a 2.4s infinite; }
.ng-demo .ng-slide-b::before { animation: ng-b 2.4s infinite; }
@keyframes ng-a { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }
@keyframes ng-b { 0%, 49% { opacity: 0; } 50%, 100% { opacity: 1; } }
.ng-demo .pz-cell.ng-found::after { box-shadow: inset 0 0 0 4px var(--ok); }
.ng-demo .pz-cell.ng-cross-in .ng-x { animation: ng-show 2.8s ease-in-out infinite both;
                                      animation-delay: calc(var(--k) * .25s); }
.ng-demo .ng-clue.ng-grey { animation: ng-grey 2.8s ease-in-out infinite; }
@keyframes ng-grey { 0%, 30% { color: var(--text); } 45%, 90% { color: #58668a; } 100% { color: var(--text); } }
/* L'image prend sa couleur, et son nom apparaît. */
.ng-demo-solve .pz-cell.ng-fill::before { animation: ng-colour 3.6s ease-in-out infinite;
                                          animation-delay: calc(var(--k) * 70ms); }
@keyframes ng-colour { 0%, 20% { background: var(--ink); } 35%, 94% { background: #d9822b; }
                       100% { background: var(--ink); } }
.ng-demo-name { width: auto; font-size: 26px; animation: ng-name-loop 3.6s ease-in-out infinite; }
@keyframes ng-name-loop { 0%, 30% { opacity: 0; transform: scale(.6); }
                          42%, 94% { opacity: 1; transform: none; } 100% { opacity: 0; } }
/* Glisser noircit une rangée, case après case ; une croix suit. */
.ng-demo .pz-cell.ng-drag::before { content: ""; position: absolute; inset: 0; background: var(--ink);
                                    animation: ng-show 3s ease-out infinite both;
                                    animation-delay: calc(var(--k) * .2s); }
.ng-demo-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
               gap: 22px; align-self: stretch; }
.ng-demo-row > .ng-frame { margin: 0; }

/* --------------------------------------------------------- embouteillage */
/* Un parking vu d'en haut : un sol clair quadrillé de places, un mur sombre
   tout autour, ouvert à droite de la troisième rangée — la sortie, marquée
   de chevrons verts, avec la place d'y voir filer la voiture rouge. */
.pk-lot {
  --wall: 12px; --floor: #e6ebf2; --bay: #cdd5e1; --wallc: #3a4a68;
  position: relative; outline: none; user-select: none;
  width: min(100%, calc(6 * var(--cell) + 2 * var(--wall) + 40px));
  padding: var(--wall) calc(var(--wall) + 40px) var(--wall) var(--wall);
}
.pk-floor {
  position: relative; aspect-ratio: 1; border-radius: 4px;
  background-color: var(--floor);
  background-image: linear-gradient(90deg, var(--bay) 2px, transparent 2px),
                    linear-gradient(var(--bay) 2px, transparent 2px);
  background-size: calc(100% / 6) calc(100% / 6);
  background-position: -1px -1px;
  box-shadow: 0 0 0 var(--wall) var(--wallc);
}
.pk-lot:focus-visible .pk-floor {
  box-shadow: 0 0 0 var(--wall) var(--wallc), 0 0 0 calc(var(--wall) + 4px) rgba(79, 156, 249, .55);
}
/* La sortie : le mur s'ouvre, et le sol se prolonge en s'effaçant. */
.pk-gate {
  position: absolute; left: 100%; top: calc(var(--exit) * 100% / 6); height: calc(100% / 6);
  width: calc(var(--wall) + 40px); display: flex; align-items: center; justify-content: center;
  padding-left: var(--wall); color: var(--ok);
  background: linear-gradient(90deg, var(--floor) var(--wall), rgba(230, 235, 242, 0));
}
.pk-gate svg { width: 18px; height: 22px; margin: 0 -3px; }
.pk-gate path, .pk-arrow path, .pk-key path { fill: none; stroke: currentColor; stroke-width: 3.4;
                                              stroke-linecap: round; stroke-linejoin: round; }

/* Les véhicules, posés par leur rangée et leur colonne ; ils glissent d'une
   case à l'autre, et suivent le pointeur sans délai pendant qu'on les tient. */
.pk-car {
  position: absolute; z-index: 1; cursor: grab;
  left: calc(var(--c) * 100% / 6); top: calc(var(--r) * 100% / 6);
  transition: left .16s ease-out, top .16s ease-out;
}
.pk-car.pk-h { width: calc(var(--len) * 100% / 6); height: calc(100% / 6); }
.pk-car.pk-v { width: calc(100% / 6); height: calc(var(--len) * 100% / 6); }
.pk-car > svg { display: block; width: 100%; height: 100%; pointer-events: none;
                filter: drop-shadow(0 2px 1.5px rgba(15, 23, 41, .35)); }
.pk-car:hover > svg { filter: drop-shadow(0 3px 3px rgba(15, 23, 41, .4)) brightness(1.06); }
.pk-car.dragging { transition: none; cursor: grabbing; z-index: 2; }
.pz-board.locked .pk-car { cursor: default; }
/* Le véhicule choisi : un liseré blanc et bleu, qui se voit sur toutes les
   couleurs. */
.pk-car::after { content: ""; position: absolute; inset: 2px; border-radius: 14px;
                 pointer-events: none; }
.pk-car.sel::after { box-shadow: 0 0 0 3px #fff, 0 0 0 6px #2f7fd8; }
/* Il ne peut pas aller par là : il tressaille. */
.pk-car.pk-bump-h { animation: pk-bump-h .26s ease; }
.pk-car.pk-bump-v { animation: pk-bump-v .26s ease; }
@keyframes pk-bump-h { 30% { translate: -5px 0; } 70% { translate: 5px 0; } }
@keyframes pk-bump-v { 30% { translate: 0 -5px; } 70% { translate: 0 5px; } }
/* La voiture rouge touche la sortie : elle file et disparaît. */
.pk-car.pk-gone { left: calc(7.5 * 100% / 6); opacity: 0;
                  transition: left .9s cubic-bezier(.45, 0, .85, .55), opacity .45s ease .45s; }

/* L'indice : le véhicule à bouger bat en or, une flèche vers où il va. */
.pk-car.pk-hint::after { box-shadow: 0 0 0 5px var(--gold); animation: pk-glow 1s ease-in-out infinite; }
@keyframes pk-glow { 50% { box-shadow: 0 0 0 9px rgba(245, 196, 81, .45); } }
.pk-arrow { display: none; }
.pk-car.pk-hint .pk-arrow {
  position: absolute; left: 50%; top: 50%; translate: -50% -50%; width: 36px; height: 36px;
  display: grid; place-items: center; border-radius: 50%; background: var(--gold); color: #1b1300;
  box-shadow: 0 2px 4px rgba(15, 23, 41, .4);
}
.pk-arrow svg { width: 22px; height: 22px; }
.pk-v .pk-arrow svg { rotate: 90deg; }
.pk-h.pk-back .pk-arrow svg { rotate: 180deg; }
.pk-v.pk-back .pk-arrow svg { rotate: -90deg; }

/* La palette : recommencer, en grand ; annuler et refaire. */
.pk-palette .pk-flash { animation: pz-pop .5s ease 2; border-color: var(--gold); }

/* La règle. Les véhicules de démonstration se déplacent par `translate`, en
   parts de leur propre longueur : `100% / --len`, c'est une case. */
.pk-demo { --wall: 8px; margin: 0 auto; pointer-events: none; }
.pk-demo .pk-car { transition: none; }
.pk-demo .pk-gate svg { width: 12px; height: 16px; }
.pk-demo .pk-car::after { border-radius: 9px; }
.pk-a-leave { animation: pk-leave 3.6s ease-in-out infinite; }
@keyframes pk-leave {
  0%, 18% { translate: 0 0; opacity: 1; }
  55% { translate: calc(300% / var(--len)) 0; opacity: 1; }
  75% { translate: calc(var(--by) * 100% / var(--len)) 0; opacity: 0; }
  90% { translate: 0 0; opacity: 0; }
  100% { translate: 0 0; opacity: 1; }
}
.pk-a-yoyo-y { animation: pk-yoyo-y 4s ease-in-out infinite; }
@keyframes pk-yoyo-y { 0%, 10% { translate: 0 0; } 35%, 55% { translate: 0 calc(var(--by) * 100% / var(--len)); }
                       80%, 100% { translate: 0 0; } }
.pk-a-yoyo-x { animation: pk-yoyo-x 4s ease-in-out infinite; }
@keyframes pk-yoyo-x { 0%, 30% { translate: 0 0; } 55%, 75% { translate: calc(var(--by) * 100% / var(--len)) 0; }
                       95%, 100% { translate: 0 0; } }
.pk-a-down { animation: pk-down 4.4s ease-in-out infinite; }
@keyframes pk-down { 0%, 12% { translate: 0 0; } 32%, 86% { translate: 0 calc(var(--by) * 100% / var(--len)); }
                     96%, 100% { translate: 0 0; } }
.pk-a-after { animation: pk-after 4.4s ease-in-out infinite; }
@keyframes pk-after {
  0%, 36% { translate: 0 0; opacity: 1; }
  62% { translate: calc(400% / var(--len)) 0; opacity: 1; }
  76% { translate: calc(var(--by) * 100% / var(--len)) 0; opacity: 0; }
  88% { translate: 0 0; opacity: 0; }
  98%, 100% { translate: 0 0; opacity: 1; }
}
.pk-a-drag { animation: pk-drag 3s ease-in-out infinite; }
.pk-a-drag::after { box-shadow: 0 0 0 3px #fff, 0 0 0 5px #2f7fd8; }
@keyframes pk-drag { 0%, 25% { translate: 0 0; } 50%, 80% { translate: 0 calc(var(--by) * 100% / var(--len)); }
                     100% { translate: 0 0; } }
.pk-hand { position: absolute; left: 48%; top: 52%; width: 28px; height: 28px; z-index: 1;
           fill: #fff; stroke: #15213a; stroke-width: 1.6; stroke-linejoin: round; }
.pk-demo-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
               gap: 22px; align-self: stretch; }
.pk-demo-row > .pk-lot { margin: 0; flex: none; }
.pk-keys { display: grid; gap: 10px; justify-items: center; color: var(--muted); font-weight: 700; }
.pk-key {
  display: inline-grid; place-items: center; min-width: 36px; height: 36px; padding: 0 8px; margin: 2px;
  border-radius: 8px; background: var(--card); border: 2px solid var(--line); border-bottom-width: 4px;
  color: var(--text); font: 700 15px/1 system-ui, sans-serif;
}
.pk-key svg { width: 16px; height: 16px; }
.pk-arrows { display: grid; justify-items: center; }
.pk-demo-restart { width: 60px; height: 50px; display: grid; place-items: center; color: var(--text);
                   background: var(--card); border: 2px solid var(--line); border-radius: 12px; }
.pk-demo-restart .ic { width: 30px; height: 30px; }

/* ---------------------------------------------------------------- reines */
/* Des zones de couleur claire, un trait épais là où la zone change — pour
   qui distingue mal les couleurs —, et par-dessus, sombres, la reine et la
   croix. Aucun état de la case ne recouvre sa couleur : la case choisie, la
   faute et l'indice sont des cadres et des voiles. */
.qn-grid { --thin: rgba(28, 42, 68, .2); }
/* La couleur s'arrête au trait : un trait fin reste gris, et le voile de
   l'indice ne laisse pas de fil coloré entre deux cases voilées. */
.pz-tiles.qn-grid .pz-cell { background: var(--zc, var(--paper)) padding-box; box-shadow: none; }
.qn-grid .pz-cell::before, .qn-grid .pz-cell::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
}
.qn-queen { position: relative; display: block; width: 66%; height: 66%; fill: #1c2a44; }
.qn-queen.pop { animation: qn-pop .2s ease-out; }
@keyframes qn-pop { from { transform: scale(.5); } }
.qn-x { position: relative; display: block; width: 44%; height: 44%; }
.qn-x path { fill: none; stroke: #26344f; stroke-opacity: .75; stroke-width: 1.35; stroke-linecap: round; }

/* La case choisie : un cadre bleu, liseré de blanc pour se lire sur toutes
   les couleurs. */
.qn-grid .pz-cell.sel::after { box-shadow: inset 0 0 0 3px #1d4ed8, inset 0 0 0 5px rgba(255, 255, 255, .75); }
/* Une reine en faute rougit, sur des rayures et dans un cadre rouge : la
   forme dit la faute autant que la couleur. */
.pz-tiles.qn-grid .pz-cell.bad::before {
  background: repeating-linear-gradient(-45deg, transparent 0 7px, rgba(255, 255, 255, .45) 7px 10px);
  box-shadow: inset 0 0 0 3px #c81e1e;
}
.pz-tiles.qn-grid .pz-cell.bad::after { background: none; }
.qn-grid .pz-cell.bad .qn-queen { fill: #c81e1e; }

/* L'indice : le reste de la grille se voile, les lignes et les zones où tout
   se passe gardent leur couleur ; les places qui donnent la réponse sont
   cerclées de brun, la reine à poser d'or, les croix à poser s'esquissent. */
.qn-hinting .pz-cell:not(.hint-zone):not(.hint-cell):not(.hint-target)::after {
  background: rgba(253, 253, 253, .68);
}
.qn-grid .pz-cell.hint-cause::after { box-shadow: inset 0 0 0 4px #92400e; }
.qn-grid .pz-cell.hint-cell::after { box-shadow: inset 0 0 0 5px #f5c451, inset 0 0 0 7px #92400e; }
.qn-grid .pz-cell.hint-cell:not(.filled)::before {
  background: center / 62% no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cg fill='%2392400e'%3E%3Cpath d='M11 47 7.5 21.5 21 33 32 13.5 43 33 56.5 21.5 53 47Z'/%3E%3Crect x='11' y='50' width='42' height='7.5' rx='3.2'/%3E%3Ccircle cx='7' cy='18.5' r='4.4'/%3E%3Ccircle cx='32' cy='10' r='4.8'/%3E%3Ccircle cx='57' cy='18.5' r='4.4'/%3E%3C/g%3E%3C/svg%3E");
  animation: qn-ghost 1.4s ease-in-out infinite;
}
.qn-grid .pz-cell.hint-target::before {
  background: center / 44% no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Cpath d='M2.9 2.9l4.2 4.2M7.1 2.9l-4.2 4.2' fill='none' stroke='%2392400e' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E");
  box-shadow: inset 0 0 0 3px #b45309; animation: qn-ghost 1.4s ease-in-out infinite;
}
.qn-grid .pz-cell.hint-wrong::after { box-shadow: inset 0 0 0 6px #c81e1e, inset 0 0 0 8px #fff; }
@keyframes qn-beat { 50% { opacity: .45; } }
@keyframes qn-ghost { 0%, 100% { opacity: .75; } 50% { opacity: .3; } }

/* La palette : une couronne et une croix, et la touche qui les pose. */
.pz-tools .qn-queen { width: 42px; height: 42px; fill: var(--text); }
.pz-tools .qn-x { width: 40px; height: 40px; }
.pz-tools .qn-x path { stroke: var(--text); stroke-opacity: 1; stroke-width: 1.2; }

/* La règle. Deux grilles côte à côte tiennent dans le calque. */
.qn-grid.pz-demo { --cell: 58px; }
.qn-demo-pair > .qn-grid.pz-demo { --cell: 48px; flex: none; margin: 0; }
.qn-spot .pz-cell:not(.hl)::after { background: rgba(253, 253, 253, .68); }
.pz-demo .pz-cell.pop .qn-queen { animation: qn-appear 4s ease-in-out infinite both;
                                  animation-delay: calc(var(--k) * .4s); }
@keyframes qn-appear { 0%, 8% { opacity: 0; transform: scale(.4); }
                       18%, 86% { opacity: 1; transform: none; }
                       96%, 100% { opacity: 0; } }
.pz-demo .pz-cell.cross-in .qn-x { animation: qn-appear 4s ease-in-out infinite both;
                                   animation-delay: calc(.6s + var(--k) * .15s); }
.pz-demo .pz-cell.bad .qn-queen { animation: qn-beat 1.4s ease-in-out infinite; }
/* Le tour des états sous un clic : vide, croix, reine. */
.pz-demo .qn-c1 { animation: tk-c1 3s steps(1) infinite; }
.pz-demo .qn-c2 { animation: tk-c2 3s steps(1) infinite; }

/* ---------------------------------------------------------------- suguru */
/* Des zones d'une teinte très claire, bordées d'un trait épais : le trait dit
   la zone à qui distingue mal les couleurs, la teinte la fait voir d'un coup
   d'œil. Les états de la case — éclairée, choisie, en faute, l'indice —
   recouvrent la teinte, comme ils recouvrent le papier du Sudoku. */
:where(.sg-grid) .pz-cell { background: var(--zc, var(--paper)); }
/* Une faute se voit aussi à son cadre : le fond rosé seul se confondrait avec
   une teinte. */
.sg-grid .pz-cell.bad { box-shadow: inset 0 0 0 3px #dc2626; }
/* L'indice : la zone — et les voisines d'un évident — en jaune, et cerclés
   de brun, les chiffres qui donnent la case. */
.sg-grid .pz-cell.hint-cause { box-shadow: inset 0 0 0 4px #a16207; }

/* La règle. */
.sg-grid.pz-demo { --cell: 62px; }
.sg-grid.pz-demo .pz-cell.cause { box-shadow: inset 0 0 0 4px #a16207; }
/* Des zones qui se remplissent en comptant : tous les 1, puis tous les 2… */
.pz-demo .pz-cell.count .pz-v { animation: sg-count 4.4s ease-in-out infinite both;
                                animation-delay: calc(var(--k) * .5s); }
@keyframes sg-count { 0%, 4% { opacity: 0; transform: scale(.4); }
                      14%, 84% { opacity: 1; transform: none; }
                      96%, 100% { opacity: 0; } }
.sg-demo-palette { pointer-events: none; }
.sg-demo-palette .pz-digits { grid-template-columns: repeat(3, 44px); gap: 6px; }
.sg-demo-palette button { height: 44px; font-size: 19px; }

/* ------------------------------------------------------------- calcudoku */
/* Des enclos bordés d'un trait épais, et leur somme dans le coin en haut à
   gauche de leur première case : petite, grasse, sur une pastille qui passe
   au vert quand l'enclos est plein et juste, au rouge quand il ne fait plus
   sa somme. Les notes descendent sous la pastille dans toutes les cases, pour
   garder partout la même place ; le chiffre, un peu sous le milieu. */
.cc-grid .pz-cell { padding-top: 14%; font-size: calc(100cqw / var(--n) * .5); }
.cc-grid .pz-notes { inset: 31% 7% 5%; }
.cc-sum {
  position: absolute; left: 4%; top: 3%; z-index: 1; pointer-events: none;
  padding: .1em .32em .06em; border-radius: .5em; line-height: 1;
  font-size: calc(100cqw / var(--n) * .2); font-weight: 850; font-style: normal;
  color: #1c2a44; transform-origin: 0 0;
}
.cc-sum.ok { background: #16a34a; color: #fff; }
.cc-sum.bad { background: #dc2626; color: #fff; }
/* L'indice : la somme qui donne la case, en or, qui bat. */
.cc-sum.hint { background: #f5c451; color: #1b1300; animation: cc-pulse 1.1s ease-in-out infinite; }
@keyframes cc-pulse { 50% { transform: scale(1.25); } }

/* La règle. */
.cc-grid.pz-demo { --cell: 72px; }
/* La règle du Takuzu donne à tout `span` direct d'une case de démonstration
   toute la hauteur de la case : les notes, qui commencent sous la somme, en
   déborderaient. */
.cc-grid.pz-demo .pz-cell > .pz-notes { width: auto; height: auto; }
/* La somme passe au vert quand les chiffres de l'enclos apparaissent. */
.pz-demo .cc-sum.turn { animation: cc-turn 1.6s ease-in-out infinite; }
@keyframes cc-turn { 0%, 55% { background: transparent; color: #1c2a44; }
                     62%, 100% { background: #16a34a; color: #fff; } }

/* ---------------------------------------------------- relier les couleurs */
/* Un papier gris très clair, pour que le jaune s'y lise ; les chemins sont des
   traits épais qui relient les centres des cases, par-dessus, dans un dessin
   qui ne prend pas le pointeur ; une case prise se teinte de la couleur de
   son chemin, et l'on voit d'un coup d'œil ce qui reste à remplir. */
.lk-grid { --paper: #f1f4f8; --thin: #d6dde8; position: relative; }
.lk-grid .pz-cell { background: var(--paper); cursor: inherit; }
.lk-grid .pz-cell.lk-on { background: color-mix(in srgb, var(--pc) 22%, var(--paper)); }
.lk-draw { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.lk-line, .lk-ghost, .lk-bad { fill: none; stroke-linecap: round; stroke-linejoin: round; }
.lk-line { stroke-width: .34; }
/* Une paire reliée : ses points s'entourent d'un anneau, qui surgit. */
.lk-ring { fill: none; stroke-width: .07; transform-box: fill-box; transform-origin: center; }
.lk-pair:not(.lk-linked):not(.lk-a) .lk-ring { opacity: 0; }
.lk-linked .lk-ring { animation: lk-ring .5s ease-out; }
@keyframes lk-ring { from { transform: scale(.5); opacity: 0; } }
/* La tête du chemin choisi, là où le clavier le prolonge : un anneau en
   pointillés qui tourne, et qui tressaille quand le pas est impossible. */
.lk-head { fill: none; stroke-width: .07; stroke-dasharray: .16 .1; opacity: 0;
           transform-box: fill-box; transform-origin: center; animation: lk-spin 4s linear infinite; }
.lk-grid:focus .lk-head { opacity: 1; }
.lk-head.lk-bump { animation: lk-spin 4s linear infinite, lk-bump .26s ease; }
@keyframes lk-spin { to { rotate: 360deg; } }
@keyframes lk-bump { 50% { scale: 1.3; } }
.pz-board.locked .lk-grid { cursor: default; }
.pz-board.locked .lk-head { display: none; }

/* Toutes les paires reliées et des cases vides : elles clignotent doucement,
   d'un cadre en tirets plutôt que d'une teinte, qui se confondrait avec celle
   d'un chemin. */
.lk-grid .pz-cell.lk-hole { outline: 3px dashed transparent; outline-offset: -8px;
                            animation: lk-hole 1.3s ease-in-out infinite; }
@keyframes lk-hole { 50% { outline-color: #d97706; background: #fff; } }

/* L'indice : un chemin entier en pointillés de sa couleur, qui bat ; ou la
   partie fausse d'un chemin, rayée de blanc sur des cases qui rosissent. */
.lk-ghost { stroke-width: .2; stroke-dasharray: .1 .2; animation: lk-ghost 1.2s ease-in-out infinite; }
@keyframes lk-ghost { 50% { opacity: .35; } }
.lk-bad { stroke: #fff; stroke-width: .12; stroke-dasharray: .12 .14; }
.lk-grid .pz-cell.lk-wrong { animation: lk-wrong 1s ease-in-out infinite; }
@keyframes lk-wrong { 50% { background: #fca5a5; } }
.lk-grid .pz-cell.lk-fill { animation: pz-pop .5s ease; }

/* La palette : une pastille par couleur, pâle tant que la paire n'est pas
   reliée, pleine et cochée ensuite — le compte se voit sans chiffre ; la
   couleur choisie est cerclée. */
.lk-pairs { display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px; }
.lk-pairs button { position: relative; height: 42px; padding: 0; }
.pz-palette .lk-pairs button[aria-pressed="true"] { background: var(--card); border-color: var(--accent);
                                                    box-shadow: inset 0 0 0 2px var(--accent); }
.lk-pairs button > svg:first-child { width: 26px; height: 26px; opacity: .4; }
.lk-pairs button.done > svg:first-child { opacity: 1; }
.lk-check { position: absolute; right: -4px; bottom: -4px; width: 16px; height: 16px; display: none;
            border-radius: 50%; background: var(--ok); }
.lk-pairs button.done .lk-check { display: block; }
.lk-check path { fill: none; stroke: #04220f; stroke-width: 2.8; stroke-linecap: round; stroke-linejoin: round; }

/* La règle. Chaque petite grille a son cadre, qui porte sa largeur — une
   largeur en pourcentage se recroquevillerait dans la rangée — et son
   verdict dans le coin. */
.lk-demo-frame { position: relative; flex: none; width: min(100%, calc(5 * var(--cell))); margin: 0 auto; }
.lk-demo-frame > .lk-grid.pz-demo { --cell: inherit; width: 100%; margin: 0; }
.lk-demo-pair > .lk-demo-frame { margin: 0; }
.lk-verdict { position: absolute; right: -11px; top: -11px; width: 30px; height: 30px; border-radius: 50%;
              display: grid; place-items: center; box-shadow: 0 2px 4px rgba(15, 23, 41, .4); }
.lk-verdict.ok { background: var(--ok); }
.lk-verdict.no { background: #dc2626; }
.lk-verdict svg { width: 18px; height: 18px; }
.lk-verdict path { fill: none; stroke: #fff; stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; }
.lk-clash { fill: none; stroke: #dc2626; stroke-width: .1; animation: lk-ghost 1s ease-in-out infinite; }
.lk-hand { fill: #fff; stroke: #15213a; stroke-width: 1.6px; vector-effect: non-scaling-stroke; }
.lk-back-key { width: 20px; height: 16px; }
.lk-back-key path { fill: none; stroke: currentColor; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
