/* Styles of every screen, loaded after tokens.css (base.html, error.html).
   They use the tokens of tokens.css only: no colour, font or size of their own
   (tests/test_static.py). The templates carry classes only, never a style.

   Components, for every template:
   - Page: main.page (forms, 40rem), main.page.page-wide (administration),
     main.chat (chat screen); .rail (navigation bar), .site-footer; .page-header (title and its
     actions on one line, wraps), with .page-intro (the sentence under the title);
     .section-head (a section title and its action on one line).
   - Buttons: <button> and a.button (main action, on the brand colour),
     .button-secondary (outlined), .button-danger (outlined, in the danger colour, for a
     destructive action), .button-quiet (discreet, like a link).
   - Card: .card (surface framed by a line), .card-emphasis (strong border),
     .secret (a value to copy once, inside a card).
   - Status badge of a text (soft ground and border of its meaning, the dot and the word): .status with .status-in_force, .status-draft,
     .status-repealed, .status-replaced, .status-ended (in force, effective period
     ended) (CLAUDE.md, rule 2).
   - Alerts and notices: .alert with .alert-danger, .alert-warning, .alert-success,
     .alert-info (a bar of the state on the left and its glyph); .error is the error alert
     (same as .alert.alert-danger).
   - Badge of a state (handled, active, verdict...): .badge, with .badge-success,
     .badge-danger, .badge-warning, .badge-info; .badge-wrap lets a long text wrap;
     .badge-note (a small line under a badge). Statuses and badges are a dot and the word.
   - Table: .table (.table-compact for the ones read in series), inside .table-wrap (a bare region that scrolls sideways, tabindex="0");
     .number (figures on the right), .nowrap (a cell that never wraps), .cell-sub (a
     secondary line in a cell); a form of a cell stays on one line.
   - Actions of a table row: .row-actions (the usual action on the right), then a .menu
     (<details>) whose .menu-list holds the others.
   - Empty list: .empty-state (one muted sentence). A state that is the normal one is plain text
     (.state-text); only an exception (draft, failed, not useful, replaced...) is a badge.
   - Filter pills: .chips (a row) of .chip (link or button, the chosen one has
     aria-current or aria-pressed); .filters groups several rows.
   - Forms: .form (column of fields), .form-full (whole width), .form-card (a column of sections on the page, no card),
     .form-inline (fields in a row), .field (label and its control), .field-help (help),
     .check (box and its label), .form-actions; in a card, .form-section (a titled block)
     and .form-grid / .form-grid-3 (two or three columns, one on a small screen);
     .dropzone (a file to drop, around its input).
   - Administration: .todo (what waits, on the home), .back-link (link above a title),
     .kpis of .kpi (a row of figures: .kpi-label, .kpi-value, .kpi-note) with a .meter (a native
     <meter> or <progress>, no inline width), .month-picker with its .month-step links.
   - Pagination: .pagination, .pagination-sm (smaller text).
   - Texts: .muted (secondary text), .meta (secondary and smaller), .text-success,
     .text-danger; .details-list (list of properties); .swatch (colour sample).
   Screens (layout only): access screens (.auth*, .totp-qr), administration (.admin, .admin-nav), corpus (.chunk), note
   editor (.note-form, .note-preview), chat (.chat-*, .composer*, .message*, .conversation-date). */

/* Fonts of the design system, hosted in app/static/fonts (OFL licences beside them):
   Fraunces for the titles (axes opsz and wght), Inter Tight for the text (axis wght),
   Latin subset, enough for French and English. No call to a font service (CSP font-src
   'self'); until a file is loaded, the stacks of tokens.css apply. */
@font-face {
  font-family: Fraunces;
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/fraunces-latin-opsz-normal.woff2") format("woff2");
}

@font-face {
  font-family: Fraunces;
  font-style: italic;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/fraunces-latin-opsz-italic.woff2") format("woff2");
}

@font-face {
  font-family: "Inter Tight";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/inter-tight-latin-wght-normal.woff2") format("woff2");
}

@font-face {
  font-family: "Inter Tight";
  font-style: italic;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/inter-tight-latin-wght-italic.woff2") format("woff2");
}

/* Base: the text in Inter Tight at 17 px, the titles in Fraunces */
body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--text-body);
  line-height: var(--leading-body);
  color: var(--ink);
  background: var(--paper);
}

h1, h2, h3, h4 {
  font-family: var(--font-serif);
  font-weight: var(--weight-title);
  letter-spacing: var(--tracking-title);
  line-height: var(--leading-title);
}

code { font-family: var(--font-mono); }

/* Links: the text colour, a thin sky underline set 4 px off, thicker on hover (sky is
   never the colour of a text on a light background) */
a {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--sky);
  text-decoration-thickness: var(--border-width);
  text-underline-offset: 4px;
}

a:hover { text-decoration-thickness: var(--border-strong); }

/* Page */
main {
  max-width: var(--width-page);
  margin: var(--space-8) auto;
  padding: 0 var(--space-4);
}

main.page-wide { max-width: var(--width-wide); }
/* On a very wide screen the administration uses more of it: the tables lose less columns */
@media (min-width: 100rem) {
  main.page-wide { max-width: calc(var(--width-wide) + 8rem); }
}

/* Navigation bar (base.html): vertical on the brand colour, stuck to the left while the
   page scrolls; folded into a horizontal bar above the page below 64 rem. Its current
   entry is said by aria-current, shown by a lighter background and a bold label. */
/* The shell paints the column of the bar on its whole height: the bar itself is 100vh and
   sticky, so on a page taller than the screen the navy continues under it */
.app-shell {
  display: grid;
  grid-template-columns: var(--rail-width) minmax(0, 1fr);
  min-height: 100vh;
  background: linear-gradient(to right, var(--brand) var(--rail-width), var(--paper) var(--rail-width));
}
.app-body { grid-area: 1 / 2; min-width: 0; }
/* Sign-in and code screens have no bar: no coloured column either */
.app-shell.no-rail { grid-template-columns: minmax(0, 1fr); min-height: 0; background: var(--paper); }
.app-shell.no-rail .app-body { grid-area: 1 / 1; }

/* Skip links (WCAG 2.4.1): out of sight until the keyboard focuses them */
.skip-links { position: absolute; top: 0; left: 0; z-index: 10; }
.skip-links a {
  position: absolute;
  top: var(--space-2);
  left: var(--space-2);
  padding: var(--space-2) var(--space-3);
  background: var(--paper);
  color: var(--ink);
  border: 2px solid var(--focus);
  border-radius: var(--radius-sm);
  white-space: nowrap;
  transform: translateY(-300%);
}
.skip-links a:focus { transform: none; }

/* Read by screen readers and password managers, not seen */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* The account and language (.rail-account) come after the page in the markup, for the
   keyboard; they sit in the same cell as the bar, over its bottom, stuck to the bottom of
   the screen. The bar keeps room under its last entry for them. */
.rail {
  grid-area: 1 / 1;
  align-self: start;
  position: sticky;
  top: 0;
  flex: 0 0 var(--rail-width);
  width: var(--rail-width);
  height: 100vh;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--space-3);
  /* The room under the last entry is the one of the account block, which sits over it */
  padding: var(--space-5) var(--space-3) 8rem;
  overflow-y: auto;
  /* A thin scroll bar in the colours of the bar, not the grey one of the browser */
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, var(--on-brand) 35%, var(--brand)) transparent;
  background: var(--brand);
  color: var(--on-brand);
}

.rail a { color: var(--on-brand); text-decoration: none; }
.rail form, .rail-account form { margin: 0; }

/* Logo of the product (macro logo of _macros.html): the same drawing on every screen, in
   the colours of the product, not of the cabinet; the paper tile stands out on any bar */
.logo { display: block; width: 100%; height: 100%; }
.logo-tile { fill: var(--paper); stroke: var(--ink); stroke-width: 3; }
.logo-mark { fill: var(--ink); }
.logo-spark { fill: var(--gold); }
/* Badge of a navigation entry (feedback to review): a small pill at the end of the entry */
.nav-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.25rem;
  height: 1.25rem;
  margin-left: auto;
  padding: 0 var(--space-1);
  box-sizing: border-box;
  border-radius: var(--radius-pill);
  background: var(--danger);
  color: var(--white);
  font-size: var(--text-xs);
  font-weight: var(--weight-strong);
  font-variant-numeric: tabular-nums;
  /* The figures sit in the middle of the pill: one line exactly the height of the pill */
  line-height: 1.25rem;
  text-align: center;
}
.rail-nav a:has(.nav-badge) { grid-template-columns: auto 1fr auto; }
/* In the bar, the edge of the tile and the mark take the blue of the bar (the brand) */
.rail .logo-tile { stroke: var(--brand); }
.rail .logo-mark { fill: var(--brand); }

/* The brand at the top of the bar: the logo and, beside it, the product and the cabinet,
   centred on the logo, aligned on the text of the entries of the bar */
.rail-brand {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
  padding: 0 var(--space-3) var(--space-2);
}
.rail-logo {
  display: block;
  flex: 0 0 auto;
  width: 2.25rem;
  height: 2.25rem;
}

.rail-title {
  min-width: 0;
  margin: 0;
  font-size: var(--text-sm);
  line-height: 1.25;
}

.rail-title .product { display: block; font-family: var(--font-serif); font-size: var(--text-base); font-weight: var(--weight-title); }
.rail-title .cabinet { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--text-meta); }

.rail-nav { display: flex; flex-direction: column; gap: var(--space-1); width: 100%; }

.rail-nav a {
  display: grid;
  grid-auto-flow: column;
  justify-content: start;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
  font-weight: 500;
  transition: background var(--transition);
}

.rail-nav a:hover, .rail-nav a[aria-current] {
  background: color-mix(in srgb, var(--on-brand) 16%, var(--brand));
}

.rail-nav a[aria-current] { font-weight: var(--weight-strong); }

/* Account at the bottom, under a thin line: the languages, then the name of the account
   (its screen) with the logout icon at the right, both aligned on the text of the entries
   of the bar */
.rail-account {
  grid-area: 1 / 1;
  align-self: end;
  position: sticky;
  bottom: 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--space-2);
  box-sizing: border-box;
  width: var(--rail-width);
  padding: var(--space-3) var(--space-3) var(--space-4);
  border-top: var(--border-width) solid color-mix(in srgb, var(--on-brand) 30%, var(--brand));
  background: var(--brand);
  color: var(--on-brand);
}
.rail-account .language { gap: var(--space-3); padding-inline: var(--space-3); }
.rail-account .language button { min-width: 0; padding: 0; }

.logout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-2);
  padding-left: var(--space-3);
}
.user-name { max-width: 100%; font-size: var(--text-sm); font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
a.user-name { color: inherit; text-decoration: none; }
a.user-name:hover { text-decoration: underline; text-decoration-color: var(--sky-2); }
.rail-account button.logout-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border-radius: var(--radius-md);
}
.rail-account button.logout-button:hover {
  background: color-mix(in srgb, var(--on-brand) 16%, var(--brand));
  text-decoration: none;
}
.logout-icon {
  width: 1.125rem;
  height: 1.125rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Second level of the column (base.html, block rail_context): the conversations of the chat,
   the menu of the administration, under the entries of the bar and a fine rule. A wide
   screen shows it always (its summary is hidden); below 64 rem it is a drawer (see the
   media query on the bar). Its texts are in the colour computed for the brand, none dimmed. */
.rail-context {
  margin-top: var(--space-2);
  padding-top: var(--space-3);
  border-top: var(--border-width) solid color-mix(in srgb, var(--on-brand) 30%, var(--brand));
}
.rail-context > summary { display: none; list-style: none; cursor: pointer; }
.rail-context > summary::-webkit-details-marker { display: none; }

.site-footer {
  max-width: var(--width-page);
  margin: var(--space-8) auto;
  padding: 0 var(--space-4);
  color: var(--ink-soft);
  font-size: var(--text-sm);
}

/* Title of a page: the title, its introduction and the main action on one line, wrapping
   on a small screen */
.page-header {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  align-items: baseline;
  justify-content: space-between;
}

.page-header .page-intro { margin: var(--space-2) 0 0; max-width: 40rem; color: var(--ink-soft); font-size: var(--text-base); }
/* The title block takes the room it needs before the action wraps under it: the action
   stays on the right of the title, whatever the length of the introduction */
.page-header > div:first-child { flex: 1 1 24rem; }

/* A form kept folded under the list it complements (launch of an evaluation) */
details.launch { margin: var(--space-6) 0; }
details.launch > summary { cursor: pointer; font-weight: var(--weight-strong); }

/* A section title and its action */
.section-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-4); }

/* Buttons: the pill of the charter on the brand colour, its text black or white
   (contrast.py); no shadow at rest, a darker navy on hover */
button, .button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 2.5rem;
  padding: 0 var(--space-5);
  border: var(--border-width) solid var(--brand);
  border-radius: var(--radius-pill);
  background: var(--brand);
  color: var(--on-brand);
  font: inherit;
  font-size: var(--text-sm);
  font-weight: var(--weight-strong);
  line-height: 1.4;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--transition), color var(--transition),
    transform var(--transition), box-shadow var(--transition);
}

button:hover, .button:hover {
  background: var(--ink-2);
  border-color: var(--ink-2);
  color: var(--white);
  box-shadow: var(--shadow-sm);
  transform: translateY(-1px);
}

button[disabled] { opacity: .6; transform: none; }

.button-secondary {
  background: var(--white);
  color: var(--ink);
  border-color: var(--line-strong);
}

.button-secondary:hover { background: var(--paper-2); border-color: var(--ink); color: var(--ink); }

.button-danger { background: var(--white); border-color: var(--line-strong); color: var(--danger); }
.button-danger:hover { background: var(--danger-soft); border-color: var(--danger); color: var(--danger); }

.button-quiet {
  min-height: 0;
  padding: 0;
  font-size: var(--text-sm);
  border-color: transparent;
  background: transparent;
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--sky);
  text-underline-offset: 4px;
}

.button-quiet:hover { background: transparent; border-color: transparent; color: var(--ink); transform: none; box-shadow: none; text-decoration-thickness: 2px; }

/* Buttons of the navigation bar: language and logout are plain text on the brand colour,
   the current language bold and underlined */
.rail button, .rail-account button {
  min-height: 2rem;
  max-width: 100%;
  padding: 0 var(--space-1);
  border: 0;
  background: transparent;
  color: var(--on-brand);
  font-size: var(--text-xs);
  font-weight: 500;
}

.rail button:hover, .rail-account button:hover {
  background: transparent;
  color: var(--on-brand);
  text-decoration: underline;
  text-decoration-color: var(--sky-2);
  transform: none;
  box-shadow: none;
}

