/* App-level rules on top of the design system (css/tokens.css + css/ds-components.css).
   Bootstrap is no longer served, so only the classes Blazor itself emits are styled here;
   typography, colour and components all come from the design system. */

html, body {
    height: 100%;
}

/* Smooth the dark/light toggle instead of an instant, jarring colour swap. Scoped to the
   properties tokens.css actually changes per theme; skipped for anyone who asked for less
   motion. */
@media (prefers-reduced-motion: no-preference) {
    * {
        transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
    }
}

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

/* A brand profile with its own key art (BrandingOptions.HeroBackgroundImage, set in
   MainLayout.razor) gets a true page backdrop behind every page, not just the hero:
   position:fixed behind everything (z-index:-1), sized to the viewport, so it reads as a <body>
   background rather than a layout element with its own height — it doesn't scroll away, and
   nothing downstream needs to account for "where the image ends". The gradient layered with it
   fades the art in from the top, where the navbar sits, rather than a hard edge at y=0; below
   that it stays fully visible behind whatever's on the page — solid panel/card backgrounds cover
   it wherever there's real content, and it shows through as plain visual texture in the gaps
   around sparser pages, which was the point of making it page-wide rather than hero-only.
   Dark theme only: a light-mode version of this image didn't read well, so light theme shows no
   backdrop and falls back to a plain surface.
   --nav-height (nav-height.js, a ResizeObserver on .m-nav) is the navbar's real rendered height,
   not a guess: a fixed fade distance read fine with the nav on one line, but the nav wraps to two
   (sometimes three) lines on a narrow screen, so the fade had already finished revealing the full
   -brightness art well above the nav's actual bottom edge, right where its own links/buttons sit.
   The 90px fallback only matters for the instant before the script's first ResizeObserver
   callback fires (or if JS is disabled). */
.m-home-backdrop {
    position: fixed;
    inset: 0;
    z-index: -1;
    background-image: linear-gradient(to bottom, var(--bg) 0, transparent calc(var(--nav-height, 90px) + 160px)), var(--home-hero-image);
    background-size: cover;
    /* The art has a calmer "dead zone" at its own center meant for content to sit over -
       center/center keeps that lined up with the viewport's center at any size, rather than
       center/top, which kept the image's top edge fixed and let the dead zone drift away from
       centered as the viewport's aspect ratio changed. */
    background-position: center;
    background-repeat: no-repeat;
}

[data-theme="light"] .m-home-backdrop {
    display: none;
}

/* The hero's content sits on that fixed backdrop. On the landing page itself we want it to fill
   roughly one screen (including the call-to-action button(s) below the title), so nothing needs
   scrolling to be reached; --nav-height (see .m-home-backdrop above) accounts for the navbar's
   actual height above it, not just its usual one-line height. The guest hero hides the navbar
   entirely (NavMenu.razor's HideNav), so it gets the full 100vh instead via .m-home-hero--full -
   otherwise it'd leave an empty gap at the bottom reserved for a navbar that isn't there. */
.m-home-hero {
    display: flex;
    align-items: center;
    min-height: calc(100vh - var(--nav-height, 90px));
}

.m-home-hero--full {
    min-height: 100vh;
}

.m-home-hero-inner {
    width: 100%;
    max-width: 1280px;
    margin: 0 auto;
    padding-inline: var(--space-8);
    box-sizing: border-box;
}

/* The signed-in card (Home.razor) sits flush left, matching every other page's content edge -
   fine once there's a 4-button row to fill it out. A signed-out visitor gets a completely
   different treatment instead (.m-home-hero-guest, below): centered, no card, a much bigger logo,
   just one button - the page's one focal point rather than a stray card. Scoped via :has() to
   that guest wrapper, so the signed-in layout is untouched. */
.m-home-hero-inner:has(.m-home-hero-guest) {
    display: flex;
    justify-content: center;
}

/* A frosted card around the hero's text/buttons rather than the image directly: the busy
   crosshatch art made both the plain text and especially transparent (ghost) buttons hard to
   read, since there was nothing behind them but the pattern itself - no longer a card at all
   (see the guest hero just below for the same "no chrome" treatment), so each button now carries
   its own contrast instead via the ghost-button override further down.
   A left/right split: the logo on the left, the action buttons in a vertical list on the right
   (.home-actions below), rather than stacked with a horizontal button row beneath the logo -
   reads more like a dashboard's one real choice than a marketing stack. min-height gives the row
   actual room to fill, rather than just hugging the logo's natural height: the logo fills its
   column by width (see .m-hero__title-image below), the button list spreads out to fill this
   height instead (justify-content: space-between, further down). Collapses to a stacked column on
   narrow screens where there's no room for two columns. */
.m-home-hero-card {
    max-width: 1100px;
    min-height: min(60vh, 560px);
    display: flex;
    flex-direction: row;
    align-items: stretch;
    justify-content: space-between;
    gap: var(--space-8);
}

@media (max-width: 720px) {
    .m-home-hero-card {
        flex-direction: column;
        align-items: stretch;
        min-height: 0;
    }
}

.m-home-hero-card__brand {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
}

.m-home-hero-card__actions {
    flex: 0 0 300px;
    display: flex;
}

@media (min-width: 721px) {
    .m-home-hero-card__brand .m-hero__title-image {
        max-width: none;
        width: 100%;
    }
}

