:root {
  color-scheme: light;
  /* -apple-system first so macOS and iOS get San Francisco's tighter,
     better-spaced UI cut rather than whatever system-ui resolves to. */
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  /* Proportional figures look uneven in a column of money; these make every
     digit the same width without switching to a monospace face. */
  font-variant-numeric: tabular-nums;

  --bg: #f1f5f9;
  --surface: #fff;
  --surface-alt: #f8fafc;
  --border: #e2e8f0;
  --border-strong: #cbd5e1;
  --text: #0f172a;
  --text-secondary: #475569;
  --text-label: #334155;
  --text-muted: #64748b;
  --text-faint: #94a3b8;
  --accent: #4d82c9;
  --accent-hover: #3e6da3;
  --accent-soft: #eaf1f8;
  --accent-soft-border: #c7d9ec;
  --success-bg: #dcfce7;
  --success-bg-soft: #f0fdf4;
  --success-border: #bbf7d0;
  --success-text: #166534;
  --success-text-strong: #14532d;
  --success-solid: #16a34a;
  --danger-bg: #fee2e2;
  --danger-text: #991b1b;
  --danger-text-strong: #b91c1c;
  --danger-solid: #dc2626;
  --warning-bg: #fef3c7;
  --warning-border: #fde68a;
  --warning-text: #92400e;
  --partial-bg: #fef9c3;
  --partial-text: #a16207;
  --info-bg: #eff6ff;
  --info-border: #bfdbfe;
  --info-text: #1e40af;
  --info-text-strong: #1e3a8a;
  --overlay: rgba(15, 23, 42, 0.45);

  /* Depth and shape, named once so a card, a modal and a popover can't
     drift apart. The shadows are deliberately soft and low-contrast —
     this is a working tool, not a landing page. */
  --shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.06);
  --shadow-md: 0 1px 3px rgba(15, 23, 42, 0.08), 0 4px 12px rgba(15, 23, 42, 0.05);
  --shadow-lg: 0 10px 30px rgba(15, 23, 42, 0.14);
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 14px;
  --row-hover: rgba(15, 23, 42, 0.035);
  --ease: 140ms cubic-bezier(0.4, 0, 0.2, 1);
}

/* Dark palette. Applied via data-theme, set on <html> by an inline script
   in <head> (before first paint) based on the saved choice or, absent one,
   prefers-color-scheme — see index.html and the theme toggle in app.js. */
:root[data-theme='dark'] {
  color-scheme: dark;

  --bg: #0b1220;
  --surface: #111827;
  --surface-alt: #17212f;
  --border: #24313f;
  --border-strong: #34445a;
  --text: #e5e9f0;
  --text-secondary: #b6c2d1;
  --text-label: #a9b6c6;
  --text-muted: #8695a7;
  --text-faint: #64748b;
  --accent: #5b9bd8;
  --accent-hover: #8fc1ee;
  --accent-soft: rgba(91, 155, 216, 0.16);
  --accent-soft-border: rgba(91, 155, 216, 0.35);
  --success-bg: rgba(34, 197, 94, 0.18);
  --success-bg-soft: rgba(34, 197, 94, 0.12);
  --success-border: rgba(34, 197, 94, 0.4);
  --success-text: #4ade80;
  --success-text-strong: #86efac;
  --danger-bg: rgba(239, 68, 68, 0.18);
  --danger-text: #f87171;
  --danger-text-strong: #fca5a5;
  --warning-bg: rgba(245, 158, 11, 0.18);
  --warning-border: rgba(245, 158, 11, 0.4);
  --warning-text: #fbbf24;
  --partial-bg: rgba(234, 179, 8, 0.18);
  --partial-text: #fde047;
  --info-bg: rgba(59, 130, 246, 0.16);
  --info-border: rgba(59, 130, 246, 0.35);
  --info-text: #93c5fd;
  --info-text-strong: #bfdbfe;
  --overlay: rgba(0, 0, 0, 0.6);

  /* On a dark background a drop shadow barely reads, so the cards lift by
     being lighter than the page instead — the shadows stay only to keep
     modals and popovers detached from what's behind them. */
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
  --shadow-md: 0 1px 3px rgba(0, 0, 0, 0.35), 0 6px 16px rgba(0, 0, 0, 0.25);
  --shadow-lg: 0 16px 40px rgba(0, 0, 0, 0.5);
  --row-hover: rgba(255, 255, 255, 0.035);
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  display: flex;
  align-items: flex-start;
}

/* Every control that doesn't name its own colours falls back to the
   browser's, which in dark mode is a warm grey that sits next to our own
   navy fields looking like it belongs to a different application. Element
   selectors, so any component rule (all of which use a class) still wins.
   surface-alt rather than surface: a field should read as a well in the
   card it sits on, not as more card. */
input,
select,
textarea {
  background-color: var(--surface-alt);
  color: var(--text);
}

/* Desktop browsers (macOS Chrome/Safari especially) draw a native bezel for
   <select> that ignores the CSS `border` property entirely unless the
   native appearance is stripped — without this, a select's actual on-screen
   border thickness silently diverges from whatever border-width its rule
   specifies, so two selects sitting side by side (e.g. the account/category
   filters) don't visually match even though their CSS is identical. This
   strips that native chrome app-wide and draws one consistent custom arrow
   instead; each context below still controls its own border/padding/size. */
select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.65rem center;
  background-size: 14px;
}

header {
  background: #0f172a;
  color: #fff;
  padding: 1.25rem 0.85rem;
  /* A hairline rather than a hard edge: the sidebar and the page meet
     without a seam you notice. */
  border-right: 1px solid rgba(255, 255, 255, 0.06);
  width: 232px;
  flex-shrink: 0;
  position: sticky;
  top: 0;
  align-self: flex-start;
  height: 100vh;
  overflow-y: auto;
  box-sizing: border-box;
}

.header-bar {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 1.25rem;
  height: 100%;
}

.privacy-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.25);
  border-radius: 999px;
  width: 2rem;
  height: 2rem;
  color: #fff;
  cursor: pointer;
  flex-shrink: 0;
}

.header-icons {
  display: flex;
  gap: 0.4rem;
  margin-left: 0;
  margin-top: auto;
  padding-top: 0.9rem;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  flex-shrink: 0;
}

.privacy-toggle:hover {
  background: rgba(255, 255, 255, 0.2);
}

.privacy-toggle.active {
  background: var(--accent);
  border-color: var(--accent);
}

.brand-logo {
  height: 56px;
  width: auto;
  display: block;
  background: #fff;
  padding: 5px 12px;
  border-radius: var(--radius-md);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
  flex-shrink: 0;
  align-self: flex-start;
}

#tabs {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

.mobile-nav-btn {
  display: none;
}

.tab-btn {
  background: transparent;
  color: #94a3b8;
  border: none;
  padding: 0.5rem 0.7rem;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 0.95rem;
  white-space: nowrap;
  text-align: left;
  transition: background var(--ease), color var(--ease);
}

.tab-btn:hover:not(.active) {
  background: rgba(255, 255, 255, 0.06);
  color: #e2e8f0;
}

/* A tinted pill rather than a solid white one: the old block was the
   loudest thing on the screen, which put the emphasis on the menu instead
   of on the work. */
.tab-btn.active {
  background: rgba(91, 155, 216, 0.18);
  color: #fff;
  font-weight: 600;
  box-shadow: inset 2px 0 0 var(--accent);
}

main {
  flex: 1;
  min-width: 0;
  margin: 2rem auto;
  padding: 0 1.5rem;
}

.tab-panel {
  display: none;
}

.tab-panel.active {
  display: block;
}

.sub-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 1.25rem;
  border-bottom: 1px solid var(--border);
  padding-bottom: 0.75rem;
}

.sub-tab-btn {
  background: var(--border);
  color: var(--text-secondary);
  border: none;
  padding: 0.5rem 0.9rem;
  border-radius: 6px;
  cursor: pointer;
  font-size: 0.9rem;
  font-weight: 600;
}

.sub-tab-btn.active {
  background: var(--accent);
  color: #fff;
}

.sub-tab-panel {
  display: none;
}

.sub-tab-panel.active {
  display: block;
}

/* Same look as .sub-tab-btn/.sub-tab-panel but a separate class+handler —
   the existing one queries .sub-tab-btn/.sub-tab-panel globally with no
   scoping, so sharing it would let switching Comptabilité's sub-tabs reset
   Soumissions' sub-tab state (and vice versa). */