.language { display: flex; }
.language button { min-width: 2rem; }

.language button[disabled] {
  opacity: 1;
  font-weight: var(--weight-strong);
  text-decoration: underline;
  text-decoration-color: var(--sky-2);
  text-underline-offset: 4px;
  cursor: default;
}

/* Card */
.card {
  background: var(--white);
  border: var(--border-width) solid var(--line);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
}

.card-emphasis {
  border: var(--border-strong) solid var(--ink);
  padding: var(--space-3) var(--space-4);
  margin: 0 0 var(--space-4);
}

/* 403 page of a signed-in account (error_nav.html): a few lines on the page, no card */
.error-card { display: grid; gap: var(--space-4); max-width: 34rem; padding: var(--space-6) 0; background: none; border: 0; box-shadow: none; }
.error-card > * { margin: 0; }

/* A password shown once: the alert holds paragraphs (title and name, the password alone on
   its line, the warning), stacked and not side by side like the one-line alerts */
.alert.secret { display: block; }
.alert.secret p { margin: 0 0 var(--space-2); }
.alert.secret p:last-child { margin-bottom: 0; }
.secret code { font-size: var(--text-lg); user-select: all; overflow-wrap: anywhere; }

/* A list with nothing in it: one muted sentence, no frame */
.empty-state {
  padding: var(--space-6) 0;
  color: var(--ink-soft);
}

.empty-state strong { display: block; color: var(--ink); }

/* Status badge of a text, as stored (CLAUDE.md, rule 2): a draft reads "not in force",
   a repealed or replaced text never reads in force. Badge of a state of an administration
   screen (handled or to review, active, locked, a verdict...): same shape, the state is
   always in its words. A dot on a neutral ground carries the colour, which only helps;
   .badge-success, .badge-danger, .badge-warning, .badge-info colour the dot */
.status, .badge {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .05rem .6rem .05rem .5rem;
  border: var(--border-width) solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--white);
  color: var(--ink);
  font-size: var(--text-xs);
  font-weight: 500;
  line-height: 1.6;
  white-space: nowrap;
}

.status::before, .badge::before {
  content: "";
  flex: none;
  width: .45rem;
  height: .45rem;
  border-radius: 50%;
  background: var(--line-strong);
}

.badge { line-height: 1.4; }
.badge-wrap { white-space: normal; border-radius: var(--radius-lg); }
.badge-note { display: block; margin-top: var(--space-1); color: var(--ink-soft); font-size: var(--text-xs); }

/* The normal state of a row (useful, active, in force, sourced...): plain words, no pill. A
   state that asks for a look (to review, draft, failed, not useful) stays a badge or is bold. */
.state-text { color: var(--ink-soft); }
.state-text.is-open { color: var(--ink); }

/* One reduced set, the same for statuses and states: a soft ground and a border of the
   colour of the meaning (success, info, warning, danger), the dot in its darkest variant,
   the word in the text colour (AA, tests/test_static.py). A draft ("not in force") is
   in the info set so that it never passes for a text in force (rule 2). */
.status-in_force, .badge-success { background: var(--success-soft); border-color: var(--success); }
.status-draft, .badge-info { background: var(--sky-soft); border-color: var(--sky); }
.badge-warning { background: var(--warning-soft); border-color: var(--warning); }
.status-ended, .status-unknown, .badge-danger { background: var(--danger-soft); border-color: var(--danger); }
.status-in_force::before, .badge-success::before { background: var(--success); }
.status-draft::before, .badge-info::before { background: var(--ink); }
.badge-warning::before { background: var(--warning); }
.status-ended::before, .status-unknown::before, .badge-danger::before { background: var(--danger); }
.status-replaced { background: var(--paper-2); border-color: var(--control); }
.status-repealed { background: var(--ink); border-color: var(--ink); color: var(--white); }
.status-repealed::before { background: var(--white); }

/* Alerts and notices: a white ground, a frame tinted with the colour of the state */
.alert, .error {
  display: flex;
  gap: var(--space-2);
  align-items: baseline;
  padding: var(--space-3) var(--space-4);
  border: var(--border-width) solid var(--line);
  border-radius: var(--radius-md);
  background: var(--white);
  color: var(--ink);
  font-size: var(--text-sm);
}

.alert strong, .error strong { flex: none; }
/* A hidden alert stays hidden: the display above would otherwise win over [hidden] */
.alert[hidden], .error[hidden] { display: none; }

/* A state-coloured bar on the left (like .message-notice) and a glyph in front, so a notice
   stands out from a card and is never said by its colour alone; the glyph carries the
   colour of the state in its text variant (contrast AA on the tinted ground). The target of
   an action (#done) keeps room above it when the page scrolls to it. */
.alert, .error { border-left-width: var(--accent-bar); scroll-margin-top: var(--space-8); }
.alert:not(.secret)::before, .error::before {
  content: "!";
  flex: none;
  min-width: 1em;
  font-weight: var(--weight-strong);
  text-align: center;
}
.alert-danger, .error { border-color: color-mix(in srgb, var(--danger) 35%, var(--white)); border-left-color: var(--danger); background: color-mix(in srgb, var(--danger-soft) 50%, var(--white)); }
.alert-danger::before, .error::before { color: var(--danger); }
.alert-warning { border-color: color-mix(in srgb, var(--warning) 35%, var(--white)); border-left-color: var(--warning); background: color-mix(in srgb, var(--warning-soft) 60%, var(--white)); }
.alert-warning::before { color: var(--warning); }
.alert-success { border-color: color-mix(in srgb, var(--success) 35%, var(--white)); border-left-color: var(--success); background: color-mix(in srgb, var(--success-soft) 50%, var(--white)); }
.alert-success:not(.secret)::before { content: "\2713"; color: var(--success-text); }
.alert-info { border-color: color-mix(in srgb, var(--sky) 45%, var(--white)); border-left-color: var(--sky); background: color-mix(in srgb, var(--sky-soft) 60%, var(--white)); }
.alert-info::before { content: "i"; color: var(--ink); }

/* Table */
/* The table sits on the page, with no frame: it scrolls sideways inside its region on a small
   screen (the region takes the keyboard focus, tabindex="0" in the templates), and the shadow
   on the side that hides more columns says so. A rule under the header row, a hairline between
   the rows, header cells in plain small text, a hovered row is lightened. */
.table-wrap {
  /* Positioned: a hidden label of a header cell (.visually-hidden, absolute) stays inside
     the region instead of widening the page */
  position: relative;
  overflow-x: auto;
  margin: var(--space-4) 0;
  /* Shadows on the sides that hide more columns: the white ones scroll with the table
     (local) and cover the grey ones (scroll) once an end is reached */
  background:
    linear-gradient(to right, var(--paper) 30%, transparent) left center / 2.5rem 100% no-repeat local,
    linear-gradient(to left, var(--paper) 30%, transparent) right center / 2.5rem 100% no-repeat local,
    linear-gradient(to right, color-mix(in srgb, var(--ink) 22%, transparent), transparent) left center / .75rem 100% no-repeat scroll,
    linear-gradient(to left, color-mix(in srgb, var(--ink) 22%, transparent), transparent) right center / .75rem 100% no-repeat scroll,
    var(--paper);
}

.table-wrap:focus-visible { outline-offset: -3px; }

/* A table whose rows open a menu does not scroll on a wide screen: a scrolling frame would
   clip the menu. Below 64 rem it scrolls again and the menu opens inside the row. */
.table-wrap:has(.menu) { overflow: visible; }

.table { width: 100%; border-collapse: collapse; font-size: var(--text-table); }

.table th, .table td {
  text-align: left;
  padding: var(--space-3) var(--space-4);
  border-bottom: var(--border-width) solid var(--line);
  vertical-align: middle;
}

.table th:first-child, .table td:first-child { padding-left: 0; }
.table th:last-child, .table td:last-child { padding-right: 0; }

.table thead th {
  border-bottom-color: var(--line-strong);
  color: var(--ink-soft);
  font-size: var(--text-sm);
  font-weight: var(--weight-strong);
  white-space: nowrap;
}

.table tbody th { font-weight: 500; }
.table tbody tr:hover { background: var(--paper-2); }
.table tbody tr:last-child > * { border-bottom: 0; }
.table td { overflow-wrap: break-word; }
.table td.number, .table th.number { text-align: right; white-space: nowrap; overflow-wrap: normal; font-variant-numeric: tabular-nums; }
.table td.nowrap, .table th.nowrap { white-space: nowrap; overflow-wrap: normal; }
/* Dense variant, for the tables read in series (feedback, exchanges, audit, usage): one line
   per row where it can, tighter cells, the actions of a row wrap instead of leaving the frame.
   The tables of accounts and documents keep their air. */
.table-compact th, .table-compact td { padding: var(--space-2); }
.table-compact .row-actions { flex-wrap: wrap; }
/* The icon buttons of a row stay side by side on one line, whatever the width of the other
   columns: the cell takes the width of its icons (1%, grown by the content that cannot
   wrap) instead of being squeezed by a long comment, which stacked them */
.table td:has(> .row-actions .icon-button) { width: 1%; white-space: nowrap; }
.row-actions:has(.icon-button) { flex-wrap: nowrap; }
.row-actions form { flex-wrap: nowrap; margin: 0; }
/* The title of a row keeps a readable width: the narrow columns around it do not squeeze it */
.table td.cell-title { min-width: 16rem; }
/* A second line (an e-mail address, a code) may break anywhere: a long one never makes the
   table wider than its frame. A badge in a cell wraps instead of leaving it. */
.table .cell-sub { display: block; color: var(--ink-soft); font-size: var(--text-xs); overflow-wrap: anywhere; }
.table td .badge { white-space: normal; border-radius: var(--radius-lg); }
/* A state under a figure (ingestion of a document) is not squeezed to one word per line */
.table td .cell-sub .badge { min-width: 7rem; }
.table tfoot th, .table tfoot td { border-top: var(--border-width) solid var(--line-strong); border-bottom: 0; font-weight: var(--weight-strong); }
.table form { display: inline-flex; flex-wrap: wrap; gap: var(--space-1); margin: 0 0 var(--space-1); max-width: 100%; }
.table td select { max-width: 100%; }

/* Actions in a row: outlined pills, smaller than the main button of the screen */
.table td button, .table td .button {
  min-height: 2rem;
  padding: 0 var(--space-3);
  border-color: var(--line-strong);
  background: var(--white);
  color: var(--ink);
  font-size: var(--text-xs);
  font-weight: var(--weight-strong);
}

.table td button:hover, .table td .button:hover { background: var(--paper-2); border-color: var(--ink); color: var(--ink); transform: none; box-shadow: none; }

/* The actions of a row: the usual one, then a menu (<details>) for the others */
.row-actions { position: relative; display: flex; justify-content: flex-end; align-items: center; gap: var(--space-2); }
/* A note beside the actions ("managed by the cabinet") stays short: two lines at most */
.row-actions .meta { max-width: 9rem; text-align: right; }
.menu { position: relative; }

.menu > summary {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 2rem;
  box-sizing: border-box;
  padding: 0 var(--space-3);
  border: var(--border-width) solid var(--line-strong);
  border-radius: var(--radius-pill);
  background: var(--white);
  color: var(--ink);
  font-size: var(--text-xs);
  font-weight: var(--weight-strong);
  list-style: none;
  cursor: pointer;
}

.menu > summary::-webkit-details-marker { display: none; }
.menu > summary::after { content: "\25BE"; font-size: .7em; }

.menu-list {
  position: absolute;
  top: calc(100% + var(--space-1));
  right: 0;
  z-index: 5;
  display: grid;
  min-width: 15rem;
  margin: 0;
  padding: var(--space-1);
  list-style: none;
  background: var(--white);
  border: var(--border-width) solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
}

.table .menu-list form { display: block; margin: 0; }

.table td .menu-list button {
  display: block;
  width: 100%;
  min-height: 2.25rem;
  padding: 0 var(--space-3);
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--ink);
  font-size: var(--text-sm);
  font-weight: 400;
  text-align: left;
}

.table td .menu-list button:hover { background: var(--paper-2); color: var(--ink); }
.table td .menu-list .danger { color: var(--danger); }
.table td .menu-list a {
  display: flex;
  align-items: center;
  min-height: 2.25rem;
  padding: 0 var(--space-3);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  text-decoration: none;
}
.table td .menu-list a:hover { background: var(--paper-2); }
.menu-list hr { margin: var(--space-1) 0; border: 0; border-top: var(--border-width) solid var(--line); }

/* Forms. A label alone (login, password) is a block with its field under it */
label { display: block; margin: var(--space-3) 0; }

input[type=email], input[type=password] {
  display: block;
  width: 100%;
  box-sizing: border-box;
  margin-top: var(--space-1);
  padding: var(--space-2);
}

input[type=checkbox], input[type=radio] { accent-color: var(--ink); }

.form { display: grid; gap: var(--space-3); max-width: var(--width-form); }
.form-full { max-width: none; }

/* A group of choices: its title, then the choices, no frame (a refused group has its red border) */
.form fieldset {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.field { display: flex; flex-direction: column; gap: var(--space-1); margin: 0; }

/* No `font` here: a field takes its own font from the administration rule below, not the
   14 px bold of its label */
.form-full .field input[type=text], .form-full .field select, .form-full .field textarea {
  width: 100%;
  box-sizing: border-box;
}

.field-help { color: var(--ink-soft); font-size: var(--text-sm); font-weight: 400; }

.check, .form fieldset label { display: flex; flex-direction: row; align-items: center; gap: .4rem; margin: 0; }
/* A choice with a help line under its title: the box stays level with the title */
.check, .form fieldset label.check { align-items: flex-start; }
.check .field-help { display: block; }
/* The title of a group of choices is the size of the label of a field */
.form legend { padding: 0 0 var(--space-2); font-size: var(--text-sm); font-weight: var(--weight-strong); }
/* A control and its value written out beside it (the colour and its #RRGGBB code) */
.field-inline { display: flex; align-items: center; gap: var(--space-3); }
.form-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }

.form-inline {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  align-items: flex-end;
  margin: var(--space-4) 0;
}

.form-inline .field { font-size: var(--text-sm); }

/* Controls of the administration: one style of field, the border of a field is `control`,
   a visible focus ring (:focus-visible below). The label is bold, what is typed is not. */
.admin-content .field { font-size: var(--text-sm); font-weight: var(--weight-strong); }
.admin-content .field .meta { font-weight: 400; }

