/* wwwroot/app.css — minimal residual styles Tailwind can't do.
   Everything else is handled by Tailwind (via CDN in App.razor).
   Kept:
     - .blazor-error-boundary  → Blazor built-in unhandled-error surface
     - .valid.modified / .invalid / .validation-message
                               → Blazor's built-in <EditForm> validation surface,
                                 used by the login + register modals.
*/

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

/* Blazor <EditForm> validation surface — used by login/register modals.
   Blazor toggles these classes automatically on <input> elements bound to a validated model. */
.valid.modified:not([type=checkbox]) {
    outline: 1px solid rgb(74 222 128 / 0.75);
}

.invalid {
    outline: 1px solid rgb(239 68 68 / 0.9);
}

.validation-message {
    color: rgb(248 113 113);
    font-size: 0.8125rem;
    margin-top: 0.25rem;
}

/* Blazor's <FocusOnNavigate Selector="h1"> in Routes.razor programmatically
   sets tabindex="-1" on the target and calls .focus() after every route
   change so screen readers announce the new page. Browsers paint the default
   focus ring around the h1 for sighted users, which reads as a rendered
   border artifact (visible for a few seconds after every navigation).
   Suppress the outline specifically for programmatically-focused elements
   — [tabindex="-1"] can't receive keyboard focus anyway, so this doesn't
   hide any real focus indicator.

   Cover :focus AND :focus-visible (some Chromium builds paint the ring via
   :focus-visible even for programmatic .focus() when the initiating gesture
   was a keyboard-activated link). Also zero box-shadow in case a future
   UA / stylesheet paints the ring via shadow instead of outline. !important
   is defensive against any Tailwind utility that could get authored onto a
   focused heading later (e.g. focus:ring-*). */
[tabindex="-1"]:focus,
[tabindex="-1"]:focus-visible {
    outline: none !important;
    box-shadow: none !important;
}


/* ============================================================================
   Blazored.Modal — dark-theme override for the `.warzone-modal` variant.
   Applied by NavMenu.OpenAuthCycleAsync via ModalOptions.Class.

   Blazored REPLACES its default `blazored-modal size-medium` classes with
   whatever we pass in Options.Class, so the box DOM ends up with just
   `.warzone-modal` (verified via DOM inspection). That means all box sizing,
   padding, and background must be declared here — Blazored's scoped defaults
   never fire for the box.

   HOWEVER, Blazored's scoped CSS DOES fire on the header/title/close children
   (`.bm-header[b-<hash>]` etc.) at 0,2,0 specificity, and its stylesheet
   loads AFTER app.css. So we need `!important` on the properties Blazored
   sets or its `padding: 0 0 2rem 0` header and `margin: -1rem -1rem -1rem auto`
   close-button win, clipping the × above the modal's `overflow: hidden` edge.
   ============================================================================ */

.bm-container:has(.warzone-modal) {
    display: flex !important;
    align-items: center;
    justify-content: center;
    background-color: rgba(10, 10, 10, 0.75) !important;
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
}

.warzone-modal {
    display: flex;
    flex-direction: column;
    background-color: rgb(23 23 23);
    color: rgb(245 245 245);
    border: 1px solid rgb(64 64 64);
    border-radius: 12px;
    /* Responsive cap — mobile stays phone-sized; tablets + desktop get
       progressively more breathing room. The boost/add-server/mint-key
       modals carry the most content and were the ones bumping into 440px. */
    width: min(94vw, 480px);
    max-height: calc(100vh - 3rem);
    margin: 1.5rem;
    overflow: hidden;
    /* 2px inset top ribbon in brand-orange + tighter outer glow so it doesn't feel like a floating grey box. */
    box-shadow:
        inset 0 2px 0 0 rgb(255 122 0),
        0 24px 48px -12px rgba(0, 0, 0, 0.7),
        0 0 0 1px rgba(255, 122, 0, 0.06);
}

