/* =============================================================================
   COMPONENTS — styles for the Thymeleaf fragment library.
   Every value here derives from tokens.css. If you need a new value,
   add a token first; never inline it.
============================================================================= */

/* ------------------------------------------------------------------- base */
*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--c-paper);
  color: var(--c-ink);
  font-family: var(--font-ui);
  font-size: var(--fs-base);
  line-height: var(--lh-base);
}

h1, h2, h3 { line-height: var(--lh-tight); margin: 0; }

a:not(.btn) { color: var(--c-primary); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:not(.btn):hover { color: var(--c-primary-hover); }

:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: var(--r-sm); }

/* Anything that displays an amount gets aligned figures. */
.num, .kpi__value, td.amount, .delta {
  font-feature-settings: var(--num-features);
  font-variant-numeric: tabular-nums lining-nums;
}

.code { font-family: var(--font-code); font-size: var(--fs-sm); }

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}

/* ---------------------------------------------------- signature: ledger rules */
/* Section heading: strong single rule beneath. */
.section-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--sp-4);
  padding-bottom: var(--sp-2);
  border-bottom: var(--rule-strong);
  margin-bottom: var(--sp-4);
}
.section-head h2 { font-size: var(--fs-lg); font-weight: var(--fw-semibold); }

/* One of several tables on a screen, each under its section head (fragments/overview-page.html :: tableSection). */
.page-section + .page-section { margin-top: var(--sp-7); }

/* Double rule = a total / definitive figure. Accounting notation. */
.ledger-total {
  border-top: var(--rule-strong);
  position: relative;
}
.ledger-total::after {
  content: ""; position: absolute; left: 0; right: 0; top: 2px;
  border-top: var(--rule-strong);
}

/* Eyebrow label: small-caps utility used above titles and KPI values. */
.eyebrow {
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--c-ink-muted);
}

/* --------------------------------------------------------------- page shell */
.shell { display: grid; grid-template-columns: var(--sidebar-w) 1fr; min-height: 100vh; }

/* Light rail. The logo's wordmark is navy, so the sidebar is a white ground:
   the mark is used exactly as drawn, never knocked out or recolored. The rail
   is separated from the page by a hairline, not by a fill. */
.shell__nav {
  background: var(--c-surface);
  color: var(--c-ink);
  border-right: var(--rule-hair);
  padding: var(--sp-5) var(--sp-4);
}
/* Brand lockup. The logo is the one brand moment per page: no gradients,
   no accent color, anywhere else. */
.shell__nav .brand {
  display: block; margin-bottom: var(--sp-6);
  color: inherit; text-decoration: none;
}
.shell__nav .brand img {
  display: block; width: 100%; max-width: 176px; height: auto;
}
/* Fallback when the logo is unavailable (e.g. print, mail) */
.shell__nav .brand .brand__text {
  font-weight: var(--fw-semibold); font-size: var(--fs-md); letter-spacing: 0.02em;
}
.shell__nav a.nav-item {
  display: block; color: var(--c-ink-muted);
  padding: var(--sp-2) var(--sp-3); border-radius: var(--r-sm);
  text-decoration: none; font-size: var(--fs-base);
  border-left: 2px solid transparent;
}
.shell__nav a.nav-item:hover { color: var(--c-ink); background: var(--c-surface-alt); }
.shell__nav a.nav-item:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: var(--r-sm); }
.shell__nav a.nav-item[aria-current="page"] {
  color: var(--c-ink); font-weight: var(--fw-medium);
  background: var(--c-primary-tint); border-left-color: var(--c-primary);
}

.shell__main { padding: var(--sp-6); max-width: var(--page-max); width: 100%; }

.page-head { margin-bottom: var(--sp-6); }
.page-head h1 { font-size: var(--fs-xl); font-weight: var(--fw-semibold); }
.page-head .page-meta { color: var(--c-ink-muted); font-size: var(--fs-sm); margin-top: var(--sp-1); }

/* Page head with actions: title + action buttons */
.page-head__actions { display: flex; align-items: center; gap: var(--sp-3); }
.page-head__title { flex: 1; }
.page-head__title h1 { margin: 0; }

@media (max-width: 900px) {
  .shell { grid-template-columns: 1fr; }
  .shell__nav { padding: var(--sp-3) var(--sp-4); }
  .shell__main { padding: var(--sp-4); }
}

