/* ============================================================================
   portal.css — the TDM3 design system.

   Role: the component layer of the portal. This is where the `.tdm3-*`
   components live (buttons, badges, cards, callouts, the vnav) and the thin
   `.k-*` overrides for what the Kendo theme cannot express in variables.

   This file is the LAST SHARED layer of the chain (tokens.css → Bootstrap →
   the Kendo swatch → font-icons → bridge.css → portal.css → screens.css) and
   therefore wins on source order from everything everyone inherits: Bootstrap,
   the theme and the bridge. That is why no `!important` belongs here: order is
   enough. Every exception carries a comment with the rule it beats and why
   order and specificity were not enough.

   AFTER this file only screens.css comes, and that is deliberate: a screen may
   deviate from what it shares, and it should do so by standing later instead
   of by weighing more. Since P7 it really does stand there - site.css loaded
   at position 3 until then, before the theme.

   THE `.k-*` OVERRIDES LIVE HERE, and nowhere else. A screen block that wants
   to adjust a Kendo widget should do that through bridge.css (a variable) or
   here (a rule with the reason beside it). What screens.css still carries is
   not chrome but layout behavior of one screen: EIGHT rules — the two grid
   cells (`.k-grid td.feedback-info-cell`, `.k-grid td.feedback-command-cell`),
   the grid height (`.k-grid.invoice-download-grid`), the answer label
   (`.k-radio-label`), the two field rows of the address form
   (`.k-form-field`, `.k-form-field-wrap`), the resend button
   (`.k-grid .btn-resend`) and the check mark on the sign-out page
   (`.auth-icon-success .k-icon`).

   Until the migration's clean-up this text said THREE, and had said so for as
   long as it existed while there were eight — exactly the kind of claim every
   review reads past. The count is therefore a test now:
   `DesignSystemGuardTests.The_Kendo_overrides_of_our_stylesheets_are_declared`
   carries the full inventory (46 here, 8 in screens.css, 54 together) with the
   reason per rule, and fails on every `.k-*` rule that is added without
   somebody writing that reason down.

   Color literals do not belong here — exclusively `var(--tdm3-…)` from
   tokens.css.

   Working rules, naming and the trade-off "theme or override":
   docs/design-system/conventions.md. Components: docs/design-system/components.md.

   Order in this file: first the base typography, then the components, then the
   layout shell (menu, footer) and finally the `.k-*` overrides. The components
   arrived in step 3 and have one consumer: /Styleguide, which renders each of
   them. The screens follow in steps 5-8.
   ========================================================================= */


/* ============================================================================
   Base typography — the scale from docs/design-system/typography.md, on the
   elements themselves instead of on demo classes.

   The rem base was broken until this step: `screens.css` (then site.css) put `html` at 14px and
   at 16px from 768px up, and `_Layout` put an inline `body { font-size: 12px }`
   on top of that. So the screen showed 12px while every rem value computed
   from 16px - the size tokens came out 14.3% too large (24px rendered as
   27.42px). Both sources are gone; the root sits here at
   --tdm3-font-size-root, the same at every size. The media query is not coming
   back: a data grid that gets LARGER on a wide screen is the opposite of what
   a working screen wants.
   ========================================================================= */

html {
    font-size: var(--tdm3-font-size-root);
}

body {
    font-family: var(--tdm3-font-family);
    font-size: var(--tdm3-font-size-base);
    line-height: var(--tdm3-line-height);
    color: var(--tdm3-text);
}

/* Headings set themselves apart with weight and color, not with a second
   family: "Aptos Display" cannot be selected without webfont delivery
   (typography.md). The color hierarchy is navy -> accent blue -> navy. H3 is
   deliberately not green, unlike in the document scale: on the web --tdm3-green
   carries success semantics, and a green heading beside a green success badge
   gives two meanings to one color. */
h1,
h2,
h3 {
    font-weight: var(--tdm3-font-weight-bold);
    line-height: var(--tdm3-line-height-tight);
}

h1 {
    font-size: var(--tdm3-font-size-h1);
    color: var(--tdm3-color-heading);
}

h2 {
    font-size: var(--tdm3-font-size-h2);
    color: var(--tdm3-blue);
}

h3 {
    font-size: var(--tdm3-font-size-lg);
    color: var(--tdm3-color-heading);
}

/* Real links only. Kendo puts `color: inherit` on `.k-link` and `.k-button`,
   and those classes weigh more than an element selector, so widget chrome
   (menu, pager, grid buttons) stays the theme's. */
a {
    color: var(--tdm3-color-link);
}

a:hover {
    color: var(--tdm3-color-link-hover);
}


/* ============================================================================
   Buttons — four kinds, and no more than four (components.md).

   `.tdm3-is-hover` and `.tdm3-is-focus` stand beside the real pseudo-class
   everywhere. They exist for the styleguide: hover and focus are the two
   states you do not see without holding the mouse or the tab key, and a
   reference image missing half the states proves nothing. They are not
   behavior - nothing outside that page sets them.
   ========================================================================= */

.tdm3-btn {
    display: inline-flex;
    align-items: center;
    /* Added in migration step 8, and not as a matter of taste: a button is a
       flex container, and a flex container drops a text node consisting of
       whitespace only. With `<i class="k-icon"></i> Terug naar Home` that made
       the space between icon and label disappear - measured on the first two
       screens that use this button WITH an icon (access-denied and
       sign-out-succeeded). The four consumers from before this step carry text
       only and therefore have one flex item: nothing changes for them. A finding
       for components.md, where the button shape names no gap. */
    gap: var(--tdm3-space-1);
    padding: var(--tdm3-space-1) var(--tdm3-space-3);
    /* Lightly filled WITH a border, and both halves are needed
       (post-processing A). The button stood on white with a --tdm3-border
       border: 1.61:1 against the page and therefore no visible boundary - on the
       sign-in page "Français" beside the tinted "Nederlands" read as text and not
       as a button. A surface alone does not fix that (--tdm3-surface-muted
       against white is 1.09:1), a border alone no more so: together they carry
       the shape. --tdm3-border-strong reaches 4.69:1 against the page and 4.30:1
       against its own surface, both above the 3:1 WCAG 1.4.11 asks for the
       boundary of an operable component. The text sits at 14.15:1 (--tdm3-text
       on --tdm3-surface-muted). --tdm3-border stays what it was: the separation
       between two surfaces. */
    border: 1px solid var(--tdm3-border-strong);
    border-radius: var(--tdm3-radius);
    background-color: var(--tdm3-surface-muted);
    color: var(--tdm3-text);
    font-family: inherit;
    font-size: var(--tdm3-font-size-base);
    font-weight: var(--tdm3-font-weight-medium);
    line-height: var(--tdm3-line-height-tight);
    text-decoration: none;
    cursor: pointer;
}

/* One step darker than the rest surface - --tdm3-surface-section is the next
   grey step tokens.css knows. Text 12.59:1, border 3.83:1 against that
   surface. */
.tdm3-btn:hover,
.tdm3-btn.tdm3-is-hover {
    background-color: var(--tdm3-surface-section);
    color: var(--tdm3-text);
    text-decoration: none;
}

/* The action of the screen or the dialog. White on --tdm3-color-primary is 6.94:1. */
.tdm3-btn-primary {
    border-color: var(--tdm3-color-primary);
    background-color: var(--tdm3-color-primary);
    color: var(--tdm3-color-primary-contrast);
}

.tdm3-btn-primary:hover,
.tdm3-btn-primary.tdm3-is-hover {
    border-color: var(--tdm3-color-primary-hover);
    background-color: var(--tdm3-color-primary-hover);
    color: var(--tdm3-color-primary-contrast);
}

/* Actions in grid cells and toolbars. A ghost button: no surface, but a border,
   and a light surface on hover.

   Until post-processing C it stood on `border-color: transparent` with only an
   underline on hover, and that is the same ailment post-processing A repaired
   for the default button - at rest there was nothing distinguishing it from
   text. That "nothing" is measurable: accent-blue button text reaches 2.22:1
   against the ordinary text color beside it (#156082 against #212529), and WCAG
   G183 asks for 3:1 as soon as color is the only thing marking an operable
   component. Color alone is therefore not enough here, and that makes the border
   the carrier - and then WCAG 1.4.11's 3:1 applies to that border.

   Hence --tdm3-border-strong and not --tdm3-border, even though this is the
   button that stands twenty times under each other in a grid. Measured on the
   three surfaces it lies on there: 4.69:1 on white, 4.30:1 on
   --tdm3-table-row-alt and 4.20:1 on the new --tdm3-table-row-hover.
   --tdm3-border reaches 1.61 / 1.47 / 1.44 there and would draw a border that
   does not count as a boundary - the shape of noise without the yield. The same
   border as .tdm3-btn, so the two kinds stay one button family: equal boundary,
   different surface.

   GEOMETRY DOES NOT CHANGE. .tdm3-btn sets `border: 1px solid` and this variant
   only overrode the color; the 1px was therefore already reserved. Re-measured
   in the running app: 69.2 x 28.89px before and after, and the Kendo counterpart
   below already carries `border: 1px solid transparent` from the theme too. */
.tdm3-btn-subtle {
    border-color: var(--tdm3-border-strong);
    background-color: transparent;
    color: var(--tdm3-color-link);
}

/* A light surface instead of an underline: underlining says "link", filling says
   "button", and this is a button. --tdm3-color-info-bg is the tint of its own
   family (the button text is accent blue) and stands clear on each of the three
   row surfaces: CIEDE2000 9.42 on white, 8.42 on the alternating row and 4.39 on
   the hover tint. Text on it 7.16:1. */
.tdm3-btn-subtle:hover,
.tdm3-btn-subtle.tdm3-is-hover {
    background-color: var(--tdm3-color-info-bg);
    color: var(--tdm3-color-link-hover);
    text-decoration: none;
}

/* Destructive. Filled only in confirmation dialogs; here the outlined shape. */
.tdm3-btn-danger {
    border-color: var(--tdm3-color-danger);
    background-color: var(--tdm3-surface);
    color: var(--tdm3-color-danger);
}

.tdm3-btn-danger:hover,
.tdm3-btn-danger.tdm3-is-hover {
    background-color: var(--tdm3-color-danger-bg);
    color: var(--tdm3-color-danger);
}

/* A size variant, not a fifth kind: it combines with each of the four above and
   only changes padding and text size. For THE action of a page that has nothing
   else to do - the sign-in button is the first consumer. Not for dialog buttons
   or toolbars: the base size stays there, which at 4px/12px is exactly as it
   was.

   The sizes come from the 4px scale and are therefore not a free choice. What
   was asked for was "about 10px/24px"; 10 does not exist on the scale, so
   vertically --tdm3-space-2 (8px) - the step below, because --tdm3-space-3
   (12px) makes a 47.6px button with 16px text and that is a control surface that
   reads as a bar on an empty card. Horizontally --tdm3-space-5 (24px), exactly
   the value asked for. Outcome, measured in the running app: 8 + 21.6 (16px x
   1.35) + 8 + 2 borders = 39.59px high against 28.89px for the base button.

   Stands AFTER the four variants and has the same specificity as .tdm3-btn: on
   equal specificity source order wins, and padding and font-size both come from
   .tdm3-btn. Moving it up freezes the size. */
.tdm3-btn-lg {
    padding: var(--tdm3-space-2) var(--tdm3-space-5);
    font-size: var(--tdm3-font-size-lg);
}

/* After the variants, so the ring sits on each of the four. --tdm3-color-focus
   is accent blue: --tdm3-sky does not make the 3:1 for non-text (2.25:1). */
.tdm3-btn:focus,
.tdm3-btn.tdm3-is-focus {
    outline: 2px solid var(--tdm3-color-focus);
    outline-offset: 1px;
}


/* ============================================================================
   Form fields — label above, help text below, error at the field.

   The three `.k-*` rules at the bottom of this block belong to the same pattern
   and therefore sit here and not with the other Kendo overrides: they are the
   shared half of what until step 5 stood copied out twice inside a view
   (`_DeliveryMethodEditor` and `EditAddressFeedbackRequest`), and then only for
   as long as that editor was open.
   ========================================================================= */

.tdm3-field {
    margin-bottom: var(--tdm3-space-4);
}

