/* 02-components.css: Cards, badges and pills, data table, filter bar, segmented toggle, pagination, sort links,
   detail header, tabs, definition lists, invitations list, stack.
   Loaded by base.html, one <link> per file in number order; a later file wins on source order. */

/* Cards, adopted from ops-platform. */
.card {
  display: block;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  padding: 1.5rem;
  text-decoration: none;
  color: var(--color-text);
}

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1.25rem;
  margin-top: 1.75rem;
}

.card-badge {
  display: inline-block;
  background: var(--color-primary);
  color: #fff;
  font-size: 0.65rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  padding: 0.15em 0.45em;
  border-radius: 4px;
  vertical-align: middle;
  margin-left: 0.4em;
}

/* Badges, adopted from ops-platform. Sized to match .btn-quiet.btn-sm (same
   font-size, line-height, vertical padding, border) so a single-line pill
   sits the same height as a button beside it, e.g. a dossier row's status
   pill next to its Opnieuw/Intrekken actions. A pill whose text wraps to two
   lines is taller by design; that's content length, not a sizing bug. */
.badge {
  display: inline-block;
  font-size: 0.8rem;
  font-weight: 600;
  line-height: 1.25;
  padding: 0.2rem 0.5rem;
  border-radius: 4px;
}

.badge-muted {
  background: var(--color-primary-soft);
  color: var(--color-muted);
  border: 1px solid rgba(230, 83, 46, 0.25);
}

/* Status pill variants, per the mockups' green "geverifieerd" / amber
   "verplicht, VOG ontbreekt" / grey "optioneel, Inactief" states. */
.badge-success {
  background: var(--color-success-bg);
  color: var(--color-success-fg);
  border: 1px solid rgba(22, 101, 52, 0.2);
}

.badge-warning {
  background: var(--color-warning-bg);
  color: var(--color-warning-fg);
  border: 1px solid rgba(138, 90, 18, 0.25);
}

.badge-neutral {
  background: var(--color-bg-accent);
  color: var(--color-muted);
  border: 1px solid var(--color-border);
}

/* Blocked / expired / missing: the red pills on HEA-189, HEA-219, HEA-227. */
.badge-error {
  background: var(--color-error-bg);
  color: var(--color-error);
  border: 1px solid rgba(180, 35, 24, 0.25);
}

/* Signing-status dots per side (K/L/KB) in the contract list and detail
   (HEA-199/HEA-196): green signed, blue signed outside BOLT, orange not yet
   signed, grey n/a, as HEA-199_contractstatus.png's legend names them. */
.sign-dot {
  display: inline-block;
  min-width: 1.6em;
  padding: 0.1em 0.35em;
  border-radius: 999px;
  border: 1px solid var(--color-border);
  font-size: 0.7rem;
  font-weight: 700;
  text-align: center;
}

.sign-dot + .sign-dot {
  margin-left: 0.25rem;
}

.sign-dot--na {
  background: var(--color-bg-accent);
  color: var(--color-muted);
}

.sign-dot--signed {
  background: var(--color-success-bg);
  color: var(--color-success-fg);
}

.sign-dot--pending {
  background: var(--color-warning-bg);
  color: var(--color-warning-fg);
}

/* Out for signing through Signhost (HEA-198): still waiting, so the waiting colours, with a
   solid ring that says something is under way. The legend of HEA-199 has no such state. */
.sign-dot--sent {
  background: var(--color-warning-bg);
  color: var(--color-warning-fg);
  border-color: var(--color-warning-fg);
}

/* The app's one blue: the fill and text of .badge-info (#dfe6ef is the deck's own pale blue,
   sampled on HEA-199's "wacht op klant" pill too). */
.sign-dot--external {
  background: #dfe6ef;
  color: #1d4e89;
  border-color: rgba(29, 78, 137, 0.2);
}

/* Data table, adopted from ops-platform. */
.data-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  margin-top: 1rem;
  background: var(--color-surface);
  border-radius: var(--radius);
  border: 1px solid var(--color-border);
  box-shadow: var(--shadow-sm);
}