/* sm — tablet portrait (Tailwind sm breakpoint) */
@media (min-width: 640px) {
    .warzone-modal { width: min(90vw, 560px); }
}
/* md — tablet landscape */
@media (min-width: 768px) {
    .warzone-modal { width: min(85vw, 640px); }
}
/* lg — desktop */
@media (min-width: 1024px) {
    .warzone-modal { width: min(80vw, 720px); }
}

.warzone-modal .bm-header {
    display: flex !important;
    align-items: center !important;
    justify-content: space-between !important;
    gap: 1rem;
    padding: 1.125rem 1.5rem !important;
    margin: 0 !important;
    border-bottom: 1px solid rgb(38 38 38);
}

.warzone-modal .bm-title {
    color: rgb(250 250 250);
    font-size: 1.25rem;
    font-weight: 600;
    letter-spacing: -0.01em;
    line-height: 1;
    margin: 0 !important;
}

.warzone-modal .bm-close {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0 !important;
    margin: 0 !important;
    color: rgb(163 163 163);
    background-color: transparent;
    border: 0;
    font-size: 1.5rem;
    font-weight: 300;
    line-height: 1;
    border-radius: 8px;
    cursor: pointer;
    transition: color 0.15s ease, background-color 0.15s ease;
    flex-shrink: 0;
}

.warzone-modal .bm-close:hover {
    color: rgb(245 245 245);
    background-color: rgba(255, 255, 255, 0.06);
}


/* ============================================================================
   Range-toggle pills + <AreaChart> — absolutely-positioned tick/tooltip layering
   Tailwind can't express without a wall of arbitrary values.
   ========================================================================= */

.wz-pill {
    padding: 0.25rem 0.75rem;
    font-size: 0.8125rem;
    border-radius: 9999px;
    background: rgba(255, 122, 0, 0.08);
    border: 1px solid rgba(255, 122, 0, 0.3);
    color: rgba(255, 255, 255, 0.75);
    white-space: nowrap;
    cursor: pointer;
    transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

.wz-pill:hover:not(:disabled) {
    background: rgba(255, 122, 0, 0.16);
    border-color: rgba(255, 122, 0, 0.5);
    color: #fff;
}

.wz-pill.active {
    background: rgba(255, 122, 0, 0.22);
    border-color: #FF7A00;
    color: #FF9633;
}

.wz-pill:disabled {
    opacity: 0.5;
    cursor: default;
}

/* Bootstrap 5.3 .form-switch reproduced for the brand palette — Bootstrap isn't
   loaded here. Same geometry (2em x 1em pill) and the same mechanic: the knob is
   an SVG background slid by background-position rather than a child element. */
.wz-switch {
    --wz-switch-knob: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255,255,255,0.25%29'/%3e%3c/svg%3e");
    -webkit-appearance: none;
    appearance: none;
    flex-shrink: 0;
    font-size: 1rem;
    width: 2em;
    height: 1em;
    margin: 0;
    background-color: transparent;
    background-image: var(--wz-switch-knob);
    background-repeat: no-repeat;
    background-position: left center;
    background-size: contain;
    border: 1px solid rgb(82 82 82);
    border-radius: 2em;
    cursor: pointer;
    print-color-adjust: exact;
    transition: background-position 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out;
}

.wz-switch:checked {
    --wz-switch-knob: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e");
    background-color: #FF7A00;
    background-position: right center;
    border-color: #FF7A00;
}

.wz-switch:focus-visible {
    outline: 0;
    box-shadow: 0 0 0 0.25rem rgba(255, 122, 0, 0.25);
}

.wz-switch:disabled {
    opacity: 0.5;
    cursor: default;
}

@media (prefers-reduced-motion: reduce) {
    .wz-switch { transition: none; }
}

/* `type="search"` keeps the searchbox role for screen readers, but its UA clear
   button would sit next to our own — suppress the native one. */
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
    -webkit-appearance: none;
    appearance: none;
}

/* Back-to-top button — hidden until site.js adds `.wz-to-top-show` past the hero.
   `visibility` (not `display`) so the fade can run both ways. */
