/* 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 */ :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: #f7f0e2; --checker-player-edge: #8c7a62; --checker-computer: #2e1c12; --checker-computer-edge: #120a05; --count-player: #2b1d15; --count-computer: #f3ead8; --die-player: #f7f0e2; --pip-player: #2b1d15; --die-computer: #2e1c12; --pip-computer: #f3ead8; --cube: #f7f0e2; --cube-text: #2b1d15; --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); /* Numéros des flèches. La charte les pose sur le cadre (point-number, * ivoire) ; notre plateau les pose sur le fond, où l'ivoire ne se lirait * pas : texte secondaire en thème clair (4,7:1 sur bed), point-number en * thème sombre (6,3:1). */ --point-label: var(--muted); --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; /* Hauteur de la barre haute : boutons de 44 px et marges. */ --topbar-height: 60px; } @media (prefers-color-scheme: dark) { :root { --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); } } /* -------------------------------------------------------------- Page */ * { box-sizing: border-box; } html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; } body { margin: 0 auto; max-width: var(--page-width); padding: 0 var(--space-4) var(--space-6); font-family: var(--font-sans); font-size: 17px; line-height: 25px; color: var(--text); background: var(--background); } [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; } /* -------------------------------------------------------- Barre haute */ .topbar { display: flex; gap: var(--space-2); align-items: center; min-height: var(--topbar-height); padding-block: var(--space-2); } .topbar .brand { flex: 1; display: flex; align-items: center; min-width: 0; margin: 0; } .topbar .brand img { display: block; width: auto; height: 32px; } /* ------------------------------------------------------------ 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; /* Pas de délai ni de zoom sur un double toucher. */ touch-action: manipulation; -webkit-tap-highlight-color: transparent; } 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. */ button:active:not(:disabled) { transform: translateY(1px); } button:disabled { opacity: 0.45; cursor: default; } .topbar button { min-height: 44px; padding: 0 14px; font-size: 15px; line-height: 20px; } .actions { display: flex; flex-wrap: wrap; gap: var(--space-2); } .actions button { flex: 1 1 auto; } /* --------------------------------------------- Messages sous le plateau */ /* Compte de points : information secondaire, discrète. */ .pips { margin: var(--space-2) 0 0; font-size: 15px; line-height: 20px; color: var(--muted); text-align: center; font-variant-numeric: tabular-nums lining-nums; } /* 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; color: var(--muted); } .info:empty { margin-top: 0; } /* 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. */ .prompt { min-height: calc(25px + 2 * var(--space-3)); margin: var(--space-3) 0; padding: var(--space-3) var(--space-4); font-weight: 700; background: var(--accent-soft); border-radius: var(--radius-md); } .prompt.thinking, 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 { content: ""; animation: thinking 1.2s steps(4, end) infinite; } @keyframes thinking { 0% { content: ""; } 25% { content: "."; } 50% { content: ".."; } 75% { content: "..."; } } @media (prefers-reduced-motion: reduce) { .prompt.thinking::after { animation: none; content: "…"; } 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; } /* 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); } .board-tray { fill: var(--tray); } .point-a { fill: var(--point-a); } .point-b { fill: var(--point-b); } .point-number { fill: var(--point-label); font-size: 13px; 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), prêt pour le jour où le plateau * le dessine. */ .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; } .checker-count { font-size: 18px; font-weight: 700; text-anchor: middle; } .count-player { fill: var(--count-player); } .count-computer { fill: var(--count-computer); } .target-zone { fill: var(--target); } .last-move { fill: var(--last-move); } .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); } .cube-face { fill: var(--cube); stroke: var(--checker-player-edge); stroke-width: 2; } .cube-value { fill: var(--cube-text); font-size: 17px; font-weight: 800; text-anchor: middle; } .hit { fill: transparent; cursor: pointer; } /* --------------------------------------------------------------- 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 dt { 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-8); font-size: 15px; line-height: 20px; color: var(--muted); } /* Une cible tactile confortable pour le lien. */ .about a { display: inline-block; padding-block: 12px; } /* ------------------------------------------------------- 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; } }