.accounting-subtab-btn {
  background: var(--border);
  color: var(--text-secondary);
  border: none;
  padding: 0.5rem 0.9rem;
  border-radius: 6px;
  cursor: pointer;
  font-size: 0.9rem;
  font-weight: 600;
}

.accounting-subtab-btn.active {
  background: var(--accent);
  color: #fff;
}

.accounting-subtab-panel {
  display: none;
}

.accounting-subtab-panel.active {
  display: block;
}

.toolbar {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-bottom: 1rem;
  flex-wrap: wrap;
}

.toolbar input[type='search'] {
  flex: 1;
  min-width: 200px;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
}

/* Explicit box styling (rather than relying on the browser's native <select>
   chrome) so the account and category filters always render with the same
   border thickness as each other — native rendering can otherwise vary with
   the select's content width, especially on mobile. */
.toolbar select {
  min-width: 160px;
  padding: 0.5rem 2.2rem 0.5rem 0.75rem;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  box-sizing: border-box;
  background-color: var(--surface);
  color: var(--text);
}

.export-dropdown {
  position: relative;
  display: inline-block;
}

.export-menu {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  box-shadow: 0 8px 20px rgba(15, 23, 42, 0.15);
  min-width: 130px;
  z-index: 50;
  overflow: hidden;
}

.export-menu.hidden {
  display: none;
}

.export-menu button {
  display: block;
  width: 100%;
  text-align: left;
  padding: 0.55rem 0.9rem;
  background: none;
  border: none;
  cursor: pointer;
  font-size: 0.9rem;
  color: var(--text);
}

.export-menu button:hover {
  background: var(--bg);
}

.checkbox-label {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.9rem;
  color: var(--text-secondary);
}

/* `.form label { display: block }` further down outranks the rule above on
   specificity, so inside any form a checkbox-label lost its row layout and
   the box sat on a line of its own above its text. The share-link modal
   had already patched this for itself; this covers the rest, including the
   supplément list in Options et prix. */
.form .checkbox-label {
  display: flex;
  margin-bottom: 0;
}

.form .checkbox-label input {
  display: inline-block;
  width: auto;
  margin: 0;
  flex: none;
}

/* A filter that belongs to the search box above it, not beside it: in the
   row it was loose text stranded in the gap at the far right. Boxed and
   sized to its own text so it reads as a control rather than a caption. */
.toolbar-tight {
  margin-bottom: 0.5rem;
}

.filter-below {
  display: inline-flex;
  align-self: flex-start;
  width: fit-content;
  margin-bottom: 1.25rem;
  padding: 0.45rem 0.75rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  white-space: nowrap;
  cursor: pointer;
}

table {
  width: 100%;
  border-collapse: collapse;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
}

th, td {
  text-align: left;
  padding: 0.65rem 0.8rem;
  border-bottom: 1px solid var(--border);
  font-size: 0.9rem;
  white-space: nowrap;
}

/* The last row already has the table's own border under it. */
tbody tr:last-child td {
  border-bottom: none;
}

/* Follows the eye across a wide row — the tables here run to eight or nine
   columns and it's easy to slip a line while reading right. */
tbody tr:hover td {
  background: var(--row-hover);
}

.invoice-merged-row {
  background: var(--accent-soft);
}

.invoice-merged-row td:nth-child(2) {
  font-weight: 700;
  color: var(--accent-hover);
}

th {
  background: var(--surface-alt);
  font-weight: 600;
  color: var(--text-muted);
  /* Small caps set the header apart from the data without needing weight
     or a heavy fill, so the rows below stay the loudest thing. */
  font-size: 0.74rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  border-bottom-color: var(--border-strong);
}

.btn-primary {
  background: var(--accent);
  color: #fff;
  border: none;
  padding: 0.55rem 1rem;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-weight: 600;
  box-shadow: var(--shadow-sm);
  transition: background var(--ease), box-shadow var(--ease), transform var(--ease);
}

.btn-primary:hover {
  background: var(--accent-hover);
}

.btn-primary:active,
.btn-secondary:active {
  /* A press you can feel, rather than a state you have to infer. */
  transform: translateY(1px);
}

.btn-secondary {
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border-strong);
  padding: 0.55rem 1rem;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background var(--ease), border-color var(--ease), transform var(--ease);
}

.btn-secondary:hover:not(:disabled) {
  background: var(--surface-alt);
  border-color: var(--text-faint);
}

.btn-secondary.active {
  background: var(--accent);
  color: #fff;
}

.btn-secondary:disabled {
  opacity: 0.5;
  cursor: default;
}

.btn-link {
  background: none;
  border: none;
  color: var(--accent);
  cursor: pointer;
  padding: 0.2rem 0.4rem;
  font-size: 0.85rem;
  /* No underline anywhere in the app — the accent colour carries the
     affordance, and most of these are icons rather than text anyway. */
  text-decoration: none;
}

/* Icon-only action buttons (Ouvrir/Modifier/Supprimer/Appliquer à une
   facture, etc.) — every one of these carries a title="" tooltip for the
   label that used to be visible text, so that attribute doubles as a
   precise selector for "this .btn-link is an icon, not a text link". */
.btn-link[title] {
  text-decoration: none;
  font-size: 0.85rem;
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
}

/* "Retour aux X" back-links above the quote/request/invoice builders — a
   real arrow icon instead of the "&larr;" text glyph, and no underline
   since the icon already reads as navigation. */
.btn-back {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  text-decoration: none;
  margin-bottom: 0.75rem;
}

.btn-link[title] svg {
  flex-shrink: 0;
}

.name-link {
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
  text-align: left;
}

.name-link:hover {
  color: var(--accent);
}

.btn-link-danger {
  color: var(--danger-text-strong);
}

.modal-backdrop {
  position: fixed;
  inset: 0;
  background: var(--overlay);
  /* Pushes the page back a step so the dialog is clearly the thing in
     front, rather than a panel floating on a dimmed screenshot. */
  backdrop-filter: blur(2px);
  display: flex;
  align-items: center;
  justify-content: center;
}

.modal-backdrop.hidden {
  display: none;
}

.modal {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: 1.5rem;
  width: 420px;
  max-width: 90vw;
  max-height: 85vh;
  overflow-y: auto;
}

.modal.modal-wide {
  width: auto;
  max-width: 94vw;
}

#login-view {
  position: fixed;
  inset: 0;
  background: var(--bg);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2000;
}

#login-view.hidden {
  display: none;
}

.login-box {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 2rem;
  width: 320px;
  max-width: 90vw;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.75rem;
  box-shadow: 0 10px 30px rgba(15, 23, 42, 0.12);
}

.login-logo {
  height: 56px;
  align-self: center;
  margin-bottom: 0.5rem;
  border-radius: 8px;
}

.login-box .btn-link {
  align-self: center;
  text-decoration: none;
}

.login-box label {
  font-size: 0.85rem;
  color: var(--text-label);
  display: block;
}

.login-box input {
  display: block;
  width: 100%;
  margin-top: 0.3rem;
  padding: 0.5rem 0.6rem;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  box-sizing: border-box;
}

.login-box form {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.login-error {
  color: var(--danger-text-strong);
  font-size: 0.85rem;
  margin: 0;
}

.passkey-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.6rem 0;
  border-bottom: 1px solid var(--bg);
}

/* The auth passkey list has no far-right column to balance against (unlike
   the bank-account/category reuses of .passkey-row), so space-between
   stranded the delete button at the row's far edge, away from the text. */
#passkey-list .passkey-row {
  justify-content: flex-start;
}

.passkey-row-main {
  flex: 1;
  min-width: 0;
}

#bank-account-list .passkey-row.dragging {
  opacity: 0.4;
}

.passkey-row-info {
  font-size: 0.9rem;
}

.passkey-row-meta {
  font-size: 0.8rem;
  color: var(--text-muted);
}

.form label {
  display: block;
  margin-bottom: 0.85rem;
  font-size: 0.9rem;
  color: var(--text-label);
}

.form input,
.form select,
.form textarea {
  display: block;
  width: 100%;
  margin-top: 0.3rem;
  padding: 0.5rem 0.6rem;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  font-size: 0.95rem;
  box-sizing: border-box;
}

.form select {
  padding-right: 2.2rem;
  background-color: var(--surface);
  color: var(--text);
}

.form textarea {
  min-height: 60px;
  resize: vertical;
}

.form-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.6rem;
  margin-top: 1rem;
}

