/*
 * Tafinder design system: the "Mosaïque 3615" world.
 * Nous Portal materials (navy ground, condensed display, Chivo grotesk text, halftone dots)
 * plus one signature move: scores drawn as Minitel-style mosaic gauges.
 * DESIGN.md is the source of truth for the rules; this file implements them.
 */

/* ---------- Fonts: self-hosted so no user request ever reaches a third party ---------- */
@font-face {
  font-family: "Sofia Sans Extra Condensed";
  src: url("../fonts/sofia-sans-extra-condensed/SofiaSansExtraCondensed-Variable.woff2") format("woff2");
  font-weight: 1 1000;
  font-display: swap;
}
@font-face {
  font-family: "Chivo";
  src: url("../fonts/chivo/Chivo-Variable.woff2") format("woff2");
  font-weight: 100 900;
  font-display: swap;
}

/* ---------- Tokens ---------- */
:root {
  --ground: #020236;      /* page: a near-black blue, darker than the panels */
  --panel: #0b0b44;       /* raised blocks: account, run counter, open row, logo-free tiles */
  --line: #22226a;        /* hairline grid rules */
  --ink: #e9e9ff;
  --ink-strong: #fff;     /* nav text on hover and on the current page */
  --muted: #9a9ad0;       /* secondary text, tinted from the ground (7.4:1) */
  --action: #1a1aff;      /* only on things that can be clicked */
  --action-hover: #3d3dff;
  --new: #f2c200;         /* only means "new since your last visit" */
  --new-text: var(--new); /* the same yellow, used as text */
  --warn: #ff6b3d;        /* only means "a source is degraded" */
  --gauge-off: #1d1d5e;
  --tile: var(--ink);     /* the company logo tile */

  --display: "Sofia Sans Extra Condensed", "Arial Narrow", sans-serif;
  --text: "Chivo", "Segoe UI", system-ui, sans-serif;
  --row-text: 0.9375rem;  /* the one size used inside offer rows */

  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-10: 2.5rem;

}

/* Light theme "Papier Minitel": warm paper like the Minitel directory pages, same ink, actions and gauges.
   Contrasts on the paper ground: ink 15.8:1, muted 5.9:1, new-text 5.5:1, warn 5.7:1, action 6.9:1,
   lit vs unlit gauge 12:1. */
:root[data-theme="light"] {
  color-scheme: light;
  --ground: #f2eee3;
  --panel: #e6e0cf;
  --line: #cdc5ad;
  --ink: #0b0b44;
  --ink-strong: #0b0b44;
  --muted: #585878;
  --action: #1a1aff;
  --action-hover: #3d3dff;
  --new: #f2c200;
  --new-text: #7a5a00;    /* the yellow itself is 1.5:1 on paper, too faint for text */
  --warn: #a8341a;
  --gauge-off: #d8d1bc;
  --tile: #fbf9f3;        /* logos are multiplied onto the tile: on the navy ink they would vanish */
}
/* The yellow square alone is 1.5:1 on paper: a hairline in the text yellow keeps it visible. */
:root[data-theme="light"] .new-mark { box-shadow: inset 0 0 0 1px var(--new-text); }
/* The select chevron is a data URI, which cannot read a token: the light theme redraws it in its own ink. */
:root[data-theme="light"] .select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 4.5 6 8l3.5-3.5' fill='none' stroke='%230b0b44' stroke-width='1.6'/%3E%3C/svg%3E");
}

