/* Régie — deliberately plain. This is a tool, not a brochure: the site itself
   carries the design language, and an admin that imitates it invites the client
   to confuse "what I see here" with "what is published".

   One visual decision does carry weight: provenance is rendered as prominently
   as the value it explains. If the source is a footnote, nobody reads it, and
   the whole point of the sidecar is lost. */

:root {
  --ink: #16181d;
  --ink-2: #4a5058;
  /* Was #767d87 = 4.16:1 on the card and 3.88:1 on the page background, so
     every 13.6px line using it (field hints, provenance, asset metadata) failed
     WCAG AA for normal text. Measured, not guessed: #6b7280 is the first value on
     the same hue that clears 4.5:1 against BOTH surfaces — but only by 0.01 on
     the page background, which is not a margin, it is a rounding coincidence.
     #666d79 gives 5.21 on the card and 4.86 on the page. */
  --ink-3: #666d79;
  --line: #dfe2e7;
  /* Borders that IDENTIFY a control (inputs, selects, file pickers) need 3:1 —
     WCAG 1.4.11. --line is 1.30:1, which is right for a decorative card edge
     and not enough for a text box. Decorative and functional borders are
     therefore two tokens, not one. */
  --line-strong: #767d87;
  --bg: #f6f7f9;
  --card: #fff;
  --volt: #c8ff00;
  --volt-ink: #3d4a00;
  /* TEXT ON A VOLT FILL. Distinct from --volt-ink, which is "volt-coloured text
     on a normal background" and therefore has to lighten in dark mode. --volt
     itself never changes, so a button using the flipping token rendered #d6ff4d
     on #c8ff00 — a 1.03:1 ratio, i.e. invisible. Caught by screenshotting the
     dark theme at 375px; it had already shipped on the Marque screen's
     "Envoyer et publier" button earlier the same day. */
  --on-volt: #3d4a00;
  --warn: #b45309;
  --stop: #b42318;
  --ok: #067647;
  --radius: 10px;
  color-scheme: light dark;
}

@media (prefers-color-scheme: dark) {
  :root {
    --ink: #e8eaee; --ink-2: #b3b9c2; --ink-3: #8a919b;
    --line: #2c3037; --line-strong: #646c79; --bg: #14161a; --card: #1b1e23;
    --volt-ink: #d6ff4d; --warn: #f0a868; --stop: #f97066; --ok: #4ade80;
  }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font: 15px/1.55 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  color: var(--ink);
  background: var(--bg);
}

a { color: inherit; }

/* ---------- chrome ---------- */
.top {
  display: flex; align-items: center; gap: 1.5rem; flex-wrap: wrap;
  padding: .85rem 1.25rem;
  background: var(--card);
  border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 10;
}
/* 23px tall as written, and 2.5.8 wants 24. It is a standalone header control,
   not a word inside running text, so the inline exception does not apply. */
.brand {
  font-weight: 500; text-decoration: none; letter-spacing: -.01em;
  /* inline-flex makes the bare "Régie " text node and the <b> two flex items,
     which collapses the whitespace between them — it shipped as
     "RégieAthletic Center" until a 320px screenshot showed it. `gap` puts the
     word space back as layout instead of relying on a collapsed text node. */
  display: inline-flex; align-items: center; gap: .3em; min-height: 24px;
}
.brand b { font-weight: 700; }
.top nav { display: flex; gap: .35rem; margin-right: auto; flex-wrap: wrap; }
.top nav a {
  text-decoration: none; padding: .35rem .7rem; border-radius: 999px;
  color: var(--ink-2); font-size: .92rem;
}
.top nav a:hover { background: var(--bg); }
.top nav a.on { background: var(--ink); color: var(--card); }
.out button {
  font: inherit; font-size: .88rem; padding: .35rem .8rem; cursor: pointer;
  background: none; border: 1px solid var(--line-strong); border-radius: 999px; color: var(--ink-2);
}
.out button:hover { border-color: var(--ink-3); }

