/* ---------- Radius ----------
   The design has TWO radii, and Tailwind's default scale is not either of them:
     8px  surfaces — cards, panels, popovers, brand tiles          (rounded-card)
     6px  controls — inputs, buttons, segmented control, alerts    (rounded-control)
     4px  details  — checkbox, listbox rows, small tags            (rounded-detail)
   Reaching for rounded-lg/rounded-xl is how this page ended up rounder than its design once
   already. The literals below must stay in step with tailwind.config.js by hand. */

h1:focus {
    outline: none;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid #e50000;
}

.validation-message {
    color: #e50000;
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

.darker-border-checkbox.form-check-input {
    border-color: #929292;
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
    color: var(--bs-secondary-color);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
    text-align: start;
}
/* Marks a row whose price came from a carrier's API rather than our tariff engine.
   Outline style — white ground, border and text in one accent — so it reads as a qualifier on
   the row, not as a status badge competing with the numbers. The forwarding agent cell next to
   it already names the carrier, so the pill stays generic. */
.api-pill {
    display: inline-block;
    padding: 1px 6px;
    border: 1px solid #c9c0ee;           /* primary-line */
    border-radius: 4px;
    color: #6244d6;                      /* primary */
    background: transparent;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .04em;
    line-height: 1.5;
    white-space: nowrap;
    cursor: help;
}

.price-source-note {
    padding: 0 8px 20px 8px;
    font-size: 12px;
    color: #6d7789;                      /* text-tertiary */
}

/* ---------- Float-label fields ----------
   Not @apply: this file does not pass through Tailwind (see Styles/tailwind.css), so the tokens are
   repeated as literals and must stay in step with tailwind.config.js by hand.

   Two things this depends on, both easy to break:
   1. The input comes BEFORE the label in the DOM. The float is driven by `~`, which only matches
      following siblings. Swap them and the label never moves.
   2. Every .fld-inp needs a placeholder attribute — `placeholder=" "` is enough. :placeholder-shown
      is how "empty" is detected; without one the label stays risen over an empty box. */
.fld {
    position: relative;
}

.fld-inp {
    width: 100%;
    height: 46px;
    padding: 17px 13px 0 13px;           /* room for the risen label */
    font: inherit;
    font-size: 13.5px;
    color: #0f172a;                      /* text */
    background: #ffffff;                 /* surface */
    border: 1px solid #e2e8f0;           /* line */
    border-radius: 6px;
    transition: border-color .12s, box-shadow .12s;
}

/* Resting: the label sits where the value would, so the box reads as one thing. */
.fld-lbl {
    position: absolute;
    left: 13px;
    top: 14px;
    font-size: 13.5px;
    font-weight: 400;
    letter-spacing: 0;
    text-transform: none;
    color: #6d7789;                      /* text-tertiary */
    pointer-events: none;
    transition: top .12s, font-size .12s, color .12s;
    z-index: 2;                          /* a listbox panel paints over the box; the label stays readable */
}

/* Risen: focused, or holding a value. */
.fld-inp:focus ~ .fld-lbl,
.fld-inp:not(:placeholder-shown) ~ .fld-lbl {
    top: 7px;
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
}

.fld-inp:focus ~ .fld-lbl {
    color: #6244d6;                      /* primary */
}

.fld-inp:hover:not(:focus):not(:disabled) {
    border-color: #cbd5e1;
}

.fld-inp:focus {
    outline: none;
    border-color: #6244d6;               /* primary */
    box-shadow: 0 0 0 3px #f0ecfd;       /* primary-soft */
}

.fld-inp:disabled {
    background: #fafafc;
    color: #6d7789;
}

.fld-inp.invalid,
.fld-inp[aria-invalid="true"] {
    border-color: #c4453e;               /* danger */
}

.fld-inp.invalid:focus,
.fld-inp[aria-invalid="true"]:focus {
    border-color: #c4453e;
    box-shadow: 0 0 0 3px #fdf3f2;       /* danger-soft */
}

/* An affordance inside the box, centred against the box rather than the value — the floating
   label pushes the value low, so centring on the value would sit it too far down. */
.fld-btn {
    position: absolute;
    right: 8px;
    top: 23px;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 4px;
    border-radius: 6px;
    color: #6d7789;
    z-index: 3;
}

.fld-btn:hover {
    color: #0f172a;
    background: #fafafc;
}

.fld-inp.has-btn {
    padding-right: 40px;
}

/* The one animation on the sign-in panel: the dashed leg drifting toward the destination. Behind
   prefers-reduced-motion, and it is the only thing that moves on the page. */
@media (prefers-reduced-motion: no-preference) {
    .lane-dash {
        animation: lane-drift 1.4s linear infinite;
    }

    @keyframes lane-drift {
        to { stroke-dashoffset: -14; }
    }
}

/* ---------- Plain data table ----------
   border-collapse: separate is NOT cosmetic. With `collapse`, a border on a sticky <th> detaches
   from the cell and scrolls away in Chrome and Safari — the header keeps its position and loses its
   bottom rule. See docs/admin-list-pages.md §3. border-spacing: 0 restores the collapsed look. */
table.plain {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    font-size: 13px;
}

table.plain th {
    position: sticky;
    top: 0;
    z-index: 5;                          /* under a listbox panel (z-40), over the rows */
    background: #ffffff;                 /* opaque: rows scroll underneath it */
    padding: 9px 12px;
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: #3f4a5c;
    text-align: left;
    white-space: nowrap;
    border-bottom: 1px solid #e2e8f0;
}

table.plain td {
    padding: 10px 12px;
    vertical-align: middle;
    border-bottom: 1px solid #eef1f5;
    color: #0f172a;
}

table.plain tbody tr:hover td {
    background: #fafafc;
}

table.plain th:first-child,
table.plain td:first-child {
    padding-left: 20px;
}

table.plain th:last-child,
table.plain td:last-child {
    padding-right: 20px;
}

table.plain .num {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* A second line under a cell's value: an id under a name, a note under a date. */
table.plain .sub {
    display: block;
    margin-top: 2px;
    font-size: 11.5px;
    color: #6d7789;
}

/* Same lesser-fact treatment, on the line rather than under it. The distinction is real and not
   just about height: a country code is part of the address it sits beside, so it belongs on that
   line, while a phone number is a different attribute of the contact above it and belongs under.
   The height matters too — every address has a country, so a block sub-line there cost a second
   row on all 400 of them. */
table.plain .sub-inline {
    margin-left: 6px;
    font-size: 11.5px;
    color: #6d7789;
    /* The pair must not break across two lines — that is the whole point of putting it inline. On
       a long place name the cell scrolls with the table instead, which is a wrapper that already
       scrolls, and a two-line column reads worse than a wide one. */
    white-space: nowrap;
}

/* Applied to the cell, not just the code: nowrap on the span alone still lets the break happen at
   the space before it. */
table.plain td.one-line {
    white-space: nowrap;
}

/* An expired agreement is still real data, so it is dimmed rather than hidden or coloured red —
   red would read as an error the customer can fix. */
table.plain tr.expired td {
    color: #6d7789;
}

/* Sortable header. The arrow is display:none rather than opacity:0 — at opacity 0 it still
   occupies space, which pushes a numeric column's header out of line with its values. */
table.plain th button {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font: inherit;
    color: inherit;
    letter-spacing: inherit;
    text-transform: inherit;
    border-radius: 0;
    background: none;
}

table.plain th button:hover {
    color: #6244d6;
}

table.plain th .arw {
    display: none;
    font-size: 9px;
}

table.plain th[aria-sort] .arw {
    display: inline;
    color: #6244d6;
}

/* ---------- Plain input ----------
   For toolbars and settings rows, where the label is elsewhere (a filter placeholder, or the
   setting's own name beside it). Same border and focus treatment as .fld-inp so the two never
   look like different families — only the label handling differs. */
.inp {
    height: 40px;
    padding: 0 11px;
    font: inherit;
    font-size: 13px;
    color: #0f172a;
    background: #ffffff;
    border: 1px solid #e2e8f0;
    border-radius: 6px;
    transition: border-color .12s, box-shadow .12s;
}

.inp::placeholder {
    color: #6d7789;
}

.inp:hover:not(:focus):not(:disabled) {
    border-color: #cbd5e1;
}

.inp:focus {
    outline: none;
    border-color: #6244d6;
    box-shadow: 0 0 0 3px #f0ecfd;
}

.inp:disabled {
    background: #fafafc;
    color: #6d7789;
}

.inp.num {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.inp.invalid {
    border-color: #c4453e;
}

.inp.invalid:focus {
    border-color: #c4453e;
    box-shadow: 0 0 0 3px #fdf3f2;
}

/* ---------- Checkbox ----------
   The tick is an SVG mask positioned center, not a rotated border with hand-tuned offsets. A
   rotated border needs different offsets at every size and never quite centres. */
.chk {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    color: #3f4a5c;
    cursor: pointer;
    user-select: none;
}

.chk input {
    appearance: none;
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    position: relative;
    border: 1.5px solid #cbd5e1;
    border-radius: 4px;
    background: #ffffff;
    cursor: pointer;
    transition: background .1s, border-color .1s;
}

.chk input:checked {
    background: #6244d6;
    border-color: #6244d6;
}

.chk input:checked::after {
    content: "";
    position: absolute;
    inset: 0;
    background: #ffffff;
    -webkit-mask: var(--tick) center / 11px 11px no-repeat;
    mask: var(--tick) center / 11px 11px no-repeat;
}

.chk input:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px #f0ecfd;
}

.chk input:disabled {
    background: #eef1f5;
    border-color: #e2e8f0;
    cursor: not-allowed;
}

.chk input:disabled:checked {
    background: #cbd5e1;
    border-color: #cbd5e1;
}

.chk:has(input:disabled) {
    cursor: not-allowed;
    color: #6d7789;
}

:root {
    --tick: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5.5 12.5l4.6 4.6L18.5 8'/%3E%3C/svg%3E");
}

/* ---------- Settings list ----------
   Name and description on the left, control on the right, one hairline per row. This is what
   removes the ragged grid that hints of different lengths produce under a field. */
.srow {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 24px;
    align-items: start;
    padding: 15px 20px;
    border-top: 1px solid #eef1f5;
}

.srow:first-child {
    border-top: none;
}

.sname {
    font-size: 13.5px;
    font-weight: 600;
    color: #0f172a;
}

.sdesc {
    margin-top: 3px;
    /* 72ch, not the 56ch the 860px page shell needed — the page runs full width now, and the old
       measure forced two-line descriptions with one-word tails ("Set it / to 0",
       "account / administrator."). text-wrap: pretty rebalances the remaining wraps so a line
       never ends one word short of the sentence. */
    max-width: 72ch;
    font-size: 12.5px;
    line-height: 1.45;
    text-wrap: pretty;
    color: #6d7789;
}

.sctl {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.sgroup {
    padding: 16px 20px 8px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: #3f4a5c;
    border-top: 1px solid #e2e8f0;
}

@media (max-width: 760px) {
    .srow {
        grid-template-columns: 1fr;
        gap: 10px;
    }
}

/* A unit inside a numeric field. Same inside-right position every other field affordance uses,
   pinned against the box rather than the value — the floating label pushes the value low. */
.fld-unit {
    position: absolute;
    right: 11px;
    top: 23px;
    transform: translateY(-50%);
    font-size: 11.5px;
    color: #6d7789;
    pointer-events: none;
}

.fld-inp.has-unit {
    padding-right: 38px;
}

.fld-inp.num {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* ---------- Collapsible card header ----------
   The chevron is hidden while the card is open and always visible once collapsed, on hover, on
   keyboard focus, and on touch. hover: none covers the touch case — a device with no hover would
   otherwise leave a collapsed card with no visible affordance at all. */
.card-h .card-chev {
    opacity: 0;
    transition: opacity .12s;
}

.card-h:hover .card-chev,
.card-h .card-chev:focus-visible,
.card-h[data-collapsed="true"] .card-chev {
    opacity: 1;
}

@media (hover: none) {
    .card-h .card-chev { opacity: 1; }
}

/* A card's collapsed read-back when it is one continuous phrase rather than a set of facts — the
   Origin and Destination addresses. Truncates with an ellipsis, which reads as "there is more";
   a chip cut through its own border reads as a rendering fault, which is why the chip row below
   drops what does not fit instead. */
.card-sum {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 12.5px;
    color: #6d7789;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.card-sum i {
    font-style: italic;
}

/* Collapsed summary chips. Truncating a pill through its own border reads as a rendering fault, so
   the row hides what does not fit behind a count instead. */
.sum-chips {
    display: flex;
    gap: 5px;
    overflow: hidden;
    white-space: nowrap;
}

.sum-chip {
    display: inline-block;
    flex: 0 0 auto;
    padding: 1px 9px;
    /* White on a grey hairline, not a filled grey block: these sit on the card header, and a filled
       chip there reads as a control you can press. The 4px matches the vol-tag and the detail-radius
       token — the design's 11px made a full pill of a 19px-tall chip, which pulled more attention
       than a read-back of what the card holds should. */
    border: 1px solid #e2e8f0;
    border-radius: 4px;
    background: #ffffff;
    font-size: 11.5px;
    color: #3f4a5c;
    max-width: 22ch;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sum-chip.none {
    border-style: dashed;
    color: #6d7789;
    background: transparent;
}

/* ---------- Toast position ----------
   MudBlazor puts the top-right stack at top:24px, which lands it on top of the header's nav. The
   header is h-14 (56px), so 68px clears it with the same 12px of air the cards get. Right edge
   matches the page column's own 20px gutter rather than Mud's 24px.

   Element-level specificity plus !important is not defensive here, it is required: Mud's own rule
   is a single class and would otherwise tie, and its stylesheet loads before this one only by
   convention. Same family of problem as the spacing and border-style collisions in
   tailwind.config.js. */
div.mud-snackbar-location-top-right {
    top: 68px !important;
    right: 20px !important;
}

/* A soft tinted panel, not a saturated fill. Mud paints the whole toast in --mud-palette-error and
   writes white on it, which is the loudest thing on a page whose only other strong colour is one
   purple button. The colour moves to the icon and a 3px left accent; the message goes to the same
   near-black as the rest of the page, so it reads at the same weight as everything else and the
   contrast question stops being about the tint at all.

   Not a colour choice dressed up as one: the tints are the danger-soft and success-soft tokens, and
   the accents are the danger and success tokens. Same two values as the rest of the app. */
.mud-snackbar.mud-alert-filled-error,
.mud-snackbar.mud-alert-filled-success {
    color: #0f172a !important;
    font-weight: 400 !important;
    border: 1px solid;
    border-left-width: 3px;
    /* Square on the left, rounded on the right. The accent is a 3px border, so a radius on that
       corner bends it into a taper — the bar thins to nothing top and bottom and reads as a
       rendering fault rather than a choice. A straight bar against two square corners is the
       whole point of an accent edge. */
    border-radius: 0 8px 8px 0;
    box-shadow: 0 4px 6px -1px rgba(15, 23, 42, .08), 0 10px 24px -6px rgba(15, 23, 42, .14);
    font-size: 13.5px;
}

.mud-snackbar.mud-alert-filled-error {
    background-color: #fdf3f2 !important;
    border-color: #c4453e;
}

.mud-snackbar.mud-alert-filled-success {
    background-color: #eef9f3 !important;
    border-color: #13875a;
}

/* The icon carries the severity now, so it stops being a 90 %-opacity white silhouette. */
.mud-snackbar.mud-alert-filled-error .mud-snackbar-icon {
    color: #c4453e;
    opacity: 1;
}

.mud-snackbar.mud-alert-filled-success .mud-snackbar-icon {
    color: #13875a;
    opacity: 1;
}

/* Mud's close button inherits the alert's text colour, which was white on the fill. On a tint it
   needs to recede instead. */
.mud-snackbar.mud-alert-filled-error button,
.mud-snackbar.mud-alert-filled-success button {
    color: #6d7789;
}

.mud-snackbar.mud-alert-filled-error button:hover,
.mud-snackbar.mud-alert-filled-success button:hover {
    color: #0f172a;
}

/* The agreement-priority flag, leading the forwarding-agent cell. Sized and spaced like the winner
   badges so the row does not gain a second visual language, but it is not one of them: a badge marks
   the single best row in one mode, this marks every row with its own classification. */
/* Fixed-width gutter, present on every row of a table that has any flag, so the agent names keep
   one left edge. Width is the glyph plus its gap; do not switch it to a margin on .prio-flag —
   that indents only the flagged row. */
.prio-slot {
    display: inline-block;
    width: 20px;
}

.prio-flag {
    display: inline-flex;
    align-items: center;
    vertical-align: -2px;
}

.prio-flag svg {
    display: block;
    width: 13px;
    height: 13px;
}

/* ---------- Date field ----------
   The native picker indicator sits on the text baseline, which the floating label pushes low, and
   it cannot be sized or coloured. Hidden, and replaced by our own glyph in the same inside-right
   slot every other field affordance uses — the listbox chevron, the unit suffix, the info icon —
   centred against the BOX at 23px, half the 46px field height, not against the value.

   Not a button: clicking a real one would need showPicker() over JS interop, and an unhandled
   interop call tears the circuit down. The whole input already opens the picker on click in Chrome
   and Safari, so the glyph only has to say that it will. */
.fld-date::-webkit-calendar-picker-indicator {
    opacity: 0;
    position: absolute;
    inset: 0;
    width: auto;
    height: auto;
    margin: 0;
    padding: 0;
    cursor: pointer;
}

.fld-cal {
    position: absolute;
    right: 10px;
    top: 23px;
    transform: translateY(-50%);
    display: inline-flex;
    color: #6d7789;
    pointer-events: none;
}

.fld-cal svg {
    display: block;
    width: 16px;
    height: 16px;
}

/* ---------- Overridden dimensions ----------
   A manual volume overrides the L×W×H calculation, so the measurements read as inactive. Muted,
   NOT disabled: they stay editable, and they still count towards each agreement's max length,
   width and height — CostCalculator rejects on those regardless of how the volume arrived. */
.fld-inp.overridden,
.inp.overridden {
    color: #6d7789;
    background: #fafafc;
}

.fld-inp.overridden:focus,
.inp.overridden:focus {
    color: #0f172a;
    background: #ffffff;
}

/* The L×W×H provenance tag inside the volume box. Left side, so it never collides with the m³
   suffix on the right. */
.vol-tag {
    position: absolute;
    left: 8px;
    top: 23px;
    transform: translateY(-50%);
    padding: 2px 5px;
    border-radius: 4px;
    background: #f0ecfd;
    font-size: 9.5px;
    font-weight: 700;
    letter-spacing: .03em;
    color: #6244d6;
    pointer-events: none;
    white-space: nowrap;
    z-index: 3;
}

.fld-inp.has-tag {
    padding-left: 62px;
}

/* ---------- Results table ----------
   The expanded row and its panel read as one unit: shared tint, an unbroken accent down the left,
   and no divider between them. Without the accent the panel floats free of the row it belongs to. */
table.res tbody tr.open > td {
    background: #faf9fe;
    font-weight: 600;
    border-bottom: none;
}

table.res tbody tr.open > td:first-child {
    box-shadow: inset 3px 0 0 #6244d6;
}

table.res tbody tr.detail > td {
    background: #faf9fe;
    padding: 0;
    box-shadow: inset 3px 0 0 #6244d6;
}

table.res tbody tr.detail:hover > td {
    background: #faf9fe;      /* the panel is not a row; it must not light up on hover */
}

table.res tbody tr.dim > td {
    color: #6d7789;
}

.detail-in {
    padding: 14px 20px 20px 20px;
}

.detail-in h4 {
    margin-bottom: 10px;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: #6d7789;
}

/* The cost breakdown is a table, not a grid: one size, no italics, weight and colour for hierarchy,
   and an unbroken rule above the total. A grid's column gap breaks that rule into segments.

   These selectors are prefixed with `table` so they outrank `table.res td`, whose descendant
   selector otherwise reaches in here and gives every breakdown row a bottom border. */
table.kv {
    border-collapse: collapse;
    font-size: 12.5px;
}

table.kv td {
    padding: 2px 0;
    border: none;
    vertical-align: baseline;
}

table.kv td.k {
    padding-right: 18px;
    color: #3f4a5c;
}

table.kv td.v {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

table.kv td.u {
    padding-left: 6px;
    color: #6d7789;
}

/* The input block: what was sent and what it is charged as. Framed by a hairline below the last
   input row rather than a box — the rows are already dimmed, and a border-box around three lines
   inside a table fights the column alignment. */
table.kv tr.in + tr:not(.in) td {
    padding-top: 7px;
    border-top: 1px solid #eef1f5;
}

table.kv tr.in td.k {
    color: #8b93a7;
}

/* A surcharge belongs to the cost step above it: indented so "Drivmedelstillägg" reads as part of
   Main transport cost, not as a sibling. Named "item", NOT "sub" — .sub is the results table's
   sub-line class and carries display:block, which silently breaks table row layout. */
table.kv tr.item td.k {
    padding-left: 14px;
}

/* Cost steps are subtotals and carry weight — but less than the total, which also has the rule. */
table.kv tr.step td.k,
table.kv tr.step td.v {
    font-weight: 600;
}

table.kv tr.tot td {
    padding-top: 6px;
    border-top: 1px solid #e2e8f0;
    font-weight: 700;
}

table.kv tr.tot td.u {
    font-weight: 400;
    color: #6d7789;
}

table.kv tr.in td {
    color: #6d7789;
}

/* A unit inside a plain (label-less) input — centred on the box, which here IS the value's line. */
.fld-unit-plain {
    position: absolute;
    right: 10px;
    top: 50%;
    transform: translateY(-50%);
    font-size: 11px;
    color: #6d7789;
    pointer-events: none;
}

/* A listbox's own label, inside its trigger. Same position and type as .fld-lbl in its risen state —
   a listbox always has a value or a placeholder, so there is nothing to float up from. */
.lb-lbl {
    position: absolute;
    left: 13px;
    top: 7px;
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: #6d7789;
    pointer-events: none;
}

/* The L×W×H tag in a label-less input: centred on the box, which here is the value's own line. */
.vol-tag-plain {
    position: absolute;
    left: 7px;
    top: 50%;
    transform: translateY(-50%);
    padding: 2px 5px;
    border-radius: 4px;
    background: #f0ecfd;
    font-size: 9.5px;
    font-weight: 700;
    letter-spacing: .03em;
    color: #6244d6;
    pointer-events: none;
    white-space: nowrap;
    z-index: 3;
}
