/* ═══════════════════════════════════════════════════════════════════════════
   DESIGN SYSTEM — Djerba Capital Platform
   Standalone. No app may define its own CSS — all styles live here.
   Palette : Noir #000  Blanc #fff  Gris #f5f5f5…#666
   Border-radius : 8 / 12 / 16 px
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── 1. DESIGN TOKENS ──────────────────────────────────────────────────── */
:root {
  /* The browser paints its own surfaces — dialog grounds, scrollbars, the
     popup a <select> opens, date pickers, autofill — and needs telling which
     scheme to paint them for. Without this they stay light under a dark page. */
  color-scheme: light;

  /* Core */
  --black:   #000000;
  --white:   #ffffff;
  --bg:      #f5f5f5;
  --surface: #ffffff;

  /* Grayscale — 6 levels */
  --gray-1: #f0f0f0;   /* hover background */
  --gray-2: #eaeaea;   /* active background */
  --gray-3: #e5e5e5;   /* component borders */
  --gray-4: #bdbdbd;   /* input borders, disabled */
  --gray-5: #999999;   /* muted icons, table headers */
  --gray-6: #666666;   /* secondary text */

  /* Semantic aliases */
  --text:         #000000;
  --text-muted:   #666666;
  --border:       #e5e5e5;
  --border-input: #bdbdbd;

  /* Semantic colors — those produced by the platform (alerts, critical, status, text states) */
  --color-danger:  #c5221f;
  --color-success: #1a7a34;
  --color-warning: #b06000;   /* .text-warning only — no alert-warning */

  /* Alert tints — pale background + deep text of the danger/success surfaces */
  --color-danger-tint:  #fef2f2;
  --color-danger-text:  #7f1d1d;
  --color-success-tint: #f0fdf4;
  --color-success-text: #14532d;

  /* Journal entry status — badges and PDF. Alias semantic/gray tokens; no new hex. */
  --color-status-posted:   var(--color-success);
  --color-status-reversed: var(--color-danger);
  --color-status-draft:    var(--gray-6);

  /* Cash flow categories — CF tables and PDF only. -operating and -financing are unique hues; -investing reuses --color-warning. */
  --color-cf-operating: #1a56cc;
  --color-cf-investing:  var(--color-warning);
  --color-cf-financing:  #7b2fbe;
  --color-cf-excluded:   var(--gray-5);

  /* Code viewer dark surface — audit log changes panel only */
  --surface-code: #1e1e1e;
  --text-code:    #d4d4d4;

  /* Sidebar */
  --sidebar-bg:     #000000;
  --sidebar-text:   #666666;
  --sidebar-link:   #999999;
  --sidebar-hover:  rgba(255,255,255,.06);
  --sidebar-active-bg: rgba(255,255,255,.1);
  --sidebar-active: #ffffff;
  --sidebar-border: rgba(255,255,255,.08);
  --sidebar-w:      240px;

  /* Border radius — 6 / 8 / 12 / 16 */
  --radius-xs: 6px;
  --radius-sm: 8px;
  --radius:    12px;
  --radius-lg: 16px;

  /* Shadows — prefer borders */
  --shadow-sm: 0 1px 2px rgba(0,0,0,.06);
  --shadow-md: 0 4px 12px rgba(0,0,0,.08);

  /* Focus rings & overlays */
  --focus-ring:         0 0 0 2px rgba(0,0,0,.1);
  --focus-ring-invalid: 0 0 0 2px rgba(197,34,31,.12);
  --backdrop:           rgba(0,0,0,.4);

  /* Transitions — minimal motion */
  --t-fast:   120ms;
  --t-normal: 180ms;
  --t-slow:   240ms;

  /* Typography */
  --font:      'Inter', 'Segoe UI', 'Helvetica Neue', system-ui, sans-serif;
  --font-mono: 'JetBrains Mono', 'Cascadia Code', 'Courier New', monospace;

  /* Icons — a replaced <select>/input[list] cannot host the CSS border-chevron
     (§X.1), so its chevron is a stroked SVG instead. A data-URI cannot embed
     var(), so its stroke is a literal mirror of --gray-5 (#999) rather than a
     live reference — kept here, the one place a literal value is allowed. */
  --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6' fill='none' stroke='%23999' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 1 5 5 9 1'/%3E%3C/svg%3E");
}

/* ── DARK THEME ────────────────────────────────────────────────────────────
   Follows the operating system and nothing else: no toggle, no persistence,
   no stored preference. The whole theme is token values — not one component
   rule below changes, because every component already reads its colour from
   here.

   `--black` and `--white` are palette slots, not literals: they name the ink
   and the ground, and both themes need both. So they trade values, and the
   grey scale runs the other way with them. A solid badge stays ink-on-ground
   and reads as emphatic in either theme without knowing which one it is in.

   The rail does not move. It is black in both themes; the page lifts to meet
   it instead, which is why it keeps its own tokens and none of them appear
   below. */
@media (prefers-color-scheme: dark) {
  :root {
    color-scheme: dark;

    /* Ink and ground trade places. */
    --black: #ececec;
    --white: #191919;

    /* The page sits above the rail's black; cards sit above the page. */
    --bg:      #141414;
    --surface: #1e1e1e;

    /* The scale keeps its meaning — 1 is nearest the ground, 6 nearest the
       ink — and so runs dark to light. */
    --gray-1: #262626;   /* hover ground */
    --gray-2: #2e2e2e;   /* active ground */
    --gray-3: #383838;   /* component borders */
    --gray-4: #4d4d4d;   /* input borders, disabled */
    --gray-5: #8a8a8a;   /* muted icons, table headers */
    --gray-6: #a8a8a8;   /* secondary text */

    --text:         #ececec;
    --text-muted:   #a8a8a8;
    --border:       #383838;
    --border-input: #4d4d4d;

    /* Status hues lift: the light-surface values are too dark to read here. */
    --color-danger:  #f87171;
    --color-success: #4ade80;
    --color-warning: #fbbf24;

    /* An alert is a tinted surface, so the tint darkens and its text lifts. */
    --color-danger-tint:  #2a1416;
    --color-danger-text:  #fca5a5;
    --color-success-tint: #10261a;
    --color-success-text: #86efac;

    /* Cash-flow hues lift the same way. */
    --color-cf-operating: #6ea8ff;
    --color-cf-financing: #c084fc;

    /* Borders carry elevation here (§L0.4 prefers them anyway), so the
       shadows stand down rather than smudging invisibly. */
    --shadow-sm: none;
    --shadow-md: none;

    /* The ring must be lighter than what it rings. */
    --focus-ring: 0 0 0 2px rgba(255,255,255,.18);

    /* A 40% veil barely separates one dark surface from another. */
    --backdrop: rgba(0,0,0,.65);
  }
}

/* ── 2. RESET ──────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { font-size: 14px; }

body {
  font-family: var(--font);
  line-height: 1.6;
  color: var(--text);
  background: var(--bg);
  display: flex;
  min-height: 100vh;
}

/* ── 3. SIDEBAR ────────────────────────────────────────────────────────── */
.sidebar {
  width: var(--sidebar-w);
  /* Exactly the viewport, not merely at least it: the rail is fixed, so it does
     not scroll with the page, and `min-height` alone never caps its height —
     `overflow-y` would have nothing to act on and rows past the fold would be
     unreachable once every section is open (§L3.5). */
  height: 100vh;
  background: var(--sidebar-bg);
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
  position: fixed;
  top: 0; left: 0;
  overflow: hidden;
  z-index: 200;
  transition: transform var(--t-slow), width var(--t-slow);
}
/* Header: the two jumps, split evenly — the company mark returns to the hub,
   the grid opens this app's landing page. The app names itself on its own
   dashboard, so the rail carries no title (§L3.5). */