.admin-content select,
.admin-content textarea,
.admin-content input[type=text],
.admin-content input[type=search],
.admin-content input[type=email],
.admin-content input[type=url],
.admin-content input[type=date],
.admin-content input[type=month],
.admin-content input[type=number],
.admin-content input[type=file] {
  box-sizing: border-box;
  min-height: 2.75rem;
  padding: 0 var(--space-3);
  border: var(--border-width) solid var(--control);
  border-radius: var(--radius-sm);
  background: var(--white);
  color: var(--ink);
  font: inherit;
  font-size: var(--text-base);
  font-weight: 400;
}

.admin-content select,
.admin-content textarea,
.admin-content input[type=text],
.admin-content input[type=search],
.admin-content input[type=email],
.admin-content input[type=url],
.admin-content input[type=number] { width: 100%; }

.admin-content textarea { padding: var(--space-2) var(--space-3); }

/* A refused value: the field the message is about has a border in the danger colour (after
   the rules of the fields above, which set their own border) */
.admin-content input[aria-invalid="true"], .admin-content select[aria-invalid="true"],
.admin-content textarea[aria-invalid="true"] { border-color: var(--danger); }
.admin-content .form fieldset.invalid { padding-left: var(--space-3); border-left: var(--accent-bar) solid var(--danger); }
.admin-content input[type=email], .admin-content input[type=password] { margin-top: 0; }
.admin-content input::placeholder { color: var(--ink-soft); }

.admin-content select {
  appearance: none;
  padding-right: 2.25rem;
  background-image: linear-gradient(45deg, transparent 50%, var(--ink-soft) 50%), linear-gradient(135deg, var(--ink-soft) 50%, transparent 50%);
  background-position: calc(100% - 1.15rem) 52%, calc(100% - .8rem) 52%;
  background-size: .35rem .35rem, .35rem .35rem;
  background-repeat: no-repeat;
}

/* A form of a screen (invitation, tenant, import, launch of an evaluation), on the page with no
   card: its sections are separated by space and a rule, its actions are on the right under a rule */
.form-card {
  box-sizing: border-box;
  width: 100%;
  max-width: 48rem;
  padding: 0;
}

.form-card > * { min-width: 0; }
/* The editor of a note takes the width of the content, like the lists (not a narrower column
   left on the side) */
.form-card.form-full { max-width: none; }
/* A help paragraph in a form: the gap of the grid is the only space around it */
.form > p, .form-card > p { margin: 0; }

.form-section { display: grid; gap: var(--space-4); padding: var(--space-6) 0; border-top: var(--border-width) solid var(--line); }
.form-section:first-of-type { border-top: 0; padding-top: 0; }
.admin-content .form-section h2 { margin: 0; font-size: var(--text-lg); }

.form-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-4); }
.form-grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }

.form-card .form-actions { justify-content: flex-end; margin-top: var(--space-2); padding-top: var(--space-5); border-top: var(--border-width) solid var(--line); }

/* File to drop: a dashed zone around its input */
.dropzone {
  display: grid;
  justify-items: center;
  gap: var(--space-1);
  padding: var(--space-6) var(--space-4);
  border: var(--border-width) dashed var(--control);
  border-radius: var(--radius-md);
  background: var(--paper);
  font-weight: 400;
  text-align: center;
  cursor: pointer;
}

.dropzone:focus-within { outline: var(--focus-width) solid var(--focus); outline-offset: 2px; }
.dropzone strong { font-weight: var(--weight-strong); text-decoration: underline; text-decoration-color: var(--sky); text-underline-offset: 4px; }

/* The scripts of the administration (admin_upload.js, admin_progress.js, admin_editor.js):
   a file dragged over the zone, the file chosen, a long task followed on the page, the
   buttons and the count of the editor of a note. Each is complete without the script. */
.dropzone.is-dragover { border-style: solid; border-color: var(--ink); background: var(--sky-soft); }
.dropzone-file { margin: var(--space-2) 0 0; color: var(--ink-soft); font-size: var(--text-sm); }
.dropzone-file:empty { display: none; }
.dropzone-error { margin: var(--space-2) 0 0; }

.task-progress { flex-direction: column; align-items: stretch; gap: var(--space-1); }
.task-progress p { margin: 0; }
/* The rail on the tinted block of an alert: white, with a rule, so that the bar is seen */
.task-progress progress.meter {
  margin-top: var(--space-2);
  border: var(--border-width) solid var(--line-strong);
  background: var(--white);
}
.task-progress progress.meter::-webkit-progress-bar { background: var(--white); }
.task-progress-actions { display: flex; flex-wrap: wrap; gap: var(--space-4); margin-top: var(--space-2); font-size: var(--text-sm); }

.editor-toolbar { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.editor-toolbar[hidden] { display: none; }
.editor-tool {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--target-touch);
  min-height: var(--target-touch);
  padding: 0 var(--space-2);
  border: var(--border-width) solid var(--control);
  border-radius: var(--radius-md);
  background: var(--white);
  color: var(--ink);
  font: inherit;
  font-size: var(--text-sm);
  cursor: pointer;
}
.editor-tool:hover { background: var(--paper-2); border-color: var(--ink); }
/* Icon of a button of the toolbar (admin_visual_editor.js), drawn in strokes of the text colour */
.editor-tool-icon {
  display: block;
  width: 1.25rem;
  height: 1.25rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.editor-count.is-over { color: var(--danger); font-weight: var(--weight-strong); }

.dropzone .glyph {
  display: grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  background: var(--sky-soft);
  font-family: var(--font-serif);
  font-size: var(--text-xl);
}

/* Link back to the list, above the title of a sheet or a form */
.back-link { margin: 0 0 var(--space-3); font-size: var(--text-sm); }
.back-link a:first-child::before { content: "\2190\00a0"; }

/* Filters of a list: a card bar (.form-inline above) holding the fields, or the pills below */
/* Filter pills: links (current one said by aria-current) or buttons (aria-pressed). The
   chosen pill is filled and carries a tick, so the choice never rests on its colour. */
.filters { margin: var(--space-4) 0; }
.filters .chips { margin: var(--space-2) 0; }
.chips { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin: var(--space-4) 0; }
.chips .chips-label { margin-right: var(--space-1); color: var(--ink-soft); font-size: var(--text-sm); }

.chip, button.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 2.25rem;
  box-sizing: border-box;
  padding: 0 var(--space-4);
  border: var(--border-width) solid var(--control);
  border-radius: var(--radius-pill);
  background: var(--white);
  color: var(--ink);
  box-shadow: none;
  font-size: var(--text-sm);
  font-weight: 500;
  text-decoration: none;
  transition: background var(--transition), color var(--transition);
}

.chip:hover, button.chip:hover { background: var(--sky-soft); border-color: var(--control); color: var(--ink); box-shadow: none; transform: none; }

.chip[aria-current], .chip[aria-pressed="true"],
.chip[aria-current]:hover, .chip[aria-pressed="true"]:hover {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--white);
  font-weight: var(--weight-strong);
}

.chip[aria-current]::before, .chip[aria-pressed="true"]::before { content: "\2713"; }

/* Pagination: previous, current page, next, as pills; a form may join them */
.pagination {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  align-items: center;
  margin: var(--space-4) 0;
}

.pagination a {
  display: inline-flex;
  align-items: center;
  min-height: 2.25rem;
  box-sizing: border-box;
  padding: 0 var(--space-4);
  border: var(--border-width) solid var(--control);
  border-radius: var(--radius-pill);
  background: var(--white);
  text-decoration: none;
}

.pagination a:hover { background: var(--sky-soft); }
.pagination form { display: flex; gap: var(--space-2); align-items: center; }
.pagination label { margin: 0; }
.pagination-sm { font-size: var(--text-sm); }

/* Filter bar above a list (filter_bar): no card, one line of fields that wraps by whole fields,
   then the way back (only when a filter is set) and the number of results, level with the last
   row. A set field has the ink border. With the script (data-filter-bar) the Filter button goes. */
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-4);
  align-items: flex-end;
  box-sizing: border-box;
  margin: var(--space-4) 0 var(--space-3);
}
.filter-fields { display: contents; }
.filter-fields .field { flex: 0 1 10rem; min-width: 7.5rem; }
.filter-fields .field:has(> input[type=search]) { flex: 1 1 12rem; max-width: 20rem; }
.filter-fields .field input:not([type=checkbox]), .filter-fields .field select { width: 100%; box-sizing: border-box; }
.filter-fields .check { align-self: flex-end; min-height: 2.5rem; font-size: var(--text-sm); }
.filter-fields .period-picker.is-enhanced { flex: 0 1 13rem; min-width: 10rem; }
.filter-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3) var(--space-4); min-height: 2.5rem; }
.filter-bar[data-filter-bar].is-live .filter-apply { display: none; }
.filter-count { color: var(--ink-soft); font-size: var(--text-sm); }
.filter-bar.is-busy .filter-count { opacity: .6; }
.field.is-set { color: var(--ink); }
.admin-content .field.is-set select, .admin-content .field.is-set input { border-color: var(--ink); }
[data-filter-results].is-busy { opacity: .65; transition: opacity var(--transition); }
/* The fields of a filter bar are compact: a smaller height and text than the fields of a form
   (a list is read, the filters are a tool beside it); 44 px again under a coarse pointer */
.filter-bar .field select,
.filter-bar .field input:not([type=checkbox]),
.filter-bar button.period-trigger {
  min-height: 2.25rem;
  height: 2.25rem;
  padding-top: 0;
  padding-bottom: 0;
  font-size: var(--text-sm);
}
.filter-bar .filter-actions, .filter-fields .check { min-height: 2.25rem; }
@media (max-width: 47.9375rem) {
  .filter-bar { gap: var(--space-3); }
  .filter-fields .field { flex: 1 1 8rem; max-width: none; min-width: 0; }
  .filter-fields .field:has(> input[type=search]), .filter-fields .period-picker.is-enhanced { flex: 1 1 100%; max-width: none; min-width: 0; }
}

/* A form in a card that takes the whole width of the screen (the invitation of a user) */
.form-card.form-wide { max-width: none; }

/* A section folded under its title (the invitation, the technical details of a document): the
   summary is the title, with a chevron; admin_disclosure.js opens it for #id */
.disclosure { margin: var(--space-5) 0; }
.disclosure > summary {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  cursor: pointer;
  list-style: none;
}
.disclosure > summary::-webkit-details-marker { display: none; }
.disclosure > summary::before { content: "\25B8"; color: var(--ink-soft); font-size: .8em; }
.disclosure[open] > summary::before { content: "\25BE"; }
.disclosure > summary h2 { margin: 0; }
.disclosure-quiet { margin: var(--space-3) 0; }
.disclosure-quiet > summary { color: var(--ink-soft); font-size: var(--text-sm); }
.disclosure[open] > summary { margin-bottom: var(--space-3); }

/* Technical lines of an audit entry, in the folded menu of its row */
.menu-detail li { display: grid; gap: var(--space-1); padding: var(--space-2) var(--space-3); }
.menu-detail code { overflow-wrap: anywhere; }

/* Filter bar folded behind one button (admin_filter_toggle.js adds it and .is-collapsible):
   under 48 rem only, the search field stays in view; the wide screen never shows the button */
.filter-toggle { display: none; }
@media (max-width: 47.9375rem) {
  .filter-bar.is-collapsible .filter-toggle { display: inline-flex; align-items: center; min-height: 2.25rem; }
  .filter-bar.is-collapsible:not(.is-open) .filter-fields > :not(:has(input[type=search])),
  .filter-bar.is-collapsible:not(.is-open) .filter-actions > :not(.filter-count) { display: none; }}

/* Grouped actions above a table (select all, then the buttons of the selection) */
.bulk-bar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  align-items: center;
  margin: var(--space-3) 0;
}
/* The script hides the bar until a row is checked, and a button that has nothing to do */
.bulk-bar[hidden], .bulk-bar button[hidden] { display: none; }
.bulk-count { color: var(--ink-soft); font-size: var(--text-sm); font-weight: var(--weight-strong); }
.table th.select-cell, .table td:has(> input[data-select-item]) { width: 2.5rem; }
.bulk-bar label { margin: 0; font-size: var(--text-sm); }
.bulk-bar button { min-height: 2rem; font-size: var(--text-sm); }

/* Compact icon button of a table row: 32 px with a mouse, 44 px on a touch screen (see the
   pointer: coarse block below) */
.icon-button, .table td .icon-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  width: 2rem;
  min-width: 2rem;
  height: 2rem;
  min-height: 2rem;
  padding: 0;
  border: var(--border-width) solid var(--line-strong);
  border-radius: var(--radius-pill);
  background: var(--white);
  color: var(--ink);
  text-decoration: none;
  cursor: pointer;
}
.icon-button:hover, .table td .icon-button:hover { background: var(--paper-2); border-color: var(--ink); color: var(--ink); transform: none; box-shadow: none; }
.icon-button .icon { display: block; flex: none; }

.pagination-range { color: var(--ink-soft); font-size: var(--text-sm); }
.pagination [aria-current="page"] { font-weight: var(--weight-strong); }
.pagination form input[type=number] { width: 5rem; }

/* Header of a sortable column: a link, the arrow only says the way (aria-sort says it too) */
.sort-link { color: inherit; text-decoration: none; white-space: nowrap; }
.sort-link:hover { text-decoration: underline; }
th[aria-sort] .sort-link { color: var(--ink); }

/* Texts */
.muted { color: var(--ink-soft); }
.meta { color: var(--ink-soft); font-size: var(--text-sm); }
.text-success { color: var(--success-text); }
.text-danger { color: var(--danger); font-weight: var(--weight-strong); }

.details-list {
  display: grid;
  grid-template-columns: minmax(9rem, 14rem) 1fr;
  gap: var(--space-2) var(--space-4);
  margin: var(--space-4) 0;
  padding: var(--space-4) 0;
  border-top: var(--border-width) solid var(--line);
  border-bottom: var(--border-width) solid var(--line);
}

/* The trace of an exchange: two pairs per line, in the size of a table, so that the figures
   weigh less than the question and the answer above them */
.details-list-compact {
  grid-template-columns: max-content minmax(0, 1fr) max-content minmax(0, 1fr);
  gap: var(--space-1) var(--space-4);
  padding: var(--space-3) 0;
  font-size: var(--text-table);
}

@media (max-width: 47.9375rem) {
  .details-list-compact { grid-template-columns: max-content minmax(0, 1fr); }
}

.details-list dt { color: var(--ink-soft); }
.details-list dd { margin: 0; overflow-wrap: anywhere; }

/* Colour sample: an SVG filled with the colour shown beside it */
.swatch {
  display: inline-block;
  width: .9rem;
  height: .9rem;
  border: var(--border-width) solid var(--ink-soft);
  border-radius: var(--radius-sm);
  vertical-align: middle;
}

