Révision UX : portrait stable, bandeaux, menu, paysage plateau = écran, vibrations
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
2be5bdcb4f
commit
c6649f94c0
+695
-136
@@ -51,6 +51,9 @@
|
||||
|
||||
/* ------------------------------------------------------------ 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;
|
||||
@@ -117,12 +120,29 @@
|
||||
--radius-md: 12px;
|
||||
--radius-pill: 999px;
|
||||
|
||||
/* Hauteur de la barre haute : boutons de 44 px et marges. */
|
||||
/* 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: 74px;
|
||||
--actions-height: 76px;
|
||||
|
||||
color-scheme: light;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
:root:not([data-theme="light"]) {
|
||||
--background: #17110d;
|
||||
--surface: #221913;
|
||||
--surface-sunken: #2c211a;
|
||||
@@ -165,29 +185,84 @@
|
||||
--point-label: var(--point-number);
|
||||
|
||||
--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: #ede3cf;
|
||||
--checker-player-edge: #8e7c64;
|
||||
--checker-computer: #140d09;
|
||||
--checker-computer-edge: #a8957d;
|
||||
--count-player: #2b1d15;
|
||||
--count-computer: #f3ead8;
|
||||
--die-player: #ede3cf;
|
||||
--pip-player: #2b1d15;
|
||||
--die-computer: #140d09;
|
||||
--pip-computer: #ede3cf;
|
||||
--cube: #ede3cf;
|
||||
--cube-text: #2b1d15;
|
||||
--highlight: #e07a5a;
|
||||
--target: rgba(224, 122, 90, 0.38);
|
||||
|
||||
--point-label: var(--point-number);
|
||||
|
||||
--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) var(--space-6);
|
||||
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] {
|
||||
@@ -205,14 +280,46 @@ a {
|
||||
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;
|
||||
}
|
||||
|
||||
.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;
|
||||
gap: var(--space-2);
|
||||
flex: none;
|
||||
gap: var(--space-1);
|
||||
align-items: center;
|
||||
min-height: var(--topbar-height);
|
||||
padding-block: var(--space-2);
|
||||
height: var(--topbar-height);
|
||||
}
|
||||
|
||||
.topbar .brand {
|
||||
@@ -224,9 +331,22 @@ a {
|
||||
}
|
||||
|
||||
.topbar .brand img {
|
||||
display: block;
|
||||
width: auto;
|
||||
height: 32px;
|
||||
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 */
|
||||
@@ -246,6 +366,8 @@ button {
|
||||
/* 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 {
|
||||
@@ -260,9 +382,11 @@ button.secondary {
|
||||
}
|
||||
}
|
||||
|
||||
/* Retour visuel au toucher. */
|
||||
/* 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 {
|
||||
@@ -270,70 +394,210 @@ button:disabled {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.topbar button {
|
||||
/* 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 14px;
|
||||
font-size: 15px;
|
||||
line-height: 20px;
|
||||
padding: 0;
|
||||
color: var(--text);
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-radius: var(--radius-md);
|
||||
}
|
||||
|
||||
.actions {
|
||||
.icon-button.labelled {
|
||||
width: 60px;
|
||||
height: 52px;
|
||||
}
|
||||
|
||||
.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-wrap: wrap;
|
||||
gap: var(--space-2);
|
||||
flex: none;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
height: var(--strip-height);
|
||||
padding: 0 4px 0 12px;
|
||||
border-radius: var(--radius-md);
|
||||
}
|
||||
|
||||
.actions button {
|
||||
flex: 1 1 auto;
|
||||
.strip.turn {
|
||||
background: var(--accent-soft);
|
||||
}
|
||||
|
||||
/* --------------------------------------------- Messages sous le plateau */
|
||||
.strip .who {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
font-weight: 700;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* Compte de points : information secondaire, discrète. */
|
||||
.pips {
|
||||
margin: var(--space-2) 0 0;
|
||||
.strip .lead {
|
||||
font-size: 15px;
|
||||
line-height: 20px;
|
||||
color: var(--muted);
|
||||
text-align: center;
|
||||
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;
|
||||
}
|
||||
|
||||
/* Ce qui vient de se passer (coup de l'ordinateur, jet d'ouverture) :
|
||||
* secondaire, mais lisible. */
|
||||
.info {
|
||||
min-height: 25px;
|
||||
margin: var(--space-3) 0 0;
|
||||
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;
|
||||
}
|
||||
|
||||
.info:empty {
|
||||
margin-top: 0;
|
||||
.infoline .replay {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
/* La consigne du moment : ce qui doit ressortir de l'écran. Fond d'accent
|
||||
* léger quand c'est au joueur, neutre pendant que l'ordinateur réfléchit. */
|
||||
/* La consigne du moment : ce qui doit ressortir de l'écran. Hauteur fixe
|
||||
* (deux lignes) ; fond d'accent léger quand c'est au joueur. */
|
||||
.prompt {
|
||||
min-height: calc(25px + 2 * var(--space-3));
|
||||
margin: var(--space-3) 0;
|
||||
flex: none;
|
||||
height: var(--prompt-height);
|
||||
margin: 0;
|
||||
padding: var(--space-3) var(--space-4);
|
||||
overflow: hidden;
|
||||
font-weight: 700;
|
||||
background: var(--accent-soft);
|
||||
border-radius: var(--radius-md);
|
||||
}
|
||||
|
||||
.prompt.thinking,
|
||||
.prompt.neutral,
|
||||
body.busy .prompt {
|
||||
font-weight: 400;
|
||||
background: var(--surface-sunken);
|
||||
}
|
||||
|
||||
/* Fin de partie : le résultat en titre. */
|
||||
#game:has(#again:not([hidden])) .prompt {
|
||||
font-size: 24px;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
/* L'ordinateur réfléchit : trois points qui apparaissent l'un après
|
||||
* l'autre (la seule animation en boucle). */
|
||||
.prompt.thinking::after {
|
||||
@@ -348,12 +612,288 @@ body.busy .prompt {
|
||||
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 {
|
||||
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-actions {
|
||||
display: flex;
|
||||
gap: var(--space-2);
|
||||
}
|
||||
|
||||
.panel-actions button {
|
||||
flex: 1 1 0;
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
/* « 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;
|
||||
}
|
||||
@@ -376,16 +916,6 @@ body.busy .prompt {
|
||||
font-variant-numeric: tabular-nums lining-nums;
|
||||
}
|
||||
|
||||
/* 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) ; chaque pixel compte pour
|
||||
* toucher un pion. */
|
||||
@media (max-width: 40rem) and (orientation: portrait) {
|
||||
.board {
|
||||
width: calc(100% + 2 * (var(--space-4) - var(--space-2)));
|
||||
margin-inline: calc(var(--space-2) - var(--space-4));
|
||||
}
|
||||
}
|
||||
|
||||
.board-frame { fill: var(--frame); }
|
||||
.board-bed { fill: var(--bed); }
|
||||
.board-bar { fill: var(--bar); }
|
||||
@@ -393,9 +923,10 @@ body.busy .prompt {
|
||||
.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). */
|
||||
.point-number {
|
||||
fill: var(--point-label);
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
text-anchor: middle;
|
||||
}
|
||||
@@ -517,37 +1048,123 @@ body.busy .prompt {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------ Confirmation (videau) */
|
||||
/* Paysage : numéros sur le cadre (ivoire), comptes de points en pastilles
|
||||
* aux bouts de la barre, consigne dans la bande, commandes à gauche. */
|
||||
.point-number.on-frame { fill: var(--point-number); }
|
||||
|
||||
/* Une carte au milieu de l'écran, comme le glossaire ; le fond de la page
|
||||
* s'assombrit derrière. */
|
||||
.confirm {
|
||||
width: min(22rem, calc(100vw - 2 * var(--space-4)));
|
||||
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);
|
||||
}
|
||||
.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); }
|
||||
|
||||
.confirm::backdrop {
|
||||
background: rgba(43, 29, 21, 0.5);
|
||||
}
|
||||
|
||||
.confirm p {
|
||||
margin: 0 0 var(--space-4);
|
||||
.pip-chip-text {
|
||||
font-weight: 700;
|
||||
text-anchor: middle;
|
||||
}
|
||||
|
||||
.confirm-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-2);
|
||||
.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;
|
||||
}
|
||||
|
||||
.confirm-actions button {
|
||||
flex: 1 1 auto;
|
||||
.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 reste une page qu'on fait défiler. */
|
||||
html.landscape.help-open,
|
||||
html.landscape.help-open body {
|
||||
height: auto;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
html.landscape.help-open body {
|
||||
padding: 0 var(--space-4);
|
||||
background: var(--background);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------- Aide */
|
||||
@@ -619,65 +1236,7 @@ body.busy .prompt {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------- Mode paysage */
|
||||
|
||||
/* Téléphone tourné : le plateau prend toute la hauteur de l'écran, à
|
||||
* gauche ; la barre haute, les messages et les boutons passent dans une
|
||||
* colonne à sa droite. */
|
||||
@media (orientation: landscape) and (max-height: 40rem) {
|
||||
body {
|
||||
max-width: none;
|
||||
padding: 0 var(--space-4);
|
||||
}
|
||||
|
||||
/* Le jeu en deux colonnes : #game laisse ses enfants dans la grille de
|
||||
* la page. Quand l'aide est affichée, #game est caché, la première
|
||||
* colonne n'a plus de largeur et l'aide prend toute la place. */
|
||||
body {
|
||||
display: grid;
|
||||
grid-template-columns: auto minmax(13rem, 1fr);
|
||||
grid-template-rows: auto auto auto auto auto 1fr;
|
||||
column-gap: var(--space-4);
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
#game {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
.topbar {
|
||||
grid-column: 2;
|
||||
grid-row: 1;
|
||||
min-height: 0;
|
||||
padding-block: var(--space-2) 0;
|
||||
}
|
||||
|
||||
.board {
|
||||
grid-column: 1;
|
||||
grid-row: 1 / -1;
|
||||
width: auto;
|
||||
height: calc(100vh - 2 * var(--space-2));
|
||||
height: calc(100dvh - 2 * var(--space-2));
|
||||
max-width: 70vw;
|
||||
margin-block: var(--space-2);
|
||||
}
|
||||
|
||||
.pips,
|
||||
.info,
|
||||
.prompt,
|
||||
.actions {
|
||||
grid-column: 2;
|
||||
}
|
||||
|
||||
.pips {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.actions {
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
.help {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
.help {
|
||||
user-select: text;
|
||||
-webkit-user-select: text;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user