main { max-width: 60rem; margin: 0 auto; padding: 2rem 1.25rem 4rem; }
h1 { font-size: 1.6rem; letter-spacing: -.02em; margin: 0 0 .4rem; }
.lead { color: var(--ink-2); margin: 0 0 1.75rem; }
.back { margin: 0 0 1rem; font-size: .9rem; }
/* Alone in its own paragraph, so not covered by 2.5.8's "in a sentence"
   exception — it measured 77x16. Padding rather than height keeps the baseline. */
.back a {
  color: var(--ink-3); text-decoration: none;
  display: inline-block; min-height: 24px; padding: 4px 0;
}
.back a:hover { color: var(--ink); }
code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .88em; }

.foot {
  max-width: 60rem; margin: 0 auto; padding: 1.25rem;
  color: var(--ink-3); font-size: .85rem; border-top: 1px solid var(--line);
}

/* ---------- login ---------- */
.login-body { display: grid; place-items: center; min-height: 100vh; min-height: 100dvh; padding: 1.25rem; }
.login {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 2rem; width: min(23rem, 100%); display: grid; gap: 1rem;
}
.login h1 { font-size: 1.2rem; margin: 0 0 .5rem; font-weight: 500; }
.login label { display: grid; gap: .35rem; font-size: .88rem; color: var(--ink-2); }
.login input {
  font: inherit; padding: .6rem .7rem; border: 1px solid var(--line-strong);
  border-radius: 8px; background: var(--bg); color: var(--ink);
}
.login input:focus-visible { outline: 3px solid var(--volt-ink); outline-offset: 1px; }
.login button {
  font: inherit; font-weight: 600; padding: .65rem; cursor: pointer; margin-top: .35rem;
  background: var(--ink); color: var(--card); border: 0; border-radius: 8px;
}
.err { color: var(--stop); font-size: .88rem; margin: 0; }

/* ---------- open items ---------- */
/* minmax(0, 1fr), not the default `auto`. An auto-sized grid track refuses to
   shrink below its content's MIN-CONTENT width, and Chrome's `input[type=file]`
   has a wide intrinsic minimum (325px here, in French), so at 320px the Marque
   cards forced the document 63px wider than the viewport — `max-width: 100%` on
   the input cannot help, because min-content sizing ignores it. Same family as
   the `1fr` = `minmax(auto, 1fr)` trap. */
.items { display: grid; gap: .85rem; grid-template-columns: minmax(0, 1fr); }
.item {
  background: var(--card); border: 1px solid var(--line);
  border-left: 4px solid var(--ink-3); border-radius: var(--radius); padding: 1rem 1.15rem;
}
.item-missing { border-left-color: var(--stop); }
.item-disputed { border-left-color: var(--warn); }
.item-inferred { border-left-color: var(--ink-3); }
.item-blocker { border-left-color: var(--stop); background: color-mix(in srgb, var(--stop) 4%, var(--card)); }
.item-done { border-left-color: var(--line); opacity: .72; }
.item-blocker .badge { color: var(--stop) !important; }
.sub { font-size: 1.1rem; margin: 2.5rem 0 .4rem; letter-spacing: -.01em; }
.item h3, .item h2 { margin: 0; font-size: .95rem; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-weight: 600; }
.item p { margin: .4rem 0 0; color: var(--ink-2); font-size: .92rem; }
.badge {
  display: inline-block; font-size: .75rem; text-transform: uppercase;
  letter-spacing: .06em; font-weight: 700; color: var(--ink-3) !important;
}
.item-missing .badge { color: var(--stop) !important; }
.item-disputed .badge { color: var(--warn) !important; }