/* Key figures of a screen: a row, each a label, a figure, a note, between two rules, no card */
.kpis { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-4) var(--space-6); margin: 0 0 var(--space-6); padding: var(--space-4) 0; border-top: var(--border-width) solid var(--line); border-bottom: var(--border-width) solid var(--line); }
.kpi { padding: 0; }
.kpi-label { margin: 0; color: var(--ink-soft); font-size: var(--text-sm); }

.kpi-value {
  margin: var(--space-1) 0 0;
  font-family: var(--font-serif);
  font-size: 2rem;
  font-weight: var(--weight-title);
  letter-spacing: var(--tracking-title);
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}

.kpi-note { margin: var(--space-1) 0 0; color: var(--ink-soft); font-size: var(--text-xs); }
/* The answers by mode: the label and its figure on one line each, nothing to decode */
.kpi-modes { display: grid; gap: var(--space-1); margin: var(--space-1) 0 0; padding: 0; list-style: none; }
.kpi-modes li { display: flex; justify-content: space-between; gap: var(--space-3); }
.kpi-modes strong { font-variant-numeric: tabular-nums; }
/* A model name stays on one line */
code.nowrap { white-space: nowrap; }

/* Gauge: a native <meter> or <progress> (its value is set by the attribute, never by a
   style), a thin rail in paper-2 and its bar in the text colour */
progress.meter, meter.meter {
  appearance: none;
  display: block;
  width: 100%;
  height: .375rem;
  margin-top: var(--space-3);
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--paper-2);
  color: var(--ink);
  overflow: hidden;
}

progress.meter::-webkit-progress-bar { background: var(--paper-2); }
progress.meter::-webkit-progress-value { background: var(--ink); border-radius: var(--radius-pill); }
progress.meter::-moz-progress-bar { background: var(--ink); border-radius: var(--radius-pill); }
meter.meter::-webkit-meter-bar { height: .375rem; border: 0; background: var(--paper-2); }
meter.meter::-webkit-meter-optimum-value,
meter.meter::-webkit-meter-suboptimum-value,
meter.meter::-webkit-meter-even-less-good-value { background: var(--ink); }
meter.meter::-moz-meter-bar { background: var(--ink); }

/* Month picker: previous, the month, next, then a menu of the months */
.month-picker { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }

.month-step {
  display: inline-grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  border: var(--border-width) solid var(--line-strong);
  border-radius: 50%;
  background: var(--white);
  color: var(--ink);
  text-decoration: none;
}

.month-step:hover { background: var(--paper-2); border-color: var(--ink); }
.month-step[aria-disabled="true"] { opacity: .4; }
.admin-content .month-picker select { width: auto; min-width: 11rem; }

/* Administration (admin/base.html): the screen only; its menu is the second level of the
   navigation column (.rail-context), below */
.admin { display: block; }

/* Menu of the role, in the column on the brand colour: bare links, the current one said by
   aria-current (bold with a rule on its left, never the colour alone) */
.admin-nav { box-sizing: border-box; }

.admin-nav ul { display: grid; gap: var(--space-1); list-style: none; margin: 0; padding: 0; }

.admin-nav a {
  display: flex;
  align-items: center;
  min-height: 2.25rem;
  box-sizing: border-box;
  padding: 0 var(--space-3);
  border-left: var(--border-strong) solid transparent;
  color: var(--on-brand);
  font-size: var(--text-sm);
  text-decoration: none;
  transition: background var(--transition);
}

.admin-nav a:hover { background: color-mix(in srgb, var(--on-brand) 16%, var(--brand)); }
.admin-nav a[aria-current] { border-left-color: var(--on-brand); color: var(--on-brand); font-weight: var(--weight-strong); }
/* Title of the second list of the menu (the screens of the platform) */
.admin-nav .admin-group { color: var(--on-brand); margin: var(--space-4) 0 var(--space-1); padding: var(--space-3) var(--space-3) 0; border-top: var(--border-width) solid color-mix(in srgb, var(--on-brand) 30%, var(--brand)); font-size: var(--text-sm); font-weight: var(--weight-strong); }

/* Scope above the menu: the cabinet administered, or every cabinet (Connexus) */
.admin-scope {
  margin: 0 0 var(--space-2);
  padding: 0 var(--space-3);
  color: var(--on-brand);
  font-size: var(--text-sm);
  font-weight: var(--weight-strong);
  overflow-wrap: anywhere;
}

.admin-content { flex: 1; min-width: 0; }

/* Titles of a screen: Fraunces, the title then a secondary introduction */
.admin-content h1 { margin: 0 0 var(--space-2); font-size: 2.25rem; overflow-wrap: anywhere; }
.admin-content h2 { margin: var(--space-8) 0 var(--space-3); font-size: var(--text-xl); }
.admin-content h1 + p, .admin-content .page-header + p { max-width: 40rem; color: var(--ink-soft); font-size: var(--text-base); }
.admin-content .page-header { align-items: flex-end; margin-bottom: var(--space-6); }
.admin-content .page-header h1 { margin: 0; }

/* Home of the administration: the dashboard of the month, flat. The month, three figures (each
   a link to its screen), then what waits and the screens in two columns (one under 48 rem) */
.admin-content .page-header .home-month-name { margin: 0; color: var(--ink-soft); font-size: var(--text-lg); text-transform: capitalize; }
.home-figures {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-4) var(--space-6);
  margin: 0 0 var(--space-8);
  padding: var(--space-4) 0;
  border-top: var(--border-width) solid var(--line);
  border-bottom: var(--border-width) solid var(--line);
}
.home-figure { display: flex; flex-direction: column; gap: var(--space-1); color: var(--ink); text-decoration: none; }
.home-figure:hover .home-figure-label, .home-figure:focus-visible .home-figure-label { text-decoration: underline; }
.home-figure-value {
  font-family: var(--font-serif);
  font-size: 2.5rem;
  font-weight: var(--weight-title);
  letter-spacing: var(--tracking-title);
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.home-figure-ceiling { color: var(--ink-soft); font-size: var(--text-xl); }
.home-figure-label { color: var(--ink-soft); font-size: var(--text-sm); }
.home-budget { display: flex; flex-direction: column; gap: var(--space-1); }
progress.home-meter { margin-top: var(--space-2); max-width: 16rem; }
progress.home-meter-info::-webkit-progress-value { background: var(--sky); }
progress.home-meter-info::-moz-progress-bar { background: var(--sky); }
progress.home-meter-alert::-webkit-progress-value { background: var(--warning); }
progress.home-meter-alert::-moz-progress-bar { background: var(--warning); }
progress.home-meter-danger::-webkit-progress-value { background: var(--danger); }
progress.home-meter-danger::-moz-progress-bar { background: var(--danger); }
/* The screens as light cards (white, a thin line, no shadow at rest), the whole card clickable
   through its name; what waits there inside it, set forward */
.home-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
  gap: var(--space-4);
  margin: 0 0 var(--space-6);
  padding: 0;
  list-style: none;
}
.home-card {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--space-3);
  min-height: 5.5rem;
  box-sizing: border-box;
  padding: var(--space-4) var(--space-5);
  border: var(--border-width) solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--white);
  transition: border-color var(--transition), box-shadow var(--transition);
}
.home-card:hover, .home-card:focus-within { border-color: var(--control); box-shadow: var(--shadow-sm); }
.home-section { font-family: var(--font-serif); font-size: var(--text-lg); color: var(--ink); text-decoration: none; }
.home-section::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.home-card > a + a { position: relative; z-index: 1; align-self: flex-start; color: var(--ink); font-size: var(--text-sm); font-weight: var(--weight-strong); }
.home-latest h2 { margin-top: 0; }
.home-list { display: grid; margin: 0; padding: 0; list-style: none; }
.home-list li { display: flex; justify-content: space-between; align-items: baseline; gap: var(--space-3); padding: var(--space-2) 0; border-bottom: var(--border-width) solid var(--line); }
.home-list a { color: var(--ink); text-decoration: none; }
.home-list a:hover, .home-list a:focus-visible { text-decoration: underline; }
.home-todo a::before { content: ""; display: inline-block; width: .5rem; height: .5rem; margin-right: var(--space-2); border-radius: 50%; background: var(--warning); }
.home-count { color: var(--ink-soft); font-size: var(--text-sm); white-space: nowrap; }
.home-none { margin: 0; color: var(--ink-soft); }
.home-group { margin: var(--space-4) 0 var(--space-1); font-size: var(--text-meta); color: var(--ink-soft); text-transform: uppercase; letter-spacing: var(--tracking-eyebrow); font-family: var(--font-sans); }
@media (max-width: 48rem) {
  .home-figures { grid-template-columns: minmax(0, 1fr); }
}

.admin-content .alert, .admin-content .error { margin: var(--space-4) 0; }
/* A notice that only informs (confidentiality of the exchanges, figures only): its bar and its
   words, no tinted box. The alerts that ask for something (danger, warning, success) keep theirs. */
.admin-content .alert-info { padding-left: var(--space-3); padding-top: 0; padding-bottom: 0; border-color: transparent; border-left-color: var(--sky); background: none; color: var(--ink-soft); }
/* A block of an administration screen is set on the page, not in a card */
.admin-content .card { padding: 0; background: none; border: 0; border-radius: 0; }

/* Sheet of a document of the corpus: one extract after the other */
.chunk { border-top: var(--border-width) solid var(--line); padding: var(--space-3) 0; }

.chunk p { margin: .3rem 0; white-space: pre-line; }

/* Sheet of an exchange: question, answer and extracts in cards, their line breaks kept */
.admin-content .card + .card { margin-top: var(--space-4); }
.exchange-text { margin: 0; white-space: pre-line; overflow-wrap: anywhere; }

/* Head line of an extract: number and reference, badges, path, period */
.chunk .chunk-head {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-3);
  align-items: center;
  margin: 0 0 var(--space-2);
  white-space: normal;
}

.chunk-head strong { color: var(--ink); }

/* An extract is folded to its head line and two lines of its text; opened, the whole text */
.chunk > summary { cursor: pointer; list-style: none; }
.chunk > summary::-webkit-details-marker { display: none; }
.chunk-preview {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  color: var(--ink-soft);
}
.chunk[open] .chunk-preview { display: none; }
/* Help folded under a title, opened on demand */
details.help > summary { cursor: pointer; color: var(--ink-soft); font-size: var(--text-sm); }

/* Note editor: the text area (fallback, Markdown in a fixed-width font) and, read-only, the content in a card */
.note-form textarea { min-height: 18rem; font-family: var(--font-mono); }

/* Editor of a note (ADR 0051): the toolbar above the text, the text in the face of the page
   (headings, lists, bold, links, quotes, tables as the writer will read them). Classes only: the
   CSP forbids style attributes. The text area is hidden by the script once the editor is there. */
.visual-editor { display: flex; flex-direction: column; gap: var(--space-2); }
.visual-editor[hidden] { display: none; }
.editor-tool[aria-pressed="true"] { background: var(--sky-soft); border-color: var(--ink); font-weight: var(--weight-strong); }
.editor-tool-undo, .editor-tool-redo { color: var(--ink-soft); }
/* Undo and redo are a group of their own, at the end of the bar */
@media (min-width: 48rem) { .editor-tool-undo { margin-inline-start: auto; } }
.visual-editable:focus-visible { outline: var(--focus-width) solid var(--focus); outline-offset: 2px; }
.visual-editable {
  box-sizing: border-box;
  min-height: 18rem;
  max-height: 70vh;
  overflow: auto;
  padding: var(--space-3) var(--space-4);
  border: var(--border-width) solid var(--control);
  border-radius: var(--radius-sm);
  background: var(--white);
  color: var(--ink);
  font-size: var(--text-base);
  font-weight: 400;
  line-height: 1.55;
  overflow-wrap: anywhere;
}
.visual-editable > :first-child { margin-top: 0; }
.visual-editable > :last-child { margin-bottom: 0; }
.visual-editable p { margin: 0 0 var(--space-3); }
.visual-editable h2 { margin: var(--space-4) 0 var(--space-2); font-size: var(--text-xl); line-height: 1.25; }
.visual-editable h3 { margin: var(--space-3) 0 var(--space-2); font-size: var(--text-lg); line-height: 1.3; }
.visual-editable ul, .visual-editable ol { margin: 0 0 var(--space-3); padding-left: var(--space-6); }
.visual-editable li { margin: var(--space-1) 0; }
.visual-editable li > ul, .visual-editable li > ol { margin-bottom: 0; }
.visual-editable a { color: var(--ink); text-decoration: underline; }
.visual-editable blockquote { margin: 0 0 var(--space-3); padding: var(--space-1) var(--space-4); border-inline-start: 4px solid var(--line-strong); color: var(--ink-soft); }
.visual-editable blockquote > :last-child { margin-bottom: 0; }
.visual-editable blockquote + blockquote { margin-top: calc(-1 * var(--space-3)); }
.visual-editable code { padding: 0 0.25em; border-radius: var(--radius-sm); background: var(--paper-2); font-family: var(--font-mono); font-size: 0.9em; }
.visual-editable hr { margin: var(--space-4) 0; border: 0; border-top: var(--border-width) solid var(--line-strong); }
.visual-editable table { width: 100%; margin: 0 0 var(--space-3); border-collapse: collapse; table-layout: auto; }
.visual-editable th, .visual-editable td { padding: var(--space-1) var(--space-2); border: var(--border-width) solid var(--line-strong); text-align: start; vertical-align: top; }
.visual-editable th { background: var(--paper-2); font-weight: var(--weight-strong); }

/* The dialog that asks the address of a link: the page's own, not the browser's prompt */
.link-dialog { width: min(28rem, calc(100vw - 2 * var(--space-4))); padding: var(--space-4); border: var(--border-width) solid var(--ink); border-radius: var(--radius-md); background: var(--white); color: var(--ink); box-shadow: var(--shadow-lg); }
.link-dialog::backdrop { background: var(--backdrop); }
.link-form { display: flex; flex-direction: column; gap: var(--space-2); }
.link-dialog-title { margin: 0; font-size: var(--text-lg); }
.link-form input { box-sizing: border-box; width: 100%; min-height: var(--target-touch); padding: 0 var(--space-3); border: var(--border-width) solid var(--control); border-radius: var(--radius-sm); font: inherit; }
.link-dialog-error { margin: 0; }
.link-dialog-error[hidden], .link-dialog button[hidden] { display: none; }
.link-dialog-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-2); }

.note-preview { padding: var(--space-2) var(--space-4); margin-top: var(--space-6); overflow-wrap: anywhere; }
.note-preview h2 { font-size: var(--text-base); margin: var(--space-2) 0; color: var(--ink-soft); }
.note-preview .item { margin: var(--space-1) 0; }
.note-preview .level-1 { margin-left: var(--space-6); }
.note-preview .level-2 { margin-left: calc(2 * var(--space-6)); }
.note-preview .item-bullet { padding-left: var(--space-4); text-indent: calc(-1 * var(--space-4)); }
.note-preview .item-bullet::before { content: "\2022"; display: inline-block; width: var(--space-4); text-indent: 0; }