.sidebar-brand {
  display: flex;
  border-bottom: 1px solid var(--sidebar-border);
}
.sidebar-brand > a {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  /* 1.75rem either side of a 1.35rem glyph holds the header at the height the
     titled block had, so removing the title did not raise the rail's shoulder. */
  padding: 1.75rem 0;
  color: var(--sidebar-text);
  transition: background var(--t-fast), color var(--t-fast);
}
.sidebar-brand > a + a { border-left: 1px solid var(--sidebar-border); }
.sidebar-brand > a:hover { background: var(--sidebar-hover); color: var(--sidebar-active); }
/* The jump you are currently on — the hub, or this app's landing page. */
.sidebar-brand > a[aria-current="page"] {
  background: var(--sidebar-active-bg);
  color: var(--sidebar-active);
}
.sidebar-brand svg { width: 1.15rem; height: 1.15rem; }
/* The company mark is a black monochrome file; on the rail it is forced to the
   sidebar's own ink so it sits at the same weight as the glyph beside it, and
   lifts with it on hover (an <img> cannot take `currentColor`). */
.sidebar-brand img {
  width: 1.35rem;
  height: 1.35rem;
  filter: brightness(0) invert(1);
  opacity: .55;
  transition: opacity var(--t-fast);
}
.sidebar-brand > a:hover img { opacity: 1; }
/* The mark breathes: mostly at rest, then swelling briefly before settling. The
   cycle is long and the rest state is the resting one, so the rail is still for
   most of it — a sign of life, not a thing that pulls at the eye while someone
   is reading a ledger. */
@keyframes logo-breathe {
  0%, 82%, 100% { transform: scale(1);   opacity: .55; }
  88%           { transform: scale(1.5); opacity: 1; }
  94%           { transform: scale(1.1); opacity: .8; }
}
.sidebar-brand img { animation: logo-breathe 7s ease-in-out infinite; }
/* Hovering states the mark plainly — a moving target is a hard one to click. */
.sidebar-brand > a:hover img { animation: none; opacity: 1; }

/* Only the list scrolls: the header above and the command below stay put. */
.sidebar-nav {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

/* Foot: a view command, not a destination. Pinned below the navigation it acts
   on, so only the list between them ever scrolls. */
.sidebar > button {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  /* The `button` base sets a .4rem gap; the chevron carries its own margins, so
     that gap would push this label past the section labels it lines up with. */
  gap: 0;
  flex-shrink: 0;
  /* Indented to the section labels: .75 section gutter + .75 label padding
     puts their chevron at 1.75rem and their text at 3.1rem; this row lands on
     both, so the foot reads as the same level of the arborescence (§X.1). */
  padding: .75rem 1rem .75rem 1.5rem;
  border: 0;
  border-top: 1px solid var(--sidebar-border);
  border-radius: 0;
  background: none;
  font-family: inherit;
  font-size: .7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .1em;
  color: var(--sidebar-text);
  cursor: pointer;
  transition: color var(--t-fast), background var(--t-fast);
}
.sidebar > button:hover { color: var(--sidebar-active); background: var(--sidebar-hover); opacity: 1; }
.sidebar > button::before { margin-left: .25rem; margin-right: .85rem; transform: rotate(-45deg); }
.sidebar > button[aria-expanded="true"]::before { transform: rotate(45deg); }

.sidebar-section { padding: 1.25rem .75rem .5rem; }
.sidebar-section-label {
  font-size: .65rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .1em;
  color: var(--sidebar-text);
  padding: 0 .5rem .5rem;
  white-space: nowrap;
  overflow: hidden;
}

/* Collapsible named section (UI_NORMS §3.6). A section is a <details>; its
   <summary class="sidebar-section-label"> is the label and disclosure control.
   Not an accordion — several may be open at once. Overrides the global
   `details`/`summary` surface styling (§18) for the dark rail. The chevron
   geometry and rotation come from the shared primitive below (§X.1). */
details.sidebar-section {
  background: transparent;
  border: 0;
  border-radius: 0;
  margin: 0;
}
/* Same leading slot as a nav item (.75rem padding + a 1rem glyph slot + .6rem
   gap) so section-header text aligns with the item text below it — every
   arborescence row at the same depth shares one left edge. Flex-centred like
   .nav-icon--back and the .nav-icon glyphs of the rows below it (§X.1), not
   the inline vertical-align nudge the generic `summary::before` uses — that
   axis-matching is what keeps this chevron on the same line as the icons
   underneath it: `position: static` cancels the inline nudge it would
   otherwise inherit from the shared primitive. .25rem left + .5rem chevron +
   .85rem right = 1.6rem, the same leading as a 1rem nav-icon + .6rem gap. */
summary.sidebar-section-label {
  cursor: pointer;
  padding: .5rem .75rem;
  display: flex;
  align-items: center;
}
summary.sidebar-section-label:hover { color: var(--sidebar-active); }
summary.sidebar-section-label::before {
  position: static;
  margin-left: .25rem;
  margin-right: .85rem;
}
details.sidebar-section > *:not(summary) { padding: 0; }
/* Section items nest one level to the RIGHT of their header — a child in the
   arborescence is never to the left of its parent. .75rem header padding + a
   1rem indent step = 1.75rem, so an item's icon sits right of the header chevron. */
details.sidebar-section > a { padding: .5rem .75rem .5rem 1.75rem; }
.sidebar-nav a {
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .5rem .75rem;
  border-radius: var(--radius-sm);
  color: var(--sidebar-link);
  text-decoration: none;
  font-size: .875rem;
  font-weight: 450;
  transition: background var(--t-fast), color var(--t-fast);
  margin-bottom: 2px;
  white-space: nowrap;
  overflow: hidden;
}
/* The rail's ink is its own (`--sidebar-active`), never the page's `--white`:
   the page inverts with the theme and the rail does not, so borrowing from it
   turned the active row into dark text on a black rail. */
.sidebar-nav a:hover {
  background: var(--sidebar-hover);
  color: var(--sidebar-active);
}
.sidebar-nav a[aria-current="page"] {
  background: var(--sidebar-active-bg);
  color: var(--sidebar-active);
  font-weight: 600;
}

.nav-icon {
  width: 1rem;
  height: 1rem;
  flex-shrink: 0;
  opacity: .6;
  transition: opacity var(--t-fast);
}
/* ── The 8px border-chevron primitive (L1.7) ──────────────────────────────
   The ONE chevron glyph on the platform. Every consumer below — the return
   chevron, the navigation/disclosure chevrons here, the account-tree
   .toggle-icon (§10), the <details> summary::before (§18) and the
   .picker-trigger dropdown (§7) — shares this exact geometry through the one
   rule below; each sets only what differs: the rotation, which encodes
   meaning (right = collapsed/forward, down = open, left = return), and its
   placement in context. Colour defaults to currentColor so the glyph follows
   its surrounding text/icon; .picker-trigger overrides it to the <select>
   chevron's muted grey (--gray-5, §X.1) since it is not inline text. */
summary::before,
.nav-icon--back::before,
.chevron-next::after,
.chevron-back::before,
.module-arrow::after,
.toggle-icon,
.picker-trigger::after,
.sidebar > button::before {
  width: .5rem; height: .5rem;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
}
/* Generated content — every consumer except .toggle-icon, a real element. */
summary::before,
.nav-icon--back::before,
.chevron-next::after,
.chevron-back::before,
.module-arrow::after,
.picker-trigger::after,
.sidebar > button::before {
  content: "";
}
/* Consumers that rotate at runtime (disclosure open/close, picker open)
   animate the turn. */
summary::before,
.toggle-icon,
.picker-trigger::after,
.sidebar > button::before {
  transition: transform var(--t-fast);
}
/* Inline consumers — drawn beside text, not flex-centred (.nav-icon--back,
   summary.sidebar-section-label above) or absolutely placed
   (.picker-trigger). `display` must move off `inline` for `transform` to
   apply, and all five share one vertical nudge so the glyph sits on the same
   axis wherever it appears inline (there is no other axis-correct way to
   centre a rotated border-chevron against surrounding text). */
summary::before,
.chevron-next::after,
.chevron-back::before,
.module-arrow::after,
.toggle-icon {
  display: inline-block;
  vertical-align: middle;
  position: relative;
  top: -.12em;
}

/* Return chevron (Accueil) — flex-centred in its 1rem glyph slot, the same
   mechanism the sidebar section-label chevron above uses, so both sit on the
   same axis as the .nav-icon glyphs beneath them (§X.1: same level = one
   left edge). One chevron size platform-wide. */
.nav-icon--back { display: inline-flex; align-items: center; justify-content: center; }
.nav-icon--back::before { transform: rotate(135deg); }

/* Navigation transition chevron (§3.7) — marks a link that NAVIGATES.
   Forward points right (::after), back points left (::before). Directional
   data arrows (Origine → Dest., Taux → CAD, ranges) are not transitions and
   keep the arrow. */
.chevron-next::after  { transform: rotate(-45deg); margin-left: .45rem; }
.chevron-back::before { transform: rotate(135deg); margin-right: .45rem; }
.module-arrow::after  { transform: rotate(-45deg); }  /* hub app redirection — forward */
.sidebar-nav a:hover .nav-icon,
.sidebar-nav a[aria-current="page"] .nav-icon { opacity: 1; }

/* Sidebar mobile toggle button */
.sidebar-toggle {
  display: none;
  position: fixed;
  top: .875rem;
  right: 1rem;
  z-index: 300;
  background: var(--black);
  color: var(--white);
  border: none;
  border-radius: var(--radius);
  width: 2.75rem;
  height: 2.75rem;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.sidebar-toggle svg { width: 1.375rem; height: 1.375rem; }

/* Sidebar overlay (mobile) */
.sidebar-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: var(--backdrop);
  z-index: 199;
  backdrop-filter: blur(2px);
}
.sidebar-overlay.active { display: block; }

/* ── 4. LAYOUT ─────────────────────────────────────────────────────────── */
.page-wrapper {
  margin-left: var(--sidebar-w);
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}
main {
  flex: 1;
  padding: 2rem 2.5rem;
  max-width: 1280px;
  width: 100%;
}
footer {
  padding: 1rem 2.5rem;
  border-top: 1px solid var(--border);
  color: var(--text-muted);
  font-size: .75rem;
}

/* ── 5. TYPOGRAPHY ─────────────────────────────────────────────────────── */
.page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 1.75rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--border);
}
.page-header h1 { margin-bottom: 0; }
.page-actions { display: flex; gap: .5rem; align-items: center; }