/* ----------------------------------------------------------------- buttons */
.btn {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  height: var(--control-h); padding: 0 var(--sp-4);
  border-radius: var(--r-sm); border: 1px solid transparent;
  font: inherit; font-size: var(--fs-base); font-weight: var(--fw-medium);
  cursor: pointer;
  text-decoration: none;
}

.btn--primary { background: var(--c-primary); color: var(--c-on-primary); }
.btn--primary:hover { background: var(--c-primary-hover); }
.btn--secondary { background: var(--c-surface); color: var(--c-primary); border-color: var(--c-border-strong); }
.btn--secondary:hover { background: var(--c-primary-tint); }
.btn--quiet { background: transparent; color: var(--c-primary); }
.btn--quiet:hover { background: var(--c-primary-tint); }
.btn--neg { background: var(--c-neg); color: var(--c-on-primary); }
.btn--neg:hover { background: var(--c-neg-hover); }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }

/* ---------------------------------------------------------------- KPI card */
.kpi-row {
  display: grid; gap: var(--sp-4);
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  margin-bottom: var(--sp-6);
}

.kpi {
  background: var(--c-surface);
  border: var(--rule-hair);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-card);
  padding: var(--sp-4) var(--sp-5);
}
.kpi__label { margin-bottom: var(--sp-2); }
.kpi__value {
  font-size: var(--fs-num);
  font-weight: var(--fw-semibold);
  display: inline-block;
  padding-top: var(--sp-1);
}
/* Definitive figures carry the double rule above the value. */
.kpi__value.ledger-total { padding-top: var(--sp-2); }
.kpi__meta { margin-top: var(--sp-2); font-size: var(--fs-sm); color: var(--c-ink-muted); }

.delta { font-weight: var(--fw-semibold); font-size: var(--fs-sm); }
.delta--pos { color: var(--c-pos); }
.delta--neg { color: var(--c-neg); }
.delta--flat { color: var(--c-ink-muted); }

/* ------------------------------------------------------------------ badges */
.badge {
  display: inline-block; padding: 0 var(--sp-2);
  border-radius: var(--r-sm);
  font-size: var(--fs-xs); font-weight: var(--fw-semibold);
  white-space: nowrap;
  line-height: 1.6; letter-spacing: 0.02em;
}
.badge--pos  { background: var(--c-pos-tint);  color: var(--c-pos); }
.badge--neg  { background: var(--c-neg-tint);  color: var(--c-neg); }
.badge--warn { background: var(--c-warn-tint); color: var(--c-warn); }
.badge--info { background: var(--c-info-tint); color: var(--c-info); }

/* ------------------------------------------------------------------- chips */
/* Where an item lives, as an icon with its name (fragments/chip.html). The library chip
   borrows the brand ink, like .badge--active: it is a state, not a financial outcome. An
   owner's chip is a quiet outline, so the library stands out in a list of both. */
.chip {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  max-width: var(--chip-max-w);
  padding: 0 var(--sp-2);
  border: var(--rule-hair); border-radius: var(--r-sm);
  font-size: var(--fs-xs); font-weight: var(--fw-semibold);
  line-height: var(--lh-base); white-space: nowrap; vertical-align: middle;
}
.chip .icon { flex: none; }
.chip__label { overflow: hidden; text-overflow: ellipsis; }
.chip--library { background: var(--c-primary-tint); border-color: var(--c-primary-tint); color: var(--c-primary); }
.chip--owned {
  background: var(--c-surface);
  color: var(--c-ink-muted); font-weight: var(--fw-medium);
}

/* The head of an entity's form panel: its chip, what that means, and the action that
   changes it. */
.ownership-bar {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center;
  gap: var(--sp-2) var(--sp-3);
  padding-bottom: var(--sp-4);
  border-bottom: var(--rule-hair);
}
.ownership-bar .chip { justify-self: start; }
.ownership-bar__text {
  grid-column: 1 / -1; margin: 0;
  font-size: var(--fs-sm); color: var(--c-ink-muted);
}

/* -------------------------------------------------------------- data table */
.table-panel {
  background: var(--c-surface);
  border: var(--rule-hair);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-card);
  overflow-x: auto;
}