.tdm3-label {
    display: block;
    margin-bottom: var(--tdm3-space-1);
    color: var(--tdm3-text-subtle);
    font-weight: var(--tdm3-font-weight-medium);
}

.tdm3-input {
    display: block;
    width: 100%;
    padding: var(--tdm3-space-1) var(--tdm3-space-2);
    /* --tdm3-border-field since post-processing D, was --tdm3-border (#CCC,
       1.61:1 on white). A field is an operable component and its border
       therefore falls under WCAG 1.4.11's 3:1; --tdm3-border stays what it always
       was, the separation between two surfaces. See tokens.css for the
       measurement and why no lighter value exists that makes it on all four
       field surfaces. */
    border: 1px solid var(--tdm3-border-field);
    border-radius: var(--tdm3-radius);
    background-color: var(--tdm3-surface);
    color: var(--tdm3-text);
    font-family: inherit;
    font-size: var(--tdm3-font-size-base);
    line-height: var(--tdm3-line-height);
}

.tdm3-input:focus,
.tdm3-input.tdm3-is-focus {
    border-color: var(--tdm3-color-focus);
    outline: 2px solid var(--tdm3-color-focus);
    outline-offset: 1px;
}

/* The remark field, the same in both dialogs. The collection screen asks for one
   (the answer dialog) and the delivery dialog for three (one per delivery
   method), and it is the same question to the same person every time. They
   differed: four rows against two, a label in the column against a floating
   label, a bare <textarea> against a real widget. What the widget itself governs
   is in UserRemarkField (rows, max length) and not here; only what CSS has to say
   stands here.

   width: the theme gives a .k-textarea 18em and corrects that to 100% as soon as
   it sits in a floating-label container. That second rule applies here too, but
   the width then depends on whether the widget has been set up yet - and that
   happens in JS, after the dialog is opened. This rule makes the field equally
   wide as the column below it at both moments, so nothing jumps.

   resize: the theme puts `resize: both` on every textarea. Dragging sideways
   pulls the field out of a 780px modal window - there is no width to grow into.
   Vertically it does make sense: two rows is the starting size, not the ceiling. */
.tdm3-remark {
    width: 100%;
    resize: vertical;
}

/* Bootstrap's own field class, which the theme does NOT cover and .tdm3-input
   does not either. Six fields on one screen (TestData/Index.cshtml) carry
   `.form-control`, and that class comes from bootstrap.css - the first
   stylesheet of the chain. Measured in the running app: border #CED4DA (1.49:1
   against the page), focus #80BDFF (1.97:1) with a glow in #007BFF. All three
   sit below WCAG 1.4.11's 3:1, and none of the three comes from tokens.css.

   Why a rule here and not replacing the class in the view: besides color
   `.form-control` also supplies height, transition and focus behavior, and
   replacing those with .tdm3-input is a markup and geometry change on a screen
   this assignment does not otherwise touch. This rule touches only the two
   colors and leaves the measured 33.5px standing. What deliberately stays open
   as a result, as a decision for the owner: that screen is the only one in the
   application still drawing its fields from Bootstrap, and lifting it to
   .tdm3-input asks for that geometry change plus a re-measurement of the whole
   form. THIS is the contrast standard, not that migration.

   The focus border has to come along for the same reason as in the theme: on the
   new rest border #80BDFF would make a field LIGHTER on focus instead of
   darker. */
.form-control {
    border-color: var(--tdm3-border-field);
}

.form-control:focus {
    border-color: var(--tdm3-color-focus);
}

/* One invalid marking for the whole application (components.md, "Validatie —
   één patroon, gedeeld"). The two copies this one comes from set
   `border: 1px solid red !important`: pure red, and `!important` because the
   Kendo CSS loaded AFTER ours back then. Both reasons have lapsed — this file
   loads last — and the color is now the system's.

   Measured: the theme already gives `.k-textbox.k-invalid` `#C00000` by itself
   (`--kendo-color-error` sits at `--tdm3-color-danger` in `bridge.css`), so for
   Kendo's own text boxes this rule confirms what already stood there; it is here
   for the widgets the theme does NOT cover — the `span.k-invalid` wrapper and a
   plain `<input>` — and so that there is one place where the color stands.

   THE BORDER IS 2PX SINCE POST-PROCESSING E, and that is a decision by the owner
   with a measurement under it. Since post-processing D the REST border sits at
   --tdm3-border-field (#6C757D) and with that the luminance difference between
   rest and error dropped from 4.34:1 to 1.38:1: red and grey are equally dark,
   so anyone who does not see color no longer saw the difference. Doubling the
   thickness puts a signal beside it that is NOT color (WCAG 1.4.1) - the color
   itself does not change, and does not need to: #C00000 reaches 6.48:1 against
   the page, well above the 3:1 that 1.4.11 asks for the boundary of an operable
   component.

   WHY HERE AND NOT IN A BRIDGE VARIABLE (conventions.md rule 1 asks for that
   order explicitly): the COLOR does come from a variable -
   --kendo-color-error-on-surface, which bridge.css sets to --tdm3-color-danger -
   but a WIDTH for the invalid state does not exist in the 2026 variable palette.
   The only width there is sits hard in the rule
   `.k-input, .k-picker { border-width: 1px }` and applies to every field in every
   state; lifting that would thicken the rest border along with it and is
   therefore the opposite of what is asked here. There is no theme route, hence
   this one. The color is only here because one declaration says nothing without
   the other.

   WHY border-width AND NOT an inset box-shadow, because that was the
   alternative: on an invalid field that has FOCUS the theme itself sets a
   box-shadow (`.k-input.k-invalid:focus`, specificity 0,3,0). An inset ring of
   ours - 0,1,1 at most - is replaced there and not supplemented, on exactly the
   field kind that is the only one in this application to really get an error
   marking. That same theme rule sets NO border-width and NO border-color, so the
   2px below does survive focus.

   CLASS NAMES. `.k-widget > span.k-invalid` stood here, and that has been dead
   since 2026: `k-widget` is no longer rendered by Kendo (measured across all five
   screens: zero elements), and the wrapper carrying the state is now the widget
   itself - `.k-input` for a text field, `.k-picker` for a picker, both WITH
   `.k-invalid`. Two classes, then, exactly as many as the theme rule, after
   which source order decides.

   GEOMETRY: zero shift, and that has been re-measured per field kind in the
   running app. Every field kind with a THEME HEIGHT absorbs the extra pixel by
   itself - they are `box-sizing: border-box` with an explicit height
   (`.k-textbox`: `height: calc(1.5em + 0.75rem + 2px)` = 33.5px), so the box
   stays put and only the interior shrinks 2px. Measured on the five address
   fields and the country picker of the delivery editor: 0.00px on x, y, width
   and height. Field kinds whose height follows from the CONTENT do grow, and
   they get their pixel back in padding below. */
.k-input.k-invalid,
.k-picker.k-invalid,
input.k-invalid,
textarea.k-invalid,
select.k-invalid,
.tdm3-field-invalid {
    border-color: var(--tdm3-color-danger);
    border-width: 2px;
}

/* The two field kinds with no theme height. Their height is content + padding + border,
   so there the second border pixel makes the box 2px taller and shifts everything below it -
   measured before this rule: .tdm3-input 31 -> 33px and the page 4px longer.
   One pixel of padding given back per side puts that back at exactly zero (re-measured: 0.00px
   on every field, every message and the document height).

   Two rules and not one, because the two have a different rest padding: ours
   sits on the 4px scale, the textarea's comes from the theme. The theme values
   sit here literally because a calc cannot refer to "the current padding";
   they are $input-padding-y/-x from 4.42.0. This is the only spot in this
   file where a theme size is overridden instead of read, and it
   sits here only to zero out a geometry change we ourselves cause. */
.tdm3-input.tdm3-field-invalid {
    padding: calc(var(--tdm3-space-1) - 1px) calc(var(--tdm3-space-2) - 1px);
}

textarea.k-invalid {
    padding: calc(0.375rem - 1px) calc(0.75rem - 1px);
}

/* The label at the top of its row instead of at the bottom. The theme puts
   `align-items: flex-end` on a label in a horizontal Kendo form, which pushes the
   label to the bottom of a field row two lines high — beside a one-line text box
   that reads as a caption.

   Two selectors, because the theme does it in two steps: `.k-form .k-label`
   (0,2,0) makes the label a flexbox, `.k-form-horizontal .k-form-field >
   .k-label` (0,3,0) sets the alignment. Each one element heavier here, so this
   wins without the `!important` the two view copies needed. */
.k-form label.k-label,
.k-form-horizontal .k-form-field > label.k-label {
    align-items: flex-start;
}

.tdm3-help {
    display: block;
    margin-top: var(--tdm3-space-1);
    color: var(--tdm3-text-muted);
    font-size: var(--tdm3-font-size-sm);
}

/* Below the field, not as a tooltip: a message that vanishes as soon as the mouse
   moves away is not a message. */
.tdm3-error {
    display: block;
    margin-top: var(--tdm3-space-1);
    color: var(--tdm3-color-danger);
    font-size: var(--tdm3-font-size-sm);
}


/* ============================================================================
   Tables. Kendo Grid is THE table of the application; this class is for the
   loose HTML tables (user info, styleguide, the tables in a help article) so
   they give the same picture. Hover gets the ordinary text color - never again
   white on a bright color.
   ========================================================================= */

.tdm3-table {
    width: 100%;
    border-collapse: collapse;
}

.tdm3-table th,
.tdm3-table td {
    padding: var(--tdm3-space-2) var(--tdm3-space-3);
    border-bottom: 1px solid var(--tdm3-table-border);
    text-align: left;
    vertical-align: top;
}

.tdm3-table th {
    background-color: var(--tdm3-table-header-bg);
    color: var(--tdm3-table-header-text);
    font-weight: var(--tdm3-font-weight-bold);
}

.tdm3-table tbody tr:nth-child(even) {
    background-color: var(--tdm3-table-row-alt);
}

.tdm3-table tbody tr:hover {
    background-color: var(--tdm3-table-row-hover);
    color: var(--tdm3-text);
}

/* Amounts and counts. Part of the table, not a standalone utility: this only
   came into being once three screens needed it. */
.tdm3-table .tdm3-table-numeric {
    text-align: right;
    font-variant-numeric: tabular-nums;
}


/* ============================================================================
   Badges. Always a tint background with dark text; white text on a status color
   makes the standard nowhere in this palette. The short state on the badge, the
   condition in `title` - the same wording as the dialog.
   ========================================================================= */

.tdm3-badge {
    display: inline-block;
    padding: var(--tdm3-space-1) var(--tdm3-space-2);
    border-radius: var(--tdm3-radius);
    font-size: var(--tdm3-font-size-sm);
    font-weight: var(--tdm3-font-weight-medium);
    line-height: var(--tdm3-line-height-tight);
    /* A pill never breaks internally: that would shift a grid's row height. */
    white-space: nowrap;
}

.tdm3-badge-success {
    background-color: var(--tdm3-color-success-bg);
    color: var(--tdm3-color-success);
}

.tdm3-badge-warning {
    background-color: var(--tdm3-color-warning-bg);
    color: var(--tdm3-color-warning);
}

.tdm3-badge-danger {
    background-color: var(--tdm3-color-danger-bg);
    color: var(--tdm3-color-danger);
}

.tdm3-badge-info {
    background-color: var(--tdm3-color-info-bg);
    color: var(--tdm3-navy);
}

.tdm3-badge-neutral {
    background-color: var(--tdm3-color-neutral-bg);
    color: var(--tdm3-color-neutral);
}


/* ============================================================================
   Cards — form blocks and the testdata screen. No cards in grid cells.
   ========================================================================= */

.tdm3-card {
    padding: var(--tdm3-space-4);
    border: 1px solid var(--tdm3-divider);
    border-radius: var(--tdm3-radius-lg);
    background-color: var(--tdm3-surface);
    box-shadow: var(--tdm3-shadow-sm);
}

.tdm3-card-title {
    margin: 0 0 var(--tdm3-space-2);
    color: var(--tdm3-color-heading);
    font-size: var(--tdm3-font-size-lg);
    font-weight: var(--tdm3-font-weight-bold);
}


/* ============================================================================
   Callouts — an explanation above a form, a warning above a screen. Not for
   validation errors: those stand at the field.
   ========================================================================= */