/* A modal taller than the screen scrolls its own body, which used to carry
   Annuler/Envoyer out of sight below a long message — the one thing the
   dialog is open for. Pinned to the bottom they stay reachable; in a modal
   short enough not to scroll this changes nothing. The negative bottom
   margin cancels the modal's own padding so the buttons sit flush against
   its edge with no strip of content scrolling underneath. */
.modal .form-actions {
  position: sticky;
  bottom: -1.5rem;
  margin-bottom: -1.5rem;
  padding: 0.75rem 0 1.5rem;
  background: var(--surface);
}

.hidden {
  display: none !important;
}

.builder-header {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 1rem;
  margin: 0.5rem 0 1rem;
}

.builder-header h2 {
  margin: 0;
  font-size: 1.2rem;
}

/* Pairs a supplier request with the customer quote produced from it, so
   which enquiry belongs to which soumission is visible at a glance. */
.request-quote-link {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.75rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.7rem 0.9rem;
  margin-bottom: 1rem;
  font-size: 0.88rem;
}

.request-quote-link .link-label {
  color: var(--text-muted);
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.request-quote-link .link-actions {
  margin-left: auto;
  display: flex;
  gap: 0.5rem;
  align-items: center;
}

.manual-item-row {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  margin-bottom: 0.5rem;
}

.manual-item-row .manual-item-label {
  flex: 1;
}

.manual-item-row .manual-item-qty {
  width: 60px;
}

.manual-item-row .manual-item-cost {
  width: 100px;
}

.production-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  background: var(--warning-bg);
  border: 1px solid var(--warning-border);
  color: var(--warning-text);
  border-radius: 999px;
  padding: 0.2rem 0.6rem;
  font-size: 0.78rem;
  font-weight: 600;
}

.production-badge.ordered {
  background: var(--success-bg);
  border-color: var(--success-border);
  color: var(--success-text);
}

#production-table td.production-ordered {
  color: var(--success-text);
  font-weight: 600;
}

.segmented-toggle {
  display: inline-flex;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  overflow: hidden;
  flex-wrap: wrap;
}

.segmented-toggle .segment {
  border: none;
  border-right: 1px solid var(--border);
  background: var(--surface);
  padding: 0.35rem 0.9rem;
  font-size: 0.8rem;
  cursor: pointer;
  color: var(--text-muted);
}

.segmented-toggle .segment:last-child {
  border-right: none;
}

.segmented-toggle .segment.active {
  font-weight: 700;
  background: var(--border);
  color: var(--text-label);
}

.segmented-toggle .segment[data-value='sent'].active {
  background: var(--accent-soft);
  color: var(--accent-hover);
}

.segmented-toggle .segment[data-value='accepted'].active,
.segmented-toggle .segment[data-value='paid'].active {
  background: var(--success-bg);
  color: var(--success-text);
}

.segmented-toggle .segment[data-value='declined'].active {
  background: var(--danger-bg);
  color: var(--danger-text);
}

.segmented-toggle .segment[data-value='unpaid'].active {
  background: var(--danger-bg);
  color: var(--danger-text);
}

.segmented-toggle .segment[data-value='partial'].active {
  background: var(--partial-bg);
  color: var(--partial-text);
}

.segmented-toggle .segment[data-value='vacation'].active {
  background: var(--warning-bg);
  color: var(--warning-text);
}

.segmented-toggle .segment[data-value='no_work'].active {
  background: var(--danger-bg);
  color: var(--danger-text);
}

.segmented-toggle-disabled .segment {
  opacity: 0.5;
  cursor: not-allowed;
  pointer-events: none;
}

.segmented-toggle-small {
  display: inline-flex;
  flex-wrap: nowrap;
  margin-top: 0.3rem;
}

.segmented-toggle-small .segment {
  padding: 0.3rem 0.5rem;
  font-size: 0.75rem;
  white-space: nowrap;
}

#invoice-deposits-table .segmented-toggle-small {
  margin-top: 0;
}

/* Same reason: the top margin is there for a toggle that sits under its
   own label, and in a row of inputs it pushed this one 5px out of line and
   left it shorter than everything beside it. */
.deposit-add-row .segmented-toggle-small {
  margin-top: 0;
  align-self: stretch;
}

#invoice-deposits-table td:nth-child(3) {
  min-width: 190px;
}

#invoice-deposits-table td:nth-child(4) {
  min-width: 140px;
}

#invoice-deposits-table td:last-child {
  white-space: nowrap;
  min-width: 175px;
}

#invoice-deposits-table .btn-link {
  padding: 0.2rem 0.3rem;
}

.row-actions {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.1rem;
}

.row-actions .btn-link {
  white-space: nowrap;
}

/* The Factures table has enough columns that its actions cell used to get
   pushed past the right edge on a narrow window, requiring a horizontal
   scroll the user might not notice — reading as "the icons are cropped".
   Pinning this cell was tried and rejected once before, back when Ouvrir/
   Supprimer were full-width text buttons that badly overlapped the Solde
   column when scrolled — now that they're compact icons the overlap is
   small enough (a few px of the Solde figure) that a left-edge shadow
   reads as an intentional pinned column rather than a hard, ugly cut.
   position: sticky also silently fails on table cells under border-
   collapse: collapse (the base `table` rule) in Chromium — separate +
   zero spacing keeps the same tight visual joins while letting sticky
   actually work here, and overflow: visible undoes the base rule's
   rounded-corner clipping, which was clipping the stuck cell too. */
#invoice-table {
  border-collapse: separate;
  border-spacing: 0;
  overflow: visible;
}

#invoice-table th:last-child,
#invoice-table td:last-child {
  white-space: nowrap;
  position: sticky;
  right: 0;
  background: var(--surface);
  box-shadow: -6px 0 6px -6px rgba(15, 23, 42, 0.15);
}

#invoice-table th:last-child {
  background: var(--surface-alt);
}

#invoice-table .invoice-merged-row td:last-child {
  background: var(--accent-soft);
}

/* A <select> sizes itself to fit its selected option's text — a long
   category name (e.g. "Téléphone et services publics") was pushing the
   Supprimer button in the next cell out of view. */
#tx-table select {
  max-width: 170px;
  padding: 0.35rem 1.8rem 0.35rem 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: 4px;
  box-sizing: border-box;
  background-color: var(--surface);
  color: var(--text);
  font-size: 0.85rem;
}

#tx-table td:last-child {
  white-space: nowrap;
}

/* The two filter selects beside it grow to fill the row; left at its
   intrinsic width the search box was a third their size and cut its own
   placeholder off mid-word. */
#tx-search {
  flex: 1 1 160px;
  min-width: 0;
}

/* Deliberately NOT display:flex. A flex <td> is taken out of the table's
   row box: it sized itself to its own content, ending a few pixels short
   of its neighbours, and drew its bottom border there — so the line under
   every row broke and stepped where this column began. The span and the
   button are inline already; they only need to agree on a baseline. */
.tx-desc-cell {
  white-space: nowrap;
}

.tx-desc-cell > span {
  vertical-align: middle;
}

.tx-desc-cell .btn-link {
  vertical-align: middle;
  margin-left: 0.3rem;
  opacity: 0.5;
}

.tx-desc-cell .btn-link:hover {
  opacity: 1;
}

.held-deposits-table {
  min-width: 900px;
}

.held-deposits-table td:nth-child(5) {
  min-width: 140px;
}

.held-deposits-table td:last-child {
  min-width: 190px;
  vertical-align: top;
}

#held-deposits-container .deposits-panel {
  margin-bottom: 1rem;
}

.deposit-note-input {
  width: 100%;
  min-width: 120px;
  padding: 0.3rem 0.4rem;
  border: 1px solid var(--border-strong);
  border-radius: 4px;
  font-size: 0.85rem;
  box-sizing: border-box;
  font-family: inherit;
}

.deposit-edit-date,
.deposit-edit-amount {
  width: 100%;
  min-width: 110px;
  padding: 0.3rem 0.4rem;
  border: 1px solid var(--border-strong);
  border-radius: 4px;
  font-size: 0.85rem;
  box-sizing: border-box;
  font-family: inherit;
}

.jobs-year-nav {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

.jobs-year-label {
  font-weight: 700;
  min-width: 4.5rem;
  text-align: center;
}

.jobs-client-name {
  font-weight: 600;
}

.jobs-client-contact {
  font-size: 0.8rem;
  color: var(--text-muted);
  margin-top: 0.15rem;
  /* Cells are nowrap so short columns keep their shape, but this one line
     (phone · courriel · adresse complète) stretched the Client column to
     600px and pushed Total, Solde and Statut off the right edge. It's the
     one cell that should wrap instead. */
  white-space: normal;
  max-width: 34rem;
}

.jobs-links-cell {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.1rem;
}

#jobs-table td {
  vertical-align: top;
}