table.ledger {
  width: 100%; border-collapse: collapse;
  font-size: var(--fs-sm);
}
table.ledger caption {
  text-align: left; padding: var(--sp-4) var(--sp-4) var(--sp-2);
  font-size: var(--fs-md); font-weight: var(--fw-semibold); color: var(--c-ink);
}
/* Top-aligned, so a row whose cell wraps keeps every cell on its first line. The first column (the item's name)
   keeps a readable measure: it stops growing at 32rem and may break a word longer than that, so a long name wraps
   instead of pushing the other columns out of the panel, and it never shrinks below 14rem, so a tight table scrolls in
   its panel instead of stacking the name a few letters a line. The other columns wrap between words only. */
table.ledger th, table.ledger td {
  padding: var(--sp-2) var(--sp-4);
  text-align: left; vertical-align: top;
}
table.ledger td:first-child { min-width: 14rem; max-width: 32rem; overflow-wrap: anywhere; }
table.ledger thead th {
  font-size: var(--fs-xs); font-weight: var(--fw-semibold);
  letter-spacing: 0.05em; text-transform: uppercase;
  color: var(--c-ink-muted);
  border-bottom: var(--rule-strong);
  position: sticky; top: 0; background: var(--c-surface);
}
table.ledger tbody tr { border-bottom: var(--rule-hair); }
table.ledger tbody tr:hover { background: var(--c-primary-tint); }

/* Clickable rows: a row with a .row-link (the item's name, linking to its edit page; list-page :: rowLink) opens
   that page on a click anywhere in the row, through static/js/row-link.js. The link itself keeps the row
   keyboard-accessible and, without JavaScript, still opens the page. :focus-within lifts the row when the link is
   focused. */
table.ledger tbody tr:has(.row-link) { cursor: pointer; }
table.ledger tbody tr:has(.row-link):focus-within { background: var(--c-primary-tint); }
.row-link { color: inherit; text-decoration: none; font-weight: var(--fw-medium); }
.row-link:hover { text-decoration: underline; }
table.ledger th.amount, table.ledger td.amount { text-align: right; }
table.ledger td.amount.is-neg { color: var(--c-neg); }

/* Totals row: the double ledger rule, no zebra, semibold. */
table.ledger tfoot td {
  font-weight: var(--fw-semibold);
  border-top: var(--rule-strong);
  position: relative;
}
table.ledger tfoot td::after {
  content: ""; position: absolute; left: 0; right: 0; top: 2px;
  border-top: var(--rule-strong);
}

/* -------------------------------------------------------------- filter bar */
.filter-bar {
  display: flex; flex-wrap: wrap; align-items: end; gap: var(--sp-3);
  background: var(--c-surface);
  border: var(--rule-hair); border-radius: var(--r-md);
  box-shadow: var(--shadow-card);
  padding: var(--sp-3) var(--sp-4);
  margin-bottom: var(--sp-4);
}

.field { display: flex; flex-direction: column; gap: var(--sp-1); }
.field > label { font-size: var(--fs-xs); font-weight: var(--fw-medium); color: var(--c-ink-muted); }
.field > input, .field > select, .field > textarea {
  height: var(--control-h);
  padding: 0 var(--sp-3);
  border: 1px solid var(--c-border-strong);
  border-radius: var(--r-sm);
  background: var(--c-surface);
  font: inherit; font-size: var(--fs-base); color: var(--c-ink);
  min-width: 10rem;
}
.field > input:focus-visible, .field > select:focus-visible, .field > textarea:focus-visible { box-shadow: var(--focus-ring); }
/* A textarea is as tall as its rows, not one control high. */
.field > textarea { height: auto; min-height: var(--control-h); padding-block: var(--sp-2); line-height: var(--lh-base); resize: vertical; }

/* A checkbox list (field :: checkboxes): a fieldset whose options scroll within it, the chosen ones on top. */
.checklist { border: 0; padding: 0; margin: 0; min-width: 0; }
.checklist > legend { padding: 0; margin-bottom: var(--sp-1); font-size: var(--fs-sm); color: var(--c-ink); }
.checklist__options {
  list-style: none; margin: 0; padding: var(--sp-2) var(--sp-3);
  max-height: var(--checklist-max-h); overflow-y: auto;
  border: 1px solid var(--c-border-strong); border-radius: var(--r-sm); background: var(--c-surface);
}
.checklist__option { display: flex; align-items: center; gap: var(--sp-2); padding-block: var(--sp-1); }
.checklist__option input[type="checkbox"] { width: 16px; height: 16px; accent-color: var(--c-primary); }
.checklist__option input[type="checkbox"]:focus-visible { box-shadow: var(--focus-ring); }
.checklist__empty { font-size: var(--fs-sm); color: var(--c-ink-muted); }
/* The search field above the options (static/js/checklist-search.js); hidden until the script shows it. */
.checklist__search { margin-bottom: var(--sp-2); }
.checklist__search > input { width: 100%; min-width: 0; }
/* Both set display: flex, which would beat the hidden attribute. */
.checklist__search[hidden], .checklist__option[hidden] { display: none; }

