html, body {
    font-family: 'Roboto', 'Helvetica Neue', Helvetica, Arial, sans-serif;
    margin: 0;
}

/* ============================================================================
   Task 3.5 — Redesign finish.
   All component CSS is built on the RangerUI MudTheme: colours are taken from
   the --mud-palette-* CSS variables the theme exports (NEVER hard-coded brand
   colours), so both light and dark themes recolour automatically. No theme
   palette is touched here — only component-level polish (radius, elevation,
   rhythm, hover) that MudBlazor parameters alone cannot express.
   ============================================================================ */

/* ---- Dashboard surface & grid rhythm --------------------------------------
   A faint background tint behind the gadget grid gives the cards something to
   "float" on in both themes (the grid container gets .dashboard-grid). */
.dashboard-grid {
    padding: 12px;
}

/* ---- Gadget cards ---------------------------------------------------------
   Full-height card with a soft resting elevation, a hairline border that reads
   in dark mode, and a lift-on-hover. A 3px accent strip animates in along the
   top edge on hover so the whole grid feels responsive without being noisy. */
.gadget-card {
    height: 100%;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: var(--mud-default-borderradius);
    transition: transform 160ms ease, box-shadow 160ms ease;
    position: relative;
    overflow: hidden;
}

.gadget-card::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 3px;
    background: var(--mud-palette-primary);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 200ms ease;
}

.gadget-card:hover {
    transform: translateY(-2px);
    box-shadow: var(--mud-elevation-8);
}

.gadget-card:hover::before {
    transform: scaleX(1);
}

/* Clickable gadgets get a slightly stronger affordance + visible focus ring. */
.gadget-card.cursor-pointer:focus-visible {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: 2px;
}

/* Card header: consistent typo + a thin divider rule under every title so the
   ten gadgets share one visual rhythm regardless of body content. */
.gadget-card .mud-card-header {
    padding-bottom: 8px;
    border-bottom: 1px solid var(--mud-palette-lines-default);
}

.gadget-card .mud-card-header .mud-typography {
    font-weight: 600;
    letter-spacing: .01em;
    color: var(--mud-palette-text-primary);
}

/* ---- User gadget ----------------------------------------------------------
   Centre the identity block so the (otherwise tall) card reads intentionally. */
.user-gadget {
    padding: 8px 0;
}

.user-avatar-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* ---- Half-pie gauge readout (Recruiting) ----------------------------------
   ROBUST CENTRING (review fix): the value used to be pinned with bottom:18%,
   which drifted whenever the chart height changed. The readout now lives in a
   flex overlay that fills the wrapper and parks the number in the lower-centre
   of the half ring via flex alignment + a fixed bottom offset, so it stays put
   at any height. */
.ranger-halfpie {
    position: relative;
}

.ranger-halfpie-value {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    padding-bottom: 14%;
    font-size: 2.25rem;
    font-weight: 700;
    line-height: 1;
    color: var(--mud-palette-primary);
    pointer-events: none;
}

.cursor-pointer {
    cursor: pointer;
}

/* Gadget details dialog reserves space so the chart doesn't jump while ApexCharts mounts. */
.gadget-dialog-content {
    min-height: 300px;
}

/* ---- GoalBar (day / week / month) -----------------------------------------
   Port of the legacy --bar-value / --label-value bars, now with rounded
   segments, taller tracks and proper threshold pins. The relative track is the
   positioning context for the absolutely positioned value/forecast fills, the
   goal marker and the bell ticks. Every percentage still comes from
   GoalCalculator (no inline numbers in the component). */
.ranger-goalbar {
    position: relative;
    margin: 12px 0 4px;
}

.ranger-goalbar-track {
    position: relative;
    height: 22px;
    margin: 8px 0;
    background: var(--mud-palette-action-default-hover);
    border-radius: 999px;
    overflow: hidden;
}