.wz-to-top {
    opacity: 0;
    visibility: hidden;
    transform: translateY(0.5rem);
    transition: opacity 180ms ease-out, transform 180ms ease-out, visibility 180ms;
}

.wz-to-top-show {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
    .wz-to-top { transition: none; transform: none; }
    .wz-to-top-show { transform: none; }
}

/* ── Tooltips ────────────────────────────────────────────────────────────
   One hover-tooltip look for the whole site; `Components/Integrations/Tooltip.razor`
   renders it. Put `wz-tip-anchor` on the element the hint belongs to and make
   the tooltip a DIRECT child, so nested anchors never trigger each other.

   Plain CSS rather than Tailwind `group-hover/<name>` variants: those need every
   scope name to exist as a literal somewhere in scan scope, which made each new
   call site a two-file change and silently rendered nothing when forgotten. */
.wz-tip-anchor {
    position: relative;
}

.wz-tip {
    position: absolute;
    bottom: 100%;
    left: 50%;
    transform: translateX(-50%);
    z-index: 40;
    margin-bottom: 0.5rem;
    width: max-content;
    max-width: 16rem;
    padding: 0.375rem 0.625rem;
    border: 1px solid rgb(64 64 64);
    border-radius: 0.375rem;
    background: rgb(10 10 10);
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
    font-size: 11px;
    line-height: 1.35;
    font-weight: 400;
    text-align: left;
    text-transform: none;
    letter-spacing: normal;
    white-space: normal;
    color: rgb(245 245 245);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 0.15s ease 0.075s, visibility 0.15s ease 0.075s;
}

/* Edge variants for anchors sitting against a container boundary, where the
   centred default would be clipped. */
.wz-tip-start {
    left: 0;
    transform: none;
}

.wz-tip-end {
    left: auto;
    right: 0;
    transform: none;
}

/* Flipped below the anchor — for anchors near the top of a scroll container. */
.wz-tip-below {
    bottom: auto;
    top: 100%;
    margin-bottom: 0;
    margin-top: 0.5rem;
}

/* `:focus-visible` (and `:has()` for wrappers around a focusable control) keeps
   the tooltip off after a mouse click but on for keyboard users. */
.wz-tip-anchor:hover > .wz-tip,
.wz-tip-anchor:focus-visible > .wz-tip,
.wz-tip-anchor:has(:focus-visible) > .wz-tip {
    opacity: 1;
    visibility: visible;
}

.wz-tip-title {
    display: block;
    margin-bottom: 0.125rem;
    font-weight: 600;
    color: #fff;
}

.wz-tip-body {
    display: block;
    color: rgb(212 212 212);
}

@media (prefers-reduced-motion: reduce) {
    .wz-tip { transition: none; }
}

/* The curve is SVG but every label stays DOM text — text inside the stretched
   viewBox distorts. */
.wz-chart {
    display: grid;
    grid-template-columns: 3.25rem 1fr;
    gap: 0.5rem;
    /* Top-aligned so the axis tracks the plot; end-aligned it would follow the
       x-axis labels and scrollbar instead, dropping the 0 tick below baseline. */
    align-items: start;
}

.wz-chart-yaxis {
    position: relative;
    height: 220px;
}

.wz-chart-ytick {
    position: absolute;
    right: 0;
    transform: translateY(50%);
    white-space: nowrap;
    font-size: 0.6875rem;
    font-variant-numeric: tabular-nums;
    color: rgb(115 115 115);
}

.wz-chart-plot {
    position: relative;
    height: 220px;
}

.wz-chart-grid {
    position: absolute;
    left: 0;
    right: 0;
    height: 1px;
    background: rgba(255, 255, 255, 0.07);
}

/* The curve is stretched to the plot box, so the stroke opts out of scaling via
   vector-effect or it renders thick horizontally and thin vertically. */
.wz-chart-svg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}

.wz-chart-line {
    fill: none;
    stroke: #FF9633;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.wz-chart-line-sub {
    stroke: rgb(163 163 163);
    stroke-width: 1.5;
}