h1 { font-size: 1.375rem; font-weight: 700; letter-spacing: -.4px; margin-bottom: 1.5rem; color: var(--black); }
h2 { font-size: 1.0625rem; font-weight: 600; margin: 1.75rem 0 .875rem; color: var(--black); }
h3 { font-size: .9375rem; font-weight: 600; margin-bottom: .5rem; color: var(--black); }
.card > h3, fieldset > h3 { margin-top: 0; margin-bottom: 1rem; }
p  { margin-bottom: .75rem; }
p.lead { color: var(--text-muted); font-size: .9rem; margin-bottom: 1.5rem; margin-top: -.75rem; }
hr { border: none; border-top: 1px solid var(--border); margin: 2rem 0; }
small { font-size: .8em; color: var(--text-muted); }
strong { font-weight: 600; }

/* ── 6. CARDS — BEM component system ──────────────────────────────────── */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 1.5rem;
  margin-bottom: 1.5rem;
}

/* Stats modifier — KPI metric cards */
.card--stats .card-title {
  font-size: .75rem;
  font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: .07em;
  margin-bottom: .5rem;
}
.card--stats .card-value {
  font-size: 1.625rem;
  font-weight: 700;
  color: var(--black);
  letter-spacing: -.5px;
  line-height: 1.2;
}
.card--stats .card-sub { font-size: .75rem; color: var(--text-muted); margin-top: .25rem; }

/* Legacy aliases kept for backward compat during migration */
.card-title {
  font-size: .75rem;
  font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: .07em;
  margin-bottom: .5rem;
}
.card-value {
  font-size: 1.625rem;
  font-weight: 700;
  color: var(--black);
  letter-spacing: -.5px;
  line-height: 1.2;
}
.card-sub { font-size: .75rem; color: var(--text-muted); margin-top: .25rem; }

/* Auto-fill grid (§L2.2) — the single auto-fill grid of the platform: it fills
   each row with as many equal columns of at least --grid-min as fit. The
   default minimum is the KPI tile of a dashboard; a wider column comes from one
   of the modifiers below, never from an inline style. */
.auto-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(var(--grid-min, 210px), 1fr));
  gap: 1rem;
  margin-bottom: 2rem;
}
/* Column-minimum modifiers (§X.3 rule 4). Only the minimum ever varies, so the
   variants are modifiers of the grid rather than classes named after whichever
   page needed one (§X.3 rule 5).
   --wide:  a card holding a date range and its export actions.
   --roomy: a module card, which carries an icon, a title and a subtitle. */
.auto-grid--wide  { --grid-min: 320px; }
.auto-grid--roomy { --grid-min: 380px; }
/* A 380px minimum cannot share a phone-width row with anything: one column. */
@media (max-width: 600px) {
  .auto-grid--roomy { --grid-min: 100%; }
}

/* Table modifier — wraps <table> elements */
.card--table {
  padding: 0;
  overflow: hidden;
}

/* ── 7. FORMS ──────────────────────────────────────────────────────────── */
fieldset {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 1.25rem 1.5rem 1.5rem;
  margin-bottom: 1.25rem;
}
legend {
  font-size: .9375rem;
  font-weight: 600;
  color: var(--black);
  padding: 0 .5rem;
  margin-bottom: .25rem;
}
label {
  display: block;
  font-size: .75rem;
  font-weight: 600;
  color: var(--gray-6);
  margin-bottom: .3rem;
  margin-top: .875rem;
  text-transform: uppercase;
  letter-spacing: .05em;
}
label:first-child { margin-top: 0; }

input[type="text"],
input[type="number"],
input[type="email"],
input[type="search"],
input[type="password"],
input[type="date"],
select,
textarea {
  display: block;
  width: 100%;
  padding: .5rem .75rem;
  font-family: var(--font);
  font-size: .875rem;
  color: var(--black);
  background: var(--white);
  border: 1px solid var(--border-input);
  border-radius: var(--radius);
  transition: border-color var(--t-fast);
  appearance: none;
  -webkit-appearance: none;
}

input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
input[type="number"] { -moz-appearance: textfield; appearance: textfield; }

/* Selection boxes show the chevron, never a triangle/arrow (§3.7). A <select>
   (and an input[list] combobox) is a replaced element (no ::after), so the
   chevron is a stroked SVG matching the border-chevron: a down "v", not a
   filled triangle — --select-chevron (§1 tokens). Non-replaced selection
   controls use ::after (.picker-trigger), whose grey is the same --gray-5. */
select, input[list] {
  background-image: var(--select-chevron);
  background-repeat: no-repeat;
  background-position: right .7rem center;
  /* Pin the chevron to the border-chevron size (§3.7): a .5rem-tall glyph, not
     the SVG's incidental intrinsic size. Width follows the 10:6 viewBox. */
  background-size: auto .5rem;
  padding-right: 2rem;
}
textarea { resize: vertical; min-height: 72px; }
textarea::-webkit-resizer { border-radius: 0 0 var(--radius) 0; }
input[readonly] { background: var(--gray-1); color: var(--gray-5); cursor: default; }

