/* /Components/Layout/BrandLockup.razor.rz.scp.css */
/* Brand lockup — full logo at scroll 0, mark alone once scrolled.
 *
 * The mechanism is a clip, not a resize. Each image sits in its own
 * overflow:hidden slot and the SLOT's max-width animates while the image keeps a
 * fixed height and width:auto. Animating the <img> width instead would compress
 * the artwork horizontally, because a fixed height plus a shrinking width
 * distorts the aspect ratio.
 *
 * Slot widths come from the measured viewBoxes: navkor-logo.svg is
 * 352.47 x 117.11 (3.010:1) and navkor-icon.svg is 112.14 x 117.11 (0.957:1).
 * At 36px tall that is 108.3px and 34.5px; at 40px, 120.4px and 38.3px. The
 * max-widths below round up so nothing clips at rest.
 *
 * The mark holds perfectly still through the crossfade, for free: the mark paths
 * in navkor-icon.svg are byte-identical to the mark paths inside
 * navkor-logo.svg, at identical coordinates, and both files share the 117.11
 * viewBox height. At equal rendered heights the mark lands on the same pixels in
 * both images, so the transition reads as the wordmark dissolving rather than as
 * two images swapping.
 *
 * The state class lives on <html>, set by wwwroot/js/brand-scroll.js. Blazor
 * scoped CSS appends its scope attribute to the LAST element of a selector, so
 * `html.is-scrolled .brand-slot-full` compiles correctly with no ::deep.
 */

.brand-lockup[b-ia9dun8u3x] {
    position: relative;
    display: flex;
    align-items: center;
    text-decoration: none;
    /* Reserve the widest state so the nav's own layout never reflows. */
    min-width: 109px;
    height: 36px;
}

.brand-slot[b-ia9dun8u3x] {
    display: flex;
    align-items: center;
    overflow: hidden;
    flex: 0 0 auto;
    transition: max-width 250ms ease, opacity 250ms ease;
}

.brand-img[b-ia9dun8u3x] {
    display: block;
    height: 36px;
    width: auto;
}

.brand-slot-full[b-ia9dun8u3x] {
    max-width: 109px;
    opacity: 1;
}

/* Absolutely positioned at the anchor's left edge so it occupies the same origin
 * as the full lockup's mark — that co-location is what makes the mark appear
 * stationary rather than sliding into place. */
.brand-slot-mark[b-ia9dun8u3x] {
    position: absolute;
    left: 0;
    top: 0;
    height: 36px;
    max-width: 0;
    opacity: 0;
}

/* The swap is MOBILE ONLY, below the 768px breakpoint.
 *
 * On a phone the wordmark is competing for scarce horizontal space against the
 * menu button, so collapsing it buys something real. On desktop there is room
 * for the full lockup at every scroll position, and a wordmark that vanishes as
 * you scroll is motion with no purpose — it reads as a distraction rather than
 * as polish. Wide viewports therefore keep the full lockup at all times.
 *
 * The `is-scrolled` class is still applied at every width by brand-scroll.js;
 * it is simply not consumed here above 768px. Left that way deliberately: it is
 * a general-purpose scroll-state hook, and anything else wanting it (a nav
 * shadow, a condensed header) should not have to re-add the listener. */
@media (max-width: 767.98px) {

    html.is-scrolled .brand-slot-full[b-ia9dun8u3x] {
        max-width: 35px;
        opacity: 0;
    }

    html.is-scrolled .brand-slot-mark[b-ia9dun8u3x] {
        max-width: 35px;
        opacity: 1;
    }
}

@media (min-width: 768px) {
    .brand-lockup[b-ia9dun8u3x] {
        min-width: 121px;
        height: 40px;
    }

    .brand-img[b-ia9dun8u3x] {
        height: 40px;
    }

    .brand-slot-full[b-ia9dun8u3x] {
        max-width: 121px;
    }

    .brand-slot-mark[b-ia9dun8u3x] {
        height: 40px;
    }
}

