/* The platform's page layer (KTD21), over the Panache Blanc design system
   (design/panache-blanc-ds/, served at /ds/): tokens.css gives every value,
   components/bundle.css every component (the pb-* classes). This sheet only
   lays the pages out: the frame, the column, the space between blocks, the
   headings, the lists, the choices of a form, a select's arrow, the device
   list, the game grid, the console's sheet and lists, the footer.

   Every colour, font, spacing, radius, size and breakpoint is a variable of
   tokens.css. The only lengths written here, which the test
   pages_the_page_layer_uses_only_the_design_system_s_values holds to a list:
   - 1px hairlines and 2px focus rings, as bundle.css writes them;
   - the heading styles of tokens.json (titre-1, titre-2), which tokens.css
     does not emit as variables: written once, below, and checked against
     tokens.json by the same test;
   - the page column, the width of bundle.css's own dialog (.pb-feuille);
   - the breakpoints of the media queries, which cannot read a custom
     property: 768px is --bp-tablette, 1200px is --bp-bureau (the test
     checks them against tokens.css).
   Mobile first: the rules without a media query are the phone's. */

:root {
  /* The design system is dark: so are the browser's own controls (the
     radio buttons and boxes, the scroll bars). */
  color-scheme: dark;
  /* tokens.json, typography, "Titres". */
  --texte-titre-1-taille: 30px;
  --texte-titre-1-interligne: 38px;
  --texte-titre-1-taille-bureau: 40px;
  --texte-titre-1-interligne-bureau: 46px;
  --texte-titre-2-taille: 22px;
  --texte-titre-2-interligne: 30px;
  --texte-titre-interlettrage: 0.01em;
  /* tokens.json, typography, "petit": helps and side notes. */
  --texte-petit-taille: 14px;
  --texte-petit-interligne: 20px;
  /* The page column from a tablet on: wide enough for a desk title on one
     line; a phone uses its whole width. */
  --page-colonne: 640px;
  /* The sizes bundle.js draws its icons at: in a badge, beside a help or a
     tag, in an alert's disc, beside a button's words, over a tab's label. */
  --icone-badge: 14px;
  --icone-aide: 16px;
  --icone-alerte: 18px;
  --icone-bouton: 22px;
  --icone-onglet: 26px;

  /* The vertical rhythm, in the spirit of the minimal frameworks' « stack »:
     every page, form and section is a column whose children stand
     --rythme apart; a group (a title and its lead, a field and its help,
     the buttons of one action) holds them --rythme-groupe apart; a section
     opens --rythme-section after the block before it. Nothing else sets a
     vertical gap. */
  --rythme: var(--space-6);
  --rythme-groupe: var(--space-3);
  --rythme-section: var(--space-12);
  /* Closer than a group: a label on its input, a help under its field. */
  --rythme-serre: var(--space-1);
}

/* ---------- The frame: the top bar, the page, the footer ---------- */

body {
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
}

/* A full-width button drawn on a link (pb-btn-bloc on an <a>) counts its
   padding inside its width, as a <button> does: bundle.css leaves the link
   at content-box, wider than its column. */
.pb-btn {
  box-sizing: border-box;
}

.logo-barre {
  display: block;
  height: var(--space-10);
  width: auto;
}

.page {
  box-sizing: border-box;
  flex: 1 0 auto;
  width: 100%;
  max-width: calc(var(--page-colonne) + 2 * var(--space-4));
  margin: 0 auto;
  padding: var(--space-8) var(--space-4) var(--space-10);
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

.page-large {
  max-width: calc(var(--contenu-max) + 2 * var(--space-4));
}

.pied {
  box-sizing: border-box;
  width: 100%;
  padding: var(--space-2) var(--space-4) calc(var(--space-4) + env(safe-area-inset-bottom));
  border-top: 1px solid var(--ligne);
  display: flex;
  justify-content: center;
  color: var(--brume);
}

/* ---------- Blocks and text ---------- */

h1,
h2 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: var(--texte-titre-interlettrage);
}

h1 {
  font-size: var(--texte-titre-1-taille);
  line-height: var(--texte-titre-1-interligne);
}