input:disabled, select:disabled, textarea:disabled {
  opacity: .38;
  cursor: not-allowed;
}

input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--black);
  box-shadow: var(--focus-ring);
}

/* One invalid treatment. A badge joins the form controls here because "this
   total does not balance" is a validation failure, not a lifecycle state — it
   earns the danger tint, not a fourth badge colour (§X.2, §L1.3). */
input[aria-invalid="true"],
select[aria-invalid="true"],
textarea[aria-invalid="true"],
.badge[aria-invalid="true"] {
  border-color: var(--color-danger);
  box-shadow: var(--focus-ring-invalid);
}

.form-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 1rem;
  align-items: end;
}
.form-inline {
  display: flex;
  align-items: center;
  gap: .75rem;
  flex-wrap: wrap;
}
.form-inline label { margin: 0; white-space: nowrap; }
.form-inline input, .form-inline select { width: auto; }

input[type="checkbox"] {
  width: 1rem; height: 1rem;
  accent-color: var(--black);
  cursor: pointer;
  display: inline;
  margin-right: .4rem;
  vertical-align: middle;
}
label:has(input[type="checkbox"]) {
  display: flex;
  align-items: center;
  font-size: .875rem;
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
  color: var(--text);
  cursor: pointer;
  margin-top: .875rem;
}

/* Filter bar */
.filters-bar {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1rem 1.5rem;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: .75rem;
  margin-bottom: 1.5rem;
}
.filter-group {
  display: flex;
  flex-direction: column;
  gap: .25rem;
}
.filter-group label { margin: 0; }
.filter-actions { justify-content: flex-end; }
.btn-row { display: flex; gap: .5rem; }
.filter-group-grow { flex: 1; min-width: 14rem; }

/* Entry ID display */
.entry-id-display           { margin-bottom: .75rem; }
.entry-id-display label     { margin-top: 0; }
.entry-id-display .id-row   { display: flex; align-items: center; gap: .5rem; margin-top: .25rem; }

/* Input width utilities — journal line table only */
.input-xs { width: 7rem; }
.input-sm { width: 9rem; }
.input-md { width: 15rem; }
input[type="number"].input-xs,
input[type="number"].input-sm { text-align: right; font-variant-numeric: tabular-nums; font-family: var(--font-mono); }

/* ── 8. BUTTONS ────────────────────────────────────────────────────────── */
button, .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .4rem;
  padding: .45rem 1rem;
  font-family: var(--font);
  font-size: .8125rem;
  font-weight: 500;
  border-radius: var(--radius);
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  transition: background var(--t-normal), opacity var(--t-fast);
  white-space: nowrap;
  letter-spacing: .01em;
}

/* Primary — black filled */
button[type="submit"],
button.btn-primary, .btn-primary {
  background: var(--black);
  color: var(--white);
  border-color: var(--black);
}
button[type="submit"]:hover,
button.btn-primary:hover, .btn-primary:hover { opacity: .8; }

/* Ghost — transparent */
button.btn-ghost, .btn-ghost {
  background: transparent;
  color: var(--gray-6);
  border-color: var(--border);
}
button.btn-ghost:hover, .btn-ghost:hover {
  background: var(--gray-1);
  color: var(--black);
}

/* Critical — irreversible ledger-posting operations (always + reinforced confirmation) */
button.btn-critical, .btn-critical {
  background: var(--color-danger);
  color: var(--white);
  border-color: var(--color-danger);
}
button.btn-critical:hover, .btn-critical:hover { opacity: .8; }

/* Disabled state */
button:disabled, .btn:disabled {
  opacity: .38;
  cursor: not-allowed;
  pointer-events: none;
}

/* Small size modifier */
.btn-sm { padding: .25rem .625rem; font-size: .75rem; }

/* Loading state */
.btn.is-loading {
  position: relative;
  color: transparent;
  pointer-events: none;
}
.btn.is-loading::after {
  content: '';
  position: absolute;
  width: .875rem;
  height: .875rem;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: btn-spin .6s linear infinite;
}
@keyframes btn-spin { to { transform: rotate(360deg); } }

/* Motion is a preference, not a default. Anything that repeats on its own stops
   when the reader has asked the system for less of it (§X.4); the spinner keeps
   turning because it reports that work is still running. */
@media (prefers-reduced-motion: reduce) {
  .sidebar-brand img { animation: none; }
  /* A development server shows the motion regardless: an author whose own
     machine asks for less of it would otherwise never see what they ship. The
     preference is still honoured everywhere it is a real reader's. */
  body[data-dev] .sidebar-brand img { animation: logo-breathe 7s ease-in-out infinite; }
}

/* Button group */
.btn-group {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
}

/* Links */
a { color: var(--black); text-decoration: underline; text-underline-offset: 2px; }
a:hover { opacity: .65; }

/* ── 9. TABLES ─────────────────────────────────────────────────────────── */
.table-toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: .75rem 1.5rem;
  border-bottom: 1px solid var(--border);
}
.table-title { font-weight: 700; }
.table-count { font-size: .75rem; color: var(--text-muted); }
/* Semantic marker — financial-statement table (section title in thead, totals in
   tfoot); exempt from the collection-table toolbar anatomy (UI_NORMS §4.6). */
.table--report { }

table { width: 100%; border-collapse: collapse; font-size: .8125rem; }
table[border] { border: none; }

thead th {
  background: var(--gray-1);
  color: var(--gray-5);
  font-size: .7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .07em;
  padding: .625rem 1rem;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
  text-align: left;
}
thead th:last-child { text-align: right; }