/* A combobox a script puts in place of a long select (static/js/overheid-combobox.js): the field, the list under it,
   each option with its code. It looks as the islands' .builder-combobox does. */
.combobox { position: relative; }
.combobox > input {
  width: 100%; min-width: 0; height: var(--control-h); padding: 0 var(--sp-3);
  border: 1px solid var(--c-border-strong); border-radius: var(--r-sm); background: var(--c-surface);
  font: inherit; font-size: var(--fs-base); color: var(--c-ink);
}
.combobox > input:focus-visible { box-shadow: var(--focus-ring); }
.combobox__list, .combobox__empty {
  position: absolute; z-index: 10; top: calc(100% + var(--sp-1)); left: 0; right: 0; margin: 0;
  border: 1px solid var(--c-border-strong); border-radius: var(--r-sm); background: var(--c-surface);
  box-shadow: var(--shadow-pop);
}
.combobox__list { max-height: var(--checklist-max-h); padding: var(--sp-1) 0; overflow-y: auto; list-style: none; }
.combobox__empty { padding: var(--sp-2) var(--sp-3); font-size: var(--fs-sm); color: var(--c-ink-muted); }
.combobox__option {
  display: flex; justify-content: space-between; gap: var(--sp-2);
  padding: var(--sp-1) var(--sp-3); font-size: var(--fs-sm); cursor: pointer;
}
.combobox__option[aria-selected="true"] { background: var(--c-primary-tint); }
.combobox__code { font-family: var(--font-code); font-size: var(--fs-xs); color: var(--c-ink-muted); }
.combobox__list[hidden], .combobox__empty[hidden] { display: none; }

/* The search field is the primary control: let it grow to fill the bar. */
.filter-bar .field { flex: 1 1 20rem; }
.filter-bar .field > input, .filter-bar .field > textarea { width: 100%; }
/* A screen's own filter after the search field keeps the width of its options. */
.filter-bar .field--filter { flex: 0 0 auto; }

.filter-bar__actions { display: flex; gap: var(--sp-2); margin-left: auto; }

/* ------------------------------------------------------------------ alerts */
.alert {
  display: flex; gap: var(--sp-3); align-items: baseline;
  border-radius: var(--r-md);
  border: 1px solid;
  padding: var(--sp-3) var(--sp-4);
  margin-bottom: var(--sp-4);
  font-size: var(--fs-base);
}
.alert--info { background: var(--c-info-tint); border-color: var(--c-info); color: var(--c-ink); }
.alert--pos  { background: var(--c-pos-tint);  border-color: var(--c-pos);  color: var(--c-ink); }
.alert--warn { background: var(--c-warn-tint); border-color: var(--c-warn); color: var(--c-ink); }
.alert--neg  { background: var(--c-neg-tint);  border-color: var(--c-neg);  color: var(--c-ink); }
.alert__title { font-weight: var(--fw-semibold); }

/* Error-page styles live in forms.css alongside the other page-card layouts. */

/* ------------------------------------------------------------ pagination */
.pagination {
  display: flex; align-items: center; justify-content: center; gap: var(--sp-4);
  margin-top: var(--sp-4);
}

.pagination__summary {
  font-size: var(--fs-sm);
  color: var(--c-ink-muted);
}

.pagination__link {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  padding: var(--sp-1) var(--sp-3);
  border-radius: var(--r-sm);
  font: inherit; font-size: var(--fs-base); font-weight: var(--fw-medium);
  color: var(--c-primary);
  text-decoration: none;
  border: 1px solid transparent;
}

.pagination__link:hover:not(.pagination__link--disabled) {
  background: var(--c-primary-tint);
}
.pagination__link:focus-visible:not(.pagination__link--disabled) { outline: none; box-shadow: var(--focus-ring); border-radius: var(--r-sm); }

.pagination__link--disabled {
  color: var(--c-ink-faint);
  cursor: not-allowed;
}