/* ---------- Base and browser surfaces ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { color-scheme: dark; scrollbar-color: var(--line) var(--ground); }
body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font: 400 var(--row-text)/1.5 var(--text);
  font-variant-numeric: tabular-nums; /* scores, times and salaries line up in columns */
  caret-color: var(--ink);
}
::selection { background: var(--action); color: #fff; }
a { color: inherit; text-underline-offset: 0.2em; }
:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
h1, h2, p, ol, ul { margin: 0; }
ol, ul { padding: 0; list-style: none; }
.icon { width: 1em; height: 1em; flex: none; stroke: currentColor; stroke-width: 1.6; fill: none; stroke-linecap: square; }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.mobile-only { display: none; }

/* Labels and navigation speak in the condensed display voice, content in the Chivo voice. */
.label, .field-label { font: 600 0.875rem/1.2 var(--display); letter-spacing: 0.05em; text-transform: uppercase; }

/* ---------- Shell ---------- */
.app { display: grid; grid-template-columns: 18.75rem 1fr; min-height: 100vh; }

.rail {
  position: sticky; top: 0; height: 100vh;
  display: flex; flex-direction: column; gap: var(--space-4);
  padding: var(--space-6) var(--space-6) var(--space-4);
  border-right: 1px solid var(--line);
  overflow: hidden;
}

.brand { display: flex; align-items: center; gap: var(--space-3); text-decoration: none; }
.brand-tile {
  width: 3.75rem; height: 3.75rem;
  background: var(--ink) radial-gradient(var(--ground) 1.4px, transparent 2px) 0 0 / 5px 5px;
}
.brand-name { font: 300 2.5rem/0.85 var(--display); letter-spacing: -0.01em; }

.account { display: flex; justify-content: space-between; padding: var(--space-2) var(--space-3); background: var(--panel); }
.account span:last-child { color: var(--muted); }

.run { display: flex; justify-content: space-between; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-4); background: var(--panel); }
.run .label { display: block; color: var(--muted); }
.run .run-new { color: var(--new-text); }
.run strong { font: 300 3.75rem/1 var(--display); color: var(--new-text); }

.section-tag {
  align-self: flex-start; margin-top: var(--space-2);
  padding: 0 0.375rem; background: var(--ink); color: var(--ground);
  font: 700 0.8125rem/1.5 var(--display); letter-spacing: 0.06em; text-transform: uppercase;
}
/* Nav items end with a dotted leader running to their count, as on Nous Portal. */
.nav-link {
  display: flex; align-items: baseline; gap: var(--space-3);
  padding: 0.3125rem 0;
  font: 600 1.0625rem/1.3 var(--display); letter-spacing: 0.04em; text-transform: uppercase;
  text-decoration: none;
}
.nav-link::after { content: ""; order: 2; flex: 1; border-bottom: 1px dotted var(--line); }
.nav-link .count { order: 3; color: var(--muted); }
.nav-link .icon { order: 0; width: 1rem; height: 1rem; color: var(--muted); align-self: center; }
.nav-link:hover .icon, .nav-link[aria-current="page"] .icon { color: var(--ink); }
.nav-link .degraded { order: 4; align-self: center; width: 0.4375rem; height: 0.4375rem; background: var(--warn); }
.nav-link:hover { color: var(--ink-strong); }
.nav-link:hover::after { border-bottom-color: var(--muted); }
/* Square cells are the world's markers: blue = where you are, yellow = new, orange = degraded. */
.nav-link[aria-current="page"] { color: var(--ink-strong); }
.nav-link[aria-current="page"]::before { content: ""; order: -1; align-self: center; width: 0.4375rem; height: 0.4375rem; background: var(--action); }
.nav-link.mobile-only { display: none; }
.rail-secondary { display: flex; flex-direction: column; gap: var(--space-2); }
/* The theme toggles are buttons: their browser chrome is reset so they wear the rail's look. */
.theme-toggle, .theme-toggle-phone { border: 0; background: none; color: inherit; cursor: pointer; }
/* On desktop the toggle is one more nav link (.nav-link gives it its type and padding), as wide as the links. */
.theme-toggle { width: 100%; text-align: left; }

.me { margin-top: auto; display: flex; align-items: center; gap: var(--space-3); }
.me-initials { display: grid; place-items: center; width: 2rem; height: 2rem; background: var(--panel); }

/* ---------- Main area ---------- */
.main { padding: var(--space-8) var(--space-10) var(--space-10); min-width: 0; }
/* The halftone map of France is the page's one image; it sits where Nous Portal puts its halftone art. */
.page-head { position: relative; padding-right: 15rem; min-height: 10rem; }
.page-art { position: absolute; top: -1.25rem; right: 0; width: 13rem; height: auto; pointer-events: none; }
.page-title { font: 300 clamp(3.5rem, 6.4vw, 5.75rem)/0.9 var(--display); letter-spacing: -0.01em; }
.page-meta { margin-top: var(--space-3); color: var(--muted); }