/* The swap still happens — it just happens instantly. Honouring the preference
 * must not cost the visitor the behaviour. */
@media (prefers-reduced-motion: reduce) {

    .brand-slot[b-ia9dun8u3x] {
        transition: none;
    }
}
/* /Components/Layout/NavMenu.razor.rz.scp.css */
/* Mobile navigation disclosure — NAV-11.
 *
 * ⛔ THE STATE CLASS IS OWNED HERE, NOT BY TAILWIND, AND THAT IS LOAD-BEARING.
 *
 * wwwroot/css/app.css pins the compiler's entire input with
 * `@import "tailwindcss" source(none)` plus two @source globs, BOTH of which
 * match only *.razor. A utility class that appears solely inside
 * wwwroot/js/nav-toggle.js is therefore never emitted: the script would run,
 * the class would land on the element, the DOM inspector would show it — and
 * `display` would never change. That is this ticket's own defect one layer
 * down, and only a computed-style assertion could see it.
 *
 * ⚠️ The obvious repair — adding an @source line for the js directory — works
 * locally and FAILS INSIDE THE IMAGE. The Dockerfile's `css` stage copies
 * app.css and the two razor trees and nothing else; wwwroot/js/ is not in that
 * stage's build context, so the container would build a stylesheet missing the
 * rule while the developer's machine built one containing it. See
 * docs/lessons/follow-the-change-to-what-ships/
 * 2026-08-09-docker-ignores-gitignore-so-the-image-was-built-from-a-file-only-one-disk-had.md
 *
 * ⭐ Scoped .razor.css is compiled by the .NET build into
 * Navkor.Web.styles.css, so it is immune to both layers. This is the same
 * arrangement BrandLockup.razor.css already uses for `html.is-scrolled` —
 * that file dodges the trap but never says why, which is how a precedent
 * transmits a pattern without its reason. Stated here.
 *
 * Blazor scoped CSS appends its scope attribute to the LAST element of a
 * selector, so `html.js-enabled #nav-mobile` compiles correctly with no ::deep.
 */

/* ── Default state: NO JAVASCRIPT.
 *
 * The list ships VISIBLE and the script collapses it, rather than shipping
 * collapsed and relying on the script to open it. With JS unavailable the
 * visitor gets a long but working navigation instead of no navigation at all —
 * which is the defect this ticket exists to fix, so shipping a fix that
 * reproduces it whenever a script fails to load would be no fix. */
#nav-mobile[b-c3jmqtwz6m] {
    display: block;
}

/* ⛔ The disclosure region is a PHONE surface and must never render above the
 * breakpoint, in ANY state.
 *
 * Without this rule the default above leaves a `bg-white border-b shadow-md`
 * div wrapping an `md:hidden` (invisible) list on every DESKTOP page — a blank
 * bordered band under the nav, which is the Experience Principles amateur
 * table, introduced by the fix for a release blocker. Nothing in the suite
 * would catch it: both browser tests run at 375x812 and the bUnit tests assert
 * hrefs. Pinned by MobileNavigation_IsNeverRenderedAboveTheBreakpoint. */
@media (min-width: 768px) {
    #nav-mobile[b-c3jmqtwz6m] {
        display: none;
    }
}

/* ⛔ 44x44 CSS px minimum — WCAG 2.5.5 Target Size (Enhanced), ruled
 * 2026-09-17 and recorded in .Codex/02 beside G13.
 *
 * Measured at 37px wide before this rule: `p-2` plus a `text-2xl` glyph is a
 * comfortable-looking button and an undersized target, which is why the
 * criterion is a measured box rather than a padding class.
 *
 * Expressed as min-width/min-height rather than by changing the padding
 * utilities, so the floor holds no matter what the icon glyph inside it
 * measures — FontAwesome swaps a bars glyph for an xmark one on toggle, and
 * those are not the same width. inline-flex centres the glyph within the
 * enlarged box.
 *
 * ⚠️ 44 sits comfortably inside the nav bar's `h-16` (64px), which is fixed;
 * a larger floor here would push its parent. Pinned by
 * MobileMenuToggle_IsAFingerSizedTarget_At375px, which asserts the bar height
 * as well as the button's.
 *
 * ⛔ The `display` half is confined to the phone breakpoint ON PURPOSE. The
 * control carries Tailwind's `md:hidden`, which is `.hidden { display: none }`
 * at (0,0,1,0); a scoped `#nav-toggle[b-…]` rule is (0,1,1,0) and OUTRANKS it,
 * so declaring display unconditionally here would un-hide the button on every
 * desktop page. Caught by MobileMenu_IsNeverRendered_AboveTheBreakpoint. */