.status-badge {
  background: var(--border);
  color: var(--text-label);
  padding: 0.25rem 0.7rem;
  border-radius: 999px;
  font-size: 0.8rem;
  font-weight: 600;
}

.builder-fields {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1rem;
  margin-bottom: 1.25rem;
}

.builder-fields label {
  font-size: 0.85rem;
  color: var(--text-label);
}

.builder-fields input,
.builder-fields select {
  display: block;
  width: 100%;
  margin-top: 0.3rem;
  padding: 0.45rem 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  box-sizing: border-box;
  /* A native <input type="date"> renders a few px taller than a text input
     or a select (its picker button carries its own internal padding), which
     left Référence and Fournisseur visibly shorter than Date. An explicit
     height makes every control in the row identical whatever its type. */
  height: 2.125rem;
  line-height: 1.2;
}

.builder-fields select {
  padding-right: 2.1rem;
  background-color: var(--surface);
  color: var(--text);
}

#quote-items-table input,
#quote-items-table select,
#invoice-items-table input,
#request-items-table input {
  width: 100%;
  min-width: 70px;
  padding: 0.35rem;
  border: 1px solid var(--border-strong);
  border-radius: 4px;
  box-sizing: border-box;
  font-size: 0.85rem;
}

/* A quantity is one or two digits — giving it the same box as a "47 1/2"
   measurement pushed the row past the content width on a 1280-wide laptop,
   which put the line's own buttons behind a horizontal scrollbar. */
#quote-items-table .item-qty,
#invoice-items-table .item-qty,
#request-items-table .item-qty {
  min-width: 52px;
}
/* Same reason: these tables carry eight columns of boxes, so they get a
   tighter gutter than the report tables the global padding is sized for. */
#quote-items-table th,
#quote-items-table td,
#invoice-items-table th,
#invoice-items-table td,
#request-items-table th,
#request-items-table td,
#invoice-table th,
#invoice-table td {
  padding-left: 0.6rem;
  padding-right: 0.6rem;
}

/* Without a min-width the browser compresses the columns to fit instead of
   letting .table-scroll scroll, which cropped the Prix input and squeezed
   the drawing/remove buttons out of the last column. */
#request-items-table {
  min-width: 900px;
}

#quote-items-table select {
  padding-right: 1.6rem;
  background-color: var(--surface);
  color: var(--text);
  background-position: right 0.4rem center;
  background-size: 11px;
}

.col-label {
  width: 40%;
}

.drag-handle-cell {
  width: 1%;
  text-align: center;
}

.drag-handle {
  cursor: grab;
  color: var(--text-faint);
  font-size: 1.1rem;
  user-select: none;
  touch-action: none;
}

.drag-handle:active {
  cursor: grabbing;
}

#quote-items-table tr.dragging,
#invoice-items-table tr.dragging,
#request-items-table tr.dragging {
  opacity: 0.4;
}

textarea.item-label {
  width: 100%;
  min-width: 220px;
  min-height: 2.4em;
  padding: 0.35rem;
  border: 1px solid var(--border-strong);
  border-radius: 4px;
  box-sizing: border-box;
  font-size: 0.85rem;
  font-family: inherit;
  /* Grows to fit its content via autoResizeTextarea() instead of needing a
     manual drag — no resize handle needed, and hidden overflow avoids a
     one-frame scrollbar flash while the height is being recalculated. */
  resize: none;
  overflow: hidden;
}

#quote-add-item-btn,
#request-add-item-btn {
  display: block;
  margin: 0.75rem 0 1.25rem;
}

.totals-panel {
  max-width: 320px;
  margin-left: auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 1rem 1.25rem;
}

.totals-panel div {
  display: flex;
  justify-content: space-between;
  padding: 0.25rem 0;
  font-size: 0.9rem;
}

.deposits-panel {
  max-width: 950px;
  margin: 0 0 1.25rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  padding: 1rem 1.25rem;
}

.deposits-panel h3 {
  margin: 0 0 0.75rem;
  font-size: 1rem;
}

.deposits-panel h3.attachments-heading {
  margin-top: 1.25rem;
}

.deposits-table-scroll {
  max-width: 100%;
  overflow-x: auto;
}

#invoice-deposits-table {
  min-width: 780px;
}

.deposit-add-row {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
  flex-wrap: wrap;
}

.deposit-add-row select {
  min-width: 0;
  max-width: 100%;
  flex: 1 1 140px;
  padding: 0.4rem 2.1rem 0.4rem 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  box-sizing: border-box;
  /* Same well as the inputs beside it — on surface it read as a lighter
     panel sitting in a row of darker fields. */
  background-color: var(--surface-alt);
  color: var(--text);
}

/* Everywhere else a segmented toggle is a pill, which is its identity. In
   this row it's one control among six square fields, and the capsule was
   the only thing not lining up with its neighbours. */
.deposit-add-row .segmented-toggle-small {
  border-radius: var(--radius-sm);
  background: var(--surface-alt);
  overflow: hidden;
}

.deposit-add-row .segmented-toggle-small .segment {
  background: transparent;
}

.deposit-add-row .segmented-toggle-small .segment.active {
  background: var(--border);
}

.deposit-add-row input {
  padding: 0.4rem 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
}

.deposit-add-row input#deposit-note {
  flex: 1;
  min-width: 140px;
}

.paycheck-week-nav {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin-bottom: 0.75rem;
}

.paycheck-week-nav input[type='date'] {
  padding: 0.4rem 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  background-color: var(--surface);
  color: var(--text);
}

.dash-employees-week-label {
  font-weight: 600;
  color: var(--text-label);
}

/* No min-width floor: with the week-type toggle allowed to wrap (below),
   the table can give up width instead of forcing a sideways scroll that
   cropped the Note column off the right edge. */
#paycheck-table th,
#paycheck-table td {
  padding-left: 0.6rem;
  padding-right: 0.6rem;
}

/* Five options in one nowrap row made this the widest column in the table
   by far. It stays on one line whenever there's room and folds onto a
   second only when the window is too narrow for it. */
#paycheck-table .segmented-toggle-small {
  flex-wrap: wrap;
}

#paycheck-table .paycheck-amount-input {
  width: 6.5rem;
  padding: 0.35rem 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
}

#paycheck-table .paycheck-note-input {
  width: 100%;
  min-width: 140px;
  padding: 0.35rem 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  box-sizing: border-box;
}

#paycheck-table .paycheck-received-checkbox {
  width: 1.15rem;
  height: 1.15rem;
  cursor: pointer;
}

.cost-add-row-wrap {
  align-items: flex-start;
}

.cost-type-field {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  flex: 1 1 200px;
  min-width: 160px;
}

/* Same specificity as the pre-existing ".deposit-add-row select" rule (this
   field sits inside .deposit-add-row too) so this wins by source order —
   without overriding it here, that rule's `flex: 1 1 140px` becomes a
   140px *height* instead of width, since this field's flex-direction is
   column, not row. */
.cost-type-field select {
  flex: none;
  min-width: 0;
  max-width: 100%;
  padding: 0.4rem 2.1rem 0.4rem 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  box-sizing: border-box;
  background-color: var(--surface);
  color: var(--text);
}

.cost-type-field-disabled .cost-type-select {
  opacity: 0.5;
  cursor: not-allowed;
  pointer-events: none;
}

.cost-type-other {
  padding: 0.4rem 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
}

#invoice-costs-table .cost-type-field {
  min-width: 220px;
}

#invoice-costs-table td:nth-child(2) {
  min-width: 220px;
}

.group-add-row {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
}

.group-add-row input {
  flex: 1;
  max-width: 220px;
  padding: 0.4rem 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
}

.group-member-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.4rem 0;
  border-bottom: 1px solid var(--bg);
  font-size: 0.9rem;
}

.group-member-row .group-member-info {
  flex: 1;
}

.group-summary {
  display: flex;
  justify-content: space-between;
  font-weight: 700;
  padding-top: 0.5rem;
  margin-top: 0.25rem;
  border-top: 2px solid var(--border);
}

.deposits-panel .totals-panel {
  max-width: none;
  margin: 0.75rem 0 0;
  padding: 0.75rem 1rem;
}