/* HomeActions.razor's own markup, rendered by a child component with no .razor.css of its own -
   these rules used to live in Home.razor.css, which (lacking ::deep) never actually matched
   them: Blazor's CSS isolation only scopes a component's own markup, not a child component's, so
   that whole block was silently dead and .home-actions had no real layout rule at all. Moved
   here instead of just adding ::deep, since it needs to behave differently depending on where
   it's used anyway (vertical list in the signed-in split below vs. the guest hero's single
   centered button). */
.home-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
}

.home-actions--center {
    justify-content: center;
}

@media (max-width: 640px) {
    .home-actions {
        flex-direction: column;
    }

    .home-actions .m-btn {
        width: 100%;
    }
}

/* The signed-in split's action list (.m-home-hero-card__actions above): always a vertical list of
   full-width buttons, regardless of viewport width - there's no "row that wraps" state here like
   the generic .home-actions default above. */
.m-home-hero-card__actions .home-actions {
    flex-direction: column;
    flex-wrap: nowrap;
    justify-content: center;
    gap: var(--space-3);
    width: 100%;
}

.m-home-hero-card__actions .home-actions .m-btn {
    width: 100%;
    min-height: 60px;
    font-size: 17px;
}

/* There's no card behind these any more (see .m-home-hero-card above) - every button needs its
   own contrast against the busy backdrop art now, not just .m-btn--ghost, which is transparent
   everywhere else in the app. */
.m-home-hero-card__actions .home-actions .m-btn--ghost {
    background: rgba(255, 255, 255, 0.1);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border-color: rgba(255, 255, 255, 0.18);
}

.m-home-hero-card__actions .home-actions .m-btn--ghost:hover {
    background: rgba(255, 255, 255, 0.16);
}

.m-home-hero-card__actions .home-actions .m-btn--primary,
.m-home-hero-card__actions .home-actions .m-btn--contrast {
    box-shadow: 0 2px 16px rgba(5, 9, 24, 0.45);
}

/* The guest hero: single centered column (logo, one button) rather than the signed-in split's
   two side-by-side ones, so its own max-width is independent of .m-home-hero-card's. */
.m-home-hero-guest {
    max-width: 960px;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 36px;
}

/* The key art's title lockup and the navbar/auth-card logo (below) both carry a glow/contrast
   drawn for one specific background. Dark and light each render their own image (when
   configured) plus a plain-text fallback; these rules pick whichever is right for the active
   theme rather than relying on one image looking right on any background.
   view-transition-name pairs this with .m-brand--nav's logo image below (same name — Blazor's
   enhanced navigation wraps page swaps in the View Transition API when the browser supports it,
   so the browser morphs one into the other across navigation to/from the home page, instead of
   an instant cut; unsupported browsers just see today's instant swap, no fallback code needed).
   display:none elements are excluded from view-transition capture, so the --dark/--light pair
   here and the hidden .m-brand--reserved logo below never conflict over the shared name. */
.m-hero__title-image {
    display: none;
    width: 100%;
    max-width: 460px;
    height: auto;
    view-transition-name: brand-logo;
}

.m-hero__title-image--dark {
    display: block;
}

.m-hero__title--fallback {
    display: none;
}

[data-theme="light"] .m-hero__title-image--dark {
    display: none;
}

[data-theme="light"] .m-hero__title-image--light {
    display: block;
}

/* The guest hero has far more room to work with (.m-home-hero-guest, above) and is the whole
   focal point of the page rather than a strip beside a 4-button row, so its logo runs much
   bigger - but only once there's actually room for it, past the mobile breakpoint. */
@media (min-width: 721px) {
    .m-hero__title-image--guest {
        max-width: 760px;
    }
}

@media (max-width: 720px) {
    .m-hero__title-image {
        max-width: 320px;
    }
}

/* The navbar/auth-card brand mark, when a profile supplies a logo image (BrandMark.razor)
   instead of the design system's icon-square + wordmark. Same dark/light-as-separate-images
   reasoning as the hero title above. */
.m-brand__logo-image {
    display: none;
    height: 40px;
    width: auto;
}

.m-brand__logo-image--dark {
    display: block;
}

.m-brand--has-image .m-brand__mark,
.m-brand--has-image .m-brand__word {
    display: none;
}

[data-theme="light"] .m-brand__logo-image--dark {
    display: none;
}

[data-theme="light"] .m-brand__logo-image--light {
    display: block;
}

/* NavMenu's own BrandMark instance only (see BrandMark.razor's IsNavBrand/Reserved) — the
   standalone usages on auth pages get neither class and are unaffected by either rule. */
.m-brand--nav .m-brand__logo-image {
    view-transition-name: brand-logo;
}

.m-brand--reserved {
    visibility: hidden;
}

/* At most the View Transition API's own ~250ms default - 0.45s read as sluggish once the
   transition was actually wired up and firing (enhanced-nav-transitions.js). */
::view-transition-group(brand-logo) {
    animation-duration: 0.2s;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid var(--success);
}

.invalid {
    outline: 1px solid var(--danger);
}

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

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

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

/* Small loading spinner for the team/auth access-check wrappers (Components/Shared/*.razor),
   replacing Bootstrap's spinner-border now that Bootstrap isn't served. */
.m-spinner {
    display: inline-block;
    width: 32px;
    height: 32px;
    border: 3px solid var(--line);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: m-spin 0.7s linear infinite;
}

.m-spinner--sm {
    width: 18px;
    height: 18px;
    border-width: 2px;
}

@keyframes m-spin {
    to { transform: rotate(360deg); }
}