.pagination__link--prev::before {
  content: "\2039";
}

.pagination__link--next::after {
  content: "\203A";
}

/* Empty state for tables */
.empty-state {
  text-align: center;
  padding: var(--sp-6);
  color: var(--c-ink-muted);
  font-size: var(--fs-md);
}

/* ------------------------------------------------------------- form panel */
/* Card used for the create/edit forms, which live on their own page (no
   modal, no overlay, no JavaScript to swap them in). */
.form-panel {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  width: min(480px, 100%);
  padding: var(--sp-5);
  border: var(--rule-hair);
  border-radius: var(--r-md);
  background: var(--c-surface);
  color: var(--c-ink);
  box-shadow: var(--shadow-pop);
  margin-bottom: var(--sp-5);
}

/* A second panel below a form (promotion on the entity form) names its action. */
.form-panel__title { font-size: var(--fs-md); font-weight: var(--fw-semibold); }

/* Fields fill the panel: the filter-bar min-width would otherwise size them. */
.form-panel .field > input,
.form-panel .field > select,
.form-panel .field > textarea { width: 100%; min-width: 0; }
.form-panel .field > label { font-size: var(--fs-sm); color: var(--c-ink); }

/* The fieldset only carries `disabled` for a read-only form: it adds no box, so the
   fields stay in the panel's column. */
.form-panel__fields { display: contents; }
.form-panel__fields:disabled .field > input,
.form-panel__fields:disabled .field > select,
.form-panel__fields:disabled .field > textarea {
  background: var(--c-surface-alt); color: var(--c-ink-muted); cursor: not-allowed;
}

.form-panel__actions {
  display: flex; justify-content: flex-end; gap: var(--sp-2);
}

/* A form screen's form and the panel after it. A panel that belongs with the form's subject (the entity form's Open
   data panel, with the binding editor) is an aside: it stands to the right of the form and takes the rest of the
   width, or goes below the form when the page is too narrow. Any other panel after the form stays below it. */
.form-page__body:has(> .form-panel--aside) {
  display: flex; flex-wrap: wrap; align-items: flex-start; column-gap: var(--sp-5);
}
.form-panel--aside { flex: 1 1 var(--form-aside-min-w); width: auto; min-width: 0; }

/* Delete action sits in its own quiet card, separated from the save form. */
.form-panel--danger {
  border-color: var(--c-neg-tint);
  background: var(--c-neg-tint);
}

/* The panel's gap spaces its lines, not the browser's paragraph margin. */
.form-panel--danger p { margin: 0; }

/* The item a delete confirmation is about, boxed so it reads as the subject of the panel. */
.form-panel__item {
  padding: var(--sp-3) var(--sp-4);
  border: var(--rule-hair);
  border-radius: var(--r-sm);
  background: var(--c-surface);
  font-size: var(--fs-lg);
  font-weight: var(--fw-semibold);
  overflow-wrap: anywhere;
}

/* --------------------------------------------------------- detail list/panel */
/* Term/description pairs, used in the detail modal and the no-JS detail page. */
.detail-list { display: flex; flex-direction: column; gap: var(--sp-3); }
.detail-list__item { display: flex; gap: var(--sp-4); }
.detail-list__term {
  min-width: 100px;
  color: var(--c-ink-muted); font-weight: var(--fw-medium); font-size: var(--fs-sm);
}
.detail-list__description { color: var(--c-ink); }

.detail-panel {
  background: var(--c-surface);
  border: var(--rule-hair); border-radius: var(--r-md);
  box-shadow: var(--shadow-card);
  padding: var(--sp-5);
  max-width: 600px;
}
.detail-panel__actions { display: flex; justify-content: flex-end; margin-top: var(--sp-5); }

/* -------------------------------------------------------- password display */
.password-display {
  margin-top: var(--sp-3);
  padding-top: var(--sp-3);
  border-top: var(--rule-hair);
}

.password-container {
  display: flex; gap: var(--sp-2); align-items: center;
  margin-top: var(--sp-2);
}

.password-container input[type="text"] {
  flex: 1;
  padding: var(--sp-2);
  border: var(--rule-hair);
  border-radius: var(--r-sm);
  background: var(--c-surface);
  color: var(--c-ink);
  font-family: var(--font-code);
  font-size: var(--fs-base);
}

.btn--small {
  padding: var(--sp-1) var(--sp-3);
  font-size: var(--fs-sm);
}