.totals-panel .total-line {
  border-top: 1px solid var(--border);
  margin-top: 0.5rem;
  padding-top: 0.6rem;
  font-weight: 700;
  font-size: 1.05rem;
}

.settings-form {
  max-width: 640px;
  margin: 0 auto 2rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  padding: 1.5rem 1.75rem;
}

.drawing-standalone-intro {
  max-width: 640px;
  margin: 0 auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 1.5rem 1.75rem;
}

/* Sits between two boxed/centered .settings-form panels in the Paramètres
   tab — without its own width cap it stretched full-width once main lost
   its 960px ceiling, throwing it out of line with the panels around it. */
#tab-settings .dashboard-section {
  max-width: 640px;
  margin: 0 auto 2rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  padding: 1.5rem 1.75rem;
}

.drawing-standalone-intro h2 {
  font-size: 1rem;
  margin: 0 0 0.75rem;
}

.drawing-standalone-intro p {
  color: var(--text-muted);
  margin: 0 0 1.25rem;
  line-height: 1.5;
}

.settings-form h2 {
  font-size: 1rem;
  margin: 0 0 1rem;
}

.settings-form h2:not(:first-child) {
  margin-top: 1.75rem;
}

.settings-form label {
  display: block;
  margin-bottom: 1rem;
  font-size: 0.9rem;
  color: var(--text-label);
}

.settings-form input,
.settings-form textarea {
  display: block;
  width: 100%;
  margin-top: 0.3rem;
  padding: 0.5rem 0.6rem;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  font-size: 0.95rem;
  box-sizing: border-box;
}

.settings-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  /* No row gap: each label already carries its own bottom margin, and the
     two stacked together made a paired field sit noticeably further from
     the next one than an unpaired field once the row collapses to a single
     column on a phone. The column gap is what this row actually needs. */
  gap: 0 1rem;
}

.table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.dashboard-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1rem;
  margin-bottom: 1.75rem;
}

.stat-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 1.1rem 1.3rem;
  display: flex;
  flex-direction: column;
  box-shadow: var(--shadow-md);
  /* A thin accent edge reads as "this is a figure worth looking at" at a
     glance, which a plain bordered rectangle doesn't. */
  border-top: 3px solid var(--accent);
}

.stat-label {
  font-size: 0.76rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--text-muted);
  line-height: 1.3;
  margin-bottom: 0.4rem;
  /* Reserves room for up to two lines so stat-value lines up horizontally
     across cards even when one label is much longer than another. */
  min-height: 2.6em;
}

.stat-value {
  font-size: 2rem;
  font-weight: 700;
  line-height: 1.1;
  /* Slightly tighter than the default: large figures set at normal
     tracking look loose next to their label. */
  letter-spacing: -0.02em;
  color: var(--text);
}

.stat-sub {
  font-size: 0.95rem;
  color: var(--accent);
  font-weight: 600;
  margin-top: 0.15rem;
}

.dashboard-section {
  margin-bottom: 2.25rem;
}

.dashboard-section h2 {
  font-size: 0.95rem;
  letter-spacing: -0.01em;
  margin: 0 0 0.7rem;
  color: var(--text-label);
}

.dashboard-section > p.empty-note:not(.hidden) {
  margin: 0.6rem 0 0.75rem;
}

.table-total-row td {
  font-weight: 700;
  border-top: 2px solid var(--border-strong);
  background: var(--surface-alt);
}

.dashboard-advanced {
  margin-bottom: 2rem;
}

.dashboard-advanced summary {
  cursor: pointer;
  font-weight: 600;
  color: var(--accent);
  padding: 0.6rem 0;
  border-top: 1px solid var(--border);
  list-style: none;
}

.dashboard-advanced summary::-webkit-details-marker {
  display: none;
}

.dashboard-advanced summary::before {
  content: '▸ ';
}

.dashboard-advanced[open] summary::before {
  content: '▾ ';
}

.dashboard-advanced .dashboard-section {
  margin-top: 1.25rem;
}

.mismatch-over {
  color: var(--success-text);
  font-weight: 600;
}

.mismatch-under {
  color: var(--danger-text);
  font-weight: 600;
}

.empty-note {
  color: var(--text-muted);
  font-size: 0.9rem;
  font-style: italic;
}

#tab-production .toolbar .empty-note {
  flex: 1;
  margin: 0;
}

.year-toggle {
  font-size: 0.9rem;
  text-decoration: none;
  padding: 0.1rem 0.3rem;
}

.year-detail-row td {
  background: var(--surface-alt);
  padding: 0.5rem 0.5rem 0.75rem 1.5rem;
}

.tx-year-header-row td {
  background: var(--accent-soft);
  color: var(--accent-hover);
  font-weight: 600;
  padding: 0.4rem 0.75rem;
}

.tx-year-header-inner {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.25rem 1rem;
}

.tx-year-header-totals {
  font-weight: 400;
  font-size: 0.85rem;
}

.receipt-thumb {
  width: 48px;
  height: 48px;
  object-fit: cover;
  border-radius: 4px;
  display: block;
}

.receipt-preview {
  max-width: 100%;
  max-height: 260px;
  object-fit: contain;
  border-radius: 6px;
  margin-bottom: 0.5rem;
}

.receipt-thumb-hidden {
  filter: blur(8px);
}

.attachment-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.4rem 0;
  border-bottom: 1px solid var(--bg);
}

.month-detail-table {
  width: 100%;
  max-width: 420px;
  border-collapse: collapse;
}

.job-stats-month-table {
  max-width: 720px;
}

.jobs-stat-count {
  font-weight: 600;
}

.jobs-stat-amount {
  font-size: 0.8rem;
  color: var(--text-muted);
  margin-top: 0.1rem;
}

.jobs-stat-average {
  font-size: 0.8rem;
  color: var(--accent);
  font-style: italic;
  margin-top: 0.1rem;
}

.month-detail-table th {
  text-align: left;
  font-size: 0.75rem;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: 0.3rem 0.5rem;
  border-bottom: 1px solid var(--border);
}

.month-detail-table td {
  padding: 0.3rem 0.5rem;
  font-size: 0.85rem;
  border-bottom: 1px solid var(--bg);
}

.summary-bar {
  background: var(--accent-soft);
  border: 1px solid var(--accent-soft-border);
  color: var(--accent-hover);
  border-radius: 6px;
  padding: 0.6rem 1rem;
  margin-bottom: 1rem;
  font-size: 0.9rem;
  font-weight: 600;
}

.summary-section-title {
  font-size: 1rem;
  margin: 1.5rem 0 0.6rem;
}

.summary-section-title:first-of-type {
  margin-top: 0;
}

.summary-bar-balance {
  background: var(--success-bg-soft);
  border-color: var(--success-border);
  color: var(--success-text);
  margin-bottom: 0.5rem;
}

.combine-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  background: var(--warning-bg);
  border: 1px solid var(--warning-border);
  color: var(--warning-text);
  border-radius: 6px;
  padding: 0.6rem 1rem;
  margin-bottom: 1rem;
  font-size: 0.9rem;
  font-weight: 600;
}

.combine-bar span {
  flex: 1;
}

.payment-message-box {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.5rem;
  background: var(--info-bg);
  border: 1px solid var(--info-border);
  border-radius: 6px;
  padding: 0.9rem 1.1rem;
  margin-top: 1.25rem;
  font-size: 0.9rem;
}

.payment-message-label {
  margin: 0;
  font-weight: 600;
  color: var(--info-text);
}

.payment-message-text {
  margin: 0;
  color: var(--info-text-strong);
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.signing-panel {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  background: var(--info-bg);
  border: 1px solid var(--info-border);
  color: var(--info-text-strong);
  border-radius: 6px;
  padding: 0.9rem 1.1rem;
  margin: 1rem 0;
}

.signing-panel.signed {
  background: var(--success-bg-soft);
  border-color: var(--success-border);
}

.signing-panel .signing-title {
  font-weight: 600;
}

.signing-panel .signing-meta {
  color: var(--text-secondary);
  font-size: 0.9rem;
}

.signing-panel img {
  max-height: 64px;
  max-width: 240px;
  background: #fff;
  border-radius: 4px;
  padding: 4px;
}

.signing-panel .signing-actions,
.share-link-modal .share-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.icon-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 2.125rem;
  min-width: 2.5rem;
  padding: 0 0.75rem;
}

.share-link-modal {
  width: min(560px, 100%);
}