/* ---------- sections ---------- */
.secs { display: grid; gap: .75rem; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); }
.sec {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 1rem 1.15rem; text-decoration: none; display: block;
}
.sec:hover { border-color: var(--ink-3); }
.sec h3 { margin: 0 0 .25rem; font-size: 1rem; }
.sec p { margin: 0 0 .5rem; color: var(--ink-2); font-size: .88rem; }
/* `.sec span` USED TO LIVE HERE and it was killing the chip colours.
   From the old card design, when the count was a bare <span>. Its specificity
   (0,1,1) beats every single-class chip rule (0,1,0), so .chip-open/.chip-ok/
   .chip-deferred all rendered in --ink-3 grey in both themes, whatever they
   said — measured rgb(107,114,128) in a live browser, while .grp-count, which
   sits outside .sec, correctly rendered orange one line above. Source order
   never entered into it. Every span in a card now carries its own class, so the
   blanket rule is deleted rather than out-specified: adding `.sec .chip` would
   have left the same trap armed for the next span. */

/* ---------- fields ---------- */
.fields { display: grid; gap: .6rem; }
.field {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); padding: .9rem 1.1rem;
}
.field-head { display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap; }
.trail { color: var(--ink-3); font-size: .78rem; }
.field-head label { font-weight: 600; font-size: .92rem; }
.field-value {
  margin: .35rem 0 .5rem; padding: .5rem .65rem;
  background: var(--bg); border-radius: 6px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .88rem;
  /* Long copy (FAQ answers, page leads) must wrap, and a very long unbroken
     string must scroll inside its own box rather than widening the document. */
  white-space: pre-wrap; overflow-wrap: anywhere; max-height: 14rem; overflow: auto;
}
.field-value.empty, .empty { color: var(--ink-3); font-style: italic; }
.field-prov { font-size: .82rem; color: var(--ink-2); display: grid; gap: .2rem; }
.prov { font-weight: 600; }
.prov-verified { color: var(--ok); }
.prov-stated { color: var(--ink-2); }
.prov-inferred, .prov-disputed { color: var(--warn); }
.prov-missing, .prov-none { color: var(--stop); }
.prov-detail { color: var(--ink-3); }
.inh { color: var(--ink-3); font-weight: 400; }

/* ---------- preview ---------- */
.preview {
  /* Width comes from the chosen device preset, inline on the element. Height is
     a viewport fraction so the frame is usable on a laptop and on a phone.

     content-box IS THE POINT. With the default border-box the 1px border eats
     into the declared width, so "320px" laid the site out at 318 and "390px" at
     388 — two pixels that can sit the wrong side of a breakpoint, in a tool
     whose only job is to show the layout at a given width. Measured: 388 before,
     390 after. */
  box-sizing: content-box;
  height: min(78vh, 900px); border: 1px solid var(--line-strong);
  border-radius: var(--radius); background: var(--card); display: block;
}
/* The stage centres a narrow frame instead of leaving it stranded on the left,
   and scrolls ITSELF if a wide preset is chosen on a narrow screen — the panel
   behind it must never scroll sideways. */
/* The stage centres a narrow frame instead of leaving it stranded on the left,
   and SCROLLS ITSELF when the chosen width is wider than the space available —
   the panel behind it must never scroll sideways. The frame keeps its true
   width: capping it with max-width made "Ordinateur 1280px" render at 914px on
   a 1280 screen, which is a label that lies about the one number it exists to
   show. */
.preview-stage {
  display: flex; justify-content: center;
  overflow-x: auto; padding: .2rem;
  background: var(--bg); border-radius: var(--radius);
}
/* A frame wider than the stage must not be squeezed by the flex centring. */
.preview-stage > .preview { flex: 0 0 auto; margin: auto; }
.screens { display: flex; flex-wrap: wrap; gap: .4rem; margin: 0 0 .5rem; }
.screens a {
  display: inline-flex; align-items: center; gap: .35rem; min-height: 32px;
  padding: .3rem .7rem; text-decoration: none; font-size: .88rem;
  color: var(--ink-2); background: var(--card);
  border: 1px solid var(--line-strong); border-radius: 999px;
}
.screens a:hover { border-color: var(--ink-3); color: var(--ink); }
.screens a.on { background: var(--ink); color: var(--card); border-color: var(--ink); }
.screens a:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.scr-w { font-variant-numeric: tabular-nums; opacity: .75; font-size: .82rem; }
.scr-note { margin: 0 0 .7rem; font-size: .85rem; color: var(--ink-3); }