/* Chat screen: the thread and its input zone, in one column; the history is the second level
   of the navigation column on the left (.rail-context, base.html), not a column of the page */
main.chat { max-width: var(--width-chat); margin: var(--space-8) auto var(--space-6); }

.chat-layout { display: grid; grid-template-columns: minmax(0, 1fr); }

/* History, in the column on the brand colour (rail_context of chat/index.html): bare links, no
   box. The current conversation is said by aria-current: bold, with a rule on its left. Its
   texts are in the colour computed for the brand, none dimmed (contrast, app/web/contrast.py). */
.chat-sidebar {
  box-sizing: border-box;
  padding: 0;
  background: none;
  border: 0;
  box-shadow: none;
  color: var(--on-brand);
}

/* The heading names the list for screen readers; the entry of the bar above it says it to the
   eye, and the summary of the drawer on a small screen */
.chat-sidebar h2 {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.chat-sidebar a { color: var(--on-brand); }
.chat-sidebar .empty-state { margin: var(--space-2) 0 0; padding: 0 var(--space-3); border: 0; border-radius: 0; color: var(--on-brand); font-size: var(--text-sm); text-align: left; }
.chat-sidebar .pagination { gap: var(--space-1) var(--space-3); margin: var(--space-2) 0 0; padding: 0 var(--space-3); }
.chat-sidebar .pagination a { min-height: 2rem; padding: 0; border: 0; border-radius: 0; background: none; color: var(--on-brand); text-decoration: underline; text-decoration-color: var(--on-brand); }
.chat-sidebar .pagination a:hover { background: none; }

.new-conversation {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-left: var(--border-strong) solid transparent;
  font-size: var(--text-sm);
  font-weight: var(--weight-strong);
  text-decoration: none;
  transition: background var(--transition);
}
.new-conversation::before { content: "+"; content: "+" / ""; }

.new-conversation:hover, .conversations a:hover { background: color-mix(in srgb, var(--on-brand) 16%, var(--brand)); }
.new-conversation[aria-current="page"], .conversations a[aria-current="page"] { border-left-color: var(--on-brand); font-weight: var(--weight-strong); }

.conversations { list-style: none; margin: 0; padding: 0; }

.conversations a {
  display: block;
  padding: var(--space-2) var(--space-3);
  border-left: var(--border-strong) solid transparent;
  color: var(--on-brand);
  font-size: var(--text-sm);
  line-height: 1.4;
  text-decoration: none;
  overflow-wrap: anywhere;
  transition: background var(--transition);
}

.conversation-date { display: block; font-size: var(--text-xs); font-weight: 400; }

/* Delete link of a conversation (issue #1043): a small cross at the right of the row, shown on
   hover and on focus of the row, always on a screen without hover (touch) and for the
   conversation open. Reachable by keyboard: it is a link, shown as soon as it has the focus. */
.conversations li { position: relative; }
.conversations li > a:first-child { padding-right: var(--space-8); }
.conversations a.conversation-delete {
  position: absolute;
  top: var(--space-1);
  right: var(--space-1);
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border-left: 0;
  color: var(--on-brand);
  font-size: var(--text-lg);
  line-height: 1;
  opacity: 0;
}
.conversations li:hover a.conversation-delete,
.conversations li:focus-within a.conversation-delete,
.conversations li:has(a[aria-current="page"]) a.conversation-delete { opacity: 1; }
.conversations a.conversation-delete:hover, .conversations a.conversation-delete:focus-visible { background: color-mix(in srgb, var(--on-brand) 16%, var(--brand)); text-decoration: underline; }
@media (hover: none) {
  .conversations a.conversation-delete { opacity: 1; }
}
/* The delete link under the title duplicates the cross of the history: a quiet text link */
.chat-head-actions { margin: var(--space-1) 0 0; }
.chat-head-actions .button { min-height: 0; padding: 0; border: 0; background: none; color: var(--ink-soft); font-size: var(--text-sm); font-weight: 400; text-decoration: underline; text-decoration-color: var(--sky); text-underline-offset: 4px; }
.chat-head-actions .button:hover { background: none; color: var(--ink); transform: none; box-shadow: none; }


/* Title of a conversation, or of a new one (empty thread): large, the reminder of use
   under it; the recent conversations to resume are the history column beside it. No
   example question, no domain pill. */
.chat-welcome { padding: 0; }

.chat-welcome h1, .chat-title {
  margin: 0 0 var(--space-2);
  font-size: clamp(1.875rem, 5vw, 2.5rem);
  overflow-wrap: anywhere;
}

/* Head of a conversation: its title, then the count of its questions */
.chat-head { display: grid; gap: var(--space-1); }
.chat-head .chat-title { margin: 0; }
.chat-head p { margin: 0; font-size: var(--text-sm); }

#thread-empty { max-width: 34rem; margin: 0; font-size: var(--text-base); color: var(--ink-soft); }

/* The thread of a new conversation shows once it holds a message; it is bare, the messages
   carry the frames */
.chat-thread { padding: 0; background: transparent; border: 0; box-shadow: none; }
.chat-thread:not(:has(h1, li.message)) { display: none; }

/* Answer, citations and sources (L7-09, L7-10). The thread is a size
   container: from 46 rem the answer keeps the left column and the sources cited the
   right one, below they are stacked under the answer. Markers [n] stay in the text.
   Nothing is boxed: an answer is laid on the page itself, a question is its first line in
   bold, an exchange is set apart from the previous one by space and one fine rule. */
.messages { list-style: none; margin: 0; padding: 0; container: thread / inline-size; }

.message { margin: 0 0 var(--space-6); }

.message-user {
  margin: 0 0 var(--space-4);
  font-weight: var(--weight-strong);
}
.message-user:not(:first-child) {
  margin-top: var(--space-8);
  padding-top: var(--space-6);
  border-top: var(--border-width) solid var(--line);
}

.message-assistant { margin-bottom: 0; }

.message-meta {
  margin: 0 0 var(--space-3);
  color: var(--ink-soft);
  font-size: var(--text-meta);
  font-weight: var(--weight-strong);
}

/* The author of a question is the side it sits on: kept for screen readers only */
.message-user .message-meta {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
}

.message-content { margin: 0; font-size: var(--text-base); white-space: pre-wrap; overflow-wrap: anywhere; line-height: 1.65; }

/* An answer is Markdown (chat/_markdown.html, chat_markdown.js): paragraphs, lists and
   small headings, no pre-wrap */
.message-assistant .message-content { white-space: normal; }
.message-assistant .message-content { line-height: 1.75; }
.message-content > :first-child { margin-top: 0; }
.message-content > :last-child { margin-bottom: 0; }
.message-content p { margin: 0 0 var(--space-4); }
/* The headings of an answer (Markdown h2 and h3 come out as h4.md-heading): the serif of the
   titles, a larger size and room above, so that the sections of a long answer read apart */
.message-content .md-heading {
  margin: var(--space-8) 0 var(--space-3);
  font-size: var(--text-lg);
  font-weight: var(--weight-strong);
  line-height: 1.3;
  letter-spacing: var(--tracking-title);
}
/* A condition the model puts in bold: heavier, with a pale sky underlay under its lower half,
   the text stays in ink */
.message-content > .md-heading:first-child { margin-top: 0; }
.message-assistant .message-content strong {
  background: linear-gradient(to bottom, transparent 55%, var(--sky-soft) 55%);
  font-weight: var(--weight-strong);
}
.message-content .md-list { margin: 0 0 var(--space-4); padding-left: var(--space-6); }
.message-content .md-list li { margin: 0 0 var(--space-3); padding-left: var(--space-1); }
.message-content .md-list li:last-child { margin-bottom: 0; }
.message-content .md-list li.md-level-1 { margin-left: var(--space-5); }
.message-content .md-list li.md-level-2 { margin-left: calc(2 * var(--space-5)); }

/* Streamed answer (L7-09, chat.js): provisional until `done` (dashed border and its
   state line), then the answer, or a notice (sources insuffisantes, refusal, interrupted
   answer): sky-soft with a bar, its state said in words */
.message-provisional { padding-left: var(--space-4); border-left: var(--border-strong) dashed var(--control); }
.message-state { margin: var(--space-2) 0 0; color: var(--ink-soft); font-size: var(--text-meta); }
/* A state, not a card: only its bar on the left stays */
.message-notice {
  padding-left: var(--space-4);
  border-left: var(--accent-bar) solid var(--sky);
}
.message-notice .message-meta, .message-notice .message-state { color: var(--ink); }
.message-notice .message-state { font-weight: var(--weight-strong); }

/* Marker [n] of a citation: a pill on sky-soft, in the text colour; a button once the
   sources are listed (it opens its source), plain text before */
.citation-marker {
  display: inline-block;
  min-width: 1.5em;
  padding: 0 .3em;
  border-radius: var(--radius-sm);
  background: var(--sky-soft);
  color: var(--ink);
  font-size: .8em;
  font-weight: var(--weight-strong);
  line-height: 1.5;
  text-align: center;
  text-decoration: none;
}
button.citation-marker {
  min-height: 0;
  border: 0;
  box-shadow: none;
  font: inherit;
  font-size: .8em;
  font-weight: var(--weight-strong);
  line-height: 1.5;
  cursor: pointer;
}
button.citation-marker:hover { background: var(--ink); color: var(--white); transform: none; box-shadow: none; }
/* The notes under an answer (chat/_sources.html): the partial coverage said by the model, the
   amounts no source says, and the expert notice written by the application (ADR 0041) make
   one discreet note: small grey lines under the answer, no box, no state colour, one fine
   rule on the left. Every one of them is still there, in words. */
.answer-notes {
  margin: var(--space-6) 0 0;
  padding-left: var(--space-3);
  border-left: var(--border-width) solid var(--line-strong);
  color: var(--ink-soft);
  font-size: var(--text-meta);
  line-height: 1.5;
}
.answer-notes p, .answer-notes .alert {
  display: block;
  margin: 0 0 var(--space-1);
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  color: inherit;
  font-size: inherit;
}
.answer-notes .alert::before { content: none; }
.answer-notes p:last-child { margin-bottom: 0; }
/* Sources cited (L7-10, chat/_sources.html): a list of extracts under a rule, each with its
   number, official reference and date always shown; a text not in force, ended, unknown or
   changed since the answer carries its status badge (.status, rule 2) */
.message-sources {
  margin: var(--space-4) 0 0;
  padding: var(--space-4) 0 0;
  border-top: var(--border-width) solid var(--line);
}
.sources-title {
  margin: 0 0 var(--space-2);
  color: var(--ink-soft);
  font-family: var(--font-sans);
  font-size: var(--text-meta);
  font-weight: var(--weight-strong);
  line-height: 1.4;
}
.sources-title-historical { margin-top: var(--space-4); }
.sources { margin: 0; padding: 0; list-style: none; }
.source {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  margin: 0;
  padding: var(--space-3) 0;
  border-top: var(--border-width) solid var(--line);
  font-size: var(--text-sm);
}
.source-date { color: var(--ink-soft); font-size: var(--text-meta); }
/* A text no longer in force, kept as historical context (ADR 0033, rule 2): a bar and a note,
   no ground, so that it never passes for a source in force (not by colour alone) */
.source-historical {
  border-left: var(--border-strong) solid var(--control);
  padding-left: var(--space-3);
}
.source-historical-note { flex-basis: 100%; margin: 0; color: var(--ink); font-size: var(--text-meta); }
/* The status of a text, always in words (rule 2), without a pill: its dot and its words; the
   ordinary state in grey, any other (draft, replaced, ended, repealed, unknown) in bold ink */
.source .status, .source-panel .status {
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  color: var(--ink);
  font-size: var(--text-meta);
  font-weight: var(--weight-strong);
  white-space: normal;
}
.source .status-in_force, .source-panel .status-in_force { color: var(--ink-soft); font-weight: 400; }
.source .status-repealed::before, .source-panel .status-repealed::before { background: var(--ink); }

/* A reference that opens the panel: a link-like button */
.source-open {
  flex: 1 1 100%;
  min-height: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  color: var(--ink);
  font: inherit;
  font-size: var(--text-sm);
  font-weight: var(--weight-strong);
  text-decoration: underline;
  text-decoration-color: var(--sky);
  text-underline-offset: 4px;
  text-align: left;
  justify-content: flex-start;
  white-space: normal;
  cursor: pointer;
  overflow-wrap: anywhere;
}
.source-open:hover { background: none; color: var(--ink); transform: none; box-shadow: none; text-decoration-thickness: 2px; }

/* The text of an answer keeps a comfortable measure. A narrow thread (a phone) shows the
   sources under the answer, unfolded; a wide one in a narrow column on the right, about 30 %
   of the width and 22 rem at most, each reference on two lines at most (the panel names it
   in full) */
.message-assistant .message-content { max-width: 42rem; }

@container thread (min-width: 46rem) {
  .message-assistant {
    display: grid;
    grid-template-columns: minmax(0, 1fr) clamp(14rem, 30%, 22rem);
    grid-template-rows: repeat(5, auto) 1fr;
    column-gap: var(--space-5);
    align-items: start;
  }
  .message-assistant > * { grid-column: 1; }
  .message-assistant > .message-sources {
    grid-column: 2;
    grid-row: 1 / span 6;
    align-self: stretch;
    margin: 0;
    padding: 0 0 0 var(--space-5);
    border-top: 0;
    border-left: var(--border-width) solid var(--line);
  }
  .message-assistant > .message-sources .source-open {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
  }
}

/* Side panel of a cited extract (chat/index.html), filled and opened by chat.js */
.source-panel {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 10;
  width: min(30rem, 100%);
  box-sizing: border-box;
  overflow-y: auto;
  padding: var(--space-5) var(--space-6);
  background: var(--white);
  color: var(--ink);
  border-left: var(--border-width) solid var(--line-strong);
  box-shadow: var(--shadow-lg);
}
.source-panel[hidden] { display: none; }
.source-panel-close {
  float: right;
  min-height: 2rem;
  margin: 0 0 var(--space-2) var(--space-2);
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--sky);
  text-underline-offset: 4px;
}
.source-panel-close:hover { background: none; color: var(--ink); text-decoration-thickness: var(--border-strong); transform: none; box-shadow: none; }
.source-panel-title {
  margin: 0 0 var(--space-2);
  font-size: var(--text-xl);
  line-height: var(--leading-title);
  letter-spacing: var(--tracking-title);
  overflow-wrap: anywhere;
}
.source-document { margin: 0 0 var(--space-2); color: var(--ink-soft); }
.source-then { display: block; margin-top: var(--space-1); color: var(--ink-soft); font-size: var(--text-sm); }
.source-fields { margin: var(--space-4) 0; }
.source-fields dt {
  color: var(--ink-soft);
  font-size: var(--text-meta);
  font-weight: var(--weight-strong);
}
.source-fields dd { margin: 0 0 var(--space-3); overflow-wrap: anywhere; }
.source-fields a { color: var(--ink); }
.source-quotes-title { margin: var(--space-5) 0 var(--space-2); font-size: var(--text-lg); }
.source-quote {
  margin: 0 0 var(--space-3);
  padding: var(--space-1) var(--space-4);
  border-left: var(--border-strong) solid var(--gold);
  font-family: var(--font-serif);
  font-style: italic;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* Input zone (L7-08), at the head of the screen, above the thread: flat, on the page itself. A
   fine rule above it, the question (its label is for screen readers) with the Send button at
   its right, the modes under them as four words (radio buttons kept, the input hidden over
   its word, the chosen one bold and underlined, the focus ring on the word), then the help,
   the counter and the permanent banner (no personal data, no client name:
   docs/garde-fous.md). The visual order is set by `order`; the reading order of the markup is
   the same for the keyboard. */
.chat-main {
  display: grid;
  gap: var(--space-6);
  min-width: 0;
  /* The column of reading: the answer and its sources, the input zone under the same width */
  width: 100%;
  max-width: 64rem;
  margin-inline: auto;
}

.composer {
  display: grid;
  /* The field and the Send button on one line, the modes, the help and the banner under them */
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
  gap: var(--space-2) var(--space-4);
  padding: var(--space-3) 0 0;
  border-top: var(--border-width) solid var(--line-strong);
  background: var(--paper);
}

/* A new conversation (no exchange yet), as in the chat assistants: the title and the bubble
   in the middle of the window, the bubble set forward; the first exchange brings back the
   layout of a conversation (rules below) */
.chat-main:not(:has(.messages > li)) {
  align-content: center;
  min-height: calc(100vh - 2 * var(--space-8));
  max-width: 46rem;
  gap: var(--space-5);
}
.chat-main:not(:has(.messages > li)) .chat-welcome { text-align: center; }
.chat-main:not(:has(.messages > li)) #thread-empty { margin-inline: auto; }
.chat-main:not(:has(.messages > li)) .composer { padding-top: 0; border-top: 0; background: transparent; }
.chat-main:not(:has(.messages > li)) .composer textarea { box-shadow: var(--shadow-md); }
.chat-main:not(:has(.messages > li)) .composer textarea:focus,
.chat-main:not(:has(.messages > li)) .composer textarea:focus-visible {
  box-shadow: 0 0 0 3px var(--sky-soft), var(--shadow-md);
}
.chat-main:not(:has(.messages > li)) .composer-modes { justify-self: center; }
.chat-main:not(:has(.messages > li)) .composer-foot { justify-content: center; text-align: center; }
@media (max-width: 48rem) {
  .chat-main:not(:has(.messages > li)) { min-height: 60vh; }
}

/* Like a chat: once the thread holds an exchange it comes before the input zone, which
   stays stuck to the bottom of the window (chat.js follows the thread above it). Only on a
   screen wide and tall enough to leave room for the thread: elsewhere the input zone stays
   under the thread in the flow of the page. The page scrolls, not the thread. */
.chat-main:has(.messages > li) .chat-thread { order: 1; }
.chat-main:has(.messages > li) .composer { order: 2; }
@media (min-width: 48rem) and (min-height: 46rem) {
  .chat-main:has(.messages > li) .composer {
    position: sticky;
    bottom: 0;
    z-index: 2;
    padding-bottom: var(--space-3);
  }
}

.composer > * { order: 10; grid-column: 1 / -1; margin-top: 0; margin-bottom: 0; }

.composer > label {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
}

.composer textarea {
  order: 2;
  /* The whole row: the Send button is laid over its right end (.composer-send) */
  grid-column: 1 / -1;
  grid-row: 1;
  display: block;
  width: 100%;
  box-sizing: border-box;
  /* One line when empty; chat.js grows it with the text up to the maximum, then it scrolls */
  min-height: 3.25rem;
  max-height: min(40vh, 16rem);
  /* A bubble as in the chat assistants: white, a thin border, round ends; room on the right
     for the button */
  padding: 0.8125rem 3.75rem 0.8125rem var(--space-5);
  border: var(--border-width) solid var(--control);
  border-radius: 1.625rem;
  font: inherit;
  font-size: var(--text-base);
  line-height: 1.5;
  color: var(--ink);
  background: var(--white);
  overflow-y: auto;
  resize: none;
}
.composer textarea:hover { border-color: var(--ink-soft); }
/* Focus as on the fields of the access screens: a dark border and a soft halo instead of the
   thick outline of the page (the field stays clearly marked for the keyboard) */
.composer textarea:focus,
.composer textarea:focus-visible {
  border-color: var(--ink);
  box-shadow: 0 0 0 3px var(--sky-soft);
  /* Transparent, not removed: the forced colours mode (Windows high contrast) still draws it */
  outline: 2px solid transparent;
}

/* The wrapper takes no box: its Send button joins the field (right), its modes the row under */
.composer-actions { display: contents; }

/* The help (counter, keys) and the permanent banner share one line when they fit */
.composer-foot {
  order: 4;
  grid-row: 3;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-1) var(--space-6);
  color: var(--ink-soft);
  font-size: var(--text-meta);
}

