html,
body {
    margin: 0;
    padding: 0;
    min-height: 100%;
    font-family: var(--font-base);
    background-color: var(--color-bg-surface);
    color: var(--color-text-primary);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 {
    font-family: var(--font-display);
    font-weight: 600;
    color: var(--color-text-primary);
}

h1:focus {
    outline: none;
}

a {
    color: var(--color-accent);
    text-decoration: none;
}

a:hover {
    text-decoration: underline;
}

code {
    font-family: var(--font-monospace);
    color: var(--color-accent);
}

.validation-message {
    color: var(--color-danger);
}

#blazor-error-ui {
    color-scheme: light only;
    background: #fbe9a0;
    color: #1f1a12;
    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: #b32121;
    padding: 1rem 1rem 1rem 1rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "Ein Fehler ist aufgetreten.";
    }

.loading-progress {
    position: fixed;
    top: 50%;
    left: 50%;
    width: 7.5rem;
    height: 7.5rem;
    margin: -3.75rem 0 0 -3.75rem;
}

    .loading-progress circle {
        fill: none;
        stroke-width: 0.5rem;
        stroke-linecap: round;
        transform-origin: 50% 50%;
        transform: rotate(-90deg);
    }

    .loading-progress circle:first-child {
        stroke: var(--color-border-strong);
    }

        .loading-progress circle:last-child {
            stroke: var(--color-accent);
            stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
            transition: stroke-dasharray 0.1s ease-in-out;
        }

.loading-progress-text {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    font-weight: 600;
    font-size: 1rem;
    letter-spacing: 0.01em;
    color: var(--color-text-secondary);
}

    .loading-progress-text:after {
        content: var(--blazor-load-percentage-text, "");
    }

/*
  Fluent's accent palette.

  Fluent UI ships a blue accent and derives every accent-coloured surface from it — primary
  buttons, focus rings, active navigation markers, empty-state icons. That blue is not this
  product's colour: the reference design puts the dark brand green on every primary action.
  Overriding the design tokens here means the 37 files that use Appearance.Accent inherit the
  right colour instead of each carrying its own class.

  Set globally rather than through FluentDesignTheme so it also covers the setup and public
  review layouts, which deliberately have no shell.
*/
:root {
    --accent-base-color: #014B43;

    --accent-fill-rest: var(--color-brand-header);
    --accent-fill-hover: var(--color-brand-header-hover);
    --accent-fill-active: var(--color-brand-header-hover);
    --accent-fill-focus: var(--color-brand-header);
    --accent-foreground-rest: var(--color-brand-header);
    --accent-foreground-hover: var(--color-brand-header-hover);
    --accent-foreground-active: var(--color-brand-header-hover);
    --accent-stroke-control-rest: var(--color-brand-header);
    --foreground-on-accent-rest: var(--color-text-on-brand);
    --foreground-on-accent-hover: var(--color-text-on-brand);
    --foreground-on-accent-active: var(--color-text-on-brand);
}

/*
  The web components read the tokens above through their own shadow styles, which do not always
  pick up a :root override. Painting the host element directly is the reliable part.
*/
fluent-button[appearance="accent"]::part(control) {
    background: var(--color-brand-header);
    color: var(--color-text-on-brand);
    border-color: var(--color-brand-header);
}

fluent-button[appearance="accent"]:hover::part(control) {
    background: var(--color-brand-header-hover);
    border-color: var(--color-brand-header-hover);
}

/*
  Secondary actions — Outline and Neutral — shipped a fully transparent fill and a hairline in
  rgb(214, 214, 214), which is the lightness of the app background itself. On any ordinary page the
  button was therefore a label with nothing around it: measured on the dashboard, "New project" had
  `background: rgba(0, 0, 0, 0)` over `#D6DCDC` with a border the eye cannot separate from it.

  They get the elevated surface and a border that exists. Painting ::part(control) rather than setting
  tokens for the same reason the accent rule above does: the shadow styles do not reliably pick up a
  :root override.

  Buttons that sit on a *dark* surface opt out with .on-dark-surface — there the page is the brand
  green and a light fill would be the thing that looks wrong.
*/
fluent-button[appearance="outline"]:not(.on-dark-surface)::part(control),
fluent-button[appearance="neutral"]:not(.on-dark-surface)::part(control) {
    background: var(--color-bg-elevated);
    border-color: var(--color-border-strong);
    color: var(--color-text-primary);
}

fluent-button[appearance="outline"]:not(.on-dark-surface):hover::part(control),
fluent-button[appearance="neutral"]:not(.on-dark-surface):hover::part(control) {
    background: var(--color-bg-selected);
    border-color: var(--color-brand-header);
}

/* On the brand-green surfaces the same buttons stay ghosts: an outline in white over the green. */
fluent-button.on-dark-surface::part(control) {
    background: transparent;
    border-color: var(--color-on-stage-border);
    color: var(--color-text-on-brand);
}

fluent-button.on-dark-surface:hover::part(control) {
    background: var(--color-on-stage-tint);
    border-color: var(--color-text-on-brand);
}

/* Danger actions keep the brand red rather than the green. */
fluent-button.danger-button::part(control) {
    background: var(--color-brand-red);
    border-color: var(--color-brand-red);
    color: var(--color-text-on-brand);
}

/*
  FluentIcon writes `style="fill: var(--accent-fill-rest)"` straight onto the SVG, and Fluent sets
  that variable closer to the element than :root, so neither the accent override above nor a plain
  rule reaches it — a green button kept a blue plus sign, the bell stayed blue on the green header,
  and the mobile tab icons were blue too.

  Making every icon inherit currentColor is both simpler and more correct than chasing contexts:
  an icon should take the colour of the text it sits next to. Fluent's icons are single-path and
  monochrome, so nothing is lost. An inline style from a third-party component is the one case
  !important genuinely exists for.
*/
svg {
    fill: currentColor !important;
}

/*
  Set on <html> while the public home page's preview notice is up. It lives here rather than in the
  page's isolated stylesheet because CSS isolation cannot reach the document element, and the notice
  has to stop the page behind it from scrolling — a notice that can be scrolled past is a notice
  that gets missed.
*/
html.home-scroll-locked {
    overflow: hidden;
}