h2 {
  font-size: var(--texte-titre-2-taille);
  line-height: var(--texte-titre-2-interligne);
}

p {
  margin: 0;
}

/* A group of blocks: --space-10 from the previous one (the page's gap and
   this margin), --space-16 on a desk; --space-4 inside it. */
section {
  display: flex;
  flex-direction: column;
  gap: var(--rythme);
  margin-top: calc(var(--rythme-section) - var(--rythme));
}

form {
  display: flex;
  flex-direction: column;
  gap: var(--rythme);
  margin: 0;
}

/* A title's first paragraph is its lead: one group with it. */
h1 + p,
h2 + p {
  margin-top: calc(var(--rythme-groupe) - var(--rythme));
}

/* The buttons of one action: a form's own buttons (.actions), a link drawn
   as a button, a form of one button. Consecutive ones are one group, so a
   button never stands farther from its alternative than --rythme-groupe,
   and always --rythme from the block before the group. */
.actions {
  display: flex;
  flex-direction: column;
  gap: var(--rythme-groupe);
}

:where(.pb-btn, .actions, form:has(> .actions:last-child)) + :where(.pb-btn, .actions, form:has(> .actions:first-child)) {
  margin-top: calc(var(--rythme-groupe) - var(--rythme));
}

/* A list after the sentence that opens it is one group with it. */
p + ul {
  margin-top: calc(var(--rythme-groupe) - var(--rythme));
}

/* A button's words may take two lines on a phone: the button then grows
   rather than spill, and keeps its sides at the column's spacing. */
.pb-btn {
  padding: var(--space-3) var(--space-4);
  text-align: center;
}

/* No button is drawn on the bare night (the designer's call, 2026-11-04).
   Three fills, one per rank: the primary in gold (bundle.css); the
   secondary light, `--plume` with `--nuit` text and no outline, in the
   neutral style Google gives its sign-in button, which is one of them; the
   default dark, on `--surface`, a step lighter than the page and a step
   darker than a field, so it never reads as an input. */
.pb-btn-secondaire {
  background: var(--plume);
  color: var(--nuit);
  border-color: transparent;
}
.pb-btn-secondaire:hover:not([disabled]) {
  background: var(--plume);
  border-color: transparent;
  filter: brightness(0.92);
}
.pb-btn-defaut.pb-btn-bloc {
  background: var(--surface);
}
.pb-btn-defaut.pb-btn-bloc:hover:not([disabled]) {
  background: var(--surface-haute);
}

.logo-google {
  flex-shrink: 0;
}

/* The icons are Phosphor's (`components/Icon.md`), as glyphs of the
   platform's icon font (`ui::Icon` says why a font): each is one character in
   the text's colour, its em its square. */
@font-face {
  font-family: "pb-icones";
  src: url("/icones.woff2?v=07d376a27a9e") format("woff2");
  font-display: block;
}
.pb-icon {
  display: block;
  flex-shrink: 0;
  font-family: "pb-icones";
  font-style: normal;
  font-weight: normal;
  line-height: 1;
  text-align: center;
  speak: never;
}
.pb-icon-14 {
  font-size: var(--icone-badge);
  width: var(--icone-badge);
  height: var(--icone-badge);
}
.pb-icon-16 {
  font-size: var(--icone-aide);
  width: var(--icone-aide);
  height: var(--icone-aide);
}
.pb-icon-18 {
  font-size: var(--icone-alerte);
  width: var(--icone-alerte);
  height: var(--icone-alerte);
}
.pb-icon-22 {
  font-size: var(--icone-bouton);
  width: var(--icone-bouton);
  height: var(--icone-bouton);
}
.pb-icon-26 {
  font-size: var(--icone-onglet);
  width: var(--icone-onglet);
  height: var(--icone-onglet);
}

/* A field: its label right on its input, its error right under it. Its
   help (.aide) stays with it: right under a field or a box, or right above
   a field whose rules must be read first (the sign-up name). */
.pb-champ {
  gap: var(--rythme-serre);
}

:where(.pb-champ, .choices) + .aide,
.aide + .pb-champ {
  margin-top: calc(var(--rythme-groupe) - var(--rythme));
}