.alert {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--space-2);
  margin-top: var(--space-6); padding: var(--space-2) var(--space-3);
  border: 1px solid var(--warn); color: var(--warn);
}
.alert a { display: inline-flex; align-items: center; gap: var(--space-2); color: var(--ink); text-decoration: none; }
.alert a:hover { text-decoration: underline; }
.alert .label { display: inline-flex; align-items: center; gap: var(--space-2); }

.toolbar {
  display: flex; flex-wrap: wrap; align-items: end; gap: var(--space-4) var(--space-6);
  margin-top: var(--space-6); border-bottom: 1px solid var(--line);
}
.tabs { display: flex; gap: var(--space-6); }
.tab { padding: var(--space-2) 0; color: var(--muted); font-size: 1rem; text-decoration: none; border-bottom: 2px solid transparent; }
.tab:hover { color: var(--ink); }
.tab[aria-current="page"] { color: var(--ink); border-bottom-color: var(--ink); }
.filters { margin-left: auto; display: flex; gap: var(--space-2); padding-bottom: var(--space-2); }
.select {
  appearance: none; border: 1px solid var(--line); border-radius: 0; background: var(--ground);
  color: var(--ink); padding: var(--space-1) 1.75rem var(--space-1) var(--space-3);
  font: 600 0.9375rem/1.5 var(--display); letter-spacing: 0.04em; text-transform: uppercase;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 4.5 6 8l3.5-3.5' fill='none' stroke='%23e9e9ff' stroke-width='1.6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 0.5rem center; background-size: 0.75rem;
}
.select:hover { border-color: var(--muted); }

/* ---------- Buttons ---------- */
.button, .button-ghost, .chip {
  display: inline-flex; align-items: center; gap: var(--space-2);
  padding: 0.375rem var(--space-3); border: 1px solid transparent; border-radius: 0;
  font: 700 0.875rem/1.3 var(--display); letter-spacing: 0.05em; text-transform: uppercase;
  text-decoration: none; white-space: nowrap; cursor: pointer;
}
.button { background: var(--action); color: #fff; }
.button:hover { background: var(--action-hover); }
.button-ghost, .chip { background: transparent; color: var(--ink); border-color: var(--line); font-weight: 400; }
.button-ghost:hover, .chip:hover { border-color: var(--ink); }
.button:disabled, .button-ghost:disabled { opacity: 0.45; cursor: not-allowed; }

/* ---------- Forms: one calm column of labelled fields ---------- */
.form { display: flex; flex-direction: column; gap: var(--space-4); max-width: 40rem; margin-top: var(--space-6); }
.field { display: flex; flex-direction: column; gap: var(--space-1); }
/* A lone checkbox sits at the left instead of stretching across the column; the ink accent keeps it in the palette. */
.field input[type="checkbox"] { align-self: flex-start; accent-color: var(--ink); }
/* Typed text is the user's own content, so it speaks in the Chivo voice; only the select keeps the control voice. */
.input, .textarea {
  width: 100%; border: 1px solid var(--line); border-radius: 0; background: var(--ground);
  color: var(--ink); padding: var(--space-1) var(--space-3); font: 400 var(--row-text)/1.5 var(--text);
}
.textarea { resize: vertical; }
.field .select { width: 100%; }
.input:hover, .textarea:hover { border-color: var(--muted); }
.input::file-selector-button {
  margin-right: var(--space-3); padding: 0 var(--space-3); border: 1px solid var(--line); border-radius: 0;
  background: transparent; color: var(--ink); font: 400 0.875rem/1.3 var(--display);
  letter-spacing: 0.05em; text-transform: uppercase; cursor: pointer;
}
.field-help { color: var(--muted); }
/* An error adds no colour: the control gets a heavier ink border and the message sits in ink beside the alert icon. */
:is(.input, .textarea, .select)[aria-invalid="true"] { border: 2px solid var(--ink); }
.field-error { display: flex; align-items: center; gap: var(--space-2); }
.form-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }

