/* ════════════════════════════════════════════════════════════════
   site/layout.css — app shell & shared content primitives
   ----------------------------------------------------------------
   Migrated out of Components/Layout/DashboardLayout.razor.css and
   Components/Layout/OnboardingLayout.razor.css. These layouts exposed
   their primitives to page content via ::deep; now that the CSS is
   global those selectors are rewritten as plain descendant selectors
   under .content / .ob-card (the layout's own root elements), which
   reach exactly the same page content.

   Design tokens live on .shell here (re-skinned for light mode by
   wwwroot/app.css). Only DashboardLayout + OnboardingLayout moved:
   MainLayout, NavMenu, DashboardSidebar, ImpersonationBanner and
   ReconnectModal keep their scoped .razor.css because their selectors
   (.sidebar, .top-row, #blazor-error-ui, .navbar-*, .imp-*, the
   #components-reconnect-modal kit) are either component-internal or
   collide with each other by name and are only safe when scoped.

   SCSS-READY: becomes _layout.scss.
   ════════════════════════════════════════════════════════════════ */

/* ════════════════════════════════════════════════════════════════
   Dashboard shell (from DashboardLayout)
   ════════════════════════════════════════════════════════════════ */

/* Always reserve the document scrollbar's gutter. The dashboard's page height
   depends on the data in it (the SecOps dashboard's closure-status list has one
   row per Jira resolution in the window), so changing the lookback can push the
   page across the viewport height and toggle the scrollbar. That resizes .content
   — which is width-capped and centred, so the whole column shifts sideways and
   every fluid tile with it: the 24h tiles measured wider than the 7/30-day ones
   (UAT: "the top 4 boxes are slightly bigger on the 24h lookback … a slightly off
   jitter as the boxes change and shift everything"). The volume chart closes the
   loop (height: auto over a fixed viewBox, so its height follows its width).
   Reserving the gutter makes the content width the same whether the page scrolls
   or not, so no amount of data can resize the layout. */
html {
    scrollbar-gutter: stable;
    /* Height of the impersonation / view-as banner, which is sticky at the very top of the document.
       Declared here because two files have to agree on it: the banner pins itself to this height and
       the top bar sticks that far down, so the two never land on top of each other while scrolling. */
    --imp-banner-h: 42px;
}

.shell {
    --bg:        #131517;
    --bg-side:   #0E1011;
    --surface:   #1A1D1F;
    --surface-2: #23272A;
    --map-land:  #24292C;
    --line:      rgba(255, 255, 255, 0.09);
    --line-soft: rgba(255, 255, 255, 0.05);
    /* Neutral hover border — the brightened edge a card takes on hover, one step up from --line.
       Exists as a token because the literal it replaces (rgba(255,255,255,.18)) is a dark-theme
       value: in light mode it resolves to white-on-white and the hover state disappears. Used by
       site/pages/contact.css; soc.css still carries the literal in two places (.stat-card /
       .panel hover) and should adopt this next time that file is touched. */
    --hair:      rgba(255, 255, 255, 0.18);
    --text:      #EAEEEF;
    --muted:     #8A9296;
    --faint:     #5C6468;
    --accent:    #2DD4BF;
    --accent-2:  #5EEAD9;
    --accent-soft: rgba(45, 212, 191, 0.14);
    --accent-line: rgba(45, 212, 191, 0.42);

    --good:   #2DD4BF;
    --warn:   #FFB454;
    --bad:    #FF6B6B;
    --crit:   #B98AFF;

    /* Square, angular cards — no rounding */
    --radius:    0px;
    --radius-sm: 0px;
    /* Single typeface across the whole UI — same as the nav bar (Inter) */
    --font-display: "Inter", "Segoe UI", system-ui, sans-serif;
    --font-body:    "Inter", "Segoe UI", system-ui, sans-serif;

    /* How wide the main column may get. This was a flat 1480px, which on any display wider than
       about 1900px left the whole portal in a band down the middle with a couple of hundred pixels
       of empty gutter each side (UAT 2026-08-21: "I am using a larger monitor and all the text is
       squashed in the middle of the page"). Every grid in the portal is fluid with a zero floor
       (§26), so the extra width lands in the content rather than in the gutters, and no page needs
       a breakpoint to take it. The cap stays a cap: it is one value in one place, so raise it here
       and nowhere else. */
    --content-max: 2100px;

    display: flex;
    min-height: 100vh;
    /* Flat background. This used to carry a teal radial wash in the top-right corner, which was
       invisible behind the dense pages but read as a green glow on the short ones (Org Settings,
       Profile, Help) where that corner is bare. Removed rather than softened: it was decoration
       that only showed up where there was nothing else to look at. */
    background: var(--bg);
    color: var(--text);
    font-family: var(--font-body);
    font-size: 14px;
    line-height: 1.45;
}