.tdm3-callout {
    padding: var(--tdm3-space-3) var(--tdm3-space-4);
    border-left: 3px solid var(--tdm3-blue);
    background-color: var(--tdm3-surface-muted);
    color: var(--tdm3-text);
}

.tdm3-callout-title {
    margin: 0 0 var(--tdm3-space-1);
    color: var(--tdm3-color-heading);
    font-weight: var(--tdm3-font-weight-bold);
}

.tdm3-callout p:last-child {
    margin-bottom: 0;
}

.tdm3-callout-info {
    border-left-color: var(--tdm3-color-info);
    background-color: var(--tdm3-color-info-bg);
}

.tdm3-callout-success {
    border-left-color: var(--tdm3-color-success);
    background-color: var(--tdm3-color-success-bg);
}

.tdm3-callout-success .tdm3-callout-title {
    color: var(--tdm3-color-success);
}

/* The warning splits color roles: --tdm3-orange for the border (3.06:1 reaches
   the non-text standard), --tdm3-orange-text for the heading (5.38:1 on the tint). One
   orange for both does not reach the standard. */
.tdm3-callout-warning {
    border-left-color: var(--tdm3-color-warning-accent);
    background-color: var(--tdm3-color-warning-bg);
}

.tdm3-callout-warning .tdm3-callout-title {
    color: var(--tdm3-color-warning);
}

.tdm3-callout-danger {
    border-left-color: var(--tdm3-color-danger);
    background-color: var(--tdm3-color-danger-bg);
}

.tdm3-callout-danger .tdm3-callout-title {
    color: var(--tdm3-color-danger);
}


/* ============================================================================
   Help entry — the help link on the pages without a top bar (Home/LinkExpired,
   Home/AccessDenied, InvoiceDownloadLink/Expired): one line under the message it
   helps with.
   ========================================================================= */

.tdm3-help-entry {
    margin: var(--tdm3-space-4) 0 0;
}


/* ============================================================================
   Status color on standalone content — an icon or a piece of text that itself
   carries the status, where a badge is too heavy: the little envelope that says
   whether feedback has come in, a struck-through amount, an expired date.

   These are the last Bootstrap color classes that were sitting in views
   (`text-danger`, `text-success`, `text-info`). They don't go away because they
   fail the standard — as non-text all three just reach the 3:1 (measured on
   white: #DC3545 4.53:1, #28A745 3.13:1, #17A2B8 3.05:1) — but because they don't
   come from tokens.css. The same trade-off as in migration step 8, where
   `alert-danger` (8.25:1) disappeared for exactly that reason.

   The token values sit higher: --tdm3-color-danger 6.48:1,
   --tdm3-color-success 6.62:1, --tdm3-color-info 6.94:1 on white. They sit on
   `currentColor` SVGs and on inline text, so color is the only thing they
   set - no size, no weight, no spacing.

   A utility and not a component, and that's allowed here: conventions.md permits
   one once three screens need it. Danger sits on four screens,
   success on four, info on two (the latter shares its files with the
   other two and would only be left behind as half a pair).
   Semantics and naming follow the badges; the class name carries the
   tdm3 prefix so Bootstrap's own `text-*` can never collide with it.
   ========================================================================= */

.tdm3-text-success {
    color: var(--tdm3-color-success);
}

.tdm3-text-danger {
    color: var(--tdm3-color-danger);
}

.tdm3-text-info {
    color: var(--tdm3-color-info);
}


/* ============================================================================
   Marked cell — a grid cell with a lane of its own on the right for a small
   mark about the value in it. One use today: the postal address that has
   been through bpost, in the Verzending column of the address screen and of
   the download screen.

   Muted, not a status colour. The icon leading that cell already carries a
   colour, and it says something else (on the address screen: whether an
   answer has come in). Two green ticks in one cell are two meanings on one
   sign; here the distinction is in the shape and in the place.

   There is no counterpart for "not checked". Absence is the signal: in this
   column red already means bounced / no answer, and components.md
   ("Neutraal, niet rood en niet geel") keeps the value the user came to
   correct out of the status colours.

   A lane of its own rather than simply trailing the text, and that is a
   measurement. The address runs over more than one line: at 1280x800 this
   cell is 134,66px wide. Inline behind the address, the mark dropped onto a
   third line by itself (mark at y 227,2, text lines at 186,2 and 207,2) and
   the marked cell became 63px tall against 42px unmarked - exactly what
   "grids hold still" forbids, because the row then jumps the moment bpost
   approves one address. With the lane the three rows measure the same: value
   83,7px wide and 63px tall, mark at the same x (566) in every row, marked
   or not. Inline in front of the address, beside the delivery icon, cost the
   same extra line.

   The class is on the empty variant too, with no icon inside it: the lane is
   there in both states, and that is what holds the column still. The same
   rule as the reserved slots in the dialogs — conventions.md.
   ========================================================================= */

.tdm3-marked-cell {
    display: flex;
    align-items: flex-start;
    gap: var(--tdm3-space-1);
}

/* The value takes what is left. `min-width: 0` because a flex item otherwise
   will not go below its min-content width: without this line a long address
   pushes the lane out of the cell instead of wrapping. */
.tdm3-marked-cell-value {
    flex: 1 1 auto;
    min-width: 0;
}

.tdm3-verified-mark {
    flex: 0 0 auto;
    width: var(--tdm3-space-3);
    color: var(--tdm3-text-muted);
}


/* ============================================================================
   Monospace — for references only: invoice numbers, markers, token names.
   Replaces the three copied `.text-monospace` in the views from step 6 onward.
   ========================================================================= */

.tdm3-mono {
    font-family: var(--tdm3-font-family-mono);
    font-variant-numeric: tabular-nums;
    /* A reference may break; it may not push a column open. Added in
       migration step 8, when the first long references got this class: a
       claim URI, an expired download URL, an access token.

       `anywhere` and not `break-word`, and that is a measurement: only `anywhere`
       counts toward the min-content width. With `break-word` the claim table's
       value column kept claiming its full 1097px and the column next to it shrank to
       130px, while 35% was declared for it.

       Why here and not in the markup: the views carried Bootstrap's `.text-break`,
       and that class DOES NOT EXIST in the 4.1.3 this application loads (measured:
       zero lines; it only arrived in 4.2). What let the long values break
       until this step was the `<code>` element itself, which in Bootstrap carries
       `word-break: break-word` - and that element is gone here because it colors #E83E8C.
       In a grid cell with `white-space: nowrap` this rule does nothing: with no
       line breaking, there's nothing to break. */
    overflow-wrap: anywhere;
}


/* ============================================================================
   Layout shell — the top bar and the footer. These sit on EVERY screen.

   The bar is a <header class="tdm3-topbar"> with four parts side by side: the
   wordmark (the way back to the home page), the tenant chip, the screens as a Kendo menu,
   and on the right the language switcher with the user. Why not everything in one Kendo
   menu, the way it was: the language switcher shows both languages side by side and is
   therefore not a menu item, and the wordmark is a link with no fly-out. Two of the four
   parts simply don't fit the widget.

   What the THEME already does and is therefore not repeated here (measured in the running app,
   not assumed): the menu font family and size (Aptos stack, 14px from $font-size), the
   submenus white with --tdm3-text, submenu hover --tdm3-table-row-hover with dark
   text, and submenu active white on --tdm3-color-primary. What the theme does NOT give and
   sits below: the navy bar, the items on it, the rail, the shadow under a
   submenu and a visible focus indicator.

   Why `.k-menu.tdm3-menu` and not `.tdm3-menu` alone: the theme rules target
   `.k-menu:not(.k-context-menu) > .k-item`, which weighs three classes. A
   single class of our own loses that on specificity, even though this file loads
   later. The doubled class makes it equal, after which source order decides -
   no !important needed.
   ========================================================================= */

/* The navy hangs off the <header>, and that's possible now that the bar carries more
   than just the <ul>. It used to hang off the <ul> because the five screens with
   ViewBag.HideNavMenu render none of it and so naturally kept a header of 0px; that
   property is still there, but now because _Layout renders a bare <header> without
   this class on those screens. Bare, not gone: HomeScreenTests looks for </header>
   to separate the screen from the bar. */
.tdm3-topbar {
    display: flex;
    /* Stretch is the flex default and therefore doesn't sit here to change anything; it
       sits here because the bar's height hangs off it, explained further down. */
    align-items: stretch;
    /* Wrap and not scroll: on a narrow screen the right-hand parts drop to a
       second line instead of disappearing below the edge. The bar then gets
       taller, which is the right answer on a phone - a menu you can't
       see is not a menu. */
    flex-wrap: wrap;
    background-color: var(--tdm3-topbar-bg);
    margin-bottom: var(--tdm3-space-4);
    padding: 0 var(--tdm3-space-4);
    font-size: var(--tdm3-font-size-base);
    /* The bar sits above the page, but below anything you open yourself: lighter than
       --tdm3-shadow, which a submenu carries below it. It doesn't separate here - 15.02:1
       against white already does that - but says it is chrome and not content, which is
       what the 16px of air underneath otherwise left open. See --tdm3-topbar-shadow for why
       this is not a step from the shared shadow scale. */
    box-shadow: var(--tdm3-topbar-shadow);
}

/* The wordmark. Used to be "TDM3 Portal" as a menu item with no link and no children:
   dead text shaped like navigation, for EVERY user. Now a link to
   the home page, and thereby the only answer the bar should have had to
   "take me back". */
.tdm3-brand {
    display: flex;
    align-items: center;
    height: var(--tdm3-topbar-height);
    padding-right: var(--tdm3-space-3);
    color: var(--tdm3-topbar-text-strong);
    font-weight: var(--tdm3-font-weight-bold);
    letter-spacing: 0.01em;
    white-space: nowrap;
    /* Bootstrap 5 underlines an `a` by default (`a { text-decoration: underline }`,
       bootstrap.css:351-354); 4 did not do that. The wordmark had therefore stood
       permanently underlined since P6 - measured `text-decoration-line: underline` at
       rest, while the rule below explicitly sets the underline on hover and focus and
       thereby says it only belongs THERE. Chrome, not a text link: here the underline goes. */
    text-decoration: none;
}

.tdm3-brand:hover,
.tdm3-brand:focus {
    color: var(--tdm3-topbar-text-strong);
    text-decoration: underline;
}

.tdm3-topbar-divider {
    width: 1px;
    margin: var(--tdm3-space-2) var(--tdm3-space-3) var(--tdm3-space-2) 0;
    background-color: var(--tdm3-topbar-divider);
}

/* The tenant. It used to sit as a bare word among the menu words, and for everyone
   except a TDM3 employee it was ALSO an item with no link and no children -
   the bar's second dead item. A chip is not a menu word: it says "this is
   where you are", not "you can go here". Whoever CAN switch gets the same
   thing with an arrow, as an item of its own small Kendo menu. */
.tdm3-tenant-chip,
.tdm3-topbar .k-menu.tdm3-tenant-menu > .k-item > .k-link {
    display: inline-flex;
    align-items: center;
    gap: var(--tdm3-space-1);
    /* 24px tall and 10px of side margin: the size of a chip in a 40px bar, not a
       step of the 4px scale. --tdm3-space-2 (8) leaves the tenant name pressed against the
       pill shape, --tdm3-space-3 (12) makes the chip wider than the menu word
       next to it. Named exception; see the spacing guard. */
    height: 24px;
    padding: 0 10px;
    border: 1px solid var(--tdm3-topbar-chip-border);
    border-radius: var(--tdm3-radius-pill);
    color: var(--tdm3-topbar-current);
    font-size: var(--tdm3-font-size-sm);
    font-weight: var(--tdm3-font-weight-bold);
    white-space: nowrap;
}

.tdm3-tenant-chip {
    align-self: center;
}

/* `transparent` carries weight here and is not clean-up: the theme itself gives the <ul>
   `background-color: #f5f5f5` (`.k-menu:not(.k-context-menu)`). On the ITEMS the
   theme only sets a color and no surface - so there's nothing to override there. */
.tdm3-topbar .k-menu.tdm3-tenant-menu {
    align-self: center;
    background-color: transparent;
}

