﻿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;
}

/* TinyMCE renders its floating toolbar popups (the "Paragraph" blocks menu, color pickers, etc.)
   into a .tox-tinymce-aux container appended to <body>, with a bundled z-index of 1201 — lower
   than MudBlazor's dialog stack. When the editor is opened inside a MudDialog, those popups paint
   underneath the dialog and are invisible. Force them above every MudBlazor layer. */
.tox-tinymce-aux {
    z-index: 20000 !important;
}

.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;
}

/* Served from wwwroot, NOT from Google Fonts.

   The font used to be fetched from fonts.gstatic.com at runtime, which meant that on any machine
   that could not reach it — no internet, a corporate proxy, a firewall — every Lao string silently
   fell back to whatever the operating system happened to have. Nothing failed and nothing was
   logged; the text simply rendered in the wrong shapes. A Lao-market back office cannot have its
   own language depend on an outside service being reachable.

   One file, ~21 KB: this is the variable font, and Google's own stylesheet points weights 400, 500
   and 700 at exactly this URL. Only the Lao subset is shipped — Latin has no matching unicode-range
   here, so it falls through to Roboto/Helvetica/Arial below, which is what English already uses.

   Licensed under the SIL Open Font License; see fonts/OFL.txt. */
@font-face {
    font-family: 'Noto Sans Lao';
    font-style: normal;
    font-weight: 400 700;
    font-display: swap;
    src: url('fonts/noto-sans-lao-v33-lao.woff2') format('woff2');
    unicode-range: U+0E81-0EDF, U+200C-200D, U+25CC;
}

/* Applied when the active culture is Lao — MudBlazor generates a separate
   --mud-typography-*-family variable per typography variant rather than having them all derive from
   one, so each needs to be overridden here for full coverage. */
html[lang="lo"] {
    font-family: 'Noto Sans Lao', Roboto, Helvetica, Arial, sans-serif;
    --mud-typography-default-family: 'Noto Sans Lao', Roboto, Helvetica, Arial, sans-serif;
    --mud-typography-h1-family: 'Noto Sans Lao', Roboto, Helvetica, Arial, sans-serif;
    --mud-typography-h2-family: 'Noto Sans Lao', Roboto, Helvetica, Arial, sans-serif;
    --mud-typography-h3-family: 'Noto Sans Lao', Roboto, Helvetica, Arial, sans-serif;
    --mud-typography-h4-family: 'Noto Sans Lao', Roboto, Helvetica, Arial, sans-serif;
    --mud-typography-h5-family: 'Noto Sans Lao', Roboto, Helvetica, Arial, sans-serif;
    --mud-typography-h6-family: 'Noto Sans Lao', Roboto, Helvetica, Arial, sans-serif;
    --mud-typography-subtitle1-family: 'Noto Sans Lao', Roboto, Helvetica, Arial, sans-serif;
    --mud-typography-subtitle2-family: 'Noto Sans Lao', Roboto, Helvetica, Arial, sans-serif;
    --mud-typography-body1-family: 'Noto Sans Lao', Roboto, Helvetica, Arial, sans-serif;
    --mud-typography-body2-family: 'Noto Sans Lao', Roboto, Helvetica, Arial, sans-serif;
    --mud-typography-button-family: 'Noto Sans Lao', Roboto, Helvetica, Arial, sans-serif;
    --mud-typography-caption-family: 'Noto Sans Lao', Roboto, Helvetica, Arial, sans-serif;
    --mud-typography-overline-family: 'Noto Sans Lao', Roboto, Helvetica, Arial, sans-serif;
}

.tl-brand {
    display: flex;
    align-items: center;
    margin-left: 8px;
    color: inherit;
    text-decoration: none;
}

.tl-brand-logo {
    flex-shrink: 0;
}

/* The company's uploaded Logo 1, when one is configured.

   Height-constrained with width:auto so any aspect ratio fits the bar — the four logo slots hold a
   square emblem and three wider lockups, and a fixed width would squash whichever one is set.

   ⚠ Placed straight on the app bar with no background, by request. Worth knowing what that costs:
   the bar is the primary (navy) colour and the current Logo 1 is navy and red on a transparent
   ground, so the navy half of the shield reads faintly against it. A white pill behind the image
   (background/border-radius/padding) is the one-line fix if it ever looks wrong; the better one is a
   reversed, light-on-dark logo — but that cannot go in slot 1, because the PDFs use the same image
   on white paper, where a light logo would disappear instead. */