.ranger-goalbar-value {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    border-radius: 999px;
    background: linear-gradient(90deg,
        var(--mud-palette-primary-darken),
        var(--mud-palette-primary));
    transition: width 600ms cubic-bezier(.22,.61,.36,1);
}

.ranger-goalbar-forecast {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    border-radius: 999px;
    background: var(--mud-palette-secondary);
    opacity: 0.55;
    transition: width 600ms cubic-bezier(.22,.61,.36,1);
}

/* Goal marker: a crisp vertical pin aligned from the right edge (GoalLabelPercent),
   with a small cap so it reads as a deliberate target marker, not a glitch line. */
.ranger-goalbar-goal {
    position: absolute;
    top: -3px;
    bottom: -3px;
    width: 2px;
    background: var(--mud-palette-error);
    border-radius: 2px;
    z-index: 3;
}

.ranger-goalbar-goal::before {
    content: "";
    position: absolute;
    top: -3px;
    left: 50%;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--mud-palette-error);
    transform: translateX(-50%);
}

/* Bell thresholds: small filled "bells" (dots) sitting on the track, positioned
   from the left (BarPercent). Unreached = warning amber, reached = success green
   — replacing the old hard-to-read 2px ticks. */
.ranger-goalbar-bell {
    position: absolute;
    top: 50%;
    width: 9px;
    height: 9px;
    margin-left: -4px;
    border-radius: 50%;
    background: var(--mud-palette-warning);
    border: 2px solid var(--mud-palette-surface);
    transform: translateY(-50%);
    z-index: 2;
}

.ranger-goalbar-bell[data-bell-reached="True"] {
    background: var(--mud-palette-success);
}

/* GoalBar legend: a wrapping flex row of chip-like items with clear gaps, so the
   Sales / Forecast / Goal entries no longer collide as one run-on string
   (review "Trennzeichen" fix). Each item gets a colour dot keyed to its bar. */
.ranger-goalbar-legend {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 18px;
    font-weight: 600;
    font-size: .8125rem;
    margin-bottom: 4px;
    color: var(--mud-palette-text-primary);
}

.ranger-goalbar-legend > span {
    display: inline-flex;
    align-items: center;
}

.ranger-goalbar-legend > span::before {
    content: "";
    width: 9px;
    height: 9px;
    border-radius: 50%;
    margin-right: 6px;
    background: currentColor;
    opacity: .35;
}

.ranger-goalbar-legend > span:nth-child(1)::before { background: var(--mud-palette-primary); opacity: 1; }
.ranger-goalbar-legend > span:nth-child(2)::before { background: var(--mud-palette-secondary); opacity: 1; }
.ranger-goalbar-legend > span:nth-child(3)::before { background: var(--mud-palette-error); opacity: 1; }

/* Daily-goal single value label (no legend row) keeps the same weight/size. */
.ranger-goalbar-legend.is-single {
    font-size: 1rem;
}

.ranger-goalbar-legend.is-single > span::before {
    display: none;
}

/* ---- Messages gadget ------------------------------------------------------ */
.message-card {
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: var(--mud-default-borderradius);
    border-left: 3px solid var(--mud-palette-primary);
    background: var(--mud-palette-background-gray);
    transition: border-color 140ms ease, background 140ms ease;
}

.message-card:hover {
    border-left-color: var(--mud-palette-secondary);
}

/* ---- Anomalies gadget: make the big count read as a stat, not a stray digit. */
.anomalies-link {
    padding: 16px 0 8px;
    text-decoration: none;
}

.anomalies-link:hover .mud-typography {
    opacity: .85;
}

/* ---- Apps page tiles ------------------------------------------------------
   Brand tiles showing the REAL brand logo on a fixed WHITE logo plate, lift +
   accent-ring on hover. The white plate is theme-independent: most brand PNGs
   are authored for light backgrounds, so keeping the plate white (even in dark
   mode) guarantees the logo always reads, while the surrounding card inverts
   with the theme as usual. The "verify" tiles (admin page TO an app) get an
   accent top-border + an "Admin" chip so they are distinct from the app tile. */
