/* Rebuild browser subsets: uv run python scripts/build_webfonts.py */
/* Concord Textile brand layer — tokens from the Claude Design system
   ("concord-textile-design-system", project 93a010fa, 2026-07-22).
   Fonts: Montserrat/Poppins, and they are the ADMIN CHROME's faces, not the
   label's. The substitution this comment used to announce ended at #766 — the
   brand pair, League Spartan and Glacial Indifference, is OFL and ships in
   `/static/fonts/`, and the label engine names it directly (`engine.typ`
   FONTS). Restyling this app in it is a design decision nobody has asked for,
   so the two stacks below stay exactly what they are: a screen, not a drum.
   Safety pictograms (CLP/GHS) and the
   red "Jamais" block are a hard product requirement and OVERRIDE any design
   iteration that drops them (Aurèle, 22.07).
   The spec-chip strip was on that list until 27.08 and no longer is: the owner
   dropped it from the fiche in the v4 review (#423) because a chip summarising a
   dosage matrix as one figure is the #8 failure in the header. The `.spec` rules
   below stay — the QR landing page (#369) still uses them. */
/* Local TTF sources make Chromium embed deterministic font subsets in server
   PDFs. No label render may depend on an external font request or synthesis. */
@font-face {
  font-family:'Montserrat'; font-style:normal; font-weight:300; font-display:swap;
  src:url('/static/fonts/Montserrat-Light.web.woff2') format('woff2'), url('/static/fonts/Montserrat-Light.ttf') format('truetype');
}
@font-face {
  font-family:'Montserrat'; font-style:normal; font-weight:500; font-display:swap;
  src:url('/static/fonts/Montserrat-Medium.web.woff2') format('woff2'), url('/static/fonts/Montserrat-Medium.ttf') format('truetype');
}
@font-face {
  font-family:'Montserrat'; font-style:normal; font-weight:600; font-display:swap;
  src:url('/static/fonts/Montserrat-SemiBold.web.woff2') format('woff2'), url('/static/fonts/Montserrat-SemiBold.ttf') format('truetype');
}
@font-face {
  font-family:'Montserrat'; font-style:normal; font-weight:700; font-display:swap;
  src:url('/static/fonts/Montserrat-Bold.web.woff2') format('woff2'), url('/static/fonts/Montserrat-Bold.ttf') format('truetype');
}
@font-face {
  font-family:'Montserrat'; font-style:normal; font-weight:800; font-display:swap;
  src:url('/static/fonts/Montserrat-ExtraBold.web.woff2') format('woff2'), url('/static/fonts/Montserrat-ExtraBold.ttf') format('truetype');
}
@font-face {
  font-family:'Poppins'; font-style:normal; font-weight:400; font-display:swap;
  src:url('/static/fonts/Poppins-Regular.web.woff2') format('woff2'), url('/static/fonts/Poppins-Regular.ttf') format('truetype');
}
@font-face {
  font-family:'Poppins'; font-style:normal; font-weight:500; font-display:swap;
  src:url('/static/fonts/Poppins-Medium.web.woff2') format('woff2'), url('/static/fonts/Poppins-Medium.ttf') format('truetype');
}
@font-face {
  font-family:'Poppins'; font-style:normal; font-weight:600; font-display:swap;
  src:url('/static/fonts/Poppins-SemiBold.web.woff2') format('woff2'), url('/static/fonts/Poppins-SemiBold.ttf') format('truetype');
}
@font-face {
  font-family:'Poppins'; font-style:normal; font-weight:700; font-display:swap;
  src:url('/static/fonts/Poppins-Bold.web.woff2') format('woff2'), url('/static/fonts/Poppins-Bold.ttf') format('truetype');
}
@font-face {
  font-family:'Poppins'; font-style:normal; font-weight:800; font-display:swap;
  src:url('/static/fonts/Poppins-ExtraBold.web.woff2') format('woff2'), url('/static/fonts/Poppins-ExtraBold.ttf') format('truetype');
}

