4018 lines
82 KiB
CSS
4018 lines
82 KiB
CSS
/* Style de l'application, selon la charte graphique (ADR 0010,
|
||
* docs/identite/charte/) : les couleurs, tailles et rayons sont les
|
||
* variables de tokens.json, sous le même nom, redéfinies pour le thème
|
||
* sombre ; les composants reprennent bundle.css. */
|
||
|
||
/* ------------------------------------------------------------ Police */
|
||
|
||
/* Alegreya Sans (SIL Open Font License 1.1, voir fonts/OFL.txt), réduite
|
||
* aux caractères latins et convertie en woff2 (voir docs/identite/README.md).
|
||
* Embarquée dans le site, donc dans le cache du service worker : elle
|
||
* fonctionne hors ligne. */
|
||
@font-face {
|
||
font-family: "Alegreya Sans";
|
||
src: url("fonts/AlegreyaSans-Regular.woff2") format("woff2");
|
||
font-weight: 400;
|
||
font-style: normal;
|
||
font-display: swap;
|
||
}
|
||
|
||
@font-face {
|
||
font-family: "Alegreya Sans";
|
||
src: url("fonts/AlegreyaSans-Italic.woff2") format("woff2");
|
||
font-weight: 400;
|
||
font-style: italic;
|
||
font-display: swap;
|
||
}
|
||
|
||
@font-face {
|
||
font-family: "Alegreya Sans";
|
||
src: url("fonts/AlegreyaSans-Medium.woff2") format("woff2");
|
||
font-weight: 500;
|
||
font-style: normal;
|
||
font-display: swap;
|
||
}
|
||
|
||
@font-face {
|
||
font-family: "Alegreya Sans";
|
||
src: url("fonts/AlegreyaSans-Bold.woff2") format("woff2");
|
||
font-weight: 700;
|
||
font-style: normal;
|
||
font-display: swap;
|
||
}
|
||
|
||
@font-face {
|
||
font-family: "Alegreya Sans";
|
||
src: url("fonts/AlegreyaSans-ExtraBold.woff2") format("woff2");
|
||
font-weight: 800;
|
||
font-style: normal;
|
||
font-display: swap;
|
||
}
|
||
|
||
/* ------------------------------------------------------------ Couleurs */
|
||
|
||
/* Thème clair par défaut ; thème sombre selon le système, ou forcé par le
|
||
* menu (data-theme sur <html>). Les deux blocs sombres sont identiques
|
||
* (vérifié par app/tests/ui.test.ts). */
|
||
:root {
|
||
--background: #f5efe5;
|
||
--surface: #fffcf6;
|
||
--surface-sunken: #ece3d4;
|
||
--text: #2b1d15;
|
||
--muted: #6b5c50;
|
||
--border: #ded2c0;
|
||
--border-strong: #8e7d6a;
|
||
--accent: #a8432b;
|
||
--on-accent: #ffffff;
|
||
--accent-soft: #f1d9cf;
|
||
--focus: #a8432b;
|
||
--error: #8c1c3a;
|
||
--verdict-good: #2f6b4f;
|
||
--verdict-doubtful: #7e5a0f;
|
||
--verdict-bad: #8c1c3a;
|
||
--brand-noyer: #4a2e1f;
|
||
--brand-ivoire: #f3ead8;
|
||
--brand-laiton: #8f6a1c;
|
||
|
||
--frame: #4a2e1f;
|
||
--bed: #e9dcc4;
|
||
--bar: #3f2619;
|
||
--tray: #3a2418;
|
||
--point-a: #6b4430;
|
||
--point-b: #c9ae88;
|
||
--point-number: #f3ead8;
|
||
--checker-player: #fafaf7;
|
||
--checker-player-edge: #55554f;
|
||
--checker-computer: #1c1c1c;
|
||
--checker-computer-edge: #b5b5b0;
|
||
--count-player: #1c1c1c;
|
||
--count-computer: #fafaf7;
|
||
--die-player: #fafaf7;
|
||
--pip-player: #1c1c1c;
|
||
--die-computer: #1c1c1c;
|
||
--pip-computer: #fafaf7;
|
||
--cube: #fafaf7;
|
||
--cube-text: #1c1c1c;
|
||
--highlight: #a8432b;
|
||
--target: rgba(168, 67, 43, 0.32);
|
||
/* Dernier coup joué (marques et traces) : le laiton, rien d'autre. */
|
||
--last-move: var(--brand-laiton);
|
||
|
||
--shadow-raised: 0 1px 2px rgba(43, 29, 21, 0.1);
|
||
|
||
--font-sans: "Alegreya Sans", "Gill Sans", "Segoe UI", system-ui, sans-serif;
|
||
|
||
--space-1: 4px;
|
||
--space-2: 8px;
|
||
--space-3: 12px;
|
||
--space-4: 16px;
|
||
--space-6: 24px;
|
||
--space-8: 32px;
|
||
--button-height: 48px;
|
||
--page-width: 40rem;
|
||
--radius-sm: 6px;
|
||
--radius-md: 12px;
|
||
--radius-pill: 999px;
|
||
|
||
/* Mouvement (interaction.md). */
|
||
--duration-instant: 90ms;
|
||
--duration-fast: 160ms;
|
||
--duration-moderate: 240ms;
|
||
--easing-standard: cubic-bezier(0.2, 0, 0, 1);
|
||
--easing-exit: cubic-bezier(0.4, 0, 1, 1);
|
||
|
||
/* Voile sous le menu et les panneaux. */
|
||
--scrim: rgba(43, 29, 21, 0.5);
|
||
|
||
/* Hauteurs fixes de l'écran de jeu en portrait : rien ne bouge sous le
|
||
* doigt (interaction.md, principe 2). */
|
||
--topbar-height: 60px;
|
||
--strip-height: 44px;
|
||
--infoline-height: 44px;
|
||
--prompt-height: 50px;
|
||
--actions-height: 76px;
|
||
|
||
color-scheme: light;
|
||
}
|
||
|
||
@media (prefers-color-scheme: dark) {
|
||
:root:not([data-theme="light"]) {
|
||
--background: #17110d;
|
||
--surface: #221913;
|
||
--surface-sunken: #2c211a;
|
||
--text: #efe5d5;
|
||
--muted: #a99886;
|
||
--border: #3a2d24;
|
||
--border-strong: #7d6b5b;
|
||
--accent: #d0694b;
|
||
--on-accent: #1a110c;
|
||
--accent-soft: #4a2519;
|
||
--focus: #e58a6e;
|
||
--error: #f08fa6;
|
||
--verdict-good: #7ccba4;
|
||
--verdict-doubtful: #e0b04f;
|
||
--verdict-bad: #f08fa6;
|
||
--brand-laiton: #d6a64a;
|
||
|
||
--frame: #2a1a10;
|
||
--bed: #4a3626;
|
||
--bar: #24170e;
|
||
--tray: #22150d;
|
||
--point-a: #3a2519;
|
||
--point-b: #7e6142;
|
||
--point-number: #cdbfa8;
|
||
--checker-player: #f2f2ef;
|
||
--checker-player-edge: #6e6e69;
|
||
--checker-computer: #141414;
|
||
--checker-computer-edge: #b5b5b0;
|
||
--count-player: #1c1c1c;
|
||
--count-computer: #fafaf7;
|
||
--die-player: #f2f2ef;
|
||
--pip-player: #1c1c1c;
|
||
--die-computer: #141414;
|
||
--pip-computer: #f2f2ef;
|
||
--cube: #f2f2ef;
|
||
--cube-text: #1c1c1c;
|
||
--highlight: #e07a5a;
|
||
--target: rgba(224, 122, 90, 0.38);
|
||
|
||
--shadow-raised: 0 1px 2px rgba(0, 0, 0, 0.4);
|
||
--scrim: rgba(0, 0, 0, 0.6);
|
||
color-scheme: dark;
|
||
}
|
||
}
|
||
|
||
:root[data-theme="dark"] {
|
||
--background: #17110d;
|
||
--surface: #221913;
|
||
--surface-sunken: #2c211a;
|
||
--text: #efe5d5;
|
||
--muted: #a99886;
|
||
--border: #3a2d24;
|
||
--border-strong: #7d6b5b;
|
||
--accent: #d0694b;
|
||
--on-accent: #1a110c;
|
||
--accent-soft: #4a2519;
|
||
--focus: #e58a6e;
|
||
--error: #f08fa6;
|
||
--verdict-good: #7ccba4;
|
||
--verdict-doubtful: #e0b04f;
|
||
--verdict-bad: #f08fa6;
|
||
--brand-laiton: #d6a64a;
|
||
|
||
--frame: #2a1a10;
|
||
--bed: #4a3626;
|
||
--bar: #24170e;
|
||
--tray: #22150d;
|
||
--point-a: #3a2519;
|
||
--point-b: #7e6142;
|
||
--point-number: #cdbfa8;
|
||
--checker-player: #f2f2ef;
|
||
--checker-player-edge: #6e6e69;
|
||
--checker-computer: #141414;
|
||
--checker-computer-edge: #b5b5b0;
|
||
--count-player: #1c1c1c;
|
||
--count-computer: #fafaf7;
|
||
--die-player: #f2f2ef;
|
||
--pip-player: #1c1c1c;
|
||
--die-computer: #141414;
|
||
--pip-computer: #f2f2ef;
|
||
--cube: #f2f2ef;
|
||
--cube-text: #1c1c1c;
|
||
--highlight: #e07a5a;
|
||
--target: rgba(224, 122, 90, 0.38);
|
||
|
||
--shadow-raised: 0 1px 2px rgba(0, 0, 0, 0.4);
|
||
--scrim: rgba(0, 0, 0, 0.6);
|
||
color-scheme: dark;
|
||
}
|
||
|
||
/* -------------------------------------------------------------- Page */
|
||
|
||
* {
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
/* Pas de « tirer pour rafraîchir » ni de rebond qui recharge la page en
|
||
* pleine partie ; pas de texte sélectionné par un appui long. */
|
||
html {
|
||
-webkit-text-size-adjust: 100%;
|
||
text-size-adjust: 100%;
|
||
overscroll-behavior: none;
|
||
}
|
||
|
||
body {
|
||
margin: 0 auto;
|
||
max-width: var(--page-width);
|
||
padding: 0 var(--space-4);
|
||
font-family: var(--font-sans);
|
||
font-size: 17px;
|
||
line-height: 25px;
|
||
color: var(--text);
|
||
background: var(--background);
|
||
overscroll-behavior: none;
|
||
user-select: none;
|
||
-webkit-user-select: none;
|
||
}
|
||
|
||
[hidden] {
|
||
display: none !important;
|
||
}
|
||
|
||
a {
|
||
color: var(--accent);
|
||
text-underline-offset: 3px;
|
||
}
|
||
|
||
/* Anneau de focus clavier, sur tout élément interactif. */
|
||
:focus-visible {
|
||
outline: 3px solid var(--focus);
|
||
outline-offset: 2px;
|
||
}
|
||
|
||
/* L'écran de jeu en portrait : des zones de hauteur fixe, de haut en bas ;
|
||
* la barre d'actions reste collée en bas de l'écran. */
|
||
.screen {
|
||
display: flex;
|
||
flex-direction: column;
|
||
min-height: 100vh;
|
||
min-height: 100dvh;
|
||
}
|
||
|
||
.game {
|
||
display: flex;
|
||
flex: 1;
|
||
flex-direction: column;
|
||
}
|
||
|
||
/* Les pages sont des éléments de la colonne flexible #screen. Leurs marges
|
||
* automatiques les centrent, mais annulent leur étirement en largeur : sans
|
||
* largeur explicite, une page au contenu court se réduit à la largeur de ce
|
||
* contenu (le plateau de l'étape 6 « à vous » du tutoriel passait de 396 à
|
||
* 300 px en 412 × 915). Leur max-width les borne toujours. */
|
||
.screen > .page {
|
||
width: 100%;
|
||
}
|
||
|
||
.spacer {
|
||
flex: 1;
|
||
}
|
||
|
||
/* Logo clair ou sombre selon le thème. */
|
||
.logo-dark {
|
||
display: none;
|
||
}
|
||
|
||
@media (prefers-color-scheme: dark) {
|
||
:root:not([data-theme="light"]) .logo-light { display: none; }
|
||
:root:not([data-theme="light"]) .logo-dark { display: block; }
|
||
}
|
||
|
||
:root[data-theme="dark"] .logo-light { display: none; }
|
||
:root[data-theme="dark"] .logo-dark { display: block; }
|
||
|
||
/* -------------------------------------------------------- Barre haute */
|
||
|
||
.topbar {
|
||
display: flex;
|
||
flex: none;
|
||
gap: var(--space-1);
|
||
align-items: center;
|
||
height: var(--topbar-height);
|
||
}
|
||
|
||
.topbar .brand {
|
||
flex: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
min-width: 0;
|
||
margin: 0;
|
||
}
|
||
|
||
.topbar .brand img {
|
||
width: auto;
|
||
max-width: 100%;
|
||
height: 28px;
|
||
}
|
||
|
||
/* ------------------------------------------------------- Pictogrammes */
|
||
|
||
.icon {
|
||
width: 24px;
|
||
height: 24px;
|
||
fill: none;
|
||
stroke: currentColor;
|
||
stroke-width: 2;
|
||
stroke-linecap: round;
|
||
stroke-linejoin: round;
|
||
flex: none;
|
||
}
|
||
|
||
/* ------------------------------------------------------------ Boutons */
|
||
|
||
/* Ronds comme des pions ; un seul bouton principal (brique) par écran,
|
||
* les autres en contour. */
|
||
button {
|
||
min-height: var(--button-height);
|
||
padding: 0 20px;
|
||
font: inherit;
|
||
font-weight: 700;
|
||
color: var(--on-accent);
|
||
background: var(--accent);
|
||
border: 2px solid var(--accent);
|
||
border-radius: var(--radius-pill);
|
||
cursor: pointer;
|
||
/* Un bouton tient sur une ligne (charte). */
|
||
white-space: nowrap;
|
||
/* Pas de délai ni de zoom sur un double toucher. */
|
||
touch-action: manipulation;
|
||
-webkit-tap-highlight-color: transparent;
|
||
transition: background-color var(--duration-instant) var(--easing-standard),
|
||
filter var(--duration-instant) var(--easing-standard);
|
||
}
|
||
|
||
button.secondary {
|
||
color: var(--text);
|
||
background: transparent;
|
||
border-color: var(--border-strong);
|
||
}
|
||
|
||
@media (hover: hover) {
|
||
button.secondary:hover:not(:disabled) {
|
||
background: var(--surface-sunken);
|
||
}
|
||
}
|
||
|
||
/* Retour visuel au toucher : le bouton descend de 1 px et s'assombrit de
|
||
* 6 %, sans ombre. */
|
||
button:active:not(:disabled) {
|
||
transform: translateY(1px);
|
||
filter: brightness(0.94);
|
||
}
|
||
|
||
button:disabled {
|
||
opacity: 0.45;
|
||
cursor: default;
|
||
}
|
||
|
||
/* Pictogramme seul (ou avec son libellé de 13 px dessous, barre haute). */
|
||
.icon-button {
|
||
display: inline-flex;
|
||
flex-direction: column;
|
||
flex: none;
|
||
align-items: center;
|
||
justify-content: center;
|
||
min-width: 44px;
|
||
min-height: 44px;
|
||
padding: 0;
|
||
color: var(--text);
|
||
background: transparent;
|
||
border: 0;
|
||
border-radius: var(--radius-md);
|
||
}
|
||
|
||
.icon-button.labelled {
|
||
position: relative;
|
||
width: 60px;
|
||
height: 52px;
|
||
}
|
||
|
||
/* Raccourci clavier d'un bouton, en petite touche (interaction.md) :
|
||
* seulement quand un clavier est détecté (classe keyboard, app.ts). */
|
||
.shortcut {
|
||
display: none;
|
||
}
|
||
|
||
.keyboard .shortcut {
|
||
display: inline-block;
|
||
min-width: 1.6em;
|
||
padding: 0 4px;
|
||
font: inherit;
|
||
font-size: 13px;
|
||
font-weight: 500;
|
||
line-height: 18px;
|
||
text-align: center;
|
||
border: 1px solid currentColor;
|
||
border-radius: 4px;
|
||
opacity: 0.8;
|
||
}
|
||
|
||
/* Barre haute : la touche en coin, sans changer la taille du bouton. */
|
||
.keyboard .icon-button.labelled .shortcut {
|
||
position: absolute;
|
||
top: 0;
|
||
right: 2px;
|
||
min-width: 0;
|
||
padding: 0 3px;
|
||
line-height: 15px;
|
||
background: var(--background);
|
||
}
|
||
|
||
.icon-button .label {
|
||
font-size: 13px;
|
||
line-height: 15px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
@media (hover: hover) {
|
||
.icon-button:hover:not(:disabled) {
|
||
background: var(--surface-sunken);
|
||
}
|
||
}
|
||
|
||
/* ------------------------------------------- Bandeaux des joueurs */
|
||
|
||
/* Un bandeau par camp, au-dessus du plateau pour l'ordinateur, dessous pour
|
||
* vous ; celui qui a la main est teinté. */
|
||
.strip {
|
||
display: flex;
|
||
flex: none;
|
||
gap: 10px;
|
||
align-items: center;
|
||
height: var(--strip-height);
|
||
padding: 0 4px 0 12px;
|
||
border-radius: var(--radius-md);
|
||
}
|
||
|
||
.strip.turn {
|
||
background: var(--accent-soft);
|
||
}
|
||
|
||
.strip .who {
|
||
flex: 1;
|
||
min-width: 0;
|
||
overflow: hidden;
|
||
font-weight: 700;
|
||
white-space: nowrap;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.strip .lead {
|
||
font-size: 15px;
|
||
line-height: 20px;
|
||
color: var(--muted);
|
||
white-space: nowrap;
|
||
}
|
||
|
||
/* Le compte de points : 20 px gras, chiffres alignés ; il se touche pour
|
||
* ouvrir la bulle du glossaire. */
|
||
.strip .count {
|
||
min-width: 56px;
|
||
min-height: 44px;
|
||
padding: 0 8px;
|
||
font-size: 20px;
|
||
line-height: 24px;
|
||
font-weight: 700;
|
||
font-variant-numeric: tabular-nums lining-nums;
|
||
text-align: right;
|
||
color: var(--text);
|
||
background: transparent;
|
||
border: 0;
|
||
border-radius: var(--radius-md);
|
||
}
|
||
|
||
.mini {
|
||
flex: none;
|
||
width: 18px;
|
||
height: 18px;
|
||
border-radius: 50%;
|
||
}
|
||
|
||
.mini-player {
|
||
background: var(--checker-player);
|
||
border: 2px solid var(--checker-player-edge);
|
||
}
|
||
|
||
.mini-computer {
|
||
background: var(--checker-computer);
|
||
border: 2px solid var(--checker-computer-edge);
|
||
}
|
||
|
||
/* La bulle du compte de points, posée sur le plateau, du côté du bandeau
|
||
* touché : elle ne déplace rien. */
|
||
.board-box {
|
||
position: relative;
|
||
flex: none;
|
||
}
|
||
|
||
/* Téléphone en portrait : le plateau, héros de l'écran, prend la largeur
|
||
* presque entière (8 px de marge au lieu de 16). */
|
||
@media (max-width: 40rem) {
|
||
html:not(.landscape) .board-box {
|
||
margin-inline: calc(var(--space-2) - var(--space-4));
|
||
}
|
||
}
|
||
|
||
.bubble {
|
||
position: absolute;
|
||
left: var(--space-2);
|
||
right: var(--space-2);
|
||
z-index: 5;
|
||
margin: 0;
|
||
padding: 10px 14px;
|
||
font-size: 15px;
|
||
line-height: 20px;
|
||
color: var(--text);
|
||
background: var(--surface);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius-md);
|
||
box-shadow: var(--shadow-raised);
|
||
animation: fade-in var(--duration-fast) var(--easing-standard);
|
||
}
|
||
|
||
.bubble[data-side="computer"] { top: var(--space-2); }
|
||
.bubble[data-side="player"] { bottom: var(--space-2); }
|
||
|
||
.bubble p {
|
||
margin: 0 0 var(--space-1);
|
||
}
|
||
|
||
.bubble-term {
|
||
font-weight: 700;
|
||
}
|
||
|
||
.link-button {
|
||
min-height: 44px;
|
||
padding: 0;
|
||
color: var(--accent);
|
||
background: transparent;
|
||
border: 0;
|
||
border-radius: 0;
|
||
text-decoration: underline;
|
||
text-underline-offset: 3px;
|
||
}
|
||
|
||
/* ----------------------------------------------- Sous le plateau */
|
||
|
||
/* Ligne d'information, toujours réservée : ce qui vient de se passer (coup
|
||
* de l'ordinateur, jet d'ouverture, chargement), et « Revoir » au bout. */
|
||
.infoline {
|
||
display: flex;
|
||
flex: none;
|
||
gap: var(--space-2);
|
||
align-items: center;
|
||
height: var(--infoline-height);
|
||
padding-left: 12px;
|
||
}
|
||
|
||
.info {
|
||
display: -webkit-box;
|
||
flex: 1;
|
||
margin: 0;
|
||
overflow: hidden;
|
||
font-size: 15px;
|
||
line-height: 20px;
|
||
color: var(--muted);
|
||
-webkit-box-orient: vertical;
|
||
-webkit-line-clamp: 2;
|
||
line-clamp: 2;
|
||
}
|
||
|
||
/* Un coup en notation du moteur, lien vers sa fiche du glossaire (ligne de
|
||
* l'ordinateur, feuille du maître) : couleur du texte, soulignement en
|
||
* pointillé discret. Le remplissage vertical d'un élément en ligne agrandit
|
||
* la zone d'appui sans changer la hauteur des lignes. */
|
||
a.notation {
|
||
padding-block: 8px;
|
||
color: inherit;
|
||
text-decoration-line: underline;
|
||
text-decoration-style: dotted;
|
||
text-decoration-color: var(--muted);
|
||
text-decoration-thickness: 1px;
|
||
}
|
||
|
||
.infoline .replay {
|
||
color: var(--accent);
|
||
}
|
||
|
||
/* La consigne du moment : ce qui doit ressortir de l'écran. Texte nu,
|
||
* 17 px gras, sur une hauteur réservée de deux lignes ; rien quand il n'y a
|
||
* rien à dire. La teinte « c'est à vous » est celle du bandeau du joueur. */
|
||
.prompt {
|
||
flex: none;
|
||
height: var(--prompt-height);
|
||
margin: var(--space-2) 0 0;
|
||
padding: 0 12px;
|
||
overflow: hidden;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.prompt.neutral {
|
||
font-weight: 400;
|
||
color: var(--muted);
|
||
}
|
||
|
||
/* L'ordinateur réfléchit : trois points qui apparaissent l'un après
|
||
* l'autre (la seule animation en boucle). */
|
||
.prompt.thinking::after {
|
||
content: "";
|
||
animation: thinking 1.2s steps(4, end) infinite;
|
||
}
|
||
|
||
@keyframes thinking {
|
||
0% { content: ""; }
|
||
25% { content: "."; }
|
||
50% { content: ".."; }
|
||
75% { content: "..."; }
|
||
}
|
||
|
||
/* Barre d'actions collée en bas : l'action secondaire à gauche, la
|
||
* principale à droite, sous le pouce. */
|
||
.actions {
|
||
position: sticky;
|
||
bottom: 0;
|
||
z-index: 2;
|
||
display: grid;
|
||
flex: none;
|
||
grid-template-columns: 1fr 1.6fr;
|
||
gap: var(--space-2);
|
||
height: var(--actions-height);
|
||
padding: var(--space-3) 0 var(--space-4);
|
||
background: var(--background);
|
||
border-top: 1px solid var(--border);
|
||
}
|
||
|
||
.actions .slot {
|
||
display: flex;
|
||
min-width: 0;
|
||
}
|
||
|
||
.actions .slot button {
|
||
flex: 1;
|
||
min-width: 0;
|
||
padding: 0 12px;
|
||
display: inline-flex;
|
||
gap: 6px;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.actions .slot .icon {
|
||
width: 20px;
|
||
height: 20px;
|
||
}
|
||
|
||
.move-hint {
|
||
align-self: center;
|
||
margin: 0;
|
||
font-size: 15px;
|
||
line-height: 20px;
|
||
color: var(--muted);
|
||
text-align: center;
|
||
}
|
||
|
||
/* --------------------------------------------------- Fenêtres */
|
||
|
||
/* Voile sous le menu et les panneaux : il assombrit l'écran derrière. */
|
||
.veil {
|
||
position: fixed;
|
||
inset: 0;
|
||
z-index: 10;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: var(--space-4);
|
||
background: var(--scrim);
|
||
animation: fade-in var(--duration-fast) var(--easing-standard);
|
||
}
|
||
|
||
/* Le menu : une feuille qui monte du bas. */
|
||
.sheet-veil {
|
||
z-index: 11; /* ouvert, le menu passe devant un panneau */
|
||
align-items: flex-end;
|
||
padding: 0;
|
||
}
|
||
|
||
.sheet {
|
||
width: min(100%, var(--page-width));
|
||
max-height: 100%;
|
||
overflow-y: auto;
|
||
padding: var(--space-2) var(--space-4) var(--space-6);
|
||
color: var(--text);
|
||
background: var(--surface);
|
||
border-radius: 20px 20px 0 0;
|
||
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.2);
|
||
animation: sheet-up var(--duration-moderate) var(--easing-standard);
|
||
}
|
||
|
||
.sheet-head {
|
||
position: relative;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
min-height: 52px;
|
||
}
|
||
|
||
.grip {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 50%;
|
||
width: 40px;
|
||
height: 4px;
|
||
margin-left: -20px;
|
||
background: var(--border-strong);
|
||
border-radius: 2px;
|
||
}
|
||
|
||
.sheet-title {
|
||
margin: 0;
|
||
font-size: 20px;
|
||
line-height: 26px;
|
||
}
|
||
|
||
.sheet .item {
|
||
display: flex;
|
||
gap: 14px;
|
||
align-items: center;
|
||
width: 100%;
|
||
min-height: 52px;
|
||
padding: 0;
|
||
font-weight: 500;
|
||
text-align: left;
|
||
color: var(--text);
|
||
background: transparent;
|
||
border: 0;
|
||
border-bottom: 1px solid var(--border);
|
||
border-radius: 0;
|
||
}
|
||
|
||
.sheet .item:last-child {
|
||
border-bottom: 0;
|
||
}
|
||
|
||
.sheet .item .icon {
|
||
color: var(--muted);
|
||
}
|
||
|
||
.item-value {
|
||
margin-left: auto;
|
||
font-size: 15px;
|
||
color: var(--muted);
|
||
}
|
||
|
||
/* Interrupteur (Vibrations, écran allumé). */
|
||
.switch {
|
||
position: relative;
|
||
flex: none;
|
||
width: 44px;
|
||
height: 26px;
|
||
margin-left: auto;
|
||
background: var(--border-strong);
|
||
border-radius: 13px;
|
||
transition: background-color var(--duration-fast) var(--easing-standard);
|
||
}
|
||
|
||
.switch::after {
|
||
content: "";
|
||
position: absolute;
|
||
top: 3px;
|
||
left: 3px;
|
||
width: 20px;
|
||
height: 20px;
|
||
background: var(--surface);
|
||
border-radius: 50%;
|
||
transition: transform var(--duration-fast) var(--easing-standard);
|
||
}
|
||
|
||
.item[aria-checked="true"] .switch {
|
||
background: var(--accent);
|
||
}
|
||
|
||
.item[aria-checked="true"] .switch::after {
|
||
background: var(--on-accent);
|
||
transform: translateX(18px);
|
||
}
|
||
|
||
/* Panneau centré : confirmation du double, fin de partie, double de
|
||
* l'ordinateur en paysage. */
|
||
.panel {
|
||
width: min(24rem, 100%);
|
||
padding: var(--space-4);
|
||
color: var(--text);
|
||
background: var(--surface);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius-md);
|
||
box-shadow: var(--shadow-raised);
|
||
animation: panel-in var(--duration-moderate) var(--easing-standard);
|
||
}
|
||
|
||
.panel p {
|
||
margin: 0 0 var(--space-4);
|
||
font-size: 20px;
|
||
line-height: 26px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.panel p:empty {
|
||
display: none;
|
||
}
|
||
|
||
/* Fin de partie : surtitre, titre de 24 px, puis le détail des points. */
|
||
.panel .overline {
|
||
margin: 0 0 var(--space-1);
|
||
font-size: 13px;
|
||
line-height: 16px;
|
||
letter-spacing: 0.08em;
|
||
text-transform: uppercase;
|
||
color: var(--muted);
|
||
}
|
||
|
||
.panel .panel-title {
|
||
margin-bottom: var(--space-1);
|
||
font-size: 24px;
|
||
line-height: 30px;
|
||
}
|
||
|
||
.panel .panel-detail {
|
||
font-size: 17px;
|
||
line-height: 25px;
|
||
font-weight: 400;
|
||
}
|
||
|
||
.panel-actions {
|
||
display: flex;
|
||
gap: var(--space-2);
|
||
}
|
||
|
||
.panel-actions button {
|
||
flex: 1 1 0;
|
||
padding: 0 12px;
|
||
}
|
||
|
||
/* Fin de partie : « Changer les réglages », lien secondaire sous les
|
||
* boutons. */
|
||
.panel-link {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
min-height: 44px;
|
||
margin-top: var(--space-2);
|
||
font-weight: 700;
|
||
}
|
||
|
||
/* « Nouvelle partie commencée. Reprendre l'ancienne », 10 s, avec sa
|
||
* barre de temps. */
|
||
.banner {
|
||
position: fixed;
|
||
left: 50%;
|
||
bottom: calc(var(--actions-height) + var(--space-2));
|
||
z-index: 9;
|
||
display: flex;
|
||
gap: var(--space-3);
|
||
align-items: center;
|
||
width: min(24rem, calc(100% - 2 * var(--space-4)));
|
||
padding: var(--space-2) var(--space-3) var(--space-3);
|
||
overflow: hidden;
|
||
font-size: 15px;
|
||
line-height: 20px;
|
||
background: var(--surface);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius-md);
|
||
box-shadow: var(--shadow-raised);
|
||
transform: translateX(-50%);
|
||
animation: fade-in var(--duration-fast) var(--easing-standard);
|
||
}
|
||
|
||
.banner span:first-child {
|
||
flex: 1;
|
||
}
|
||
|
||
.banner button {
|
||
flex: none;
|
||
min-height: 44px;
|
||
padding: 0 14px;
|
||
}
|
||
|
||
.banner-timer {
|
||
position: absolute;
|
||
left: 0;
|
||
bottom: 0;
|
||
width: 100%;
|
||
height: 4px;
|
||
background: var(--accent);
|
||
transform-origin: left;
|
||
}
|
||
|
||
.banner-timer.running {
|
||
animation: banner-timer 10s linear forwards;
|
||
}
|
||
|
||
@keyframes banner-timer {
|
||
from { transform: scaleX(1); }
|
||
to { transform: scaleX(0); }
|
||
}
|
||
|
||
@keyframes fade-in {
|
||
from { opacity: 0; }
|
||
to { opacity: 1; }
|
||
}
|
||
|
||
@keyframes sheet-up {
|
||
from { transform: translateY(100%); }
|
||
to { transform: translateY(0); }
|
||
}
|
||
|
||
@keyframes panel-in {
|
||
from { opacity: 0; transform: translateY(8px); }
|
||
to { opacity: 1; transform: translateY(0); }
|
||
}
|
||
|
||
/* Mouvement réduit : tout est instantané, rien ne roule ni ne glisse ; la
|
||
* barre de temps reste visible, immobile. */
|
||
@media (prefers-reduced-motion: reduce) {
|
||
*,
|
||
*::before,
|
||
*::after {
|
||
animation-duration: 0s !important;
|
||
transition-duration: 0s !important;
|
||
}
|
||
|
||
.prompt.thinking::after {
|
||
animation: none;
|
||
content: "…";
|
||
}
|
||
|
||
.banner-timer.running {
|
||
animation: none;
|
||
}
|
||
|
||
button:active:not(:disabled) {
|
||
transform: none;
|
||
}
|
||
}
|
||
|
||
/* ------------------------------------------------------------ Plateau */
|
||
|
||
.board {
|
||
display: block;
|
||
width: 100%;
|
||
height: auto;
|
||
aspect-ratio: 640 / 520;
|
||
user-select: none;
|
||
-webkit-user-select: none;
|
||
touch-action: manipulation;
|
||
-webkit-tap-highlight-color: transparent;
|
||
font-family: var(--font-sans);
|
||
/* Alegreya Sans dessine par défaut des chiffres elzéviriens (de hauteurs
|
||
* variables) : sur le plateau, des chiffres alignés se lisent mieux. */
|
||
font-variant-numeric: tabular-nums lining-nums;
|
||
}
|
||
|
||
/* Le plateau de la partie : le doigt y fait glisser les pions, il ne fait
|
||
* ni défiler ni zoomer la page (glisser-déposer, double toucher ; charte,
|
||
* 1i). Les autres plateaux (accueil, tutoriel, position) laissent défiler. */
|
||
#board {
|
||
touch-action: none;
|
||
}
|
||
|
||
.board-frame { fill: var(--frame); }
|
||
.board-bed { fill: var(--bed); }
|
||
.board-bar { fill: var(--bar); }
|
||
.board-tray { fill: var(--tray); }
|
||
.point-a { fill: var(--point-a); }
|
||
.point-b { fill: var(--point-b); }
|
||
|
||
/* Numéros des flèches : leur taille est une mesure du dessin (attribut
|
||
* font-size), calculée pour faire au moins 12 px à l'écran (geometry.ts).
|
||
* Posés sur le cadre, en portrait comme en paysage. */
|
||
.point-number {
|
||
fill: var(--point-number);
|
||
font-weight: 500;
|
||
text-anchor: middle;
|
||
}
|
||
|
||
.checker {
|
||
stroke-width: 2;
|
||
}
|
||
|
||
.checker-player {
|
||
fill: var(--checker-player);
|
||
stroke: var(--checker-player-edge);
|
||
}
|
||
|
||
.checker-computer {
|
||
fill: var(--checker-computer);
|
||
stroke: var(--checker-computer-edge);
|
||
}
|
||
|
||
/* Filet intérieur des pions (bundle.css), l'écho du logo : un cercle aux
|
||
* trois cinquièmes du rayon, dessiné avec chaque pion (board-view.ts). */
|
||
.checker-ring {
|
||
fill: none;
|
||
stroke-width: 1.5;
|
||
}
|
||
|
||
.ring-player { stroke: var(--checker-player-edge); }
|
||
.ring-computer { stroke: var(--checker-computer-edge); }
|
||
|
||
.checker.movable {
|
||
stroke: var(--highlight);
|
||
stroke-width: 3;
|
||
}
|
||
|
||
.checker.selected {
|
||
stroke: var(--highlight);
|
||
stroke-width: 6;
|
||
}
|
||
|
||
/* Glisser-déposer (charte, 1i) : le pion parti laisse un fantôme en
|
||
* pointillés ; le pion glissé, agrandi, passe devant tout. */
|
||
.drag-origin .checker {
|
||
fill: none;
|
||
stroke: var(--highlight);
|
||
stroke-width: 2.5;
|
||
stroke-dasharray: 5 4;
|
||
}
|
||
|
||
.drag-origin .checker-ring,
|
||
.drag-origin .checker-count {
|
||
display: none;
|
||
}
|
||
|
||
.drag-piece { pointer-events: none; }
|
||
|
||
.checker.dragged {
|
||
stroke: var(--highlight);
|
||
stroke-width: 4;
|
||
}
|
||
|
||
/* Clavier : le pion ou la case d'arrivée choisis aux flèches. */
|
||
.key-focus {
|
||
fill: none;
|
||
stroke: var(--focus);
|
||
stroke-width: 3;
|
||
}
|
||
|
||
/* Tailles des chiffres du plateau : attribut font-size, calculé par
|
||
* geometry.ts (13 px au moins à l'écran). */
|
||
.checker-count {
|
||
font-weight: 700;
|
||
text-anchor: middle;
|
||
}
|
||
|
||
.count-player { fill: var(--count-player); }
|
||
.count-computer { fill: var(--count-computer); }
|
||
|
||
.target-zone { fill: var(--target); }
|
||
/* Le dernier coup de l'ordinateur (couleur laiton, charte) : une flèche par
|
||
* demi-coup, les pions arrivés et frappés entourés, un pion fantôme là où
|
||
* un pion est parti. */
|
||
/* Épaisseur des flèches : attribut stroke-width (2,5 px à l'écran,
|
||
* geometry.ts) ; elles passent sous les pions. */
|
||
.trace-arrow {
|
||
stroke: var(--last-move);
|
||
stroke-linecap: round;
|
||
opacity: 0.85;
|
||
}
|
||
|
||
.trace-head { fill: var(--last-move); }
|
||
|
||
/* Où le pion touché se posera : un anneau pointillé, comme les fantômes du
|
||
* coup de l'ordinateur, en brique. */
|
||
.landing {
|
||
fill: none;
|
||
stroke: var(--highlight);
|
||
stroke-width: 3;
|
||
stroke-dasharray: 6 5;
|
||
}
|
||
|
||
.trace-landed,
|
||
.trace-hit {
|
||
fill: none;
|
||
stroke: var(--last-move);
|
||
stroke-width: 4;
|
||
}
|
||
|
||
.trace-hit { stroke-dasharray: 6 4; }
|
||
|
||
.trace-ghost {
|
||
fill: none;
|
||
stroke: var(--last-move);
|
||
stroke-width: 2.5;
|
||
stroke-dasharray: 5 4;
|
||
}
|
||
|
||
.die-player { fill: var(--die-player); stroke: var(--checker-player-edge); stroke-width: 1.5; }
|
||
.die-computer { fill: var(--die-computer); stroke: var(--checker-computer-edge); stroke-width: 1.5; }
|
||
.pip-player { fill: var(--pip-player); }
|
||
.pip-computer { fill: var(--pip-computer); }
|
||
|
||
/* Dés du joueur en attente d'être lancés, et videau quand il peut doubler :
|
||
* ils se touchent comme les boutons. */
|
||
.die-waiting rect {
|
||
stroke: var(--highlight);
|
||
stroke-width: 2.5;
|
||
stroke-dasharray: 5 4;
|
||
}
|
||
|
||
.cube.can-double .cube-face {
|
||
stroke: var(--highlight);
|
||
stroke-width: 3;
|
||
}
|
||
|
||
/* Jet sans coup possible : dés estompés et barrés. */
|
||
.die-blocked { opacity: 0.5; }
|
||
|
||
.die-strike {
|
||
stroke: var(--text);
|
||
stroke-width: 3;
|
||
stroke-linecap: round;
|
||
}
|
||
|
||
/* Dé déjà utilisé par un demi-coup du coup en cours : estompé, sans être
|
||
* barré (il n'est pas perdu : « Annuler » le rend). */
|
||
.die-used { opacity: 0.35; }
|
||
|
||
.cube-face { fill: var(--cube); stroke: var(--checker-player-edge); stroke-width: 2; }
|
||
|
||
.cube-value {
|
||
fill: var(--cube-text);
|
||
font-weight: 800;
|
||
text-anchor: middle;
|
||
}
|
||
|
||
.hit {
|
||
fill: transparent;
|
||
cursor: pointer;
|
||
}
|
||
|
||
/* Paysage : comptes de points en pastilles aux bouts de la barre, consigne
|
||
* dans la bande, commandes à gauche. */
|
||
.pip-chip { stroke-width: 1.5; }
|
||
.chip-player { fill: var(--checker-player); stroke: var(--checker-player-edge); }
|
||
.chip-computer { fill: var(--checker-computer); stroke: var(--checker-computer-edge); }
|
||
|
||
.pip-chip-text {
|
||
font-weight: 700;
|
||
text-anchor: middle;
|
||
}
|
||
|
||
.chip-text-player { fill: var(--pip-player); }
|
||
.chip-text-computer { fill: var(--pip-computer); }
|
||
|
||
.band-pill { fill: var(--accent-soft); }
|
||
|
||
.band-text {
|
||
fill: var(--text);
|
||
font-weight: 700;
|
||
text-anchor: middle;
|
||
}
|
||
|
||
.control-circle {
|
||
fill: none;
|
||
stroke: var(--point-number);
|
||
stroke-width: 2;
|
||
}
|
||
|
||
.control-icon {
|
||
fill: none;
|
||
stroke: var(--point-number);
|
||
stroke-width: 2px;
|
||
stroke-linecap: round;
|
||
stroke-linejoin: round;
|
||
vector-effect: non-scaling-stroke;
|
||
}
|
||
|
||
.control.disabled { opacity: 0.35; }
|
||
|
||
/* ------------------------------------------------------- Mode paysage */
|
||
|
||
/* Téléphone tourné (ADR 0012) : le plateau est l'écran, sur la hauteur
|
||
* réelle (barre d'adresse comprise), cadre noyer jusqu'aux bords. La
|
||
* classe vient de app.ts (rotation du téléphone, ou repli du plein écran). */
|
||
html.landscape,
|
||
html.landscape body {
|
||
height: 100%;
|
||
overflow: hidden;
|
||
}
|
||
|
||
html.landscape body {
|
||
max-width: none;
|
||
padding: 0;
|
||
background: var(--frame);
|
||
}
|
||
|
||
html.landscape .topbar,
|
||
html.landscape .strip,
|
||
html.landscape .infoline,
|
||
html.landscape .prompt,
|
||
html.landscape .spacer,
|
||
html.landscape .actions {
|
||
display: none;
|
||
}
|
||
|
||
html.landscape .board-box {
|
||
position: fixed;
|
||
inset: 0;
|
||
}
|
||
|
||
html.landscape .board {
|
||
width: 100%;
|
||
height: 100%;
|
||
aspect-ratio: auto;
|
||
}
|
||
|
||
html.landscape .banner {
|
||
bottom: var(--space-2);
|
||
}
|
||
|
||
/* L'aide et la vue d'une position restent des pages qu'on fait défiler. */
|
||
html.landscape.page-open,
|
||
html.landscape.page-open body {
|
||
height: auto;
|
||
overflow: visible;
|
||
}
|
||
|
||
html.landscape.page-open body {
|
||
padding: 0 var(--space-4);
|
||
background: var(--background);
|
||
}
|
||
|
||
/* Hors de l'écran de jeu, la barre haute (Aide, Plein écran, Menu) reste
|
||
* en paysage : seul le plateau en paysage s'en passe. Les écrans qui ont
|
||
* leur propre en-tête (bare) la masquent toujours. */
|
||
html.landscape.page-open:not(.bare) .topbar {
|
||
display: flex;
|
||
}
|
||
|
||
/* Repli du plein écran : le paysage ne peut pas être verrouillé, l'écran
|
||
* entier tourne d'un quart de tour dans le portrait. Les touchers suivent
|
||
* la rotation ; le plateau et les fenêtres sont posés dans #screen. */
|
||
html.rotated .screen {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100vh;
|
||
width: 100dvh;
|
||
height: 100vw;
|
||
min-height: 0;
|
||
overflow: hidden;
|
||
transform-origin: top left;
|
||
transform: rotate(90deg) translateY(-100%);
|
||
}
|
||
|
||
html.rotated .board-box,
|
||
html.rotated .veil {
|
||
position: absolute;
|
||
}
|
||
|
||
html.rotated .banner {
|
||
position: absolute;
|
||
}
|
||
|
||
/* ------------------------------------------------------- Mes parties */
|
||
|
||
/* La feuille « Mes parties » (app/src/ui/games-view.ts) : une partie par
|
||
* ligne, ses actions dessous, ses branches dépliables. */
|
||
.games-list,
|
||
.games-branches {
|
||
margin: 0;
|
||
padding: 0;
|
||
list-style: none;
|
||
}
|
||
|
||
.games-item {
|
||
padding: var(--space-2) 0 var(--space-4);
|
||
border-bottom: 1px solid var(--border);
|
||
}
|
||
|
||
.games-item:last-child {
|
||
border-bottom: 0;
|
||
}
|
||
|
||
.games-item p {
|
||
margin: 0 0 var(--space-2);
|
||
font-weight: 500;
|
||
}
|
||
|
||
.games-actions {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: var(--space-2);
|
||
}
|
||
|
||
.games-branch {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: var(--space-2);
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding-top: var(--space-2);
|
||
color: var(--muted);
|
||
}
|
||
|
||
/* --------------------------------------------------------------- Aide */
|
||
|
||
.help {
|
||
max-width: var(--page-width);
|
||
margin: 0 auto;
|
||
}
|
||
|
||
.help h2 {
|
||
margin: var(--space-8) 0 var(--space-2);
|
||
font-size: 24px;
|
||
line-height: 30px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.help h3 {
|
||
margin: var(--space-6) 0 var(--space-1);
|
||
font-size: 20px;
|
||
line-height: 26px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.help p {
|
||
margin: var(--space-2) 0;
|
||
}
|
||
|
||
.steps {
|
||
margin: var(--space-2) 0;
|
||
padding-left: var(--space-6);
|
||
}
|
||
|
||
.steps li + li {
|
||
margin-top: var(--space-1);
|
||
}
|
||
|
||
.steps li::marker {
|
||
color: var(--muted);
|
||
}
|
||
|
||
/* Glossaire : une liste de définitions, sur une carte. */
|
||
.glossary {
|
||
margin: var(--space-3) 0 0;
|
||
padding: var(--space-1) var(--space-4);
|
||
background: var(--surface);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius-md);
|
||
box-shadow: var(--shadow-raised);
|
||
}
|
||
|
||
.glossary .term-card {
|
||
padding-top: var(--space-3);
|
||
font-weight: 700;
|
||
}
|
||
|
||
.glossary dd {
|
||
margin: 0;
|
||
padding-bottom: var(--space-3);
|
||
}
|
||
|
||
.glossary dd + dt {
|
||
border-top: 1px solid var(--border);
|
||
}
|
||
|
||
.about {
|
||
margin-top: var(--space-2);
|
||
font-size: 15px;
|
||
line-height: 20px;
|
||
color: var(--muted);
|
||
}
|
||
|
||
.help {
|
||
user-select: text;
|
||
-webkit-user-select: text;
|
||
}
|
||
|
||
/* La barre haute de l'aide (« Retour » et onglets) reste en vue quand la
|
||
* page défile. Sa hauteur est fixe (12 + 48 + 8 + 44 + 1 px de filet) : une
|
||
* question ou un terme ouvert par son adresse s'arrête 12 px sous elle. */
|
||
.help {
|
||
--help-bar-height: 113px;
|
||
}
|
||
|
||
.help-bar {
|
||
position: sticky;
|
||
top: env(safe-area-inset-top);
|
||
z-index: 3;
|
||
height: var(--help-bar-height);
|
||
margin-inline: calc(-1 * var(--space-4));
|
||
padding: var(--space-3) var(--space-4) 0;
|
||
background: var(--background);
|
||
}
|
||
|
||
.help .question,
|
||
.glossary .term-card {
|
||
scroll-margin-top: calc(var(--help-bar-height) + 12px + env(safe-area-inset-top));
|
||
}
|
||
|
||
/* Les onglets de l'aide : des liens, l'onglet courant souligné en brique ;
|
||
* sur une ligne, qui défile si l'écran est trop étroit. */
|
||
.help-tabs {
|
||
display: flex;
|
||
gap: var(--space-1);
|
||
overflow-x: auto;
|
||
white-space: nowrap;
|
||
margin-top: var(--space-2);
|
||
border-bottom: 1px solid var(--border);
|
||
}
|
||
|
||
.help-tabs a {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
min-height: 44px;
|
||
padding: 0 var(--space-3);
|
||
font-weight: 500;
|
||
color: var(--muted);
|
||
text-decoration: none;
|
||
border-bottom: 3px solid transparent;
|
||
}
|
||
|
||
.help-tabs a[aria-current="page"] {
|
||
font-weight: 700;
|
||
color: var(--text);
|
||
border-bottom-color: var(--accent);
|
||
}
|
||
|
||
.help-notice:empty {
|
||
display: none;
|
||
}
|
||
|
||
/* Une question de l'aide : son titre est un lien qui l'ouvre (son adresse),
|
||
* ou la referme quand elle est ouverte. */
|
||
.question {
|
||
border-bottom: 1px solid var(--border);
|
||
}
|
||
|
||
.help .question h3 {
|
||
margin: 0;
|
||
}
|
||
|
||
.question h3 a {
|
||
display: flex;
|
||
gap: var(--space-2);
|
||
align-items: center;
|
||
min-height: 52px;
|
||
padding: var(--space-2) 0;
|
||
color: var(--text);
|
||
text-decoration: none;
|
||
}
|
||
|
||
.question h3 a::after {
|
||
content: "";
|
||
flex: none;
|
||
width: 9px;
|
||
height: 9px;
|
||
margin: 0 6px 4px auto;
|
||
border-right: 2px solid var(--muted);
|
||
border-bottom: 2px solid var(--muted);
|
||
transform: rotate(45deg);
|
||
}
|
||
|
||
.question.open h3 a::after {
|
||
margin-bottom: -4px;
|
||
transform: rotate(-135deg);
|
||
}
|
||
|
||
.answer {
|
||
padding-bottom: var(--space-3);
|
||
}
|
||
|
||
/* Le terme ouvert par son adresse (#/glossaire/<terme>). */
|
||
.glossary dt a {
|
||
color: var(--text);
|
||
text-decoration: none;
|
||
}
|
||
|
||
.glossary dt.current,
|
||
.glossary dt.current + dd {
|
||
margin-inline: calc(-1 * var(--space-4));
|
||
padding-inline: var(--space-4);
|
||
background: var(--accent-soft);
|
||
/* Le surlignage montre où l'on arrive, puis s'efface après 2 s. */
|
||
animation: term-fade var(--duration-moderate) var(--easing-exit) 2s forwards;
|
||
}
|
||
|
||
@keyframes term-fade {
|
||
to { background-color: transparent; }
|
||
}
|
||
|
||
/* -------------------------------------------------- Liens et boutons */
|
||
|
||
/* Un lien qui mène à un écran, avec l'allure d'un bouton. */
|
||
a.button {
|
||
display: inline-flex;
|
||
gap: 6px;
|
||
align-items: center;
|
||
justify-content: center;
|
||
min-height: var(--button-height);
|
||
padding: 0 20px;
|
||
font-weight: 700;
|
||
color: var(--on-accent);
|
||
text-decoration: none;
|
||
background: var(--accent);
|
||
border: 2px solid var(--accent);
|
||
border-radius: var(--radius-pill);
|
||
white-space: nowrap;
|
||
touch-action: manipulation;
|
||
-webkit-tap-highlight-color: transparent;
|
||
}
|
||
|
||
a.button.secondary {
|
||
color: var(--text);
|
||
background: transparent;
|
||
border-color: var(--border-strong);
|
||
}
|
||
|
||
a.button:active {
|
||
transform: translateY(1px);
|
||
filter: brightness(0.94);
|
||
}
|
||
|
||
a.icon-button,
|
||
a.item,
|
||
a.link-button {
|
||
text-decoration: none;
|
||
touch-action: manipulation;
|
||
-webkit-tap-highlight-color: transparent;
|
||
}
|
||
|
||
a.link-button {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
text-decoration: underline;
|
||
}
|
||
|
||
.infoline .copy-link {
|
||
color: var(--accent);
|
||
}
|
||
|
||
/* Zone de texte de la copie de repli (presse-papiers), hors de l'écran. */
|
||
.offscreen {
|
||
position: fixed;
|
||
top: 0;
|
||
left: -10000px;
|
||
opacity: 0;
|
||
}
|
||
|
||
/* ------------------------------------------------ Vue d'une position */
|
||
|
||
.position-view {
|
||
max-width: var(--page-width);
|
||
margin: 0 auto;
|
||
padding-bottom: var(--space-6);
|
||
}
|
||
|
||
.position-title {
|
||
margin: var(--space-6) 0 var(--space-2);
|
||
font-size: 24px;
|
||
line-height: 30px;
|
||
}
|
||
|
||
.position-message:empty {
|
||
display: none;
|
||
}
|
||
|
||
.position-board {
|
||
margin: var(--space-2) 0;
|
||
}
|
||
|
||
.position-detail {
|
||
margin: var(--space-2) 0 var(--space-4);
|
||
font-size: 15px;
|
||
line-height: 20px;
|
||
color: var(--muted);
|
||
}
|
||
|
||
/* Les actions empilées sur toute la largeur, la principale en premier. */
|
||
.position-actions {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--space-2);
|
||
}
|
||
|
||
.position-actions > * {
|
||
width: 100%;
|
||
}
|
||
|
||
#position-copy {
|
||
display: inline-flex;
|
||
gap: 6px;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
#position-copy .icon {
|
||
width: 20px;
|
||
height: 20px;
|
||
}
|
||
|
||
/* ------------------------------------------- Accueil, tutoriel, aide */
|
||
|
||
/* Maquettes « Étape 0e.5 » et « Accueil » ; règles :
|
||
* docs/identite/charte/accueil-tutoriel-aide.md. */
|
||
|
||
.brand-link {
|
||
display: flex;
|
||
align-items: center;
|
||
min-height: 44px;
|
||
}
|
||
|
||
/* Le tutoriel et le premier lancement ont leur propre en-tête. */
|
||
html.bare .topbar {
|
||
display: none;
|
||
}
|
||
|
||
.home,
|
||
.tutorial {
|
||
max-width: var(--page-width);
|
||
margin: 0 auto;
|
||
padding-bottom: var(--space-6);
|
||
}
|
||
|
||
.overline {
|
||
margin: 0;
|
||
font-size: 13px;
|
||
line-height: 16px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.08em;
|
||
text-transform: uppercase;
|
||
color: var(--muted);
|
||
}
|
||
|
||
.muted {
|
||
color: var(--muted);
|
||
}
|
||
|
||
.caption {
|
||
margin: 0;
|
||
font-size: 13px;
|
||
line-height: 18px;
|
||
color: var(--muted);
|
||
}
|
||
|
||
.card {
|
||
display: block;
|
||
padding: var(--space-4);
|
||
color: var(--text);
|
||
text-decoration: none;
|
||
background: var(--surface);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius-md);
|
||
box-shadow: var(--shadow-raised);
|
||
}
|
||
|
||
/* Une étiquette d'action dans une carte-lien, en contour. */
|
||
.pill {
|
||
display: inline-flex;
|
||
flex: none;
|
||
align-items: center;
|
||
min-height: 44px;
|
||
padding: 0 16px;
|
||
font-weight: 700;
|
||
color: var(--text);
|
||
border: 2px solid var(--border-strong);
|
||
border-radius: var(--radius-pill);
|
||
}
|
||
|
||
/* Premier lancement. */
|
||
.welcome {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--space-6);
|
||
min-height: 100vh;
|
||
min-height: 100dvh;
|
||
padding: var(--space-6) 0 var(--space-6);
|
||
}
|
||
|
||
.welcome-logo {
|
||
margin: 0;
|
||
}
|
||
|
||
.welcome-logo img {
|
||
height: 34px;
|
||
width: auto;
|
||
}
|
||
|
||
.welcome-board {
|
||
margin-inline: calc(-1 * var(--space-2));
|
||
width: calc(100% + 2 * var(--space-2));
|
||
}
|
||
|
||
.welcome-text h2,
|
||
.home-intro h2 {
|
||
margin: 0 0 var(--space-2);
|
||
font-size: 32px;
|
||
line-height: 36px;
|
||
font-weight: 800;
|
||
letter-spacing: -0.01em;
|
||
}
|
||
|
||
.welcome-text p,
|
||
.home-intro p {
|
||
margin: 0;
|
||
}
|
||
|
||
.welcome-choices {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 10px;
|
||
margin-top: auto;
|
||
}
|
||
|
||
.choice {
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
min-height: 64px;
|
||
padding: 10px 20px;
|
||
color: var(--text);
|
||
text-decoration: none;
|
||
border: 2px solid var(--border-strong);
|
||
border-radius: 16px;
|
||
touch-action: manipulation;
|
||
-webkit-tap-highlight-color: transparent;
|
||
}
|
||
|
||
.choice span {
|
||
font-size: 15px;
|
||
line-height: 20px;
|
||
color: var(--muted);
|
||
}
|
||
|
||
.choice.primary {
|
||
color: var(--on-accent);
|
||
background: var(--accent);
|
||
border-color: var(--accent);
|
||
}
|
||
|
||
.choice.primary span {
|
||
color: var(--on-accent);
|
||
}
|
||
|
||
.choice:active {
|
||
transform: translateY(1px);
|
||
filter: brightness(0.94);
|
||
}
|
||
|
||
.welcome-choices .caption {
|
||
margin-top: var(--space-1);
|
||
text-align: center;
|
||
}
|
||
|
||
/* Accueil. */
|
||
.home-main {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 20px;
|
||
padding-top: var(--space-2);
|
||
}
|
||
|
||
.home-game {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 14px;
|
||
}
|
||
|
||
.home-game-top {
|
||
display: flex;
|
||
gap: 14px;
|
||
align-items: center;
|
||
}
|
||
|
||
.home-mini {
|
||
flex: none;
|
||
width: 132px;
|
||
}
|
||
|
||
/* La miniature ne porte pas les numéros des flèches, illisibles à cette
|
||
* taille. */
|
||
.home-board .point-number {
|
||
display: none;
|
||
}
|
||
|
||
.home-facts {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 2px;
|
||
min-width: 0;
|
||
}
|
||
|
||
.home-pips {
|
||
font-size: 15px;
|
||
line-height: 20px;
|
||
color: var(--muted);
|
||
font-variant-numeric: tabular-nums lining-nums;
|
||
}
|
||
|
||
.home-actions {
|
||
display: flex;
|
||
gap: var(--space-2);
|
||
}
|
||
|
||
.home-actions > * {
|
||
flex: 1 1 0;
|
||
min-width: 0;
|
||
padding: 0 12px;
|
||
}
|
||
|
||
.install-card {
|
||
display: flex;
|
||
gap: var(--space-3);
|
||
align-items: center;
|
||
margin-top: calc(-1 * var(--space-2));
|
||
padding: 10px 4px 10px 14px;
|
||
background: var(--surface-sunken);
|
||
border-radius: var(--radius-md);
|
||
}
|
||
|
||
.install-card .install-symbol {
|
||
flex: none;
|
||
width: 32px;
|
||
height: 32px;
|
||
}
|
||
|
||
.install-text {
|
||
display: flex;
|
||
flex: 1;
|
||
flex-direction: column;
|
||
min-width: 0;
|
||
font-size: 15px;
|
||
line-height: 20px;
|
||
}
|
||
|
||
.install-card button.secondary {
|
||
flex: none;
|
||
min-height: 44px;
|
||
padding: 0 14px;
|
||
background: var(--surface);
|
||
}
|
||
|
||
.install-card .icon-button .icon {
|
||
width: 18px;
|
||
height: 18px;
|
||
color: var(--muted);
|
||
}
|
||
|
||
.home-rules {
|
||
display: flex;
|
||
gap: var(--space-3);
|
||
align-items: center;
|
||
}
|
||
|
||
.home-rules-text {
|
||
display: flex;
|
||
flex: 1;
|
||
flex-direction: column;
|
||
min-width: 0;
|
||
}
|
||
|
||
.home-rules-text .muted {
|
||
font-size: 15px;
|
||
line-height: 20px;
|
||
}
|
||
|
||
/* La ligne de progression : un lien vers #/progression (1h), haut de
|
||
* 44 px pour le doigt, en caption. */
|
||
.home-progress {
|
||
display: flex;
|
||
gap: var(--space-1);
|
||
align-items: center;
|
||
min-height: 44px;
|
||
text-decoration: none;
|
||
}
|
||
|
||
.home-progress[hidden] {
|
||
display: none;
|
||
}
|
||
|
||
.home-progress-text {
|
||
text-decoration: underline;
|
||
text-underline-offset: 3px;
|
||
}
|
||
|
||
.home-progress .icon {
|
||
flex: none;
|
||
width: 16px;
|
||
height: 16px;
|
||
}
|
||
|
||
.home-footer {
|
||
display: flex;
|
||
gap: 10px;
|
||
align-items: center;
|
||
margin-top: var(--space-4);
|
||
font-size: 13px;
|
||
line-height: 18px;
|
||
color: var(--muted);
|
||
}
|
||
|
||
.home-footer img {
|
||
flex: none;
|
||
width: 28px;
|
||
height: 28px;
|
||
}
|
||
|
||
/* Leçons (1g) : la liste (#/lecons) et la carte « prochaine leçon » de
|
||
* l'accueil (docs/identite/charte/ecrans-etape-1.md, « 1g. Leçons »). */
|
||
.lessons {
|
||
max-width: var(--page-width);
|
||
margin: 0 auto;
|
||
padding-bottom: var(--space-6);
|
||
}
|
||
|
||
.lessons-intro {
|
||
padding-top: var(--space-2);
|
||
}
|
||
|
||
.lessons-intro h2 {
|
||
margin: 0 0 var(--space-2);
|
||
font-size: 32px;
|
||
line-height: 36px;
|
||
font-weight: 800;
|
||
letter-spacing: -0.01em;
|
||
}
|
||
|
||
.lessons-intro p {
|
||
margin: 0;
|
||
}
|
||
|
||
.lessons-rules {
|
||
display: flex;
|
||
align-items: center;
|
||
width: fit-content;
|
||
min-height: 44px;
|
||
margin-top: var(--space-2);
|
||
font-size: 15px;
|
||
line-height: 20px;
|
||
color: var(--muted);
|
||
text-decoration: none;
|
||
}
|
||
|
||
.lessons-rules span {
|
||
margin-left: var(--space-1);
|
||
font-weight: 700;
|
||
color: var(--accent);
|
||
text-decoration: underline;
|
||
}
|
||
|
||
#lessons-status:empty {
|
||
display: none;
|
||
}
|
||
|
||
.lesson-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--space-3);
|
||
margin: var(--space-2) 0 0;
|
||
padding: 0;
|
||
list-style: none;
|
||
}
|
||
|
||
.lesson-card {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--space-3);
|
||
}
|
||
|
||
.lesson-card.current {
|
||
border: 2px solid var(--accent);
|
||
}
|
||
|
||
.lesson-card-top {
|
||
display: flex;
|
||
gap: var(--space-3);
|
||
align-items: center;
|
||
}
|
||
|
||
.lesson-card-body {
|
||
display: flex;
|
||
flex: 1;
|
||
flex-direction: column;
|
||
gap: 2px;
|
||
min-width: 0;
|
||
}
|
||
|
||
.lesson-card-title {
|
||
font-size: 17px;
|
||
line-height: 25px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.lesson-card-state {
|
||
font-size: 15px;
|
||
line-height: 20px;
|
||
color: var(--muted);
|
||
}
|
||
|
||
.lesson-card-state.done {
|
||
color: var(--verdict-good);
|
||
font-weight: 700;
|
||
}
|
||
|
||
/* La pastille ronde au numéro : contour pour une leçon à commencer, brique
|
||
* pour la leçon proposée, verte une fois terminée. */
|
||
.lesson-badge {
|
||
display: inline-flex;
|
||
flex: none;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 40px;
|
||
height: 40px;
|
||
font-size: 17px;
|
||
font-weight: 800;
|
||
color: var(--text);
|
||
border: 2px solid var(--border-strong);
|
||
border-radius: var(--radius-pill);
|
||
}
|
||
|
||
.lesson-badge.current {
|
||
color: var(--on-accent);
|
||
background: var(--accent);
|
||
border-color: var(--accent);
|
||
}
|
||
|
||
.lesson-badge.done {
|
||
color: var(--on-accent);
|
||
background: var(--verdict-good);
|
||
border-color: var(--verdict-good);
|
||
}
|
||
|
||
/* La barre de progression : un segment par exercice. */
|
||
.lesson-progress {
|
||
display: grid;
|
||
grid-auto-columns: minmax(0, 1fr);
|
||
grid-auto-flow: column;
|
||
gap: var(--space-1);
|
||
margin-top: var(--space-1);
|
||
}
|
||
|
||
.lesson-progress .segment {
|
||
display: block;
|
||
height: 6px;
|
||
background: var(--surface-sunken);
|
||
border-radius: var(--radius-pill);
|
||
}
|
||
|
||
.lesson-progress .segment.done {
|
||
background: var(--accent);
|
||
}
|
||
|
||
.lesson-card-action {
|
||
align-self: stretch;
|
||
}
|
||
|
||
.home-lesson {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--space-3);
|
||
}
|
||
|
||
.home-lesson-info {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 2px;
|
||
}
|
||
|
||
.home-lesson-info .muted {
|
||
font-size: 15px;
|
||
line-height: 20px;
|
||
}
|
||
|
||
.home-lesson-actions {
|
||
display: flex;
|
||
gap: var(--space-3);
|
||
align-items: center;
|
||
}
|
||
|
||
.home-lesson-actions .button {
|
||
flex: 1 1 0;
|
||
min-width: 0;
|
||
padding: 0 12px;
|
||
}
|
||
|
||
.home-lessons-link {
|
||
display: inline-flex;
|
||
flex: 1 1 0;
|
||
align-items: center;
|
||
justify-content: center;
|
||
min-height: 44px;
|
||
font-weight: 700;
|
||
color: var(--accent);
|
||
}
|
||
|
||
/* Feuille d'installation. */
|
||
.sheet-head .install-symbol {
|
||
width: 40px;
|
||
height: 40px;
|
||
margin-right: var(--space-3);
|
||
}
|
||
|
||
#install-sheet .sheet-title {
|
||
flex: 1;
|
||
}
|
||
|
||
.install-lead {
|
||
margin: var(--space-2) 0 var(--space-4);
|
||
color: var(--muted);
|
||
}
|
||
|
||
.install-steps {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--space-3);
|
||
margin: 0 0 var(--space-4);
|
||
padding: 0;
|
||
list-style: none;
|
||
}
|
||
|
||
.install-steps li {
|
||
display: flex;
|
||
gap: var(--space-3);
|
||
align-items: flex-start;
|
||
}
|
||
|
||
.step-number {
|
||
display: flex;
|
||
flex: none;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 28px;
|
||
height: 28px;
|
||
font-weight: 800;
|
||
font-variant-numeric: tabular-nums lining-nums;
|
||
background: var(--accent-soft);
|
||
border-radius: 50%;
|
||
}
|
||
|
||
.install-done {
|
||
width: 100%;
|
||
}
|
||
|
||
/* Tutoriel. */
|
||
.tutorial-head {
|
||
display: flex;
|
||
gap: var(--space-3);
|
||
align-items: center;
|
||
min-height: 52px;
|
||
padding-top: var(--space-2);
|
||
}
|
||
|
||
.tutorial-progress {
|
||
display: grid;
|
||
flex: 1;
|
||
grid-auto-columns: minmax(0, 1fr);
|
||
grid-auto-flow: column;
|
||
gap: var(--space-1);
|
||
}
|
||
|
||
/* Un segment : 4 px de trait, dans une zone de 44 px de haut quand c'est
|
||
* un lien vers une étape déjà vue. */
|
||
.tutorial-progress .segment {
|
||
position: relative;
|
||
display: block;
|
||
height: 44px;
|
||
}
|
||
|
||
.tutorial-progress .segment::before {
|
||
content: "";
|
||
position: absolute;
|
||
top: 20px;
|
||
left: 0;
|
||
right: 0;
|
||
height: 4px;
|
||
background: var(--border);
|
||
border-radius: var(--radius-pill);
|
||
}
|
||
|
||
.tutorial-progress .segment.done::before {
|
||
background: var(--accent);
|
||
}
|
||
|
||
.tutorial-progress .segment[aria-current]::before {
|
||
top: 19px;
|
||
height: 6px;
|
||
}
|
||
|
||
.tutorial-skip {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
min-height: 44px;
|
||
font-size: 15px;
|
||
font-weight: 500;
|
||
color: var(--muted);
|
||
}
|
||
|
||
/* En portrait, l'écran tient au moins la hauteur de l'écran : « Retour »
|
||
* et « Continuer » restent en bas, sous le pouce. */
|
||
.tutorial {
|
||
display: flex;
|
||
flex-direction: column;
|
||
box-sizing: border-box;
|
||
min-height: 100vh;
|
||
min-height: 100dvh;
|
||
}
|
||
|
||
/* Le titre, et « Revoir » sur sa ligne, à droite. */
|
||
.tutorial-title-row {
|
||
display: flex;
|
||
gap: var(--space-2);
|
||
align-items: center;
|
||
margin: var(--space-1) 0 var(--space-3);
|
||
}
|
||
|
||
.tutorial-title {
|
||
flex: 1;
|
||
min-width: 0;
|
||
margin: 0;
|
||
font-size: 24px;
|
||
line-height: 30px;
|
||
}
|
||
|
||
.tutorial-board-box {
|
||
position: relative;
|
||
}
|
||
|
||
@media (max-width: 40rem) {
|
||
.tutorial-board-box {
|
||
margin-inline: calc(var(--space-2) - var(--space-4));
|
||
}
|
||
}
|
||
|
||
.tutorial-replay {
|
||
flex: none;
|
||
color: var(--accent);
|
||
}
|
||
|
||
.tutorial-text {
|
||
margin-top: var(--space-3);
|
||
}
|
||
|
||
.tutorial-text p {
|
||
margin: 0 0 10px;
|
||
}
|
||
|
||
.tutorial-task {
|
||
margin: var(--space-3) 0 0;
|
||
padding: 10px 14px;
|
||
font-weight: 700;
|
||
background: var(--accent-soft);
|
||
border-radius: var(--radius-md);
|
||
}
|
||
|
||
.tutorial-feedback {
|
||
display: flex;
|
||
gap: var(--space-2);
|
||
align-items: flex-start;
|
||
min-height: 25px;
|
||
margin: var(--space-3) 0 0;
|
||
}
|
||
|
||
.tutorial-feedback:empty {
|
||
min-height: 0;
|
||
}
|
||
|
||
.tutorial-feedback[data-verdict="right"] {
|
||
font-weight: 700;
|
||
}
|
||
|
||
.tutorial-feedback[data-verdict="right"] .icon {
|
||
color: var(--verdict-good);
|
||
}
|
||
|
||
.tutorial-feedback[data-verdict="info"] {
|
||
color: var(--muted);
|
||
}
|
||
|
||
.tutorial-cube {
|
||
display: flex;
|
||
gap: var(--space-2);
|
||
margin-top: var(--space-3);
|
||
}
|
||
|
||
.tutorial-cube button {
|
||
flex: 1 1 0;
|
||
}
|
||
|
||
.tutorial-nav {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1.4fr;
|
||
gap: var(--space-2);
|
||
margin-top: auto;
|
||
padding-top: var(--space-6);
|
||
}
|
||
|
||
.tutorial-nav .button {
|
||
min-width: 0;
|
||
}
|
||
|
||
/* Le sens du jeu : deux flèches circulaires, claire pour le joueur, sombre
|
||
* pour l'ordinateur, aux couleurs de leurs pions, chacune avec un liseré de
|
||
* la couleur opposée pour rester lisible sur le bois ; jamais en brique (la
|
||
* brique veut dire « à faire »). */
|
||
.tutorial-path path {
|
||
fill: none;
|
||
stroke-linecap: round;
|
||
stroke-linejoin: round;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.tutorial-path .direction-player.direction-line { stroke: var(--checker-player); }
|
||
.tutorial-path .direction-player.direction-edge { stroke: var(--checker-computer); }
|
||
.tutorial-path .direction-computer.direction-line { stroke: var(--checker-computer); }
|
||
.tutorial-path .direction-computer.direction-edge { stroke: var(--checker-player); }
|
||
|
||
.tutorial-path .direction-head.direction-player {
|
||
fill: var(--checker-player);
|
||
stroke: var(--checker-computer);
|
||
}
|
||
|
||
.tutorial-path .direction-head.direction-computer {
|
||
fill: var(--checker-computer);
|
||
stroke: var(--checker-player);
|
||
}
|
||
|
||
/* En paysage, comme la position partagée : le plateau à gauche sur toute
|
||
* la hauteur (avec la colonne gauche du cadre), et à droite une colonne
|
||
* avec la barre de progression, le titre, le texte, la consigne « à vous »
|
||
* et les boutons, le tout sans défilement de la page. Si le texte est trop
|
||
* long pour l'écran, lui seul défile : les boutons restent en vue. */
|
||
html.landscape .tutorial {
|
||
position: fixed;
|
||
inset: 0;
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1fr) clamp(288px, 44vw, 400px);
|
||
grid-template-rows: auto auto minmax(0, 1fr) auto auto;
|
||
max-width: none;
|
||
margin: 0;
|
||
padding: 0;
|
||
overflow: hidden;
|
||
background: var(--background);
|
||
}
|
||
|
||
html.landscape .tutorial > * {
|
||
grid-column: 2;
|
||
margin-inline: 0;
|
||
padding-inline: var(--space-4) calc(var(--space-4) + env(safe-area-inset-right));
|
||
}
|
||
|
||
html.landscape .tutorial .overline {
|
||
display: none;
|
||
}
|
||
|
||
html.landscape .tutorial-head {
|
||
grid-row: 1;
|
||
min-height: 44px;
|
||
padding-top: 0;
|
||
}
|
||
|
||
html.landscape .tutorial-title-row {
|
||
grid-row: 2;
|
||
margin: 0 0 var(--space-1);
|
||
padding-right: calc(var(--space-2) + env(safe-area-inset-right));
|
||
}
|
||
|
||
html.landscape .tutorial-title {
|
||
font-size: 20px;
|
||
line-height: 26px;
|
||
}
|
||
|
||
/* Une leçon garde en paysage sa ligne « Leçon 1 · 1 sur 4 · à vous »
|
||
* au-dessus du titre (recette 1g) : une rangée de plus dans la grille. */
|
||
html.landscape #lesson {
|
||
grid-template-rows: auto auto auto minmax(0, 1fr) auto auto;
|
||
}
|
||
|
||
html.landscape #lesson .overline {
|
||
display: block;
|
||
grid-row: 2;
|
||
}
|
||
|
||
html.landscape #lesson .tutorial-title-row {
|
||
grid-row: 3;
|
||
}
|
||
|
||
html.landscape #lesson .tutorial-body {
|
||
grid-row: 4;
|
||
}
|
||
|
||
html.landscape #lesson .tutorial-cube {
|
||
grid-row: 5;
|
||
}
|
||
|
||
html.landscape #lesson .tutorial-nav {
|
||
grid-row: 6;
|
||
}
|
||
|
||
/* La boîte du plateau s'efface : le plateau se place lui-même dans la
|
||
* grille. */
|
||
html.landscape .tutorial-board-box {
|
||
display: contents;
|
||
}
|
||
|
||
html.landscape .tutorial-board {
|
||
grid-row: 1 / -1;
|
||
grid-column: 1;
|
||
width: 100%;
|
||
height: 100%;
|
||
margin: 0;
|
||
aspect-ratio: auto;
|
||
background: var(--frame);
|
||
}
|
||
|
||
html.landscape .tutorial-body {
|
||
grid-row: 3;
|
||
min-height: 0;
|
||
overflow-y: auto;
|
||
font-size: 15px;
|
||
line-height: 20px;
|
||
}
|
||
|
||
html.landscape .tutorial-text {
|
||
margin: 0;
|
||
padding-right: 0;
|
||
}
|
||
|
||
html.landscape .tutorial-text p {
|
||
margin-bottom: var(--space-2);
|
||
}
|
||
|
||
html.landscape .tutorial-task {
|
||
margin: 0;
|
||
padding: var(--space-2) 12px;
|
||
}
|
||
|
||
html.landscape .tutorial-feedback {
|
||
min-height: 0;
|
||
margin: var(--space-2) 0 0;
|
||
}
|
||
|
||
html.landscape .tutorial-cube {
|
||
grid-row: 4;
|
||
margin-top: var(--space-2);
|
||
}
|
||
|
||
/* La réponse au double donnée et saluée, les deux boutons n'ont plus
|
||
* d'usage : en paysage, leur place revient au texte. */
|
||
html.landscape .tutorial[data-solved] .tutorial-cube {
|
||
display: none;
|
||
}
|
||
|
||
/* Écran très bas (844 × 320) : texte un cran plus petit. */
|
||
@media (max-height: 360px) {
|
||
html.landscape .tutorial-body {
|
||
font-size: 14px;
|
||
line-height: 18px;
|
||
}
|
||
|
||
html.landscape .tutorial-title {
|
||
font-size: 18px;
|
||
line-height: 24px;
|
||
}
|
||
}
|
||
|
||
html.landscape .tutorial-nav {
|
||
grid-row: 5;
|
||
margin: 0;
|
||
padding-block: var(--space-2) calc(var(--space-2) + env(safe-area-inset-bottom));
|
||
}
|
||
|
||
/* Le premier lancement, en paysage : le plateau tient dans la hauteur. */
|
||
html.landscape .welcome-board {
|
||
width: min(100%, calc(70vh * 640 / 520));
|
||
height: auto;
|
||
margin-inline: auto;
|
||
aspect-ratio: 640 / 520;
|
||
}
|
||
|
||
html.landscape .welcome {
|
||
min-height: 0;
|
||
}
|
||
|
||
/* Aide. */
|
||
.help-tutorial {
|
||
display: flex;
|
||
gap: var(--space-3);
|
||
align-items: center;
|
||
margin-top: var(--space-4);
|
||
}
|
||
|
||
.help-tutorial-text {
|
||
display: flex;
|
||
flex: 1;
|
||
flex-direction: column;
|
||
min-width: 0;
|
||
}
|
||
|
||
.help-tutorial-text .muted {
|
||
font-size: 15px;
|
||
line-height: 20px;
|
||
}
|
||
|
||
.help-intro {
|
||
margin-top: var(--space-4);
|
||
}
|
||
|
||
.see-board {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
min-height: 44px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.glossary-search {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--space-1);
|
||
margin-top: var(--space-3);
|
||
}
|
||
|
||
.search-label {
|
||
font-size: 15px;
|
||
line-height: 20px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.glossary-search input {
|
||
min-height: 48px;
|
||
padding: 0 var(--space-3);
|
||
font: inherit;
|
||
color: var(--text);
|
||
background: var(--surface);
|
||
border: 1px solid var(--border-strong);
|
||
border-radius: var(--radius-md);
|
||
user-select: text;
|
||
-webkit-user-select: text;
|
||
}
|
||
|
||
.term-card + .term-card {
|
||
border-top: 1px solid var(--border);
|
||
}
|
||
|
||
.glossary .english {
|
||
margin-left: var(--space-2);
|
||
font-size: 13px;
|
||
font-style: italic;
|
||
font-weight: 400;
|
||
color: var(--muted);
|
||
}
|
||
|
||
.glossary dd p {
|
||
margin: 0 0 var(--space-1);
|
||
}
|
||
|
||
.see-also {
|
||
font-size: 15px;
|
||
line-height: 20px;
|
||
color: var(--muted);
|
||
}
|
||
|
||
.glossary .term-card.current {
|
||
margin-inline: calc(-1 * var(--space-4));
|
||
padding-inline: var(--space-4);
|
||
background: var(--accent-soft);
|
||
}
|
||
|
||
.glossary .term-card.current dt,
|
||
.glossary .term-card.current dd {
|
||
margin-inline: 0;
|
||
padding-inline: 0;
|
||
background: none;
|
||
}
|
||
|
||
/* ------------------------------------------------------------ Match */
|
||
|
||
/* « Match en 5 points » sous la barre haute (portrait), hauteur fixe. */
|
||
.match-line {
|
||
flex: none;
|
||
height: 20px;
|
||
text-align: center;
|
||
}
|
||
|
||
/* Le score de chaque camp, dans son bandeau, juste avant son compte de
|
||
* points : une pastille carrée. */
|
||
.strip .match-score {
|
||
display: inline-flex;
|
||
flex: none;
|
||
align-items: center;
|
||
justify-content: center;
|
||
min-width: 28px;
|
||
height: 28px;
|
||
padding: 0 4px;
|
||
font-weight: 700;
|
||
font-variant-numeric: tabular-nums lining-nums;
|
||
border: 2px solid var(--border-strong);
|
||
border-radius: var(--radius-sm);
|
||
}
|
||
|
||
/* Paysage : le score dans la colonne de commandes, sous le menu. */
|
||
.match-box-frame {
|
||
fill: none;
|
||
stroke: var(--point-number);
|
||
stroke-opacity: 0.5;
|
||
stroke-width: 1.5;
|
||
}
|
||
|
||
.match-box-score {
|
||
font-weight: 700;
|
||
fill: var(--point-number);
|
||
}
|
||
|
||
.match-box-of {
|
||
fill: var(--point-number);
|
||
}
|
||
|
||
/* ------------------------------------------------- Nouvelle partie */
|
||
|
||
/* La page remplit l'écran : la barre d'action reste collée en bas, même
|
||
* quand le contenu est plus court que l'écran. */
|
||
.new-game {
|
||
display: flex;
|
||
flex: 1;
|
||
flex-direction: column;
|
||
width: 100%;
|
||
max-width: var(--page-width);
|
||
margin: 0 auto;
|
||
}
|
||
|
||
.new-game .new-game-body {
|
||
flex: 1;
|
||
}
|
||
|
||
.new-game-head {
|
||
display: flex;
|
||
gap: var(--space-2);
|
||
align-items: center;
|
||
min-height: 60px;
|
||
}
|
||
|
||
.new-game-head h2 {
|
||
margin: 0;
|
||
font-size: 22px;
|
||
line-height: 28px;
|
||
}
|
||
|
||
.new-game-body {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--space-3);
|
||
padding-bottom: var(--space-6);
|
||
}
|
||
|
||
/* Portrait : les deux colonnes l'une sous l'autre, comme une seule. */
|
||
.new-game-column {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--space-3);
|
||
min-width: 0;
|
||
}
|
||
|
||
.new-game-body .overline {
|
||
margin-top: var(--space-4);
|
||
}
|
||
|
||
/* Sélecteur à deux segments : fond creusé, segment choisi en relief. */
|
||
.segmented {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: var(--space-1);
|
||
padding: var(--space-1);
|
||
background: var(--surface-sunken);
|
||
border-radius: var(--radius-pill);
|
||
}
|
||
|
||
.segmented .segment {
|
||
color: var(--text);
|
||
background: transparent;
|
||
border-color: transparent;
|
||
}
|
||
|
||
.segmented .segment[aria-checked="true"] {
|
||
background: var(--surface);
|
||
box-shadow: var(--shadow-raised);
|
||
}
|
||
|
||
.new-game-options {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--space-2);
|
||
}
|
||
|
||
.lengths {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: var(--space-2);
|
||
align-items: center;
|
||
}
|
||
|
||
.lengths .length {
|
||
width: 44px;
|
||
min-width: 44px;
|
||
height: 44px;
|
||
min-height: 44px;
|
||
padding: 0;
|
||
color: var(--text);
|
||
background: transparent;
|
||
border-color: var(--border-strong);
|
||
border-radius: var(--radius-sm);
|
||
}
|
||
|
||
.lengths .length[aria-checked="true"] {
|
||
color: var(--on-accent);
|
||
background: var(--accent);
|
||
border-color: var(--accent);
|
||
}
|
||
|
||
.new-game-rule {
|
||
margin: 0;
|
||
font-size: 15px;
|
||
line-height: 21px;
|
||
color: var(--muted);
|
||
}
|
||
|
||
/* Six barres de hauteur croissante ; celles jusqu'au niveau choisi sont en
|
||
* brique, le niveau choisi porte l'anneau de focus. */
|
||
.level-bars {
|
||
display: flex;
|
||
gap: var(--space-2);
|
||
align-items: flex-end;
|
||
}
|
||
|
||
.level-bars .level {
|
||
display: flex;
|
||
flex: 1;
|
||
align-items: flex-end;
|
||
min-width: 44px;
|
||
height: 84px;
|
||
padding: 4px;
|
||
background: transparent;
|
||
border: 0;
|
||
border-radius: var(--radius-sm);
|
||
}
|
||
|
||
.level-bar {
|
||
display: block;
|
||
width: 100%;
|
||
background: var(--border);
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.level-1 .level-bar { height: 18px; }
|
||
.level-2 .level-bar { height: 28px; }
|
||
.level-3 .level-bar { height: 38px; }
|
||
.level-4 .level-bar { height: 50px; }
|
||
.level-5 .level-bar { height: 62px; }
|
||
.level-6 .level-bar { height: 76px; }
|
||
|
||
.level-bars .level.reached .level-bar {
|
||
background: var(--accent);
|
||
}
|
||
|
||
.level-bars .level[aria-checked="true"] {
|
||
outline: 3px solid var(--focus);
|
||
outline-offset: 0;
|
||
}
|
||
|
||
.level-name {
|
||
margin: 0;
|
||
font-size: 22px;
|
||
line-height: 28px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.level-text {
|
||
margin: 0;
|
||
color: var(--muted);
|
||
}
|
||
|
||
.new-game-body .item {
|
||
display: flex;
|
||
gap: 14px;
|
||
align-items: center;
|
||
width: 100%;
|
||
min-height: 60px;
|
||
padding: 0;
|
||
font-weight: 500;
|
||
text-align: left;
|
||
color: var(--text);
|
||
background: transparent;
|
||
border: 0;
|
||
border-radius: 0;
|
||
}
|
||
|
||
.new-game-body .item-label {
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.new-game-body .item small {
|
||
font-size: 15px;
|
||
line-height: 20px;
|
||
font-weight: 400;
|
||
color: var(--muted);
|
||
}
|
||
|
||
/* Barre d'action collée en bas : le seul bouton principal de l'écran. */
|
||
.new-game-actions {
|
||
position: sticky;
|
||
bottom: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--space-1);
|
||
align-items: stretch;
|
||
padding: var(--space-3) 0 var(--space-4);
|
||
background: var(--background);
|
||
border-top: 1px solid var(--border);
|
||
}
|
||
|
||
.new-game-kept {
|
||
margin: 0;
|
||
font-size: 13px;
|
||
line-height: 18px;
|
||
text-align: center;
|
||
color: var(--muted);
|
||
}
|
||
|
||
/* En paysage (915 × 412, et jusqu'à 844 × 320), tout tient sans défiler :
|
||
* deux colonnes au-dessus de la barre d'action, le type de partie à
|
||
* gauche, le niveau et le conseil du maître à droite ; tout est resserré,
|
||
* et la barre d'action tient sur une ligne, le bouton à droite sous le
|
||
* pouce. */
|
||
html.landscape .new-game {
|
||
max-width: 60rem;
|
||
}
|
||
|
||
html.landscape .new-game-head {
|
||
min-height: 44px;
|
||
}
|
||
|
||
html.landscape .new-game-head h2 {
|
||
font-size: 20px;
|
||
line-height: 24px;
|
||
}
|
||
|
||
html.landscape .new-game-body {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
||
gap: var(--space-6);
|
||
align-content: start;
|
||
padding-bottom: var(--space-2);
|
||
}
|
||
|
||
html.landscape .new-game-column {
|
||
gap: var(--space-2);
|
||
}
|
||
|
||
html.landscape .new-game-body .overline {
|
||
margin-top: 0;
|
||
}
|
||
|
||
html.landscape .new-game-body .during-game {
|
||
display: none;
|
||
}
|
||
|
||
html.landscape .level-bars .level {
|
||
height: 48px;
|
||
padding: 3px;
|
||
}
|
||
|
||
html.landscape .level-1 .level-bar { height: 10px; }
|
||
html.landscape .level-2 .level-bar { height: 17px; }
|
||
html.landscape .level-3 .level-bar { height: 24px; }
|
||
html.landscape .level-4 .level-bar { height: 30px; }
|
||
html.landscape .level-5 .level-bar { height: 36px; }
|
||
html.landscape .level-6 .level-bar { height: 42px; }
|
||
|
||
html.landscape .level-name {
|
||
font-size: 18px;
|
||
line-height: 22px;
|
||
}
|
||
|
||
html.landscape .level-text {
|
||
font-size: 15px;
|
||
line-height: 20px;
|
||
}
|
||
|
||
html.landscape .new-game-body .item {
|
||
min-height: 44px;
|
||
}
|
||
|
||
html.landscape .new-game-body .item-label {
|
||
line-height: 22px;
|
||
}
|
||
|
||
html.landscape .new-game-body .item small {
|
||
line-height: 18px;
|
||
}
|
||
|
||
html.landscape .new-game-actions {
|
||
flex-direction: row;
|
||
gap: var(--space-4);
|
||
align-items: center;
|
||
justify-content: flex-end;
|
||
padding: var(--space-2) 0;
|
||
}
|
||
|
||
html.landscape .new-game-kept {
|
||
order: -1;
|
||
text-align: right;
|
||
}
|
||
|
||
/* Un peu plus d'air quand la hauteur le permet (915 × 412). */
|
||
@media (min-height: 380px) {
|
||
html.landscape .new-game-column {
|
||
gap: var(--space-3);
|
||
}
|
||
|
||
html.landscape .level-bars .level {
|
||
height: 64px;
|
||
}
|
||
|
||
html.landscape .level-1 .level-bar { height: 14px; }
|
||
html.landscape .level-2 .level-bar { height: 22px; }
|
||
html.landscape .level-3 .level-bar { height: 30px; }
|
||
html.landscape .level-4 .level-bar { height: 39px; }
|
||
html.landscape .level-5 .level-bar { height: 48px; }
|
||
html.landscape .level-6 .level-bar { height: 58px; }
|
||
}
|
||
|
||
/* En paysage, comme l'écran de jeu : le plateau à gauche sur toute la
|
||
* hauteur (colonne gauche du cadre avec le videau seul), le titre, le contexte et les actions
|
||
* dans une colonne à droite. */
|
||
html.landscape .position-view.with-board {
|
||
position: fixed;
|
||
inset: 0;
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1fr) 288px;
|
||
grid-template-rows: auto auto auto auto 1fr;
|
||
max-width: none;
|
||
margin: 0;
|
||
padding: 0;
|
||
overflow-y: auto;
|
||
background: var(--background);
|
||
}
|
||
|
||
html.landscape .position-view.with-board > * {
|
||
grid-column: 2;
|
||
margin-inline: 0;
|
||
padding-inline: var(--space-4) calc(var(--space-4) + env(safe-area-inset-right));
|
||
}
|
||
|
||
html.landscape .position-view.with-board .position-title {
|
||
margin-top: var(--space-4);
|
||
}
|
||
|
||
html.landscape .position-view.with-board .position-board {
|
||
grid-row: 1 / -1;
|
||
grid-column: 1;
|
||
width: 100%;
|
||
height: 100%;
|
||
margin: 0;
|
||
padding: 0;
|
||
aspect-ratio: auto;
|
||
background: var(--frame);
|
||
}
|
||
|
||
html.landscape .position-view.with-board .position-actions {
|
||
padding-bottom: var(--space-4);
|
||
}
|
||
|
||
html.landscape .position-view.with-board .position-actions > * {
|
||
padding-inline: 16px;
|
||
}
|
||
|
||
/* ------------------------------------------- Conseil du maître (1d) */
|
||
|
||
/* La ligne du maître : à la place du dernier coup, dans la ligne réservée
|
||
* de 44 px (elle ne pousse rien). Pictogramme et mot en couleur
|
||
* d'appréciation, phrase en italique tronquée, chevron. */
|
||
.advice-line {
|
||
display: flex;
|
||
flex: 1;
|
||
gap: var(--space-2);
|
||
align-items: center;
|
||
min-width: 0;
|
||
height: 44px;
|
||
font-size: 15px;
|
||
line-height: 20px;
|
||
color: var(--text);
|
||
text-decoration: none;
|
||
border-radius: 12px;
|
||
-webkit-tap-highlight-color: transparent;
|
||
}
|
||
|
||
.advice-line.appear {
|
||
animation: fade-in var(--duration-fast) var(--easing-standard);
|
||
}
|
||
|
||
.advice-line .icon {
|
||
width: 20px;
|
||
height: 20px;
|
||
}
|
||
|
||
.advice-line .icon-chevron {
|
||
width: 16px;
|
||
height: 16px;
|
||
color: var(--muted);
|
||
}
|
||
|
||
.advice-text {
|
||
flex: 1;
|
||
min-width: 0;
|
||
overflow: hidden;
|
||
white-space: nowrap;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.advice-word {
|
||
font-weight: 700;
|
||
}
|
||
|
||
[data-verdict="good"] .icon:not(.icon-chevron),
|
||
[data-verdict="good"] .advice-word { color: var(--verdict-good); }
|
||
[data-verdict="doubtful"] .icon:not(.icon-chevron),
|
||
[data-verdict="doubtful"] .advice-word { color: var(--verdict-doubtful); }
|
||
[data-verdict="bad"] .icon:not(.icon-chevron),
|
||
[data-verdict="bad"] .advice-word,
|
||
[data-verdict="veryBad"] .icon:not(.icon-chevron),
|
||
[data-verdict="veryBad"] .advice-word { color: var(--verdict-bad); }
|
||
|
||
/* Paysage : la pastille du mot, au début de la bande centrale. */
|
||
.advice-chip-pill {
|
||
fill: var(--surface);
|
||
stroke: currentColor;
|
||
stroke-width: 2;
|
||
}
|
||
|
||
.advice-chip-icon {
|
||
fill: none;
|
||
stroke: currentColor;
|
||
stroke-width: 2px;
|
||
stroke-linecap: round;
|
||
stroke-linejoin: round;
|
||
vector-effect: non-scaling-stroke;
|
||
}
|
||
|
||
.advice-chip-text {
|
||
fill: currentColor;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.advice-chip.verdict-good { color: var(--verdict-good); }
|
||
.advice-chip.verdict-doubtful { color: var(--verdict-doubtful); }
|
||
.advice-chip.verdict-bad,
|
||
.advice-chip.verdict-veryBad { color: var(--verdict-bad); }
|
||
|
||
/* La feuille d'explication : elle monte du bas, au-dessus du plateau
|
||
* voilé. */
|
||
.explain-sheet {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--space-3);
|
||
}
|
||
|
||
.explain-verdict {
|
||
display: inline-flex;
|
||
gap: 6px;
|
||
align-items: center;
|
||
margin: 0;
|
||
font-size: 15px;
|
||
line-height: 20px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.explain-verdict .icon {
|
||
width: 18px;
|
||
height: 18px;
|
||
}
|
||
|
||
.explain-verdict[data-verdict="good"] { color: var(--verdict-good); }
|
||
.explain-verdict[data-verdict="doubtful"] { color: var(--verdict-doubtful); }
|
||
.explain-verdict[data-verdict="bad"],
|
||
.explain-verdict[data-verdict="veryBad"] { color: var(--verdict-bad); }
|
||
|
||
.explain-title {
|
||
margin: 0;
|
||
font-size: 24px;
|
||
line-height: 30px;
|
||
}
|
||
|
||
.explain-phrase {
|
||
margin: 0;
|
||
font-style: italic;
|
||
}
|
||
|
||
.explain-body {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--space-2);
|
||
}
|
||
|
||
.explain-body .segment {
|
||
min-height: 44px;
|
||
font-size: 15px;
|
||
}
|
||
|
||
/* Le coup montré : le vôtre en couleur du texte, celui du maître en
|
||
* couleur du bon coup (charte 1d). */
|
||
.explain-board[data-move="mine"] { --last-move: var(--text); }
|
||
.explain-board[data-move="best"] { --last-move: var(--verdict-good); }
|
||
|
||
.explain-legend {
|
||
margin: 0;
|
||
font-size: 13px;
|
||
line-height: 18px;
|
||
color: var(--muted);
|
||
}
|
||
|
||
.explain-numbers {
|
||
border-top: 1px solid var(--border);
|
||
}
|
||
|
||
.explain-numbers summary {
|
||
display: flex;
|
||
align-items: center;
|
||
min-height: 44px;
|
||
font-size: 15px;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.explain-table {
|
||
display: grid;
|
||
grid-template-columns: auto 1fr auto;
|
||
gap: 4px 12px;
|
||
font-size: 15px;
|
||
line-height: 20px;
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
|
||
.explain-table .strong {
|
||
font-weight: 700;
|
||
}
|
||
|
||
.explain-note {
|
||
margin: var(--space-2) 0 0;
|
||
font-size: 13px;
|
||
line-height: 18px;
|
||
color: var(--muted);
|
||
}
|
||
|
||
.explain-glossary {
|
||
min-height: 44px;
|
||
}
|
||
|
||
.explain-actions {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
}
|
||
|
||
.explain-actions button {
|
||
min-width: 140px;
|
||
}
|
||
|
||
/* En paysage : la feuille prend la hauteur de l'écran ; le plateau à
|
||
* gauche, le texte à droite. */
|
||
/* Le plateau tient dans la hauteur, sous le sélecteur et sa légende. */
|
||
html.landscape .explain-board {
|
||
width: auto;
|
||
max-width: 100%;
|
||
height: calc(100vh - 140px);
|
||
height: calc(100dvh - 140px);
|
||
aspect-ratio: 640 / 520;
|
||
}
|
||
|
||
html.landscape .explain-sheet {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
||
grid-auto-flow: dense;
|
||
column-gap: var(--space-4);
|
||
align-content: start;
|
||
width: min(100%, 60rem);
|
||
height: 100%;
|
||
border-radius: 0;
|
||
}
|
||
|
||
html.landscape .explain-sheet > * {
|
||
grid-column: 2;
|
||
}
|
||
|
||
html.landscape .explain-sheet > .explain-body {
|
||
grid-column: 1;
|
||
grid-row: 1 / span 8;
|
||
}
|
||
|
||
/* ------------------------------------------ Bilan de fin de partie (1e) */
|
||
|
||
/* Maquette « Bilan de fin de partie » (charte, ecrans-etape-1.md) : un
|
||
* panneau centré, à la place du panneau de fin de partie ; il défile si
|
||
* l'écran est trop bas. */
|
||
.summary-panel {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--space-3);
|
||
width: min(26rem, 100%);
|
||
max-height: 100%;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.summary-panel p {
|
||
margin: 0;
|
||
font-size: 17px;
|
||
line-height: 25px;
|
||
font-weight: 400;
|
||
}
|
||
|
||
.summary-head {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
min-height: 44px;
|
||
margin: calc(-1 * var(--space-2)) 0;
|
||
}
|
||
|
||
.summary-title {
|
||
margin: 0;
|
||
font-size: 28px;
|
||
line-height: 34px;
|
||
}
|
||
|
||
.summary-panel .summary-status {
|
||
font-size: 15px;
|
||
line-height: 20px;
|
||
color: var(--muted);
|
||
}
|
||
|
||
/* Trois cases : bons coups, imprécisions, erreurs. */
|
||
.summary-counts {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||
gap: var(--space-2);
|
||
}
|
||
|
||
.summary-count {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
padding: var(--space-2) var(--space-1);
|
||
background: var(--surface-sunken);
|
||
border-radius: var(--radius-sm);
|
||
}
|
||
|
||
.summary-number {
|
||
font-size: 28px;
|
||
line-height: 34px;
|
||
font-weight: 800;
|
||
font-variant-numeric: tabular-nums lining-nums;
|
||
}
|
||
|
||
.summary-word {
|
||
display: inline-flex;
|
||
gap: 4px;
|
||
align-items: center;
|
||
font-size: 13px;
|
||
line-height: 18px;
|
||
font-weight: 700;
|
||
text-align: center;
|
||
}
|
||
|
||
.summary-word .icon {
|
||
width: 16px;
|
||
height: 16px;
|
||
}
|
||
|
||
[data-verdict="good"] > .summary-word,
|
||
.summary-verdict[data-verdict="good"],
|
||
.row-word[data-verdict="good"],
|
||
.viewer-phrase[data-verdict="good"] strong { color: var(--verdict-good); }
|
||
[data-verdict="doubtful"] > .summary-word,
|
||
.summary-verdict[data-verdict="doubtful"],
|
||
.row-word[data-verdict="doubtful"],
|
||
.viewer-phrase[data-verdict="doubtful"] strong { color: var(--verdict-doubtful); }
|
||
[data-verdict="bad"] > .summary-word,
|
||
.summary-verdict[data-verdict="bad"],
|
||
.summary-verdict[data-verdict="veryBad"],
|
||
.row-word[data-verdict="bad"],
|
||
.row-word[data-verdict="veryBad"],
|
||
.viewer-phrase[data-verdict="bad"] strong,
|
||
.viewer-phrase[data-verdict="veryBad"] strong { color: var(--verdict-bad); }
|
||
|
||
/* Deux jauges sur une ligne chacune : votre jeu (niveau), les dés. */
|
||
.summary-gauges {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--space-1);
|
||
}
|
||
|
||
.gauge {
|
||
display: grid;
|
||
grid-template-columns: 5.5rem minmax(3rem, 1fr) auto;
|
||
gap: var(--space-2);
|
||
align-items: center;
|
||
min-height: 28px;
|
||
font-size: 15px;
|
||
line-height: 20px;
|
||
}
|
||
|
||
.gauge-name {
|
||
font-weight: 700;
|
||
}
|
||
|
||
.gauge-value {
|
||
color: var(--muted);
|
||
text-align: right;
|
||
}
|
||
|
||
.gauge-track {
|
||
position: relative;
|
||
height: 8px;
|
||
overflow: hidden;
|
||
background: var(--surface-sunken);
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.gauge-fill {
|
||
position: absolute;
|
||
top: 0;
|
||
bottom: 0;
|
||
left: 0;
|
||
background: var(--verdict-good);
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.gauge-fill.level-1 { width: 16.7%; }
|
||
.gauge-fill.level-2 { width: 33.3%; }
|
||
.gauge-fill.level-3 { width: 50%; }
|
||
.gauge-fill.level-4 { width: 66.7%; }
|
||
.gauge-fill.level-5 { width: 83.3%; }
|
||
.gauge-fill.level-6 { width: 100%; }
|
||
|
||
/* La chance : jauge centrée, à droite si elle vous a aidé. */
|
||
.gauge-track.centred::after {
|
||
content: "";
|
||
position: absolute;
|
||
top: 0;
|
||
bottom: 0;
|
||
left: calc(50% - 1px);
|
||
width: 2px;
|
||
background: var(--muted);
|
||
}
|
||
|
||
.gauge-fill.dice { background: var(--border-strong); border-radius: 0; }
|
||
.gauge-fill.dice.for-1 { left: 50%; width: 25%; }
|
||
.gauge-fill.dice.for-2 { left: 50%; width: 50%; }
|
||
.gauge-fill.dice.against-1 { left: 25%; width: 25%; }
|
||
.gauge-fill.dice.against-2 { left: 0; width: 50%; }
|
||
.gauge-fill.dice.even { left: calc(50% - 6px); width: 12px; }
|
||
|
||
.summary-glossary {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
align-self: flex-start;
|
||
font-size: 15px;
|
||
}
|
||
|
||
/* Le coup à revoir : mini-plateau, mot, votre coup, celui du maître. */
|
||
.summary-review {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--space-2);
|
||
padding-top: var(--space-3);
|
||
border-top: 1px solid var(--border);
|
||
}
|
||
|
||
.summary-review-body {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 9rem) minmax(0, 1fr);
|
||
gap: var(--space-3);
|
||
align-items: start;
|
||
}
|
||
|
||
.summary-panel .summary-verdict {
|
||
display: inline-flex;
|
||
gap: 6px;
|
||
align-items: center;
|
||
font-size: 15px;
|
||
line-height: 20px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.summary-verdict .icon {
|
||
width: 18px;
|
||
height: 18px;
|
||
}
|
||
|
||
.summary-panel .summary-played,
|
||
.summary-panel .summary-master {
|
||
font-size: 15px;
|
||
line-height: 20px;
|
||
}
|
||
|
||
.summary-panel .summary-master {
|
||
font-style: italic;
|
||
}
|
||
|
||
.summary-review-actions,
|
||
.viewer-actions {
|
||
display: flex;
|
||
gap: var(--space-2);
|
||
align-items: center;
|
||
}
|
||
|
||
/* L'emplacement de « Demander à une IA » (étape 1f) : réservé, vide. */
|
||
.ask-ai-slot {
|
||
flex: 1 1 0;
|
||
min-height: 44px;
|
||
}
|
||
|
||
/* Deux boutons de 48 px, côte à côte, jamais étirés en hauteur. */
|
||
.summary-actions {
|
||
align-items: center;
|
||
}
|
||
|
||
.summary-actions > * {
|
||
flex: 1 1 0;
|
||
height: var(--button-height);
|
||
padding: 0 12px;
|
||
}
|
||
|
||
/* En paysage : deux colonnes, le résultat et les mesures à gauche, le
|
||
* coup à revoir et les actions à droite. */
|
||
html.landscape .summary-panel {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
||
grid-auto-flow: row dense;
|
||
column-gap: var(--space-6);
|
||
align-content: start;
|
||
width: min(52rem, 100%);
|
||
}
|
||
|
||
html.landscape .summary-panel > * {
|
||
grid-column: 1;
|
||
}
|
||
|
||
html.landscape .summary-panel > .summary-review,
|
||
html.landscape .summary-panel > .summary-end {
|
||
grid-column: 2;
|
||
}
|
||
|
||
html.landscape .summary-panel > .summary-review {
|
||
grid-row: 1 / span 4;
|
||
padding-top: 0;
|
||
border-top: 0;
|
||
}
|
||
|
||
/* Les actions en bas de la colonne de droite, « Changer les réglages »
|
||
* dessous, comme en portrait. */
|
||
html.landscape .summary-panel > .summary-end {
|
||
grid-row: 5 / span 2;
|
||
align-self: end;
|
||
}
|
||
|
||
/* ------------------------------------------- Analyse d'une partie (1e) */
|
||
|
||
/* Maquette interactive « Analyse » : une page qui défile. */
|
||
.analysis {
|
||
max-width: var(--page-width);
|
||
margin: 0 auto;
|
||
padding-bottom: var(--space-6);
|
||
}
|
||
|
||
.analysis-head {
|
||
display: flex;
|
||
gap: var(--space-3);
|
||
align-items: center;
|
||
margin: var(--space-3) 0;
|
||
}
|
||
|
||
.analysis-title {
|
||
margin: 0;
|
||
font-size: 24px;
|
||
line-height: 30px;
|
||
}
|
||
|
||
.analysis-message:empty {
|
||
display: none;
|
||
}
|
||
|
||
.analysis-card {
|
||
margin: 0 0 var(--space-4);
|
||
padding: var(--space-3);
|
||
background: var(--surface);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius-md);
|
||
}
|
||
|
||
.analysis-card > .overline {
|
||
margin-bottom: var(--space-2);
|
||
}
|
||
|
||
/* La courbe de vos chances de gagner : on la parcourt du doigt. */
|
||
.analysis-curve {
|
||
display: block;
|
||
width: 100%;
|
||
height: 168px;
|
||
touch-action: pan-y;
|
||
user-select: none;
|
||
-webkit-user-select: none;
|
||
-webkit-tap-highlight-color: transparent;
|
||
font-family: var(--font-sans);
|
||
}
|
||
|
||
.analysis-curve:focus-visible {
|
||
outline: 2px solid var(--focus);
|
||
outline-offset: 2px;
|
||
}
|
||
|
||
.curve-axis { stroke: var(--border); stroke-width: 1; }
|
||
.curve-half { stroke: var(--border-strong); stroke-width: 1; stroke-dasharray: 4 4; }
|
||
.curve-label { fill: var(--muted); font-size: 12px; }
|
||
.curve-area { fill: var(--accent-soft); }
|
||
.curve-line { fill: none; stroke: var(--text); stroke-width: 2; stroke-linejoin: round; }
|
||
.curve-dot.other { fill: var(--text); }
|
||
.curve-dot.verdict-good { fill: var(--verdict-good); }
|
||
.curve-dot.verdict-doubtful { fill: var(--verdict-doubtful); }
|
||
.curve-dot.verdict-bad,
|
||
.curve-dot.verdict-veryBad { fill: var(--verdict-bad); }
|
||
.curve-cursor { stroke: var(--accent); stroke-width: 2; }
|
||
.curve-ring { fill: none; stroke: var(--accent); stroke-width: 2; }
|
||
.curve-band { fill: transparent; cursor: pointer; }
|
||
.curve-band.selected { fill: var(--accent); fill-opacity: 0.08; }
|
||
|
||
/* La progression (#/progression, 1h) : le titre, la phrase du maître, la
|
||
* courbe du taux d'erreur, puis les parties (charte, ecrans-etape-1.md,
|
||
* « 1h »). Les cartes reprennent celles de l'analyse. */
|
||
.progression-title {
|
||
margin: var(--space-3) 0 var(--space-2);
|
||
font-size: 32px;
|
||
line-height: 36px;
|
||
font-weight: 800;
|
||
letter-spacing: -0.01em;
|
||
}
|
||
|
||
.progression-summary {
|
||
margin: 0 0 var(--space-4);
|
||
font-size: 17px;
|
||
line-height: 24px;
|
||
}
|
||
|
||
.progression-summary:empty {
|
||
display: none;
|
||
}
|
||
|
||
.progression-curve {
|
||
display: block;
|
||
width: 100%;
|
||
height: 168px;
|
||
font-family: var(--font-sans);
|
||
}
|
||
|
||
/* Le dernier point, plus gros, à l'encre du texte ; en verdict-good
|
||
* seulement si le taux baisse (le vert dit « mieux », jamais « dernier »). */
|
||
.progression-dot { fill: var(--text); }
|
||
.progression-dot.better { fill: var(--verdict-good); }
|
||
.progression-value { fill: var(--muted); font-size: 13px; }
|
||
.progression-value.last { fill: var(--text); font-weight: 700; }
|
||
.progression-value.better { fill: var(--verdict-good); }
|
||
|
||
.progression .link-button {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.progression-actions {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
margin: 0 0 var(--space-4);
|
||
}
|
||
|
||
/* Sans partie terminée : « Nouvelle partie », pleine largeur en portrait. */
|
||
@media (orientation: portrait) {
|
||
.progression-empty .button {
|
||
flex: 1;
|
||
}
|
||
}
|
||
|
||
.progression-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--space-2);
|
||
margin: var(--space-2) 0 0;
|
||
padding: 0;
|
||
list-style: none;
|
||
}
|
||
|
||
.progression-item {
|
||
background: var(--surface);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius-md);
|
||
}
|
||
|
||
/* Une ligne, un seul lien vers le bilan : résultat et date à gauche, taux
|
||
* en gras, puis le chevron. */
|
||
.progression-game {
|
||
display: flex;
|
||
gap: var(--space-3);
|
||
align-items: center;
|
||
min-height: 56px;
|
||
padding: var(--space-2) var(--space-3);
|
||
color: inherit;
|
||
text-decoration: none;
|
||
}
|
||
|
||
.progression-game > .icon {
|
||
flex: none;
|
||
width: 20px;
|
||
height: 20px;
|
||
color: var(--muted);
|
||
}
|
||
|
||
.progression-text {
|
||
display: flex;
|
||
flex: 1;
|
||
flex-direction: column;
|
||
min-width: 0;
|
||
}
|
||
|
||
.progression-rate {
|
||
display: flex;
|
||
flex: none;
|
||
flex-direction: column;
|
||
align-items: flex-end;
|
||
text-align: right;
|
||
}
|
||
|
||
.progression-rate strong {
|
||
font-size: 22px;
|
||
line-height: 26px;
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
|
||
.progression-rate.pending {
|
||
font-size: 13px;
|
||
color: var(--muted);
|
||
}
|
||
|
||
/* Le visualiseur : « ‹ Coup 7 sur 24 · 6-1 › », le plateau d'avant le
|
||
* coup, la phrase du maître, votre coup contre celui du maître. */
|
||
.viewer-nav {
|
||
display: flex;
|
||
gap: var(--space-2);
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
#analysis-prev .icon {
|
||
transform: rotate(180deg);
|
||
}
|
||
|
||
.viewer-step[aria-disabled="true"] {
|
||
opacity: 0.35;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.viewer-turn {
|
||
margin: 0;
|
||
font-weight: 700;
|
||
text-align: center;
|
||
font-variant-numeric: tabular-nums lining-nums;
|
||
}
|
||
|
||
.viewer-body,
|
||
.viewer-text {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--space-2);
|
||
}
|
||
|
||
.viewer-phrase {
|
||
margin: 0;
|
||
}
|
||
|
||
.viewer-phrase strong {
|
||
display: inline-flex;
|
||
gap: 4px;
|
||
align-items: center;
|
||
}
|
||
|
||
.viewer-phrase strong .icon {
|
||
width: 18px;
|
||
height: 18px;
|
||
}
|
||
|
||
.viewer-legend {
|
||
margin: 0;
|
||
font-size: 13px;
|
||
line-height: 18px;
|
||
color: var(--muted);
|
||
}
|
||
|
||
.viewer-chance {
|
||
margin: 0;
|
||
font-size: 15px;
|
||
line-height: 20px;
|
||
}
|
||
|
||
.viewer-chance:empty {
|
||
display: none;
|
||
}
|
||
|
||
.viewer-text .segment {
|
||
min-height: 44px;
|
||
font-size: 15px;
|
||
}
|
||
|
||
.analysis-board[data-move="mine"] { --last-move: var(--text); }
|
||
.analysis-board[data-move="best"] { --last-move: var(--verdict-good); }
|
||
|
||
/* Les coups à revoir : filtres en pastilles, une ligne par coup. */
|
||
.filters {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: var(--space-2);
|
||
margin-bottom: var(--space-2);
|
||
}
|
||
|
||
.filters .filter {
|
||
min-height: 44px;
|
||
padding: 0 14px;
|
||
font-size: 15px;
|
||
font-weight: 500;
|
||
color: var(--text);
|
||
background: var(--surface-sunken);
|
||
border: 1px solid var(--border);
|
||
}
|
||
|
||
/* Le filtre choisi en accent-soft, comme l'onglet choisi de l'aide. */
|
||
.filters .filter[aria-pressed="true"] {
|
||
font-weight: 700;
|
||
color: var(--text);
|
||
background: var(--accent-soft);
|
||
border-color: var(--accent);
|
||
}
|
||
|
||
.analysis-list {
|
||
margin: 0;
|
||
padding: 0;
|
||
list-style: none;
|
||
}
|
||
|
||
.analysis-row {
|
||
display: grid;
|
||
grid-template-columns: 2rem 2.5rem minmax(0, 1fr) auto;
|
||
gap: var(--space-2);
|
||
align-items: center;
|
||
min-height: 44px;
|
||
padding: 0 var(--space-1);
|
||
color: var(--text);
|
||
text-decoration: none;
|
||
border-bottom: 1px solid var(--border);
|
||
}
|
||
|
||
.analysis-row[aria-current="true"] {
|
||
background: var(--accent-soft);
|
||
}
|
||
|
||
.row-number,
|
||
.row-roll {
|
||
color: var(--muted);
|
||
font-variant-numeric: tabular-nums lining-nums;
|
||
}
|
||
|
||
.row-move {
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.row-word {
|
||
display: inline-flex;
|
||
gap: 4px;
|
||
align-items: center;
|
||
font-size: 15px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.row-word .icon {
|
||
width: 16px;
|
||
height: 16px;
|
||
}
|
||
|
||
.analysis-empty {
|
||
padding: var(--space-2) 0;
|
||
color: var(--muted);
|
||
}
|
||
|
||
.analysis-table {
|
||
grid-template-columns: minmax(0, 1fr) auto auto;
|
||
}
|
||
|
||
/* En paysage : le plateau du visualiseur à gauche, tenu dans la hauteur
|
||
* de l'écran ; le texte à droite. */
|
||
html.landscape .viewer-body {
|
||
display: grid;
|
||
grid-template-columns: auto minmax(0, 1fr);
|
||
gap: var(--space-4);
|
||
align-items: start;
|
||
}
|
||
|
||
html.landscape .analysis-board {
|
||
width: auto;
|
||
max-width: 100%;
|
||
height: calc(100vh - 120px);
|
||
height: calc(100dvh - 120px);
|
||
aspect-ratio: 640 / 520;
|
||
}
|
||
|
||
/* Le mini-plateau du coup à revoir : trop petit pour les numéros des
|
||
* flèches, qui se chevaucheraient. */
|
||
.summary-board .point-number {
|
||
display: none;
|
||
}
|
||
|
||
/* ------------------------------------------- Demander à une IA (1f) */
|
||
|
||
/* Le bouton : secondaire partout, avec l'icône de copie (charte, 1f). */
|
||
a.button.ask-ai .icon,
|
||
#prompt-copy .icon {
|
||
flex: none;
|
||
width: 20px;
|
||
height: 20px;
|
||
}
|
||
|
||
.ask-ai-slot .ask-ai {
|
||
width: 100%;
|
||
}
|
||
|
||
.explain-actions {
|
||
gap: var(--space-2);
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.term-card .ask-ai {
|
||
margin-top: var(--space-2);
|
||
}
|
||
|
||
/* Sa propre feuille, au-dessus de l'analyse et du glossaire. */
|
||
.prompt-veil {
|
||
z-index: 12;
|
||
}
|
||
|
||
.prompt-page {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--space-2);
|
||
}
|
||
|
||
/* Depuis la feuille du maître ou le bilan, la page du prompt prend la place
|
||
* de leur contenu, à la même hauteur : la feuille garde sa taille, son
|
||
* contenu reste en place mais invisible, et la page la couvre ; le texte du
|
||
* prompt défile dans la hauteur qui reste. Une seule feuille, une seule
|
||
* poignée, une seule croix. */
|
||
.sheet.prompting,
|
||
.panel.prompting {
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.prompting > :not(.prompt-page) {
|
||
visibility: hidden;
|
||
}
|
||
|
||
/* (plus précis que « html.landscape .explain-sheet > * », qui la placerait
|
||
* dans une colonne) */
|
||
.sheet.prompting > .prompt-page,
|
||
.panel.prompting > .prompt-page {
|
||
position: absolute;
|
||
inset: 0;
|
||
grid-area: auto;
|
||
padding: inherit;
|
||
}
|
||
|
||
.prompting .prompt-text {
|
||
flex: 1 1 auto;
|
||
max-height: none;
|
||
}
|
||
|
||
/* Le bilan est un panneau : pas de poignée. */
|
||
.panel .prompt-page .grip {
|
||
display: none;
|
||
}
|
||
|
||
/* « ‹ Explication » : revenir à l'écran d'où l'on vient. */
|
||
a.prompt-back {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
min-height: 44px;
|
||
padding-right: var(--space-2);
|
||
font-weight: 500;
|
||
color: var(--accent);
|
||
text-decoration: none;
|
||
touch-action: manipulation;
|
||
-webkit-tap-highlight-color: transparent;
|
||
}
|
||
|
||
.prompt-lead {
|
||
margin: 0;
|
||
color: var(--muted);
|
||
}
|
||
|
||
/* Le texte du prompt, à relire avant de le copier : une zone en creux qui
|
||
* défile, en chasse fixe pour que le diagramme garde ses colonnes. */
|
||
.prompt-text {
|
||
min-height: 0;
|
||
max-height: 50vh;
|
||
max-height: 50dvh;
|
||
margin: 0;
|
||
padding: var(--space-3);
|
||
overflow: auto;
|
||
font-family: ui-monospace, "DejaVu Sans Mono", "Roboto Mono", monospace;
|
||
font-size: 13px;
|
||
line-height: 18px;
|
||
white-space: pre-wrap;
|
||
overflow-wrap: anywhere;
|
||
color: var(--text);
|
||
background: var(--surface-sunken);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius-md);
|
||
user-select: text;
|
||
}
|
||
|
||
.prompt-status {
|
||
margin: 0;
|
||
color: var(--muted);
|
||
}
|
||
|
||
.prompt-status:empty {
|
||
display: none;
|
||
}
|
||
|
||
.prompt-actions {
|
||
display: flex;
|
||
flex: none;
|
||
gap: var(--space-2);
|
||
justify-content: flex-end;
|
||
}
|
||
|
||
.prompt-actions button {
|
||
display: inline-flex;
|
||
gap: 6px;
|
||
align-items: center;
|
||
justify-content: center;
|
||
min-width: 120px;
|
||
}
|
||
|
||
/* « ✓ Copié », 2 s : la copie se confirme sur le bouton (recette de 1f). */
|
||
#prompt-copy.copied {
|
||
color: var(--verdict-good);
|
||
background: var(--surface);
|
||
border-color: var(--verdict-good);
|
||
}
|
||
|
||
html.landscape .prompt-text {
|
||
max-height: calc(100vh - 190px);
|
||
max-height: calc(100dvh - 190px);
|
||
}
|
||
|
||
html.landscape .prompting .prompt-text {
|
||
max-height: none;
|
||
}
|
||
|
||
/* Le bouton ne se coupe pas : trop étroit à côté de « Revoir ce coup » ou
|
||
* « Rejouer d'ici », il passe à la ligne. */
|
||
.summary-review-actions,
|
||
.viewer-actions {
|
||
flex-wrap: wrap;
|
||
}
|