@media (max-width: 767.98px) {
    #nav-toggle[b-c3jmqtwz6m] {
        min-width: 44px;
        min-height: 44px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }
}

/* ── The control's icon, driven by aria-expanded.
 *
 * ⭐ Keyed off the SAME attribute assistive technology reads, rather than off a
 * second class of its own. A sighted visitor and a screen-reader user are then
 * looking at one piece of state in two renderings, and "the icon says close
 * while aria-expanded says false" is not a reachable state.
 *
 * Both icons are always in the DOM and one is hidden, rather than swapping the
 * element's classes, so the button's box never changes size as it toggles.
 * They carry aria-hidden in the markup: the accessible name comes from
 * aria-label, and an unlabelled <i> would otherwise add noise. */
#nav-toggle .nav-toggle-open[b-c3jmqtwz6m] {
    display: none;
}

#nav-toggle[aria-expanded="true"] .nav-toggle-open[b-c3jmqtwz6m] {
    display: inline-block;
}

#nav-toggle[aria-expanded="true"] .nav-toggle-closed[b-c3jmqtwz6m] {
    display: none;
}

/* ⛔ G13 requires a VISIBLE focus state on every interactive element, and this
 * button sets `border-none`, so it is exactly the kind of control that ends up
 * with nothing to show when tabbed to. Stated explicitly rather than left to
 * whatever the user agent happens to do over a transparent borderless button.
 *
 * :focus-visible, not :focus — a mouse tap should not leave a ring behind. */
#nav-toggle:focus-visible[b-c3jmqtwz6m] {
    outline: 2px solid var(--color-primary-600);
    outline-offset: 2px;
    border-radius: 0.375rem;
}

/* ── Enhanced state: JavaScript confirmed.
 *
 * `js-enabled` is set on <html> by a synchronous script in App.razor's <head>,
 * so the collapse happens BEFORE first paint. Doing it from the deferred body
 * scripts instead would paint the menu open and then shut it — visible layout
 * shift on every page load on a phone, which is the amateur table again.
 *
 * <html> is also the one element Blazor's enhanced navigation never replaces,
 * which is why brand-scroll.js binds it. */
@media (max-width: 767.98px) {

    html.js-enabled #nav-mobile[b-c3jmqtwz6m] {
        display: none;
    }

    html.js-enabled #nav-mobile.is-open[b-c3jmqtwz6m] {
        display: block;
    }
}
/* /Components/Layout/ReconnectModal.razor.rz.scp.css */
.components-reconnect-first-attempt-visible[b-j2kzkrvvkr],
.components-reconnect-repeated-attempt-visible[b-j2kzkrvvkr],
.components-reconnect-failed-visible[b-j2kzkrvvkr],
.components-pause-visible[b-j2kzkrvvkr],
.components-resume-failed-visible[b-j2kzkrvvkr],
.components-rejoining-animation[b-j2kzkrvvkr] {
    display: none;
}