.tdm3-topbar .k-menu.tdm3-tenant-menu > .k-item:hover > .k-link,
.tdm3-topbar .k-menu.tdm3-tenant-menu > .k-item.k-hover > .k-link,
.tdm3-topbar .k-menu.tdm3-tenant-menu > .k-item.tdm3-is-hover > .k-link {
    background-color: var(--tdm3-topbar-chip-hover);
    color: var(--tdm3-topbar-current);
}

/* The menu's own spacing. The theme puts `padding-block` on a horizontal
   menu - 2026 does that with `.k-menu.k-menu-horizontal:not(.k-context-menu) {
   padding-block: var(--kendo-spacing-2) }` - and that makes the bar 14px taller than the
   40px --tdm3-topbar-height agrees on. Measured before this rule: 54px, with the
   stations sitting away from the words below them.

   Until P4 this sat as $navbar-padding-y/x in the theme source, exactly because an
   override back then RACED the class: `k-menu-horizontal` gets added by Kendo's JS,
   so the bar was 40px on first paint and then jumped. That
   argument no longer applies here, and that's the whole point of this spot: the rule
   hangs off the SAME class as the theme rule, so they become active at the same moment
   and there's nothing to race. There is also no variable for this in 2026 -
   `--kendo-spacing-2` carries half the theme and is therefore not a dial you may
   remap for a single widget.

   `.tdm3-topbar` in front of it weighs one class more than the theme rule and moreover
   bounds it to the bar; a menu elsewhere in the application keeps its theme spacing. */
.tdm3-topbar .k-menu.k-menu-horizontal:not(.k-context-menu) {
    padding-block: 0;
}

/* THE MENU BEFORE KENDO REACHES IT. The wrapper renders the full Kendo markup server-side -
   `k-menu`, `k-item`, `k-link` and a `<ul class="k-menu-group">` per fly-out - and the theme gives
   `.k-menu-group` `display: flex; position: absolute`. Nothing hides those groups until
   `kendo.syncReady` runs `kendoMenu({})` on document-ready, so between the first paint and that
   moment the bar carries five open fly-outs.

   Measured on a harness-rendered invoice screen with the scripts stripped, which freezes the
   pre-init state: 5 of 5 groups visible, the first 141 x 84 px at y 80. After init: 0 of 5, each
   moved into a `.k-menu-popup`. The bar measures 160px either way - the groups are absolutely
   positioned, so this is paint and not layout, and that is why CLS reads 0,00 while the flash is
   plainly visible.

   `k-menu-horizontal` is the marker: the wrapper does not render it, Kendo's JS adds it. The rule
   therefore stops applying at the moment the widget exists, which is the same moment the popups
   take over hiding the groups. */
.tdm3-topbar .k-menu:not(.k-menu-horizontal) .k-menu-group {
    display: none;
}

/* The screens themselves. The menu no longer carries a surface of its own - that's the bar.

   `min-width: 0` IS needed, though, and it's the only rule that saves the narrow
   bar: the theme already gives `.k-menu` `display: flex; flex-wrap: wrap`, but a
   flex item does not shrink below its min-content width as long as `min-width` sits at
   `auto`, so the <ul> kept claiming its full content width and ran off the
   viewport - measured at 380px, with "Backend" half cut off and a
   horizontal scrollbar across the WHOLE page. No `overflow-x: auto`, because
   scrolling would clip the fly-out: Kendo keeps the <ul class="k-menu-group">
   inside its own <li>.

   This is the floor and not the answer: truly small screens call for a
   collapsed menu, and that's a decision of its own. */
.tdm3-topbar .k-menu.tdm3-menu {
    margin-bottom: 0;
    margin-left: var(--tdm3-space-3);
    background-color: transparent;
    min-width: 0;
}

.tdm3-topbar .k-menu.tdm3-menu > .k-item {
    position: relative;
}

.tdm3-topbar .k-menu.tdm3-menu > .k-item > .k-link {
    display: flex;
    align-items: center;
    height: var(--tdm3-topbar-height);
    /* Space at the bottom for the station; the text therefore shifts 3px up
       relative to the bar's middle. Deliberate: the dot should sit below the
       word and not beside it.

       6px is not a step and that's worked out, not chosen: the dot is
       --tdm3-station-size (7px) and sits with its bottom edge at 5px, so there has to
       be exactly enough room under the text line to carry it without making the
       bar taller than --tdm3-topbar-height. 4px clips the dot, 8px
       throws the text off balance. Named exception; see the spacing guard. */
    padding: 0 var(--tdm3-space-3) 6px;
    color: var(--tdm3-topbar-text);
}

/* ---- Stations on a rail -----------------------------------------------------
   The same figure as in .tdm3-vnav (components.md, "Stations on a rail"),
   now horizontal: a thin line under the items, with an open dot on every screen
   and a filled dot on the screen you're on.

   Why this and not the filled surface the bar used to have: that surface is
   --tdm3-color-primary on --tdm3-navy and reaches 2.16:1 - measured, and below the 3:1
   WCAG 1.4.11 asks for a state boundary. It therefore barely stood out, and
   it only ever marked hover anyway: `HighlightPath(true)` was on but never set a
   `k-state-active` on any screen, because the two feedback items carry a
   query string the bare screen URL never matches. The bar therefore literally
   never said where you were. Now the layout decides that itself, from the request's
   controller, and sets `tdm3-menu-current` on the item.

   The rail is decoration (2.01:1) and the dot carries the meaning: open 3.08:1,
   filled 6.68:1. Color doesn't carry it alone - the current item is also bold
   and full white, and carries aria-current. */
/* The rail is drawn per item and not as one line under the whole <ul>, and that
   is the same construction as in .tdm3-vnav: the first item begins its stretch at the
   dot and the last one ends there. One continuous line ran from the edge of the
   first word to past the last one and stopped there in mid-air - a rail that
   doesn't begin or end at a station. A side effect that turns out correct: a user with
   only one section (a group sees only Feedback requests) gets 50% on both left
   and right, so no line - one station is not a route. */
.tdm3-topbar .k-menu.tdm3-menu > .k-item::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 8px;
    height: 1px;
    background-color: var(--tdm3-topbar-rail);
}

.tdm3-topbar .k-menu.tdm3-menu > .k-item:first-child::before {
    left: 50%;
}

.tdm3-topbar .k-menu.tdm3-menu > .k-item:last-child::before {
    right: 50%;
}

.tdm3-topbar .k-menu.tdm3-menu > .k-item::after {
    content: "";
    position: absolute;
    left: 50%;
    bottom: 5px;
    width: var(--tdm3-station-size);
    height: var(--tdm3-station-size);
    /* Half of --tdm3-station-size (7px), so the dot sits on the middle of the
       item and not beside it. Not a step, and by definition not one: it is a
       half dot. Named exception; see the spacing guard. */
    margin-left: -3.5px;
    border: var(--tdm3-station-ring) solid var(--tdm3-topbar-station);
    border-radius: 50%;
    background-color: var(--tdm3-topbar-bg);
}

/* Pointing opens the station instead of putting a surface behind it. The
   text moves along to full white, so the pointer state doesn't live in 7px alone.

   Only a color, no `background-color: transparent` next to it: the theme sets
   only `color` on a top-level item (checked in the compiled artifact -
   `.k-menu:not(.k-context-menu)>.k-item:hover` and the `.k-state-active` variant
   carry no surface). The surface removed here was one from this project
   itself, and that already disappeared in this change.

   `.tdm3-is-hover` sits here for the same reason as with the buttons at the top of this
   file: the styleguide must be able to show a pointed-at station without a mouse
   actually resting on it. It's not behavior - nothing outside that page sets the class. */
.tdm3-topbar .k-menu.tdm3-menu > .k-item:hover > .k-link,
.tdm3-topbar .k-menu.tdm3-menu > .k-item.k-hover > .k-link,
.tdm3-topbar .k-menu.tdm3-menu > .k-item.tdm3-is-hover > .k-link,
.tdm3-topbar .k-menu.tdm3-menu > .k-item > .k-link.k-active {
    color: var(--tdm3-topbar-text-strong);
}

.tdm3-topbar .k-menu.tdm3-menu > .k-item:hover::after,
.tdm3-topbar .k-menu.tdm3-menu > .k-item.k-hover::after,
.tdm3-topbar .k-menu.tdm3-menu > .k-item.tdm3-is-hover::after {
    border-color: var(--tdm3-topbar-text-strong);
}

.tdm3-topbar .k-menu.tdm3-menu > .k-item.tdm3-menu-current > .k-link {
    color: var(--tdm3-topbar-text-strong);
    font-weight: var(--tdm3-font-weight-bold);
}

.tdm3-topbar .k-menu.tdm3-menu > .k-item.tdm3-menu-current::after {
    border-color: var(--tdm3-topbar-current);
    background-color: var(--tdm3-topbar-current);
}

/* The current station also responds to pointing. Same cause as with the
   language switcher: the two rules above (:hover and .tdm3-menu-current) both
   weigh (0,5,1) and .tdm3-menu-current sits later, so the filled dot took over the
   hover rule - measured, NOTHING changed on the current item under the mouse, while
   another item goes from #DDE1E4 to white and carries its dot border along.

   Only the DOT, because the label can't: `tdm3-menu-current` already sits at
   --tdm3-topbar-text-strong, exactly the color hover moves to, so there is
   literally nothing left to change there. The dot stays filled - the fill says "you are
   here" - and gets a white ring around it, the same white border another
   station gets when pointed at. That way hover speaks the same language in both cases and
   the location marker stays intact. White on --tdm3-navy is 15.02:1. */
.tdm3-topbar .k-menu.tdm3-menu > .k-item.tdm3-menu-current:hover::after,
.tdm3-topbar .k-menu.tdm3-menu > .k-item.tdm3-menu-current.k-hover::after,
.tdm3-topbar .k-menu.tdm3-menu > .k-item.tdm3-menu-current.tdm3-is-hover::after {
    border-color: var(--tdm3-topbar-text-strong);
}

/* ---- Right: language and user ---------------------------------------------- */
.tdm3-topbar-end {
    display: flex;
    align-items: center;
    gap: var(--tdm3-space-3);
    /* Replaces the `float: right` that sat on the user item and did nothing:
       the menu is a flexbox and float is inert inside one - measured, the item
       used to sit right next to Backend, at x=592 of a 1235px bar. */
    margin-left: auto;
}

/* Both languages side by side, and the current one is the filled half. It used to be
   a fly-out menu with the CURRENT language as the button and the other underneath: two
   clicks, and the button said what you already had instead of what you could get. */
.tdm3-lang {
    display: inline-flex;
    /* Does not shrink along, and that's not precaution but a fix: `overflow: hidden`
       below - needed to keep the two halves inside the radius - sets `min-width`
       to 0, and that lets the flexbox shrink the switcher down to nothing. Measured in
       a tight bar: a box of 30px with 64px of content, in which FR simply
       dropped out. A language switcher that shows one language is exactly what had to
       go here. */
    flex: none;
    height: 24px;
    border: 1px solid var(--tdm3-topbar-station);
    border-radius: var(--tdm3-radius);
    overflow: hidden;
}

.tdm3-lang a {
    display: flex;
    align-items: center;
    /* 9px: the two halves NL and FR together have to fit in a switcher that still
       leaves room next to the user chip, and the box is 24px tall with a 1px border. At
       --tdm3-space-2 (8) the two labels nearly touch, at --tdm3-space-3 (12)
       the switcher becomes wider than the tenant chip next to it. Named exception;
       see the spacing guard. */
    padding: 0 9px;
    color: var(--tdm3-topbar-text);
    font-size: var(--tdm3-font-size-sm);
    font-weight: var(--tdm3-font-weight-medium);
    /* The same Bootstrap 5 underline as on the wordmark, and here it stood on its head:
       the two halves were underlined AT REST (measured `underline`) and the rule
       below actually removed the underline on hover. A switcher made of two half
       surfaces is chrome - the shape already says you can click it. */
    text-decoration: none;
}

.tdm3-lang a:hover,
.tdm3-lang a:focus {
    background-color: var(--tdm3-topbar-hover);
    color: var(--tdm3-topbar-text-strong);
    text-decoration: none;
}

.tdm3-lang a[aria-current="true"] {
    background-color: var(--tdm3-topbar-text-strong);
    color: var(--tdm3-navy);
    font-weight: var(--tdm3-font-weight-bold);
}