/* A help that follows a field or a group of choices is theirs, not the next
   field's: the field stands the full --rythme apart (the account page's
   language help, then its time zone). */
:where(.pb-champ, .choices) + .aide + .pb-champ {
  margin-top: 0;
}

.aide {
  font-size: var(--texte-petit-taille);
  line-height: var(--texte-petit-interligne);
  color: var(--brume);
}

/* A secondary text: a hint, a side note. */
.aside,
.lead {
  color: var(--brume);
}

.name {
  font-weight: 600;
}

/* The account page's name and address: a column of fields, as a form's,
   but no form, so that no Enter key ever sends them anywhere. */
.identite {
  display: flex;
  flex-direction: column;
  gap: var(--rythme);
}

/* A field the player reads but cannot change (the account page's name and
   address): flat on the surface, its hairline quieter, the text as written. */
.pb-champ-input[readonly] {
  background: var(--surface);
  border-color: var(--ligne);
  cursor: default;
}

/* A list to choose from (the account page's language and time zone, test
   mode's, `ui::select`): a TextField's input, whose height, hairline,
   radius, focus ring and 16px text bundle.css gives .pb-champ-input, and
   whose error its frame shows.
   The browser's own arrow gives way to one in --brume, a triangle drawn as
   two half squares of --fleche, standing --space-5 from the right edge as
   the text stands from the left; the text never runs under it. The design
   system has no Select yet: proposed. */
select.pb-champ-input {
  --fleche: calc(var(--space-3) / 2);
  appearance: none;
  width: 100%;
  min-width: 0;
  padding-right: calc(var(--space-5) + 2 * var(--fleche) + var(--space-3));
  background-color: var(--surface-haute);
  background-image:
    linear-gradient(45deg, transparent 50%, var(--brume) 50%),
    linear-gradient(135deg, var(--brume) 50%, transparent 50%);
  background-position:
    calc(100% - var(--space-5) - var(--fleche)) 50%,
    calc(100% - var(--space-5)) 50%;
  background-size: var(--fleche) var(--fleche);
  background-repeat: no-repeat;
  text-overflow: ellipsis;
  cursor: pointer;
}

/* A link in the text: underlined, so that its colour never speaks alone. */
a:not([class]) {
  color: var(--plume);
  text-decoration: underline;
  text-underline-offset: var(--space-1);
  border-radius: var(--radius-sm);
}

a:not([class]):hover {
  color: var(--or-vif);
}

a:not([class]):focus-visible,
.choice input:focus-visible {
  outline: 2px solid var(--or);
  outline-offset: 2px;
}

/* A link on its own line, the footer's, and a console list's: a whole touch target. */
.link a,
.pied a,
.links a,
.lignes a {
  display: inline-flex;
  align-items: center;
  min-height: var(--cible-tactile);
}

/* ---------- Lists ---------- */

.page ul {
  margin: 0;
  padding-left: var(--space-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.page .links {
  gap: 0;
}

/* The devices: one per line between hairlines, this browser tagged. */
.page .devices {
  list-style: none;
  padding: 0;
  gap: 0;
  border-top: 1px solid var(--ligne);
}

.devices li {
  box-sizing: border-box;
  min-height: var(--cible-tactile);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--ligne);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-3);
}

.devices .seen {
  color: var(--brume);
}

/* The games: one column on a phone, two on a tablet, three on a desk. */
.page .games {
  list-style: none;
  padding: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-5);
}

.games li {
  display: flex;
}

.games .pb-carte {
  flex: 1;
}

/* A game not open yet is not a link: no hover that promises a press. */
div.pb-carte:hover {
  background: var(--surface);
}

div.pb-carte:hover .pb-carte-visuel {
  background: var(--surface-haute);
}

/* ---------- The home page's head ---------- */

.accueil {
  margin-top: 0;
  width: 100%;
  max-width: var(--page-colonne);
  align-self: center;
  align-items: center;
  text-align: center;
}

/* ---------- Choices: a radio button or a box beside its words ---------- */