.share-link-modal textarea {
  font-family: inherit;
  line-height: 1.5;
}

/* .form input stretches every input to a full-width block — checkboxes
   here sit inline beside their label instead. */
.share-link-modal .checkbox-label {
  display: flex;
  margin-bottom: 0.5rem;
}

.share-link-modal .checkbox-label input {
  display: inline-block;
  width: auto;
  margin: 0;
}

.review-link-box {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.5rem;
  background: var(--success-bg-soft);
  border: 1px solid var(--success-border);
  border-radius: 6px;
  padding: 0.9rem 1.1rem;
  margin-top: 1.25rem;
  font-size: 0.9rem;
}

.review-message-label {
  margin: 0;
  font-weight: 600;
  color: var(--success-text);
}

.review-message-text {
  margin: 0;
  color: var(--success-text-strong);
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

#quote-notes,
#invoice-notes,
#request-notes {
  display: block;
  width: 100%;
  margin: 1.25rem 0 0;
  padding: 0.5rem 0.6rem;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  min-height: 60px;
  box-sizing: border-box;
}

.item-draw-btn.has-drawing {
  color: var(--success-text);
  font-weight: 600;
}

.drawing-editor {
  display: flex;
  gap: 1.75rem;
  /* The drawing is the point of this screen and it was being rendered into
     a 600px column on a 1500px monitor. The form stays a fixed sidebar, so
     every pixel this gains goes to the elevation itself. */
  width: min(1500px, 94vw);
  max-width: 94vw;
  /* Takes the height it can get: the sheet is taller than it is wide, so
     every pixel of height is what the drawing is actually scaled by. */
  height: min(90vh, 1150px);
}

.drawing-editor-form {
  /* Wide enough that the two-up rows below can hold a native date field
     and still leave its neighbour the same width. */
  width: 320px;
  flex-shrink: 0;
  /* The form is far shorter than a tall drawing; letting it scroll on its
     own keeps the elevation in view while you work down the fields. */
  max-height: 84vh;
  overflow-y: auto;
  padding-right: 0.5rem;
}

.drawing-editor-form label {
  display: block;
  font-size: 0.8rem;
  color: var(--text-secondary);
  margin: 0.8rem 0 0.25rem;
}

.drawing-editor-form input,
.drawing-editor-form select,
.drawing-editor-form textarea {
  width: 100%;
  padding: 0.4rem 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  font-size: 0.85rem;
  box-sizing: border-box;
  font-family: inherit;
}

.drawing-editor-form select {
  padding-right: 1.9rem;
  background-color: var(--surface);
  color: var(--text);
}

.drawing-editor-row {
  display: grid;
  /* minmax(0, ...): a bare 1fr is floored at the field's intrinsic width,
     and a native date input is wider than a text one — which left
     "Référence" visibly narrower than the "Date" beside it. */
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  /* Column gap only: each field's label already carries its own top
     margin, so a row gap would double the spacing once these stack on a
     phone. */
  gap: 0 0.75rem;
}

.drawing-editor-form input[readonly] {
  background: var(--bg);
  color: var(--text-secondary);
  cursor: default;
}

.drawing-editor-seg {
  display: flex;
  gap: 0.4rem;
}

.drawing-editor-seg button {
  flex: 1;
  padding: 0.35rem;
  font-size: 0.8rem;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  background: var(--surface);
  cursor: pointer;
}

.drawing-editor-seg button.on {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--accent-hover);
}

/* Nine categories wrapped into ragged rows of two and three, each button a
   different width. A grid gives them one shape and a straight left edge. */
.drawing-editor-categories {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.drawing-editor-categories button {
  white-space: nowrap;
}

.drawing-editor-colors {
  display: flex;
  gap: 0.5rem;
}

.drawing-editor-colors .sw {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 2px solid var(--border);
  cursor: pointer;
}

.drawing-editor-colors .sw.on {
  border-color: var(--accent);
}

.drawing-editor-preview {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.drawing-editor-preview-card {
  /* Always white, not themed — the door/window SVG paints no background of
     its own and its strokes/colors are tuned to sit on white (same as the
     PDF export), so a dark theme would make it unreadable. */
  background: #fff;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  /* Enough to read as a sheet of paper rather than a panel with a drawing
     pressed against its edges, but no more — every pixel of padding comes
     straight off the size the drawing is rendered at. */
  padding: 0.9rem;
  box-shadow: var(--shadow-md);
  flex: 1;
  min-height: 0;
  /* Nothing scrolls and nothing crops: the whole sheet, elevation and spec
     list together, is always in view. */
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Scaled by height, because the sheet is taller than it is wide — sized to
   the panel's width instead it rendered at 1.8x and ran off the bottom.
   The list is drawn inside the same SVG, so it grows and shrinks with the
   elevation in exact proportion. width:auto keeps that proportion; the
   sheet staying wider than the drawing is what makes it read as paper. */
.drawing-editor-preview-card svg {
  height: 100%;
  width: auto;
  max-width: 100%;
  display: block;
}

.drawing-editor-toolbar {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
  flex-wrap: wrap;
}

.toast {
  position: fixed;
  bottom: 1.5rem;
  left: 50%;
  transform: translateX(-50%) translateY(12px);
  background: var(--success-solid);
  color: #fff;
  padding: 0.7rem 1.25rem;
  border-radius: 8px;
  font-size: 0.9rem;
  font-weight: 500;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.18s ease, transform 0.18s ease;
  z-index: 1000;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.2);
  max-width: 90vw;
  text-align: center;
}

.toast.show {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

.toast.toast-error {
  background: var(--danger-solid);
}

/* ---------- Mobile ---------- */
@media (max-width: 640px) {
  body {
    display: block;
  }

  header {
    padding: 0.6rem 0.75rem;
    position: relative;
    width: auto;
    height: auto;
    overflow: visible;
    align-self: auto;
  }

  .header-bar {
    flex-direction: row;
    align-items: center;
    height: auto;
    gap: 0.75rem;
  }

  .brand-logo {
    align-self: auto;
  }

  #tabs {
    flex: initial;
  }

  .tab-btn {
    text-align: left;
  }

  .header-icons {
    margin-left: auto;
    margin-top: 0;
    padding-top: 0;
    border-top: none;
  }

  .brand-logo {
    height: 37px;
    padding: 4px 8px;
  }

  .mobile-nav-btn {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    flex: 1;
    min-width: 0;
    background: rgba(255, 255, 255, 0.1);
    border: 1px solid rgba(255, 255, 255, 0.25);
    color: #fff;
    border-radius: 8px;
    padding: 0.5rem 0.75rem;
    font-size: 0.9rem;
    font-weight: 600;
    cursor: pointer;
  }

  .mobile-nav-btn span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .mobile-nav-btn::after {
    content: '▾';
    margin-left: auto;
    flex-shrink: 0;
  }

  #tabs {
    display: none;
    position: absolute;
    top: 100%;
    left: 0.75rem;
    right: 0.75rem;
    margin-top: 0.4rem;
    background: #1e293b;
    border-radius: 10px;
    box-shadow: 0 12px 30px rgba(0, 0, 0, 0.35);
    flex-direction: column;
    flex-wrap: nowrap;
    gap: 0.15rem;
    padding: 0.4rem;
    z-index: 500;
  }

  #tabs.open {
    display: flex;
  }

  .tab-btn {
    width: 100%;
    text-align: left;
    padding: 0.6rem 0.75rem;
    font-size: 0.9rem;
  }

  .privacy-toggle {
    width: 2.1rem;
    height: 2.1rem;
  }

  main {
    margin: 1rem auto;
    padding: 0 0.6rem;
  }

  /* On a phone, forcing every row onto one line just trades a tall row for
     a sideways-scrolling one — worse on a touch screen. Desktop keeps
     nowrap (real estate to spare); mobile goes back to wrapping in place. */
  th, td {
    white-space: normal;
  }

  /* Side by side there is no room left for the drawing itself — the
     preview was a sliver down the right edge and its Imprimer / PDF button
     sat off-screen. Stacked, the form gets the width and the drawing sits
     under it. */
  .drawing-editor {
    flex-direction: column;
    /* The desktop rule pins a height so the preview card can scale the
       drawing into it; stacked on a phone the two halves need to size to
       their own content instead. */
    height: auto;
  }
  .drawing-editor-form {
    width: 100%;
    max-height: none;
    overflow-y: visible;
    padding-right: 0;
  }
  /* Back to intrinsic height, since there's no fixed box to fit into. */
  .drawing-editor-preview-card svg {
    height: auto;
  }
  .drawing-editor-preview-card {
    padding: 0.75rem;
  }

  /* Kept on one line on desktop so it sits neatly in a table cell; on a
     phone that same nowrap is what pushed "Installation seulement" off the
     right edge of the screen. */
  .segmented-toggle-small {
    flex-wrap: wrap;
    max-width: 100%;
  }

  /* minmax(0, ...) rather than a bare 1fr: a plain 1fr is floored at the
     widest field's min-content, and a long <select> option or a segmented
     toggle pushed the single column past the screen, which left the whole
     page scrolling a few pixels sideways. */
  .builder-fields,
  .settings-row,
  .drawing-editor-row {
    grid-template-columns: minmax(0, 1fr);
  }

  th, td {
    padding: 0.5rem 0.6rem;
    font-size: 0.85rem;
  }

  .modal {
    padding: 1rem;
    width: 100%;
  }
}

