/*
 * Recipient-facing styles for the download pages (Figma IP-2130).
 *
 * Everything the design system already draws is left to it: the password field is a MudStaticTextField and
 * the submit is a MudStaticButton, both themed from Ranger.Blazor.Components.Core. What is here is the
 * page-level layout the library has no opinion about - the centred card, the notices, the file rows, the
 * footer.
 *
 * The token block below aliases the MudTheme that MudThemeProvider emits, so nothing hardcodes a brand value
 * outside :root and theming or per-client branding stays a token swap.
 */

/*
 * Open Sans, self-hosted. Ranger.Blazor.Components.Core's bundle pulls Open Sans from Google Fonts via an
 * @import (fonts.googleapis.com) - which sends every recipient's IP to Google, and only fetches 400 and 600,
 * so the design's Bold 700 heading was being faux-bolded. Shipping the woff2 locally (Latin subset, which
 * covers German) fixes both: a real 700, and no third-party font request. That library @import is blocked by
 * the CSP (style-src/font-src 'self') set in WebApplicationExtensions, so it never reaches Google. The files
 * live under wwwroot/fonts and are served at /fonts/... (url() below is relative to this sheet in /css).
 */
@font-face {
    font-family: "Open Sans";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("../fonts/open-sans-400.woff2") format("woff2");
}

@font-face {
    font-family: "Open Sans";
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url("../fonts/open-sans-600.woff2") format("woff2");
}

@font-face {
    font-family: "Open Sans";
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url("../fonts/open-sans-700.woff2") format("woff2");
}

/* The file-list PDF glyph, as a self-hosted icon webfont. The design draws PDF rows with Font Awesome's
   "file-pdf" (Font Awesome 7 Pro in Figma; the Solid glyph is identical in Font Awesome Free, which is what
   is subsetted and shipped here - one glyph, ~0.5 KB). A font glyph, not an inline SVG: the browser
   rasterises it fresh at 16px, instead of downscaling a traced path by a fractional 0.889 onto sub-pixels,
   so it renders crisp - the way Figma renders it. Self-hosted, so it needs no Font Awesome kit and makes no
   third-party request from a recipient's browser (the library's own kit stays blocked by the CSP). */
@font-face {
    font-family: "odds-icon";
    font-style: normal;
    font-weight: 900;
    /* block, not swap: an icon slot must never flash a fallback letter. The file is same-origin and ~0.5 KB,
       so it is there at once and the block period is imperceptible. */
    font-display: block;
    src: url("../fonts/fa-file-pdf.woff2") format("woff2");
}