.choices {
  margin: 0;
  padding: 0;
  border: 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.choices legend {
  padding: 0;
  margin-bottom: var(--space-1);
}

.choice {
  min-height: var(--cible-tactile);
  display: flex;
  align-items: center;
  gap: var(--space-3);
  cursor: pointer;
}

.choice input {
  flex-shrink: 0;
  width: var(--space-6);
  height: var(--space-6);
  margin: 0;
  accent-color: var(--or);
}

/* ---------- The console ---------- */

/* The console's menu: a TabBar at the top of the column, not fixed, its
   tabs on a surface with rounded corners, at every width. */
.page .pb-onglets {
  border: 1px solid var(--ligne);
  border-radius: var(--radius-lg);
}

/* An account's sheet: each term over its value, between hairlines; an
   address or an id breaks anywhere rather than spill on a phone. */
.fiche {
  margin: 0;
  display: flex;
  flex-direction: column;
  border-top: 1px solid var(--ligne);
}

.fiche div {
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--ligne);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--rythme-serre);
}

.fiche dt,
.lignes .quand {
  font-size: var(--texte-petit-taille);
  line-height: var(--texte-petit-interligne);
  color: var(--brume);
}

.fiche dd {
  margin: 0;
  overflow-wrap: anywhere;
}

/* The console's lists (the bans, the journal, a sheet's actions): one entry
   per line between hairlines, its time first, on a line of its own. */
.page .lignes {
  list-style: none;
  padding: 0;
  gap: 0;
  border-top: 1px solid var(--ligne);
}

.lignes li {
  box-sizing: border-box;
  min-height: var(--cible-tactile);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--ligne);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  overflow-wrap: anywhere;
}

.lignes .quand {
  width: 100%;
}

/* A profile's lines (`profile/page.rs`): a console list's hairlines, each
   line a column: its name, then its world and score on a quieter row, then
   an ended line's why and day, then the link to its sheet. A game's text
   wraps, never truncated. */
.lignes.profil li {
  flex-direction: column;
  align-items: flex-start;
  gap: var(--rythme-serre);
}

.profil .nom {
  font-weight: 600;
}

.profil .detail {
  color: var(--brume);
}

/* A score moves to the next line whole rather than split from its label,
   and wraps within itself only when longer than a line. */
.profil .score {
  display: inline-block;
  max-width: 100%;
  color: var(--plume);
  font-variant-numeric: tabular-nums;
}

.profil .fin {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
}

.profil .quand {
  width: auto;
}

/* A sheet's « Accès » zone (`console/sheet.rs`): per game, its name over
   its accesses, one row each between hairlines, a console list's rhythm:
   its label and its state, then its one button, a full control high. From
   a tablet on, the button stands at the row's end, as wide as its words. */
.acces-jeu {
  display: flex;
  flex-direction: column;
}

.acces h3 {
  margin: 0;
  padding-bottom: var(--space-3);
  border-bottom: 1px solid var(--ligne);
  font-size: inherit;
  line-height: inherit;
  font-weight: 600;
}

.acces-ligne {
  box-sizing: border-box;
  min-height: var(--cible-tactile);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--ligne);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.acces-etat {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  overflow-wrap: anywhere;
}

.acces .pb-btn {
  min-height: var(--cible-tactile);
}

/* Words only a screen reader reads: a button's access and game. */
.masque {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------- Test mode's outbox ---------- */

.mail {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-5);
  border-radius: var(--radius-lg);
  background: var(--surface);
}

.mail pre {
  margin: 0;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* ---------- Tablet: --bp-tablette ---------- */

@media (min-width: 768px) {
  .page {
    max-width: calc(var(--page-colonne) + 2 * var(--space-6));
    padding: var(--space-12) var(--space-6) var(--space-16);
  }

  .page-large {
    max-width: calc(var(--contenu-max) + 2 * var(--space-6));
  }

  .page .games {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .acces-ligne {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
  }

  .acces .pb-btn {
    width: auto;
  }
}

/* ---------- Desk: --bp-bureau ---------- */

@media (min-width: 1200px) {
  h1 {
    font-size: var(--texte-titre-1-taille-bureau);
    line-height: var(--texte-titre-1-interligne-bureau);
  }

  section {
    margin-top: calc(var(--space-16) - var(--rythme));
  }

  .accueil {
    margin-top: 0;
  }

  .page .games {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}