.tl-brand-logo-image {
    height: 32px;
    width: auto;
    max-width: 160px;
    object-fit: contain;
}

/* On small screens (phones and narrow tablet/desktop windows — MudBlazor's xs+sm range) the app
   bar has too little room for the icon buttons, language toggle, and profile menu alongside the
   full company name — keep only the logo mark. */
@media (max-width: 959.98px) {
    .tl-brand-text {
        display: none;
    }
}

/* The profile menu shows the signed-in user's full name when there's room.

   ⚠ On a phone it shows NOTHING but the account icon. It used to fall back to the word "Profile",
   which still did not fit: by the time the bar carries the menu button, the logo, the bell, the
   theme, skin and language buttons and three text-size buttons, the word was cut off mid-way and
   pushed the icon off the edge. Every other control in the bar is already an icon, so this is the
   one that was out of step rather than the one that needed the label. */
@media (max-width: 959.98px) {
    .tl-profile-fullname {
        display: none;
    }

    /* MudButton reserves a label's worth of width whether or not there is a label, and the
       start-icon margin assumes text follows it — both are empty space in the one place on the
       screen where there is none to spare. */
    .tl-profile-button {
        min-width: 0;
        padding-inline: 8px;
    }

    .tl-profile-button .mud-button-icon-start {
        margin-inline: 0;
    }
}

/* Clickable Dashboard stat/quick-link tiles — a plain hover lift is enough to signal they're
   navigable, matching MudBlazor's own elevation-on-hover convention used elsewhere. */
/* The hover lift, shared by every card on the dashboard so they all respond the same way.
   ⚠ Deliberately separate from the pointer cursor below: the lift is presentation, the cursor is a
   PROMISE that clicking does something. The summary cards are read-only, so they get the first and
   not the second — a pointer on a card that ignores the click is how a UI teaches people that
   clicking is pointless. */
.tl-hover-lift,
.tl-dashboard-tile {
    transition: box-shadow 0.15s ease-in-out, transform 0.15s ease-in-out;
}

.tl-hover-lift:hover,
.tl-dashboard-tile:hover {
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    transform: translateY(-2px);
}

/* Only the tiles that actually navigate. */
.tl-dashboard-tile {
    cursor: pointer;
}

/* Applied to a table/pagination wrapper while a page change (or any reload) is in flight — dims
   and disables pointer interaction so a slow network reads as "working on it" instead of a
   frozen/broken UI, without needing a full-screen overlay for what's usually a sub-second wait. */
.tl-loading-dim {
    opacity: 0.5;
    pointer-events: none;
    transition: opacity 0.15s ease-in-out;
}

/* Outlined text fields/selects/etc. share --mud-default-borderradius (10px) with cards, buttons,
   and dialogs sitewide — that's too heavy on a compact input border, so it's overridden here
   specifically for input outlines rather than lowering the shared theme token everywhere. */
.mud-input-outlined-border {
    border-radius: 4px;
}

/* Shared PageLoading component (Components/Shared/PageLoading.razor) — centres the spinner in the
   content area rather than letting it sit in the top-left corner. min-height is set inline so each
   usage can size the reserved space. */
.tl-page-loading {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
}

/* Signature capture pads (Application wizard). The canvas width/height ATTRIBUTES set the drawing
   buffer; these rules pin the on-screen size so a pad renders identically wherever it sits. Without
   the explicit size + align-self, a pad placed inside a MudStack (a flex column, which stretches
   its children) blows up to the full container width — and because a canvas with height:auto keeps
   its aspect ratio, it grows just as dramatically in height. */
.tl-signature-pad {
    display: block;
    width: 800px;
    /* height:auto, NOT a fixed height. A canvas is a replaced element, so auto height follows the
       intrinsic ratio of its width/height ATTRIBUTES -- which is what keeps the drawing buffer and
       the on-screen box in proportion once max-width kicks in. Pinning the height instead lets the
       box squash horizontally while the buffer stays 500 wide, and signaturePad.js then scales x and
       y by different factors: the stroke still tracks the cursor, but the SAVED png comes out
       horizontally stretched compared to what was signed. Also serves both pad sizes in use
       (500x200 on the profile, 500x150 on the application) from one rule. */
    height: auto;
    max-width: 100%;
    align-self: flex-start;
    flex: 0 0 auto;
    border: 1px solid var(--mud-palette-lines-default);
    background: white;
    touch-action: none;
}