:root {
  --indigo-700:#0e0c63; --indigo-500:#2a26ab; --indigo-100:#e3e2f0;
  --green-500:#97c422; --green-050:#f2f8e2;
  --blue-500:#2581c4;  --blue-050:#e8f3fb; --blue-600:#1f6fac;
  --ink-800:#2b3136; --ink-500:#6b727c; --ink-200:#dfe3e9; --ink-100:#eef1f5;
  --admin-background:#e8eaf0; --surface:#fff; --radius-sm:7px;
  --shadow-admin:0 1px 6px rgba(14,12,99,.35);
  --mist:#f5f6fa; --danger-ct:#d64545; --warning-ct:#e8a723;
  --gradient-drop:linear-gradient(135deg,var(--green-500) 0%,var(--blue-500) 100%);
  --shadow-sm:0 1px 3px rgba(14,12,99,.08),0 1px 2px rgba(14,12,99,.04);
  --radius-md:10px; --radius-lg:16px;
  --font-display:'Montserrat',system-ui,sans-serif;
  --font-body:'Poppins',system-ui,sans-serif;

  /* Which stack is this? (#358) — set by /static/env-badge.js from
     /api/health.app_env. A DEDICATED token, deliberately not an override of
     --indigo-700: that one also paints primary buttons, the chat bubbles, the
     language chips and the FT ribbon, so repointing it would tint half the app
     and change a printed document. --env-bar means "chrome that tells you where
     you are" and nothing else. */
  --env-bar:var(--indigo-700);
  --env-chip-bg:#ffffff2e;
  --env-chip-fg:#fff;
}

/* Shared drawer section labels (#1174): headings stay in the scroll flow. */
.nav-h {
  font-family:var(--font-display); font-size:.62rem; font-weight:700;
  letter-spacing:.14em; text-transform:uppercase; color:var(--blue-600);
  padding:.75rem .6rem .3rem;
}

/* #b45309 rather than --warning-ct (#e8a723): the bars carry white text, and
   e8a723 gives 2.1:1 against white — unreadable. b45309 gives 5.02:1 (AA). */