/* ─── Main column ─────────────────────────────────────────────── */

/* Everything right of the sidebar: the static top bar, then the page. The column exists so the bar
   spans the page rather than the whole shell, and so it can stick to the top of what scrolls under
   it while the sidebar keeps its own full-height sticky. */
.shell-main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.content {
    flex: 1;
    min-width: 0;
    padding: 34px 38px 56px;
    display: flex;
    flex-direction: column;
    gap: 34px;
    /* Fallback spelled out because the token is declared on .shell: a .content rendered outside the
       dashboard shell (MainLayout's) would otherwise resolve to an invalid var() and lose its cap
       entirely, which is the one failure mode worse than a cap that is too small. */
    max-width: var(--content-max, 1480px);
    margin-inline: auto;
    width: 100%;
}

/* The top bar carries its own height above the page, so the column starts nearer the bar than it did
   when the page began at the top of the viewport. Without this the eyebrow sat 86px down. */
.shell-main .content { padding-top: 24px; }

/* ─── Top bar (from TopBar.razor) ─────────────────────────────────
   Help, settings and the profile photo, in the same place on every page and staying there as the page
   scrolls. Sticky rather than fixed, so it stays inside the column and needs no width maths. Its
   z-index clears the page toolbars that stick at 10 and stays below the flyouts (200) and modals
   (1000), which must cover it. */

.topbar {
    position: sticky;
    top: 0;
    z-index: 100;
    flex: none;
    background: var(--bg-side);
    border-bottom: 1px solid var(--line);
}

/* The impersonation / view-as banner is sticky at the top of the document and has to stay visible
   (it is the only thing saying this session is not the operator's own), so the bar sticks below it
   rather than under it. */
body:has(.imp-banner) .topbar { top: var(--imp-banner-h); }

/* Capped and centred on the same track as .content, with its padding, so the icons line up with the
   right edge of the page rather than the right edge of the monitor (§28). */
.topbar-inner {
    max-width: var(--content-max, 1480px);
    margin-inline: auto;
    width: 100%;
    height: 52px;
    padding: 0 38px;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 4px;
}

.topbar-btn {
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    border-radius: var(--radius-sm);
    color: var(--muted);
    text-decoration: none;
    transition: color .18s ease, background .18s ease;
}

.topbar-btn:hover { color: var(--text); background: var(--surface-2); }
.topbar-btn svg { width: 19px; height: 19px; display: block; }

.topbar-avatar {
    display: block;
    margin-left: 6px;
    border-radius: 50%;
    text-decoration: none;
}

.topbar-avatar:hover { box-shadow: 0 0 0 2px var(--accent-line); }

.topbar :is(a, button):focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* ─── Page header (exposed to page content) ───────────────────── */

.content .page-head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 18px;
    flex-wrap: wrap;
}

.content .eyebrow {
    margin: 0 0 4px;
    font-size: 12.5px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--accent);
}

/* Page titles are plain text, not accent — the accent belongs to the .eyebrow above it and to
   interactive chrome (UAT: "for every page I think the larger text should be white"). Five pages
   used to hard-code `style="color:#fff"` here for exactly this; the rule lives in one place now.
   --text, never a #fff literal: the token flips to near-black under [data-theme=light], where
   white-on-light reads as nothing. Both themes take this rule — there is no light-mode override. */
.content .page-head h1 {
    margin: 0;
    font-family: var(--font-display);
    font-size: 30px;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--text);
}

.content .head-actions {
    display: flex;
    align-items: center;
    gap: 14px;
    color: var(--muted);
    font-size: 13px;
}

.content .btn-ghost {
    padding: 9px 16px;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--text);
    font: 600 13px var(--font-body);
    cursor: pointer;
    transition: border-color .18s ease, background .18s ease, transform .18s ease;
}

.content .btn-ghost:hover {
    border-color: var(--accent-line);
    background: var(--surface-2);
    transform: translateY(-1px);
}

/* ─── Section scaffolding (exposed to page content) ───────────── */

.content .section { display: flex; flex-direction: column; gap: 16px; }

.content .section-head {
    display: flex;
    align-items: baseline;
    gap: 12px;
    flex-wrap: wrap;
}

.content .section-head h2 {
    margin: 0;
    font-family: var(--font-display);
    font-size: 17px;
    font-weight: 600;
    letter-spacing: 0.005em;
}

.content .section-head.tight { margin-bottom: 14px; }