.data-table thead th:first-child {
  border-top-left-radius: calc(var(--radius) - 1px);
}
.data-table thead th:last-child {
  border-top-right-radius: calc(var(--radius) - 1px);
}
.data-table tbody tr:last-child td:first-child {
  border-bottom-left-radius: calc(var(--radius) - 1px);
}
.data-table tbody tr:last-child td:last-child {
  border-bottom-right-radius: calc(var(--radius) - 1px);
}

.data-table th,
.data-table td {
  padding: 0.85rem 1rem;
  text-align: left;
}

/* The header row sits on the card, not on a tinted band: its rule and its
   muted small caps carry the separation. Sampled #ffffff in HEA-191/HEA-192. */
.data-table th {
  background: var(--color-surface);
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-muted);
  border-bottom: 1px solid var(--color-border);
}

.data-table td {
  border-bottom: 1px solid var(--color-border);
  font-size: 0.9rem;
  vertical-align: middle;
}

/* Alternating rows, as every list mockup draws them (sampled #faf7f0 on
   HEA-181 and HEA-189: the field token, not the darker accent). Totals rows
   keep their own fill. */
.data-table tbody tr:nth-child(even):not(.row-total) td {
  background: var(--color-field);
}

.data-table tr:last-child td {
  border-bottom: none;
}

.data-table a:not(.btn):not(.action-link) {
  color: var(--color-primary-hover);
  font-weight: 600;
  text-decoration: none;
}

.data-table a:not(.btn):not(.action-link):hover {
  text-decoration: underline;
}

/* Count columns (Kandidaten / Contracten). Header and cell are both
   right-aligned so the digits line up under their label; HEA-181's mockup
   left-aligns the header and sets the number loosely beneath it, which reads
   as a ragged column once the counts reach two digits. */
.data-table th.col-num,
.data-table td.col-num {
  text-align: right;
}

/* A table of status pills (HEA-189's supplier overview) keeps each pill on
   one line ("ontheffing t/m 31-07"): a pill broken over two lines reads as two
   statuses. Opt-in per table, so lists with longer pill texts keep wrapping
   rather than overflow. */
.data-table--pills .badge,
.data-table--pills .col-nowrap {
  white-space: nowrap;
}

/* NAAM and the Dossierstatus pill truncate with an ellipsis and carry the
   full text in their title; rows take their natural single-line height (user
   ruling, HEA-462, superseding the uniform 3rem floor). Inside a truncating
   cell the text and its "+N" badge are a flex row: the text shrinks, the
   badge never does, so the count the user reads stays visible. */
.data-table--pills .col-truncate {
  max-width: 16rem;
}

.data-table--pills .pill-row {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  min-width: 0;
}