@media (max-width: 40rem) {
  main { padding: 1.5rem 1rem 3rem; }
  .top { gap: .75rem; padding: .7rem 1rem; }
}

/* ---------- editing (phase 3) ---------- */
.field input[type="text"], .field textarea {
  font: inherit; width: 100%; margin: .35rem 0 .5rem;
  padding: .5rem .65rem; border: 1px solid var(--line-strong); border-radius: 6px;
  background: var(--bg); color: var(--ink);
}
.field textarea { resize: vertical; line-height: 1.5; }
.field input:focus-visible, .field textarea:focus-visible {
  outline: 3px solid var(--volt-ink); outline-offset: 1px; border-color: transparent;
}
/* An empty field is a job to do, not a neutral state — the launch blockers are
   all empty fields, and they should look like it. */
.field-empty { border-left: 3px solid var(--stop); }
.field-empty input { border-color: var(--stop); }
.bool { display: flex; align-items: center; gap: .5rem; margin: .35rem 0 .5rem; }
.bool input { width: 1.1rem; height: 1.1rem; }
.ro { margin: .2rem 0 .5rem; font-size: .8rem; color: var(--ink-3); font-style: italic; }

.publish {
  position: sticky; bottom: 0; margin-top: 1.25rem; padding: 1rem 1.15rem;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  display: grid; gap: .6rem;
}
.note { display: grid; gap: .3rem; font-size: .85rem; color: var(--ink-2); }
.note input {
  font: inherit; padding: .5rem .65rem; border: 1px solid var(--line-strong);
  border-radius: 6px; background: var(--bg); color: var(--ink);
}
.publish-why { margin: 0; font-size: .82rem; color: var(--ink-3); }
.publish button {
  font: inherit; font-weight: 600; padding: .7rem 1.1rem; cursor: pointer;
  background: var(--ink); color: var(--card); border: 0; border-radius: 8px; justify-self: start;
}
.publish button[disabled] { opacity: .45; cursor: default; }
.warn-inline { margin: 0; color: var(--warn); font-size: .85rem; }

/* ---------- publish result ---------- */
.step { color: var(--ink-2); font-variant-numeric: tabular-nums; }
.ok-big { font-size: 1.4rem; font-weight: 700; color: var(--ok); margin: 0 0 .3rem; }
.fail-big { font-size: 1.4rem; font-weight: 700; color: var(--stop); margin: 0 0 .3rem; }
.findings { margin: .5rem 0 1rem; padding-left: 1.1rem; color: var(--ink-2); }
.findings li { margin: .25rem 0; }
.btn {
  display: inline-block; text-decoration: none; font-weight: 600;
  padding: .55rem 1rem; background: var(--ink); color: var(--card); border-radius: 8px;
}
.item-deferred { border-left-color: var(--ink-3); opacity: .85; }
.item-deferred .badge { color: var(--ink-3) !important; }
.item-actions { display: flex; gap: .9rem; align-items: center; flex-wrap: wrap; margin-top: .7rem !important; }
.btn-sm { padding: .35rem .8rem; font-size: .85rem; }
/* The deep link lands on a field; make it obvious which one. */
.field:target { outline: 3px solid var(--volt-ink); outline-offset: 3px; }

/* Items computed by the truth gate headline a SENTENCE, not a JSON path, so the
   monospace face that suits `club.foundedYear` is wrong for them — it makes
   French read like a stack trace. Same card, different heading voice. */