tbody td {
  padding: .75rem 1rem;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
tbody tr:last-child td { border-bottom: none; }
tbody tr:hover { background: var(--gray-1); }

tfoot th, tfoot td {
  padding: .75rem 1rem;
  font-weight: 700;
  background: var(--gray-1);
  font-size: .8125rem;
}

td.num, th.num,
td:last-child, tfoot td:last-child, tfoot th:last-child { text-align: right; }
td.col-actions { text-align: right; white-space: nowrap; }
td.col-actions a, td.col-actions button { margin-left: .25rem; }

.col-amount {
  font-variant-numeric: tabular-nums;
  font-family: var(--font-mono);
  font-size: .8125rem;
  text-align: right;
}

/* Editable line table — journal entry form */
#lines-table { font-size: .8rem; }
#lines-table thead th { padding: .5rem .625rem; }
#lines-table tbody td,
#lines-table tfoot td  { padding: .375rem .5rem; }
#lines-table input, #lines-table select { font-size: .8rem; padding: .3125rem .5rem; }
/* Line-editor selects keep the one pinned chevron (§3.7), tight spacing. */
#lines-table select { background-position: right .3rem center; padding-right: 1.1rem; }
/* The row account/currency pickers match the compact row height + tight chevron gap. */
#lines-table .picker-trigger { font-size: .8rem; padding: .3125rem 1.1rem .3125rem .5rem; min-height: 0; }
#lines-table .picker-trigger::after { right: .4rem; }
/* The fx-currency picker keeps its narrow column width (was .input-xs select). */
#lines-table .picker-trigger.input-xs { width: 7rem; }
#lines-table input[type="number"] { font-family: var(--font-mono); }
/* Amount inputs fill their column; 0.25rem inner right pad preserved for readability.
   tfoot and base-amount offset = cell padding (.5rem) + input inner pad (.25rem) = .75rem
   so all three anchor points equal cell_right − .75rem and stay perfectly aligned. */
#lines-table td.col-amount > input  { width: 100%; padding-right: .25rem; }
#lines-table tfoot td               { padding-right: .75rem; }
#lines-table .cell-base-amount      { padding-right: .75rem; }
#lines-table input[type="number"]::-webkit-inner-spin-button,
#lines-table input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; display: none; }

/* ── Utility: visibility & feedback state (use instead of JS style mutation) */
.is-hidden          { display: none !important; }
.is-italic          { font-style: italic !important; }
/* Boxed like the status badges (D13) — anchored inline next to the action.
   One shape, two colours: success confirms, danger reports an inline error. */
.feedback-success,
.feedback-danger    {
  display: inline-block;
  margin-left: .5rem;
  padding: .2em .65em;
  font-size: .8rem;
  font-weight: 700;
  border: 1px solid currentColor;
  border-radius: var(--radius-sm);
  white-space: nowrap;
}
.feedback-success   {
  color: var(--color-success) !important;
  background: color-mix(in srgb, var(--color-success) 10%, transparent);
}
.feedback-danger    {
  color: var(--color-danger) !important;
  background: color-mix(in srgb, var(--color-danger) 10%, transparent);
}

/* Account picker list button */
.acc-option {
  display: block; width: 100%;
  padding: .5rem .75rem;
  text-align: left; font-family: var(--font-mono); font-size: .8rem;
  border: none; border-bottom: 1px solid var(--border); border-radius: 0;
  background: none; cursor: pointer; color: var(--text);
}
.acc-option:hover  { background: var(--bg-hover); }
.acc-option:last-child { border-bottom: none; }

/* ── 10. BADGES ────────────────────────────────────────────────────────── */
.badge {
  display: inline-block;
  padding: .2em .65em;
  font-size: .68rem;
  font-weight: 700;
  border-radius: var(--radius-sm);
  letter-spacing: .04em;
  text-transform: uppercase;
  white-space: nowrap;
  border: 1px solid transparent;
}
.badge-muted   { background: var(--gray-1); color: var(--black);  border-color: var(--gray-3); }
.badge-solid   { background: var(--black);  color: var(--white);  border-color: var(--black); }
.badge-outline { background: transparent;   color: var(--black);  border-color: var(--gray-4); }

/* Arborescence parent/disclosure row (§X.1) — a parent row in any table tree
   is marked by the black left rule only, no grey fill. */
.tree-parent td:first-child { box-shadow: inset 3px 0 0 var(--black); }
.tree-toggle { cursor: pointer; user-select: none; }
.tree-toggle:hover td { opacity: .8; }
/* Geometry, transition and inline placement come from the shared 8px
   border-chevron primitive (§3) — this rule sets only the rotation. */
.toggle-icon { transform: rotate(-45deg); margin-right: .5rem; }
.toggle-icon.open { transform: rotate(45deg); }

/* Progress meter (§L2.9) — filled bar + percentage label. The bar's width is
   set inline: per-record data that cannot be a static class (§X.6). */
.progress-cell { min-width: 120px; }
.progress { background: var(--gray-3); border-radius: var(--radius-sm); height: 8px; overflow: hidden; }
.progress > span { display: block; height: 100%; background: var(--gray-4); transition: width var(--t-slow); }
.progress.is-done > span    { background: var(--color-success); }
.progress.is-partial > span { background: var(--color-warning); }
.progress-label { font-size: .8em; margin-top: 2px; }

/* Scrollable picker list — bordered, capped-height option list inside a dialog (account picker) */
.picker-list { max-height: 300px; overflow-y: auto; border: 1px solid var(--border); border-radius: var(--radius-sm); }

/* Picker trigger — opens a searchable dialog in place of a <select>. It must be
   visually INDISTINGUISHABLE from a native select box before selection (§3.7):
   same font, size, colour, border, radius and padding, and the same chevron in
   the same place. It overrides its .btn .btn-ghost base entirely. */
.picker-trigger {
  display: block;
  position: relative;
  width: 100%;
  padding: .5rem 2rem .5rem .75rem;   /* = select box + room for the chevron */
  font-family: var(--font);
  font-size: .875rem;
  font-weight: 400;
  letter-spacing: normal;
  color: var(--black);
  background: var(--white);
  border: 1px solid var(--border-input);
  border-radius: var(--radius);
  text-align: left;
  transition: border-color var(--t-fast);
}
/* A select box does not react to hover — neither does its stand-in. */
.picker-trigger:hover { background: var(--white); color: var(--black); }
/* Focus ring identical to a <select> (§X.2, §X.4) — a picker stands in for a
   select and must not be less accessible than the control it replaces. */
.picker-trigger:focus {
  outline: none;
  border-color: var(--black);
  box-shadow: var(--focus-ring);
}
/* Geometry, generated content and the rotation transition come from the
   shared 8px border-chevron primitive (§3) — this rule sets only placement
   (absolute, right .7rem, vertically centred) and colour (--gray-5, the same
   grey as the <select> SVG stroke): `color` here is what the shared
   `currentColor` border resolves against for this pseudo-element specifically,
   overriding the black text colour it would otherwise inherit (§X.1). */
.picker-trigger::after {
  position: absolute;
  right: .7rem;
  top: 50%;
  transform: translateY(-60%) rotate(45deg);
  color: var(--gray-5);
}
/* Open state (§3.7): while the picker dialog is open, the chevron rotates up —
   the same disclosure motion a tree/summary chevron uses. */
.picker-trigger[aria-expanded="true"]::after { transform: translateY(-40%) rotate(-135deg); }

/* Field hint — a small helper line under a form control */
.field-hint { display: block; margin-top: .2rem; }

/* Compact card value — a metric shown at body size instead of the large stat size */
.card-value.card-value--sm { font-size: 1rem; }

/* Checkbox label — small inline label beside a checkbox */
.checkbox-label { font-size: .85rem; }

/* ── 11. ALERTS ────────────────────────────────────────────────────────── */
.alert {
  display: flex;
  align-items: flex-start;
  gap: .75rem;
  padding: .875rem 1rem;
  border-radius: var(--radius);
  margin-bottom: 1rem;
  font-size: .875rem;
  border-left: 3px solid var(--black);
  background: var(--gray-1);
  color: var(--black);
}
.alert-danger  { border-left-color: var(--color-danger);  background: var(--color-danger-tint);  color: var(--color-danger-text); }
.alert-success { border-left-color: var(--color-success); background: var(--color-success-tint); color: var(--color-success-text); }

/* API error banner */
#api-error {
  background: var(--gray-1);
  border-left: 3px solid var(--black);
  border-radius: var(--radius);
  padding: .75rem 1rem;
  margin-bottom: 1rem;
  font-size: .875rem;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
}
#api-error pre {
  font-family: var(--font-mono);
  font-size: .75rem;
  white-space: pre-wrap;
  flex: 1;
}

/* Form errors block */
#form-errors {
  background: var(--gray-1);
  border-left: 3px solid var(--color-danger);
  border-radius: var(--radius);
  padding: .75rem 1rem;
  margin: 1rem 0;
}
#form-errors li { margin-left: 1rem; font-size: .85rem; }

/* ── 13. CASH FLOW ─────────────────────────────────────────────────────── */
.cf-section-header {
  background: var(--black);
  color: var(--white);
  font-weight: 700;
  font-size: .75rem;
  text-transform: uppercase;
  letter-spacing: .07em;
  padding: .625rem 1rem;
}
.cf-section-total  { background: var(--gray-1); font-weight: 700; }
.cf-summary-total  { font-weight: 700; font-size: .9375rem; }