/* Shared PageHeader component (Components/Shared/PageHeader.razor) — title stacked above any
   action buttons, never on the same row, regardless of MudBlazor's own default display rules. */
.tl-page-header {
    display: block;
    width: 100%;
}

.tl-page-header-title {
    display: block;
    width: 100%;
}

.tl-page-header-actions {
    display: block;
    width: 100%;
}
/* Multi-line fields the user may drag taller — the underwriting assessment's narrative boxes, where an
   entry can run to a few hundred words and a fixed window means reading it through a slot.

   Manual only. MudBlazor 9.7.0 has no AutoGrow parameter -- setting one compiles, because these
   components capture unmatched attributes, and then silently does nothing but add an attribute to the
   DOM. So the fields carry a generous starting Lines instead, and the handle covers the rest.

   VERTICAL only, deliberately. `resize: both` lets the handle drag the box wider than the grid column
   it sits in, which overlaps the field beside it and cannot be undone without a reload. */
/* The selector has to out-specify MudBlazor's own `.mud-input > textarea.mud-input-root { resize: none }`
   (0,2,2). `.tl-resizable textarea` alone is (0,1,1) and loses silently -- the handle simply never
   appears. Matching its shape and adding our class makes it (0,3,2), which wins without !important. */
.tl-resizable .mud-input > textarea.mud-input-root {
    resize: vertical;
}

/* Full-screen submission blocker (see BlockingProgressOverlay.razor).

   z-index 2000 clears MudBlazor's whole stack — drawer 1100, popover 1200, appbar 1300, dialog 1400,
   snackbar 1500, tooltip 1600 — so nothing on the page can sit on top of it and nothing behind it can
   be clicked. It stays well under the 20000 the TinyMCE aux container needs above, so the two hacks
   do not fight.

   position: fixed with all four insets rather than width/height 100%: on a page that is already
   scrolled, a percentage box is measured against the document and leaves the bottom of the viewport
   uncovered, which is exactly where the Submit button the agent just pressed lives. */
.tl-blocking-overlay {
    position: fixed;
    inset: 0;
    z-index: 2000;
    display: flex;
    align-items: center;
    justify-content: center;
    /* Deliberately a literal rgba rather than a MudBlazor palette variable: this must read as "the
       page is not available" in both light and dark themes, and a theme-following surface colour does
       not. */
    background: rgba(0, 0, 0, 0.55);
}

.tl-blocking-overlay-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: 32px 40px;
    border-radius: 8px;
    max-width: 90vw;
    background: var(--mud-palette-surface);
    color: var(--mud-palette-text-primary);
    box-shadow: var(--mud-elevation-8);
}

/* A status chip must never break mid-word: the label is one token and a wrapped chip pushes the
   whole table row open. Lao labels are the ones that hit this first. */
.tl-nowrap-chip {
    white-space: nowrap;
}

/* A date picker's Style is applied to the popover PAPER as well as the input, so a
   Style="max-width:220px" written for the input also caps the calendar — and that paper has
   overflow:hidden, so the calendar is not just narrow, it is cut off. Saturday and Sunday
   disappear and most of the month with them.

   Measured on the live pages: the calendar needs 310px and every picker in the app declared
   between 190px and 250px, so all fourteen were clipped.

   Scoped to .mud-popover so it only releases the floating calendar — the input keeps the width
   the page asked for, because that element is not inside the popover provider. Fixed here rather
   than at fourteen call sites so the next picker written the same way is not broken again. */
.mud-popover .mud-picker-paper {
    /* !important is required, not lazy: the cap is an INLINE style written onto the paper by
       MudBlazor from the picker's Style parameter, and no stylesheet selector outranks an
       inline style. The alternative is removing Style from all fourteen call sites and
       reaching the input through a class instead, which is more code to say the same thing and
       leaves the next picker free to reintroduce the bug. */
    max-width: none !important;
}

.mud-picker .mud-picker-container {
    min-width: max-content;
}