.wz-chart-points {
    position: absolute;
    inset: 0;
    /* A dot or tooltip at the very edge must not widen the scroll area. */
    overflow: hidden;
}

/* Full-height hover target, already clamped inside the plot by the component. */
.wz-chart-hit {
    position: absolute;
    top: 0;
    bottom: 0;
}

.wz-chart-dot {
    position: absolute;
    left: 50%;
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 0 0 3px rgba(255, 122, 0, 0.3);
    transform: translate(-50%, 50%);
    opacity: 0;
    transition: opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

.wz-chart-hit:hover .wz-chart-dot {
    opacity: 1;
}

.wz-chart-dot-sub {
    width: 0.4rem;
    height: 0.4rem;
    background: rgb(212 212 212);
    box-shadow: 0 0 0 3px rgba(163, 163, 163, 0.25);
}

/* Spans both grid columns so it lines up with the plot, not the y-axis gutter. */
.wz-chart-legend {
    grid-column: 1 / -1;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.25rem 1rem;
    margin-top: 0.75rem;
}

.wz-chart-legend-item {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.6875rem;
    color: rgb(163 163 163);
}

/* `translate` carries the offsets rather than `transform` so the edge and below
   variants can each override one axis without restating both. Visual properties
   deliberately match `.wz-tip` — one tooltip look site-wide. */
.wz-chart-tip {
    --tip-x: -50%;
    --tip-y: 0;
    position: absolute;
    left: 50%;
    z-index: 2;
    min-width: 8.5rem;
    margin-bottom: 0.9rem;
    padding: 0.375rem 0.625rem;
    translate: var(--tip-x) var(--tip-y);
    background: rgb(10 10 10);
    border: 1px solid rgb(64 64 64);
    border-radius: 0.375rem;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s ease 0.075s;
}

.wz-chart-hit:hover .wz-chart-tip {
    opacity: 1;
}

.wz-chart-tip-below {
    --tip-y: calc(100% + 1.8rem);
}

.wz-chart-tip-start {
    --tip-x: 0;
    left: 0;
}

.wz-chart-tip-end {
    --tip-x: 0;
    left: auto;
    right: 0;
}

.wz-chart-tip-title {
    font-size: 11px;
    font-weight: 600;
    color: #fff;
    line-height: 1.35;
    white-space: nowrap;
}

.wz-chart-tip-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.125rem;
    font-size: 11px;
    line-height: 1.35;
    color: rgb(212 212 212);
    white-space: nowrap;
}

.wz-chart-tip-swatch {
    width: 0.6rem;
    height: 0.6rem;
    border-radius: 2px;
    background: #FF9633;
    flex: 0 0 auto;
}

.wz-chart-tip-swatch-muted {
    background: rgb(115 115 115);
}

.wz-chart-xaxis {
    display: flex;
    gap: 2px;
    margin-top: 0.4rem;
}

.wz-chart-xtick {
    flex: 1 1 0;
    text-align: center;
    white-space: nowrap;
    font-size: 0.6875rem;
    color: rgb(115 115 115);
}

/* The plot scrolls sideways rather than crushing labels together — on phones for
   any bucket count, on desktop only once a long range outgrows the container. */
.wz-chart-scroll {
    overflow-x: auto;
    /* A dot sitting on the baseline hangs half below it; clip rather than scroll. */
    overflow-y: hidden;
    overscroll-behavior-x: contain;
}

/* The plot never grows past this, so any container at least this wide shows the
   whole range and only phones scroll. Long ranges thin their axis labels. */
.wz-chart-plot,
.wz-chart-xaxis {
    min-width: 620px;
}

/* Opens on the newest bucket when it does scroll. `rtl` on the scroller alone
   flips the initial scroll position; the content restores `ltr`. */
.wz-chart-scroll-end {
    direction: rtl;
}

.wz-chart-scroll-end > * {
    direction: ltr;
}

.warzone-modal .bm-close:focus-visible {
    outline: 2px solid rgb(255 122 0);
    outline-offset: 2px;
}

.warzone-modal .bm-content {
    padding: 1.5rem;
    overflow-y: auto;
}