/* ── 14. EMPTY STATE ───────────────────────────────────────────────────── */
.empty-state {
  text-align: center;
  padding: 3rem 1rem;
  color: var(--text-muted);
}
.empty-state svg { display: block; margin: 0 auto .75rem; opacity: .3; }
.empty-state p   { margin: 0; font-size: .875rem; }

/* ── 15. LOADING STATE ─────────────────────────────────────────────────── */
.loading-row, td.loading-row {
  text-align: center;
  color: var(--text-muted);
  padding: 1.5rem;
  font-size: .875rem;
  font-style: italic;
}

/* ── 16. PAGINATION ────────────────────────────────────────────────────── */
.pagination-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: .5rem;
  margin-top: 1.5rem;
}
.page-info { font-size: .8125rem; color: var(--text-muted); }
.pagination-links { display: flex; gap: .25rem; }
.pagination-links a,
.pagination-links span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2rem;
  height: 2rem;
  padding: 0 .5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: .8125rem;
  text-decoration: none;
  color: var(--text);
  transition: background var(--t-fast);
}
.pagination-links a:hover  { background: var(--gray-1); }
.pagination-links .current { background: var(--black); color: var(--white); border-color: var(--black); font-weight: 600; }

/* ── 17. DIALOG ────────────────────────────────────────────────────────── */
dialog {
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 2rem;
  box-shadow: var(--shadow-md);
  max-width: 420px;
  width: 100%;
  max-height: 90vh;
  overflow-y: auto;
  font-family: var(--font);
}
dialog::backdrop { background: var(--backdrop); backdrop-filter: blur(2px); }
dialog h3 { margin-bottom: 1.25rem; font-size: 1rem; }
dialog .dialog-actions { display: flex; gap: .5rem; margin-top: 1.5rem; }
dialog .modal-error {
  margin-top: 1rem;
  margin-bottom: 0;
  padding: .6rem .75rem;
  border-left: 3px solid var(--color-danger);
  border-radius: var(--radius);
  background: var(--color-danger-tint);
  color: var(--color-danger);
  font-size: .875rem;
  line-height: 1.4;
}

/* Wide dialog — complex forms with multi-column tables */
dialog.dialog--wide { max-width: 780px; }

/* ── 18. DETAILS / COLLAPSIBLE ─────────────────────────────────────────── */
details {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  margin: 1rem 0;
}
summary {
  padding: .75rem 1rem;
  cursor: pointer;
  font-size: .875rem;
  font-weight: 500;
  color: var(--gray-6);
  list-style: none;
  user-select: none;
}
summary::-webkit-details-marker { display: none; }
/* Single platform-wide disclosure indicator: the shared 8px border-chevron
   primitive (§3) rotating cleanly around its centre — geometry, generated
   content, the rotation transition and inline placement all come from there;
   this rule sets only the rotation and the label gap. Closed = points right;
   open = points down. */
summary::before { margin-right: .55rem; transform: rotate(-45deg); }
details[open] > summary::before { transform: rotate(45deg); }
details > *:not(summary) { padding: 0 1rem 1rem; }
details pre {
  background: var(--gray-1);
  padding: 1rem;
  border-radius: var(--radius-sm);
  font-size: .8rem;
  overflow-x: auto;
  font-family: var(--font-mono);
}

/* ── 19. AUDIT LOG ─────────────────────────────────────────────────────── */
.audit-table { width: 100%; border-collapse: collapse; font-size: .8125rem; }
.audit-table th {
  text-align: left;
  padding: .6rem .75rem;
  font-size: .7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--text-muted);
  border-bottom: 2px solid var(--border);
  white-space: nowrap;
}
.audit-table td {
  padding: .5rem .75rem;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}
.audit-table tr:last-child td { border-bottom: none; }
.audit-table tr:hover td { background: var(--gray-1); }

.model-pill {
  display: inline-block;
  padding: .2rem .5rem;
  border-radius: var(--radius-sm);
  background: var(--gray-1);
  color: var(--text-muted);
  font-size: .72rem;
  font-weight: 600;
}
.ts        { color: var(--text-muted); font-size: .75rem; white-space: nowrap; }
.user-cell { font-weight: 500; }
.repr-cell { max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.changes-toggle {
  background: none;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: .2rem .5rem;
  font-size: .72rem;
  cursor: pointer;
  color: var(--text-muted);
  transition: background var(--t-fast), color var(--t-fast);
}
.changes-toggle:hover { background: var(--gray-1); color: var(--text); }

.changes-panel {
  display: none;
  margin-top: .5rem;
  padding: .75rem;
  background: var(--surface-code);
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: .73rem;
  line-height: 1.5;
  color: var(--text-code);
  white-space: pre-wrap;
  word-break: break-all;
  max-height: 260px;
  overflow-y: auto;
}
.changes-panel.open { display: block; }

/* ── 20. LOGIN PAGE ────────────────────────────────────────────────────── */
.login-body {
  font-family: var(--font);
  background: var(--bg);
  color: var(--black);
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
}
.login-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  padding: 2.5rem 2rem;
  width: 100%;
  max-width: 380px;
}
.login-brand { margin-bottom: 2rem; text-align: center; }
.login-brand-name {
  font-size: 1.125rem;
  font-weight: 700;
  letter-spacing: -.3px;
  color: var(--black);
}
.login-brand-sub {
  font-size: .7rem;
  color: var(--gray-5);
  text-transform: uppercase;
  letter-spacing: .08em;
  margin-top: .2rem;
}
.login-card h1 {
  font-size: 1rem;
  font-weight: 600;
  margin-bottom: 1.5rem;
  color: var(--black);
}
.error-list {
  background: var(--gray-1);
  border-left: 3px solid var(--color-danger);
  border-radius: var(--radius);
  padding: .75rem 1rem;
  margin-bottom: 1.25rem;
  font-size: .8125rem;
}
.error-list li { margin-left: 1rem; margin-top: .2rem; }
.next-info {
  font-size: .75rem;
  color: var(--gray-5);
  text-align: center;
  margin-top: 1.25rem;
}

/* Two-factor enrolment / verification (login-card pages) */
.totp-qr {
  display: flex;
  justify-content: center;
  margin: 1.25rem 0;
}
.totp-qr img {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--white);
  padding: .5rem;
}
.totp-manual-key {
  text-align: center;
  letter-spacing: .12em;
  font-size: .8125rem;
  margin-bottom: 1rem;
  word-break: break-all;
}
.recovery-codes {
  list-style: none;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .4rem .75rem;
  margin: 1.25rem 0;
  padding: 1rem;
  background: var(--gray-1);
  border-radius: var(--radius);
  font-size: .875rem;
  letter-spacing: .06em;
  text-align: center;
}

/* ── 21. UTILITIES ─────────────────────────────────────────────────────── */
.text-muted    { color: var(--text-muted); }
.text-warning  { color: var(--color-warning); }
.text-danger   { color: var(--color-danger); }
.text-success  { color: var(--color-success); }
.text-xs       { font-size: .75rem; }
.text-base     { font-size: 1rem; }
.font-mono     { font-family: var(--font-mono); }
.fw-bold       { font-weight: 700; }
.text-truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.text-id       { font-family: var(--font-mono); font-size: .875rem; font-weight: 600; }

.m-0  { margin: 0; }
.mt-1 { margin-top: .5rem; }    .mt-2 { margin-top: 1rem; }    .mt-3 { margin-top: 1.5rem; }
.mb-0 { margin-bottom: 0; }
.mb-1 { margin-bottom: .5rem; } .mb-2 { margin-bottom: 1rem; }
.ml-1 { margin-left: .5rem; }
.pt-1 { padding-top: .5rem; }
.d-flex { display: flex; }
.gap-1 { gap: .5rem; } .gap-2 { gap: 1rem; }
.align-center { align-items: center; }
.w-full { width: 100%; }