/* Multi-appartement documents: the Appartement column only exists while the
   toggle is on, so a normal single-unit quote looks exactly as it did. */
.col-group { display: none; }
.multi-project-on .col-group { display: table-cell; }
#quote-items-table .item-group,
#invoice-items-table .item-group,
#request-items-table .item-group {
  min-width: 110px;
}
/* A visible break where one apartment's lines end and the next begin, so a
   long multi-apartment list reads as distinct blocks while entering it. */
.multi-project-on .group-boundary td {
  border-top: 2px solid var(--border-strong);
}
.multi-project-bar {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  margin-bottom: 0.6rem;
}
.multi-project-toggle {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  font-size: 0.85rem;
  color: var(--text-secondary);
}
.multi-project-toggle input {
  width: auto;
  margin: 0;
}

/* Document-level material picker: sets every window line at once, then each
   line can still be changed on its own in the drawing editor. */
.doc-material-bar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-bottom: 0.6rem;
}
.doc-material-label {
  font-size: 0.85rem;
  color: var(--text-secondary);
  /* These bars stack (matériau, carrelage, type de vue) and each label is a
     different length, so without a shared width every row's toggle — and the
     hint after it — starts at its own x and the block reads as ragged.
     flex-shrink keeps it from forcing a scroll on a narrow phone. */
  flex: 0 0 auto;
  min-width: 9.5rem;
}
@media (max-width: 640px) {
  /* On its own line on a phone, where a fixed label column would only push
     the toggle off the screen — and all three bars read the same way
     instead of one label wrapping and the next two sitting inline. */
  .doc-material-label {
    min-width: 0;
    flex-basis: 100%;
  }
}
.doc-material-hint {
  font-size: 0.78rem;
  color: var(--text-muted);
}
/* Lines disagree: nothing is shown as selected, so the picker never claims
   the document is all one material when it isn't. */
.doc-material-toggle.is-mixed {
  border-style: dashed;
}

/* Règles de prix (Paramètres) */
.pricing-rule {
  border: 1px solid var(--border);
  border-radius: 8px;
  margin-bottom: 0.6rem;
  background: var(--surface);
}
.pricing-rule > summary {
  cursor: pointer;
  padding: 0.6rem 0.85rem;
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  list-style: none;
}
.pricing-rule > summary::-webkit-details-marker {
  display: none;
}
/* Chevron on the right: points down when closed, up when open. */
.pricing-rule > summary::after {
  content: '';
  margin-left: auto;
  align-self: center;
  width: 0.45rem;
  height: 0.45rem;
  border-right: 2px solid var(--text-muted);
  border-bottom: 2px solid var(--text-muted);
  transform: rotate(45deg);
  transition: transform 0.15s;
}
.pricing-rule[open] > summary::after {
  transform: rotate(-135deg);
}
.pricing-rule[open] > summary {
  border-bottom: 1px solid var(--border);
  margin-bottom: 0.75rem;
}
.pricing-rule-name { font-weight: 600; }
.pricing-rule-summary { font-size: 0.82rem; color: var(--text-muted); }
.pricing-rule-body { padding: 0 0.85rem 0.85rem; }
.pricing-addon-row {
  margin-bottom: 0.6rem;
}
.pricing-addon-row-main {
  display: grid;
  grid-template-columns: 1fr 6.5rem 9rem 11rem auto;
  gap: 0.5rem;
  align-items: center;
}
@media (max-width: 640px) {
  /* Five columns need about 460px; on a phone the row simply ran off the
     side of the card, and since nothing scrolls sideways there the mode
     picker and the delete button could not be reached at all. */
  .pricing-addon-row-main {
    grid-template-columns: minmax(0, 1fr) auto;
  }
}
.pricing-addon-row-threshold {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.78rem;
  color: var(--text-muted);
  margin-top: 0.3rem;
}
.pricing-addon-row-threshold input {
  width: 5rem;
}
.pricing-rule-actions {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  margin-top: 0.6rem;
}

/* Produire une soumission — per-line pricing review */
.convert-pricing { margin: 0.75rem 0; }
.convert-line {
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.55rem 0.7rem;
  margin-bottom: 0.45rem;
}
.convert-line-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.75rem;
}
.convert-line-label { font-weight: 600; }
.convert-line-price { white-space: nowrap; }
.convert-line-price input { width: 7rem; text-align: right; }
.convert-line-cost {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.82rem;
  color: var(--text-secondary);
  margin-top: 0.35rem;
}
.convert-line-cost input { width: 6.5rem; text-align: right; }
.convert-line-detail {
  font-size: 0.78rem;
  color: var(--text-muted);
  margin-top: 0.2rem;
}
.convert-line-options {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 0.4rem;
  /* The labels inside carry no bottom margin of their own (the gap spaces
     them), so the block needs its own separation from the next field. */
  margin-bottom: 0.85rem;
}

/* ---------------------------------------------------------------------
   One control height, everywhere.

   A native <select> and a native <input> do not agree on height on their
   own (and an <input type="date"> is taller than both), so a form row ends
   up with controls sitting a few pixels off each other. Pinning an explicit
   height is the only reliable fix — box-sizing is already border-box
   app-wide, so this is the outer height in every case.

   Two tiers, because item tables are deliberately denser than forms:
   the standard control, and the compact one used inside a table row.
   Textareas, checkboxes and radios are excluded — they are not single-line
   controls and have their own sizing.
   --------------------------------------------------------------------- */
input:not([type='checkbox']):not([type='radio']):not([type='file']):not([type='hidden']),
select {
  height: 2.125rem;
  /* Pinned alongside the height on purpose: a control still on the default
     content-box would add its padding and border on top of that height and
     end up ~15px taller than the select beside it. */
  box-sizing: border-box;
}

table input:not([type='checkbox']):not([type='radio']),
table select {
  height: 1.9rem;
  box-sizing: border-box;
}

/* A textarea in an item row still sizes itself to its content. */
table textarea {
  height: auto;
}

.text-cleanup-table td:first-child,
.text-cleanup-table th:first-child {
  width: 2rem;
}

.text-cleanup-table td {
  white-space: normal;
  overflow-wrap: anywhere;
}

.text-cleanup-table .text-cleanup-before {
  color: var(--text-muted);
}

/* Address search dropdown (client/supplier forms). */
.address-field {
  position: relative;
}

.address-suggestions {
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  z-index: 20;
  margin-top: 2px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
  overflow: hidden;
}

.address-suggestion {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 100%;
  padding: 0.5rem 0.7rem;
  background: none;
  border: none;
  text-align: left;
  cursor: pointer;
  color: var(--text);
}

.address-suggestion:hover,
.address-suggestion.active {
  background: var(--accent-soft);
}

.address-suggestion-main {
  font-size: 0.92rem;
}

.address-suggestion-secondary {
  font-size: 0.8rem;
  color: var(--text-muted);
}

.form-row-3 {
  display: grid;
  grid-template-columns: 2fr 1fr 1.3fr;
  gap: 0.6rem;
}