:root[data-env="test"] { --env-bar:#b45309; --env-chip-bg:#00000038; --env-chip-fg:#fff; }
:root[data-env="prod"] { --env-bar:var(--indigo-700); }

/* The chip is the signal that survives greyscale, colour-blindness and a
   screenshot pasted into a chat. The colour is the fast path; this is the
   one that is actually unambiguous. */
.env-chip {
  font-family:var(--font-display); font-size:.62rem; font-weight:700;
  letter-spacing:.12em; line-height:1; white-space:nowrap; flex:0 0 auto;
  padding:.28rem .5rem; border-radius:5px;
  background:var(--env-chip-bg); color:var(--env-chip-fg);
  border:1px solid #ffffff40;
}
/* On the two pages whose bar is white, the chip has to carry its own contrast
   instead of borrowing the bar's. */
.topbar .env-chip, .bar[data-light] .env-chip,
:root[data-env="test"] .topbar .env-chip {
  background:var(--env-bar); color:#fff; border-color:transparent;
}

/* On a gate the chip is the whole signal, so it is solid and sits on its own
   line above the form title rather than inline. */
.env-chip-gate {
  display:block; width:fit-content; margin:0 0 .9rem;
  background:var(--env-bar); color:#fff; border-color:transparent;
  font-size:.66rem; padding:.34rem .6rem;
}

body { font-family:var(--font-body); }
header h1 { font-family:var(--font-display); font-weight:600; letter-spacing:.01em; }
h2 { font-family:var(--font-display); font-weight:700; letter-spacing:.14em; font-size:.72rem; }

/* --- gamme navigation chips --- */
.gammes { display:flex; gap:.4rem; overflow-x:auto; padding-bottom:.2rem; -webkit-overflow-scrolling:touch; }
.gammes button { flex:none; font:inherit; font-size:.78rem; padding:.35rem .8rem; cursor:pointer;
  border:1px solid var(--ink-200); border-radius:999px; background:#fff; color:var(--ink-800); }
.gammes button.on { background:var(--indigo-700); border-color:var(--indigo-700); color:#fff; font-weight:600; }

/* --- product list rows --- */
.ref { font-family:ui-monospace,Consolas,monospace; font-size:.72rem; background:var(--indigo-100);
  color:var(--indigo-700); border-radius:6px; padding:.05rem .4rem; font-weight:600; }
.prod-row .eco { color:var(--green-500); font-weight:700; letter-spacing:-.1em; margin-left:.3rem; }
/* packaging highlight colour — the band at the top of the fiche echoes the
   label band on the physical bidon (recognition aid, per Aurèle 22.07) */
.fiche { overflow:hidden; }
.fiche .band { height:9px; margin:-1rem -1rem .8rem; }

/* --- fiche produit --- */
.fiche { background:#fff; border:1px solid var(--ink-200); border-radius:var(--radius-lg);
  padding:1rem; box-shadow:var(--shadow-sm); }
.fiche .name { font-family:var(--font-display); font-weight:700; color:var(--indigo-700);
  font-size:1.15rem; line-height:1.2; text-transform:uppercase; }
/* commercial names render UPPERCASE like the labels/FT; the DB keeps the
   official brand casing (ProtEx, TanEx…) as source of truth (Aurèle 24.07).
   Safe on .name/.t: the .ref chip is already uppercase and the eco pipes and
   name_full/description are separate elements. */
.prod-row .t { text-transform:uppercase; }
.fiche .full { color:var(--ink-500); font-size:.85rem; margin-top:.1rem; }
.fiche .eyebrow { font-family:var(--font-display); text-transform:uppercase; letter-spacing:.14em;
  font-size:.62rem; font-weight:700; color:var(--blue-600); margin:.8rem 0 .3rem; }

/* --- fiche v4 (#423) -------------------------------------------------------
   Header: identity left, the bidon right. The drawing is capped rather than
   fluid so a long product name never squeezes it into an unrecognisable sliver,
   and it drops out entirely under 360 px where the name needs the width more
   than the recognition aid does. */
.fiche-head { display:flex; align-items:flex-start; gap:.8rem; }
.fiche-head .fh-id { flex:1 1 auto; min-width:0; }
.fiche-head .fh-pack { flex:0 0 auto; width:76px; text-align:center; }
.fiche-head .bidon { width:76px; height:80px; display:block; }
.fiche-head .soft { display:block; color:var(--blue-500); }
.fiche .lede { margin:.6rem 0 0; font-size:.92rem; }

/* Dosage — always visible since v4, so the table needs to read on its own
   rather than as the first thing inside an opened accordion. */
.dose-mode { font-size:.88rem; font-weight:600; color:var(--ink-800); margin:.1rem 0 .3rem; }

/* Textiles strip — the compact summary of the ✓ ratings and the prudence
   fibres, shown only when the record carries either (see the renderer). */
.textile-strip { display:flex; flex-wrap:wrap; align-items:center; gap:.4rem; margin-top:.7rem; }
.textile-strip .tx { display:inline-flex; align-items:baseline; gap:.3rem; background:var(--mist);
  border:1px solid var(--ink-200); border-radius:999px; padding:.15rem .6rem; }
.textile-strip .tx small { font-size:.62rem; text-transform:uppercase; letter-spacing:.06em;
  color:var(--ink-500); }
.textile-strip .tx b { font-size:.8rem; color:var(--green-500); letter-spacing:-.05em; }
.textile-strip .tx-caution { background:#fff8ec; color:#8a6d00; border-radius:999px;
  font-size:.75rem; padding:.15rem .6rem; }

/* Sécurité & réglementaire — one unfurl, anchored by the GHS row. The summary
   is the safety summary: pictograms, signal word and the ADR badge stay legible
   with the section closed, which is the 24.07 "always visible" rule kept by
   construction. `display:flex` drops the native triangle, hence .sf-more. */
details.sec.safety { margin-top:.8rem; }
details.sec.safety > summary { display:flex; flex-wrap:wrap; align-items:center;
  justify-content:space-between; gap:.5rem; padding:.5rem .8rem; }
details.sec.safety > summary::-webkit-details-marker { display:none; }
.sf-sum { display:flex; align-items:center; flex-wrap:wrap; gap:.5rem; }
.sf-sum .ghs-row { margin-top:0; }
.sf-more { font-size:.78rem; font-weight:700; letter-spacing:.04em; color:var(--indigo-700);
  white-space:nowrap; }
.sf-more::after { content:' ▾'; }
details.sec.safety[open] .sf-more::after { content:' ▴'; }
.adr-badge { font-family:var(--font-display); font-weight:800; font-size:.7rem; letter-spacing:.08em;
  background:var(--warning-ct); color:#3a2c00; border-radius:.35rem; padding:.2rem .45rem; }

@media (max-width:360px) {
  .fiche-head .fh-pack { display:none; }
}

/* --- variantes de base (#424) ---------------------------------------------
   « C'est lequel, déjà ? » is asked before anything else, so the switcher sits
   in the header zone, right under the designation. One line of chips, no
   accordion: it is navigation, not content. Renders only when the family has
   more than one member (the data-gated pattern). */
.variants { display:flex; flex-wrap:wrap; align-items:center; gap:.3rem;
  margin-top:.45rem; font-size:.78rem; color:var(--ink-500); }
.variants .vlead { font-weight:600; color:var(--ink-800); }
.variants .vlink { display:inline-flex; align-items:center; gap:.3rem; text-decoration:none;
  border:1px solid var(--ink-200); border-radius:999px; padding:.15rem .5rem .15rem .55rem;
  background:#fff; color:var(--indigo-700); font-weight:600; }
.variants .vlink:hover { border-color:var(--indigo-700); }
/* the family marker on a collapsed catalogue row */
.prod-row .vmark { font-size:.62rem; background:var(--indigo-100); color:var(--indigo-700);
  border-radius:99px; padding:.05rem .4rem; margin-left:.3rem; font-weight:600;
  text-transform:none; letter-spacing:0; }

/* spec chips — the catalogue legend strip (dosage/temp/pH/actif/ADR/éco).
   The fiche dropped them in v4 (#423); the QR landing page still renders them. */
.spec { display:grid; grid-template-columns:repeat(3,1fr); gap:.4rem; margin-top:.7rem; }
.spec > div { border:1px solid var(--ink-200); border-radius:var(--radius-md); background:var(--mist);
  padding:.4rem .3rem; text-align:center; }
.spec b { display:block; font-size:.8rem; color:var(--ink-800); }
.spec small { font-size:.58rem; text-transform:uppercase; letter-spacing:.08em; color:var(--ink-500); }

/* ✓ benefit checklist with the drop gradient */
.ct-checklist { list-style:none; padding:0; margin:.3rem 0 0; display:grid; gap:.35rem; }
.ct-checklist li { padding-left:1.5rem; position:relative; font-size:.9rem; }
.ct-checklist li::before { content:'✓'; position:absolute; left:0; top:0; width:1.05rem; height:1.05rem;
  border-radius:50%; background:var(--gradient-drop); color:#fff; font-size:.68rem; font-weight:700;
  display:flex; align-items:center; justify-content:center; }

/* the red "Jamais" block — non-negotiable safety element */
.never-block { border:2px solid var(--danger-ct); border-radius:var(--radius-md);
  background:#fdf1f1; padding:.6rem .8rem; margin-top:.8rem; }
.never-block .nt { color:var(--danger-ct); font-weight:700; font-size:.78rem;
  text-transform:uppercase; letter-spacing:.06em; margin-bottom:.25rem; }
.never-block ul { padding-left:1.1rem; margin:0; display:grid; gap:.25rem; font-size:.88rem; }

.stain-chips { display:flex; flex-wrap:wrap; gap:.3rem; margin-top:.3rem; }
.stain-chips span { background:var(--blue-050); color:var(--blue-600); border-radius:999px;
  font-size:.75rem; padding:.1rem .6rem; }

/* Vue Pro (collapsed) */
details.pro { margin-top:.8rem; border:1px solid var(--ink-200); border-radius:var(--radius-md); background:var(--mist); }
details.pro summary { cursor:pointer; padding:.6rem .8rem; font-weight:600; color:var(--indigo-700); font-size:.88rem; }
details.pro .body { padding:0 .8rem .8rem; }
details.pro table { width:100%; border-collapse:collapse; font-size:.8rem; font-variant-numeric:tabular-nums; }
details.pro th { text-align:left; font-size:.62rem; text-transform:uppercase; letter-spacing:.06em;
  color:var(--ink-500); padding:.25rem .3rem; border-bottom:1px solid var(--ink-200); }
details.pro td { padding:.3rem; border-bottom:1px dashed var(--ink-200); }
.conflict { background:#fff8ec; border-left:3px solid var(--warning-ct); padding:.35rem .6rem;
  font-size:.78rem; margin-top:.3rem; }

/* competitor equivalences — pro-only, validated rows only. Deliberately shows
   BOTH sides: a commercial who only knows why we win gets ambushed on the one
   thing the rival does better, so ✓ and △ always render as a pair. */
.equiv { border:1px solid var(--ink-200); border-radius:var(--radius-md); background:#fff;
  padding:.5rem .65rem; margin-top:.45rem; font-size:.82rem; }
.equiv-h { font-size:.86rem; margin-bottom:.15rem; }
.equiv-h .doc-badge { background:var(--mist); margin-left:.25rem; }
.equiv-spec { color:var(--ink-500); font-size:.76rem; margin-bottom:.3rem; }
.equiv-win { color:var(--indigo-700); margin-top:.2rem; }
.equiv-lose { color:var(--warning-ct); margin-top:.2rem; }
.equiv .doc-link { margin-top:.4rem; font-size:.72rem; padding:.25rem .5rem; }
.equiv-q { width:100%; padding:.6rem .8rem; font-size:.95rem; border:1px solid var(--ink-200);
  border-radius:var(--radius-md); margin-bottom:.7rem; }
.equiv-to { font-family:var(--font-display); color:var(--indigo-700); font-weight:700; }

/* fiche header swish — the REAL label artwork (/static/swish.webp, extracted
   from the 2026 label PDFs) as a zero-space translucent BACKGROUND, tinted by
   the packaging colour via CSS mask. Renders only when the product has one. */
.fiche { position:relative; z-index:0; }
.fiche .swish-bg { position:absolute; top:0; left:0; right:0; height:170px;
  z-index:-1; opacity:.34; pointer-events:none;
  -webkit-mask-image:url(/static/swish.webp); mask-image:url(/static/swish.webp);
  -webkit-mask-size:cover; mask-size:cover;
  -webkit-mask-position:center top; mask-position:center top;
  -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat; }

/* fiche v3 — GHS pictograms, accordions, dosage table, conditionnements */
.ghs-row { display:flex; align-items:flex-start; gap:.55rem; margin-top:.8rem; flex-wrap:wrap; }
.ghs { display:inline-flex; flex-direction:column; align-items:center; gap:.15rem; width:56px; }
.ghs svg, .ghs img { width:44px; height:44px; }
.ghs small { font-size:.52rem; text-align:center; line-height:1.15; color:var(--ink-500); }
.signal { align-self:center; font-weight:800; font-size:.78rem; letter-spacing:.06em;
  padding:.25rem .6rem; border-radius:.4rem; background:#fff3cd; color:#8a6d00; }
.signal.danger { background:#fde8e8; color:#b91c1c; }
details.sec { border:1px solid var(--ink-200); border-radius:.7rem; margin-top:.6rem; background:#fff; }
details.sec summary { cursor:pointer; padding:.6rem .8rem; font-weight:600; font-size:.88rem;
  color:var(--indigo-700); }
details.sec .body { padding:0 .8rem .8rem; font-size:.88rem; }
table.dose { border-collapse:collapse; width:100%; margin:.3rem 0 .5rem; font-size:.85rem; }
table.dose th, table.dose td { border:1px solid var(--ink-200); padding:.35rem .5rem; text-align:center; }
table.dose th { background:var(--indigo-100); color:var(--indigo-700); font-size:.72rem; }
table.dose th small { display:block; font-size:.6rem; font-weight:600; }
/* dose cell (#422, /static/dose-render.js): the dose to pour carries the accent,
   the range it sits in reads underneath. Shared with the printed FT, which
   scopes the same two classes to its mm-based sheet. */
table.dose .dose-v { font-weight:700; }
table.dose .dose-r { display:block; font-size:.68rem; font-weight:400; color:var(--ink-500); }
table.dose td.dose-none { color:var(--ink-200); }
/* #366 §1.1 — a general range still prints its numbers, under a mark that says
   it is provisional. Never colour-only: the sentence is in the flow. */
.dose-fallback { font-size:.8rem; line-height:1.35; margin:.3rem 0 .4rem; font-style:italic;
  border-left:3px solid var(--ink-200); padding:.35rem 0 .35rem .6rem; background:var(--mist); }
.dose-intro { font-size:.8rem; margin:.3rem 0; color:var(--ink-500); }
ol.steps { padding-left:1.2rem; display:grid; gap:.3rem; font-size:.9rem; margin:.3rem 0; }
ul.notes { padding-left:1.1rem; display:grid; gap:.25rem; font-size:.85rem; margin:.3rem 0; }
.phr { font-size:.82rem; margin:.18rem 0; }
.phr b { font-family:ui-monospace,Consolas,monospace; font-size:.75rem; color:var(--indigo-700); }

/* generated danger label — multilingual warning box derived from CLP codes */
.dl-langs { display:flex; gap:.3rem; margin:.1rem 0 .6rem; }
.dl-lang { border:1px solid var(--ink-200); background:#fff; color:var(--ink-500);
  border-radius:.5rem; padding:.2rem .55rem; font-size:.72rem; font-weight:700;
  letter-spacing:.05em; cursor:pointer; }
.dl-lang.on { background:var(--indigo-700); color:#fff; border-color:var(--indigo-700); }
.danger-label { border:1px solid var(--ink-200); border-radius:.6rem; padding:.6rem .7rem; background:var(--mist); }
.danger-label .dl-head { display:flex; align-items:center; gap:.5rem; flex-wrap:wrap; margin-bottom:.4rem; }
.dl-list { display:grid; gap:.1rem; }
.dl-list.dl-p { margin-top:.5rem; padding-top:.5rem; border-top:1px dashed var(--ink-200); }
.dl-note { font-size:.72rem; color:var(--ink-500); margin-top:.5rem; font-style:italic; }
.pack-grid { display:flex; flex-wrap:wrap; gap:.45rem; }
.pack { display:inline-flex; align-items:center; gap:.35rem; border:1px solid var(--ink-200);
  border-radius:.6rem; padding:.35rem .6rem; font-size:.82rem; }

/* fiche documents — proper names + filetype badge (FT/FDS deep links) */
.doc-links { display:flex; flex-wrap:wrap; gap:.45rem; }
.doc-link { display:inline-flex; align-items:center; gap:.4rem; background:var(--indigo-100);
  color:var(--indigo-700); border-radius:.6rem; font-size:.82rem; font-weight:600;
  padding:.42rem .7rem; text-decoration:none; }
.doc-link svg { flex:none; }
.doc-badge { font-size:.62rem; font-weight:700; letter-spacing:.04em; background:#fff;
  border-radius:.3rem; padding:.1rem .32rem; }

/* The fiche-level language switcher (#369) is gone with #17 ruling 3 — one menu,
   in the header (`#langChip`), on every surface. Its rule went with it: what a
   visitor who cannot read the page has to find is the pulldown in the header
   bar, which is above the fold by construction and in the same place whatever
   they are looking at. */

/* The verified French behind a translated protocol card (#904, card-render.js).
   Quiet, closed and last on both surfaces: it is the evidence, never the answer
   — a visitor reads the card in their own language, and whoever needs to check
   what the rule table actually read is one tap away. Here rather than in either
   page, because the chat and the admin replay must not drift apart on it. */
.card-fr { margin-top:.7rem; border-top:1px dashed var(--ink-200); padding-top:.5rem; }
.card-fr > summary { cursor:pointer; font-size:.72rem; color:var(--ink-500);
  list-style:none; }
.card-fr > summary::before { content:'🇫🇷 '; }
.card-fr[open] > summary { margin-bottom:.5rem; }