/* A shadow along the sidebar's RIGHT EDGE, so the menu reads as a panel sitting above the page
   rather than a column drawn on it.

   MudDrawer's Elevation cannot do this. Elevation maps to Material's shadow set, and every offset in
   it is VERTICAL — at elevation 8 the drawer gets
   `0 5px 5px -3px, 0 8px 10px 1px, 0 3px 14px 2px`. A downward shadow on a full-height panel is
   invisible at the side, which is the one edge anybody looks at, so raising Elevation changed the
   computed style and nothing a person could see.

   Scoped to the LEFT-positioned drawer: a right-hand drawer would need the offset mirrored, and
   nothing in this app has one, so it stays out of the selector rather than being guessed at. */
.mud-drawer.mud-drawer-pos-left {
    /* Two layers on purpose. The wide, soft one gives the panel its lift; the tight, darker one keeps
       a crisp boundary, which a single large blur loses — the edge goes vague and the sidebar starts
       to look out of focus. */
    box-shadow:
        10px 0 24px rgba(0, 0, 0, .14),
        2px 0 6px rgba(0, 0, 0, .09);

    /* ⚠ The part that carries DARK MODE, and it is a border rather than a second shadow for a
       reason. A shadow works by darkening what is behind it; over a near-black page there is almost
       nothing left to darken, so the same rule that lifts the panel on white does nothing at all on
       dark. A divider is theme-derived, so it stays visible either way.

       This also cannot be solved by branching on a class: MudBlazor 8 does not mark dark mode on
       <html> or <body> — measured, both are empty — it swaps CSS custom properties on :root. An
       earlier attempt here used `.mud-theme-dark` and was simply dead CSS. And prefers-color-scheme
       is the wrong signal too: the theme is a manual toggle kept in local storage, so the OS setting
       says nothing about which one this user is looking at. */
    border-right: 1px solid var(--mud-palette-divider);
}

/* The unread count sits on the bell rather than floating off it.

   MudBadge positions itself against the wrapped element's bounding box, and here that is a
   MudIconButton: 48x48 with 12px of padding around a 24px icon. So the badge anchors to the BUTTON's
   corner, which is 12px out and 12px up from the icon's own corner — measured at 22px right and 22px
   up from the icon's centre, which is what made it look detached.

   Translating by half the badge (10px of its 20px) puts its centre on the icon's top-right corner,
   which is the conventional Material position.

   ⚠ Done here, not by reducing the button's padding. That 48px box is the touch target — trimming it
   to reposition a badge would make the bell measurably harder to hit on a phone, which is a real cost
   for a cosmetic gain. */
.tl-bell-badge .mud-badge {
    transform: translate(-10px, 10px);
}

/* Data markers on a line chart.

   MudBlazor 9.7.0 already emits one <circle r="5.5"> per data point inside .mud-charts-line-series,
   but with opacity="0" — they exist only as hover targets for the tooltip. The supported switch,
   ShowDataMarkers, lives on LineChartOptions, which does NOT derive from ChartOptions and therefore
   cannot be passed to MudChart at all (it is a compile error, not a silent no-op). So the markers
   are revealed here instead.

   A CSS declaration always beats an SVG presentation attribute, so `opacity: 1` overrides the
   attribute without !important. `r` as a CSS property needs Chrome/Edge/Firefox or Safari 16+; where
   it is unsupported the markers simply stay at their native 5.5 radius, which still looks correct. */