/* ---------- Calendrier des installations ---------- */
.calendar-toolbar {
  flex-wrap: wrap;
  gap: 0.75rem;
  align-items: center;
}
.calendar-nav {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}
.calendar-range {
  font-weight: 600;
  margin-left: 0.5rem;
}
.calendar-legend {
  display: flex;
  gap: 0.9rem;
  flex-wrap: wrap;
  font-size: 0.8rem;
  color: var(--text-secondary);
  margin-left: auto;
}
.cal-legend-item::before {
  content: '';
  display: inline-block;
  width: 0.7rem;
  height: 0.7rem;
  border-radius: 3px;
  margin-right: 0.35rem;
  vertical-align: -1px;
  background: var(--cal-bg);
  border-left: 3px solid var(--cal-edge);
}
.cal-state-ready { --cal-bg: var(--accent-soft); --cal-edge: var(--accent); }
.cal-state-waiting { --cal-bg: var(--warning-bg); --cal-edge: #d97706; }
.cal-state-done { --cal-bg: var(--success-bg-soft); --cal-edge: var(--success-solid); }

.calendar-week {
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  overflow: hidden;
  /* Keeps the bookings' z-index inside the calendar, so they never draw on
     top of a modal opened over it. */
  isolation: isolate;
}
.cal-head,
.cal-body {
  display: grid;
  grid-template-columns: 3.2rem repeat(7, minmax(0, 1fr));
}
.cal-head {
  border-bottom: 1px solid var(--border);
}
.cal-day-head {
  padding: 0.45rem 0.3rem;
  text-align: center;
  font-size: 0.8rem;
  color: var(--text-secondary);
  border-left: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  text-transform: capitalize;
}
.cal-day-head strong {
  font-size: 1.05rem;
  color: var(--text);
}
.cal-day-head.today strong {
  color: var(--accent);
}
.cal-hour-label {
  height: var(--cal-hour);
  font-size: 0.72rem;
  color: var(--text-muted);
  text-align: right;
  padding-right: 0.4rem;
  transform: translateY(-0.45rem);
}
.cal-hour-label:first-child {
  transform: none;
}
.cal-day {
  position: relative;
  border-left: 1px solid var(--border);
  cursor: copy;
}
.cal-day.today {
  background: var(--accent-soft);
}
.cal-slot {
  height: var(--cal-hour);
  border-top: 1px solid var(--border);
}
.cal-slot:first-child {
  border-top: none;
}
.cal-event {
  position: absolute;
  z-index: 1;
  padding: 0.25rem 0.35rem;
  border-radius: 5px;
  background: var(--cal-bg);
  border-left: 3px solid var(--cal-edge);
  color: var(--text);
  font-size: 0.75rem;
  line-height: 1.25;
  overflow: hidden;
  cursor: grab;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
  touch-action: none;
  user-select: none;
}
.cal-event.dragging {
  cursor: grabbing;
  opacity: 0.85;
  z-index: 5;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.25);
}
.cal-event.cal-state-done .cal-event-title {
  text-decoration: line-through;
  text-decoration-color: var(--text-muted);
}
.cal-event-time {
  font-weight: 600;
  color: var(--text-secondary);
}
.cal-event-title {
  font-weight: 600;
}
.cal-event-meta {
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Dark mode: the soft backgrounds above are light tints — swap for darker
   ones so the text stays readable. */
:root[data-theme='dark'] .cal-state-ready { --cal-bg: rgba(77, 130, 201, 0.22); }
:root[data-theme='dark'] .cal-state-waiting { --cal-bg: rgba(217, 119, 6, 0.22); }
:root[data-theme='dark'] .cal-state-done { --cal-bg: rgba(22, 163, 74, 0.18); }
:root[data-theme='dark'] .cal-day.today { background: rgba(77, 130, 201, 0.08); }

/* Phones: a day-by-day list instead of the 7-column grid. */
.calendar-agenda {
  display: none;
}
@media (max-width: 760px) {
  .calendar-week { display: none; }
  .calendar-agenda { display: flex; flex-direction: column; gap: 0.9rem; }
  .calendar-legend { margin-left: 0; }
}
.cal-agenda-date {
  font-weight: 600;
  margin-bottom: 0.35rem;
}
.cal-agenda-item {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.1rem;
  width: 100%;
  text-align: left;
  padding: 0.55rem 0.7rem;
  margin-bottom: 0.4rem;
  border: none;
  border-radius: 6px;
  background: var(--cal-bg);
  border-left: 3px solid var(--cal-edge);
  color: var(--text);
  font-size: 0.88rem;
  cursor: pointer;
}

/* Booking form */
.installation-form {
  width: min(560px, 100%);
}
.installation-form .checkbox-label {
  display: flex;
  margin-bottom: 0.5rem;
}
.installation-form .checkbox-label input {
  display: inline-block;
  width: auto;
  margin: 0;
}
.installation-form input[type='date'],
.installation-form input[type='time'],
.installation-form select {
  height: 2.3rem;
}
.installation-crew {
  margin-bottom: 0.85rem;
}
.installation-crew-label {
  font-size: 0.9rem;
  color: var(--text-label);
  margin-bottom: 0.35rem;
}

/* Dashboard */
#dash-installations tr[data-id] {
  cursor: pointer;
}
.dash-install-done td {
  color: var(--text-muted);
}
.dash-install-waiting {
  color: #d97706;
  font-weight: 600;
}

.calendar-sync {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  font-size: 0.8rem;
  color: var(--text-muted);
  margin: -0.4rem 0 0.6rem;
}
.calendar-sync.error {
  color: #d97706;
}
.calendar-sync .btn-link {
  font-size: 1rem;
  line-height: 1;
}

.quote-client-progress {
  font-size: 0.78rem;
  color: var(--text-muted);
}
.send-mode-toggle {
  margin-bottom: 0.4rem;
}

/* Production: status per ordered job */
.production-stage {
  font-weight: 600;
  border-radius: 999px;
  padding: 0.2rem 1.8rem 0.2rem 0.7rem;
  height: auto;
}
.production-stage.production-ordered { background-color: var(--info-bg); color: var(--info-text); }
.production-stage.production-ready { background-color: var(--accent-soft); color: var(--accent-hover); }
.production-stage.production-started { background-color: var(--warning-bg); color: var(--warning-text); }
.production-stage.production-installed { background-color: var(--success-bg); color: var(--success-text); }
:root[data-theme='dark'] .production-stage.production-ordered { background-color: rgba(59, 130, 246, 0.18); color: #bfdbfe; }
:root[data-theme='dark'] .production-stage.production-ready { background-color: rgba(77, 130, 201, 0.25); color: #c7d9ec; }
:root[data-theme='dark'] .production-stage.production-started { background-color: rgba(217, 119, 6, 0.22); color: #fde68a; }
:root[data-theme='dark'] .production-stage.production-installed { background-color: rgba(22, 163, 74, 0.2); color: #bbf7d0; }
.production-badge {
  display: inline-block;
  padding: 0.15rem 0.55rem;
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 600;
  white-space: nowrap;
  background: var(--warning-bg);
  color: var(--warning-text);
}
.production-actions {
  white-space: nowrap;
}
.production-date {
  width: auto;
  height: 2rem;
  padding: 0 0.4rem;
}

/* Phones: one card per order instead of a table. */
@media (max-width: 760px) {
  #production-table thead {
    display: none;
  }
  #production-table,
  #production-table tbody,
  #production-table tr,
  #production-table td {
    display: block;
    width: 100%;
    box-sizing: border-box;
  }
  #production-table {
    border: none;
    background: none;
  }
  #production-table tr {
    border: 1px solid var(--border);
    border-radius: 8px;
    margin-bottom: 0.7rem;
    padding: 0.5rem 0.75rem;
    background: var(--surface);
  }
  #production-table td {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    border: none;
    padding: 0.25rem 0;
  }
  #production-table td[data-label]::before {
    content: attr(data-label);
    color: var(--text-muted);
    font-size: 0.82rem;
  }
  #production-table td.production-client {
    font-weight: 600;
    font-size: 1rem;
    display: block;
  }
  #production-table td.production-client::before {
    content: none;
  }
  #production-table td.production-actions {
    justify-content: flex-end;
  }
}

/* Rapports */
.reports-period {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.9rem;
  color: var(--text-label);
}
.reports-period select {
  width: auto;
}
#tab-reports tfoot td {
  font-weight: 700;
  border-top: 2px solid var(--border-strong);
}
#tab-reports .num,
#tab-reports th.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.report-bars {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}
.report-bar-row {
  display: grid;
  grid-template-columns: 6.5rem 1fr 7rem;
  align-items: center;
  gap: 0.6rem;
  font-size: 0.85rem;
}
.report-bar {
  display: block;
  background: var(--border);
  border-radius: 4px;
  height: 0.9rem;
  overflow: hidden;
}
.report-bar > span {
  display: block;
  height: 100%;
  background: var(--accent);
  border-radius: 4px;
}
.report-bar-value {
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--text-secondary);
}