.item-audit h3 { font-family: inherit; font-weight: 650; font-size: 1rem; letter-spacing: -.01em; }
.item-more { font-size: .82rem !important; color: var(--ink-3) !important; }

/* ---------- answering a question, as opposed to filling a field ----------
   Two items in the queue were readable but unanswerable: the data was already
   right, so there was no box to type in and no way to say "yes, that is
   correct". This is that answer. Deliberately quiet — it sits inside a card
   that has already asked the question, and it must not compete with the
   "Répondre dans …" link on items that DO have a field to fill. */
.decide {
  margin-top: .85rem; padding-top: .8rem; border-top: 1px dashed var(--line);
  display: grid; gap: .6rem;
}
.decide fieldset { border: 0; padding: 0; margin: 0; display: flex; gap: 1.1rem; flex-wrap: wrap; align-items: center; }
.decide legend { padding: 0; font-size: .82rem; color: var(--ink-3); }
.decide .choice { display: inline-flex; align-items: center; gap: .4rem; font-variant-numeric: tabular-nums; font-weight: 600; }
/* 24px minimum target, enforced by the responsive gate on the public site and
   applied here by hand — the client uses this on a phone at the club. */
.decide .choice input { width: 24px; height: 24px; accent-color: var(--ink); }
.decide label { display: grid; gap: .3rem; font-size: .85rem; color: var(--ink-2); }
.decide textarea {
  width: 100%; box-sizing: border-box; font: inherit; line-height: 1.5;
  padding: .5rem .6rem; border: 1px solid var(--line-strong); border-radius: 8px;
  background: var(--card); color: var(--ink); resize: vertical;
}
.decide textarea:focus-visible { outline: 3px solid var(--volt-ink); outline-offset: 2px; }
/* The sentence above the "apply" button. It says what the click will change and
   how long it takes — a button that republishes the site must never be a bare
   verb. Sized like the card body, not like a form label: it is prose. */
.decide-lead { margin: 0 !important; font-size: .85rem; color: var(--ink-2); line-height: 1.55; }
.decide-actions { display: flex; gap: .7rem; align-items: center; flex-wrap: wrap; margin: 0 !important; }
.decide button { font: inherit; cursor: pointer; border: 0; }
/* "Reporter" must be reachable but never the obvious click. */
.btn-quiet { background: transparent; color: var(--ink-2); border: 1px solid var(--line-strong) !important; }

/* ---------------------------------------------------------------- MARQUE */
/* The upload screen. The thumbnail sits on a checkerboard because half of what
   lands here is a transparent PNG or an SVG with no background: on a white card
   a white logo is indistinguishable from an upload that silently failed. */
