/*
  Quindi design system
  ====================

  Shared look and feel for the Quindi.SmartMaintenance apps, adopted from Quindi.Rfid.Legacy's
  "liquid glass" theme: mint accent on graphite, translucent surfaces over a fixed gradient,
  glowing status lamps, uppercase micro-labels and tabular numerals.

  This file owns the vocabulary every app draws from - tokens, type roles, shell, cards, badges,
  status lamps, buttons. Anything specific to one app's screens belongs in that app's own
  stylesheet, which loads after this one and may build on these tokens.

  Served from an RCL, so paths resolve under _content/Quindi.SmartMaintenance.Ui/.
  Fonts are self-hosted: these are offline-first PWAs and a service worker can only cache
  same-origin assets. Both families are SIL Open Font License.
*/

/* ---------------------------------------------------------------- fonts */

@font-face {
    font-family: "Hanken Grotesk";
    font-style: normal;
    font-weight: 300 700;
    font-display: swap;
    src: url("../fonts/hanken-grotesk-latin.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304,
        U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: "Hanken Grotesk";
    font-style: normal;
    font-weight: 300 700;
    font-display: swap;
    src: url("../fonts/hanken-grotesk-latin-ext.woff2") format("woff2");
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308,
        U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113,
        U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
    font-family: "Spline Sans Mono";
    font-style: normal;
    font-weight: 400 600;
    font-display: swap;
    src: url("../fonts/spline-sans-mono-latin.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304,
        U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: "Spline Sans Mono";
    font-style: normal;
    font-weight: 400 600;
    font-display: swap;
    src: url("../fonts/spline-sans-mono-latin-ext.woff2") format("woff2");
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308,
        U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113,
        U+2C60-2C7F, U+A720-A7FF;
}
/* ---------------------------------------------------------------- tokens */

:root {
    --primary: #1cd685;
    --primary-dark: #36b084;
    --danger: #e05151;
    --warning: #e5b364;
    --info: #51e0cf;
    --accent-soft: rgba(28, 214, 133, 0.14);

    --bg-0: #0c1014;
    --bg-1: #121820;
    --surface: rgba(255, 255, 255, 0.04);
    --surface-2: rgba(255, 255, 255, 0.06);
    --border: rgba(255, 255, 255, 0.09);
    --border-strong: rgba(255, 255, 255, 0.16);

    --text-primary: rgba(255, 255, 255, 0.90);
    --text-secondary: rgba(255, 255, 255, 0.62);
    --text-muted: rgba(255, 255, 255, 0.42);

    --radius: 14px;
    --font-sans: "Hanken Grotesk", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    --font-mono: "Spline Sans Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

    color-scheme: dark;
}

* {
    box-sizing: border-box;
}

html {
    margin: 0;
    height: 100%;
    background: var(--bg-0);
    /* Kills double-tap zoom everywhere while leaving pans alone. Not `pan-x pan-y`:
       iOS WebKit mishandles that pair on an ancestor and stops inner overflow
       containers from scrolling at all. Pinch stays blocked by the other vectors —
       the viewport meta on Android, the gesture-event blocker on iOS. */
    touch-action: manipulation;
}

body {
    margin: 0;
    /* The percentage chain, not svh: the ICB is the same box position:fixed anchors to,
       so the shell always meets the docked bars — iOS 26's floating Safari toolbar sits
       over the page, and svh stops well short of it, leaving a dead band at the bottom. */
    height: 100%;
    overflow: hidden;
    font-family: var(--font-sans);
    font-size: 15px;
    line-height: 1.45;
    color: var(--text-primary);
    /* The mint glow sits top-right and stays put while the roster scrolls under it. */
    background:
        radial-gradient(1200px 700px at 80% -10%, rgba(28, 214, 133, 0.08), transparent 60%),
        linear-gradient(160deg, var(--bg-1), var(--bg-0));
    background-attachment: fixed;
    -webkit-font-smoothing: antialiased;
    -webkit-tap-highlight-color: transparent;
    overscroll-behavior-y: none;
}

button {
    font: inherit;
    color: inherit;
    border: 0;
    background: none;
    cursor: pointer;
}

a {
    color: inherit;
    text-decoration: none;
}

:focus-visible {
    outline: 2px solid rgba(28, 214, 133, 0.52);
    outline-offset: 2px;
}
/* ---------------------------------------------------------------- type roles */

.eyebrow {
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--primary);
}

.label {
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.text-mono {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
}

.text-secondary {
    color: var(--text-secondary);
}

.text-muted {
    color: var(--text-muted);
}
/* ---------------------------------------------------------------- boot screen */

.boot {
    position: fixed;
    inset: 0;
    display: grid;
    place-content: center;
    justify-items: center;
    gap: 1.25rem;
}

.boot__mark {
    width: 2.5rem;
    height: 2.5rem;
    border: 2px solid var(--border-strong);
    border-top-color: var(--primary);
    border-radius: 50%;
    animation: spin 0.9s linear infinite;
}

.boot__legend {
    margin: 0;
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--text-muted);
}

@keyframes spin {
    to {
        transform: rotate(1turn);
    }
}
/* ---------------------------------------------------------------- shell */

/*
  Header and capture dock are rows of the page grid, not floating layers: the roster between them
  is the only thing that scrolls. That keeps the record button planted while the list moves under
  the thumb, and it removes the guesswork of padding the list to clear a fixed element.
*/
.shell {
    display: grid;
    grid-template-rows: auto minmax(0, 1fr) auto;
    /* Match body's percentage chain: same box the fixed bars anchor to. */
    height: 100%;
    overflow: hidden;
}

.topbar {
    z-index: 20;
    display: flex;
    align-items: center;
    gap: 0.7rem;
    padding: calc(env(safe-area-inset-top) + 0.7rem) 1rem 0.7rem;
    background: rgba(8, 11, 15, 0.72);
    border-bottom: 1px solid var(--border);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
}

/* Same brand block as the Legacy sidebar, laid on its side to fit a phone header. */
.brand {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    min-width: 0;
}

.brand-mark {
    height: 28px;
    width: auto;
    flex: none;
}

.brand-text {
    display: flex;
    flex-direction: column;
    line-height: 1.1;
    min-width: 0;
}

.brand-kicker {
    font-size: 0.8rem;
    font-weight: 700;
    line-height: 1;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--primary);
}