/* The CURRENT half also responds, and that's a fix and not a flourish. The
   rule above and `.tdm3-lang a:hover` weigh (0,2,1) and
   (0,2,0)+pseudo respectively - equal weight - and this one sits later, so the filled
   half took over the hover rule: measured, ZERO changed under the mouse in color, background,
   border and underline, while the other half went #DDE1E4 -> white and transparent ->
   rgb(38,62,84). The focus ring DOES fire there (portal.css, the rings rule), so
   the keyboard got a response and the mouse didn't - that's not a choice.

   A half-step back from white and not toward navy: the half is filled because you
   ARE there, and pointing at it must not undo that. --tdm3-topbar-text (#DDE1E4)
   is the color the other half carries at rest, so no sixth grey is introduced;
   navy text reaches 12.11:1 on it. */
.tdm3-lang a[aria-current="true"]:hover {
    background-color: var(--tdm3-topbar-text);
}

/* Help, left of the language switch. A word in the bar like the menu items, so it
   takes their text color and size; it opens a page and chooses nothing, so it has
   no frame like the switch beside it. Hover and focus are the switch's own:
   --tdm3-topbar-hover under --tdm3-topbar-text-strong, and the two rings of the
   focus rule below. On the help page itself it carries aria-current and the strong
   text color, the same white the current language half is filled with. */
.tdm3-topbar-help {
    display: flex;
    flex: none;
    align-items: center;
    padding: var(--tdm3-space-1) var(--tdm3-space-2);
    border-radius: var(--tdm3-radius);
    color: var(--tdm3-topbar-text);
    font-size: var(--tdm3-font-size-sm);
    font-weight: var(--tdm3-font-weight-medium);
    text-decoration: none;
}

.tdm3-topbar-help:hover,
.tdm3-topbar-help:focus {
    background-color: var(--tdm3-topbar-hover);
    color: var(--tdm3-topbar-text-strong);
    text-decoration: none;
}

.tdm3-topbar-help[aria-current="page"] {
    color: var(--tdm3-topbar-text-strong);
}

.tdm3-topbar .k-menu.tdm3-user-menu {
    background-color: transparent;
}

.tdm3-topbar .k-menu.tdm3-user-menu > .k-item > .k-link {
    display: flex;
    align-items: center;
    gap: var(--tdm3-space-2);
    height: var(--tdm3-topbar-height);
    padding: 0 var(--tdm3-space-2);
    color: var(--tdm3-topbar-text);
}

/* The 8px above has sat on the wrong seam since Kendo 2026, and this rule puts it
   back where it belonged. The theme now wraps a menu item's content in a
   `<span class="k-menu-link-text">`, so the link's direct children are that block
   plus the arrow - and the link's gap lands between those. The initials and the name have
   since been SIBLINGS INSIDE the wrapper, which sits at `display: flex` with `gap: normal`.
   Measured: circle right 1113.3 == name left 1113.3, so 0px - the initials circle stuck
   to the email address, while there was 8px between the text and the arrow.

   The gap sits here and not as `margin-inline-end` on `.tdm3-avatar`: that class comes from
   Olympos.Portal.Web/Util/UserChip.cs and is also shown standalone in the styleguide, where a
   margin has no business being. The seam between two things belongs to the box that places them
   next to each other.

   `align-items: center` added because the wrapper sat at `normal` (= stretch): the circle
   has its own height of 24px and didn't care, but the name next to it stretched
   along. Measured, it changes nothing about today's geometry (0px on x, y and height for
   both) - it only states what already happens, so that with a second line of text it doesn't
   still throw itself off balance. The 8px between the text and the arrow stays exactly 8px. */
.tdm3-topbar .k-menu.tdm3-user-menu > .k-item > .k-link > .k-menu-link-text {
    align-items: center;
    gap: var(--tdm3-space-2);
}

.tdm3-topbar .k-menu.tdm3-user-menu > .k-item:hover > .k-link,
.tdm3-topbar .k-menu.tdm3-user-menu > .k-item.k-hover > .k-link {
    background-color: var(--tdm3-topbar-hover);
    color: var(--tdm3-topbar-text-strong);
}

/* The initials. Not an ornament: they keep the name away from the screen edge and
   give the item a grab handle that doesn't shift with the length of an
   email address. */
.tdm3-avatar {
    display: flex;
    align-items: center;
    justify-content: center;
    /* The circle sits in a flex row, so `flex-basis` decides the width, not
       `width`. Just the flex property, then - two sizes claiming the same thing
       leave the reader guessing which one wins. */
    flex: 0 0 24px;
    height: 24px;
    border-radius: 50%;
    background-color: var(--tdm3-topbar-avatar-bg);
    color: var(--tdm3-topbar-text-strong);
    font-size: var(--tdm3-font-size-sm);
    font-weight: var(--tdm3-font-weight-bold);
}

/* Below 720px, the name is the first thing allowed to give way: the initials already say who
   you are and the fly-out menu stays reachable. */
@media (max-width: 720px) {
    .tdm3-user-name {
        display: none;
    }
}

/* Below 480px the menu already sits on its own line anyway, so the indent that
   separates it from the wordmark no longer has anything to separate there - and it was
   exactly what pushed the longest label out. Measured on a 360px bar: 6px overflowing the <ul>
   with the margin, 0px without. The space between the items shrinks along, from 12 to 8. */
@media (max-width: 480px) {
    .tdm3-topbar .k-menu.tdm3-menu {
        margin-left: 0;
    }

    .tdm3-topbar .k-menu.tdm3-menu > .k-item > .k-link {
        padding-left: var(--tdm3-space-2);
        padding-right: var(--tdm3-space-2);
    }
}

/* Keyboard focus. The menu is one tab stop: the <ul> carries tabindex="0" and
   Kendo does not move DOM focus, but marks the current item with the class
   `k-state-focused`. A rule on `:focus` alone - what the theme does - therefore
   never comes into play, and what the theme draws (inset 0 0 0 3px
   rgba(33,37,41,.15)) would be invisible on navy anyway.

   Two rings, not one: --tdm3-color-focus (accent blue) only reaches 2.16:1
   against navy and therefore not the 3:1 for non-text. The white inner ring separates it from
   the bar (15.02:1 against navy) and the accent-blue ring sits against that.
   Logo blue doesn't come into it: in this bar it's the color of "you are here",
   and focus is not the same as location. */
.k-menu.tdm3-menu > .k-item:focus,
.k-menu.tdm3-menu > .k-item.k-focus,
.k-menu.tdm3-tenant-menu > .k-item:focus,
.k-menu.tdm3-tenant-menu > .k-item.k-focus,
.k-menu.tdm3-user-menu > .k-item:focus,
.k-menu.tdm3-user-menu > .k-item.k-focus,
.tdm3-brand:focus,
.tdm3-lang a:focus,
.tdm3-topbar-help:focus {
    box-shadow: inset 0 0 0 2px var(--tdm3-color-primary-contrast),
                inset 0 0 0 4px var(--tdm3-color-focus);
}

/* The submenu DOES sit on white, so the single accent-blue ring is enough there -
   the same ring .tdm3-btn and .tdm3-input carry. */
.tdm3-menu .k-menu-group .k-item:focus,
.tdm3-menu .k-menu-group .k-item.k-focus,
.tdm3-tenant-menu .k-menu-group .k-item:focus,
.tdm3-tenant-menu .k-menu-group .k-item.k-focus,
.tdm3-user-menu .k-menu-group .k-item:focus,
.tdm3-user-menu .k-menu-group .k-item.k-focus {
    box-shadow: inset 0 0 0 2px var(--tdm3-color-focus);
}

/* A submenu is a layer above the page and should show that; the theme
   gives it the white background but no shadow. */
.tdm3-menu .k-menu-group,
.tdm3-tenant-menu .k-menu-group,
.tdm3-user-menu .k-menu-group {
    box-shadow: var(--tdm3-shadow);
}

/* ============================================================================
   The vnav side nav (bundle overview). The design is that of the branch —
   section headers in caps, counters trailing the label, one active item; only
   the location and the colors change (components.md, "Navigation").

   Sat as a <style> block in InvoiceDownloadLink/Index.cshtml until this step,
   where it applied to the whole page for as long as it was open. The markup itself sits
   in _Layout (the <nav> wrapper) AND in that view (the <ul>), so the block belonged
   in neither of the two anyway.

   The class name `.sidebar` has become `.tdm3-vnav`. What sits underneath keeps
   its name: `.nav`/`.nav-item`/`.nav-link` are Bootstrap classes that still
   supply their base, and `filter-link`, `filter-count`,
   `filter-link-has-results` and `active` are read by the screen's filter
   scripts (`$(".filter-link")`, `toggleClass("filter-link-has-results")`,
   `addClass("active")`). Renaming them would affect behavior there; that's not what this
   step does.

   Two colors were not just remapped but corrected, both
   contrast violations (accessibility.md):
   - the section header sat at #ADB5BD: 2.29:1 on white, in 9.8px bold caps;
   - the counter sat at #6C757D at 0.8em (9.8px), while muted per
     accessibility.md may only be used on white and never smaller than 12px.
   Both now carry --tdm3-text-subtle (8.18:1), which lets the size stay
   as it was. Muted no longer appears in this side nav.
   ========================================================================= */

/* Since post-processing C the side nav sits on a surface of its own. It used to float on white:
   the same background as the grid next to it, so nothing said where the navigation
   ended and the work surface began. A SURFACE was chosen over a
   right-hand divider line, and that's a deliberate choice: a line draws a
   boundary but gives the column no floor of its own, and it's precisely the floor that makes
   the filter list read as a panel. The surface is --tdm3-surface-muted, the same
   step as a button's rest surface, so no sixth grey is added.

   The sizing that goes with it: 8px of air top and bottom (the sides already get
   Bootstrap's column padding) and --tdm3-radius, so the panel reads as a shape
   and not as a lane that got colored by accident.

   What this means for the colors, measured: the text now sits on #F5F5F5 instead
   of on white - --tdm3-text-subtle 8.18 -> 7.50:1, the active --tdm3-color-link
   on its own tint 5.49:1, both well above 4.5. */
.tdm3-vnav {
    padding-top: var(--tdm3-space-2);
    padding-bottom: var(--tdm3-space-2);
    border-radius: var(--tdm3-radius);
    background-color: var(--tdm3-surface-muted);
}

.tdm3-vnav .nav-link {
    /* Was 0.3rem 0.75rem (4.2 / 10.5px); rounded onto the 4px scale. */
    padding: var(--tdm3-space-1) var(--tdm3-space-3);
    border-radius: var(--tdm3-radius);
    color: var(--tdm3-text-subtle);
    font-size: var(--tdm3-font-size-sm);
    /* Label left, counter right (post-processing C). The counter trailed the
       label, so it stood in a different place on every line and there was no
       column to read. The label is a text node and the counter a <span>: in a
       flex container those are two items, and space-between pushes them apart.
       `baseline` and not `center`, because the counter is 0.8em - on center it
       would optically creep upwards. The `gap` is the floor for when a long label
       approaches the counter. */
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--tdm3-space-2);
}

.tdm3-vnav .nav-link:hover:not(.active):not([aria-current="page"]) {
    /* Was --tdm3-surface-muted, and since this step that is the color of the
       panel itself: pointing at an item then did nothing any more. Now the shared
       hover surface, the same one a grid row and a submenu item get (CIEDE2000
       4.46 against the panel). */
    background-color: var(--tdm3-surface-hover);
    color: var(--tdm3-text);
}

.tdm3-vnav .filter-count {
    color: var(--tdm3-text-subtle);
    font-size: 0.8em;
}

/* The section header is itself a filter (the total of the group below it), hence
   the link inside it that fully imitates its wrapper. 0.7rem stays a literal
   size: below --tdm3-font-size-sm (12px) the scale has no step, and the header
   should be smaller than the items it groups.

   The padding sat on this <li> and has moved to the link below it. The reason:
   the section header is a filter, so it can be ACTIVE, and the active surface
   plus the 3px bar hang off the link. With the padding on the <li> the link was
   24px narrower than the line and its bar started 12px inwards, while the bar of
   "Alles tonen" - the other item without track indentation - sits at the edge of
   the panel. Measured after the move: the label stays at x 22.5 / y 98 (0px
   shift) and the counter stays in the same column, because the content box is
   165.83px before and after; only the LINK BOX itself now runs from 10.5 to
   200.33 instead of from 22.5 to 188.33. */