.tl-chart-markers .mud-charts-line-series circle {
    r: 3;
    opacity: 1;
    fill: var(--mud-palette-surface, #fff);
    stroke: #3B7DDB;
    stroke-width: 2;
}

/* Stat tiles: label pinned at the top, figure centred in whatever space is left.

   The tiles are a fixed height so every card on the dashboard matches, which left the number
   stranded against the top edge of a mostly empty card. Centring is done with flex rather than a
   fixed margin so it stays correct if the tile height changes again. */
.tl-stat-tile {
    position: relative;
}

/* Taken out of flow and centred against the CARD, not against the space left under the label.
   In flow it sat 16px low, because the label consumed the top of the box before the figure was
   centred in the remainder. The label stays pinned top-left in normal flow above it. */
.tl-stat-tile .tl-stat-value {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0;
}

/* The detail dialog opened from the Policies / Quotations / Applications lists (RouteDetail).

   Nearly the whole viewport, but NOT FullScreen: a little backdrop showing on every side is what
   says "the list is still underneath, this closes" — full screen reads as a page you navigated to,
   and then the browser's Back button is the only obvious way out. The gutter is in vw/vh so it
   stays proportional rather than vanishing on a laptop and gaping on a wall display. */
.tl-route-detail-dialog {
    width: 94vw;
    max-width: 94vw;
    height: 92vh;
    max-height: 92vh;
}

/* The detail screens are written for a page, so they size to their content; without this the
   dialog's own body scrolls independently of the scroll container inside it and the header can be
   pushed out of reach. */
.tl-route-detail-dialog .mud-dialog-content {
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

/* ── Footer ──────────────────────────────────────────────────────────────────────────────────────
   The company's own details, on every page including login and no-access.

   ⚠ EVERY COLOUR IS THEME-DERIVED (var(--mud-palette-*)), never a literal and never branched on a
   dark-mode class. MudBlazor 8 does not mark dark mode on <html> or <body> — it swaps custom
   properties on :root — so a `.mud-theme-dark` rule here would be dead CSS, exactly as the drawer
   comment above records. Hardcoding #666 instead would read as grey-on-near-black in dark mode. */

/* ⚠⚠ PUSHED TO THE BOTTOM ON A SHORT PAGE, without ever being fixed.

   The Agent Code picker is half a screen tall, and the footer sat immediately under it with a third
   of the window empty below — which reads as content that failed to load rather than as the end of
   the page. `position: fixed` would solve that and create a worse problem: it would cover the
   bottom row of every long table in the application, and this app is mostly long tables.

   So MudMainContent becomes a column flex box at least as tall as the viewport, and the footer's
   `margin-top: auto` eats whatever space is left over. On a long page there is none, and the footer
   simply follows the content as before. Nothing is pinned, nothing overlaps.

   ⚠ 100vh with NO subtraction, and that is measured rather than assumed. MudMainContent starts at
   top: 0 and carries the app bar's height as its own padding-top — so its box already spans the
   whole viewport, and subtracting the bar again (the obvious-looking calc) leaves the footer exactly
   one app-bar short of the bottom: 64px of dead space, which is the very gap this rule exists to
   remove. Verified in the browser: padding-top 64px, top 0, viewport 950, so min-height 950. */
.mud-main-content {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

/* The page content takes the space it needs; the footer takes the rest. */
.mud-main-content > .mud-container {
    flex: 1 0 auto;
}

.tl-footer {
    flex-shrink: 0;
    margin-top: auto;
    border-top: 1px solid var(--mud-palette-divider);
    padding: 14px 24px 16px;
    background-color: var(--mud-palette-background-gray);
    color: var(--mud-palette-text-secondary);
    font-size: .8125rem;
    line-height: 1.6;
}

.tl-footer-inner {
    max-width: 1100px;
    margin: 0 auto;
    text-align: center;
}

/* Name and slogan share a line. */
.tl-footer-name {
    font-weight: 600;
    color: var(--mud-palette-text-primary);
    letter-spacing: .02em;
}

.tl-footer-slogan {
    font-style: italic;
}

/* The dots between parts. Quieter than the text they separate, so they read as punctuation rather
   than as content. */
.tl-footer-sep {
    margin: 0 8px;
    opacity: .45;
}

.tl-footer-address,
.tl-footer-contact {
    margin-top: 2px;
}

.tl-footer-link {
    color: inherit;
    text-decoration: none;
}

.tl-footer-link:hover {
    text-decoration: underline;
}

.tl-footer-legal {
    margin-top: 8px;
    /* Quieter than the rest: it is the least useful line on the page and should read that way. */
    opacity: .7;
    font-size: .75rem;
}

/* On a phone the footer is the last thing between the content and the bottom of the screen, so it
   gets less padding rather than pushing real content further out of reach. The min-height above
   needs no phone variant: 100vh is the viewport whatever the app bar's height. */
@media (max-width: 600px) {
    .tl-footer {
        padding: 12px 16px 14px;
    }

    /* Stacked rather than dotted: three parts separated by dots wrap mid-phrase on a narrow screen,
       which is harder to read than three short lines.
       ⚠ display: none, not visibility/opacity — a hidden separator that still occupies a line box
       leaves a visibly wider gap before the part after it than between the others. */
    .tl-footer-sep {
        display: none;
    }

    .tl-footer-headline .tl-footer-slogan,
    .tl-footer-contact a,
    .tl-footer-contact span {
        display: block;
        /* Even spacing between the stacked parts: without this the browser's default inline
           line-height leaves a wider gap wherever a separator used to sit. */
        margin: 0;
    }
}

/* The Policy menu's queue-count badges.

   ⚠ The nav link's text span is made a full-width flex row so the pill can sit hard right with
   margin-left:auto. That rule lands on EVERY nav link, badge or not — which is safe because a link
   with a single text node lays out identically either way, and is the only way to right-align
   something that MudBlazor renders inside the text span rather than beside it.

   ⚠ The pill does NOT shrink: flex-shrink 0, so a long Lao label wraps or truncates before the
   number does. A half-hidden count is worse than a wrapped label — it can be misread as a smaller
   one. */
.mud-nav-link .mud-nav-link-text {
    display: flex;
    align-items: center;
    width: 100%;
}

.tl-nav-count {
    margin-left: auto;
    flex-shrink: 0;
    min-width: 22px;
    padding: 0 6px;
    border-radius: 11px;
    background-color: var(--mud-palette-error);
    color: var(--mud-palette-error-text);
    font-size: 0.72rem;
    font-weight: 600;
    line-height: 18px;
    text-align: center;
}

/* Application wizard: room between the step headers and the step content. Without it the first
   field sat right under the scrollbar of the step strip. Scoped to this wizard's own class so
   no other MudStepper changes.
   ⚠ The selector carries .mud-stepper as well on purpose. MudBlazor sets
   `.mud-stepper .mud-stepper-content { padding: 0 24px }`, exactly as specific as
   `.application-wizard .mud-stepper-content`, and its stylesheet loads AFTER this one — so the
   shorter selector lost the tie and the padding computed to 0px. */
.mud-stepper.application-wizard .mud-stepper-content {
    padding-top: 24px;
}

/* ── Signature pad: bigger to sign on, same size when saved ──────────────────────────────────────
   ⚠⚠ Nothing in here ever sets a HEIGHT on the canvas. A canvas resolves height:auto from the ratio
   of its width/height attributes, so sizing by width alone is what keeps the on-screen box and the
   drawing buffer in proportion. Pin a height and signaturePad.js starts scaling x and y by different
   factors: the stroke still follows the finger, but the saved picture comes out stretched. */
.tl-signature-wrap {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
}

.tl-signature-stage {
    position: relative;
    display: inline-block;
    max-width: 100%;
}

/* The corner grip. ⚠ 28px, not the 8px a desktop resize handle would be: on a phone this is hit with
   a fingertip, and a target smaller than about 24px is one people miss and draw a stroke instead. */
.tl-signature-grip {
    position: absolute;
    right: 0;
    bottom: 0;
    width: 28px;
    height: 28px;
    cursor: nwse-resize;
    touch-action: none;
    background:
        linear-gradient(135deg, transparent 50%, var(--mud-palette-lines-default) 50%);
    border-right: 1px solid var(--mud-palette-primary);
    border-bottom: 1px solid var(--mud-palette-primary);
}

/* Full screen. ⚠ An overlay rather than the browser's Fullscreen API, because iOS Safari refuses
   requestFullscreen on anything but a <video> — and a phone is the device this exists for. */
/* ⚠⚠ THE PAD CANNOT GET TALLER WITHOUT TURNING SIDEWAYS, and that is not a styling choice — it is
   arithmetic. The saved picture is 500x150, so the box on screen has to keep that 3.33 shape or the
   signature comes out stretched. On a phone held upright, 96vw of width buys about 110px of height
   and no CSS can buy more.

   So on a portrait screen the pad is ROTATED a quarter turn: its long side runs down the screen
   instead of across it, and the signing area goes from roughly 374x112 to roughly 240x800 — seven
   times the room, with the saved bitmap untouched. The person turns their hand, not the app.

   ⚠ Rotation is a TRANSFORM, so the layout box stays the un-rotated one and the visible box is its
   bounding rect with width and height swapped. signaturePad.js has to undo that to know where a
   finger landed; see the note there. Changing the angle here without changing that is how the stroke
   ends up at right angles to the finger. */
.tl-signature-wrap--expanded {
    position: fixed;
    inset: 0;
    z-index: 2000;
    background: var(--mud-palette-surface);
    padding: 0;
    gap: 0;
}

/* ⚠ Pinned to the top and OUT of the signing area, not stacked above it in a flex column.
   Sitting directly above the pad, it was close enough that the heel of a signing hand reached
   Done — which closes the pad mid-signature. The stage below starts underneath it. */
.tl-signature-bar {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 56px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 0 16px;
    background: var(--mud-palette-surface);
    border-bottom: 1px solid var(--mud-palette-lines-default);
}

/* Everything below the bar, with the pad centred in it. ⚠ The 24px of extra top inset is the gap
   that keeps a signing hand away from Done. */
.tl-signature-wrap--expanded .tl-signature-stage {
    position: absolute;
    inset: 80px 8px 8px 8px;
    display: grid;
    place-items: center;
    max-width: none;
}

/* ⚠ Hidden in full screen, not removed from the page. Removing it is what broke resizing: the grip
   is wired up once by init(), so a node that comes and goes leaves the listeners on a node that has
   gone. It is also meaningless here — full screen is already as large as the pad can get, and once
   the pad is turned a quarter turn the grip would be sitting on the wrong corner. */
.tl-signature-wrap--expanded .tl-signature-grip {
    display: none;
}

/* Landscape — a laptop, or a phone turned on its side. No rotation needed: the screen is already
   the right shape, so the pad just grows to fit.
   ⚠ --tl-pad-ratio comes from the component, because the two pads in use are different shapes
   (one ratio today, but the variable is what stops a second size silently letterboxing).
   ⚠ !important is load-bearing, not laziness: the corner grip sets an INLINE width on the canvas,
   and an inline style beats a stylesheet rule — so without this, somebody who had dragged the pad
   narrow would press Full screen and get their small pad centred in an empty screen. */
.tl-signature-wrap--expanded .tl-signature-pad {
    width: min(96vw, calc((100vh - 120px) * var(--tl-pad-ratio, 3))) !important;
    max-width: 96vw;
}

/* Portrait — the case this whole block exists for. */
@media (orientation: portrait) {
    .tl-signature-wrap--expanded .tl-signature-pad {
        /* The width here is the pad's own long side, measured BEFORE the turn — so it is bounded by
           the viewport HEIGHT, and its short side (width / ratio) by the viewport width. */
        width: min(86vh, calc(92vw * var(--tl-pad-ratio, 3))) !important;
        max-width: none;
        transform: rotate(90deg);
    }
}

/* ── Signature slots: the tiles on the form ──────────────────────────────────────────────────────
   ⚠ A fixed shape, matching the pad's own 500x150. A tile that grew with its picture would make the
   row of signatures jump about as each one is signed. */
.tl-signature-slot-wrap {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 4px;
    width: 100%;
    max-width: 280px;
}

.tl-signature-slot {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    width: 100%;
    /* ⚠ Matches the buffer's 800x267. A tile of a different shape letterboxes the preview, which
       reads as the signature having been captured off-centre. */
    aspect-ratio: 800 / 267;
    padding: 8px;
    border: 1px dashed var(--mud-palette-lines-default);
    border-radius: 4px;
    background: var(--mud-palette-surface);
    color: var(--mud-palette-text-secondary);
    cursor: pointer;
}

.tl-signature-slot:hover:not(:disabled) {
    border-color: var(--mud-palette-primary);
    color: var(--mud-palette-primary);
}

.tl-signature-slot:disabled {
    cursor: default;
    opacity: 0.6;
}

/* Signed: a solid edge, so a filled slot is distinguishable from an empty one at a glance and not
   only by what is inside it. */
.tl-signature-slot--signed {
    border-style: solid;
    background: white;
}

.tl-signature-slot--signed img {
    width: 100%;
    height: 100%;
    object-fit: contain;
}

.tl-signature-slot-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

/* The signing surface inside the dialog. Dashed, because the box is an instruction — "sign here" —
   rather than a panel. */
.tl-signature-surface {
    display: flex;
    justify-content: center;
    width: 100%;
    padding: 8px;
    border: 1px dashed var(--mud-palette-lines-default);
    border-radius: 4px;
    background: white;
}

/* ⚠ The pad fills the surface it sits in rather than staying at its design width. The surface is as
   wide as the dialog, and a 600px pad centred in it would waste the room the dialog exists to
   provide.
   ⚠⚠ WIDTH ONLY — height stays auto, which a canvas resolves from the ratio of its width/height
   ATTRIBUTES. That is what keeps the box on screen and the drawing buffer in proportion; pin a height
   here and signaturePad.js starts scaling x and y by different factors, so the stroke follows the
   finger but the saved picture comes out stretched. */
/* ⚠⚠ THE WRAPPERS HAVE TO STRETCH TOO. The canvas is not a direct child of the surface — it sits
   inside .tl-signature-stage, which is inline-block and therefore sized by its own content. Setting
   width:100% on the canvas alone made it 100% of a box that was 100% of the canvas: circular, so it
   fell back to the canvas's design width and sat in the middle of the dashed surface with empty space on
   both sides. */
.tl-signature-surface .tl-signature-wrap,
.tl-signature-surface .tl-signature-stage {
    width: 100%;
    max-width: 100%;
    align-items: stretch;
}

.tl-signature-surface .tl-signature-pad {
    width: 100%;
    height: auto;
    max-width: 100%;
}

/* ⚠ No grip inside the dialog. The pad already fills the dialog, the dialog already has a
   full-screen button, and a drag handle on a touch device sitting over the signing area is one more
   thing to catch with the side of a hand. */
.tl-signature-surface .tl-signature-grip {
    display: none;
}

/* The signature dialog at full screen.
   ⚠⚠ Full screen is the DIALOG's, not the pad's. The pad's own overlay uses position:fixed, and
   MudDialog puts a transform on its container for the open animation — a transformed ancestor becomes
   the containing block for fixed positioning, so that overlay was sized against the viewport and then
   clipped to the dialog, with scrollbars round it. Growing the dialog has no such trap. */
.mud-dialog-fullscreen .mud-dialog-content {
    display: flex;
    flex-direction: column;
}

.tl-signature-surface--full {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Landscape at full screen: the whole surface, height following the ratio on its own.
   ⚠ No height cap. At a 3:1 ratio a full-width pad on a wide screen is a third as tall, which fits;
   capping it would leave the pad smaller than the space the user just asked for by pressing the
   button. */
.tl-signature-surface--full .tl-signature-pad {
    width: 100%;
    height: auto;
}

/* ⚠ Portrait is the case this exists for. A 600x200 box that fits a phone's WIDTH is about 120px
   tall — no CSS buys more, because the shape is fixed by what gets saved. Turned a quarter turn, its
   long side runs down the screen instead: roughly 260x780 rather than 360x120. The person turns
   their hand, not the app. signaturePad.js undoes the turn when mapping a finger to the bitmap. */
@media (orientation: portrait) {
    .tl-signature-surface--full .tl-signature-pad {
        /* ⚠ Still expressed as a WIDTH, because that is the pad's own long side before the turn — so
           it is bounded by the surface's HEIGHT (78vh) and its short side by the width (86vw). Height
           stays auto throughout; the turn is a transform and does not change the layout box. */
        width: min(78vh, calc(86vw * var(--tl-pad-ratio, 3)));
        height: auto;
        max-width: none;
        transform: rotate(90deg);
    }
}

/* Saving. ⚠ Over the tile, not instead of it: the signature is already drawn and visible, and this
   only says that the server has not confirmed it yet. A translucent veil keeps the drawing readable
   underneath, so nobody thinks Confirm discarded it. */
.tl-signature-slot-busy {
    position: absolute;
    inset: 0;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 4px;
    background: rgba(255, 255, 255, 0.65);
}

/* Page action bars (tl-actions) show ICONS ONLY on small screens — the same rule the app bar follows.
   Seven labelled buttons in the Policy Details header wrapped into tall two-line pills on a phone.
   Each button carries its label as title/aria-label, so the name is still there on hover and for a
   screen reader. ⚠ A button placed in a tl-actions bar needs a StartIcon, or it shrinks to nothing. */
@media (max-width: 959.98px) {
    .tl-actions .tl-action-label {
        display: none;
    }

    .tl-actions .mud-button-root {
        min-width: 0;
        padding-inline: 10px;
    }

    .tl-actions .mud-button-icon-start {
        margin-inline: 0;
    }
}