.brand-name {
    font-size: 1rem;
    font-weight: 700;
    letter-spacing: -0.01em;
}

.topbar__spacer {
    flex: 1;
}

.topbar__back {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    /* 44px touch floor: this is the back control on every inner screen. */
    min-height: 2.75rem;
    padding: 0.45rem 0.6rem 0.45rem 0;
    font-size: 0.85rem;
    font-weight: 500;
    color: var(--text-secondary);
}

.topbar__back:active {
    color: var(--primary);
}
/* ---------------------------------------------------------------- status dots */

.status {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.78rem;
    color: var(--text-secondary);
    white-space: nowrap;
}

.status-dot {
    display: inline-block;
    width: 9px;
    height: 9px;
    border-radius: 50%;
    flex: none;
    background: var(--text-muted);
}

.status-dot.is-ready {
    background: var(--primary);
    box-shadow: 0 0 8px rgba(28, 214, 133, 0.6);
}

.status-dot.is-live {
    background: var(--primary);
    animation: pulse 1.6s infinite;
}

.status-dot.is-fault {
    background: var(--danger);
    box-shadow: 0 0 8px rgba(224, 81, 81, 0.5);
}

@keyframes pulse {
    0% {
        box-shadow: 0 0 0 0 rgba(28, 214, 133, 0.55);
    }
    70% {
        box-shadow: 0 0 0 7px rgba(28, 214, 133, 0);
    }
    100% {
        box-shadow: 0 0 0 0 rgba(28, 214, 133, 0);
    }
}
/* ---------------------------------------------------------------- badges */

.badge {
    display: inline-flex;
    align-items: center;
    padding: 0.15rem 0.55rem;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 600;
    background: var(--surface-2);
    color: var(--text-secondary);
    border: 1px solid var(--border);
    white-space: nowrap;
}

/* Shows the work is moving, inside whatever badge or line it sits in. */
.badge__spinner {
    display: inline-block;
    width: 0.7em;
    height: 0.7em;
    margin-right: 0.4em;
    /* Fallback first: without color-mix the ring goes transparent and the
       currentColor top arc alone still reads as a spinner. */
    border: 1.5px solid transparent;
    border: 1.5px solid color-mix(in srgb, currentColor 28%, transparent);
    border-top-color: currentColor;
    border-radius: 50%;
    vertical-align: -0.05em;
    animation: spin 0.8s linear infinite;
}