.tdm3-vnav .nav-section-header {
    color: var(--tdm3-text-subtle);
    font-size: 0.7rem;
    font-weight: var(--tdm3-font-weight-bold);
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

/* `flex` and no longer `inline`: the section header is itself a filter with a
   counter of its own, and that belongs in the same column as the counters below
   it (post-processing C). With this it fills the line, which it did not do as an
   inline link - and that is what carries the counter to the right. */
.tdm3-vnav .nav-section-header .section-filter-link {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--tdm3-space-2);
    /* Taken over from the <li> above - see there for why. Literally the same
       three values, so the header stands where it stood. The radius goes 0 ->
       --tdm3-radius for the same reason: it is only visible when there is a
       surface behind it, and from now on that is the active state, which should
       round the same way an ordinary item does. */
    padding: var(--tdm3-space-2) var(--tdm3-space-3) var(--tdm3-space-1);
    border-radius: var(--tdm3-radius);
    color: inherit;
    font-size: inherit;
    font-weight: inherit;
    letter-spacing: inherit;
    text-transform: inherit;
    /* The same Bootstrap 5 underline as on the wordmark in the bar. The items
       UNDER this header escape it by carrying `.nav-link`, which Bootstrap itself
       puts at `text-decoration: none` (bootstrap.css:3811-3821); the section
       header does not carry that class and was therefore the only line of the
       sidebar standing underlined - measured `underline` at rest beside `none` on
       the items below it. The hover rule below sets the underline explicitly, so
       here too it was meant as a hover signal. */
    text-decoration: none;
}

/* Darker on hover, not lighter. It went from #ADB5BD to #6C757D — one step
   darker from a grey that was too light; from --tdm3-text-subtle, --tdm3-text is
   the next step in the same direction.

   `:not(.active)` for the same reason as on .nav-link above: `background: none`
   would take the active surface away under the mouse, and that surface says
   WHERE YOU ARE. */
.tdm3-vnav .nav-section-header .section-filter-link:hover:not(.active) {
    background: none;
    color: var(--tdm3-text);
    text-decoration: underline;
}

/* A section header that is not a filter: the help page groups its topics under
   headers that do nothing when clicked, so there is no link inside. The same
   padding as the filter link above, so a header stands in the same place on both
   screens. */
.tdm3-vnav .nav-section-header .nav-section-label {
    display: block;
    padding: var(--tdm3-space-2) var(--tdm3-space-3) var(--tdm3-space-1);
}

/* ---- The two states the filter script writes --------------------------------
   ON `.filter-link` AND NOT ON `.nav-link`, and that is the whole repair. The
   screen's script does `$(".filter-link").removeClass("active")` /
   `$(this).addClass("active")` (InvoiceDownloadLink/Index.cshtml:713-714) and
   `toggleClass("filter-link-has-results")` on `$(".filter-link[data-count-key]")`
   (:701-705). Those are TEN elements; eight of them also carry `.nav-link`, the two
   section headers do not (`class="filter-link section-filter-link"`,
   Index.cshtml:61,89). Keyed on `.nav-link` these rules therefore reached eight of
   the ten, and measured on an active section header there stood
   `background-color: rgba(0,0,0,0)` and `box-shadow: none` - identical to the rest
   state, beside `rgb(213,232,240)` plus the bar on an ordinary item. Clicking
   "Actie ondernomen" filtered the grid and the sidebar said nothing.
   `.filter-link` is the class the script itself points at, so this is the selector
   that cannot drift apart again.

   AFTER the section-header rules above and not before: those set `color: inherit`
   and `font-weight: inherit` to let the link imitate its wrapper, and that is a
   RESET. A state should beat a reset; on equal specificity (0,3,0) only source
   order does that. Placed before them, the active section header stayed grey.
   --------------------------------------------------------------------------- */

/* Active: --tdm3-color-link on --tdm3-color-info-bg, as components.md prescribes
   — was #007BFF on #E8F0FE, Bootstrap blue on a tint of ours.

   Since post-processing C with an accent bar on the left. The surface alone had
   become too little distinction now that a hovered item beside it can carry a
   blueish tint too (4.39 apart); the bar is a second, non-color signal. As an
   `inset box-shadow` and not as a `border-left`: a 3px border would push the
   label 3px sideways and then every item jumps the moment it becomes active.
   Measured: 0px shift. The bar is --tdm3-color-primary on the tint, 5.49:1 and
   therefore above the 3:1 for non-text.

   The second selector is the help page's topic list. Its links are pages, not
   filters, and no script marks them: the open topic carries aria-current="page"
   from the server, and that attribute is what this rule reads, so the state a
   screen reader hears and the state on screen are one. The hover rule above
   leaves it alone for the same reason it leaves `.active` alone. */
.tdm3-vnav .filter-link.active,
.tdm3-vnav .nav-link[aria-current="page"] {
    background-color: var(--tdm3-color-info-bg);
    color: var(--tdm3-color-link);
    font-weight: var(--tdm3-font-weight-bold);
    box-shadow: inset 3px 0 0 0 var(--tdm3-color-primary);
}

/* A filter with results weighs more than an empty one. The script sets this class
   from the count FilterCounts returns. On the section headers it changes nothing
   visible - those already sit at --tdm3-font-weight-bold - but it should reach
   them, otherwise the rule is once again where the script is not. */
.tdm3-vnav .filter-link.filter-link-has-results {
    font-weight: var(--tdm3-font-weight-bold);
}

/* -------------------------------------------------------------------------
   Stations aan een spoor.

   The filters of the bundle overview are not a classification but a life cycle.
   That is already in that screen's filter definitions: "opvolging nodig" is
   literally an escalation ladder (not visited -> reminder -> expired) and the
   three steps exclude each other; "actie ondernomen" runs the same way from
   visited to fully collected. Both sequences add up to their section header.
   One bundle moves from stop to stop until it ends somewhere.

   Nine equivalent lines said nothing about that. The track says it, and it
   stops where the case stops: at --nav-step-end the line ends at the dot
   instead of running on to the next line.

   The same vocabulary as the Verloop timeline of the collection screen
   (`.feedback-history` in screens.css): a hairline with dots on it, the dot
   anchored on the first line of the label. What differs here is the dot's
   border: Verloop's lies on white, this one on --tdm3-surface-muted, where
   --tdm3-border reaches 1.47:1. The dot CARRIES meaning here (open = under way,
   closed = end stop), so it falls under WCAG 1.4.11's 3:1 and gets
   --tdm3-border-strong: 4.30:1. The track itself is decoration - it groups what
   the section header already names - and may stay on --tdm3-border.
   ------------------------------------------------------------------------- */
.tdm3-vnav .nav-step {
    position: relative;
    /* Room for the line and the dot. The label shifts 16px; the counters stay
       in their own column, because that hangs off the right-hand side. */
    padding-left: var(--tdm3-space-4);
    /* The centre of the FIRST text line: the item's padding plus half a line.
       As a variable, because the track of an end stop has to stop at exactly the
       same height as where the dot sits. */
    --tdm3-vnav-step-dot-y: calc(var(--tdm3-space-1) + 0.75em);
}

/* The track. At the first stop of a sequence it runs on upwards, to just below
   the section header: that is where the sequence begins. No separate class for
   that first stop is needed - the segment simply runs from the top edge of the
   item, and above the first item stands the header. */
.tdm3-vnav .nav-step::before {
    content: "";
    position: absolute;
    left: var(--tdm3-space-2);
    top: 0;
    bottom: 0;
    width: 1px;
    background-color: var(--tdm3-border);
}

/* End stop: the line stops at the dot. */
.tdm3-vnav .nav-step-end::before {
    bottom: auto;
    height: var(--tdm3-vnav-step-dot-y);
}

/* The dot. Anchored on the first line and not in the middle of the item: a
   label breaking over two lines (French does that sooner than Dutch) would
   otherwise take the dot down with it, away from the line it belongs to. */
.tdm3-vnav .nav-step::after {
    content: "";
    position: absolute;
    left: calc(var(--tdm3-space-2) - 3px);
    top: var(--tdm3-vnav-step-dot-y);
    /* Half a dot upwards, so that its CENTRE lies on --tdm3-vnav-step-dot-y.
       --tdm3-station-size is 7px, so half is 3.5; rounded to 4 because the dot
       carries a 1px border and at 3.5 was rendered subpixel - measured, the dot
       then came out a hair above the text line. A named exception; see the
       spacing guard. */
    margin-top: -4px;
    width: var(--tdm3-station-size);
    height: var(--tdm3-station-size);
    border-radius: 50%;
    background-color: var(--tdm3-surface);
    border: var(--tdm3-station-ring) solid var(--tdm3-border-strong);
}

/* The two end stops carry their outcome: collected in full, or expired without
   anyone looking. Closed instead of open, so the shape says it without the color
   too - the label says it anyway, and with that nothing leans on color alone
   (WCAG 1.4.1). Measured on --tdm3-surface-muted: 6.08:1 and 5.94:1. */
.tdm3-vnav .nav-step-end-success::after {
    background-color: var(--tdm3-color-success);
    border-color: var(--tdm3-color-success);
}

.tdm3-vnav .nav-step-end-danger::after {
    background-color: var(--tdm3-color-danger);
    border-color: var(--tdm3-color-danger);
}


/* The footer. --tdm3-text-muted may sit on white and not smaller than
   --tdm3-font-size-sm (accessibility.md); both hold here. A surface in
   --tdm3-surface-muted underneath would push that 4.69:1 down to 4.23:1 and is
   therefore not there.

   The classes `border-top` and `text-muted` were taken out of the markup in this
   step: they are Bootstrap utilities that set their value with !important
   (#dee2e6 and #6c757d), and a token does not win from that. Without those
   classes this rule draws the border. */
.footer {
    border-top: 1px solid var(--tdm3-divider);
    color: var(--tdm3-text-muted);
    font-size: var(--tdm3-font-size-sm);
}


/* ============================================================================
   Kendo overrides — what the theme cannot express in variables.
   ========================================================================= */

/* ---------------------------------------------------------------------------
   Grids — the table vocabulary of the application (components.md, "Tabellen en
   grids").

   First measured what the theme already supplies, then added only what was
   missing. The swatch already delivers: cell padding, borders and
   `.k-grid td { vertical-align: middle }` — the last of which also stood as a
   copy in the <style> block of Views/Invoice/Index.cshtml and was removed there
   without replacement, because the theme already said it.

   What the theme does NOT give and stands below:
   - the HEADER BAR in the brand tint. Until P4 that came from $grid-header-bg /
     $grid-header-text in the theme source; 2026 no longer knows those two
     variables and colors the header from --kendo-color-surface, a neutral
     surface it also gives to field affixes and picker hover. Putting that
     surface in the brand tint would therefore touch far more than a grid header,
     so it stands here. Measured without this rule: #F5F5F5 with #212529 on it;
   - the header at weight 600 (the theme leaves it at 400, the sort link in it
     too);
   - alternation as a token color instead of the wash the theme computes —
     `color-mix(in srgb, var(--kendo-color-on-app-surface) 4%, transparent)`,
     which on white happens to come out at --tdm3-table-row-alt (244.8 against
     245), but on any other surface does something other than the token
     promises;
   - hover in the brand tint; the theme computes the same wash at 8% and does not
     derive it from a color variable.

   CLASS NAMES, and why they changed. Row alternation was called `tr.k-alt` in the
   2021 rendering and is called `.k-table-alt-row` in 2026; measured on the
   invoices screen `tr.k-alt` was zero hits and `.k-table-alt-row` five, so that
   rule stood dead. In 2026 the header cell carries BOTH names
   (`k-table-th k-header`), but `k-header` is the legacy one and `k-table-th` the
   name the theme itself uses - hence that one.

   SPECIFICITY, and why the hover selector is so long. The theme rule is
   `.k-grid tbody>tr:not(.k-detail-row):hover` and therefore weighs three classes;
   the old `.k-grid tbody tr:hover` weighed two and lost, even though this file
   loads later - measured, a row under the mouse got the grey wash instead of the
   tint. The rule below is literally the theme selector, in both branches, so the
   weighting is equal and source order decides again.
   ------------------------------------------------------------------------ */