.data-table--pills .pill-row > a,
.data-table--pills .badge-ellipsis {
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The contract list (HEA-199): every row is two lines and no cell wraps, so the rows are one
   height. A name that does not fit its column is cut with an ellipsis; a link or a second line
   in such a cell is a block, so it is cut too. */
.contract-list .col-truncate {
  max-width: 13rem;
  overflow: hidden;
  text-overflow: ellipsis;
}

.contract-list .col-truncate > a,
.contract-list .col-truncate > strong,
.contract-list .col-truncate > .cell-sub {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The legend of the signing dots, under the table it explains. */
.data-table + .sign-legend {
  margin: 0.75rem 0 0;
}

/* Secondary line inside a table cell: the e-mail under a candidate's name. */
.cell-sub {
  display: block;
  margin-top: 0.15rem;
  color: var(--color-muted);
  font-size: 0.8rem;
}

/* Per-row action cluster in the last column ("Bekijk - Bewerk"). The separator
   is a character in the template, not a ::before: the Bewerk link is
   role-gated, and a pseudo-element cannot be hidden along with it. */
.row-actions {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  white-space: nowrap;
}

/* Row actions one above the other, for a column too narrow to set them side by side. */
.row-actions--stacked {
  flex-direction: column;
  align-items: flex-start;
  gap: 0.1rem;
}

.row-actions__sep {
  color: var(--color-muted);
}

.action-link {
  color: var(--color-primary);
  text-decoration: none;
  font-weight: 600;
}

.action-link:hover {
  text-decoration: underline;
}

/* A row action that changes something is a form post, so a button: it reads exactly as the
   link beside it (HEA-198, the signatories on the Signhost settings page). */
button.action-link {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

.back-link {
  display: inline-block;
  color: var(--color-muted);
  text-decoration: none;
  font-size: 0.875rem;
  margin-bottom: 1.25rem;
}

.back-link:hover {
  color: var(--color-primary);
}

/* Filter/search bar controls. */
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  margin-top: 1rem;
}

/* One height for every control on the bar: unpinned, the search box measures
   37px next to 43px selects and a 44px segmented group; HEA-181 draws
   all three at the same 35px. */
.filter-bar input[type="text"],
.filter-bar input[type="search"] {
  box-sizing: border-box;
  height: 2.75rem;
  padding: 0 0.8rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  font-size: 0.9rem;
  background: var(--color-field);
  color: var(--color-text);
}

/* The last control on a bar takes the width the others leave, so the row ends
   flush with the table under it instead of stopping short. */
.filter-bar .filter-bar__grow {
  flex: 1 1 12rem;
  min-width: 12rem;
}

/* The list filters read as their own state ("Status: actief + inactief"), so
   they sit on the surface colour rather than the sunken field colour: they
   are readouts you can change, not blanks you fill in (HEA-191). */
.filter-bar select {
  /* width:auto overrides the global `select { width: 100% }` meant for the
     form grid -- a filter is as wide as its longest option, not its column. */
  width: auto;
  box-sizing: border-box;
  height: 2.75rem;
  padding: 0 0.8rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  font-size: 0.9rem;
  font-weight: 600;
  background: var(--color-surface);
  color: var(--color-text);
  cursor: pointer;
}

/* The "Filteren" submit sits shorter than the selects/inputs beside it --
   .btn-sm's own padding (0.25rem) undershoots their fixed 2.75rem. Scoped to
   [type="submit"] so it leaves the bar's other .btn uses alone: the
   metric-tab toggles (financials/report_charts.html, rendered as <a class=
   "btn btn-sm">) and the formatting-toolbar buttons (core/beheer_email_
   template.html, type="button") reuse .filter-bar as a plain flex row, not
   a control bar, and must not grow to match. inline-flex + centering
   replaces .btn's line-height-based centring, which reads off-centre once
   the box is taller than its text needs. */
.filter-bar .btn[type="submit"] {
  box-sizing: border-box;
  height: 2.75rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* The search box leads the bar and is its widest control. Narrower than a
   4-filter bar would need: HEA-191's fifth filter (Documenten) otherwise
   pushes Klant onto a second row at the 1440 viewport the mockups are
   measured against. */
.filter-bar input[type="search"] {
  width: 16rem;
  max-width: 100%;
}

/* A bar with room to spare gets the mockups' full-width search box. HEA-181's
   klantoverzicht draws it 401px wide (x=40..441 at 1440) against four
   controls, where HEA-191 needs 256px to fit five on one row. */
.filter-bar--roomy input[type="search"] {
  width: 25rem;
}

/* Between the two: HEA-189's bar carries a segmented group and five selects,
   so 25rem wraps Waadi onto the second row at 1440, while 16rem clips its
   own placeholder ("...of contactpersoon"). 18rem holds the placeholder and
   keeps the mockup's first row intact (measured 1333px of 1360). */
.filter-bar--wide-search input[type="search"] {
  width: 18rem;
}

/* Starts a second row of filters. HEA-189 keeps the mockup's row exactly
   (search, type, Dossier, Uitbetaling, Waadi) and puts the two filters the
   ticket adds beyond the deck on the row under it, rather than letting the
   bar wrap wherever the widths happen to fall. */
.filter-bar__break {
  flex-basis: 100%;
  height: 0;
}

/* Segmented single-choice toggle ("Alle / Direct / Via broker", HEA-181): one
   filled segment on --color-primary, the rest on --color-bg-accent. Sampled
   #e2543a / #ece4d5 off the mockup, i.e. the tokens, not new colours.

   The radio itself stays in the DOM and focusable (clipped, not
   display:none), so the group is reachable and operable by keyboard exactly
   like the native control it is; :focus-visible then lands on the label. */
.segmented {
  display: inline-flex;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  overflow: hidden;
}

.segmented__option {
  display: inline-flex;
  position: relative;
  /* The global label rule's margin-bottom would show as a strip under the
     segments, inside the rounded border. */
  margin: 0;
}

.segmented__option input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  margin: 0;
}

/* Equal-width segments, as HEA-181 draws them (x=462..761, three of 100px).
   The min-width is 125px rather than the deck's 100px: the deck sets its
   controls in a smaller face than this bar's 0.9rem/600, and "Via broker"
   needs 125px at our size. Widening all three keeps them equal, which is the
   part of the deck's geometry that reads; letting one segment run wider than
   its siblings does not. */
.segmented__option > span {
  display: inline-block;
  box-sizing: border-box;
  min-width: 125px;
  padding: 0.6rem 0.75rem;
  background: var(--color-bg-accent);
  color: var(--color-muted);
  font-size: 0.9rem;
  font-weight: 600;
  text-align: center;
  cursor: pointer;
}

.segmented__option + .segmented__option > span {
  border-left: 1px solid var(--color-border);
}

.segmented__option input:checked + span {
  background: var(--color-primary);
  color: #ffffff;
}

/* A read-only toggle (a frozen contract, a role that cannot write): the chosen segment in the
   muted ink rather than the primary, the other faded, no pointer. */
.segmented__option input:disabled + span {
  cursor: default;
}

.segmented__option input:disabled:checked + span {
  background: var(--color-muted);
  color: #ffffff;
}

.segmented__option input:disabled:not(:checked) + span {
  opacity: 0.6;
}

.segmented__option input:focus-visible + span {
  outline: 3px solid rgba(230, 83, 46, 0.35);
  outline-offset: -3px;
}

/* A two-word toggle inside a form card (HEA-186's Ja / Nee): the 125px
   segments are sized for "Via broker" and leave "Ja" floating in a wide box,
   and the filter bar's padding stands taller than the card's inputs. */
.segmented--compact .segmented__option > span {
  min-width: 4.5rem;
  padding-block: 0.4rem;
}

/* HEA-180's Type-klant row: the segmented toggle plus the direct-only hint
   beside it, sitting right under the page header on the customer create
   screen. */
.type-klant-row {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-bottom: 1.5rem;
}

.type-klant-row .section-note {
  margin: 0;
}

/* HEA-542: the toggle differs from the klant's stored kind, so Opslaan replaces its agreements. */
.type-klant-row .section-note--warning {
  color: var(--color-warning-fg);
  font-weight: 600;
}

/* A long note beside the toggle (HEA-542's locked note) must not squeeze the segments. */
.type-klant-row .segmented {
  flex-shrink: 0;
}

/* A card section that only applies to a direct customer (HEA-180's
   Facturatiegegevens, greyed out for a via-broker one): a plain <fieldset>
   carries the native disabled cascade to every control inside it, so this
   only has to undo <fieldset>'s own default chrome and dim it when off. */
/* A banner that follows a card keeps the cards' own vertical rhythm
   (HEA-180's via-broker banner under Selecteer broker). */
.form-section + .info-banner {
  margin-top: 1.25rem;
}

.form-section fieldset {
  display: block;
  border: 0;
  margin: 0;
  padding: 0;
  /* Chrome's UA sheet sets min-inline-size: min-content on <fieldset>, which
     stops the .field-grid inside from shrinking and overflows the page. */
  min-width: 0;
  min-inline-size: 0;
  width: 100%;
}

.form-section fieldset:disabled {
  opacity: 0.55;
}

/* Pagination controls, rendered inside the swapped table partial. */
.pagination {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  margin-top: 1rem;
  font-size: 0.85rem;
  color: var(--color-muted);
}

.pagination-status {
  font-weight: 600;
  color: var(--color-text);
}

/* The page-size dropdown closes the row at its right end, on the row's own
   line: a compact select the height of the .btn-sm page buttons beside it. */
.pagination-size {
  display: flex;
  align-items: center;
  margin-left: auto;
}

.pagination-size label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
}

/* The global select carries a form field's bottom margin and height; here it
   is one more item on the row's centre line, exactly as tall as .btn-sm. */
.pagination-size select {
  width: auto;
  height: 1.75rem;
  margin: 0;
  padding: 0 1.75rem 0 0.5rem;
  font-size: 0.85rem;
}

/* Sortable column header link, used inside .data-table thead. */
.sortable-header {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  color: inherit;
  text-decoration: none;
}

.sortable-header:hover {
  color: var(--color-primary-hover);
}

.sortable-header--active {
  color: var(--color-text);
}

.sort-indicator {
  font-size: 0.7em;
}

/* On a filter bar the pill is as high as the controls beside it, and a label keeps no gap under
   it: that gap is for a label above its control, and here it would lift the label off the
   row's middle. */
.filter-bar .checkbox-label {
  box-sizing: border-box;
  height: 2.75rem;
}

.filter-bar label {
  margin-bottom: 0;
}

.checkbox-label {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-weight: 500;
  font-size: 0.9rem;
  cursor: pointer;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 999px;
  padding: 0.4rem 0.65rem;
}

.empty-state {
  color: var(--color-muted);
}

/* Detail screens: h1 + primary action on one row (company/candidate detail). */
.detail-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.detail-header h1 {
  margin: 0;
}

/* Tab bar, e.g. company detail's info/contacts tabs. */
.tabs {
  display: flex;
  gap: 1.5rem;
  border-bottom: 1px solid var(--color-border);
  margin: 1.5rem 0 1.25rem;
}

/* A tab is a link to another page, or a button (role="tab") that switches a panel in place. */
.tabs a,
.tabs button {
  display: inline-block;
  padding: 0.65rem 0.1rem;
  color: var(--color-muted);
  text-decoration: none;
  font: inherit;
  font-size: 0.9375rem;
  font-weight: 600;
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  cursor: pointer;
}

.tabs a:hover,
.tabs button:hover {
  color: var(--color-text);
  border-bottom-color: var(--color-border-strong);
}

.tabs a.active,
.tabs button[aria-selected="true"] {
  color: var(--color-text);
  border-bottom-color: var(--color-primary);
}

/* Definition lists used by detail tabs/screens (company info tab, candidate detail). */
dl {
  margin: 1rem 0 0;
}

dl dt {
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-muted);
  margin-top: 1rem;
}