.content .panel {
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
    overflow: hidden;
}

.content .panel.pad { padding: 22px 24px; }

/* ─── Responsive (shell / content) ────────────────────────────── */

@media (max-width: 900px) {
    .shell { flex-direction: column; }
    .content { padding: 22px 18px 40px; }
    .shell-main .content { padding-top: 16px; }
    /* Under this width the sidebar itself becomes a bar across the top, so a second sticky bar would
       only fight it for the same strip of screen. The top bar scrolls with the page instead. */
    .topbar { position: static; }
    .topbar-inner { height: 48px; padding: 0 18px; }
}

/* ─── Accessibility ───────────────────────────────────────────── */

.content :is(a, button):focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
    .content * { transition-duration: 0.01ms !important; }
}

/* ════════════════════════════════════════════════════════════════
   Onboarding return-leg layout (from OnboardingLayout)
   Standalone (outside .shell), palette declared locally to match the
   dashboard tokens.
   ════════════════════════════════════════════════════════════════ */

.ob-shell {
    --bg:        #131517;
    --surface:   #1A1D1F;
    --line:      rgba(255, 255, 255, 0.09);
    --line-soft: rgba(255, 255, 255, 0.05);
    --text:      #EAEEEF;
    --muted:     #8A9296;
    --accent:    #2DD4BF;
    --accent-2:  #5EEAD9;
    --accent-line: rgba(45, 212, 191, 0.42);
    --accent-soft: rgba(45, 212, 191, 0.14);
    --bad:       #FF6B6B;

    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 40px 20px;
    background:
        radial-gradient(1100px 520px at 85% -12%, rgba(45, 212, 191, 0.08), transparent 60%),
        var(--bg);
    color: var(--text);
    font-family: "Inter", "Segoe UI", system-ui, sans-serif;
    font-size: 14px;
    line-height: 1.5;
}

.ob-card {
    width: min(520px, 100%);
    padding: 36px 38px 32px;
    text-align: center;
    background: var(--surface);
    border: 1px solid var(--line);
    box-shadow: 0 40px 90px -30px rgba(0, 0, 0, 0.85);
}

.ob-brand { height: 26px; width: auto; margin-bottom: 26px; }

/* Shared content primitives used by Connected.razor. */

.ob-card .ob-title {
    margin: 0 0 10px;
    font-size: 24px;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--text);
}

.ob-card .ob-text {
    margin: 0 auto 22px;
    max-width: 42ch;
    color: var(--muted);
}

.ob-card .ob-icon {
    width: 60px;
    height: 60px;
    margin: 0 auto 18px;
    display: grid;
    place-items: center;
    border-radius: 50%;
    font-size: 28px;
    line-height: 1;
}
.ob-card .ob-icon-good {
    color: var(--accent);
    border: 2px solid var(--accent-line);
    background: var(--accent-soft);
}
.ob-card .ob-icon-bad {
    color: var(--bad);
    border: 2px solid rgba(255, 107, 107, 0.42);
    background: rgba(255, 107, 107, 0.12);
}

.ob-card .ob-spinner {
    width: 46px;
    height: 46px;
    margin: 4px auto 20px;
    border: 3px solid var(--line);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: ob-spin 0.8s linear infinite;
}
@keyframes ob-spin { to { transform: rotate(360deg); } }

.ob-card .ob-bar {
    height: 6px;
    width: 100%;
    margin-top: 8px;
    background: var(--surface);
    border: 1px solid var(--line);
    overflow: hidden;
}
.ob-card .ob-bar-fill {
    height: 100%;
    background: linear-gradient(90deg, var(--accent), var(--accent-2));
    transition: width .4s ease;
}

.ob-card .ob-metric {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin: 0 0 22px;
}
.ob-card .ob-metric-value {
    font-size: 30px;
    font-weight: 700;
    color: var(--accent-2);
}
.ob-card .ob-metric-label {
    font-size: 12px;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--muted);
}

.ob-card .btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 10px 20px;
    border: 1px solid var(--line);
    background: var(--surface);
    color: var(--text);
    font: 600 13px "Inter", "Segoe UI", system-ui, sans-serif;
    cursor: pointer;
    transition: border-color .18s ease, background .18s ease, filter .18s ease;
}
.ob-card .btn:hover { border-color: var(--accent-line); }
.ob-card .btn-primary {
    border-color: var(--accent);
    background: var(--accent);
    color: #04201D;
}
.ob-card .btn-primary:hover { filter: brightness(1.08); }

@media (prefers-reduced-motion: reduce) {
    .ob-card .ob-spinner { animation-duration: 2s; }
}