.composer-help {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-4);
  margin: 0;
  padding: 0;
}

.composer-banner { margin: 0; }

/* Modes: four words in a row; the chosen one is bold and underlined, so that its state is
   said by more than its colour */
.composer-modes {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  box-sizing: border-box;
  min-width: 0;
  grid-column: 1 / -1;
  grid-row: 2;
  justify-self: start;
  margin: 0;
  padding: 0;
  border: 0;
}

.composer-modes legend {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.composer-modes label {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 2.125rem;
  box-sizing: border-box;
  margin: 0;
  padding: 0 var(--space-3);
  border-bottom: var(--border-strong) solid transparent;
  color: var(--ink-soft);
  font-size: var(--text-sm);
  font-weight: 500;
  cursor: pointer;
  transition: color var(--transition);
}
.composer-modes label:first-of-type { padding-left: 0; }

.composer-modes label:hover { color: var(--ink); }

.composer-modes input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.composer-modes label:has(input:checked) {
  border-bottom-color: var(--ink);
  color: var(--ink);
  font-weight: var(--weight-strong);
}
.composer-modes label:has(input:focus-visible) { outline: var(--focus-width) solid var(--focus); outline-offset: 2px; }

/* Send: a round button with an arrow, inside the bubble of the field, at its bottom right (it
   stays by the last line when the field grows) */
.composer-actions button.composer-send {
  position: relative;
  z-index: 1;
  grid-column: 1 / -1;
  grid-row: 1;
  justify-self: end;
  align-self: end;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  min-height: 0;
  margin: 0 0.375rem 0.375rem 0;
  padding: 0;
  border-radius: 50%;
}
.composer-send-icon {
  width: 1.25rem;
  height: 1.25rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.25;
  stroke-linecap: round;
  stroke-linejoin: round;
}


/* Sending (role status) and a refused question (role alert), filled by chat.js */
/* The status region (« Réponse en cours », « Réponse terminée ») is for screen readers only:
   the thread shows the answer itself. It stays rendered, out of sight, for them to announce it */
.composer-status {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}
.composer .error { white-space: pre-wrap; }
.composer button[disabled] { cursor: wait; }

/* Actions under an answer (L7-11, chat/_actions.html): two kinds apart. The generation
   actions (export, "ask again in" another mode) are small outlined pills with a short label;
   the feedback of the user is two discreet thumbs at the end of the line. The rating kept is
   pressed (aria-pressed): the thumb is filled on a sky ground, never the colour alone; a
   refusal is said in the danger colour */
.message-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1) var(--space-6);
  margin: var(--space-4) 0 0;
  color: var(--ink-soft);
  font-size: var(--text-meta);
}
.feedback, .retry, .export {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}
.feedback { margin-left: auto; gap: var(--space-1); }
.feedback-question, .retry-label, .export-label { color: var(--ink-soft); font-size: var(--text-meta); }
.retry-label, .export-label { margin-right: var(--space-1); }
/* Retry and export: words, not pills; the thumbs are bare icons */
.message-actions button, .message-actions .export-format {
  min-height: 2rem;
  padding: 0 var(--space-2);
  border-color: transparent;
  background: transparent;
  color: var(--ink);
  font-size: var(--text-meta);
  font-weight: var(--weight-strong);
  text-decoration: underline;
  text-decoration-color: var(--sky);
  text-underline-offset: 4px;
}
.message-actions button:hover, .message-actions .export-format:hover {
  background: var(--paper-2);
  border-color: transparent;
  color: var(--ink);
  box-shadow: none;
}
/* The thumbs: a bare icon, a round target, no frame until hovered */
.message-actions .feedback-rate {
  display: grid;
  place-items: center;
  width: 2rem;
  min-width: 2rem;
  padding: 0;
  border-color: transparent;
  background: transparent;
  color: var(--ink-soft);
}
.message-actions .feedback-rate:hover { background: var(--paper-2); border-color: transparent; color: var(--ink); }
.feedback-icon { display: block; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.message-actions .feedback-rate[aria-pressed="true"], .message-actions .feedback-rate[aria-pressed="true"]:hover {
  background: transparent;
  border-color: transparent;
  color: var(--ink);
}
.feedback-rate[aria-pressed="true"] .feedback-icon { fill: currentColor; }
.message-actions[aria-busy="true"] button, .message-actions[aria-busy="true"] .export-format { cursor: wait; }
.feedback-comment { order: 3; flex: 1 1 100%; }
.feedback-comment summary { color: var(--ink-soft); font-size: var(--text-meta); cursor: pointer; }
.feedback-comment-label { display: block; margin: var(--space-2) 0 var(--space-1); }
.feedback-comment-text {
  display: block;
  width: 100%;
  box-sizing: border-box;
  margin-top: var(--space-1);
  padding: var(--space-2);
  border: var(--border-width) solid var(--control);
  border-radius: var(--radius-sm);
  font: inherit;
  color: var(--ink);
  background: var(--white);
  resize: vertical;
}
.feedback-help { margin: 0 0 var(--space-2); color: var(--ink-soft); }
.message-actions .feedback-save { margin-left: calc(-1 * var(--space-2)); }
/* The status region stays rendered, even empty, for screen readers; empty, it takes no room */
.feedback-status { order: 4; flex: 1 1 100%; margin: 0; color: var(--ink-soft); }
.feedback-status:empty { position: absolute; width: 1px; height: 1px; overflow: hidden; }
.feedback-status-error { color: var(--danger); font-weight: var(--weight-strong); }
.message-notice .feedback-status-error { color: var(--ink); }

/* Keyboard focus, always visible: the focus colour on the page, the text colour on the navigation bar */
:focus-visible { outline: var(--focus-width) solid var(--focus); outline-offset: 2px; }
.rail :focus-visible, .rail-account :focus-visible { outline-color: var(--on-brand); }

/* Tablet (1024 px and less): administration and corpus sheet in one column */
@media (max-width: 64rem) {
  .table-wrap:has(.menu) { overflow-x: auto; }
  .table-wrap .menu-list { position: static; margin-top: var(--space-1); box-shadow: none; }
  main.chat { margin: var(--space-4) auto; }

  .admin-content { width: 100%; }
  .details-list { grid-template-columns: 1fr; }
  .kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* The navigation column folds into a horizontal bar above the page below 64 rem (1024 px), so
   that on a tablet held upright (768 px) the thread keeps the width of the page and not the
   15 rem of the column. Its second level (the conversations, the menu of the administration)
   is then a drawer in the bar, closed by app/static/rail.js: the summary opens it. */
@media (max-width: 63.9375rem) {
  .app-shell { display: flex; flex-direction: column; background: var(--paper); }
  .app-body { flex: 1; order: 2; }

  .rail {
    position: static;
    flex: none;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    height: auto;
    padding: var(--space-2) var(--space-4) 0;
    overflow-y: visible;
  }

  .rail-brand { flex: 1 1 12rem; padding: 0; }
  .rail-nav { flex-direction: row; width: auto; }
  .rail-nav a { padding: var(--space-2) var(--space-3); }
  /* Under the bar, on its colour, before the page (order) */
  .rail-account {
    order: 1;
    align-self: stretch;
    position: static;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-2) var(--space-4);
    width: auto;
    padding: 0 var(--space-4) var(--space-2);
  }
  .logout { grid-template-columns: auto auto; gap: var(--space-2); padding-left: 0; }
  .rail-account { border-top: 0; }
  .rail-account .language { padding-inline: 0; }

  /* The drawer: a line in the bar, the list under it once opened */
  .rail-context { flex: 1 1 100%; margin-top: 0; padding-top: 0; border-top: 0; }
  .rail-context > summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    min-height: var(--target-touch);
    padding: 0 var(--space-1);
    font-size: var(--text-sm);
    font-weight: var(--weight-strong);
  }
  .rail-context > summary::after { content: "\25BE"; content: "\25BE" / ""; }
  .rail-context[open] > summary::after { transform: rotate(180deg); }
  .rail-context[open] { max-height: 70vh; overflow-y: auto; padding-bottom: var(--space-2); scrollbar-width: thin; scrollbar-color: color-mix(in srgb, var(--on-brand) 35%, var(--brand)) transparent; }
  .admin-nav ul { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .admin-nav .admin-group { margin-top: var(--space-2); padding-top: var(--space-2); }
}

@media (max-width: 47.9375rem) {
  .form-grid, .form-grid-3 { grid-template-columns: minmax(0, 1fr); }

  .table th, .table td { padding: var(--space-3) var(--space-2); }
}

@media (max-width: 29.9375rem) {
  .kpis { grid-template-columns: minmax(0, 1fr); }
  .admin-nav ul { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  /* Chat: the modes in a grid, two by two, none under the other */
  .composer-modes {
    flex: 1 1 100%;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-1);
  }
  .composer-modes label { justify-content: center; padding: 0 var(--space-2); }
  .composer-modes label:first-of-type { padding-left: var(--space-2); }
}


/* Access screens (auth/*.html): sign-in, code, enrolment, password. Two columns,
   the product, a sentence and a help text on the left, the form in a card on the right;
   one column on a small screen (intro, card, help). Sign-in and code have no navigation bar. */
/* The block is centred in the window, both ways: the page takes the height of the window,
   less the room of a banner above it (the warning of a development workstation), no scroll */
main.auth-page {
  display: grid;
  align-content: center;
  min-height: calc(100vh - 5rem);
  max-width: 65rem;
  margin: 0 auto;
  padding: var(--space-8) var(--space-4);
  box-sizing: border-box;
}

.auth {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 27.5rem);
  grid-template-areas: "intro card" "help card";
  column-gap: 6rem;
  row-gap: var(--space-6);
  align-items: center;
}