dl dt:first-child {
  margin-top: 0;
}

dl dd {
  margin: 0.2rem 0 0;
  font-size: 0.95rem;
}

/* The outstanding-invitations list (HEA-235, HEA-462). One grid for the whole
   list so every row's cells share the same column tracks and line up; each li
   is a subgrid row of it, which keeps its own separator rule. The last two
   tracks collapse to nothing when no row is overdue or has a date. */
.contact-list {
  list-style: none;
  margin: 1rem 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(5, max-content);
}

.contact-list li {
  display: grid;
  grid-template-columns: subgrid;
  grid-column: 1 / -1;
  align-items: center;
  gap: 0 0.75rem;
  padding: 0.65rem 0;
  border-bottom: 1px solid var(--color-border);
  font-size: 0.9rem;
}

.contact-list li:last-child {
  border-bottom: none;
}

.contact-name {
  font-weight: 600;
}

.contact-email {
  color: var(--color-muted);
}

/* Vertical stack with consistent gaps, e.g. the external dashboard's sections. */
.section-stack > * + * {
  margin-top: 1.25rem;
}

.dossier-list {
  list-style: none;
  margin: 0.75rem 0 0;
  padding: 0;
}

.dossier-list li {
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--color-border);
  font-size: 0.9rem;
}

.dossier-list li:last-child {
  border-bottom: none;
}
