/* Design language: Dieter Rams / Braun — paper, ink, one orange. Shared with "aer" (SOtM). */

@font-face { font-family: "Archivo"; font-weight: 500; font-display: swap; src: url("/demo/fonts/archivo-latin-500-normal.woff2") format("woff2"); }
@font-face { font-family: "Archivo"; font-weight: 600; font-display: swap; src: url("/demo/fonts/archivo-latin-600-normal.woff2") format("woff2"); }
@font-face { font-family: "Archivo"; font-weight: 700; font-display: swap; src: url("/demo/fonts/archivo-latin-700-normal.woff2") format("woff2"); }
@font-face { font-family: "Archivo"; font-weight: 800; font-display: swap; src: url("/demo/fonts/archivo-latin-800-normal.woff2") format("woff2"); }

:root {
  color-scheme: light;
  --paper: #eeede6;
  --ink: #18160f;
  --tile: #e3e2da;
  --tile-2: #d8d7ce;
  --orange: #da5b1f;   /* 13/10 (the owner): half way between the orange of before (#e9531a) and Rams 01 (#cc6324) */
  --orange-fill: #c6531c;   /* 18/10 (audit): the same orange a shade deeper under white text (4.5:1); --orange elsewhere */
  --amber: #ed8008;   /* 13/10: palette « Dieter Rams 03 » (the owner): the room as it is (« Avant ») */
  --olive: #736b1e;   /* « it works »: playing, done, OK */
  --alert: #bf1b1b;   /* errors only */
  --on: #ffffff;
  --muted: #66645c;   /* 18/10 (audit): 4.5:1 on the paper and on the tiles (#7c7a70 before: 3.7 and 3.3) */
  --grid: #d3d2c9;
  --left: #3b6ea5;
  --right: #e9531a;
  --target: #18160f;
  --r: 5px;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --paper: #151410;
    --ink: #eeede6;
    --tile: #211f19;
    --tile-2: #2b2922;
    --orange: #e8662a;
    --orange-fill: #e8662a;
    --amber: #f08a1e;
    --olive: #a39a3a;
    --alert: #e0503f;
    --on: #151410;
    --muted: #89877c;
    --grid: #2e2c25;
    --left: #4a80c8;
    --right: #e85a1b;
    --target: #eeede6;
  }
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --paper: #151410; --ink: #eeede6; --tile: #211f19; --tile-2: #2b2922; --orange: #e8662a; --orange-fill: #e8662a; --amber: #f08a1e; --olive: #a39a3a; --alert: #e0503f; --on: #151410;
  --muted: #89877c; --grid: #2e2c25; --left: #4a80c8; --right: #e85a1b; --target: #eeede6;
}

* { box-sizing: border-box; }
html, body { margin: 0; }
body {
  background: var(--paper);
  color: var(--ink);
  font: 500 15px/1.45 "Archivo", system-ui, -apple-system, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
  padding: env(safe-area-inset-top) 20px calc(40px + env(safe-area-inset-bottom));
}
.wrap { max-width: 680px; margin: 0 auto; padding-block: clamp(20px, 4vh, 40px) 0; position: relative; overflow-x: clip; }

/* ── Type ────────────────────────────────────────────── */
.label, .k {
  font-size: 11px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--muted);
}
.muted { color: var(--muted); font-size: 13px; font-weight: 600; }
p { margin: 8px 0; }
b, strong { font-weight: 700; }
.num { font-variant-numeric: tabular-nums; }
a { color: inherit; text-underline-offset: 3px; }
code { font: 600 13px/1.4 ui-monospace, "SF Mono", Menlo, monospace; background: var(--tile-2); padding: 1px 5px; border-radius: 3px; }

/* ── Header ──────────────────────────────────────────── */
.top { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 26px; }
/* :hover:not(:disabled) too (08/10, the iPhone app): a touch screen keeps :hover after a tap, and the buttons' rule below
   would box the logo in ink. */
button.logo, button.logo:hover, button.logo:hover:not(:disabled) {
  font-size: 22px; font-weight: 800; letter-spacing: -.03em; text-transform: none; background: none; border: 0;
  padding: 0; min-height: 0; color: var(--ink); font-family: inherit; cursor: pointer; display: inline; line-height: 1;
}
.logo .back { color: var(--muted); font-weight: 700; margin-right: 6px; }
.status { font-size: 13px; font-weight: 600; color: var(--muted); letter-spacing: .02em; display: inline-flex; align-items: center; gap: 7px; white-space: nowrap; }
.status i { width: 7px; height: 7px; border-radius: 50%; background: var(--muted); display: inline-block; }
.status.on i { background: var(--olive); }
.title { font-size: clamp(26px, 7vw, 34px); font-weight: 800; letter-spacing: -.03em; line-height: 1; margin: 0 0 6px; }
.subtitle { font-size: 13px; font-weight: 600; color: var(--muted); letter-spacing: .02em; margin-bottom: 22px; }

/* ── Sections ────────────────────────────────────────── */
section.sec { margin-top: 34px; }

.panel { background: var(--tile); border-radius: var(--r); padding: 15px 15px 14px; }
.panel + .panel, .panel + .grid, .grid + .panel, .board + .panel, .panel + .board, .grid + .board, .board + .grid { margin-top: 10px; }
.grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; }
.grid.four { grid-template-columns: repeat(4, 1fr); }
.grid.three { grid-template-columns: repeat(3, 1fr); }
.gap { height: 10px; }

/* ── Tiles (choices) ─────────────────────────────────── */
.tile {
  position: relative; display: flex; flex-direction: column; justify-content: space-between; gap: 10px;
  min-height: 150px; padding: 14px 14px 13px; border: 0; border-radius: var(--r);
  background: var(--tile); color: var(--ink); font: inherit; text-align: left; cursor: pointer;
  transition: transform .08s ease;
}
button.tile {
  display: flex; align-items: stretch; text-transform: none; letter-spacing: normal; font-weight: 500;
  font-size: 15px; line-height: 1.3; min-height: 150px; border: 0;
}
button.tile:hover:not(:disabled) { background: var(--tile-2); color: var(--ink); }
button.tile.active, button.tile.active:hover { background: var(--orange-fill); color: var(--on); }
button.tile.small { min-height: 104px; }
.tile .nm, .tile .rt { display: block; }
.tile:active { transform: translateY(1px); }
.tile .idx { font-size: 12px; font-weight: 700; letter-spacing: .14em; color: var(--muted); }
.tile svg { width: 44px; height: 44px; display: block; }
.tile .nm { font-size: 17px; font-weight: 800; letter-spacing: -.02em; line-height: 1.05; }
.tile .rt { font-size: 12px; font-weight: 600; color: var(--muted); margin-top: 5px; line-height: 1.3; }
.tile.small { min-height: 104px; }
.tile.active { background: var(--orange-fill); color: var(--on); }
.tile.active .idx, .tile.active .rt { color: var(--on); opacity: 1; }   /* (18/10, audit) white on the deeper orange: 4.5:1, no transparency */
.tile:disabled { cursor: default; }
.tile:disabled .nm, .tile:disabled svg { opacity: .5; }
/* Greyed as a cue only (the calibrated mics' tiles until one is plugged in): still a button. */
button.tile.off .nm, button.tile.off svg { opacity: .5; }

/* Wider image: three lengths side by side. */
.image-form .grid .field + .field { margin-top: 0; }
.image-form .field .k { min-height: 2.4em; }
.image-form input[type="text"] { font-variant-numeric: tabular-nums; }

/* A/B page (public/ab.js): the choice compared, outlined (it plays as A or B); "Playing now", one line per setting. */
button.tile.chosen { box-shadow: inset 0 0 0 2px var(--orange); }
.ab-now .step-label { margin-bottom: 8px; }
.ab-line { display: flex; gap: 12px; align-items: baseline; padding: 6px 0; border-top: 1px solid var(--grid); font-size: 15px; font-weight: 600; }
.ab-now .step-label + .ab-line { border-top: 0; }
.ab-line b { flex: 0 0 34%; font-size: 11px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--muted); }
.ab-line span { flex: 1; min-width: 0; overflow-wrap: anywhere; }

/* ── Board (big readout) ─────────────────────────────── */
.board {
  background: var(--ink); color: var(--paper); border-radius: var(--r);
  padding: 18px 20px; display: flex; align-items: flex-end; justify-content: space-between; gap: 16px;
}
.board .lab { font-size: 11px; font-weight: 700; letter-spacing: .16em; text-transform: uppercase; opacity: .6; }
.board .big { font-size: clamp(36px, 10vw, 58px); font-weight: 800; letter-spacing: -.03em; line-height: .9; font-variant-numeric: tabular-nums; margin-top: 8px; }
.board .big em { font-style: normal; font-size: .4em; font-weight: 700; color: var(--orange); margin-left: 6px; letter-spacing: 0; }
.board .side { display: flex; gap: 22px; font-variant-numeric: tabular-nums; }
.board .kv { text-align: right; }
.board .kv b { display: block; font-size: 16px; font-weight: 700; line-height: 1.1; }
.board .kv small { display: block; font-size: 11px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; opacity: .6; margin-top: 4px; }
.board .bar { height: 3px; background: color-mix(in srgb, var(--paper) 18%, transparent); margin-top: 14px; border-radius: 2px; overflow: hidden; }
.board .bar > div { height: 100%; width: 0; background: var(--orange); transition: width .25s linear; }
/* « Recentre sur moi » (14/10): where the listener sits, said in a sentence on the board */
.board .rc-said { font-size: clamp(20px, 5.4vw, 28px); font-weight: 800; letter-spacing: -.02em; line-height: 1.15; margin: 10px 0 0; }
#rc-preset { margin: 8px 0 4px; }
/* (15/10, the owner: « pas assez bavard ») the distances in large, the gap, what is done, a plan seen from above */
.rc-dist { font-size: clamp(18px, 4.6vw, 24px); font-weight: 800; letter-spacing: -.01em; line-height: 1.2; margin: 18px 0 2px; }
.rc-gap { font-size: 15px; font-weight: 700; margin: 10px 0 0; }
.rc-what { margin: 8px 0 0; }
.rc-plan { margin: 14px 0 4px; max-width: 360px; }
.rc-plan svg { display: block; overflow: visible; }
.rc-plan .pl-spk { fill: var(--ink); }
.rc-plan .pl-lab { fill: var(--paper); font-size: 11px; font-weight: 800; }
.rc-plan .pl-ray { stroke: var(--muted); stroke-width: 1; stroke-dasharray: 3 4; }
.rc-plan .pl-seat { fill: none; stroke: var(--muted); stroke-width: 2; }
.rc-plan .pl-you { fill: var(--orange); }
.rc-plan .pl-txt { fill: var(--muted); font-size: 11px; font-weight: 700; letter-spacing: .04em; }
.rc-plan .pl-you-t { fill: var(--ink); }
#rc-following { margin-top: 12px; }
#rc-following .acts { margin-top: 10px; }

/* ── Cells (key / value) ─────────────────────────────── */
.cells { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-top: 10px; }
.cell { background: var(--tile); border-radius: var(--r); padding: 12px 13px; min-width: 0; }
.cell .v { font-size: 15px; font-weight: 700; margin-top: 6px; font-variant-numeric: tabular-nums; letter-spacing: -.01em; overflow-wrap: anywhere; }

/* ── Buttons ─────────────────────────────────────────── */
button, .btn {
  font: 700 13px/1 "Archivo", system-ui, sans-serif; letter-spacing: .04em; text-transform: uppercase;
  background: none; color: var(--ink); border: 2px solid var(--ink); border-radius: var(--r);
  padding: 13px 14px; min-height: 46px; cursor: pointer; text-decoration: none;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px; transition: background .12s, color .12s;
}
button:hover:not(:disabled), .btn:hover { background: var(--ink); color: var(--paper); }
button.go, .btn.go { background: var(--orange-fill); border-color: var(--orange-fill); color: var(--on); min-height: 58px; font-size: 14px; }
button.go:hover:not(:disabled), .btn.go:hover { background: var(--orange-fill); color: var(--on); filter: brightness(1.05); }
button.quiet { border-color: transparent; color: var(--muted); padding-inline: 6px; min-height: 36px; }
button.quiet:hover:not(:disabled) { background: none; color: var(--ink); }
button:disabled { opacity: .4; cursor: default; }
.block { width: 100%; }
.acts { display: flex; gap: 10px; margin-top: 10px; }
.acts > * { flex: 1; }

.seg { display: flex; gap: 6px; }
.seg + .seg { margin-top: 10px; }
.seg button { flex: 1; min-height: 38px; padding: 8px 6px; font-size: 12px; }
.seg button.on, .seg button.on:hover { background: var(--orange-fill); border-color: var(--orange-fill); color: var(--on); }

