/* ==========================================================================
   GRASP Cloud — JupyterHub theme · "Instrument Light"
   --------------------------------------------------------------------------
   Distinct identity, deliberately opposite to DIVA. DIVA views the atmosphere
   FROM orbit: nighttime, cyan, deep space. GRASP looks THROUGH it: solar
   photometry, daylight penetrating an air column.

   Two core principles govern everything else:

   · Cold haze as background and SOLAR AMBER as accent. Not a decorative pairing:
     it reflects the physical separation GRASP performs — direct solar beam (warm)
     versus diffuse skylight (cold).
   · The four channels of an AERONET sun photometer (440/675/870/1020 nm) serve as
     the structural marker of the system, appearing as data rather than ornament.

   Layered on top of base.css (neutral structure). This file specifies the design
   tokens and applies GRASP's custom component skin.
   ========================================================================== */

:root {
    color-scheme: light dark;

    /* --- surfaces: cool haze, not cream ---------------------------------- */
    --bg:          #eef2f5;
    --bg-1:        #ffffff;
    --bg-2:        #e4ebf0;
    --bg-3:        #d6e0e8;
    --panel:       rgba(255, 255, 255, 0.92);
    --panel-solid: #ffffff;

    /* --- lines: instrument tick marks ------------------------------------ */
    --line:        rgba(20, 35, 43, 0.10);
    --line-soft:   rgba(20, 35, 43, 0.055);
    --line-strong: rgba(20, 35, 43, 0.20);

    /* --- typography colors: deep petroleum, never pure black ------------- */
    --text:  #14232b;
    --muted: #526673;
    --faint: #8b9aa6;

    /* --- accent: the direct solar beam ----------------------------------- */
    /* #a84f00 rather than vivid amber: channel labels and links render with
       --accent over the cool haze background; brighter shades drop below 4.5:1.
       Measured: 4.93:1 as text over #eef2f5, and 5.55:1 for white text on solid fill.
       Burnt amber also visually aligns with direct beam light through an aerosol column. */
    --accent:       #a84f00;
    --accent-hover: #8a4000;
    --accent-glow:  rgba(168, 79, 0, 0.35);
    --accent-wash:  rgba(168, 79, 0, 0.07);
    --ok:           #1c7a5e;
    --ok-wash:      rgba(28, 122, 94, 0.10);
    --warn:         #a86a00;
    --warn-wash:    rgba(168, 106, 0, 0.10);
    --danger:       #a32820;
    --danger-wash:  rgba(163, 40, 32, 0.09);

    /* --- the four sun photometer channels ---------------------------------
       Data attributes, not general palette: identify wavelength. Appear only
       in channel markers, the login header band, and the convergence graphic. */
    --ch-440:  #3e4cc4;
    --ch-675:  #b8332a;
    --ch-870:  #7a2233;
    --ch-1020: #4a1b2e;

    /* --- typography: IBM Plex superfamily, three distinct roles ----------
       Condensed for headings (instrument character), regular for body copy,
       mono for data values. Distinct from DIVA (Space Grotesk + JetBrains)
       and legacy GRASP theme (Inter). */
    --display: 'IBM Plex Sans Condensed', 'IBM Plex Sans', system-ui, sans-serif;
    --body:    'IBM Plex Sans', system-ui, -apple-system, sans-serif;
    --mono:    'IBM Plex Mono', ui-monospace, SFMono-Regular, monospace;

    /* Micro-eyebrows use condensed display font; monospace is reserved strictly
       for true data (paths, identifiers, allocation figures). */
    --data-family:     var(--mono);
    --label-family:    var(--display);
    --label-transform: uppercase;

    --maxw:   1280px;
    --radius: 6px;
    --ease:   cubic-bezier(0.32, 0.72, 0, 1);

    /* --- derived roles --------------------------------------------------- */
    --on-accent:     #ffffff;
    --on-logo-plate: #14232b;

    --accent-line:        rgba(168, 79, 0, 0.22);
    --accent-ring:        rgba(168, 79, 0, 0.28);
    --accent-drop:        rgba(168, 79, 0, 0.16);
    --ok-line:            rgba(28, 122, 94, 0.30);
    --warn-line:          rgba(168, 106, 0, 0.30);
    --warn-line-strong:   rgba(168, 106, 0, 0.42);
    --danger-line:        rgba(163, 40, 32, 0.30);
    --danger-line-strong: rgba(163, 40, 32, 0.45);

    --row-hover:       rgba(20, 35, 43, 0.035);
    --neutral-wash:    rgba(20, 35, 43, 0.04);
    --logo-plate:      #ffffff;
    --logo-plate-line: rgba(20, 35, 43, 0.10);

    /* Daylight shadows: crisp and cool, avoiding diffuse neon glow */
    --shadow-drop:       rgba(20, 35, 43, 0.14);
    --shadow-panel:      rgba(20, 35, 43, 0.10);
    --shadow-modal:      rgba(20, 35, 43, 0.18);
    --shadow-tile:       rgba(20, 35, 43, 0.20);
    --shadow-tile-hover: rgba(20, 35, 43, 0.28);

    /* No heavy glow or frosted glass: hierarchy is achieved through lines and spacing */
    --panel-blur:        none;
    --logo-hover-filter: none;
    --card-logo-filter:  none;

    /* Light theme defaults: bootstrap close icon is black; hover darkening accentuates amber */
    --close-filter:  none;
    --hover-filter:  brightness(0.92);

    /* Atmospheric column: brighter at the top where solar flux enters */
    --vignette: linear-gradient(180deg, rgba(255, 255, 255, 0.55), transparent 42%);
}