.col-description { max-width: 280px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.col-email { max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Auto-generated journal entry rows — info accent + tinted background */
tr.tr-auto > td:first-child    { border-left: 3px solid var(--black); padding-left: calc(1rem - 3px); }


.line-num { font-size: .75rem; color: var(--text-muted); padding: 0 .25rem; }

/* ── 22. HUB PAGE — platform selector landing ─────────────────────────── */
body.hub-page {
  display: block;          /* escape sidebar flex-row layout */
  padding: 3rem 1.5rem;
}
.hub-wrapper { width: 100%; max-width: 860px; margin: 0 auto; }
.hub-header  { margin-bottom: 3rem; }
.hub-brand {
  font-size: .75rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .12em;
  color: var(--text-muted); margin-bottom: .5rem;
}
.hub-title { font-size: 2rem; font-weight: 800; letter-spacing: -.6px; color: var(--black); margin-bottom: .5rem; }
.hub-sub   { font-size: .9375rem; color: var(--text-muted); }
.hub-user  {
  font-size: .8125rem; color: var(--text-muted);
  margin-top: 1.5rem; display: flex; align-items: center; gap: .75rem;
}
/* Hub domain section (UI_NORMS §L3.4) — cards grouped by business domain, each
   under a fixed-order label. The grid inside carries its own column minimum. */
.hub-domain { margin-bottom: 2.5rem; }
.hub-domain-label {
  font-size: .7rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .12em;
  color: var(--text-muted); margin-bottom: 1rem;
}
.module-card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: 1.75rem 2rem;
  text-decoration: none; color: inherit;
  display: flex; flex-direction: column; gap: 1rem;
  transition: border-color var(--t-normal), box-shadow var(--t-normal), transform var(--t-normal);
}
.module-card:hover {
  border-color: var(--black); box-shadow: var(--shadow-md);
  transform: translateY(-2px); opacity: 1;
}
.module-card-header { display: flex; align-items: center; gap: 1rem; }
.module-icon {
  width: 2.75rem; height: 2.75rem; border-radius: var(--radius);
  background: var(--gray-1); border: 1px solid var(--border);
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.module-icon svg { width: 1.25rem; height: 1.25rem; }
.module-name {
  font-size: 1rem; font-weight: 700; color: var(--black);
  letter-spacing: -.3px; margin: 0;
}
.module-code {
  font-size: .7rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: .1em;
  color: var(--text-muted); margin-top: .1rem;
}
.module-arrow {
  margin-left: auto; color: var(--gray-4);
  transition: color var(--t-fast), transform var(--t-fast);
}
.module-card:hover .module-arrow { color: var(--black); transform: translateX(3px); }
.hub-footer {
  font-size: .75rem; color: var(--text-muted);
  border-top: 1px solid var(--border); padding-top: 1.5rem;
  display: flex; justify-content: space-between; align-items: center;
}
@media (max-width: 600px) {
  body.hub-page { padding: 1.5rem 1rem; }
  .hub-title { font-size: 1.5rem; }
}

/* ── 23. RESPONSIVE — 3-BREAKPOINT SIDEBAR ─────────────────────────────── */

/* Tablet: icon-only sidebar (56px) */
@media (max-width: 1023px) {
  :root { --sidebar-w: 56px; }

  /* 56px cannot hold the two jumps side by side; they stack, each still a
     full-width target. */
  .sidebar-brand { flex-direction: column; }
  .sidebar-brand > a { padding: .7rem 0; }
  .sidebar-brand > a + a { border-left: 0; border-top: 1px solid var(--sidebar-border); }

  .sidebar-section { padding: .75rem .5rem .25rem; }
  /* Element-qualified to match the `summary.sidebar-section-label` shape rule:
     a bare class selector loses to it and the label would survive into the
     icon rail, which the tablet rule below assumes cannot happen. */
  summary.sidebar-section-label { display: none; }
  /* The bulk toggle commands a collapse the tablet rule below overrides, so it
     has nothing to act on at this width. */
  .sidebar > button { display: none; }

  .sidebar-nav a {
    justify-content: center;
    padding: .625rem;
    gap: 0;
  }
  /* Labels only. Accueil's return chevron is a <span class="nav-icon">, not an
     <svg>, so hiding every span left that row with no glyph at all. */
  .sidebar-nav a span:not(.nav-icon) { display: none; }

  main { padding: 1.5rem 1.75rem; }
  footer { padding: .75rem 1.75rem; }
}

/* Tablet only: the section label (summary) is hidden, so collapse is not
   reachable — force every section's links visible regardless of open state,
   otherwise a collapsed section would hide its icons. */
@media (min-width: 768px) and (max-width: 1023px) {
  details.sidebar-section > a { display: flex !important; }
}

/* Mobile: off-canvas drawer */
@media (max-width: 767px) {
  :root { --sidebar-w: 0px; }

  .sidebar {
    width: 240px;
    transform: translateX(-100%);
  }
  .sidebar.sidebar--open {
    transform: translateX(0);
  }

  .sidebar-brand { flex-direction: row; }
  .sidebar-brand > a { padding: 1.75rem 0; }
  .sidebar-brand > a + a { border-left: 1px solid var(--sidebar-border); border-top: 0; }

  .sidebar-section { padding: 1.25rem .75rem .5rem; }
  .sidebar-section-label { display: block; }

  .sidebar-nav a {
    justify-content: flex-start;
    padding: .5rem .75rem;
    gap: .6rem;
  }
  .sidebar-nav a span { display: inline; }

  .sidebar-toggle { display: flex; }

  .page-wrapper { margin-left: 0; }
  main { padding: 4rem 1rem 1rem; }
  footer { padding: .75rem 1rem; }
}

/* ── Section 23 — Attachment items (within .card wrapper) ───────────────────── */
.attachment-list { display: flex; flex-direction: column; gap: .5rem; }
.att-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: .5rem .75rem;
  background: var(--gray-1);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.att-item-info { display: flex; align-items: center; gap: .75rem; min-width: 0; }
.att-label {
  font-size: .75rem;
  font-weight: 600;
  color: var(--text-muted);
  white-space: nowrap;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 1px 6px;
}
.att-filename {
  font-size: .85rem;
  color: var(--black);
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 300px;
}
.att-filename:hover { text-decoration: underline; }
.att-date { font-size: .75rem; white-space: nowrap; color: var(--text-muted); }

/* ── Section 24 — Detail page table ─────────────────────────────────────────── */
.detail-table { width: 100%; border-collapse: collapse; }
.detail-table th, .detail-table td {
  padding: .65rem .75rem;
  border-bottom: 1px solid var(--border);
  text-align: left;
  font-size: .875rem;
}
.detail-table th {
  width: 180px;
  color: var(--text-muted);
  font-weight: 500;
  white-space: nowrap;
}
.detail-table tr:last-child th,
.detail-table tr:last-child td { border-bottom: none; }

/* ── 23. TOKEN SWATCH — single-screen: UI/UX gallery (§SR) ─────────────────
   DEBUG-only /ui/ catalog. A .swatch is a visual specimen of one L0 atom; the
   token it demonstrates is passed at the use site through the --swatch /
   --swatch-radius / --swatch-shadow custom property (displaying that token is
   the specimen's whole purpose). Bounded to the gallery — not replicated. */
.swatch-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 1rem;
}
.swatch { display: flex; flex-direction: column; gap: .35rem; }
.swatch-chip {
  height: 3rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--swatch, var(--surface));
}
.swatch-chip--radius { background: var(--gray-2); border-radius: var(--swatch-radius, 0); }
.swatch-chip--shadow { background: var(--surface); box-shadow: var(--swatch-shadow, none); }