/* ── Forms ───────────────────────────────────────────── */
.field { display: block; }
.field + .field { margin-top: 12px; }
.field .k { display: block; margin-bottom: 7px; }
.field.target > span { display: block; margin-bottom: 8px; }
.field.target .btn { display: inline-block; }
input[type="text"], input[type="password"], select {
  font: 700 16px/1.2 "Archivo", system-ui, sans-serif; width: 100%; color: var(--ink);
  background: var(--paper); border: 0; border-radius: var(--r); padding: 12px 12px; min-height: 46px;
  -webkit-appearance: none; appearance: none;
}
select { background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 18px) 50%, calc(100% - 13px) 50%; background-size: 5px 5px; background-repeat: no-repeat; padding-right: 34px; }
input[type="text"]::placeholder { color: var(--muted); font-weight: 600; }
input[type="text"]:focus, input[type="password"]:focus, select:focus, button:focus-visible, .tile:focus-visible { outline: 2px solid var(--orange); outline-offset: 2px; }

input[type="checkbox"] {
  -webkit-appearance: none; appearance: none; width: 22px; height: 22px; flex: 0 0 auto; margin: 0;
  border: 2px solid var(--ink); border-radius: 3px; background: transparent; cursor: pointer; display: grid; place-content: center;
}
input[type="checkbox"]:checked { background: var(--orange); border-color: var(--orange); }
input[type="checkbox"]:disabled { cursor: default; opacity: .55; }
input[type="checkbox"]:checked::after { content: ""; width: 10px; height: 6px; border: 2.5px solid var(--on); border-top: 0; border-right: 0; transform: translateY(-1px) rotate(-45deg); }

input[type="range"] { -webkit-appearance: none; appearance: none; width: 100%; background: transparent; height: 28px; margin: 2px 0 0; }
input[type="range"]::-webkit-slider-runnable-track { height: 2px; background: var(--ink); border-radius: 1px; }
input[type="range"]::-moz-range-track { height: 2px; background: var(--ink); }
input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; width: 18px; height: 18px; border-radius: 50%; background: var(--orange); margin-top: -8px; border: 0; }
input[type="range"]::-moz-range-thumb { width: 18px; height: 18px; border-radius: 50%; background: var(--orange); border: 0; }

.slider + .slider { margin-top: 10px; }
.slider .head { display: flex; justify-content: space-between; align-items: baseline; }
.slider .head b { font-size: 14px; font-variant-numeric: tabular-nums; }

.check { display: flex; gap: 12px; align-items: flex-start; padding: 11px 0; border-top: 1px solid var(--grid); font-size: 14px; }
.check:first-child { border-top: 0; padding-top: 2px; }
.check label { cursor: pointer; }

/* ── Notes (status messages; always labelled, never colour alone) ── */
.note { border-radius: var(--r); padding: 12px 14px; font-size: 14px; background: var(--tile); border-left: 4px solid var(--ink); }
.note .k { display: block; margin-bottom: 3px; color: var(--ink); }
.note.warn { border-left-color: var(--orange); }
.note.ok { border-left-color: var(--olive); }
/* (17/10) the ways at 1 m (live tuning, public/app.js drawWays): the number of ways asked over the colours' key */
.ways-k { margin: 6px 0; }
.note.error { background: var(--ink); color: var(--paper); border-left-color: var(--alert); }
.note.error .k { color: color-mix(in srgb, var(--alert) 72%, var(--paper)); }
.note + .note, .note + *, * + .note { margin-top: 10px; }
.notes { margin-bottom: 28px; }
/* What is new in a version, inside its note (src/news.js). */
.note ul.news { margin: 6px 0 8px; padding-left: 18px; }
.note ul.news li + li { margin-top: 4px; }

/* ── Lists ───────────────────────────────────────────── */
.rows { list-style: none; margin: 0; padding: 0; }
.rows li { display: flex; align-items: center; gap: 12px; padding: 12px 0; border-top: 1px solid var(--grid); }
.rows li:first-child { border-top: 0; padding-top: 0; }
.rows li:last-child { padding-bottom: 0; }
.rows .idx { font-size: 12px; font-weight: 700; letter-spacing: .14em; color: var(--muted); width: 22px; flex: 0 0 auto; }
.rows .main { flex: 1 1 auto; min-width: 0; }
/* In place of the « Utiliser » checkbox on rows that cannot be used (verification captures). */
.rows .m-slot { width: 22px; flex: 0 0 auto; }
.rows .main .nm { font-weight: 800; letter-spacing: -.01em; }
.rows .main .rt { font-size: 12px; font-weight: 600; color: var(--muted); font-variant-numeric: tabular-nums; margin-top: 2px; }
.rows li.sel .nm { color: var(--orange); }
.rows a.row-link { display: flex; align-items: center; gap: 12px; color: inherit; text-decoration: none; flex: 1; min-width: 0; }
.rows .warns { margin: 4px 0 0; padding: 0; list-style: none; font-size: 12px; font-weight: 600; }
.rows .warns li { border: 0; padding: 2px 0 0; display: block; }
.rows .warns li::before { content: "▲ "; color: var(--orange); font-size: 9px; vertical-align: 1px; }

ol.steps { margin: 0; padding: 0; list-style: none; counter-reset: s; }
ol.steps li { counter-increment: s; display: grid; grid-template-columns: 30px 1fr; padding: 10px 0; border-top: 1px solid var(--grid); font-size: 14px; }
ol.steps li:first-child { border-top: 0; padding-top: 0; }
ol.steps li::before { content: counter(s, decimal-leading-zero); font-size: 12px; font-weight: 700; letter-spacing: .1em; color: var(--muted); padding-top: 2px; }

details > summary { cursor: pointer; list-style: none; font-size: 11px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; padding: 12px 0 4px; }
details > summary::-webkit-details-marker { display: none; }
details > summary::before { content: "+ "; color: var(--orange); }
details[open] > summary::before { content: "− "; }

/* ── Meter ───────────────────────────────────────────── */
.meter { height: 4px; background: var(--tile-2); border-radius: 2px; overflow: hidden; margin-top: 12px; }
.meter > div { height: 100%; width: 0; background: var(--ink); transition: width 80ms linear; }
.meter.hot > div { background: var(--orange); }

/* ── Chart ───────────────────────────────────────────── */
.chart { position: relative; }
.chart canvas { width: 100%; height: 260px; display: block; touch-action: pan-y; }
.chart .tip {
  position: absolute; pointer-events: none; background: var(--ink); color: var(--paper); border-radius: var(--r);
  padding: 8px 10px; font-size: 12px; font-weight: 600; white-space: nowrap; font-variant-numeric: tabular-nums; z-index: 2; line-height: 1.5;
}
.chart .tip b { font-weight: 800; }
.chart .tip .sw { display: inline-block; width: 10px; height: 3px; border-radius: 1px; margin-right: 6px; vertical-align: middle; }
.legend { display: flex; flex-wrap: wrap; gap: 6px 16px; font-size: 12px; font-weight: 600; color: var(--muted); margin-top: 10px; }
.legend span { display: inline-flex; align-items: center; gap: 7px; }
.legend i { width: 16px; height: 0; border-top: 2px solid; display: inline-block; }
.legend i.dash { border-top-style: dashed; }
.legend i.faint { opacity: .4; }

/* ── Toast ───────────────────────────────────────────── */
.toast {
  position: fixed; left: 20px; right: 20px; bottom: calc(20px + env(safe-area-inset-bottom)); z-index: 10;
  max-width: 640px; margin: 0 auto; background: var(--ink); color: var(--paper); border-radius: var(--r);
  padding: 14px 16px; font-size: 14px; font-weight: 600; border-left: 4px solid var(--orange);
}
.toast .k { display: block; color: var(--orange); margin-bottom: 2px; }
/* (13/10) its colour says what it is, as everywhere: olive when it worked, orange to warn, the alert's for an error (the
   label's colour softened toward the paper: read on the ink) */
.toast.ok { border-left-color: var(--olive); }
.toast.ok .k { color: color-mix(in srgb, var(--olive) 72%, var(--paper)); }
.toast.error { border-left-color: var(--alert); }
.toast.error .k { color: color-mix(in srgb, var(--alert) 72%, var(--paper)); }
/* (18/10, audit) « Réessayer » in an error that only read (audiolaz not answering): on the ink, the paper's outline */
.toast .toast-again { display: flex; margin-top: 10px; min-height: 44px; border-color: var(--paper); color: var(--paper); }
.toast .toast-again:hover:not(:disabled) { background: var(--paper); color: var(--ink); }

.hidden { display: none !important; }

@media (max-width: 560px) {
  body { padding-inline: 16px; }
  .cells { grid-template-columns: 1fr 1fr; }
  .board { flex-direction: column; align-items: stretch; gap: 10px; }
  .board .kv { text-align: left; }
  .grid.four { grid-template-columns: repeat(2, 1fr); }
}

/* ── Guided flow ─────────────────────────────────────── */
.dots { display: flex; gap: 5px; }
.dots i { width: 18px; height: 3px; border-radius: 2px; background: var(--tile-2); }
.dots i.done { background: var(--ink); }
.dots i.on { background: var(--orange); }
@media (prefers-reduced-motion: reduce) { .board.live.on .lab::before, .room .pulse { animation: none !important; } }

.step-label { font-size: 11px; font-weight: 700; letter-spacing: .16em; text-transform: uppercase; color: var(--muted); margin-bottom: 10px; }
.title.xl { font-size: clamp(32px, 9.5vw, 46px); line-height: .98; margin-bottom: 12px; }
.lead { font-size: 17px; font-weight: 500; line-height: 1.4; margin: 0 0 22px; max-width: 34ch; }
.device { overflow-wrap: anywhere; }
.device .cal-missing { color: var(--orange); }
.lead + .device { margin-top: -12px; }
.actions { display: grid; gap: 6px; margin-top: 18px; }
.actions .go { margin-bottom: 4px; }

button.link, button.link:hover:not(:disabled) {
  background: none; border: 0; color: var(--muted); text-transform: none; letter-spacing: 0;
  font-size: 15px; font-weight: 600; min-height: 44px; padding: 6px 0; text-decoration: underline; text-underline-offset: 4px;
}
button.link:hover:not(:disabled) { color: var(--ink); }

button.tile.wide { width: 100%; min-height: 0; flex-direction: row; align-items: center; justify-content: flex-start; gap: 16px; margin-bottom: 4px; }
button.tile.wide .idx { min-width: 76px; }

.rows button.row-link {
  all: unset; box-sizing: border-box; display: flex; align-items: center; gap: 12px; width: 100%; cursor: pointer; min-height: 44px;
}
.rows .main .nm, .rows .main .rt { display: block; }
/* The home's rows: an icon before each name (07/10), in the ink, the line of the other icons. */
.rows .ico { width: 26px; height: 26px; flex: 0 0 26px; color: var(--ink); margin-right: 2px; }
.rows .ico svg { width: 100%; height: 100%; display: block; }
.rows button.row-link.active .nm, .rows button.row-link.active .muted { color: var(--orange); }
/* (15/10) « Comment le son arrive »: a way not there now, greyed and never chosen; the expert's keys under each way */
.rows button.row-link.gone { opacity: .5; cursor: default; }
#rs-paths .rt.tech { font-size: 12px; overflow-wrap: anywhere; }

ol.steps.big li { font-size: 16px; padding: 14px 0; }
ol.steps.big { margin-bottom: 18px; }

.waiting { display: flex; align-items: center; gap: 10px; font-size: 14px; font-weight: 600; color: var(--muted); margin-top: 18px; }
.waiting i { width: 8px; height: 8px; border-radius: 50%; background: var(--orange); animation: blink 1.2s ease-in-out infinite; }
@keyframes blink { 50% { opacity: .2; } }

.board .addr { font-size: 18px; font-weight: 700; margin-top: 8px; overflow-wrap: anywhere; }
/* The phone's address as a QR code, on the computer (app.js phoneHandoff) */
.handoff { margin: 14px 0; }
.handoff-row { display: flex; gap: 14px; align-items: center; }
.handoff .qr svg { display: block; width: 132px; height: 132px; border-radius: 6px; flex: none; }
.handoff .lab { font-size: 11px; font-weight: 700; letter-spacing: .16em; text-transform: uppercase; opacity: .6; }
.handoff-lead { margin: 6px 0 8px; }
.handoff .addr { font-weight: 700; overflow-wrap: anywhere; }
.handoff details { margin-top: 12px; }
.handoff summary { cursor: pointer; font-weight: 700; }
.handoff .steps { margin: 10px 0 0; }
.handoff-here { margin: 12px 0 0; }
.board + .btn, .board + .lead, .board + p { margin-top: 14px; }

/* Room plan */
#stage { transition: opacity .3s; margin: 4px 0 6px; }
#stage.dim { opacity: .35; }
.room { width: 100%; max-width: 420px; height: auto; display: block; margin: 0 auto; }
.room .spk { fill: none; stroke: var(--ink); stroke-width: 2.5; }
.room .seat { fill: var(--tile); stroke: var(--tile-2); stroke-width: 2; }
.room .ray { stroke: var(--orange); stroke-width: 1.5; stroke-dasharray: 3 5; fill: none; opacity: .7; }
.room .spot { fill: var(--paper); stroke: var(--muted); stroke-width: 2.5; }
.room .spot.done { fill: var(--ink); stroke: var(--ink); }
.room .spot.now { fill: var(--orange); stroke: var(--orange); }
.room .pulse { fill: var(--orange); opacity: .35; transform-box: fill-box; transform-origin: center; animation: pulse 1.6s ease-out infinite; }
.room .num { font: 700 10px "Archivo", sans-serif; letter-spacing: .1em; fill: var(--muted); text-anchor: middle; }
@keyframes pulse { from { transform: scale(1); opacity: .45; } to { transform: scale(3.2); opacity: 0; } }