/* Info, success and error messages: a panel block with an icon. */
/* The AI-proposal notice follows the upload form: give it the spacing of a form section. */
.form + .notice { margin-top: var(--space-6); }
.notice { display: flex; align-items: center; gap: var(--space-3); max-width: 40rem; margin-bottom: var(--space-4); padding: var(--space-3) var(--space-4); background: var(--panel); }

/* ---------- Public pages (login, sign-up): the brand above one centred panel, no rail ---------- */
.public { min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--space-8); }
.public-panel { width: 100%; max-width: 28rem; padding: var(--space-6); background: var(--panel); }
.public-panel .page-title { font-size: 3.75rem; }
.public-panel .page-meta:last-child { margin-top: var(--space-6); }

/* Account section at the bottom of a page: set apart by a hairline. */
.account-section { margin-top: var(--space-10); padding-top: var(--space-6); border-top: 1px solid var(--line); max-width: 40rem; }

/* ---------- Offer list: a strict grid with visible hairline columns ---------- */
/* Widths are sized from the real copy (Chivo, tabular figures):
   the gauge column holds 10 cells plus a score, "Télétravail" fits without touching a rule. */
.offers-head, .offer-row {
  display: grid;
  grid-template-columns: 10.75rem minmax(17rem, 1fr) minmax(10.5rem, 13rem) minmax(8rem, 11rem) 4.5rem;
  align-items: center;
}
.offers-head { min-height: 2rem; color: var(--muted); border-bottom: 1px solid var(--line); }
.offers-head > *, .offer-row > * { padding: 0 var(--space-3); border-right: 1px solid var(--line); }
.offers-head > * { padding: var(--space-2) var(--space-3); }
.offers-head > *:last-child, .offer-row > *:last-child { border-right: 0; }

.offer { border-bottom: 1px solid var(--line); }
.offer-row { min-height: 3rem; cursor: pointer; list-style: none; }
.offer-row::-webkit-details-marker { display: none; }
.offer-row:hover { background: var(--panel); }
.offer[open] { border: 1px solid var(--ink); background: var(--panel); }
.offer-title { display: flex; align-items: center; gap: var(--space-3); font-weight: 600; padding: var(--space-2) var(--space-3); }
.offer-muted { color: var(--muted); }
/* The city repeats inside the company cell when its own column is dropped. */
.inline-city { display: none; }

/* Company logo tile: logos arrive in every colour, so they are flattened to one ink stamp.
   On a light tile, grayscale + multiply turns a white logo background into the tile itself. */
.logo { flex: none; display: grid; place-items: center; width: 2.25rem; height: 2.25rem; background: var(--tile); overflow: hidden; }
.logo img { width: 80%; height: 80%; object-fit: contain; filter: grayscale(1) contrast(1.15); mix-blend-mode: multiply; }
/* No logo found: the company's initials, set like a Minitel character cell. */
.logo-monogram { background: var(--panel); border: 1px solid var(--line); font: 600 1.125rem/1 var(--display); color: var(--ink); letter-spacing: 0.02em; }

/* Facts line at the top of an open offer: one icon per fact, so it scans without reading. */
.offer-facts { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-6); color: var(--muted); }
.offer-facts span { display: inline-flex; align-items: center; gap: var(--space-2); }
.offer-facts .icon { color: var(--ink); }

/* "New since your last visit": a yellow square cell, the same shape as every other marker. */
.new-mark { display: inline-block; width: 0.5rem; height: 0.5rem; margin-right: var(--space-2); background: var(--new); vertical-align: 0.1em; }

.score { display: flex; align-items: center; gap: var(--space-3); }
.score-value { min-width: 1.75rem; }

/* The signature move: a 10-cell gauge, each cell a 2x3 Minitel semigraphic. */
.gauge { display: inline-flex; gap: 2px; }
.gauge-cell { display: grid; grid-template-columns: repeat(2, 4px); grid-template-rows: repeat(3, 5px); gap: 1px; }
.gauge-cell i { background: var(--gauge-off); }
.gauge-cell i.on { background: var(--ink); }

/* ---------- Motion: "1200 bauds", stepped and never eased ----------
   Every animation sits in the one reduced-motion guard below; with reduced motion nothing moves. */