.k-grid .k-grid-header {
    background-color: var(--tdm3-table-header-bg);
    color: var(--tdm3-table-header-text);
}

/* A sticky header cell paints its own surface, and that has to be the same surface
   as the bar it stands in. The rule above colors the header BAR; an ordinary header
   cell is transparent and therefore shows it, but a `sticky` cell floats above its
   neighbours and gets its own background from the theme
   (`.k-grid-header .k-grid-header-sticky { background-color: var(--kendo-color-surface) }`).
   Measured on the bundle overview with .Sticky(true) on the Acties column: that one
   header cell came out at rgb(245,245,245) while the other thirteen stood at
   #D5E8F0.

   Not solvable through the bridge, and that was worth considering:
   `--kendo-color-surface` is exactly the variable the theme uses here, but it is
   consumed 65 times (field affixes, popups, cards). Pulling it towards the header
   color would make all those places blue. The deviation is OURS - this product
   picks a different grid header color than the theme - so it belongs here, beside
   the rule that makes that same choice on the bar. */
.k-grid .k-grid-header .k-grid-header-sticky {
    background-color: var(--tdm3-table-header-bg);
}

/* A descendant and not a direct child: 2026 hangs a `<span class="k-cell-inner">`
   between the header cell and the sort link, so `> .k-link` matches nothing any
   more (measured across the five screens: zero hits, while there are nineteen sort
   links). The cell itself does not inherit into the link, because that sets its own
   weight. */
.k-grid-header .k-table-th,
.k-grid-header .k-table-th .k-link {
    font-weight: var(--tdm3-font-weight-bold);
}

/* A column's sort button says under the mouse that it is a button. Measured, it was
   the only control surface in the application standing completely still: color,
   background, border, underline, shadow and opacity all six UNCHANGED under the
   mouse, while the filter icon beside it in the same cell does react
   (#0E2841 -> #114E6A). Two controls in one cell, one that answers and one that
   does not.

   On `.k-link` and not on the cell: that span IS the sort button (`cursor: pointer`,
   measured 35px high inside a cell of 36) and it only exists on a sortable column -
   a command column or a `Sortable(false)` column has none, and those should promise
   nothing either. Measured on the bundle overview: 14 of 14 columns carry one; on
   the collection grid 5 of 6, the Verloop column not.

   --tdm3-surface-hover on --tdm3-table-header-bg is CIEDE2000 4.39
   (accessibility.md, "Vlakken die van elkaar moeten verschillen"), well above the
   2.01 the application itself carries as a floor, and it is the same surface a grid
   row and a sidebar item get - not a seventh grey. */
.k-grid-header .k-table-th .k-link:hover {
    background-color: var(--tdm3-surface-hover);
}

.k-grid .k-table-alt-row {
    background-color: var(--tdm3-table-row-alt);
}

/* AFTER the alternation, so hover takes over an alternating row too: equally
   heavy on specificity, so source order decides. The expanded detail row is
   excluded in both branches, just as in the theme. */
.k-grid tbody > tr:not(.k-detail-row):hover,
.k-grid .k-table-tbody > .k-table-row:not(.k-detail-row).k-hover {
    background-color: var(--tdm3-table-row-hover);
}

/* Columns that do not move along with their content. As a class and not globally:
   it binds the widths from the colgroup, and that is only allowed on a grid where
   EVERY column carries a Width(). The collection grid does the same with
   `.feedback-collection-grid table` in screens.css.

   Measured on the invoices screen, one row switching status: without this rule
   five of the seven columns shifted along, by up to 6.27px; on the bundle
   overview a row going from "ZIP aangemaakt" to "E-mail verzonden" shifted seven
   columns, by up to 15.80px. With this rule that is exactly 0px on both screens.
   Row heights already held still in both cases. */
.tdm3-grid-fixed table {
    table-layout: fixed;
}

/* A grid wider than its column scrolls inside itself, not along with the page.
   Added in migration step 9 for the bundle overview: fourteen columns are 2040px
   together and `main` is 1054, which made the whole page shift 1008px sideways -
   including the menu bar and the vnav sidebar, which ran out of view as soon as
   somebody looked at the right-hand columns.

   Deliberately not Kendo's `Scrollable()`: that turns it into a header plus content
   table with a fixed height, and that is different behavior. This wrapper leaves the
   grid alone - measured, both the grid and its table kept their width exactly, and
   the pager stayed just as wide.

   `overflow-y` comes along at `auto` per the CSS spec as soon as `overflow-x` is;
   an explicit `visible` does not exist here. That is harmless here (measured: no
   vertical scrollbar, because the grid grows with its content), but it is the
   reason this class only belongs on a grid that determines its own height.

   One consumer today. It sits here and not as a screen block in screens.css
   because it belongs to the grid vocabulary - the pair of .tdm3-grid-fixed above -
   and not to that one screen.

   `container-type: inline-size` turns the wrapper into a container-query context.
   That is not styling but a measuring point: the three rules below need the width
   of the VISIBLE box (100cqi), and that stands nowhere else in CSS. The filter
   menus keep working - Kendo hangs them under <body>, so the containment does not
   touch them (re-measured: menu opens at [342, 171], 252 x 280px, outside the
   wrapper). */
.tdm3-grid-scroll {
    overflow-x: auto;
    container-type: inline-size;
}

/* THE CHROME DOES NOT SCROLL OUT OF VIEW.
   The grid was as wide as its wrapper (1012px) while its table is 2240px. Toolbar
   and pager belong to that 1012, the columns to that 2240 - so whoever scrolled to
   the right-hand columns scrolled the chrome out from under them. Measured on the
   rendered bundle overview, 1280 x 800, wrapper box [232, 1244]:

     scroll          table            pager             visible?
     0               [233, 2473]      [233, 1243]       yes
     1229 (max)      [-996, 1244]     [-996, 14]        NO - 1229.8px of columns without chrome

   That is the white gap at the bottom right: rows with no pager under them, and a
   search box that at scroll 1229 sits at x=7 and is therefore gone. Three rules,
   each with a task:

     - the grid gets the width of its table (max-content), so the grid's borders and
       surfaces run under EVERY column. `min-width: 100%` keeps it at wrapper width
       as long as the table is narrower than the box;
     - the table keeps its own width. Without the second rule the theme rule
       `.k-grid .k-table { width: 100% }` wins from a parent on max-content and
       blows the table up to 1000000px (measured, and not a typo);
     - toolbar and pager stick to the left side of the BOX instead of to the table,
       and are exactly as wide as that box (100cqi).

   Afterwards, the same measurement: grid 2242px, table unchanged 2240px, column
   widths unchanged (sum 2240 over fourteen columns), pager at scroll 0 at
   [233, 1245] and at scroll 1230 at [231, 1243] - so fully in view in both
   positions. Horizontal overflow of the page stays 0. */
/* THE SIDE BORDERS MOVE FROM THE GRID TO THE WRAPPER, and that is not styling but
   arithmetic. `width: max-content` measures the CONTENT of the grid and adds its
   own borders to it. The table already fills the grid (the theme gives it
   `width: 100%`), so the grid became exactly 2px wider than the box around it -
   and a wrapper with `overflow-x: auto` then shows a scrollbar while there is
   nothing to scroll. Measured on the collection screen at 1920px, where all
   columns fit comfortably:

     box (clientWidth)   1863      grid  1865 (= table 1863 + 2 borders)   overflow 2px
     after this rule     1861      grid  1861 (= table 1861)               overflow 0

   The border itself stays, only no longer on the element whose width is measured.
   That also changes its behavior, and in the better direction: it stays with the
   visible box instead of scrolling away with the table.

   Re-measured that the wrapper keeps doing its job on a box that IS too narrow
   (900px): scroll range 745px, grid 1643, pager 898 - and the pager stays in view
   at the outermost scroll position. */
.tdm3-grid-scroll {
    border-inline: 1px solid var(--tdm3-border);
}

.tdm3-grid-scroll > .k-grid {
    width: max-content;
    min-width: 100%;
    border-inline-width: 0;
}

.tdm3-grid-scroll > .k-grid > table {
    width: auto;
}

.tdm3-grid-scroll > .k-grid > .k-grid-toolbar,
.tdm3-grid-scroll > .k-grid > .k-pager {
    position: sticky;
    left: 0;
    width: 100cqi;
}

/* THE ACTIONS COLUMN HOLDS STILL AT THE RIGHT - AND TELERIK DOES THAT ITSELF.
   A hand-written block of seven rules stood here (position: sticky on
   `:last-child`, plus four backgrounds and a separator). It worked, and it is out
   again: Kendo 2026 knows `columns.sticky` and does exactly this. See
   `.Sticky(true)` on the Acties column in InvoiceDownloadLink/Index.cshtml; the
   theme puts `k-grid-header-sticky` / `k-grid-content-sticky` on it.

   Re-measured that the vendor variant really works here, because it is documented
   for scrollable grids and this grid is not one (`scrollable: false`, with our own
   wrapper around it):

     scrollable: false + our wrapper   column stays in the box at scroll 0, 600 and 1188
     scrollable: true                  table 1000000px wide, column out of view - unusable

   So: the vendor feature, in the set-up this screen already had. The backgrounds
   also come from the theme and already sit on our tokens, measured in the running
   chain: header rgb(213,232,240) = --tdm3-table-header-bg, row white =
   --tdm3-surface, alternating row rgb(245,245,245) = --tdm3-table-row-alt. They
   run through `--kendo-color-surface-alt`, `--kendo-color-base-subtle` and
   `-hover`, and all three of those are in bridge.css. So nothing of ours is
   needed. */

/* On paper nobody can scroll. A scroll container shows only its visible box
   there, and that is less than half here: the wrapper is 1012px wide around a
   table of 2040px. Without this rule the print of the bundle overview would lose
   eight of the fourteen columns - a regression the wrapper itself causes, and one
   that cannot be seen on screen.

   This is the only print rule the application has, and it designs nothing: it
   puts this one element back to what it did before the wrapper. The print of a
   2040px grid therefore stays what it always was - the browser scales or clips,
   and that is a design question for the owner, not for this migration. */
@media print {
    .tdm3-grid-scroll {
        overflow-x: visible;
    }
}

/* One button style in a grid — the subtle variant from components.md ("acties in
   gridcellen, toolbars"). Before this there were three: a hand-made
   .k-grid-Detail override in #007BFF, Bootstrap-outlined .btn-sm buttons on the
   bundle detail, and the bare Kendo button beside them. Those three are gone
   from the views; this is what takes their place.

   Aims at .k-grid and not at .k-button alone, so the buttons outside a grid
   (dialogs, the delivery method editor) stay the theme's — those are for step 7.
   The pager falls outside it by itself: it builds its buttons from .k-link.
   .k-grid .k-button weighs one class more than the theme rule .k-button.

   Since post-processing C it carries the same ghost shape as .tdm3-btn-subtle -
   a border at rest, a light surface on hover - and for the same measured reason
   (see there). The `border-width: 1px` and `border-style: solid` come from the
   theme and were already there; only the color was transparent. Re-measured in
   the running app before the change, on a real grid button: 1px/solid/
   rgba(0,0,0,0). So the size does not change, and that is more load-bearing here
   than on the loose button: this one sits in a cell whose column width is
   fixed. */
.k-grid .k-button {
    border-color: var(--tdm3-border-strong);
    background-color: transparent;
    background-image: none;
    box-shadow: none;
    color: var(--tdm3-color-link);
    font-weight: var(--tdm3-font-weight-medium);
    text-decoration: none;
}

.k-grid .k-button:hover,
.k-grid .k-button.k-hover {
    border-color: var(--tdm3-border-strong);
    background-color: var(--tdm3-color-info-bg);
    color: var(--tdm3-color-link-hover);
    text-decoration: none;
}