/* --- night mode ----------------------------------------------------------
   The theme switcher is preserved in grasp-cloud. Same identity with inverted
   surface: amber increases in luminance to maintain contrast against dark backgrounds. */
:root[data-bs-theme="dark"],
html[data-bs-theme="dark"] {
    color-scheme: dark;

    --bg:          #0f1a20;
    --bg-1:        #16242c;
    --bg-2:        #1d2f39;
    --bg-3:        #263d49;
    --panel:       rgba(22, 36, 44, 0.92);
    --panel-solid: #16242c;

    --close-filter:  invert(1) grayscale(1);
    --hover-filter:  brightness(1.12);

    --line:        rgba(200, 220, 232, 0.10);
    --line-soft:   rgba(200, 220, 232, 0.055);
    --line-strong: rgba(200, 220, 232, 0.20);

    --text:  #e3ebf0;
    --muted: #93a6b2;
    --faint: #5f7481;

    --accent:       #f0913a;
    --accent-hover: #f7ad63;
    --accent-glow:  rgba(240, 145, 58, 0.35);
    --accent-wash:  rgba(240, 145, 58, 0.08);
    --on-accent:    #12202a;
    --ok:           #35b28a;
    --danger:       #e8695f;
    --warn:         #e0a33c;

    --ch-440:  #6d79e8;
    --ch-675:  #e35b4f;
    --ch-870:  #c2566c;
    --ch-1020: #9c5570;

    --row-hover:       rgba(200, 220, 232, 0.035);
    --neutral-wash:    rgba(200, 220, 232, 0.04);
    --logo-plate-line: rgba(200, 220, 232, 0.10);

    --shadow-drop:       rgba(0, 0, 0, 0.50);
    --shadow-panel:      rgba(0, 0, 0, 0.42);
    --shadow-modal:      rgba(0, 0, 0, 0.58);
    --shadow-tile:       rgba(0, 0, 0, 0.70);
    --shadow-tile-hover: rgba(0, 0, 0, 0.85);

    --vignette: linear-gradient(180deg, rgba(120, 170, 200, 0.06), transparent 42%);
}