/* The title types in behind a block cursor, which stays hidden until the print animation runs. */
.page-title .print-wrap { position: relative; display: inline-block; }
.page-title .print { display: inline-block; }
.page-title .cursor { position: absolute; top: 0.08em; bottom: 0.08em; left: 100%; width: 0.38em; background: var(--ink); opacity: 0; }
/* Pressed: the button inverts to an ink fill while held. An instant state, not an animation. */
.button:active, .button-ghost:active { background: var(--ink); color: var(--ground); border-color: var(--ink); }
/* While the CV is read (the AI takes seconds), the form shows a status line and a gauge that scans. */
.cv-status { display: none; align-items: center; gap: var(--space-3); color: var(--muted); }
.is-loading .cv-status { display: flex; }
.is-loading button[type=submit] { cursor: progress; opacity: 0.6; }
.loader .gauge-cell i { background: var(--gauge-off); }
/* List fields and the education field grow with their content; static/js/tafinder.js covers browsers without field-sizing. */
textarea.input, .textarea { field-sizing: content; min-height: 2.6rem; }
textarea.input { resize: none; }
@media (prefers-reduced-motion: reduce) { .cv-status .loader { display: none; } }

/* A fresh run writes its gauges in cell by cell, like a Minitel page drawing at 1200 baud.
   The cells stay visible throughout: only a short flash travels along them. */
@media (prefers-reduced-motion: no-preference) {
  .is-fresh .gauge-cell i.on { animation: cell-write 480ms steps(2, end) both; animation-delay: calc(var(--cell) * 45ms + var(--row) * 90ms); }
  /* A page arrives at 1200 bauds: the title types in behind the cursor, then the map draws row by row. */
  .is-printing .page-title .print { animation: type-in 420ms steps(var(--chars), end) both; }
  .is-printing .page-title .cursor { animation: cursor-ride 420ms steps(var(--chars), end) both, cursor-blink 1s steps(1, end) 420ms infinite both; }
  .is-printing .page-art { animation: draw-rows 640ms steps(16, end) 260ms both; }
  .is-printing .page-meta { animation: type-in 300ms steps(12, end) 380ms both; }
  /* A message writes itself left to right, like a teletext line. */
  .notice.is-new { animation: type-in 260ms steps(10, end) both; }
  /* While the CV is read, a yellow write head sweeps the gauge and leaves ink behind. */
  .is-loading .loader .gauge-cell i { animation: cell-scan 1300ms steps(1, end) infinite; animation-delay: calc(var(--cell) * 90ms); }
}
@keyframes cell-write { 0% { background: var(--new); } 100% { background: var(--ink); } }
@keyframes type-in { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes draw-rows { from { clip-path: inset(0 0 100% 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes cursor-ride { from { left: 0; opacity: 1; } to { left: 100%; opacity: 1; } }
@keyframes cursor-blink { 0% { opacity: 1; } 50% { opacity: 0; } 100% { opacity: 0; } }
@keyframes cell-scan {
  0% { background: var(--gauge-off); } 8% { background: var(--new); } 16% { background: var(--ink); }
  78% { background: var(--ink); } 86% { background: var(--gauge-off); } 100% { background: var(--gauge-off); }
}

.offer-detail {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)) auto; gap: var(--space-4) var(--space-6);
  align-items: start; padding: var(--space-4) var(--space-4) var(--space-6) 11.5rem;
}
/* Each criterion reads like a nav item: name, dotted leader, value. */
.criterion-head { display: flex; align-items: baseline; gap: var(--space-2); margin-bottom: var(--space-2); }
.criterion-head::after { content: ""; order: 2; flex: 1; border-bottom: 1px dotted var(--line); }
.criterion-head .label { color: var(--muted); }
.criterion-value { order: 3; }
.criterion p { margin-top: var(--space-1); color: var(--muted); }
.offer-actions { display: flex; gap: var(--space-2); align-self: end; }

/* "Not interested" asks for an optional one-click reason and can be undone. */
.reasons { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); padding: var(--space-3) var(--space-4) var(--space-4) 11.5rem; }
.reasons > .label { margin-right: var(--space-2); color: var(--muted); }

/* Empty run: nothing new, and the sources are fine. Must never look like the broken-source alert. */
.empty { margin-top: var(--space-8); padding: var(--space-8) var(--space-6); border: 1px dotted var(--line); display: grid; gap: var(--space-4); justify-items: start; }
.empty .gauge-cell { grid-template-columns: repeat(2, 8px); grid-template-rows: repeat(3, 10px); gap: 2px; }
.empty .gauge { gap: 4px; }
.empty p { max-width: 60ch; color: var(--muted); }

.pager { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-4); margin-top: var(--space-6); }