.transcript__empty .badge__spinner {
    color: var(--primary);
}

.badge-success {
    background: rgba(28, 214, 133, 0.16);
    color: var(--primary);
    border-color: rgba(28, 214, 133, 0.34);
}

.badge-danger {
    background: rgba(224, 81, 81, 0.16);
    color: var(--danger);
    border-color: rgba(224, 81, 81, 0.34);
}

.badge-info {
    background: rgba(81, 224, 207, 0.14);
    color: var(--info);
    border-color: rgba(81, 224, 207, 0.3);
}
/* ---------------------------------------------------------------- glass card */

.glass-card {
    background: linear-gradient(180deg, var(--surface-2), var(--surface));
    border: 1px solid var(--border);
    border-radius: var(--radius);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.25);
    overflow: hidden;
}

.glass-card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.85rem 1rem;
    border-bottom: 1px solid var(--border);
}

.glass-card-body {
    padding: 1rem;
}
/* ---------------------------------------------------------------- notices */

.notice {
    padding: 2.5rem 1rem;
    text-align: center;
}

.notice__title {
    margin: 0 0 0.5rem;
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-secondary);
}

.notice__text {
    margin: 0 auto;
    max-width: 28ch;
    font-size: 0.9rem;
    line-height: 1.55;
    color: var(--text-muted);
}

.banner {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    margin: 0.85rem 0 0;
    padding: 0.7rem 0.85rem;
    border: 1px solid rgba(224, 81, 81, 0.28);
    border-radius: 10px;
    background: rgba(224, 81, 81, 0.10);
    color: var(--text-primary);
    font-size: 0.85rem;
    line-height: 1.45;
}

.banner__dismiss {
    display: grid;
    place-items: center;
    min-width: 2.25rem;
    min-height: 2.25rem;
    /* Negative margins keep the banner visually compact while the hit area grows. */
    margin: -0.45rem -0.45rem -0.45rem auto;
    padding: 0;
    color: var(--text-muted);
    flex: none;
}
/* ---------------------------------------------------------------- actions */

.actions {
    display: grid;
    gap: 0.55rem;
    margin: 1.1rem 0 0;
}

/* Glove-friendly: 3rem clears the 44px touch minimum with room to spare. */
.glass-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-height: 3rem;
    padding: 0 1rem;
    border-radius: 10px;
    border: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--text-secondary);
    font-weight: 600;
    font-size: 0.9rem;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.glass-btn:active {
    background: var(--surface);
    color: var(--text-primary);
}

.glass-btn:disabled {
    opacity: 0.5;
    cursor: default;
}

.glass-btn--primary {
    background: var(--accent-soft);
    color: var(--primary);
    border-color: rgba(28, 214, 133, 0.34);
}

.glass-btn--primary:active {
    background: rgba(28, 214, 133, 0.22);
    color: var(--primary);
}

.glass-btn--danger {
    color: rgba(255, 180, 180, 0.9);
    border-color: rgba(224, 81, 81, 0.28);
    background: rgba(224, 81, 81, 0.10);
}

.glass-btn--danger:active {
    background: rgba(224, 81, 81, 0.18);
    color: #fff;
}

.btn-spinner {
    width: 0.9rem;
    height: 0.9rem;
    border: 2px solid rgba(255, 255, 255, 0.25);
    border-top-color: currentColor;
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
}
/* ---------------------------------------------------------------- blazor error ui */

#blazor-error-ui {
    display: none;
    position: fixed;
    inset: auto 0 0 0;
    z-index: 100;
    /* Right gutter clears the 2.75rem dismiss button so the message never runs under it. */
    padding: 1rem calc(3.4rem + env(safe-area-inset-right))
        calc(1rem + env(safe-area-inset-bottom)) max(1.25rem, env(safe-area-inset-left));
    background: var(--danger);
    color: #1a0505;
    font-size: 0.875rem;
    font-weight: 500;
}

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

#blazor-error-ui .reload {
    display: inline-block;
    padding: 0.6rem 0.4rem;
    margin: -0.6rem -0.4rem;
    text-decoration: underline;
}
/* ---------------------------------------------------------------- accessibility */

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

/*
  Reading measure. Every app's scrolling region and docked bars opt in by carrying .measure,
  so a phone layout stays edge to edge while a tablet keeps the column readable.
*/
@media (min-width: 34rem) {
    .measure {
        max-width: 34rem;
        margin-inline: auto;
    }
}