/* Map Bootstrap 5.3 variables to design tokens across both themes */
:root,
[data-bs-theme="light"],
[data-bs-theme="dark"] {
    --bs-body-bg:          var(--bg);
    --bs-body-color:       var(--text);
    --bs-body-font-family: var(--body);
    --bs-emphasis-color:   var(--text);
    --bs-secondary-color:  var(--muted);
    --bs-tertiary-color:   var(--faint);
    --bs-secondary-bg:     var(--bg-2);
    --bs-tertiary-bg:      var(--bg-1);
    --bs-border-color:     var(--line-strong);
    --bs-border-radius:    var(--radius);
    --bs-border-radius-sm: 3px;
    --bs-border-radius-lg: 10px;
    --bs-link-color:       var(--accent);
    --bs-link-hover-color: var(--accent-hover);
    --bs-code-color:       var(--accent);
    --bs-heading-color:    var(--text);
    --bs-font-monospace:   var(--mono);
}

body {
    font-family: var(--body);
}

h1, h2, h3, h4, h5, h6 {
    font-family: var(--display);
    letter-spacing: 0.005em;
}

h1 {
    font-weight: 600;
}

/* ==========================================================================
   Channel marker
   --------------------------------------------------------------------------
   Replaces DIVA's single bar before eyebrows. Renders the four wavelengths
   of a sun photometer, stepped in height according to optical depth decay.
   Encodes meaningful context: the spectral channels used by GRASP.
   ========================================================================== */
.eyebrow {
    font-weight: 600;
    font-size: 12px;
    letter-spacing: 0.18em;
    gap: 12px;
}

.eyebrow::before {
    content: "";
    width: 25px;
    height: 13px;
    flex: none;
    background:
        linear-gradient(var(--ch-440)  0 0) 0    100% / 3px 6px  no-repeat,
        linear-gradient(var(--ch-675)  0 0) 7px  100% / 3px 9px  no-repeat,
        linear-gradient(var(--ch-870)  0 0) 14px 100% / 3px 13px no-repeat,
        linear-gradient(var(--ch-1020) 0 0) 21px 100% / 3px 10px no-repeat;
}

/* ==========================================================================
   Navigation: precise instrument-like underline
   ========================================================================== */
.navbar {
    border-bottom: 1px solid var(--line-strong);
}

.navbar .nav-link,
.dropdown-item,
.btn,
.powered-by-text,
#login_widget {
    text-transform: none;
    letter-spacing: 0.01em;
}

.navbar .nav-link {
    font-size: 14.5px;
    font-weight: 500;
}

.btn {
    font-weight: 600;
}

.navbar .nav-link::after {
    content: "";
    position: absolute;
    left: 0.9rem;
    right: 0.9rem;
    bottom: 0.1rem;
    height: 2px;
    background: var(--accent);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 0.28s var(--ease);
}

.navbar .nav-link:hover::after,
.navbar .nav-link:focus-visible::after {
    transform: scaleX(1);
}

/* ==========================================================================
   Spectral band
   --------------------------------------------------------------------------
   Prominent brand accent placed on the top border of the login panel and
   environment profile cards: four proportional contiguous channel bands.
   ========================================================================== */
.login-box::before,
.profile-card::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
    background: linear-gradient(90deg,
        var(--ch-440)  0 25%,
        var(--ch-675)  25% 50%,
        var(--ch-870)  50% 75%,
        var(--ch-1020) 75% 100%);
}

/* On profile cards, the spectral band expands on hover to indicate selection */
.profile-card::before {
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 0.3s var(--ease);
}

.profile-card:hover::before,
.profile-card:focus-within::before {
    transform: scaleX(1);
}

.profile-card:hover {
    transform: none;
    border-color: var(--line-strong);
    box-shadow: 0 10px 26px -16px var(--shadow-tile);
}

/* Outline button fills on hover in sync with the top spectral band expansion */
.profile-card .btn-primary {
    background: transparent;
    color: var(--accent);
    border: 1px solid var(--accent-line);
    box-shadow: none;
}