/* Live measurement */
.board.live { display: block; margin-top: 8px; }
.board.live .big { font-size: clamp(72px, 26vw, 120px); margin-top: 6px; }
.board.live .lab { display: flex; align-items: center; gap: 8px; opacity: .75; }
.board.live .hint { margin-top: 10px; font-size: 13px; line-height: 1.4; opacity: .85; }
textarea { font: 600 16px/1.35 "Archivo", system-ui, sans-serif; width: 100%; box-sizing: border-box; color: var(--ink); background: var(--paper); border: 0; border-radius: var(--r); padding: 12px; resize: vertical; -webkit-appearance: none; appearance: none; }
textarea:focus { outline: 2px solid var(--orange); outline-offset: 2px; }
/* Fields outside a panel (06/10): the page's colour and no edge left them invisible (the Core's password, the report, the
   licence file, the player's output). There, the tile's colour and a rule under them, ink while typing; inside a panel
   they stay as they are. A menu keeps its arrow (its background image): its colour alone. */
input[type="text"]:not(.panel *), input[type="password"]:not(.panel *), textarea:not(.panel *) { background: var(--tile); box-shadow: inset 0 -2px 0 var(--muted); }
select:not(.panel *) { background-color: var(--tile); box-shadow: inset 0 -2px 0 var(--muted); }
input[type="text"]:not(.panel *):focus, input[type="password"]:not(.panel *):focus, textarea:not(.panel *):focus, select:not(.panel *):focus { box-shadow: inset 0 -2px 0 var(--ink); }
pre.report { font: 12px/1.45 ui-monospace, "SF Mono", Menlo, monospace; white-space: pre-wrap; word-break: break-word; background: var(--tile-2); padding: 12px; border-radius: var(--r); max-height: 40vh; overflow: auto; }
.board.live.on .lab::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--orange); animation: blink 1s ease-in-out infinite; }
.board.live.success .big { color: color-mix(in srgb, var(--olive) 72%, var(--paper)); }   /* taken: the olive, read on the ink */

/* Score */
.board.score .big { font-size: clamp(56px, 18vw, 88px); display: flex; align-items: baseline; gap: 10px; }
.board.score .big .before { opacity: .4; }
.board.score .big em { font-size: .45em; margin: 0; }

details.expert { margin-top: 26px; border-top: 1px solid var(--grid); padding-top: 6px; }
details.expert[open] > summary { margin-bottom: 10px; }
/* The result's expert settings (01/10: nobody found the folded line): a tile that says what is inside. */
details#expert { border-top: 0; padding-top: 0; margin-top: 18px; }
details#expert > summary { list-style: none; display: block; padding: 14px; border-radius: var(--r); background: var(--tile); cursor: pointer; }
details#expert > summary::-webkit-details-marker { display: none; }
details#expert > summary .nm { display: block; font-weight: 700; }
details#expert > summary .rt { display: block; margin-top: 3px; font-size: 13px; color: var(--muted); }
details#expert > summary::after { content: '›'; float: right; font-size: 22px; line-height: 1; color: var(--muted); }
details#expert[open] > summary::after { content: '⌄'; }
/* « Expert settings » at the foot of « Settings and help » (09/10, audit lot 3, « le tiroir expert »): a drawer, the same
   tile as the result's expert settings. */
details.drawer { border-top: 0; padding-top: 0; margin-top: 30px; }
details.drawer > summary { list-style: none; display: block; padding: 14px; border-radius: var(--r); background: var(--tile); cursor: pointer; }
details.drawer > summary::-webkit-details-marker { display: none; }
/* 10/10: a tile, not the folded lines' small capitals and « + » (« Autres réglages » read as a heading otherwise) */
details.drawer > summary { font-size: 15px; letter-spacing: 0; text-transform: none; position: relative; padding-right: 36px; }
details.drawer > summary::after { float: none; position: absolute; right: 14px; top: 50%; transform: translateY(-50%); }
details.drawer > summary::before { content: none; }
details.drawer > summary .nm { display: block; font-weight: 700; }
details.drawer > summary .rt { display: block; margin-top: 3px; font-size: 13px; color: var(--muted); }
details.drawer > summary::after { content: '›'; float: right; font-size: 22px; line-height: 1; color: var(--muted); }
details.drawer[open] > summary::after { content: '⌄'; }
/* « My rooms »: each room's line, « Rename » and « Delete » under it, the field or the confirmation in place. */
.rows.rooms li { display: block; }
.rows.rooms .room-acts { display: flex; gap: 20px; }
.rows.rooms .room-acts .link { min-height: 36px; padding: 4px 0; font-size: 13px; }
.rows.rooms .room-edit:empty { display: none; }
.rows.rooms .room-edit { margin-top: 6px; }
.room-installed { margin: 6px 0 0; }
/* The result's notes with links (the speakers apart, the measurement kept). */
.note .gap-tools { display: flex; flex-wrap: wrap; gap: 0 20px; }
.note .gap-tools .link, .note#previous .link { min-height: 36px; padding: 4px 0; }

.wordmark { font-size: 22px; font-weight: 800; letter-spacing: -.03em; line-height: 1; }
a.btn.block { box-sizing: border-box; }

/* Pairing code: one transparent input over four boxes */
.code { position: relative; display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin: 6px 0 14px; cursor: text; }
.code span {
  display: grid; place-items: center; height: 84px; border-radius: var(--r); background: var(--tile);
  font: 800 42px/1 "Archivo", system-ui, sans-serif; color: var(--ink);
}
.code span.on { outline: 2px solid var(--orange); background: var(--paper); }
.code input {
  position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; border: 0; padding: 0;
  font-size: 16px; color: transparent; background: transparent; caret-color: transparent;
}

button.back-btn, button.back-btn:hover:not(:disabled) {
  background: none; border: 0; padding: 0 8px 0 0; min-height: 44px; color: var(--ink);
  font-size: 15px; font-weight: 700; letter-spacing: .01em; text-transform: none; justify-content: flex-start;
}
button.back-btn:hover:not(:disabled) { color: var(--orange); }

/* The audiolaz zones in place, on the first screen (04/10): each with its state and its page one tap away. */
.engines { display: flex; flex-direction: column; gap: 8px; margin: 6px 0 16px; }
.engine-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 14px; border-radius: var(--r); background: var(--tile); }
.engine-row .nm { font-weight: 600; }
.engine-act { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }

/* Live tuning (05/10): each speaker's linearity, and how it compares with the held curves */
.live-lin { margin-top: 8px; font-variant-numeric: tabular-nums; }
.live-lin div { margin: 2px 0; }
.live-lin .nm { display: inline-block; min-width: 64px; }
.live-lin .up { color: #2e8540; }
.live-lin .down { color: #c0392b; }
.live-lin .same { color: var(--muted, #89877c); }
/* The live tuning's mark out of 100, large (05/10, « beaucoup plus visible »): grey until a control moves the curve, then
   green when it rises above the start, red when it falls (« c'est cette note qui passe au rouge ou au vert »). */
.live-marks { display: flex; gap: 10px; margin: 12px 0; }
.live-mark { flex: 1; border-radius: var(--r); padding: 12px 14px; text-align: center; background: var(--tile); color: var(--ink); transition: background-color 0.3s; }
.live-mark .who { font-size: 13px; letter-spacing: 0.04em; text-transform: uppercase; opacity: 0.85; }
.live-mark .num { font-size: 64px; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; margin: 4px 0; }
.live-marks.two .live-mark .num { font-size: 44px; }
.live-mark .of { font-size: 18px; font-weight: 600; opacity: 0.7; margin-left: 2px; }
.live-mark .sub { font-size: 13px; opacity: 0.92; }
.live-mark.up { background: #2e8540; color: #fff; }
.live-mark.down { background: #c0392b; color: #fff; }

/* ── Home (06/10) ─────────────────────────────────────── */
/* « ‹ Back » under the header, on every screen that has one. */
/* The room's board: the result's score board, with the room's name and what plays, its chart under it. */

/* 10/10: the rooms' cards, swiped across (scroll-snap: a finger, a trackpad), dots under them, ‹ › for a mouse or a
   keyboard (hidden on a touch screen). Each card: its board, its curve, its status line or « Listen here ». */

.board + .panel.home-chart { margin-top: 0; border-radius: 0 0 var(--r) var(--r); padding-top: 12px; }
/* its height kept while the curve is on its way: the list under it does not move */
.panel.home-chart { min-height: 203px; }
/* Labels between the home's and the hubs' blocks. */
.k.home-k { display: block; margin: 22px 0 8px; }
/* The sound keys: the four sounds side by side (two by two on a phone), « No correction » across. */
.seg.keys { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
.seg.keys-none { margin-top: 6px; }
.seg.keys button, .seg.keys-none button { min-height: 44px; }
/* 10/10: the key tapped waits for its sound: outlined, a thin bar sweeping under its name while the player switches,
   then filling over the output's latency (--fill-ms: the sound on its way to the speakers); then it is the one lit. */
.seg button.wait, .seg button.wait:hover { position: relative; overflow: hidden; border-color: var(--orange); color: var(--ink); }
.seg button.wait::after { content: ''; position: absolute; left: 6px; right: 6px; bottom: 5px; height: 3px; border-radius: 2px; background: var(--orange); transform-origin: left center; transform: scaleX(0); animation: key-wait 1.2s ease-in-out infinite; }
.seg button.wait.fill::after { animation: key-fill var(--fill-ms, 1500ms) linear forwards; }
@keyframes key-wait { 0% { transform: scaleX(0); opacity: 1; } 75% { transform: scaleX(1); opacity: 1; } 100% { transform: scaleX(1); opacity: 0; } }
@keyframes key-fill { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@media (prefers-reduced-motion: reduce) { .seg button.wait::after { animation: none; transform: scaleX(.5); } .seg button.wait.fill::after { transform: scaleX(1); } }
.home-sound-msg { margin: 8px 0 0; font-size: 13px; font-weight: 600; color: var(--muted); }
/* 10/10: « Pièce de chaque sortie » on the player's screen: each output, the room it plays in at its right. */
#eng-rooms .row-link .eng-room-now { margin-left: auto; padding-left: 10px; font-weight: 700; text-align: right; overflow-wrap: anywhere; }
/* The room's status line (08/10, audit lot 2): where its correction plays and which sound, or what is left to do. */

/* The result's « Your 4 sounds are ready. » */
h2.sounds-ready { margin: 26px 0 4px; font-size: 22px; font-weight: 800; letter-spacing: -.02em; line-height: 1.15; }
h2.sounds-ready + .muted { margin: 0 0 12px; }
#resume { margin-top: 18px; }
.panel.hub { margin-top: 18px; }
.panel.hub .rows .main .nm { font-size: 16px; }
.panel.hub .rows a.row-link, .panel.hub .rows button.row-link { min-height: 44px; }
.panel.hub .rows .muted { font-size: 16px; }

.subtitle + .panel.hub, .home-k + .panel.hub { margin-top: 0; }
.seg#lang { margin-bottom: 4px; }
@media (max-width: 560px) {
  .seg.keys { grid-template-columns: repeat(2, 1fr); }
}

/* ── The audiolaz engine (06/10) ─────────────────────── */
/* A checklist that ticks itself (what the machine has, the install's steps, the Roon settings): the checkbox's box, filled
   and ticked when done, dashed with « ? » while it cannot be known yet, a dot while under way, round for a choice. */
.tick { width: 22px; height: 22px; flex: 0 0 auto; border: 2px solid var(--muted); border-radius: 3px; display: grid; place-content: center; }
.tick.on { background: var(--olive); border-color: var(--olive); }   /* done, it works: the olive */
.tick.radio.on { background: var(--orange); border-color: var(--orange); }   /* a choice: the orange */
.tick.on::after { content: ""; width: 10px; height: 6px; border: 2.5px solid var(--on); border-top: 0; border-right: 0; transform: translateY(-1px) rotate(-45deg); }
.tick.unknown { border-style: dashed; }
.tick.unknown::after { content: "?"; font-size: 12px; font-weight: 700; line-height: 1; color: var(--muted); }
.tick.now { border-color: var(--orange); }
.tick.now::after { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--orange); animation: blink 1.2s ease-in-out infinite; }
.tick.radio { border-radius: 50%; }
.tick.radio.on::after { width: 8px; height: 8px; border: 0; border-radius: 50%; background: var(--on); transform: none; }
.eng-checks li.todo .nm { color: var(--muted); }
.eng-checks .main .nm { overflow-wrap: anywhere; }
.eng-time { margin: 2px 0 0; }
.panel + .eng-time { margin-top: 10px; }
#eng-confirm .check { margin-top: 10px; }
#eng-confirm .acts { margin-top: 4px; }
@media (prefers-reduced-motion: reduce) { .tick.now::after { animation: none; } }

/* « Mon lecteur » (10/10, the owner: « trop compliquée »): one card per player — its name, where it is, one status line
   (a dot for its tone, never the colour alone: the words say it), one button; the rest under « Plus ». */
/* (11/10, « erreur de centrement ») one column that never grows past the page: a long title (ellipsis) no longer widens the card */
.pcards { display: grid; gap: 10px; grid-template-columns: minmax(0, 1fr); }
.pcard { background: var(--tile); border-radius: var(--r); padding: 14px 15px 15px; min-width: 0; }
.pcard .pcard-id { all: unset; box-sizing: border-box; display: flex; align-items: center; gap: 12px; width: 100%; }
.pcard button.pcard-id { cursor: pointer; min-height: 44px; margin: -6px 0; }
.pcard .pcard-name { flex: 1 1 auto; min-width: 0; display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 10px; }
.pcard .pcard-name .nm { font-size: 19px; font-weight: 800; letter-spacing: -.02em; }
.pcard .pcard-name .where { font-size: 12px; font-weight: 600; color: var(--muted); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.pcard .pcard-status { margin: 8px 0 0; font-weight: 700; display: flex; align-items: baseline; gap: 8px; }
.pcard .pcard-status::before { content: ""; flex: 0 0 8px; height: 8px; border-radius: 50%; background: var(--ink); transform: translateY(-1px); }
.pcard .pcard-status.on::before { background: var(--olive); }   /* playing: the olive, as everywhere */
.pcard .pcard-status.todo::before { background: none; box-shadow: inset 0 0 0 2px var(--orange); }
.pcard .pcard-status.off::before { background: var(--muted); }
.pcard .actions { margin-top: 14px; }
.pcard .actions .go { margin-bottom: 0; }

.pcards + .muted, .eng-lead { margin-top: 14px; }
#eng-body > .pcards + * { margin-top: 12px; }
/* 10/10 (« juste un bouton par lecteur »): the whole card one button, its status line inside; its screen in the app */
.pcard .pcard-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.pcard button.pcard-id { margin: -4px 0; padding: 2px 0; }
.mac-block:not(:empty) { margin-top: 10px; }

.pp-val { margin: 8px 0 0; }
#pp-main .pp-sound .k.home-k { margin-top: 18px; }
#mac-body > .pcards + * { margin-top: 12px; }
/* 10/10 (the owner: « la page a besoin de lisibilité, on s'y perd »): the player's screen. Its card says what plays in one
   sentence (« Maintenant »), the curve of its filter small under it; then « Son », « Sortie » (the output and its room,
   one line each, « Changer › »), « Synchro image » while an AirPlay video plays; the rest under « Autres réglages ». */
.pp-now { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--grid); }
.pp-now-line { margin: 0; font-size: 17px; font-weight: 800; letter-spacing: -.01em; line-height: 1.3; overflow-wrap: anywhere; }
.pp-curve { margin-top: 10px; }
.pp-curve-svg { aspect-ratio: 320 / 104; }
.pp-curve-svg svg { display: block; width: 100%; height: 100%; overflow: visible; }
.pp-curve-svg .g { stroke: var(--grid); stroke-width: 1; }
.pp-curve-svg .z { stroke: var(--ink); stroke-width: 1; stroke-dasharray: 4 4; opacity: .5; }
.pp-curve-svg .c { fill: none; stroke: var(--orange); stroke-width: 2.2; stroke-linejoin: round; stroke-linecap: round; }
.pp-curve-svg text { fill: var(--muted); font: 600 9px "Archivo", system-ui, sans-serif; }
.pp-curve-rt { margin: 4px 0 0; font-size: 12px; font-weight: 600; color: var(--muted); }
#pp-out .row-link .eng-room-now { margin-left: auto; padding-left: 10px; font-size: 14px; font-weight: 700; color: var(--muted); white-space: nowrap; }
#pp-out li > .main .nm { font-weight: 800; }
.panel.pp-list { margin-top: 6px; box-shadow: inset 0 0 0 2px var(--grid); }
.panel.pp-list + .actions { margin-top: 4px; }
.pp-ask { margin: 0 0 8px; font-size: 15px; font-weight: 700; }
.seg.pp-sync button { flex-direction: column; gap: 4px; min-height: 60px; padding: 10px 6px; text-transform: none; letter-spacing: 0; }
.seg.pp-sync .nm { font-size: 14px; font-weight: 800; }
.seg.pp-sync .rt { font-size: 11.5px; font-weight: 600; color: var(--muted); line-height: 1.25; }
.seg.pp-sync button:hover:not(:disabled) .rt { color: inherit; opacity: .75; }

/* 10/10 (« c'est ce qui fait la différence »): the welcome card the first time a player is ready (« Bienvenue, audiolaz
   Salon est prêt », « Écouter un essai », « Plus tard »), above the players; an orange line on its left, nothing louder. */
#welcome-card:not(:empty) { margin-bottom: 12px; }
.welcome-card { box-shadow: inset 4px 0 0 var(--orange); padding-left: 19px; }
.welcome-card .welcome-title { margin: 0; font-size: 19px; font-weight: 800; letter-spacing: -.02em; overflow-wrap: anywhere; }
.welcome-card .muted { margin: 6px 0 0; }
/* The AirPlay notice (an Apple TV starting through a player): small, at the top like the phone's own, gone after 9 s; a
   tap opens that player's screen. */
.notice {
  all: unset; box-sizing: border-box; cursor: pointer; position: fixed; left: 16px; right: 16px;
  top: calc(10px + env(safe-area-inset-top)); z-index: 11; max-width: 520px; margin: 0 auto;
  display: flex; flex-direction: column; gap: 2px; background: var(--ink); color: var(--paper); border-radius: var(--r);
  padding: 11px 14px; font-size: 14px; font-weight: 600; box-shadow: 0 6px 24px rgba(0, 0, 0, .18);
  animation: notice-in .25s ease-out;
}
.notice .k { color: var(--orange); font-size: 12px; font-weight: 700; overflow-wrap: anywhere; }
.notice .nm { overflow-wrap: anywhere; }
@keyframes notice-in { from { transform: translateY(-12px); opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .notice { animation: none; } }
/* 10/10 (« Montrer quelle entrée est active »): the player's inputs as chips in « Maintenant », the one playing in the
   olive (13/10: playing, as everywhere), the others muted; nothing playing: all muted and « À l'arrêt ». Informative only. */
.pp-inputs { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; margin: 0 0 10px; }
.pp-inputs > .k { font-size: 11px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--muted); margin-right: 2px; }
.pp-chips { display: contents; list-style: none; margin: 0; padding: 0; }
.pp-chip { display: inline-flex; align-items: center; min-height: 26px; padding: 3px 10px; border-radius: 13px; font-size: 13px; font-weight: 700;
  color: var(--muted); box-shadow: inset 0 0 0 1.5px var(--grid); overflow-wrap: anywhere; }
.pp-chip.on { background: var(--olive); color: var(--on); box-shadow: none; }   /* the input playing: the olive */
.pp-chips-off { font-size: 13px; font-weight: 600; color: var(--muted); }
/* « Détails »: its readouts, a name on the left, the value on the right. */
.pp-details { margin-top: 14px; }
.pp-dl li { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding: 9px 0; }
.pp-dl .pp-dv { font-weight: 700; font-variant-numeric: tabular-nums; text-align: right; overflow-wrap: anywhere; }
/* 10/10 (the simple app): the first launch's one sentence of how it works. */

/* « Maintenant »: the cover on the left, the title, the artist and the rate on the right; nothing when not known. */
.pp-track { display: flex; align-items: center; gap: 12px; margin: 0 0 12px; min-width: 0; }
.pp-cover { flex: 0 0 64px; width: 64px; height: 64px; border-radius: 4px; object-fit: cover; background: var(--tile-2); }
.pp-track-text { min-width: 0; }
.pp-track-text p { margin: 0; overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow-wrap: anywhere; }
.pp-title { font-size: 16px; font-weight: 800; letter-spacing: -.01em; }
.pp-artist { font-size: 14px; font-weight: 600; color: var(--muted); margin-top: 2px !important; }
.pp-rate { font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; margin-top: 4px !important; }
/* the home's playing card: the cover, small, before « En lecture · … » */

/* « Filtre : X — Changer › », « Sortie : Y — Changer › » under the sound keys */
.panel.pp-out { margin-top: 18px; }
.panel.pp-out + .panel.pp-out, .pp-list + .panel.pp-out { margin-top: 10px; }

/* 10/10 (« le filtre appartient à une sortie »): the system under the filter's name on the home's first card */

/* the player's systems: one card per output, the one it plays to lit */

/* 12/10 (mockup v2): « Mes filtres », the filters grouped by output, each a tile with its small curve; the home's link
   to them; the Apple TV block, only while one plays; the measurement's steps. */

.badge { display: inline-block; vertical-align: 2px; margin-left: 6px; padding: 1px 7px; border-radius: 10px; background: var(--orange-fill); color: var(--on); font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .5px; }

.panel.pp-atv { box-shadow: inset 0 0 0 2px var(--orange); margin-top: 12px; }
.panel.pp-atv > .k:first-child { color: var(--orange); margin-top: 0; }

#leave-row { margin-top: 12px; }
#lr li, #captures li { display: flex; align-items: center; gap: 10px; }
#lr .link, #captures .link { margin-left: auto; min-height: 36px; padding: 4px 0; }

/* 13/10 (the owner: « la page du lecteur … tient sur un écran d'iPhone »): its name once (the title), its keys on one
   line, its blocks closer */
#screen[data-screen="engine"] #eng-machine, #screen[data-screen="player-mac"] #eng-machine { display: none; }
#screen[data-screen="engine"] h1.title, #screen[data-screen="player-mac"] h1.title { font-size: 26px; margin: 4px 0 10px; }
.seg.keys.line { grid-template-columns: repeat(4, 1fr); }
.seg.keys.line button { min-height: 40px; font-size: 11px; padding: 6px 2px; }
#pp-main .pp-sound .k.home-k { margin-top: 12px; }

#pp-main .panel.pp-out { margin-top: 10px; padding-top: 4px; padding-bottom: 4px; }


/* ── 13/10, maquette 3: the app around the room ─────────────────────── */
/* (the screens' motion: « Mouvement » at the end of this file) */
.view { background: var(--paper); position: relative; z-index: 1; }

/* The header's right: the room's hardware (an orange dot while it plays), the settings. */
.top { margin-bottom: 18px; }
/* (13/10) The header: « ‹ Retour » on the left, the wordmark in the middle, the menu on the right, always there. */
.top { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); align-items: center; gap: 10px; position: relative; z-index: 5; }
.top-l { min-width: 0; justify-self: start; max-width: 100%; }
.top-r { min-width: 0; justify-self: end; display: flex; align-items: center; }
.top-l button.back-btn, .top-l button.back-btn:hover:not(:disabled) { display: block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: left; padding-right: 0; }
button.menu-btn, button.menu-btn:hover:not(:disabled) { border: 0; background: none; color: var(--ink); padding: 0; min-height: 44px; min-width: 44px; justify-content: flex-end; }
button.menu-btn svg { width: 24px; height: 24px; }
button.menu-btn[aria-expanded="true"] { color: var(--orange); }
/* The menu: a panel coming down under the header, on the right, the app's lines; the page shown in orange. */
.menu {
  position: absolute; top: calc(100% + 4px); right: 0; width: min(280px, 100%); padding: 6px 16px 8px;
  background: var(--paper); border-radius: var(--r); box-shadow: 0 0 0 1px var(--grid), 0 14px 34px rgba(0, 0, 0, .18);
  transform-origin: top right; animation: menu-in .18s ease-out;
}
.menu ul { list-style: none; margin: 0; padding: 0; }
.menu-room { display: block; padding: 12px 0 0; font-size: 13px; font-weight: 600; color: var(--muted); overflow-wrap: anywhere; }
.menu li + li, .menu ul + .menu-group, .menu-group + ul, .menu ul + ul { border-top: 1px solid var(--grid); }
button.menu-item, button.menu-item:hover:not(:disabled) {
  display: block; width: 100%; text-align: left; border: 0; background: none; color: var(--ink); padding: 12px 0; min-height: 46px;
  font-size: 15px; font-weight: 700; letter-spacing: 0; text-transform: none;
}
button.menu-item:hover:not(:disabled) { color: var(--orange); }
button.menu-item.on, button.menu-item.on:hover:not(:disabled) { color: var(--orange); }
button.menu-item.on::before { content: "● "; font-size: 10px; vertical-align: 2px; }
@keyframes menu-in { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .menu { animation: none; } }
.view .title { font-size: clamp(30px, 9vw, 38px); line-height: 1; margin: 0 0 6px; }
.view .lead { color: var(--muted); font-size: 15px; font-weight: 600; margin: 0 0 16px; max-width: none; }
.view .k:not(.home-k) { display: block; margin: 20px 0 8px; }
.center { text-align: center; }
p.center { margin-top: 10px; }

/* The board: ink, the room, its score, what plays (a button: its measurements, or the room). */
button.board.room-board, .board.room-board {
  display: block; width: 100%; text-align: left; text-transform: none; letter-spacing: normal; font: inherit; border: 0;
  min-height: 0; padding: 16px 18px 14px; border-radius: var(--r) var(--r) 0 0; cursor: pointer; color: var(--paper); background: var(--ink);
}
.board.room-board.solo, div.board.room-board { border-radius: var(--r); }
div.board.room-board { cursor: default; }
button.board.room-board:hover:not(:disabled) { background: var(--ink); color: var(--paper); }
.room-board .line { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
.room-board .line.main { margin-top: 8px; align-items: flex-end; }
.room-board .lab[hidden] { display: none; }
.room-board .name { font-size: clamp(26px, 8vw, 34px); font-weight: 800; letter-spacing: -.03em; line-height: 1; min-width: 0; overflow-wrap: anywhere; }
.room-board .name .chev { opacity: .5; font-weight: 700; margin-left: 6px; }
.room-board .big, .board.room-board > .big { display: flex; align-items: baseline; gap: 6px; font-size: clamp(36px, 11vw, 52px); font-weight: 800; letter-spacing: -.03em; line-height: .9; white-space: nowrap; font-variant-numeric: tabular-nums; margin: 0; }
.board.room-board > .big { margin-top: 8px; }
.room-board .big .before { opacity: .4; }
.room-board .big em { font-style: normal; font-size: .4em; font-weight: 700; color: var(--orange); margin: 0; }
.room-board .now { display: flex; align-items: center; gap: 10px; margin-top: 12px; padding-top: 10px; border-top: 1px solid color-mix(in srgb, var(--paper) 18%, transparent); font-size: 14px; font-weight: 600; min-width: 0; }
.room-board .now i { width: 7px; height: 7px; border-radius: 50%; background: var(--olive); flex: none; }   /* 13/10: playing = the green */
.room-board .now i.off { background: color-mix(in srgb, var(--paper) 45%, transparent); }
.room-board .now .cover { width: 34px; height: 34px; border-radius: 3px; flex: none; object-fit: cover; background: color-mix(in srgb, var(--paper) 15%, transparent); }
.room-board .now .t { min-width: 0; flex: 1; overflow: hidden; }
/* (18/10, the owner's iPhone: « on ne voit plus le nom ni l'artiste », the title cut to « F… » by the source, the rate and
   « Corrigé pour votre pièce » beside it) the title and artist keep the line after the cover; the rest goes under them */
.room-board .now { flex-wrap: wrap; row-gap: 6px; }
.room-board .now .t { flex: 1 1 calc(100% - 80px); }
.room-board .now .dim { opacity: .6; white-space: nowrap; }
/* (13/10) its cover there, the olive dot before the title all the same, as in « Mes pièces »'s lines: playing, in olive */
.room-board .now .cover + .t::before { content: ''; display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: var(--olive); margin-right: 8px; vertical-align: 1px; }

/* The curve under the board: the tile, its grid, its legend; its height kept while it is on its way. */
.panel.chart-panel { display: block; width: 100%; border: 0; text-align: left; font: inherit; text-transform: none; letter-spacing: normal; color: var(--ink); cursor: pointer; min-height: 0; }
button.panel.chart-panel:hover:not(:disabled) { background: var(--tile); color: var(--ink); }
.board.room-board + .panel.chart-panel { margin-top: 0; border-radius: 0 0 var(--r) var(--r); padding: 12px 12px 12px; }
.chart-panel .chart { min-height: 196px; }
.chart-panel .chart canvas { height: 170px; }
.chart-panel.empty { display: none; }
#home-chart-box .chart { min-height: 176px; }
.chart.mini { min-height: 0; }
.chart.mini canvas { height: 70px; }

/* « Son »: two by two (Neutre, Équilibré / Chaleureux, Sans correction), lit in orange. */
.grid.sounds button, #atv-keys button, #place button { min-height: 46px; }
.grid.sounds button.on, .grid.sounds button.on:hover, #atv-keys button.on, #atv-keys button.on:hover, #place button.on, #place button.on:hover { background: var(--orange-fill); border-color: var(--orange-fill); color: var(--on); }
.grid.sounds button.wait, .grid.sounds button.wait:hover { position: relative; overflow: hidden; border-color: var(--orange); background: none; color: var(--ink); }
.grid.sounds button.wait::after { content: ''; position: absolute; left: 6px; right: 6px; bottom: 5px; height: 3px; border-radius: 2px; background: var(--orange); transform-origin: left center; transform: scaleX(0); animation: key-wait 1.2s ease-in-out infinite; }
.grid.sounds button.wait.fill::after { animation: key-fill var(--fill-ms, 1500ms) linear forwards; }
/* (13/10, the owner) the sounds on one line across the whole width, « Sans correction » alone on the line under them
   (validated; brought back after « Le bon endroit » had put them two by two again) */
.grid.sounds { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }
.grid.sounds.n3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid.sounds.n5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.grid.sounds button { padding-inline: 2px; font-size: clamp(9.5px, 2.55vw, 13px); letter-spacing: 0; }
.grid.sounds button.off { grid-column: 1 / -1; }
@media (prefers-reduced-motion: reduce) { .grid.sounds button.wait::after { animation: none; transform: scaleX(.5); } }

/* Rows: a tile that says what is inside, › on the right. */
button.row { display: block; width: 100%; text-align: left; text-transform: none; letter-spacing: normal; font: inherit; border: 0; min-height: 0; padding: 14px 34px 14px 14px; border-radius: var(--r); background: var(--tile); color: var(--ink); cursor: pointer; margin-top: 10px; position: relative; }
button.row:hover:not(:disabled) { background: var(--tile-2); color: var(--ink); }
button.row .nm { display: block; font-weight: 700; font-size: 15px; }
button.row .rt { display: block; margin-top: 3px; font-size: 13px; color: var(--muted); font-weight: 600; }
button.row::after { content: '›'; position: absolute; right: 14px; top: 50%; transform: translateY(-55%); font-size: 22px; line-height: 1; color: var(--muted); }
button.wide { width: 100%; margin-top: 12px; }
#home-big + #home-rows button.row:first-child { margin-top: 10px; }

/* The first opening. */
.first { min-height: calc(100vh - 160px); display: flex; flex-direction: column; justify-content: flex-end; padding-bottom: 10px; }
.first-board { display: block; padding: 22px 20px; }
.first-board .name { font-size: clamp(34px, 10vw, 40px); font-weight: 800; letter-spacing: -.03em; line-height: 1.02; margin-top: 10px; }
.first .go { margin-top: 12px; }
#chains .tile, #where-names .tile { min-height: 118px; }
#where-names .tile { min-height: 86px; justify-content: flex-end; }
#where-field .field { margin-top: 8px; }

/* A room's measurements: its small curve on the grid, the one playing outlined in orange. */
button.meas { display: block; width: 100%; text-align: left; text-transform: none; letter-spacing: normal; font: inherit; border: 0; min-height: 0; background: var(--tile); color: var(--ink); border-radius: var(--r); padding: 12px 14px; margin-top: 10px; cursor: pointer; box-shadow: inset 0 0 0 2px transparent; transition: box-shadow .15s; }
button.meas:hover:not(:disabled) { background: var(--tile); color: var(--ink); }
button.meas.on { box-shadow: inset 0 0 0 2px var(--orange); }
button.meas.busy { box-shadow: inset 0 0 0 2px var(--orange); opacity: .7; }
button.meas .line { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; margin-bottom: 6px; }
button.meas b { font-size: 17px; font-weight: 800; letter-spacing: -.02em; }
button.meas .muted { display: block; margin-top: 6px; }
button.meas .line .muted { display: inline; margin: 0; }
button.meas .mini { display: block; min-height: 70px; }
.meas .badge, .badge { display: inline-block; font-size: 11px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--orange); background: none; padding: 0; margin: 0; }
.meas-detail { min-height: 32px; padding: 2px 0; font-size: 13px; }

/* A room's settings: key and value lines in a tile; each « › » opens its choice under it. */
.panel.kvs { padding-block: 4px; }
.kvs .kv { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; width: 100%; padding: 11px 0; border: 0; border-bottom: 1px solid var(--grid); border-radius: 0; background: none; color: var(--ink); font: 500 15px/1.35 "Archivo", system-ui, sans-serif; text-transform: none; letter-spacing: normal; min-height: 0; text-align: left; }
.kvs .kv:last-child, .kvs .kv-edit:last-child { border-bottom: 0; }
.kvs button.kv { cursor: pointer; }
.kvs button.kv:hover:not(:disabled) { background: none; color: var(--ink); }
.kvs button.kv:disabled { opacity: 1; cursor: default; }
.kvs .kv b { font-weight: 700; }
.kvs .kv span { color: var(--muted); font-weight: 600; text-align: right; overflow-wrap: anywhere; }
.kvs .kv-edit { padding: 10px 0 12px; border-bottom: 1px solid var(--grid); }
.kvs .kv-edit .seg + .seg { margin-top: 8px; }
.kvs .kv-edit input[type="text"] { background: var(--paper); }

/* The measurement's first screen: where you listen, how to place the microphone (folded). */
details.drawer.how { margin-top: 16px; }
details.drawer.how[open] > summary { margin-bottom: 10px; }
details.drawer.how .seg { margin-top: 12px; }
.room .floor { fill: var(--tile); }
.room .spk { fill: var(--ink); stroke: none; }
.room .lab { font: 700 10px "Archivo", sans-serif; letter-spacing: .14em; fill: var(--muted); text-anchor: middle; text-transform: uppercase; }
.room .seat { fill: var(--tile-2); stroke: none; }
.room .spot { fill: var(--paper); }

/* A confirmation with its way back (« Annuler »). */
.toast .toast-undo { display: inline-block; margin-left: 12px; min-height: 0; padding: 0; color: var(--orange); font-size: 14px; }
.toast .toast-undo:hover:not(:disabled) { color: var(--orange); }

#screen[data-screen="measure"] #ready, #meas-new { margin-top: 16px; }

/* « Le bon endroit »: the way the music goes (the sources, this computer + audiolaz, the DAC), what the app sees. */
.flow { display: grid; justify-items: center; gap: 4px; margin: 14px 0 14px; text-align: center; }
.flow-src { font-size: 12px; font-weight: 700; letter-spacing: .06em; color: var(--muted); }
.flow-arrow { color: var(--orange); font-weight: 800; line-height: 1; }
.flow-box { background: var(--ink); color: var(--paper); border-radius: var(--r); padding: 12px 16px; font-size: 15px; font-weight: 600; max-width: 100%; overflow-wrap: anywhere; }
.flow-box b { font-weight: 800; }
.flow-dac { font-size: 13px; font-weight: 700; padding: 8px 12px; border-radius: var(--r); background: var(--tile); }
.place-case { margin-top: 6px; }
.place-say { font-size: 17px; font-weight: 700; line-height: 1.35; margin: 0 0 12px; }
.place-ok { display: flex; gap: 10px; align-items: baseline; font-size: 17px; font-weight: 700; line-height: 1.35; margin: 0 0 12px; }
.place-ok i { font-style: normal; color: var(--orange); font-weight: 800; }
.place-case .grid button { min-height: 46px; }
.place-link { display: grid; justify-items: center; gap: 8px; margin: 6px 0 4px; }
.place-link .qr svg { width: 112px; height: 112px; display: block; border-radius: 6px; }
.place-link .muted { margin: 0; overflow-wrap: anywhere; }
#place-laptop, #place-windows { margin: 0 0 12px; }

/* Spacing helpers (13/10: no inline style in app.js, everything here for the identity pass) */
.gap-t { margin-top: 12px; }
.tight { margin: 0 0 10px; }
.k.k-gap { margin: 20px 0 8px; }
.w0 { width: 0; }
.boot-why { font-size: 12px; margin-top: 16px; }

/* (13/10) « Le bon endroit »: the three answers one under the other, the whole width */
.grid.one { grid-template-columns: 1fr; }

/* ── 13/10, maquette 4: the app's black and orange, less systematic ─────────────── */
/* (the owner: fewer small capitals, no more numbered tiles, one strong action per screen and the rest in lines of
   text; the app's type unchanged: every size and weight below is one the app already had) */
button.go.ink, .btn.go.ink, button.go.ink:hover:not(:disabled), .btn.go.ink:hover { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.view .k.soft { font-size: 15px; font-weight: 700; letter-spacing: 0; text-transform: none; color: var(--ink); margin: 24px 0 8px; }
.view .k.soft + .panel.hub { margin-top: 0; }   /* (13/10) its title as close as over the other panels */

/* The first opening: the board's curve going from bumpy (grey) to smoothed (orange), the title, its sentence, « Commencer ». */
.first { justify-content: space-between; }
.first-main { flex: 1; display: flex; flex-direction: column; justify-content: center; }
.board.first-board { display: block; padding: 16px 14px 10px; }
.board.first-board { padding: 14px 14px 12px; }
.demo-head { display: flex; justify-content: space-between; align-items: center; font-size: 12px; font-weight: 600; color: color-mix(in srgb, var(--paper) 60%, transparent); margin-bottom: 10px; }
.demo-key { display: flex; align-items: center; gap: 6px; }
.demo-key i { display: inline-block; width: 14px; height: 0; border-top: 2px solid; margin-left: 8px; }
.demo-key i.b { border-color: color-mix(in srgb, var(--paper) 55%, transparent); }
.demo-key i.a { border-color: var(--orange); border-top-width: 3px; }
.demo-plot { display: grid; grid-template-columns: 34px 1fr; gap: 6px; }
.demo-db { position: relative; height: 130px; }
.demo-db span { position: absolute; right: 0; transform: translateY(-50%); font-size: 10px; font-weight: 600; font-variant-numeric: tabular-nums; color: color-mix(in srgb, var(--paper) 45%, transparent); white-space: nowrap; }
.demo-db span:nth-child(1) { top: 14%; } .demo-db span:nth-child(2) { top: 32%; } .demo-db span:nth-child(3) { top: 50%; color: color-mix(in srgb, var(--paper) 75%, transparent); } .demo-db span:nth-child(4) { top: 68%; } .demo-db span:nth-child(5) { top: 86%; }
.demo-area { min-width: 0; }
.demo-hz { position: relative; height: 16px; margin-top: 6px; }
.demo-hz span { position: absolute; transform: translateX(-50%); font-size: 10px; font-weight: 600; font-variant-numeric: tabular-nums; color: color-mix(in srgb, var(--paper) 45%, transparent); white-space: nowrap; }
.demo-hz span:nth-child(1) { left: 0; transform: none; } .demo-hz span:nth-child(2) { left: 23.3%; } .demo-hz span:nth-child(3) { left: 56.63%; } .demo-hz span:nth-child(4) { left: 89.97%; transform: translateX(-70%); } .demo-hz span:nth-child(5) { right: 0; left: auto; transform: none; }
.demo-curve { display: block; width: 100%; height: 130px; border-left: 1px solid color-mix(in srgb, var(--paper) 22%, transparent); border-bottom: 1px solid color-mix(in srgb, var(--paper) 22%, transparent); }
.demo-curve .g line { stroke-width: 1; vector-effect: non-scaling-stroke; }
.demo-curve .g .mi { stroke: color-mix(in srgb, var(--paper) 7%, transparent); }
.demo-curve .g .ma { stroke: color-mix(in srgb, var(--paper) 16%, transparent); }
.demo-curve .g .zero { stroke: color-mix(in srgb, var(--paper) 30%, transparent); stroke-dasharray: 3 4; }
.demo-curve path { fill: none; vector-effect: non-scaling-stroke; }
.demo-curve .b { stroke: color-mix(in srgb, var(--paper) 50%, transparent); stroke-width: 1.8; animation: demo-b 4.5s ease-in-out infinite alternate; }
.demo-curve .a { stroke: var(--orange); stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; animation: demo-a 4.5s ease-in-out infinite alternate; }
@keyframes demo-b { 0%, 25% { opacity: 1; } 75%, 100% { opacity: .12; } }
@keyframes demo-a { 0%, 25% { opacity: 0; } 75%, 100% { opacity: 1; } }
.title.hero { margin: 22px 0 10px; }
.title.hero em { font-style: normal; color: var(--orange); }
@media (prefers-reduced-motion: reduce) { .demo-curve .b { animation: none; opacity: .12; } .demo-curve .a { animation: none; opacity: 1; } }

/* The beginner's start (13/10): « Votre chaîne » on its board; Avant and Après side by side. */
.board + .title { margin-top: 22px; }
.first .actions { margin-top: 18px; }
.grid.sounds.n2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* two keys: the app's own button type, not the four keys' narrower one */
.grid.sounds.n2 button { font-size: 13px; letter-spacing: .04em; }
.title.diff-title { margin-top: 20px; }
#diff-keys + .muted { margin: 8px 0 18px; }
.muted.err { color: var(--alert); }   /* (13/10) an error said in a line: the alert's colour, never the orange */
/* Lines to choose (« On corrige quoi ? », « Dans quelle pièce ? »): the one chosen in ink, its round orange. */
.picks { display: grid; gap: 8px; }
button.pick {
  display: flex; align-items: center; justify-content: space-between; gap: 12px; width: 100%; min-height: 0; padding: 16px;
  border: 0; border-radius: var(--r); background: var(--tile); color: var(--ink); font: inherit; text-align: left; text-transform: none; letter-spacing: normal;
}
button.pick:hover:not(:disabled) { background: var(--tile-2); color: var(--ink); }
button.pick.on, button.pick.on:hover:not(:disabled) { background: var(--ink); color: var(--paper); }
.pick .main { min-width: 0; }
.pick .nm { display: block; font-size: 17px; font-weight: 800; letter-spacing: -.02em; line-height: 1.15; overflow-wrap: anywhere; }
.pick .rt { display: block; margin-top: 3px; font-size: 13px; font-weight: 600; opacity: .6; overflow-wrap: anywhere; }
.pick .r { flex: none; width: 20px; height: 20px; border-radius: 50%; border: 2px solid currentColor; opacity: .5; }
.pick.on .r { border: 6px solid var(--orange); opacity: 1; }
#chains-go { margin-top: 18px; }
#chains-go + .muted { margin-top: 14px; }
#where-names { margin-top: 4px; }

/* Lines of text, › at their right (« Mes pièces », « Réglages », « Le bon endroit »): no more tiles. */
button.row { background: none; border-radius: 0; border-bottom: 1px solid var(--grid); padding: 14px 28px 14px 0; margin-top: 0; }
button.row:hover:not(:disabled) { background: none; color: var(--ink); }
button.row:hover:not(:disabled) .nm { color: var(--orange); }
button.row::after { right: 2px; }
button.row.plus { border-bottom: 0; font-weight: 700; margin-top: 6px; }
button.row.plus::after { content: none; }
.lines { margin-top: 4px; }
.lines + .note, .lines + .actions { margin-top: 10px; }

/* The room's board: its name, the hardware under it, the score at its right. */
.room-board .line.main { margin-top: 0; }
.room-board .who { display: flex; flex-direction: column; min-width: 0; }
.room-board .hw { font-size: 13px; font-weight: 600; letter-spacing: 0; opacity: .55; margin-top: 4px; overflow-wrap: anywhere; }
.room-board .now { margin-top: 14px; padding-top: 12px; }
#room-sound .grid.sounds { margin-top: 16px; }
/* « Mesurer à nouveau », then « Mesures (n) » and « Ma chaîne › » as two lines of text. */
.room-go { margin-top: 22px; }
.room-go .muted.center { margin: 8px 0 0; }
.text-links { display: flex; justify-content: space-between; align-items: center; gap: 12px; margin-top: 8px; }
.text-links button, .text-links button:hover:not(:disabled) {
  background: none; border: 0; padding: 6px 0; min-height: 44px; color: var(--ink); font-size: 15px; font-weight: 700;
  letter-spacing: 0; text-transform: none; gap: 6px;
}
.text-links button:hover:not(:disabled) { color: var(--orange); }
.text-links small { font-size: 13px; font-weight: 600; color: var(--muted); }

/* A room's measurements: a list with room to breathe, the score in large, « joue » after the olive dot, the small curve. */
#meas-list { margin-top: 4px; }
button.meas, button.meas:hover:not(:disabled) { background: none; border-radius: 0; box-shadow: none; padding: 14px 0 12px; margin-top: 0; border-bottom: 1px solid var(--grid); }
button.meas.on { box-shadow: none; }
button.meas.busy { box-shadow: none; opacity: .7; }
button.meas .line { align-items: baseline; margin-bottom: 2px; }
button.meas .sc { font-size: 22px; font-weight: 800; letter-spacing: -.02em; line-height: 1; font-variant-numeric: tabular-nums; }
button.meas > .muted { display: block; margin-top: 0; }
.meas .badge { font-size: inherit; font-weight: 700; letter-spacing: 0; text-transform: none; color: var(--olive); }
.meas .badge::before { content: ''; display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: var(--olive); margin-right: 6px; vertical-align: 1px; }   /* the board's dot */
button.meas .mini { margin-top: 8px; min-height: 56px; }
.chart.mini canvas { height: 56px; }
#meas-new { margin-top: 18px; }
button.row + .note, button.row + #st-lang-box + .note { margin-top: 22px; }
/* « Votre chaîne »: its small label over the name, as on the 1.2.7's boards */
#begin-chain .line.main { margin-top: 8px; }
.first .actions .muted.center { margin: 0 0 4px; }

/* 13/10 (the owner): « Mes pièces », a room playing: the green dot, its cover, its title and its source, under its name */
.row .row-now { display: flex; align-items: center; gap: 8px; margin-top: 8px; font-size: 13px; font-weight: 600; min-width: 0; }
.row .row-now i { width: 7px; height: 7px; border-radius: 50%; background: var(--olive); flex: none; }
.row .row-now i.off { background: var(--grid); }
.row .row-now .cover { width: 28px; height: 28px; border-radius: 3px; flex: none; object-fit: cover; background: var(--tile-2); }
.row .row-now .cover + .t::before { content: none; }
.row .row-now .t { min-width: 0; flex: 1; overflow: hidden; }
.row .row-now .dim { color: var(--muted); white-space: nowrap; }

/* 13/10 (the owner): the room's « Mesures » and « Ma chaîne » as its two keys, « Mesurer à nouveau » a quiet line under */
.room-keys { margin-top: 14px; }
.room-keys button { min-height: 58px; border: 0; background: var(--tile); color: var(--ink); text-transform: none; letter-spacing: -.01em; font-size: 16px; font-weight: 700; justify-content: space-between; padding: 0 16px; }
.room-keys button:hover:not(:disabled) { background: var(--tile-2); color: var(--ink); }   /* (13/10, the owner) not the sound keys' look: tiles, not outlined capitals */
.room-keys button.wide { grid-column: 1 / -1; }
.room-keys small { margin-left: 6px; color: var(--muted); font-size: 13px; font-weight: 700; }
.room-keys small.chev { font-size: 20px; font-weight: 600; line-height: 1; }   /* (13/10) at the right of its key, as « Mesures »'s number: the two keys alike */
button.link.center-link { display: block; margin: 16px auto 0; background: none; border: 0; min-height: 0; padding: 6px; text-transform: none; letter-spacing: 0; font-size: 15px; font-weight: 700; color: var(--muted); text-decoration: underline; text-underline-offset: 3px; }

/* 13/10 (the owner): the artist smaller than the title, wherever what plays is said */
.now .t small.ar, .row-now .t small.ar { font-size: .82em; font-weight: 500; opacity: .7; }
/* (15/10) title and artist each on their own lines, two at most, never cut short at one */
.now .t .ti, .row-now .t .ti, .now .t small.ar, .row-now .t small.ar { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; overflow-wrap: anywhere; line-height: 1.25; }
.now .t .ti, .row-now .t .ti { font-weight: inherit; }
.row .row-now .cover { width: 40px; height: 40px; }

/* 13/10: a source with its own app (Roon, Spotify): touched, that app opens */
.src.open-app { cursor: pointer; text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }

/* 13/10 (the owner): « Mes pièces », the other rooms as small cards: name and score, state, their curve */
.row.room-card { display: block; text-align: left; padding: 14px 14px 10px; }
.room-card .rc-head { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
.room-card .nm { font-size: 19px; font-weight: 800; letter-spacing: -.02em; }
.room-card .rc-score { font-size: 22px; font-weight: 800; letter-spacing: -.03em; font-variant-numeric: tabular-nums; }
.room-card .rt { display: block; margin-top: 2px; }
.room-card .rc-curve { display: block; margin-top: 8px; pointer-events: none; }

/* 13/10 (the owner): « Mes pièces » as an accordion: the open room unfolds in place, the others are lines */
#home-list .row { margin-top: 10px; }
#home-list .home-open { margin-top: 10px; }
#home-list .home-open:first-child { margin-top: 0; }
/* 18/10 (the owner: « supprimer une pièce ») a room not seen for a week: « Supprimer cette pièce » small under its line */
#home-list .row-away { text-align: right; }
#home-list .row-away button.link.center-link { display: inline-block; margin: 2px 0 0; font-size: 13px; font-weight: 600; }
#home-list .row-away .note { margin-top: 8px; text-align: left; }
#rs-away { margin-top: 24px; }
#rs-remove { margin-top: 8px; }
#rs-remove .note { margin-top: 16px; }

/* 13/10 « Ma chaîne »: the expert's lines in the type of the lines above them (15 px, 700), one list, not two sizes */
#rs-body .panel.hub .rows .main .nm { font-size: 15px; font-weight: 700; letter-spacing: 0; }

/* 14/10 (the owner): « Mes pièces » and a room's page told apart at a glance: the room's page titled by its name, its
   board then without the name again (the score, the hardware, what plays); « Mes pièces » keeps its own title */
.room-title { margin-bottom: 14px; }
#screen[data-screen="room"] .room-board .name, .screen-room .room-board .name { display: none; }

/* ── « Votre place » (15/10, the owner: « Recentre est une fonction majeure, reléguée en bas de page ») ──
   The room's page, under what plays: the board then this block (the board's corners all round again), the state in
   large beside a small plan (two speakers, the measuring seat's ring, you: the orange dot on your side, beating while
   followed or listening), « Recentrer sur moi » (the page's strong key once the room is measured: the orange with its
   target; a room not measured yet keeps « Mesurer cette pièce » orange, this one in ink), the places as chips, « Suivre
   ma position » as a switch (olive: it works), « Revenir à ma place de mesure » as a line. */
#screen[data-screen="room"] .board.room-board { border-radius: var(--r); }
#screen[data-screen="room"] .panel.chart-panel { margin-top: 10px; border-radius: var(--r); }
#room-place-box:empty, #room-busy:empty { display: none; }
#room-busy .note, #room-place-box .place { margin-top: 10px; }
.place { padding: 10px 12px 12px; }
/* (15/10 night, the owner: « le logo est bof, le texte pas forcément nécessaire ») one row under a small title: the key,
   then the chips; the lit chip says the state (ink, the orange dot); a line only while it measures and just after */
.place-top { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; margin: -4px 0 6px; }
.place-top .k { color: var(--muted); line-height: 1; }
button.link.place-more, button.link.place-more:hover:not(:disabled) { min-height: 32px; padding: 4px 0; font-size: 13px; text-decoration: none; color: var(--muted); }
button.link.place-more:hover:not(:disabled) { color: var(--ink); }
.place-sub { margin: 8px 0 0; font-size: 12px; font-weight: 600; line-height: 1.35; color: var(--muted); animation: place-said .3s ease-out; }
@keyframes place-said { from { opacity: 0; } }
.place-sub.warn { color: var(--ink); }
.place-sub.warn::before { content: "▲ "; color: var(--orange); font-size: 9px; vertical-align: 1px; }
.place-bar { height: 3px; margin: 10px 0 2px; border-radius: 2px; background: var(--tile-2); overflow: hidden; }
.place-bar > div { height: 100%; width: 0; background: var(--orange); transition: width .6s linear; }
.place-acts { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
button.place-go { gap: 8px; }
#room-place button.place-go { min-height: 40px; padding: 8px 13px; font-size: 12px; }
button.place-go svg { width: 16px; height: 16px; flex: none; }
.place .chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chips button.chip { min-height: 32px; padding: 5px 12px; border-radius: 999px; border-width: 1.5px; border-color: color-mix(in srgb, var(--ink) 28%, transparent); font-size: 12px; font-weight: 700; letter-spacing: 0; text-transform: none; color: var(--ink); }
.chips button.chip:hover:not(:disabled) { background: var(--tile-2); color: var(--ink); }
.chips button.chip.on, .chips button.chip.on:hover:not(:disabled) { background: var(--ink); border-color: var(--ink); color: var(--paper); cursor: default; }
.chips button.chip.on::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--orange); margin-right: 2px; }
/* « Suivre ma position » (the expert's): a small line with its switch */
button.switch-row, button.switch-row:hover:not(:disabled) {
  display: flex; align-items: center; gap: 10px; min-height: 40px; padding: 0; border: 0; border-radius: 0; background: none;
  color: var(--ink); text-align: left; text-transform: none; letter-spacing: 0; font: inherit;
}
#room-place button.switch-row { margin-left: auto; }
.rc-panel button.switch-row { width: 100%; }
.switch-row .main { flex: 1; min-width: 0; }
.switch-row .nm { display: block; font-weight: 700; font-size: 13px; }
.rc-panel .switch-row .nm { font-weight: 800; font-size: 15px; letter-spacing: -.01em; }
.switch-row .rt { display: block; margin-top: 2px; font-size: 12px; font-weight: 600; color: var(--muted); line-height: 1.35; }
.switch { position: relative; width: 40px; height: 24px; flex: none; border-radius: 999px; background: var(--tile-2); box-shadow: inset 0 0 0 1.5px var(--grid); transition: background .18s; }
.switch::after { content: ""; position: absolute; top: 3px; left: 3px; width: 18px; height: 18px; border-radius: 50%; background: var(--muted); transition: transform .18s, background .18s; }
.switch-row[aria-checked="true"] .switch { background: var(--olive); box-shadow: none; }
.switch-row[aria-checked="true"] .switch::after { transform: translateX(16px); background: var(--on); }
@media (prefers-reduced-motion: reduce) { .place-sub { animation: none; } .switch, .switch::after { transition: none; } }

/* Recentre's details (15/10): the state or the reading in large, the plan, « Ce qui est appliqué », the places */
.board.rc-hero { display: block; }
.rc-hero .rc-fig { margin: 8px 0 0; font-size: 13px; font-weight: 600; opacity: .7; }
#screen[data-screen="recentre"] .rc-plan { max-width: 260px; margin: 18px auto 6px; }
.rc-plan figcaption.rc-approx { text-align: center; font-size: 12px; margin-top: 2px; }
.rc-panel { margin-top: 14px; }
.view .rc-panel > .k.soft { display: block; margin: 0 0 8px; }
.rc-rows li { padding: 10px 0; }
.rc-rows .rt.on { color: var(--ink); }
.rc-seat .rc-seat-acts { display: flex; flex-wrap: wrap; gap: 0 16px; margin-top: 2px; }
.rc-seat .rc-seat-acts button.link { min-height: 36px; padding: 4px 0; font-size: 13px; }
.rc-seat.sel .nm { color: var(--orange); }
.rc-xp { margin-top: 10px; }
.rc-hero .rc-said:first-child { margin-top: 0; }
.muted.ok { color: var(--olive); }
/* (15/10) what the DAC plays, after the source */
.now .dim.rate, .row-now .dim.rate { color: var(--muted); white-space: nowrap; font-variant-numeric: tabular-nums; }

/* (18/10, the owner) « Bit-perfect, vérifié » in the green of « it works »; changed on the way: said, muted, never an alert */
.bp { color: var(--muted); white-space: nowrap; font-size: .85em; letter-spacing: .01em; }
.bp.ok { color: var(--olive); }
.bp.ok::before { content: ""; display: inline-block; width: .45em; height: .45em; margin-right: .35em; border-radius: 50%; background: currentColor; vertical-align: .12em; }
.sound-path { margin: 6px 0 0; color: var(--muted); font-size: .9em; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.sound-path.ok { color: var(--ink); }
.pp-bp { margin: 4px 0 0; }
/* (15/10, the owner: « la même que sur Roon mais en vert ») playing: three bars, in the green */
.now .eq, .row-now .eq { display: inline-flex; align-items: flex-end; gap: 2px; width: 13px; height: 12px; flex: none; }
.now .eq b, .row-now .eq b { display: block; width: 3px; height: 100%; background: var(--olive); border-radius: 1px; transform-origin: bottom; animation: az-eq 1.1s ease-in-out infinite; }
.now .eq b:nth-child(2), .row-now .eq b:nth-child(2) { animation-duration: .8s; animation-delay: -.3s; }
.now .eq b:nth-child(3), .row-now .eq b:nth-child(3) { animation-duration: 1.3s; animation-delay: -.6s; }
@keyframes az-eq { 0%, 100% { transform: scaleY(.25); } 50% { transform: scaleY(1); } }
@media (prefers-reduced-motion: reduce) { .now .eq b, .row-now .eq b { animation: none; transform: scaleY(.6); } }

/* (15/10, the owner: « comme avant ») the room's board: « titre · artiste » on one line */
.room-board .now .t { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.room-board .now .t small.ar { display: inline; }
/* (15/10, the owner: « adapte un peu la zone, c'est un peu le bazar ») « Votre place »: the main button on its own full
   line, the places under it on one line (scrolled when many), « Sans correction de place » last, set apart */
#room-place .place-acts { display: block; min-width: 0; }
#room-place .place-acts > .chips { margin-top: 10px; width: 100%; min-width: 0; }
#room-place button.place-go { width: 100%; justify-content: center; min-height: 44px; font-size: 13px; }
#room-place .chips { flex-wrap: wrap; }   /* (15/10) every place seen, « Sans correction de place » too: never scrolled off */
#room-place .chips::-webkit-scrollbar { display: none; }
#room-place .chips button.chip { flex: 0 1 auto; max-width: 100%; white-space: normal; text-align: left; }
#room-place .chips button#room-place-off { border-style: dashed; }
#room-place .chips button#room-place-off.on { border-style: solid; }
/* (15/10, « de A à Z ») « Votre place »: what plays in one line, the button, the places as one chosen list */
#room-place .place-now { margin: 0 0 10px; font-size: 15px; font-weight: 700; line-height: 1.3; }
#room-place .place-rows { margin: 10px 0 0; }
#room-place .place-rows .row-link { min-height: 44px; }
#room-place .place-keep { margin-top: 4px; }
/* (15/10, « mieux dessinée ») « Votre place »: the place chosen in large, the button, the places as one list */
#room-place .place-name { margin: 2px 0 12px; font-size: 22px; font-weight: 800; letter-spacing: -.01em; line-height: 1.15; }
#room-place .place-list { list-style: none; margin: 14px 0 0; padding: 0; border-top: 1px solid color-mix(in srgb, var(--ink) 14%, transparent); }
#room-place .place-list li { border-bottom: 1px solid color-mix(in srgb, var(--ink) 14%, transparent); }
#room-place button.place-item { display: grid; grid-template-columns: 18px 1fr auto; align-items: center; gap: 12px; width: 100%; min-height: 48px; padding: 8px 2px; background: none; border: 0; border-radius: 0; color: var(--ink); text-align: left; text-transform: none; letter-spacing: 0; font-size: 15px; font-weight: 600; cursor: pointer; }
#room-place button.place-item:hover:not(:disabled) { background: color-mix(in srgb, var(--ink) 5%, transparent); }
#room-place button.place-item .dot { width: 16px; height: 16px; border-radius: 50%; border: 2px solid color-mix(in srgb, var(--ink) 40%, transparent); box-sizing: border-box; }
#room-place button.place-item.on .dot { border-color: var(--orange); background: radial-gradient(circle, var(--orange) 0 4px, transparent 4.5px); }
#room-place button.place-item.on .nm { font-weight: 800; }
#room-place button.place-item .dt { font-size: 12px; font-weight: 600; color: var(--muted); text-align: right; font-variant-numeric: tabular-nums; }
#room-place button.place-item.on { cursor: default; }
/* (15/10, « beaucoup trop d'espace ») « Votre place » in one line: the place and what it sets, « Recentrer » beside it;
   the places folded under « Changer de place » */
#room-place .place-head { display: flex; align-items: center; gap: 10px; }
#room-place .place-cur { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
#room-place .place-cur .nm { font-size: 16px; font-weight: 800; line-height: 1.2; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#room-place .place-cur .dt { font-size: 12px; font-weight: 600; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#room-place .place-head button.place-go { width: auto; flex: none; min-height: 36px; padding: 6px 12px; font-size: 12px; }
#room-place button.place-toggle, #room-place button.place-toggle:hover:not(:disabled) { display: block; min-height: 28px; margin-top: 6px; padding: 2px 0; font-size: 12px; text-decoration: none; color: var(--muted); }
#room-place .place-list { margin-top: 6px; }
#room-place button.place-item { min-height: 40px; padding: 6px 2px; font-size: 14px; }

/* (18/10, audit) audiolaz not answering over the rooms kept on this device: the band first, its « Rechercher à nouveau » */
.note.offline-band { margin-bottom: 16px; }
.note.offline-band button.link { display: flex; margin-top: 4px; color: var(--ink); }
/* (18/10, audit) « Mes pièces »: each line's correction on the right of its name (« 80 → 93 », « Pas encore mesurée ») */
button.row .row-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
button.row .row-name { min-width: 0; overflow-wrap: anywhere; }
button.row .row-corr { flex: none; font-size: 14px; font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
button.row .row-corr .before { opacity: .65; }
button.row .row-corr em { font-style: normal; margin: 0 4px; color: var(--muted); }
button.row .row-corr.none { font-size: 13px; font-weight: 600; color: var(--muted); }
/* (18/10, audit: « Hold the sound backBring the sound forward ») « Synchro image »: the slider over the whole width, its two
   ends named under it, one each side */
.pp-sync input[type="range"] { width: 100%; }
.pp-sync-ends { display: flex; justify-content: space-between; gap: 16px; margin-top: 4px; font-size: 12px; font-weight: 600; color: var(--muted); }
.pp-sync-ends span:last-child { text-align: right; }

/* (18/10, audit) every link and key cited at 44 px at least to the finger, their look unchanged (the height taken in
   their padding, the space around them kept by negative margins where they sit in a line) */
button.logo, button.logo:hover, button.logo:hover:not(:disabled) { min-height: 44px; display: inline-flex; align-items: center; }
button.link.center-link { min-height: 44px; }
button.link.place-more, button.link.place-more:hover:not(:disabled) { min-height: 44px; margin: -6px 0; }
#room-place .place-head button.place-go { min-height: 44px; }
#room-place button.place-toggle, #room-place button.place-toggle:hover:not(:disabled) { min-height: 44px; margin-top: 0; margin-bottom: -8px; }
#room-place button.place-item { min-height: 44px; }
.note .gap-tools .link, .note#previous .link, .rc-seat .rc-seat-acts button.link { min-height: 44px; }
.handoff details > summary { min-height: 44px; padding-top: 14px; }
#home-list .row-away button.link.center-link { min-height: 44px; }
button.link.licence-line { min-height: 44px; margin-top: 8px; font-size: 13px; font-weight: 600; text-decoration: none; }
#wrong-mic button.link, #room-unnamed button.link { display: flex; }
/* (18/10, audit) a measurement and its « Modifier la correction » in one card: the line under both */
.meas-card { border-bottom: 1px solid var(--grid); }
.meas-card button.meas, .meas-card button.meas:hover:not(:disabled) { border-bottom: 0; padding-bottom: 4px; }
.meas-card .meas-detail { min-height: 44px; padding: 0 0 6px; }

/* ── Mouvement (18/10) ───────────────────────────────────────────────────────────────────────────────────────────────
   Utile, calme, jamais gadget : un mouvement dit d'où vient ce qui arrive et où va ce qui part, rien d'autre.
   Seulement transform et opacity (le compositeur : 60 i/s sur un téléphone moyen). Tout est en jetons, et app.js lit les
   mêmes (Motion, Web Animations) : une durée se change ici, une seule fois. Mouvement réduit (le réglage du système) :
   les distances à zéro, les durées courtes, plus de ressort : il ne reste que des fondus. À coller à la fin de
   public/style.css (il remplace le bloc « Screens slide » de la maquette 3 : .view.from-right… et leurs @keyframes). */
:root {
  --dur-press: 90ms;      /* le doigt se pose : la touche s'enfonce */
  --dur-release: 240ms;   /* le doigt se lève : elle revient, un léger ressort */
  --dur-quick: 160ms;     /* menu, états, détails, tout ce qui s'en va */
  --dur-nav: 300ms;       /* un écran qui arrive */
  --dur-shared: 440ms;    /* un élément qui devient l'écran suivant (la carte d'une pièce, son nom) */
  --dur-sheet: 400ms;     /* une feuille qui monte */
  --dur-count: 700ms;     /* un chiffre qui va à sa valeur */
  --dur-theme: 360ms;     /* clair ↔ sombre */
  --stagger: 24ms;        /* l'écart entre deux lignes d'une liste qui apparaît */
  --nav-dx: 40px;         /* la glisse d'un écran : assez pour dire le sens, pas plus */
  --rise: 8px;            /* une ligne qui apparaît monte de si peu */
  --press: .97;           /* une touche enfoncée */
  --press-lg: .985;       /* une grande surface enfoncée (la carte, la courbe) */
  --ease-out: cubic-bezier(.2, .8, .2, 1);       /* la courbe de la maison (13/10) : arrive vite, se pose doucement */
  --ease-in: cubic-bezier(.4, 0, 1, 1);          /* ce qui s'en va */
  --ease-move: cubic-bezier(.3, 0, 0, 1);        /* ce qui va d'un endroit à un autre (élément partagé, listes) */
  --ease-spring: cubic-bezier(.3, 1.3, .5, 1);   /* un ressort court (repli des navigateurs sans linear()) */
}
/* le même ressort, vrai (amortissement 0,78 : 2 % au-delà, puis posé) ; linear() n'existe qu'à partir de Safari 17.2 :
   avant, le jeton garde le cubic-bezier ci-dessus, et une animation JS qui le refuserait repart en ease-out (Motion.anim) */
@supports (transition-timing-function: linear(0, 1)) {
  :root { --ease-spring: linear(0, 0.039 4%, 0.134 8%, 0.256 12%, 0.387 16%, 0.512 20%, 0.653 25%, 0.767 30%, 0.856 35%, 0.92 40%, 0.965 45%, 0.993 50%, 1.009 55%, 1.017 60%, 1.02 68%, 1.016 76%, 1.01 86%, 1); }
}
@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-release: 0ms; --dur-nav: 160ms; --dur-shared: 160ms; --dur-sheet: 160ms; --dur-count: 0ms; --stagger: 0ms;
    --nav-dx: 0px; --rise: 0px; --press: 1; --press-lg: 1; --ease-spring: ease-out; --ease-move: ease-out;
  }
}

/* Les écrans (Motion.swap) : celui qui part reste à sa place, sous l'autre, sans fond (ils se croisent en fondu), jamais
   sur le chemin d'un doigt ; le titre du nouveau reçoit le focus (lu par VoiceOver) sans cadre. */
.view { background: none; }
.view.leaving { position: absolute; left: 0; right: 0; z-index: 0; pointer-events: none; }
.view .shared-gone { opacity: 0 !important; }
.view .flying { position: relative; z-index: 3; }   /* un nom qui devient un titre passe au-dessus des cartes */
.screen [tabindex="-1"]:focus { outline: none; }

/* Le toucher : la touche s'enfonce tout de suite (90 ms), revient avec un petit ressort ; les grandes surfaces à peine ;
   les lignes de texte pâlissent, leur › avance d'un pas (on va par là). Rien n'attend l'animation : le clic part au
   relâcher, comme avant. (iOS : :active n'existe qu'avec un écouteur touchstart, posé au démarrage d'app.js.) */
button, .btn {
  transition: background-color var(--dur-quick), color var(--dur-quick), border-color var(--dur-quick), box-shadow var(--dur-quick), opacity var(--dur-quick), transform var(--dur-release) var(--ease-spring);
}
button:active:not(:disabled), .btn:active { transform: scale(var(--press)); transition-duration: var(--dur-press); transition-timing-function: var(--ease-out); }
button.board:active:not(:disabled), button.panel:active:not(:disabled), button.pick:active:not(:disabled), button.meas:active:not(:disabled), button.tile:active:not(:disabled) { transform: scale(var(--press-lg)); }
button.row:active:not(:disabled), button.menu-item:active:not(:disabled), button.back-btn:active:not(:disabled), button.link:active:not(:disabled),
.text-links button:active:not(:disabled), .kvs button.kv:active:not(:disabled), button.logo:active, #room-place button.place-item:active:not(:disabled),
.rows button.row-link:active:not(:disabled), button.switch-row:active:not(:disabled) { transform: none; opacity: .55; }
button.row::after { transition: transform var(--dur-release) var(--ease-spring); }
button.row:active:not(:disabled)::after { transform: translate(3px, -55%); transition-duration: var(--dur-press); }
@media (hover: hover) { button.row:hover:not(:disabled)::after { transform: translate(2px, -55%); } }

/* Le menu : il descend de son bouton (un rien d'échelle, le coin en haut à droite), remonte plus vite ; les trois traits
   deviennent la croix qui le ferme. */
.menu { transform-origin: top right; animation: menu-in var(--dur-quick) var(--ease-out); }
.menu.closing { animation: menu-out calc(var(--dur-quick) * .8) var(--ease-in) forwards; pointer-events: none; }
@keyframes menu-in { from { opacity: 0; transform: translateY(calc(var(--rise) * -.75)) scale(.98); } }
@keyframes menu-out { to { opacity: 0; transform: translateY(calc(var(--rise) * -.5)) scale(.98); } }
button.menu-btn svg path { transform-box: fill-box; transform-origin: center; transition: transform var(--dur-nav) var(--ease-out), opacity var(--dur-quick); }
button.menu-btn[aria-expanded="true"] .m1 { transform: translateY(9px) rotate(45deg); }
button.menu-btn[aria-expanded="true"] .m2 { opacity: 0; transform: scaleX(.3); }
button.menu-btn[aria-expanded="true"] .m3 { transform: translateY(-9px) rotate(-45deg); }

/* « Mes pièces », la pièce qui s'ouvre en place (les autres lignes glissent, Motion.flip) : elle se pose, sans s'écraser */
.home-open.unfold { animation: rise-in var(--dur-nav) var(--ease-out); }
@keyframes rise-in { from { opacity: 0; transform: translateY(var(--rise)); } }
@keyframes fade-in { from { opacity: 0; } }

/* Les barres (mesure, Recentre, mise à jour, niveau du micro) : en transform, plus en largeur (app.js : Motion.bar) */
.board .bar > div, .place-bar > div, .meter > div { width: 100%; transform-origin: left center; transform: scaleX(0); transition: transform .25s linear; }
.meter > div { transition-duration: 80ms; }
.place-bar > div { transition-duration: .6s; }

/* La mesure : le tableau monte quand il prend la place du plan ; le point mesuré se pose (un ressort), le suivant bat. */
.board.live:not(.hidden) { animation: rise-in var(--dur-nav) var(--ease-out); }
.room .spot { transform-box: fill-box; transform-origin: center; }
.room .spot.just { animation: spot-in var(--dur-sheet) var(--ease-spring); }
@keyframes spot-in { from { transform: scale(.35); } }
.board.live.success .big { animation: fade-in var(--dur-quick) var(--ease-out); }

/* Une attente : rien les 120 premières ms (pas d'éclair pour ce qui vient vite), puis des lignes qui respirent, calmes ;
   ce qui les remplace arrive en fondu. */
.skel { display: block; height: 12px; margin: 9px 0; border-radius: 3px; background: var(--tile-2); animation: fade-in var(--dur-quick) 120ms backwards, skel-breathe 1.4s 300ms ease-in-out infinite alternate; }
.skel.w60 { width: 60%; } .skel.w40 { width: 40%; } .skel.w80 { width: 80%; } .skel.big { height: 26px; width: 45%; }
.kvs .skel-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 43px; border-bottom: 1px solid var(--grid); }   /* la hauteur d'une ligne .kv : rien ne saute quand elle arrive */
.kvs .skel-row .skel { margin: 0; }
.kvs .skel-row:last-child { border-bottom: 0; }
@keyframes skel-breathe { to { opacity: .45; } }
.fill-in { animation: fade-in var(--dur-nav) var(--ease-out); }
/* ce que l'attente dit à VoiceOver (« Lecture… »), sans le montrer : les lignes qui respirent le disent à l'œil */
.sr { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* Un message : il monte avec un ressort court, s'en va plus vite qu'il n'est venu (Motion.toastOut). */
.toast { animation: toast-in var(--dur-sheet) var(--ease-spring); }
.toast.out { animation: toast-out var(--dur-quick) var(--ease-in) forwards; pointer-events: none; }
@keyframes toast-in { from { opacity: 0; transform: translateY(calc(var(--rise) * 2)); } }
@keyframes toast-out { to { opacity: 0; transform: translateY(var(--rise)); } }

/* Une feuille (Motion.sheet, un <dialog> modal : le reste de la page inerte, Échap la ferme) : du bas sur un téléphone,
   au centre sur un ordinateur ; le voile en fondu ; tirée vers le bas par sa poignée, elle s'en va. */
/* (top/right/bottom/left plutôt qu'inset : Safari 14.0 ; z-index : sans showModal, avant iOS 15.4, la feuille n'est pas
   dans la couche du dessus et doit passer sur .view, z-index 1, et sur le message, 10) */
dialog.sheet { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 20; width: 100%; height: 100%; max-width: none; max-height: none; margin: 0; padding: 0; border: 0; background: none; color: var(--ink); overflow: hidden; }
dialog.sheet[open] { display: flex; align-items: flex-end; justify-content: center; }
dialog.sheet::backdrop { background: none; }
.sheet-scrim { position: absolute; top: 0; right: 0; bottom: 0; left: 0; background: rgba(10, 9, 6, .38); }
.sheet-card {
  position: relative; width: 100%; max-width: 680px; background: var(--paper); border-radius: 14px 14px 0 0;
  /* 24 px de plus sous le bord : le ressort monte un rien plus haut que sa place, jamais de jour dessous */
  margin-bottom: -24px; padding: 8px 20px calc(44px + env(safe-area-inset-bottom)); box-shadow: 0 -12px 40px rgba(0, 0, 0, .16), 0 0 0 1px var(--grid);
}
.sheet-grip { display: block; height: 26px; margin: -8px -20px 6px; cursor: grab; touch-action: none; position: relative; }
.sheet-grip::after { content: ""; position: absolute; left: 50%; top: 11px; width: 36px; height: 4px; margin-left: -18px; border-radius: 2px; background: var(--tile-2); }
.sheet-card .title { font-size: clamp(24px, 7vw, 30px); margin: 4px 0 8px; }
.sheet-card .lead { color: var(--muted); font-size: 15px; font-weight: 600; margin: 0 0 16px; }
.sheet-card .actions { margin-top: 10px; }
button.go.danger, button.go.danger:hover:not(:disabled) { background: var(--alert); border-color: var(--alert); color: var(--on); }   /* --on : blanc sur le rouge clair, l’encre sur celui du sombre (4,5:1) */
@media (min-width: 640px) {
  dialog.sheet[open] { align-items: center; }
  .sheet-card { width: min(440px, calc(100% - 40px)); margin: 0; border-radius: 10px; padding: 22px 24px 20px; }
  .sheet-grip { display: none; }
}

/* Clair ↔ sombre : quand le système bascule (le soir), les couleurs glissent au lieu de sauter (Motion.watchTheme). */
:root.theme-shift, :root.theme-shift * { transition: background-color var(--dur-theme) ease, color var(--dur-theme) ease, border-color var(--dur-theme) ease, fill var(--dur-theme) ease, stroke var(--dur-theme) ease !important; }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: var(--dur-theme); }

/* Mouvement réduit : ce qui bouge sans fin s'arrête (en plus des règles déjà là : .eq, .pulse, .tick.now, .demo-curve) */
@media (prefers-reduced-motion: reduce) {
  .skel { animation: fade-in var(--dur-quick) 120ms backwards; }
  .waiting i { animation: none; }
  .room .spot.just { animation: none; }
  button.menu-btn svg path { transition: opacity var(--dur-quick); }   /* la croix est là, sans tourner */
}