.asset-now { display: flex; gap: 1rem; align-items: flex-start; margin: 0.9rem 0; flex-wrap: wrap; }
.asset-thumb {
  flex: none; display: grid; place-items: center;
  width: 148px; min-height: 84px; padding: 0.5rem;
  border: 1px solid var(--line); border-radius: var(--radius);
  background-color: #fff;
  background-image:
    linear-gradient(45deg, #eceef1 25%, transparent 25%, transparent 75%, #eceef1 75%),
    linear-gradient(45deg, #eceef1 25%, transparent 25%, transparent 75%, #eceef1 75%);
  background-size: 14px 14px;
  background-position: 0 0, 7px 7px;
}
.asset-thumb img { max-width: 100%; max-height: 120px; height: auto; display: block; }
.asset-meta { display: grid; grid-template-columns: auto 1fr; gap: 0.15rem 0.8rem; margin: 0; font-size: 0.88rem; }
.asset-meta dt { color: var(--ink-3); }
.asset-meta dd { margin: 0; color: var(--ink); font-variant-numeric: tabular-nums; word-break: break-all; }
.asset-empty { color: var(--ink-2); margin: 0.6rem 0 0.9rem; }
.asset-remove { margin: 0 0 1rem; }
.asset-form { border-top: 1px solid var(--line); padding-top: 0.9rem; margin-top: 0.5rem; }
.asset-form .help { color: var(--ink-2); margin: 0 0 0.7rem; }
.asset-file, .asset-alt { display: block; margin: 0 0 0.75rem; }
.asset-file > span, .asset-alt > span { display: block; font-weight: 600; margin-bottom: 0.3rem; }
.asset-alt input {
  width: 100%; max-width: 34rem; padding: 0.5rem 0.6rem;
  border: 1px solid var(--line-strong); border-radius: 8px; background: var(--card); color: var(--ink);
  font: inherit;
}
.asset-alt em { display: block; color: var(--ink-3); font-size: 0.85rem; margin-top: 0.25rem; font-style: normal; }
.asset-file input[type=file] { font: inherit; color: var(--ink-2); width: 100%; max-width: 100%; }

/* The provenance row's "voir la source" link measured 251x20 and sits in a
   metadata row rather than a sentence, so WCAG 2.5.8's inline exception does not
   cover it. Padding, not height, so the text position does not move. */
.field-prov a, .prov + a { display: inline-block; min-height: 24px; padding: 2px 0; }
.asset-rules { color: var(--ink-3); font-size: 0.85rem; margin: 0 0 0.9rem; }
.asset-form button {
  font: inherit; font-weight: 600; padding: 0.55rem 1.1rem; cursor: pointer;
  border: 1px solid var(--ink); border-radius: 8px; background: var(--volt); color: var(--on-volt);
}
.asset-form button:hover { filter: brightness(1.06); }
@media (max-width: 560px) {
  .asset-thumb { width: 100%; }
}

/* --------------------------------------------------------------- CONTENU */
/* The index of every published value: a search box, a one-line summary of what
   is outstanding, and the eighteen rubrics in five fixed groups.

   Restraint is the point. This screen is a way in, not a dashboard: no
   progress rings, no counts racing each other for attention. Exactly one chip
   per card, and the only colour that appears is on the cards that want him. */

.sum { margin: 0 0 1rem; font-size: .95rem; }
.sum-open {
  border-left: 3px solid var(--warn); padding-left: .7rem; color: var(--ink);
}
.sum-clear { color: var(--ink-2); }
.sum a { color: var(--ink); }

/* ---- search ---- */
.find { margin: 0 0 1.6rem; }
.find label { display: block; font-weight: 600; font-size: .9rem; margin-bottom: .35rem; }
.find-row { display: flex; gap: .5rem; flex-wrap: wrap; }
.find input[type="search"] {
  font: inherit; flex: 1 1 20rem; min-width: 0;
  padding: .55rem .7rem; border: 1px solid var(--line-strong); border-radius: 8px;
  background: var(--card); color: var(--ink);
  /* iOS zooms the page when a focused input is under 16px. */
  font-size: max(1rem, 16px);
}
.find button {
  font: inherit; font-weight: 600; cursor: pointer; padding: .55rem 1.1rem;
  border: 1px solid var(--ink); border-radius: 8px;
  background: var(--volt); color: var(--on-volt);
}
.find .btn-quiet {
  font: inherit; padding: .55rem 1rem; border-radius: 8px; text-decoration: none;
  display: inline-flex; align-items: center;
}
.find-help { margin: .4rem 0 0; font-size: .84rem; color: var(--ink-3); }
.find-count { margin: 0 0 .8rem; font-size: .9rem; color: var(--ink-2); }
.find-none { margin: 0 0 1rem; color: var(--ink-2); }

.hits { list-style: none; margin: 0; padding: 0; display: grid; gap: .5rem; }
.hit a {
  display: grid; gap: .15rem; text-decoration: none; color: inherit;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: .7rem .85rem;
}
.hit a:hover { border-color: var(--ink-3); }
.hit-where { font-size: .78rem; color: var(--ink-3); text-transform: uppercase; letter-spacing: .04em; }
.hit-label { font-weight: 600; font-size: .95rem; }
.hit-loc {
  font-weight: 500; font-size: .72rem; color: var(--ink-2);
  border: 1px solid var(--line-strong); border-radius: 4px; padding: 0 .25rem; vertical-align: .1em;
}
.hit-val { font-size: .9rem; color: var(--ink-2); overflow-wrap: anywhere; }
/* The browser default is a yellow that vanishes in dark mode. */
.hit-val mark {
  background: var(--volt); color: var(--on-volt); border-radius: 2px; padding: 0 .1em;
  font-weight: 600;
}

/* ---- groups ---- */
.grp { margin: 0 0 1.8rem; }
.grp h2 { font-size: 1.02rem; margin: 0 0 .15rem; font-weight: 600; }
.grp-hint { margin: 0 0 .7rem; font-size: .86rem; color: var(--ink-3); }

.sec-foot { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; font-size: .82rem; }
.sec-count { color: var(--ink-3); font-variant-numeric: tabular-nums; }
.sec-langs {
  color: var(--ink-3); font-size: .74rem; letter-spacing: .04em;
  margin-left: auto; white-space: nowrap;
}

.chip {
  display: inline-block; border-radius: 999px; padding: .1rem .5rem;
  font-weight: 600; font-size: .78rem; border: 1px solid currentColor;
}
.chip-open { color: var(--warn); }
.chip-deferred { color: var(--ink-2); }
.chip-ok { color: var(--ok); border-color: var(--line-strong); font-weight: 500; }

/* Off-screen but announced. `display:none` and `visibility:hidden` remove it
   from the accessibility tree too, which is the opposite of the point. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* ---- focus: one visible ring everywhere, in both themes ---- */
/* --ink is 17.8:1 on the light card and 13.9:1 on the dark one, so a ring drawn
   in it is unmissable without inventing an accent colour this tool does not
   have. :focus-visible only, or a mouse click leaves a ring behind. */
/* The header was left on Chrome's default 1px ring, which contradicted the
   claim below. Named explicitly rather than with a blanket `a:focus-visible`,
   so a future element does not inherit a ring that has not been looked at. */
.sec:focus-visible, .hit a:focus-visible, .find input:focus-visible,
.find button:focus-visible, .find .btn-quiet:focus-visible, .sum a:focus-visible,
.top nav a:focus-visible, .brand:focus-visible, .out button:focus-visible,
.rec a:focus-visible {
  outline: 2px solid var(--ink); outline-offset: 2px;
}

@media (max-width: 560px) {
  /* `flex: 1 1 20rem` on the input sizes the MAIN axis. Stacking the row turns
     that axis vertical, so the search box became a 320px-tall void with the
     placeholder floating in the middle of it. Basis must go back to auto
     whenever the direction changes — flex-basis is not "width". */
  .find-row { flex-direction: column; align-items: stretch; }
  .find input[type="search"] { flex: 0 0 auto; width: 100%; }
  .find .btn-quiet { justify-content: center; }
  .sec-langs { margin-left: 0; }
}

/* The group heading's aside: the total for the group, counted once per question.
   Deliberately quieter than the card chips — it is a signpost while scrolling,
   not a third thing competing for the same glance. */
.grp-count {
  /* At 320px "Tarifs et abonnement 1 question" wraps, and without this the pill
     itself broke across the line — "(1" above "question)" — which nothing
     detects as overflow because the document never widens. */
  white-space: nowrap;
  font-weight: 500; font-size: .8rem; color: var(--warn);
  border: 1px solid currentColor; border-radius: 999px; padding: .05rem .45rem;
  vertical-align: .12em; margin-left: .3rem;
}
/* "One question, two rubrics" — see the comment in the /contenu route. Last
   line of the card, quiet, because it is context and not a task. */
.sec-linked {
  display: block; margin-top: .45rem; font-size: .78rem; color: var(--ink-3);
  border-top: 1px dashed var(--line); padding-top: .4rem;
}

/* ---- "Vos dernières modifications": absent entirely when there is nothing ---- */
.recent { border-top: 1px solid var(--line); padding-top: 1.1rem; }
.rec { list-style: none; margin: 0; padding: 0; display: grid; gap: .35rem; }
.rec a {
  display: flex; gap: .6rem; align-items: baseline; flex-wrap: wrap;
  text-decoration: none; color: inherit; padding: .45rem .6rem;
  border: 1px solid var(--line); border-radius: 8px; background: var(--card);
}
.rec a:hover { border-color: var(--ink-3); }
.rec a:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.rec-what { font-weight: 600; font-size: .9rem; }
.rec-when { font-size: .8rem; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.rec-was { font-size: .8rem; color: var(--ink-3); margin-left: auto; overflow-wrap: anywhere; }
@media (max-width: 560px) { .rec-was { margin-left: 0; } }
/* The audit could not be run, so we do not know. Never rendered alongside a
   count — it replaces one, and it must not read like reassurance. */
.chip-unknown { color: var(--ink-2); border-style: dashed; }

/* -------------------------------------------------------------- FICHIERS */
/* The drop zone is a <label> around a real file input: clicking it opens the
   picker with no script at all, and app.js only adds dropping. */
.drop-form { margin: 0 0 1.6rem; }
.drop {
  display: grid; gap: .3rem; place-items: center; text-align: center;
  padding: 1.8rem 1rem; cursor: pointer;
  border: 2px dashed var(--line-strong); border-radius: var(--radius);
  background: var(--card); color: var(--ink-2);
}
.drop:hover { border-color: var(--ink-3); }
.drop:focus-within { outline: 2px solid var(--ink); outline-offset: 2px; }
/* The dragged-over state changes BORDER and BACKGROUND, not just colour: a
   colour-only cue is invisible to anyone who cannot distinguish it. */
.drop-over { border-style: solid; border-color: var(--ink); background: color-mix(in srgb, var(--volt) 12%, var(--card)); }
.drop-strong { font-weight: 600; font-size: 1rem; color: var(--ink); }
.drop-or { font-size: .88rem; color: var(--ink-3); }
/* The <label> around it is a ~110px target, so the effective hit area was
   already fine — but the control itself measured 253x21 and arguing an
   exemption is worse than clearing the bar. It stays VISIBLE on purpose:
   with JavaScript off, the native input's own "2 files" text is the only
   confirmation he gets that anything was selected. */
.drop input[type=file] { margin-top: .5rem; max-width: 100%; min-height: 24px; }
.drop-picked { font-size: .85rem; color: var(--ink); overflow-wrap: anywhere; }
.drop-form button {
  margin-top: .8rem; font: inherit; font-weight: 600; cursor: pointer;
  padding: .55rem 1.1rem; border: 1px solid var(--ink); border-radius: 8px;
  background: var(--volt); color: var(--on-volt);
}
.drop-form button[disabled] { opacity: .6; cursor: default; }
.drop-form button:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

.inbox { list-style: none; margin: 0; padding: 0; display: grid; gap: .4rem; }
.inbox li {
  display: flex; gap: .7rem; align-items: center; flex-wrap: wrap;
  padding: .55rem .7rem; background: var(--card);
  border: 1px solid var(--line); border-radius: 8px;
}
.inbox-name { color: var(--ink); font-weight: 600; font-size: .92rem; overflow-wrap: anywhere; min-height: 24px; display: inline-flex; align-items: center; }
.inbox-name:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.inbox-meta { font-size: .82rem; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.inbox-del { margin-left: auto; }
@media (max-width: 560px) { .inbox-del { margin-left: 0; } }