#components-reconnect-modal.components-reconnect-show .components-reconnect-first-attempt-visible[b-j2kzkrvvkr],
#components-reconnect-modal.components-reconnect-show .components-rejoining-animation[b-j2kzkrvvkr],
#components-reconnect-modal.components-reconnect-paused .components-pause-visible[b-j2kzkrvvkr],
#components-reconnect-modal.components-reconnect-resume-failed .components-resume-failed-visible[b-j2kzkrvvkr],
#components-reconnect-modal.components-reconnect-retrying[b-j2kzkrvvkr],
#components-reconnect-modal.components-reconnect-retrying .components-reconnect-repeated-attempt-visible[b-j2kzkrvvkr],
#components-reconnect-modal.components-reconnect-retrying .components-rejoining-animation[b-j2kzkrvvkr],
#components-reconnect-modal.components-reconnect-failed[b-j2kzkrvvkr],
#components-reconnect-modal.components-reconnect-failed .components-reconnect-failed-visible[b-j2kzkrvvkr] {
    display: block;
}


#components-reconnect-modal[b-j2kzkrvvkr] {
    background-color: white;
    width: 20rem;
    margin: 20vh auto;
    padding: 2rem;
    border: 0;
    border-radius: 0.5rem;
    box-shadow: 0 3px 6px 2px rgba(0, 0, 0, 0.3);
    opacity: 0;
    transition: display 0.5s allow-discrete, overlay 0.5s allow-discrete;
    animation: components-reconnect-modal-fadeOutOpacity-b-j2kzkrvvkr 0.5s both;
    &[open]

{
    animation: components-reconnect-modal-slideUp-b-j2kzkrvvkr 1.5s cubic-bezier(.05, .89, .25, 1.02) 0.3s, components-reconnect-modal-fadeInOpacity-b-j2kzkrvvkr 0.5s ease-in-out 0.3s;
    animation-fill-mode: both;
}

}

#components-reconnect-modal[b-j2kzkrvvkr]::backdrop {
    background-color: rgba(0, 0, 0, 0.4);
    animation: components-reconnect-modal-fadeInOpacity-b-j2kzkrvvkr 0.5s ease-in-out;
    opacity: 1;
}

@keyframes components-reconnect-modal-slideUp-b-j2kzkrvvkr {
    0% {
        transform: translateY(30px) scale(0.95);
    }

    100% {
        transform: translateY(0);
    }
}

@keyframes components-reconnect-modal-fadeInOpacity-b-j2kzkrvvkr {
    0% {
        opacity: 0;
    }

    100% {
        opacity: 1;
    }
}

@keyframes components-reconnect-modal-fadeOutOpacity-b-j2kzkrvvkr {
    0% {
        opacity: 1;
    }

    100% {
        opacity: 0;
    }
}

.components-reconnect-container[b-j2kzkrvvkr] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
}

#components-reconnect-modal p[b-j2kzkrvvkr] {
    margin: 0;
    text-align: center;
}

#components-reconnect-modal button[b-j2kzkrvvkr] {
    border: 0;
    background-color: #6b9ed2;
    color: white;
    padding: 4px 24px;
    border-radius: 4px;
}

    #components-reconnect-modal button:hover[b-j2kzkrvvkr] {
        background-color: #3b6ea2;
    }

    #components-reconnect-modal button:active[b-j2kzkrvvkr] {
        background-color: #6b9ed2;
    }

.components-rejoining-animation[b-j2kzkrvvkr] {
    position: relative;
    width: 80px;
    height: 80px;
}

    .components-rejoining-animation div[b-j2kzkrvvkr] {
        position: absolute;
        border: 3px solid #0087ff;
        opacity: 1;
        border-radius: 50%;
        animation: components-rejoining-animation-b-j2kzkrvvkr 1.5s cubic-bezier(0, 0.2, 0.8, 1) infinite;
    }

        .components-rejoining-animation div:nth-child(2)[b-j2kzkrvvkr] {
            animation-delay: -0.5s;
        }

@keyframes components-rejoining-animation-b-j2kzkrvvkr {
    0% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 0;
    }

    4.9% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 0;
    }

    5% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 1;
    }

    100% {
        top: 0px;
        left: 0px;
        width: 80px;
        height: 80px;
        opacity: 0;
    }
}