.auth-intro { grid-area: intro; align-self: end; display: grid; gap: var(--space-6); }
.auth-help { grid-area: help; align-self: start; }
.auth-card { grid-area: card; }

.auth-brand { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); margin: 0; }

.auth-logo {
  display: block;
  width: 2.25rem;
  height: 2.25rem;
}

.auth-product { font-family: var(--font-serif); font-size: 1.25rem; font-weight: var(--weight-title); letter-spacing: var(--tracking-title); }
.auth-cabinet { color: var(--ink-soft); font-size: var(--text-sm); }
.auth-cabinet::before { content: "· "; }

.auth-headline {
  margin: 0;
  font-family: var(--font-serif);
  font-size: clamp(2.25rem, 4.5vw, 3.5rem);
  font-weight: 400;
  line-height: 1.05;
  letter-spacing: -0.03em;
}

.auth-help {
  max-width: 27.5rem;
  color: var(--ink-soft);
  font-size: var(--text-sm);
}

.auth-help h2 { margin: 0 0 var(--space-2); color: var(--ink); font-family: var(--font-sans); font-size: var(--text-sm); font-weight: var(--weight-strong); letter-spacing: 0; line-height: 1.4; }
.auth-help p { margin: 0; }

/* Numbered steps: the number is drawn by the list counter, the list stays a list */
.auth-steps { display: grid; gap: var(--space-3); margin: 0; padding: 0; list-style: none; counter-reset: auth-step; }
.auth-steps li { display: flex; align-items: center; gap: var(--space-3); counter-increment: auth-step; }

.auth-steps li::before {
  content: counter(auth-step);
  flex: none;
  display: grid;
  place-items: center;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  background: var(--sky-soft);
  color: var(--ink);
  font-size: var(--text-xs);
  font-weight: var(--weight-strong);
}

/* The form is set on the page: no card, the space and one rule above its foot do the work */
.auth-card {
  display: grid;
  gap: var(--space-5);
  /* Flat: the form is laid on the page, only a fine rule on its left sets it apart from the
     sentence beside it */
  padding: 0 0 0 var(--space-8);
  border-left: var(--border-width) solid var(--line-strong);
}

.auth-card > * { margin: 0; }
.auth-card-head { display: grid; gap: var(--space-1); }
.auth-card-head h1 { margin: 0; font-size: 1.75rem; }
.auth-card-head p { margin: 0; color: var(--ink-soft); font-size: var(--text-sm); }

.auth-form { display: grid; gap: var(--space-4); }
.auth-form > * { margin: 0; }
.auth-field { display: grid; gap: var(--space-1); font-size: var(--text-sm); font-weight: var(--weight-strong); }

.auth-form .auth-field input {
  display: block;
  width: 100%;
  box-sizing: border-box;
  min-height: 3rem;
  margin: 0;
  padding: 0 var(--space-4);
  border: var(--border-width) solid var(--control);
  border-radius: var(--radius-sm);
  background: var(--white);
  color: var(--ink);
  font: inherit;
  font-size: var(--text-body);
  font-weight: 400;
}

.auth-form .auth-field input:focus { border-color: var(--ink); box-shadow: 0 0 0 3px var(--sky-soft); }

/* Code of the authenticator app: one field (autocomplete one-time-code), digits large and apart */
.auth-form .auth-field input.auth-code {
  min-height: 3.75rem;
  border-radius: var(--radius-lg);
  text-align: center;
  font-family: var(--font-serif);
  font-size: 1.625rem;
  font-weight: var(--weight-title);
  letter-spacing: .3em;
}

.auth-form .auth-field input.auth-code:focus { border: var(--border-strong) solid var(--ink); box-shadow: 0 0 0 4px var(--sky-soft); }

.auth-submit { box-sizing: border-box; width: 100%; min-height: 3rem; margin-top: var(--space-2); font-size: var(--text-base); }
/* The next actions of a screen (sign out everywhere) are outlined, only the first is filled */
.auth-card form ~ form .auth-submit { background: transparent; border-color: var(--control); color: var(--ink); }
.auth-card form ~ form .auth-submit:hover { background: var(--paper-2); border-color: var(--ink); color: var(--ink); }
.auth-card .button-secondary { background: transparent; border-color: var(--control); }
.auth-card .button-secondary:hover { background: var(--paper-2); border-color: var(--ink); }
.auth-note { margin: 0; color: var(--ink-soft); font-size: var(--text-sm); }

.auth-card-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding-top: var(--space-4);
  border-top: var(--border-width) solid var(--line);
  color: var(--ink-soft);
  font-size: var(--text-sm);
}

.auth-card-foot form { margin: 0; }
.auth-card-foot button, .auth-card-foot a { display: inline-flex; align-items: center; min-height: 2rem; }

/* Language: one text button per language, the current one disabled, bold and underlined (aria-current) */
.auth-language { display: flex; align-items: center; gap: var(--space-1); }
/* The text of the first language on the edge of the form (its button has a side padding) */
.auth-card-foot .auth-language { margin-left: calc(-1 * var(--space-2)); }

.auth-language button {
  min-height: 1.75rem;
  padding: 0 var(--space-2);
  border-color: transparent;
  background: transparent;
  color: var(--ink);
  font-size: var(--text-sm);
}

.auth-language button:hover { background: transparent; border-color: transparent; color: var(--ink); transform: none; box-shadow: none; text-decoration: underline; text-decoration-color: var(--sky); }

.auth-language button[disabled] {
  opacity: 1;
  font-weight: var(--weight-strong);
  text-decoration: underline;
  text-decoration-color: var(--sky);
  text-underline-offset: 4px;
  cursor: default;
}

/* QR code of the enrolment: dark on white whatever the page, at its own size (the SVG has
   no viewBox, so it is never scaled), the key to type below it */
.totp-qr { display: grid; justify-items: center; padding: var(--space-4); background: var(--white); border-radius: var(--radius-md); }
.totp-qr svg { display: block; }
.totp-key { overflow-wrap: anywhere; font-size: var(--text-base); user-select: all; }

@media (max-width: 47.9375rem) {
  .auth { grid-template-columns: minmax(0, 1fr); grid-template-areas: "intro" "card" "help"; row-gap: var(--space-5); }
  .auth-intro, .auth-help { align-self: auto; }
  .auth-help { max-width: none; }
  .auth-card { padding: 0; border-left: 0; }
  .auth-card-head h1 { font-size: 1.625rem; }
}

/* Touch screens (tablet): every control is at least 44 px high, wide enough to be hit */
@media (pointer: coarse) {
  /* The compact fields of a filter bar (above) get their 44 px back */
  .filter-bar .field select,
  .filter-bar .field input:not([type=checkbox]),
  .filter-bar button.period-trigger { min-height: var(--target-touch); height: auto; }
  button, .button, .chip, .rail-nav a, .table td button, .table td .button, .table td .menu-list button,
  .menu > summary, .message-actions button, .message-actions .export-format, .auth-language button,
  .admin-nav a, .composer-modes label, .auth-card-foot a, .auth-card-foot button {
    min-height: var(--target-touch);
  }
  .rail button, .rail-account button, .auth-language button, button.citation-marker {
    min-width: var(--target-touch);
    min-height: var(--target-touch);
  }
  .rail button, .rail-account button { padding: 0 var(--space-2); }
  .home-list li { min-height: var(--target-touch); align-items: center; }
  .message-actions .feedback-rate { width: var(--target-touch); min-width: var(--target-touch); }
  /* The columns of icon buttons grow with the buttons (more specific than the widths below) */
  col.col-action-one { width: 6rem; }
  col.col-actions { width: 9.5rem; }
  col.col-actions-wide { width: 11rem; }
  .icon-button, .table td .icon-button { width: var(--target-touch); min-width: var(--target-touch); height: var(--target-touch); min-height: var(--target-touch); }
  .new-conversation {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: var(--target-touch);
  }
}

/* No movement for a person who asks for less of it: the colour changes stay */
@media (prefers-reduced-motion: reduce) {
  button, .button, .rail-nav a { transition: none; }
  button:hover, .button:hover { transform: none; }
}

/* Charts and gauges of the administration (U4-A): SVG drawn by the server (admin/_charts.html,
   geometry in app/web/charts.py). The size of a mark is an attribute of the SVG, never a
   style (CSP); the colours are these classes. A series is never told by its colour alone:
   a legend, a tooltip, a table of the values, and a hatching for the third series. */
.chart { margin: 0 0 var(--space-4); }
.chart-title { margin: 0 0 var(--space-2); color: var(--ink); font-size: var(--text-sm); font-weight: var(--weight-strong); }

.chart-frame {
  overflow-x: auto;
  padding: var(--space-3) 0;
}

/* Wide enough for its text to stay readable (the frame scrolls on a phone) */
.chart-svg { display: block; width: 100%; min-width: 44rem; height: auto; }
.chart-grid { stroke: var(--line); stroke-width: 1; vector-effect: non-scaling-stroke; }
.chart-baseline { stroke: var(--ink-soft); stroke-width: 1; vector-effect: non-scaling-stroke; }
.chart-axis { fill: var(--ink-soft); font-family: var(--font-sans); font-size: 13px; font-variant-numeric: tabular-nums; }
.chart-column.is-current .chart-axis-x { fill: var(--ink); font-weight: 700; }
.chart-slot { fill: none; pointer-events: all; }
.chart-column.is-current .chart-slot { fill: var(--sky-soft); }
.chart-link:hover .chart-slot { fill: var(--paper-2); }
.chart-link:focus-visible .chart-slot { stroke: var(--focus); stroke-width: var(--focus-width); }
.chart-bar { stroke: var(--ink); stroke-width: 1; vector-effect: non-scaling-stroke; }
.chart-series-short { fill: var(--ink); }
.chart-series-detailed { fill: var(--sky); }
.chart-series-cost { fill: var(--sky); }
.chart-column.is-current .chart-series-cost { fill: var(--ink); }
.chart-hatch-ground { fill: var(--white); }
.chart-hatch-line { stroke: var(--gold); stroke-width: 3; }
.chart-limit { stroke: var(--danger); stroke-width: 2; stroke-dasharray: 8 5; vector-effect: non-scaling-stroke; }
.chart-limit-text {
  fill: var(--danger);
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 600;
  paint-order: stroke;
  stroke: var(--white);
  stroke-width: 4px;
}

.chart-legend { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-5); margin: var(--space-2) 0 0; padding: 0; list-style: none; color: var(--ink-soft); font-size: var(--text-sm); }
.chart-swatch { width: 1rem; height: 1rem; vertical-align: -.2em; }
.chart-data { margin: var(--space-2) 0 var(--space-4); }
.chart-data > summary { cursor: pointer; color: var(--ink); font-size: var(--text-sm); }

/* Parts of a total (cost by mode and by model), and the three cards that hold them */
.chart-cards { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-4); margin: 0 0 var(--space-6); }
.chart-cards .card { margin: 0; }
.chart-cards h3 { margin: 0 0 var(--space-3); font-size: var(--text-base); }
.chart-shares { display: grid; gap: var(--space-3); margin: 0; padding: 0; list-style: none; }
.chart-shares li { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--space-1) var(--space-3); font-size: var(--text-sm); }
.chart-share-value { font-variant-numeric: tabular-nums; text-align: right; }
.chart-share-bar { grid-column: 1 / -1; display: block; width: 100%; height: .5rem; border-radius: var(--radius-pill); overflow: hidden; }
.chart-share-track { fill: var(--paper-2); }
.chart-share-fill { fill: var(--ink); }

/* Gauge of the monthly ceiling: a bar, a mark at each alert threshold, the level said by a
   word (the badge), the figures in a sentence */
.gauge { margin-top: var(--space-3); }
.gauge-text { margin: 0 0 var(--space-1); font-size: var(--text-sm); }
.gauge-bar { display: block; width: 100%; max-width: 24rem; height: .625rem; border-radius: var(--radius-pill); overflow: hidden; }
.gauge-track { fill: var(--paper-2); }
.gauge-fill { fill: var(--ink); stroke: var(--ink); stroke-width: 1; vector-effect: non-scaling-stroke; }
.gauge-info .gauge-fill { fill: var(--sky); }
.gauge-alert .gauge-fill { fill: var(--warning); stroke: var(--warning); }
.gauge-danger .gauge-fill { fill: var(--danger); stroke: var(--danger); }
.gauge-mark { stroke: var(--ink-soft); stroke-width: 1; vector-effect: non-scaling-stroke; }
.gauge-mark.is-reached { stroke: var(--white); }
.gauge-info .gauge-mark.is-reached { stroke: var(--ink); }
.gauge-level { margin: var(--space-2) 0 0; }
.gauge-note, .gauge-events { margin: var(--space-1) 0 0; color: var(--ink-soft); font-size: var(--text-xs); }
.gauge-events { padding: 0; list-style: none; }
.gauge-compact { margin-top: 0; }
.gauge-compact .gauge-bar { max-width: 12rem; }
.gauge-cell { min-width: 13rem; }

/* Grid of the months of a year, in the menu of the month picker (links, no script) */
.month-menu > summary { min-height: 2.5rem; font-size: var(--text-sm); }

.month-panel {
  position: absolute;
  top: calc(100% + var(--space-1));
  right: 0;
  z-index: 5;
  box-sizing: border-box;
  width: 16rem;
  padding: var(--space-3);
  background: var(--white);
  border: var(--border-width) solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
}

.month-year { display: flex; align-items: center; justify-content: space-between; margin: 0 0 var(--space-2); }
.month-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-1); margin: 0; padding: 0; list-style: none; }

.month-cell {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 2.5rem;
  border: var(--border-width) solid var(--white);
  border-radius: var(--radius-md);
  color: var(--ink);
  font-size: var(--text-sm);
  text-decoration: none;
}

.month-cell:hover { background: var(--paper-2); }
.month-cell.is-empty { color: var(--ink-soft); }
.month-cell.is-future { color: var(--ink-soft); opacity: .5; cursor: default; }
.month-cell.is-future:hover { background: none; }
.month-cell[aria-current="date"] { border-color: var(--ink); }
.month-cell[aria-current="page"] { background: var(--brand); color: var(--on-brand); font-weight: var(--weight-strong); }

@media (max-width: 63.9375rem) {
  .chart-cards { grid-template-columns: minmax(0, 1fr); }
}