.demo-note { margin-top: var(--space-8); color: var(--muted); font-size: 0.8125rem; }

/* ---------- Narrower desktops: city moves under the company ---------- */
@media (max-width: 89.9375rem) {
  .offers-head, .offer-row { grid-template-columns: 10.75rem minmax(15rem, 1fr) minmax(10.5rem, 13rem) 4.5rem; }
  .col-city { display: none; }
  .inline-city { display: block; color: var(--muted); }
  .offer-detail { grid-template-columns: repeat(3, minmax(0, 1fr)); padding-left: var(--space-4); }
  .offer-actions { grid-column: 1 / -1; justify-self: end; }
  .reasons { padding-left: var(--space-4); }
  .page-head { padding-right: 12rem; }
  .page-art { width: 10.5rem; }
}

/* ---------- Phone: the rail becomes a top bar and a bottom tab bar ---------- */
@media (max-width: 47.5rem) {
  .app { grid-template-columns: minmax(0, 1fr); align-content: start; } /* rows keep their natural height on short pages */
  .toolbar > *, .filters { min-width: 0; }
  .nav-link.mobile-only { display: flex; }
  .rail { position: static; height: auto; flex-direction: row; align-items: center; padding: var(--space-3) var(--space-4); border-right: 0; border-bottom: 1px solid var(--line); }
  .account, .section-tag, .rail-secondary, .me { display: none; }
  .brand-tile { width: 2.25rem; height: 2.25rem; }
  .brand-name { font-size: 1.375rem; }
  .run { margin-left: auto; padding: var(--space-2) var(--space-3); }
  .run strong { font-size: 1.75rem; }
  .run .label:not(.run-new) { display: none; } /* keep the label that explains the yellow count */
  /* The only icon-only control: the top bar has no room for a label, so its aria-label carries it.
     It takes over the counter's push to the right, and is as tall as the counter: 44px to tap. */
  .theme-toggle-phone { display: grid; place-items: center; width: 2.75rem; height: 2.75rem; margin-left: auto; border: 1px solid var(--line); }
  .theme-toggle-phone + .run { margin-left: 0; }
  .theme-toggle-phone:hover { border-color: var(--ink); }
  .theme-toggle-phone .icon { width: 1rem; height: 1rem; }
  .rail-primary {
    position: fixed; inset: auto 0 0 0; z-index: 2;
    display: grid; grid-template-columns: repeat(4, 1fr);
    background: var(--ground); border-top: 1px solid var(--line);
  }
  .rail-primary .nav-link { justify-content: center; padding: var(--space-3) 0 var(--space-6); font-size: 0.8125rem; border-top: 2px solid transparent; margin-top: -1px; }
  .rail-primary .nav-link[aria-current="page"] { border-top-color: var(--ink); }
  .rail-primary .nav-link::after, .rail-primary .nav-link::before, .rail-primary .count { display: none; }
  .main { padding: var(--space-6) var(--space-4) 6rem; }
  .page-head { padding-right: 6.5rem; min-height: 0; }
  .page-art { top: -0.5rem; width: 6.5rem; }
  .toolbar { flex-direction: column; align-items: stretch; }
  .filters { margin-left: 0; flex-wrap: wrap; }
  .offers-head { display: none; }
  .offer-row {
    grid-template-columns: auto 1fr auto;
    grid-template-areas: "score score time" "title title title" "meta meta meta";
    row-gap: var(--space-1); padding: var(--space-3) 0;
  }
  .offer-row > * { border-right: 0; }
  .offer-row .score { grid-area: score; }
  .offer-row .col-time { grid-area: time; }
  .offer-row .offer-title { grid-area: title; padding: 0 var(--space-3); }
  .offer-row .col-company { grid-area: meta; }
  .inline-city { display: inline; }
  .inline-city::before { content: " · "; }
  .offer-detail { grid-template-columns: 1fr 1fr; padding: var(--space-2) var(--space-3) var(--space-4); }
  .offer-actions { grid-column: 1 / -1; justify-self: stretch; }
  .offer-actions > *, .offer-actions form > * { flex: 1; justify-content: center; }
  .reasons { padding: 0 var(--space-3) var(--space-4); }
}