:root {
    /* Aliases, not copies: MudThemeProvider emits the brand palette as --mud-palette-* from the theme in
       Ranger.Blazor.Components.Core, so a change there lands here without this file being touched. Each
       fallback is the value that theme currently holds, which keeps the page sensible if the provider is
       ever missing from a shell rather than leaving it unstyled.

       Primary (orange) is never used for a negative state - the design system says so explicitly - and the
       design uses Secondary (navy) for the primary action. */
    --odds-primary: var(--mud-palette-primary, #ff5a10);
    --odds-secondary: var(--mud-palette-secondary, #08204a);
    --odds-secondary-darken: var(--mud-palette-secondary-darken, #061735);
    --odds-tertiary: var(--mud-palette-tertiary, #76849b);

    /* Denotive colours, for states only. */
    --odds-info: var(--mud-palette-info, #3a5da5);
    --odds-success: var(--mud-palette-success, #058a5e);
    --odds-warning: var(--mud-palette-warning, #f18f11);
    --odds-error: var(--mud-palette-error, #d62c0a);

    /* The badge tints on the link-state pages: the denotive colour at 6% alpha over the surface, which is
       exactly what the design's badge SVGs carry (fill-opacity 0.06 on the circle). Kept as their own tokens
       because they are much lighter than the notice tints above. */
    --odds-warning-badge: rgba(241, 143, 17, 0.06);
    --odds-error-badge: rgba(214, 44, 10, 0.06);

    /* Surfaces and text. */
    --odds-background: var(--mud-palette-background, #e6e9ed);
    --odds-surface: var(--mud-palette-surface, #ffffff);
    --odds-text-primary: var(--mud-palette-text-primary, rgba(0, 0, 0, 1));
    --odds-text-secondary: var(--mud-palette-text-secondary, rgba(0, 0, 0, 0.537));
    --odds-lines-inputs: var(--mud-palette-lines-inputs, #d5d5d5);
    /* The grey the design uses for the file size and the provider disclaimer. Sampled off the Figma export as
       #757575, which is the theme's GrayDark - not --mud-palette-text-secondary, whose alpha happens to land
       one unit away. Same reasoning as everything else here: take the value from the source. */
    --odds-text-muted: var(--mud-palette-gray-dark, #757575);
    --odds-divider: var(--mud-palette-divider, #d5d5d5);
    /* The download-control BORDERS - the per-file download circle and the "download everything" button - are
       #000000 at 40%, read off the Figma nodes. Deliberately darker than the --odds-divider / --odds-lines-inputs
       #d5d5d5 used for the row separators, the field and the request-new box: the download controls read a step
       stronger than those hairlines. The glyph inside them is full-strength #000000, not this (see
       .odds-download-glyph). */
    --odds-download-mark: rgba(0, 0, 0, 0.4);

    --odds-radius: var(--mud-default-borderradius, 10px);
    /* 12px, read off the Figma node (Mudpaper_Whitebox), not estimated from a screenshot - and deliberately
       not --mud-default-borderradius, which is 10px: the card overrides it, the controls inside do not. */
    --odds-radius-card: 12px;

    /* The shell's max width. 586px is the card's fixed width (read off the Figma Mudpaper_Whitebox:
       "Fixed 586px"), and the new design uses this one width for every screen - login, state and file list -
       on every device, so there is no per-screen override. */
    --odds-shell-max: 586px;

    /* Open Sans is the Ranger brand font, and the library's CSS bundle now ships the @font-face and the
       files with it - so this resolves locally, with no request to a font CDN from a recipient's browser. */
    --odds-font: "Open Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

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

/* Painting html itself in the page's grey (with color-scheme: light, as this UI is light-only) means the brief
   inter-page paint on a navigation is that grey rather than the browser's white default. */
html {
    background: var(--odds-background);
    color-scheme: light;
}

body {
    margin: 0;
    padding: 24px 16px 48px;
    background: var(--odds-background);
    color: var(--odds-text-primary);
    font-family: var(--odds-font);
    font-size: 16px;
    line-height: 1.5;
    /* One centred column at every breakpoint - one fixed width now (see --odds-shell-max), so there is one
       layout and no media query. Centred vertically as well as horizontally: the design places the card in the
       middle of the viewport rather than pinned to the top. justify-content stays "center" even when the
       content is taller than the viewport because the 24px/48px padding keeps a gutter and the page just
       scrolls. */
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
}

/* The centred column width: 586px for every screen (see --odds-shell-max). 586px also happens to match the
   library's own static card (MfaVerificationCardStatic), so the cards land on geometry the design system
   already assumes. */
main {
    width: 100%;
    max-width: var(--odds-shell-max);
}

/* The supplied wordmark, at its own aspect ratio. max-width keeps it inside a narrow viewport rather than
   forcing the page to scroll sideways. */
.odds-logo {
    display: block;
    margin: 24px auto 20px;
    height: 42px;
    width: auto;
    max-width: 100%;
}

.odds-card {
    /* Padding and the 20px rhythm both come from the Figma node's auto-layout (padding 16, gap size-20)
       rather than from per-child margins - so the spacing between the heading, the intro, the form and the
       provider notice is stated once instead of maintained on each of them. MudPaper supplies the surface
       colour; the radius overrides its default. */
    border-radius: var(--odds-radius-card);
    padding: 16px;
    display: flex;
    flex-direction: column;
    gap: 20px;
}

/* The brand accent bar (the Telekom skin): a 16px coloured cap across the very top of the card. BrandCardHeader
   renders it only when the active brand sets an accent colour, and supplies that colour inline; the Ranger skin
   omits the element, so none of the Telekom-only card rules below apply to it. Positioned absolutely so it
   spans the full card width and overlays the top without taking a flex slot; its rounded top corners match the
   card's own radius. */
.odds-accent-bar {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 16px;
    border-radius: var(--odds-radius-card) var(--odds-radius-card) 0 0;
}

/* Telekom-skin card geometry, scoped by the presence of the accent bar so the Ranger card (padding 16, above)
   is untouched. Padding is the design's "Grid/Margin", which is responsive: 16 on mobile, 48 from tablet up
   (measured off the nodes - mobile inner content ~325 of 361, desktop 490 of 586). The top adds the 16px bar
   height on top of that. position:relative anchors the absolute accent bar. This one media query is the only
   one in the sheet, and it is here because the token genuinely changes, not because the layout does. */
.odds-card:has(> .odds-accent-bar) {
    position: relative;
    padding: 32px 16px 16px;
}

@media (min-width: 600px) {
    .odds-card:has(> .odds-accent-bar) {
        padding: 64px 48px 48px;
    }
}

/* The brand lockup inside the card header (the Telekom skin). Left-aligned at the design's measured size
   (the "Im Auftrag der Telekom - Logo" node is 133x43, same 112x36 aspect as the asset). align-self:flex-start
   keeps it from being stretched by the card's flex layout - which would otherwise blow it to full width and
   centre the artwork inside. Explicit width/height rather than width:auto because the asset carries no viewBox,
   so an auto width collapses to zero. */
.odds-card-logo {
    display: block;
    align-self: flex-start;
    width: 133px;
    height: 43px;
}

.odds-card h1 {
    margin: 0;
    /* 24px, which is what the mobile and tablet frames measure. The one place the design is not a single
       layout: the desktop frame steps the heading up to 32px, hence the query below. Everything else - the
       card, the spacing, the type - is identical across all three. */
    font-size: 24px;
    line-height: 1.2;
    /* The design's spacing-h2 token is 0; the inherited theme typography otherwise adds ~0.17px, which loosens
       the heading and shifts wrapping away from the Figma. Reset it (same for the body below). */
    letter-spacing: normal;
}

/* The card's own max-width is 586px, so this fires exactly when the column has stopped growing and the page
   has become the desktop composition. */
@media (min-width: 700px) {
    .odds-card h1 {
        font-size: 32px;
    }
}

.odds-card p {
    margin: 0;
    /* spacing-body1 token is 0 (see the heading note above). */
    letter-spacing: normal;
}

/* The field's helper/error line (e.g. "Das Passwort ist nicht korrekt …"). MudBlazor renders it at 12px with
   ~0.4px tracking - its own caption default - but the design's caption token is 10px / 12px line-height / 0
   tracking (Size/caption, Line Height/lineheight-caption, Spacing/spacing-caption on the Figma node). Match it
   so the error message sits like the Figma. */
.odds-card .mud-input-helper-text {
    font-size: 10px;
    line-height: 12px;
    letter-spacing: normal;
}

/* The session notice's headline (e.g. "Sitzung beendet") over its body. The design's MudAlert renders a bold
   headline above the message; MudBlazor lays its message inline, so make the title a block so the body wraps
   beneath it. */
.odds-alert-title {
    display: block;
    margin-bottom: 2px;
    font-weight: 700;
}

/* ── Form ── */

/* The field itself is a MudStaticTextField, so its border, label and reveal adornment are the design
   system's - the rules that used to draw them here were deleted rather than left to fight it.
 *
 * Its focus treatment is the library's too, and deliberately so: the Ranger bundle hides MudBlazor's notched
 * outline (`.mud-input-outlined .mud-input-outlined-border { display: none }`) and draws its own 1px border on
 * .mud-input, tinted with the theme's Primary on focus. That is the design system's decision for every Ranger
 * app, so it is left alone here rather than repainted per page.
 *
 * The field is Variant.Filled with a Label (not a Placeholder) - see LoginPage for why: Filled floats the label
 * into the field's own top inset, which the hidden notch of an outlined field would leave nowhere to sit. */

/* No asterisk on the label. Required="true" is what actually emits the HTML `required` attribute (splatting
   it through UserAttributes is silently dropped), but it also makes MudBlazor append a "*" to the label - and
   the design shows none. With a single field on the page, "required" is not information the recipient is
   missing, and the error line below says it plainly if they submit empty anyway. Only the marker is dropped,
   not the validation. */
.odds-card .mud-input-control.mud-input-required > .mud-input-control-input-container > .mud-input-label::after {
    content: none;
}

/* The submit button is always shown active - the design draws it filled (magenta) even over an empty field.
   There is no disabled look: an empty submit simply posts and the server answers with the field error (?empty),
   and `novalidate` on the form keeps the browser's native validation bubble away. */

/* The form is one flex child of the card, so the card's own gap does not reach inside it - without this the
   field and the button sit flush against each other. Same 20px rhythm, one level down. */
.odds-card form {
    display: flex;
    flex-direction: column;
    gap: 20px;
}

.odds-button {
    display: block;
    width: 100%;
    border: 0;
    border-radius: var(--odds-radius);
    background: var(--odds-secondary);
    color: #fff;
    padding: 14px 20px;
    font: inherit;
    font-weight: 600;
    cursor: pointer;
    text-align: center;
}

.odds-button:hover {
    background: var(--odds-secondary-darken);
}

/* The secondary action. Outlined, so "download everything" reads as weaker than the per-file buttons next
   to it - which is what the design intends. */
.odds-button-outline {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    width: auto;
    /* Tighter than the primary button so the label fits on one line at 375px - the icon otherwise ends up
       stranded at the far left while the text wraps beneath it. Narrower viewports still wrap, which is a
       fair way for it to give. */
    padding: 12px 16px;
    border: 1px solid var(--odds-download-mark);
    background: transparent;
    color: var(--odds-text-primary);
    text-decoration: none;
}

/* No visible hover on this one: the design draws the "download everything" button without a hover state. It
   still carries .odds-button, though, whose :hover darkens the background to navy - so the hover has to be
   held at the resting transparent explicitly, or that inherited rule takes over and the button turns navy.
   (The per-file download control does change on hover; this button does not.) */
.odds-button-outline:hover {
    background: transparent;
}

/* 14px, not the inherited 16: the design draws this secondary action smaller than the body text. */
.odds-actions .odds-button-outline {
    font-size: 14px;
}

/* ── Link states (expired, locked, unknown) ── */

/* 64px circle, the size the Figma node measures, with the 32px glyph the export names. */
.odds-state-badge {
    width: 64px;
    height: 64px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    /* Never stretched by the card's flex column, which would turn the circle into a pill. */
    flex: 0 0 auto;
}

.odds-state-badge .mud-icon-root {
    font-size: 32px;
}

/* The design's own glyph, rendered as an <img> inside the badge (the badge draws the circle). 32px to match
   the MudIcon fallback above; the SVG carries its own colour, so no fill rule here. */
.odds-state-badge .odds-state-icon {
    display: block;
    width: 32px;
    height: 32px;
}

.odds-state-warning {
    background: var(--odds-warning-badge);
    color: var(--odds-warning);
}

.odds-state-error {
    background: var(--odds-error-badge);
    color: var(--odds-error);
}

/* 24px, not the 32px of the login heading - the design sets these pages a step smaller. */
.odds-state-heading {
    margin: 0;
    font-size: 24px;
    line-height: 1.2;
}

/* The "Neuen Link anfordern" box: outlined rather than tinted, so it reads as the way out rather than as a
   second warning. 1px and the line colour are what the design draws. */
.odds-state-hint {
    border: 1px solid var(--odds-lines-inputs);
    border-radius: 12px;
    padding: 20px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.odds-state-hint-title {
    font-weight: 700;
}

/* ── File list ── */

.odds-files {
    list-style: none;
    margin: 0;
    padding: 0;
}

.odds-files li + li {
    border-top: 1px solid var(--odds-divider);
}

.odds-files a {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 0;
    color: var(--odds-text-primary);
    text-decoration: none;
}

/* The row's hover, taken from the design's MudIconButton hover state: the download control's ring goes to
   full black (up from its resting #000 40%) while the glyph inside softens to the secondary grey - the
   outline "fills in" as the mark recedes. The name and size are left as they are; the design does not
   recolour them. The whole row is the link, so the hover fires from anywhere on it - which is where the
   pointer is when reaching for the control on the right. */
.odds-files a:hover .odds-file-download {
    border-color: var(--odds-text-primary);
}

.odds-files a:hover .odds-download-glyph {
    color: var(--odds-text-secondary);
}

/* The brief cooldown after a download is started: the link greys out and stops responding for a second or
   two, so an impatient double-click cannot fire a second request. download-cooldown.js sets the attribute;
   with the script off nothing sets it and the links behave as before. The server-side rate limit, not this,
   is the actual guard. Attribute-based and element-agnostic, so it covers the file rows and the ZIP button
   alike. */
[data-cooling] {
    opacity: 0.5;
    pointer-events: none;
    cursor: default;
}

/* The file glyph. Shared by both kinds: a PDF (.odds-file-icon-pdf, the design's Font Awesome file-pdf as a
   font glyph) and the neutral fallback for anything else (a MudBlazor inline SVG). Both carry the design's
   text-secondary colour - #000000 at 54% - and neither is allowed to stretch on the row's flex line. */
.odds-file-icon {
    flex: 0 0 auto;
    color: var(--odds-text-secondary);
}

/* The PDF glyph itself, drawn from the self-hosted icon webfont declared above. An 18px-wide slot (the
   design's icon frame) with the 16px glyph centred in it, which is the size Figma measures - its own visible
   ink comes out at ~14.78x15.22, matching the design exactly. The colour is inherited from .odds-file-icon. */
.odds-file-icon-pdf {
    width: 18px;
    font-family: "odds-icon";
    font-weight: 900;
    font-size: 16px;
    line-height: 1;
    text-align: center;
}

.odds-file-icon-pdf::before {
    content: "\f1c1";
}

.odds-file-text {
    display: flex;
    flex-direction: column;
    /* min-width lets a long file name wrap instead of pushing the download circle off the row. */
    min-width: 0;
}

.odds-file-name {
    overflow-wrap: anywhere;
}

/* The design's size line goes here, under the name - added together with whatever makes the name and size
   available to this page. */
.odds-file-size {
    font-size: 12px;
    color: var(--odds-text-muted);
}

/* The circular download affordance from the design, now holding a real icon. A span, not a button: the whole
   row is already the link, and an interactive element inside an anchor is invalid markup. */
.odds-file-download {
    margin-left: auto;
    flex: 0 0 auto;
    width: 30px;
    height: 30px;
    border: 1px solid var(--odds-download-mark);
    border-radius: 50%;
    display: grid;
    place-items: center;
}

/* The design's download glyph (FileList renders it inline). Sized off its 11x12 art, and drawn full-strength
   #000000 (the design's icon is 100%, unlike the 40% control borders around it): fill:currentColor picks up the
   row's / button's own text colour, which is text-primary. flex:0 0 auto keeps it from being stretched when it
   sits on the button's flex row. */
.odds-download-glyph {
    flex: 0 0 auto;
    width: auto;
    height: 11.5px;
}

/* A file whose blob has vanished: same row geometry as a download link, but greyed and inert - there is no
   anchor, no download circle and no hover, because there is nothing to fetch. The name still shows (see
   FileList) so the document does not silently disappear; "Nicht mehr verfügbar" takes the size line's place. */
.odds-file-unavailable .odds-file-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 0;
    color: var(--odds-text-muted);
}

.odds-file-unavailable .odds-file-name {
    color: var(--odds-text-muted);
}

.odds-actions {
    text-align: center;
}

/* Logout sits outside the card in the design, and reads as a link rather than a button. */
.odds-logout {
    margin: 20px 0 0;
    text-align: center;
}

.odds-logout button {
    border: 0;
    background: transparent;
    padding: 8px;
    font: inherit;
    /* Bold, 14px and NOT underlined - checked against the design, which draws it that way. It reads as an
       action rather than a link, which is what it is. */
    font-size: 14px;
    font-weight: 600;
    color: var(--odds-text-primary);
    cursor: pointer;
}

/* ── Provider notice (inside the card) ── */

.odds-provider {
    display: flex;
    align-items: center;
    gap: 16px;
    /* No top margin: the card's own gap already separates it. Only the rule and the space under it. */
    padding-top: 20px;
    border-top: 1px solid var(--odds-divider);
}

.odds-provider p {
    /* Overrides the card's paragraph spacing: this one sits on a flex row, not in the text flow. */
    margin: 0;
    font-size: 10px;
    line-height: 1.4;
    color: var(--odds-text-muted);
}

.odds-provider img {
    /* Never squeezed by the text beside it, and never scaled up past its own size. */
    flex: 0 0 auto;
    margin-left: auto;
    height: 36px;
    width: auto;
}

/* Telekom skin only: its provider lockup is the Ranger logo, which the design sizes smaller than the Ranger
   skin's Telekom lockup - 25px (the "Logo Section" node is 95x25) vs 36px. Scoped by the accent bar. */
.odds-card:has(> .odds-accent-bar) .odds-provider img {
    height: 25px;
}

/* ── Footer ── */

.odds-footer {
    width: 100%;
    max-width: var(--odds-shell-max);
    margin-top: 20px;
    text-align: center;
    /* 12px and full-strength text, both taken from the design - not the muted grey the disclaimer uses. The
       legal links are the one thing on the page that must not read as fine print. */
    font-size: 12px;
    color: var(--odds-text-primary);
}

.odds-footer p {
    margin: 0 0 6px;
}

.odds-footer a {
    color: inherit;
    margin: 0 8px;
    /* Underlined, as the design draws them. MudBlazor's reset strips link underlines globally, so this puts
       it back rather than adding something new. */
    text-decoration: underline;
}