/* Gallery frame — single-screen (gallery, §SR). A clipped, positioned box that
   contains normally-escaping elements so they can be shown in place instead of
   floating: `transform` makes it the containing block for position:fixed
   descendants (the sidebar), and being positioned contains an absolute
   `<dialog open>`. Lets the catalog render a real sidebar / dialog visually. */
.gallery-frame {
  position: relative;
  transform: translateZ(0);
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--bg);
}
/* An open <dialog> is absolutely positioned by the browser, so inside a
   clipping frame it is cut off. In the catalog it flows instead, and the frame
   grows to it — the specimen is the dialog's real box, whole. */
.gallery-frame dialog[open] {
  position: static;
  margin: 1.25rem auto;
  max-height: none;
}
.gallery-frame--tall { min-height: 420px; }

/* Layer specimens — single-screen (gallery, §SR). One aspect of an element,
   drawn with every other aspect stripped, so a reviewer sees the layer itself
   instead of subtracting the rest from a composed component. The audited
   values are passed at the use site through custom properties (--l-*), exactly
   as the token swatch does: displaying that value is the specimen's purpose. */
.layer-box {
  width: 7rem;
  height: 2.5rem;
  background: var(--gray-1);
  border-radius: var(--l-radius, 0);
  border: var(--l-border-width, 0) solid var(--gray-4);
  box-shadow: var(--l-shadow, none);
  flex-shrink: 0;
}
/* Spacing: the padding drawn as the gap between an outer edge and an inner
   block — the value itself, not a number to imagine. */
.layer-pad {
  display: inline-block;
  background: repeating-linear-gradient(45deg, var(--gray-2) 0 3px, transparent 3px 6px);
  border: 1px solid var(--gray-3);
  border-radius: var(--radius-xs);
  padding: var(--l-padding, 0);
}
.layer-pad > span {
  display: block;
  min-width: 3rem;
  min-height: 1rem;
  background: var(--gray-4);
}
/* Colour: the declared fill, text and border colours as flat chips. */
.layer-chip {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  font-size: .7rem;
  color: var(--text-muted);
}
.layer-chip::before {
  content: "";
  width: 1.25rem;
  height: 1.25rem;
  border-radius: var(--radius-xs);
  border: 1px solid var(--gray-3);
  background: var(--l-color, transparent);
}
/* Typography: the scale itself, on a neutral ground, with no box around it. */
.layer-type {
  font-size: var(--l-font-size, 1rem);
  font-weight: var(--l-font-weight, 400);
  text-transform: var(--l-transform, none);
  letter-spacing: var(--l-tracking, normal);
  color: var(--text);
}


/* BEGIN §SR · site public ──────────────────────────────────────────────────
   The public brochure site (WEBSITE) renders pages the platform has no shape
   for: a marketing hero, a public header carrying the language switch,
   content sections under a centred heading, a public footer, and a long-form
   legal document. None of them is an application screen, so none of them may
   join a General set — and each is a debt, recorded in the §SR register so it
   stays visible until the General vocabulary expresses a public page.

   Everything the General vocabulary already expresses is used as it stands:
   the card, the buttons, the badge, the auto-fill grid, the typography scale
   and the whole token palette. Nothing below restates any of them; what is
   here is only the frame those parts sit in, and it is bounded to the public
   site by the register row that names it.
   ───────────────────────────────────────────────────────────────────────── */

/* The page itself: the application shell lays the body out as a flex row for
   the rail beside the content, and a public page has no rail. */
body.site-page { display: block; }
.site-page main { margin: 0 auto; }

/* Keyboard's first stop, off-screen until it is focused. */
.site-skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 300;
  padding: .5rem 1rem;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  text-decoration: none;
}
.site-skip:focus { left: .5rem; top: .5rem; }

/* The public header: mark, page links, language. One row, wrapping rather
   than overflowing when the viewport cannot hold it. */
.site-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .75rem 1.5rem;
  width: 100%;
  max-width: 1280px;
  margin: 0 auto;
  padding: 1.25rem 2.5rem;
  border-bottom: 1px solid var(--border);
}
.site-brand {
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  margin-right: auto;
  color: var(--black);
  font-weight: 700;
  letter-spacing: -.3px;
  text-decoration: none;
}
/* The mark is a black monochrome file, so it is forced to the page's ink
   rather than carried as a second, differently-coloured copy (R86); an <img>
   cannot take `currentColor`. */
.site-brand img { width: 1.5rem; height: 1.5rem; filter: brightness(0); }

.site-nav { display: flex; align-items: center; gap: 1.25rem; }
.site-nav a {
  color: var(--text-muted);
  font-size: .875rem;
  font-weight: 500;
  text-decoration: none;
}
.site-nav a:hover { color: var(--black); opacity: 1; }
.site-nav a[aria-current="page"] { color: var(--black); font-weight: 600; }

.site-lang { display: flex; align-items: center; gap: .35rem; margin-left: auto; }
.site-lang a {
  padding: .15rem .45rem;
  border-radius: var(--radius-xs);
  color: var(--gray-5);
  font-size: .75rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-decoration: none;
}
.site-lang a:hover { color: var(--black); opacity: 1; }
.site-lang a[aria-current="true"] { background: var(--gray-1); color: var(--black); }
.site-lang span { color: var(--gray-4); }

/* The opening statement of a page. Wider type than the application's §L0.6
   scale, because it is read from across a room and not from a desk. */
.site-hero {
  max-width: 48rem;
  margin: 0 auto;
  padding: 3.5rem 0 2rem;
  text-align: center;
}
.site-hero h1 {
  font-size: clamp(1.75rem, 4.5vw, 2.5rem);
  line-height: 1.2;
  margin-bottom: 1rem;
}
.site-hero p { margin-bottom: 0; color: var(--text-muted); font-size: 1rem; }

/* The small capitalised line that names what follows — above a hero title and
   above a section title alike. */
.site-eyebrow {
  display: inline-block;
  margin-bottom: .75rem;
  color: var(--text-muted);
  font-size: .7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .12em;
}

/* One band of content, under a centred heading of its own. */
.site-section { padding: 3rem 0; border-top: 1px solid var(--border); }
.site-section > header { max-width: 40rem; margin: 0 auto 2rem; text-align: center; }
.site-section > header h2 { margin-top: 0; font-size: 1.5rem; }

/* Long-form legal prose: a reading measure, and the list markers the reset
   removes. */
.site-doc { max-width: 46rem; margin: 0 auto; }
.site-doc ul { list-style: disc; padding-left: 1.25rem; margin-bottom: .75rem; }

.site-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem 1.5rem;
  width: 100%;
  max-width: 1280px;
  margin: 0 auto;
}
.site-footer a { color: var(--text-muted); text-decoration: none; }
.site-footer a:hover { color: var(--black); }

/* Sections arrive rather than appear. The state is set by the site's script
   when the section reaches the viewport; a reader who has asked for less
   motion gets the arrived state from the start. */
.site-page [data-anim] {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity var(--t-slow), transform var(--t-slow);
}
.site-page [data-anim].is-visible { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .site-page [data-anim] { opacity: 1; transform: none; transition: none; }
}

/* The dark theme inverts the page's ink, and the mark has to invert with it or
   it is black on black. */
@media (prefers-color-scheme: dark) {
  .site-brand img { filter: brightness(0) invert(1); }
}

@media (max-width: 700px) {
  .site-header, .site-footer { padding-left: 1.25rem; padding-right: 1.25rem; }
  .site-page main { padding: 1.5rem 1.25rem; }
  .site-hero { padding-top: 2.5rem; }
  .site-section { padding: 2rem 0; }
}
/* END §SR · site public ─────────────────────────────────────────────────── */