/* ---------- Applications: what to confirm first, then the same hairline grid as the offers ---------- */
/* An undo sits at the end of the confirmation it can reverse. */
.notice .button-ghost { margin-left: auto; }
/* Each button of a notice or of a row is its own POST form, laid out as if the form was not there. */
.offer-actions form, .notice form, .confirm-actions form { display: contents; }
.to-confirm { margin-top: var(--space-6); }
.to-confirm h2 { padding-bottom: var(--space-2); border-bottom: 1px solid var(--line); }
.to-confirm h2 .offer-muted { font: 400 var(--row-text)/1.5 var(--text); letter-spacing: 0; text-transform: none; }
.confirm-row { display: grid; grid-template-columns: minmax(17rem, 1fr) minmax(10.5rem, 14rem) auto; align-items: center; min-height: 3rem; border-bottom: 1px solid var(--line); }
.confirm-row > * { padding: 0 var(--space-3); border-right: 1px solid var(--line); }
.confirm-row > *:last-child { border-right: 0; }
.confirm-actions { display: flex; gap: var(--space-2); padding: var(--space-2) var(--space-3); }
/* "Mails à vérifier" reuses the confirm rows: a select and three buttons wrap. The rows share one grid (subgrid),
   so the column rules line up even when a row has no "Créer". */
.to-check ol { display: grid; grid-template-columns: minmax(17rem, 1fr) minmax(10.5rem, 14rem) auto; }
.to-check .confirm-row { grid-column: 1 / -1; grid-template-columns: subgrid; }
.to-check .confirm-actions { flex-wrap: wrap; align-items: center; }
.to-check-all { display: flex; justify-content: flex-end; margin-top: var(--space-3); }
.to-check .confirm-actions .select { width: 14rem; }
/* A second fact under a cell's value (when an offer was opened, a source's last error), in muted text. */
.inline-note { display: block; color: var(--muted); font-weight: 400; }

:is(.apps-head, .app-row) {
  display: grid;
  grid-template-columns: 12.5rem minmax(17rem, 1fr) minmax(10.5rem, 13rem) minmax(8rem, 11rem) 6.5rem;
  align-items: center;
}
.apps-head { min-height: 2rem; color: var(--muted); border-bottom: 1px solid var(--line); }
:is(.apps-head, .app-row) > * { padding: 0 var(--space-3); border-right: 1px solid var(--line); }
.apps-head > * { padding: var(--space-2) var(--space-3); }
:is(.apps-head, .app-row) > *:last-child { border-right: 0; }
.app-row { min-height: 3rem; cursor: pointer; list-style: none; }
.app-row::-webkit-details-marker { display: none; }
.app-row:hover { background: var(--panel); }
/* The stage track reuses the gauge's cells: one lit cell per stage reached (applied, followed up, interview, answer). */
.stage { display: flex; align-items: center; gap: var(--space-3); }
.stage-track { gap: 3px; }