.app-tile {
    position: relative;
    height: 100%;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: var(--mud-default-borderradius);
    transition: transform 160ms ease, box-shadow 160ms ease, border-color 160ms ease;
}

.app-tile:hover {
    transform: translateY(-3px);
    box-shadow: var(--mud-elevation-8);
    border-color: var(--mud-palette-primary);
}

.app-tile-content {
    min-height: 160px;
    position: relative;
}

/* White logo plate: keeps brand artwork legible in both light and dark themes.
   No border — the dark/grey hairline framed every brand logo (Nina: "schwarz-grauer
   Rahmen um die Logos"). The white plate alone is enough separation from the card; in
   dark mode it reads as a clean light panel against the inverted card with no outline. */
.app-tile-logo {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 84px;
    padding: 10px 16px;
    background-color: #ffffff;
    border-radius: var(--mud-default-borderradius);
}

.app-tile-logo-img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

/* Admin/"verify" treatment: accent top-border + a chip pinned to the corner. */
.app-tile-admin {
    border-top: 3px solid var(--mud-palette-secondary);
}

.app-tile-admin-chip {
    position: absolute;
    top: 8px;
    right: 8px;
    margin: 0;
    z-index: 1;
}

/* ---- Login page -----------------------------------------------------------
   A calm branded backdrop (radial brand wash on the theme surface) with a
   single elevated card. No imagery — pure theme colours so it inverts cleanly
   in dark mode. */
.login-shell {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background:
        radial-gradient(1200px 600px at 50% -10%,
            var(--mud-palette-primary-hover), transparent 60%),
        var(--mud-palette-background-gray);
}

.login-card {
    width: 100%;
    border-radius: 16px;
    border: 1px solid var(--mud-palette-lines-default);
}

.login-brand {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    margin-bottom: 8px;
}

.login-brand-mark {
    width: 56px;
    height: 56px;
    border-radius: 16px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 800;
    font-size: 1.4rem;
    color: var(--mud-palette-primary-text);
    background: linear-gradient(135deg,
        var(--mud-palette-primary),
        var(--mud-palette-primary-darken));
    box-shadow: var(--mud-elevation-4);
}

/* ---- Embedded pages (Products / Ranger TV) --------------------------------
   Full-bleed iframe under the 64px app bar, with a themed surface behind so the
   loading state and any letterboxing read as part of the app, not a void. */
.embed-shell {
    height: calc(100vh - 64px);
    background: var(--mud-palette-background-gray);
}

.embed-frame {
    width: 100%;
    height: 100%;
    border: 0;
    display: block;
}

.embed-loading {
    display: flex;
    align-items: center;
    justify-content: center;
    height: calc(100vh - 64px);
}

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

.invalid {
    outline: 1px solid red;
}

.validation-message {
    color: red;
}

#blazor-error-ui {
    color-scheme: light only;
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

    #blazor-error-ui .dismiss {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }

.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."
    }

.loading-spinner-custom {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
}

    .loading-spinner-custom span {
        display: inline-block;
        vertical-align: middle;
        width: 1.0em;
        height: 1.0em;
        margin: .19em;
        background: #c52e8a;
        border-radius: .6em;
        animation: loading 1s infinite alternate;
    }

        .loading-spinner-custom span:nth-of-type(2) {
            background: #f08dcb;
            animation-delay: 0.2s;
        }

        .loading-spinner-custom span:nth-of-type(3) {
            background: #5aa789;
            animation-delay: 0.4s;
        }

        .loading-spinner-custom span:nth-of-type(4) {
            background: #8ac9c6;
            animation-delay: 0.6s;
        }

        .loading-spinner-custom span:nth-of-type(5) {
            background: #589bd6;
            animation-delay: 0.8s;
        }

        .loading-spinner-custom span:nth-of-type(6) {
            background: #8acde9;
            animation-delay: 1.0s;
        }

@keyframes loading {
    0% {
        opacity: 0;
    }

    100% {
        opacity: 1;
    }
}