/* The focus indicator the theme takes away. The Kendo swatch sets
   `.k-button:hover, .k-button:focus { text-decoration: none; outline: 0 }` —
   which left a Kendo command button without a visible focus, and that is a
   keyboard user who cannot see where they are.

   Solved here and not in the theme build: that `outline: 0` sits hard in the
   theme's button module, not behind a variable, so through the scss it could
   only be done by patching generated CSS. This rule weighs one class more
   (.k-grid .k-button:focus against .k-button:focus) and loads later as well —
   the thinnest route.

   A single ring, not a double one like the menu bar in step 4. Measured: the
   surfaces a grid button sits on are all light — white, --tdm3-table-row-alt,
   the hover tint, and even the selected row, because the theme colors that with
   rgba(21,96,130,.25) which comes out on white as rgb(197,215,224). Accent blue
   reaches 4.68:1 against that and 6.21:1 against the hover tint, well above the
   3:1 for non-text. So step 4's white inner ring is not needed here. */
.k-grid .k-button:focus,
.k-grid .k-button.k-focus {
    outline: 2px solid var(--tdm3-color-focus);
    outline-offset: 1px;
    box-shadow: none;
}


/* ---------------------------------------------------------------------------
   Dialogs (components.md, "Dialogen"). Kendo Window supplies the frame.

   The TITLE BAR stood in the theme source as $window-titlebar-bg/-text until P4
   and has sat here since, and that is not a step back but what 2026 leaves over:
   the theme only knows VARIANTS any more (`.k-window-primary`, `-light`,
   `-dark`), each taking its color from a --kendo-color-* pair, and a bare
   `.k-window-titlebar` gets NO surface. Measured in the running app on the three
   windows the application knows: transparent with #212529 on it. So there is no
   variable to set - the variant would have to be `k-window-primary`, and that
   sets accent blue and not navy. One class is enough: the theme sets nothing on
   this selector, so there is nothing to win from.

   The content padding stays the theme's: measured 14px (1rem) on all three
   windows. components.md prescribes --tdm3-space-4 (16px); that 2px difference
   is density, and the density of this application was approved by the owner
   after step 4. Not touched.
   ------------------------------------------------------------------------ */

.k-window-titlebar {
    background-color: var(--tdm3-navy);
    color: var(--tdm3-color-primary-contrast);
}

/* The border of a DROPDOWN LIST. In 2026 it does not hang off --kendo-color-border-alt
   (the field border, which bridge.css already sets to --tdm3-border-field) but off
   --kendo-color-border, the light neutral for gridlines and popup borders -
   measured on the country picker in the delivery method editor: rgba(33,37,41,.13), on
   white ~1.13:1, where WCAG 1.4.11 asks for 3:1 for the boundary of an operable
   component.

   The same ailment as in the old theme, where $dropdownlist-border hung off the
   button palette, and the same trade-off: lifting --kendo-color-border would darken
   EVERY table line in the application (181 read sites in the swatch), so the
   dropdown list gets the field border here. A filter menu is a form and that
   operator choice is a field.

   Hover and focus don't need to come along: the theme already derives the hover border in 2026 from
   --kendo-color-border-alt and focus from --kendo-color-primary-emphasis, and
   those two already both point at a token through the bridge. */
.k-picker,
.k-picker.k-picker-solid {
    border-color: var(--tdm3-border-field);
}

/* A window whose content sits as ordinary markup in the page and that
   Kendo only takes over on first opening (the resend dialog on the
   bundle overview). Without this rule that content simply sits on the
   screen until that moment.

   It replaced an inline `style="display:none"`, and that's not a given:
   Kendo itself has to be able to undo the hiding again. Measured that it
   does — the widget calls jQuery's .show(), which writes an inline
   `display: block` onto an element hidden by a stylesheet, and that beats
   this class. After initialization the element carries `style="display: block;
   overflow: hidden;"` and measures 598x344. With a Bootstrap `.d-none` that
   would not work: that sets its none with !important, and no inline
   value beats that. */
.tdm3-dialog-source {
    display: none;
}

/* The collection screen's answer dialog.

   Kendo lays out this popup as a form of labeled fields, which it is not: the
   editor template comes in a k-edit-form-container fixed at 400px inside a window that is
   500 at its narrowest, and k-window-content gets 12px top and bottom and nothing on the sides.
   Together that pushes the content against the left edge with an empty lane along the right. Both classes
   are set by OnEdit, so this touches no other popup editor in the application.

   Moved out of screens.css (then site.css) in migration step 2, and the two !important are gone. They were needed
   as long as the Kendo stylesheets came from their CDN after that file: those won on source order and their
   rules could not be read out of the page per CORS to weigh specificity against. The theme
   is now our own and loads before this file, so source order handles it. */
.k-window-content.collection-answer-window {
    padding-left: var(--tdm3-space-4);
    padding-right: var(--tdm3-space-4);
    padding-top: var(--tdm3-space-3);
    padding-bottom: var(--tdm3-space-3);
}

/* The delivery method editor's legend holds its own line. Bootstrap 5 gives
   `legend` in its reboot `float: left; width: 100%` and immediately clears that float
   again with `legend + * { clear: left }` (bootstrap.css:515-530). Bootstrap 4 did NOT
   have that float; it arrives with P6. The 2026 theme sets width and bottom border on
   `.k-form .k-form-legend` but no `float`, so there's nothing that undoes
   it.

   Why Bootstrap's own `clear` doesn't save this, and this is the whole catch: the first
   sibling after the legend in `editUnifiedDeliveryTemplate` is a callout that carries
   `display: none` on the download-link screens. An element with no box clears no
   float, so `legend + *` falls back on nothing and the float stays in place for EVERYTHING
   that comes after it. `.delivery-button-group` is a flex container and thereby its own
   formatting context: that cannot overlap a float and gets placed NEXT to it.

   Measured in the 780px window, with the callouts hidden: the button row ended up at
   x=726 next to the 702px-wide legend, squeezed to width 0, and its three
   `white-space: nowrap` buttons ran 504px outside the window (scrollWidth 1282
   against clientWidth 778). With this rule: width 702 at x=24, BELOW the legend, and
   overflow 0. With that first callout visible - the FeedbackRequest screens - the
   overflow was always already 0, and THAT is why the migration's render prints came out
   green here: only the download-link variant of this shared partial shows the
   bug.

   On `.k-form-legend` and not on `legend`: this is the ONLY legend in the application
   (one `<fieldset>`/`<legend>` pair, in `_DeliveryMethodEditor.cshtml`), it carries the
   Kendo class, and it's that same theme rule that sets the legend's box without
   carrying the float along. This rule finishes the job. */
.k-form-legend {
    float: none;
}

/* No hover marking on an expanded row. The grid colors a row under the mouse, which on a
   master row says "this is the one you're pointing at" - but the row underneath is a panel you're
   reading, not a row you're choosing, and coloring it across its full width says it's selectable
   when it isn't.

   Moved out of screens.css (then site.css) in migration step 2, without !important (same reason as above). The
   values are redrawn: that file restored #f5f5f5/#787878, the Metro theme's rest colors.
   Under the TDM3 theme a detail row sits transparent with the ordinary text color - measured, not
   assumed - and that is what's restored here now.

   Since 2026 the theme excludes the detail row itself (`:not(.k-detail-row)` in both
   hover branches), and the rule above now does that too. This rule therefore fixes nothing
   any more - it pins down what an expanded panel OUGHT to do, so that a later theme version
   dropping that exception doesn't silently carry this behavior along. Not a dead selector:
   `k-detail-row` still exists in 2026, it just doesn't appear in a print where no row
   is open. */
.k-grid tr.k-detail-row:hover,
.k-grid tr.k-detail-row:hover > td {
    background-color: transparent;
    color: var(--tdm3-text);
}


/* ---------------------------------------------------------------------------
   Toasts (components.md, "Toasts / notifications"). One Kendo Notification in
   _Notifications.cshtml, on every screen, fed by the SignalR messages in
   site.js. The templates there supply the shape; the color sits here.

   WHY THIS IS AN OVERRIDE AND NOT A BRIDGE VARIABLE. In 2026 the theme does
   color a notification from variables — `.k-notification.k-notification-info` reads
   --kendo-color-info-subtle / -on-subtle / -emphasis — and bridge.css does set
   those three families to tokens. What the bridge CANNOT do is make the BORDER equal
   to the surface: --kendo-color-*-emphasis is in the theme the translucent
   accent border of ten other widgets (messagebox, card, chip, badge), and that
   role is a different one. The theme thereby draws a lighter halo around a notification,
   and on white that reads as a double border; the boundary here comes from the
   shadow. Hence three declarations per pair instead of two.

   The pairs themselves are the measured pairs from accessibility.md, the same ones the
   badges carry (components.md).

   The classes are Kendo's own: the widget sets `k-notification-<type>` on
   the outer border, with type from NotificationHub. Measured, not assumed —
   success/info/error each got their class. `newmessage` is the fifth and has
   no rule in the theme; it sits here under info, because that's what the
   template does too.
   ------------------------------------------------------------------------ */

/* --tdm3-radius-lg and a shadow, as components.md asks for a toast.

   The shadow used to sit here on `.k-animation-container > .k-notification` until P4,
   because the 2021 theme set `.k-animation-container > .k-popup` twice, the
   second time to `none`. Both reasons are gone, and the old selector would now
   moreover be DEAD: 2026 hangs an extra `.k-child-animation-container`
   between the wrapper and the notification, so the direct-child combinator no longer
   matches anything. The theme now sets the shadow on `.k-notification` itself
   (--kendo-elevation-4), one class, so this rule wins on source order -
   measured: without it rgba(0,0,0,.125) 0 6px 13px, with it --tdm3-shadow. */
.k-notification {
    border-radius: var(--tdm3-radius-lg);
    box-shadow: var(--tdm3-shadow);
}

/* Two classes, not one: the theme rule is `.k-notification.k-notification-info`
   and that outweighed the single class that used to sit here until P4 - measured,
   an info notification got rgba(13,202,240,.4) as its border, Bootstrap 5 cyan on a
   brand surface. Equal weight, loaded later, so source order decides.

   `k-notification-newmessage` is the fifth kind from NotificationHub; the theme
   doesn't know it, so one class is enough there. It sits under info, because that's
   what the template does too. */
.k-notification-newmessage,
.k-notification.k-notification-info {
    border-color: var(--tdm3-color-info-bg);
    background-color: var(--tdm3-color-info-bg);
    color: var(--tdm3-navy);
}

.k-notification.k-notification-success {
    border-color: var(--tdm3-color-success-bg);
    background-color: var(--tdm3-color-success-bg);
    color: var(--tdm3-color-success);
}

.k-notification.k-notification-warning {
    border-color: var(--tdm3-color-warning-bg);
    background-color: var(--tdm3-color-warning-bg);
    color: var(--tdm3-color-warning);
}

.k-notification.k-notification-error {
    border-color: var(--tdm3-color-danger-bg);
    background-color: var(--tdm3-color-danger-bg);
    color: var(--tdm3-color-danger);
}

/* Icon left, text right. Its own flex, not Bootstrap's grid: this sits
   inside a Kendo container (pre-existing rule, conventions.md).

   The width is the one from before this step: the demo templates fixed their content
   at 300px, which with the theme padding made a toast 330px wide. The
   HEIGHT used to be fixed there too (100px) and it no longer is — a toast of
   two lines was 130px tall with a gap underneath. */
.tdm3-toast {
    display: flex;
    gap: var(--tdm3-space-2);
    align-items: flex-start;
    box-sizing: border-box;
    width: 300px;
}

/* The icon inherits the text color of its status — even on a warning, and
   that's a measurement that runs against the first reading of accessibility.md.
   Rule 3 there splits the color roles: --tdm3-orange for border and icon,
   --tdm3-orange-text for the text. That split holds where the accent sits against
   WHITE (3.06:1) — a callout's left border. This icon sits on the tint
   itself, and there --tdm3-orange reaches 2.63:1, below the 3:1 for non-text;
   measured with the accent on it. --tdm3-color-warning reaches 5.38:1 there, so the
   icon follows the text. A finding for accessibility.md.

   The 1px is optical: a 16px icon line otherwise sits just above the cap line
   of the title next to it. */
.tdm3-toast-icon {
    flex: none;
    margin-top: 1px;
}

/* Without min-width, a long word breaks the flex row open instead of within the
   text itself. */
.tdm3-toast-body {
    min-width: 0;
}

.tdm3-toast-title {
    display: block;
    font-weight: var(--tdm3-font-weight-bold);
}

.tdm3-toast-message {
    display: block;
    overflow-wrap: break-word;
}