/* Measures of the evaluations from one run to the next (V-1): small charts side by side, the
   state of a point told by its shape (disc, diamond, hollow disc) as well as its colour */
.chart-multiples { display: grid; grid-template-columns: repeat(auto-fit, minmax(22rem, 1fr)); gap: var(--space-4); margin: 0 0 var(--space-6); }
.chart-svg.chart-svg-small { min-width: 18rem; }
.chart-line { fill: none; stroke: var(--ink); stroke-width: 2; vector-effect: non-scaling-stroke; }
.chart-point { stroke: var(--ink); stroke-width: 2; vector-effect: non-scaling-stroke; }
.chart-point-met { fill: var(--success); }
.chart-point-missed { fill: var(--danger); }
.chart-point-unknown { fill: var(--white); }
/* Period picker of the lists (admin_period.js): a calendar with the quick periods beside it,
   written over the native date fields, which stay in the markup (and are all there is without
   the script). The wrapper has no box until the script has run. States are classes, never a
   style attribute (CSP). */
.period-picker { display: contents; }
.period-picker.is-enhanced { display: block; position: relative; min-width: 0; grid-column: span 2; }
.period-picker.is-enhanced > label.field, .period-picker.is-enhanced > details { display: none; }
.period-picker.is-month { grid-column: auto; }
.period-picker.is-month .period-caption { display: none; }
/* The server's quick-period links give way to the ones of the calendar */
.is-replaced { display: none; }

button.period-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  width: 100%;
  min-height: 2.75rem;
  box-sizing: border-box;
  padding: 0 2.25rem 0 var(--space-3);
  border: var(--border-width) solid var(--control);
  border-radius: var(--radius-sm);
  background-color: var(--white);
  /* The chevron of the other selects of the filter bar (.admin-content select) */
  background-image: linear-gradient(45deg, transparent 50%, var(--ink-soft) 50%), linear-gradient(135deg, var(--ink-soft) 50%, transparent 50%);
  background-position: calc(100% - 1.15rem) 52%, calc(100% - .8rem) 52%;
  background-size: .35rem .35rem, .35rem .35rem;
  background-repeat: no-repeat;
  color: var(--ink);
  font-size: var(--text-base);
  font-weight: 400;
  text-align: left;
  transform: none;
  box-shadow: none;
}
button.period-trigger:hover { background-color: var(--sky-soft); color: var(--ink); border-color: var(--control); transform: none; box-shadow: none; }
.period-picker.is-set button.period-trigger, .period-picker.is-open button.period-trigger { border-color: var(--ink); }
.period-picker.is-month button.period-trigger { min-height: 2.5rem; width: auto; min-width: 9rem; font-size: var(--text-sm); font-weight: var(--weight-strong); }

.period-panel {
  position: absolute;
  top: calc(100% + var(--space-1));
  left: 0;
  z-index: 20;
  display: grid;
  grid-template-columns: 11rem minmax(0, 19rem);
  grid-template-areas: "quick nav" "quick grid" "quick summary" "quick actions";
  grid-template-rows: auto auto auto auto;
  align-content: start;
  gap: var(--space-2) var(--space-4);
  box-sizing: border-box;
  width: max-content;
  max-width: calc(100vw - 2 * var(--space-4));
  padding: var(--space-4);
  background: var(--white);
  border: var(--border-width) solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  font-size: var(--text-sm);
  font-weight: 400;
}
.period-panel[hidden] { display: none; }
.period-quick { grid-area: quick; display: flex; flex-direction: column; align-items: stretch; gap: var(--space-1); }
.period-quick .chip { justify-content: flex-start; width: 100%; }
.period-nav { grid-area: nav; display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
.period-title { flex: 1; text-align: center; text-transform: capitalize; font-size: var(--text-base); }
button.period-step {
  width: 2.5rem;
  min-width: 2.5rem;
  min-height: 2.5rem;
  padding: 0;
  border: var(--border-width) solid var(--line-strong);
  border-radius: 50%;
  background: var(--white);
  color: var(--ink);
  font-size: 1.25rem;
  transform: none;
  box-shadow: none;
}
button.period-step:hover:not(:disabled) { background: var(--paper-2); border-color: var(--ink); color: var(--ink); transform: none; box-shadow: none; }
button.period-step:disabled { opacity: .4; cursor: default; }

.period-grid { grid-area: grid; width: 100%; border-collapse: collapse; table-layout: fixed; }
.period-grid th { padding: var(--space-1) 0; color: var(--ink-soft); font-size: var(--text-xs); font-weight: var(--weight-strong); text-align: center; text-transform: capitalize; }
.period-grid td { padding: 1px 0; text-align: center; }
button.period-day {
  display: block;
  width: 100%;
  min-width: 0;
  min-height: 2.5rem;
  padding: 0;
  border: var(--border-width) solid transparent;
  border-radius: 0;
  background: var(--white);
  color: var(--ink);
  font-size: var(--text-sm);
  font-weight: 400;
  transform: none;
  box-shadow: none;
}
button.period-day.is-outside { color: var(--ink-soft); opacity: .55; }
button.period-day:hover:not(:disabled) { background: var(--paper-2); color: var(--ink); border-color: var(--line-strong); transform: none; box-shadow: none; }
button.period-day:disabled { opacity: .3; cursor: default; }
button.period-day.is-today { border-color: var(--ink); border-radius: var(--radius-sm); }
button.period-day.is-between, button.period-day.is-between:hover:not(:disabled) { background: var(--sky-soft); border-radius: 0; border-color: var(--sky-soft); }
button.period-day.is-start, button.period-day.is-end,
button.period-day.is-start:hover:not(:disabled), button.period-day.is-end:hover:not(:disabled) {
  background: var(--brand);
  border-color: var(--brand);
  color: var(--on-brand);
  font-weight: var(--weight-strong);
  opacity: 1;
}
button.period-day.is-start { border-radius: var(--radius-sm) 0 0 var(--radius-sm); }
button.period-day.is-end { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }

.period-summary { grid-area: summary; margin: 0; color: var(--ink-soft); }
.period-actions { grid-area: actions; display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }

/* Month variant (usage): the quick months above, the grid of the year below */
.period-picker.is-month .period-panel {
  right: 0;
  left: auto;
  grid-template-columns: minmax(0, 17rem);
  grid-template-areas: "quick" "nav" "months";
}
.period-picker.is-month .period-quick { flex-direction: row; flex-wrap: wrap; }
.period-picker.is-month .period-quick .chip { width: auto; }
.period-months { grid-area: months; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-1); margin: 0; padding: 0; list-style: none; }
.period-month {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 2.5rem;
  border: var(--border-width) solid var(--white);
  border-radius: var(--radius-md);
  color: var(--ink);
  text-decoration: none;
}
a.period-month:hover { background: var(--paper-2); }
span.period-month { opacity: .4; }
.period-month[aria-current="page"] { background: var(--brand); color: var(--on-brand); font-weight: var(--weight-strong); }
.period-quick .chip[aria-current="page"] { background: var(--ink); border-color: var(--ink); color: var(--white); }

/* Narrow screens: the panel is the width of the form, the quick periods become a row */
@media (max-width: 47.9375rem) {
  .period-picker.is-enhanced { grid-column: 1 / -1; }
  .period-picker.is-month.is-enhanced { grid-column: auto; flex: 1 0 100%; }
  .period-panel, .period-picker.is-month .period-panel {
    position: static;
    width: auto;
    max-width: none;
    margin-top: var(--space-1);
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "quick" "nav" "grid" "summary" "actions";
  }
  .period-picker.is-month .period-panel { grid-template-areas: "quick" "nav" "months"; }
  .period-quick { flex-direction: row; flex-wrap: wrap; }
  .period-quick .chip { width: auto; }
  .period-picker.is-month button.period-trigger { width: 100%; }
}

/* Month calendar on a narrow screen: the arrows and the button stay on one line, the panel is
   the width of that line */
@media (max-width: 47.9375rem) {
  .month-picker { position: relative; flex: 1 0 100%; flex-wrap: nowrap; }
  .period-picker.is-month.is-enhanced { position: static; flex: 1 1 8rem; }
  .period-picker.is-month .period-panel { position: absolute; top: calc(100% + var(--space-1)); right: 0; left: 0; margin: 0; }
}

/* Refusal of a field, under the field (app/static/form_validation.js, or written by the server
   with the same class): a sentence in the danger colour with its glyph, never the colour alone.
   The field has the danger border (the admin rule above, and the access screens here). */
.field-error {
  display: block;
  margin-top: var(--space-1);
  color: var(--danger);
  font-size: var(--text-sm);
  font-weight: 400;
  line-height: 1.4;
}
.field-error::before { content: "! "; font-weight: var(--weight-strong); }
.auth-form .auth-field input[aria-invalid="true"] { border-color: var(--danger); }

/* Dialog of the application (app/static/dialog.js): a native <dialog>, in a card, over a veil.
   The danger button is solid red for a deletion. */
.app-dialog {
  box-sizing: border-box;
  width: calc(100% - var(--space-8));
  max-width: 34rem;
  padding: 0;
  border: var(--border-width) solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--white);
  color: var(--ink);
  box-shadow: var(--shadow-lg);
}
.app-dialog::backdrop { background: color-mix(in srgb, var(--ink) 45%, transparent); }
.app-dialog-body { display: grid; gap: var(--space-4); padding: var(--space-6) var(--space-8); }
.app-dialog-body > * { margin: 0; min-width: 0; }
.app-dialog-title { font-family: var(--font-serif); font-size: var(--text-xl); font-weight: var(--weight-title); line-height: var(--leading-title); }
.app-dialog-text { color: var(--ink-soft); }
.app-dialog .form-actions { justify-content: flex-end; margin-top: var(--space-2); }
.app-dialog .form { max-width: none; }
.app-dialog .button-danger { background: var(--danger); border-color: var(--danger); color: var(--white); }
.app-dialog .button-danger:hover { background: color-mix(in srgb, var(--danger) 85%, var(--ink)); border-color: color-mix(in srgb, var(--danger) 85%, var(--ink)); color: var(--white); }
.app-dialog[aria-busy="true"] { cursor: progress; }
@media (max-width: 47.9375rem) {
  .app-dialog-body { padding: var(--space-5); }
  .app-dialog .form-actions { flex-direction: column-reverse; }
  .app-dialog .form-actions > * { width: 100%; }
}
/* The page of a confirmation (also the content of its dialog): a title, the facts, the form */
.dialog-page { display: grid; gap: var(--space-4); max-width: var(--width-form); }
.dialog-page > * { margin: 0; }

/* Tooltip of the application (app/static/tooltip.js): one element for the page, laid out by the
   script (left and top, set with element.style: the CSP allows it) and shown by a class. It never
   takes the pointer. The arrow points at the element: at the bottom of the box above it, at the
   top of the box below it (.is-below). */
.app-tooltip {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 30;
  box-sizing: border-box;
  max-width: min(20rem, calc(100vw - 1rem));
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-md);
  background: var(--ink);
  color: var(--white);
  box-shadow: var(--shadow-md);
  font-size: var(--text-xs);
  font-weight: 500;
  line-height: 1.35;
  overflow-wrap: anywhere;
  pointer-events: none;
  visibility: hidden;
  opacity: 0;
  transition: opacity .12s ease, visibility 0s linear .12s;
}
.app-tooltip.is-visible { visibility: visible; opacity: 1; transition-delay: 0s; }
.app-tooltip-arrow {
  position: absolute;
  top: 100%;
  width: 0;
  height: 0;
  margin-left: -5px;
  border: 5px solid transparent;
  border-top-color: var(--ink);
}
.app-tooltip.is-below .app-tooltip-arrow { top: auto; bottom: 100%; border-top-color: transparent; border-bottom-color: var(--ink); }
@media (prefers-reduced-motion: reduce) {
  .app-tooltip { transition: none; }
}

/* Fixed tables (class table-fixed, with a <colgroup> in the template, see colgroup() in
   admin/_macros.html): the width of a column comes from its <col> and never from the content,
   so that a longer e-mail address after a sort or a filter does not move the columns. A text
   that may be long (.cell-clip: an address, a title, a comment, a reference) stays on one line
   and ends with an ellipsis; the whole text is in the tooltip (data-tooltip-clip,
   app/static/tooltip.js). Below the minimum width the region scrolls sideways, as before.
   The headers wrap rather than overflow their column. */
.table-fixed { table-layout: fixed; }
/* A table with flexible columns (a <col> without a width class) keeps them readable: the table
   is never narrower than its fixed columns plus about 10 rem for each flexible one (tw-N is
   N rem), and the region scrolls below that. A table with no flexible column is as wide as
   its columns. */
.tw-52 { min-width: 52rem; }
.tw-56 { min-width: 56rem; }
.tw-62 { min-width: 62rem; }
.tw-64 { min-width: 64rem; }
.tw-66 { min-width: 66rem; }
.tw-72 { min-width: 72rem; }
.table-fixed thead th, .table-fixed thead th.number { white-space: normal; overflow-wrap: break-word; }
.table-fixed .sort-link { white-space: normal; }
.table-fixed td { vertical-align: middle; }
.table-fixed td.cell-clip { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; overflow-wrap: normal; }
.table-fixed td.cell-clip .cell-sub { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; overflow-wrap: normal; }
.table-fixed td.cell-clip .cell-sub .badge { white-space: normal; }
.table-fixed td.cell-clip.cell-title { min-width: 0; }
/* Widths of the columns, by what they hold */
.col-select { width: 2.75rem; }
.col-date { width: 10rem; }
.col-datetime { width: 11.5rem; }
.col-datetime-wide { width: 13rem; }
.col-date-short { width: 8rem; }
.col-date-range { width: 11rem; }
.col-tenant { width: 10rem; }
.col-role { width: 8rem; }
.col-mode { width: 7rem; }
.col-mode-wide { width: 10rem; }
.col-status { width: 8.5rem; }
.col-status-wide { width: 11rem; }
.col-state { width: 7.5rem; }
.col-rating { width: 6.5rem; }
.col-cost { width: 6.5rem; }
.col-num { width: 6rem; }
.col-metric { width: 4.5rem; }
.col-kind { width: 7rem; }
.col-source { width: 7rem; }
.col-source-wide { width: 10rem; }
.col-chunks { width: 8rem; }
.col-event { width: 12rem; }
.col-detail { width: 6rem; }
.col-modes { width: 10rem; }
.col-gauge { width: 13rem; }
.col-yes-no { width: 5.5rem; }
.col-branding { width: 9rem; }
.col-tokens { width: 9rem; }
.col-budget { width: 9rem; }
.col-action-one { width: 4.5rem; }
.col-actions { width: 7rem; }
.col-actions-wide { width: 9rem; }