.app-detail {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: var(--space-4) var(--space-6);
  align-items: start; padding: var(--space-4) var(--space-4) var(--space-6) 13.5rem;
}
.app-detail .offer-actions { grid-column: 1 / -1; justify-self: end; }
/* The history reads like the criteria: stage, dotted leader, date. */
.history li { display: flex; align-items: baseline; gap: var(--space-2); }
.history li::after { content: ""; order: 2; flex: 1; border-bottom: 1px dotted var(--line); }
.history li + li { margin-top: var(--space-1); }
.history .label { color: var(--muted); }
.history .criterion-value { white-space: nowrap; }
/* A mail the reader attached reads like a step, led by a smaller mail icon. */
.history-mail .label { display: inline-flex; align-items: center; gap: var(--space-1); }
.history-mail .icon { width: 0.875rem; height: 0.875rem; vertical-align: -0.125em; }
.stage-picker { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.stage-picker > .label { flex-basis: 100%; color: var(--muted); }
/* The current stage is marked like the current page: an ink border and the blue "you are here" cell. */
.chip[aria-pressed="true"] { border-color: var(--ink); }
.chip[aria-pressed="true"]::before { content: ""; width: 0.4375rem; height: 0.4375rem; background: var(--action); }

/* ---------- Sources: one row per site, failure loud, history as a mosaic bar ---------- */
:is(.sources-head, .source-row) {
  display: grid;
  grid-template-columns: minmax(15rem, 1fr) 8.5rem 10.5rem minmax(12rem, 14rem) 5rem 9rem;
  align-items: center;
}
.sources-head { margin-top: var(--space-6); min-height: 2rem; color: var(--muted); border-bottom: 1px solid var(--line); }
:is(.sources-head, .source-row) > * { padding: 0 var(--space-3); border-right: 1px solid var(--line); }
.sources-head > * { padding: var(--space-2) var(--space-3); }
:is(.sources-head, .source-row) > *:last-child { border-right: 0; }
.source-row { min-height: 3.5rem; border-bottom: 1px solid var(--line); }
.source-state { display: inline-flex; align-items: center; gap: var(--space-2); }
.source-state.is-degraded { color: var(--warn); }
.source-state .degraded { width: 0.4375rem; height: 0.4375rem; background: var(--warn); }
/* Each run is one cell that fills from the bottom with the offers it found; a failed run is an empty frame. */
.run-history { gap: 3px; }
.run-history .gauge-cell { grid-template-columns: repeat(2, 5px); grid-template-rows: repeat(3, 6px); }
.inline-day { display: none; }
.run-history .is-failed { outline: 1px solid var(--line); }
.run-history .is-failed i { background: transparent; }

@media (max-width: 89.9375rem) {
  :is(.apps-head, .app-row) { grid-template-columns: 12.5rem minmax(15rem, 1fr) minmax(10.5rem, 13rem) 6.5rem; }
  .app-detail { padding-left: var(--space-4); }
  /* The 24 h count moves under the last run, so the screen drops a rule, not a fact. */
  :is(.sources-head, .source-row) { grid-template-columns: minmax(11rem, 1fr) 7.5rem 10rem minmax(11rem, 13rem) 8rem; }
  .col-day { display: none; }
  .inline-day { display: block; }
}

@media (max-width: 47.5rem) {
  .notice { flex-wrap: wrap; }
  .confirm-row { grid-template-columns: 1fr; padding: var(--space-3) 0; row-gap: var(--space-2); }
  .confirm-row > * { border-right: 0; }
  .confirm-actions { padding-top: 0; }
  .confirm-actions > *, .confirm-actions form > * { flex: 1; justify-content: center; }
  /* A long option must not widen the row past the screen. */
  .to-check ol { display: block; }
  .to-check .confirm-row { grid-template-columns: minmax(0, 1fr); }
  .to-check .confirm-actions .select { width: 100%; min-width: 0; flex: 1 1 100%; }
  .apps-head, .sources-head { display: none; }
  .app-row {
    grid-template-columns: auto 1fr auto;
    grid-template-areas: "stage stage time" "title title title" "meta meta meta";
    row-gap: var(--space-1); padding: var(--space-3) 0;
  }
  .app-row > * { border-right: 0; }
  .app-row .stage { grid-area: stage; }
  .app-row .col-time { grid-area: time; }
  .app-row .offer-title { grid-area: title; padding: 0 var(--space-3); }
  .app-row .col-company { grid-area: meta; }
  .app-detail { grid-template-columns: 1fr; padding: var(--space-2) var(--space-3) var(--space-4); }
  .app-detail .offer-actions { justify-self: stretch; }
  .source-row { grid-template-columns: 1fr auto; row-gap: var(--space-1); padding: var(--space-3) 0; }
  .source-row > * { border-right: 0; }
  .source-row .col-day { display: block; }
  .source-row .inline-day { display: none; }
  .source-row [data-label] { grid-column: 1 / -1; color: var(--muted); }
  .source-row [data-label]::before { content: attr(data-label) " · "; }
  .source-row .history-cell { grid-column: 1 / -1; }
}