.profile-card:hover .btn-primary,
.profile-card .btn-primary:hover,
.profile-card .btn-primary:focus-visible {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--on-accent);
}

/* GRASP login footer uses vertical stack layout */
#login-main {
    flex-direction: column;
    gap: 26px;
}

/* ==========================================================================
   Data values
   --------------------------------------------------------------------------
   Monospace font is strictly reserved for concrete data (memory, CPU, paths, timestamps)
   with tabular numbers for clean alignment.
   ========================================================================== */
.stat-value,
.volume-badge {
    font-family: var(--mono);
    font-variant-numeric: tabular-nums;
}

.login-box {
    border-radius: var(--radius);
}

/* ==========================================================================
   Spawn screen — converging inversion graphic
   --------------------------------------------------------------------------
   During server startup (which may take minutes for multi-gigabyte images),
   visualizes the algorithmic concept: fitting a model to observations
   until convergence is achieved.
   ========================================================================== */
.inversion {
    width: 300px;
    margin: 0 auto;
}

.inversion svg {
    width: 100%;
    height: auto;
    overflow: visible;
}

.iv-axis { stroke: var(--line-strong); stroke-width: 1; }
.iv-grid { stroke: var(--line); stroke-width: 1; stroke-dasharray: 2 6; }

.iv-obs {
    fill: var(--panel-solid);
    stroke: var(--text);
    stroke-width: 1.5;
}

/* Axis channel ticks styled with wavelength colors */
.iv-ch      { stroke-width: 2; }
.iv-ch-440  { stroke: var(--ch-440); }
.iv-ch-675  { stroke: var(--ch-675); }
.iv-ch-870  { stroke: var(--ch-870); }
.iv-ch-1020 { stroke: var(--ch-1020); }

.iv-fit {
    fill: none;
    stroke: var(--accent);
    stroke-width: 2;
    stroke-linecap: round;
    opacity: 0;
    animation: iv-iterate 4.8s var(--ease) infinite;
}

/* Sequential iteration curve entrance */
.iv-fit-1 { animation-delay: 0s;    }
.iv-fit-2 { animation-delay: 0.55s; }
.iv-fit-3 { animation-delay: 1.10s; }

/* The final converged iteration remains visible */
.iv-fit-3 { animation-name: iv-converge; }

@keyframes iv-iterate {
    0%           { opacity: 0; }
    6%, 14%      { opacity: 0.45; }
    24%, 100%    { opacity: 0; }
}

@keyframes iv-converge {
    0%          { opacity: 0; }
    6%          { opacity: 1; }
    78%         { opacity: 1; }
    92%, 100%   { opacity: 0; }
}

.iv-resid-track { stroke: var(--line); stroke-width: 3; stroke-linecap: round; }

.iv-resid {
    stroke: var(--accent);
    stroke-width: 3;
    stroke-linecap: round;
    stroke-dasharray: 242;
    animation: iv-residual 4.8s var(--ease) infinite;
}

/* Residual decreases step-by-step with each iteration */
@keyframes iv-residual {
    0%        { stroke-dashoffset: 24;  }
    22%       { stroke-dashoffset: 121; }
    46%       { stroke-dashoffset: 182; }
    70%, 88%  { stroke-dashoffset: 228; }
    100%      { stroke-dashoffset: 24;  }
}

.iv-axis-labels {
    display: flex;
    justify-content: space-between;
    padding: 0 10px 0 46px;
    margin-top: -4px;
    font-family: var(--mono);
    font-size: 9px;
    letter-spacing: 0.06em;
    color: var(--faint);
}

.spawn-feeds {
    font-family: var(--mono);
    letter-spacing: 0.14em;
}

@media (prefers-reduced-motion: reduce) {
    /* Retain converged solution without continuous animation */
    .iv-fit-1,
    .iv-fit-2 { animation: none; opacity: 0; }
    .iv-fit-3 { animation: none; opacity: 1; }
    .iv-resid { animation: none; stroke-dashoffset: 228; }
}
