/* =====================================================================
   ORBIX — design tokens and base layer

   A quiet dark theme: near-neutral greys, one muted indigo doing the
   accent work, and colour reserved for things that carry meaning —
   presence, warnings, the moderation surfaces. Saturation is kept low on
   purpose. A dark interface reads as a tool when the colour is scarce and
   as a screensaver when it is everywhere, so anything that glows, sweeps
   or gradients has to earn its place, and almost nothing does.

   Accent colours are declared as raw channels so a component can tint one
   without hardcoding the hex; changing the palette means changing the
   five *-rgb lines below and nothing else.
   ===================================================================== */

:root {
    /* Surfaces, from deepest to most raised */
    --void:        #0D0E11;
    --surface-0:   #111317;
    --surface-1:   #16181DCC;
    --surface-1s:  #16181D;
    --surface-2:   #1C1F25;
    --surface-3:   #24272F;
    --surface-4:   #2E323B;

    /* Hairlines and glass — plain white, so nothing takes on a cast */
    --line:        rgb(255 255 255 / .07);
    --line-strong: rgb(255 255 255 / .14);
    --glass:       rgb(28 31 37 / .82);

    /* Type */
    --text:        #E6E7EA;
    --text-dim:    #9EA3AE;
    --text-faint:  #6C717C;
    --text-invert: #14161A;

    /* Brand */
    --accent-rgb:   123 117 209;
    --accent-2-rgb: 94 171 186;
    --accent:      rgb(var(--accent-rgb));
    --accent-soft: #A7A2E0;
    --accent-deep: #565099;
    --accent-2:    rgb(var(--accent-2-rgb));
    /* Single-hue, and shallow: a sweep across the spectrum is the loudest
       thing an interface can do, and this one only marks a boot bar and a
       couple of active states. */
    --beam:        linear-gradient(115deg, #6A64C2, #8B85DC);
    --beam-dim:    linear-gradient(115deg, rgb(var(--accent-rgb) / .16), rgb(var(--accent-rgb) / .06));

    /* Presence */
    --on-online:  #5EBA94;
    --on-idle:    #D1A861;
    --on-busy:    #D86477;
    --on-offline: #5C616B;

    /* Feedback */
    --ok-rgb:     94 186 148;
    --warn-rgb:   209 168 97;
    --danger-rgb: 216 100 119;
    --danger:     rgb(var(--danger-rgb));
    --danger-dim: rgb(var(--danger-rgb) / .13);
    --warn:       rgb(var(--warn-rgb));
    --ok:         rgb(var(--ok-rgb));

    /* Geometry */
    --r-sm: 8px;
    --r-md: 12px;
    --r-lg: 18px;
    --r-xl: 26px;
    --rail-w: 76px;
    --panel-w: 268px;
    --crew-w: 248px;
    --bar-h: 56px;

    /* Motion */
    --ease: cubic-bezier(.2, .8, .2, 1);
    --fast: 120ms var(--ease);
    --mid: 220ms var(--ease);
    --slow: 420ms var(--ease);

    /* Elevation — neutral black, no coloured halo */
    --shadow-1: 0 2px 8px rgb(0 0 0 / .35);
    --shadow-2: 0 10px 28px rgb(0 0 0 / .45);
    --shadow-3: 0 24px 56px rgb(0 0 0 / .55);
    /* A hairline ring, not a glow: it marks the active station without
       lighting up the rail around it. */
    --ring-accent: 0 0 0 1px rgb(var(--accent-rgb) / .5);

    --font-scale: 100%;
    --font: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --font-mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace;
}

*, *::before, *::after { box-sizing: border-box; }

html, body {
    height: 100%;
    margin: 0;
}

html { font-size: var(--font-scale); }

body {
    background: var(--void);
    color: var(--text);
    font-family: var(--font);
    font-size: .9375rem;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    overflow: hidden;
}

/* No aurora, no coloured wash behind the app. The background is a flat
   surface for the content to sit on; it is not the content. */

h1, h2, h3, h4 {
    margin: 0;
    font-weight: 650;
    letter-spacing: -.01em;
}

p { margin: 0; }

a {
    color: var(--accent-2);
    text-decoration: none;
}
a:hover { text-decoration: underline; }

button, input, textarea, select {
    font: inherit;
    color: inherit;
}

button {
    background: none;
    border: 0;
    cursor: pointer;
    padding: 0;
}

/* Icons carry only a viewBox, so give every one a predictable box.
   Component rules below override this wherever a different size is wanted. */
svg {
    width: 16px;
    height: 16px;
    flex: none;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.9;
    stroke-linecap: round;
    stroke-linejoin: round;
}
svg[data-fill="true"], .mark svg { stroke-width: 0; }

.caret { width: 12px; height: 12px; }

/* One accent for focus, matching the border a focused field already
   takes — two different colours on the same control read as a fault. */
:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: 4px;
}

::selection {
    background: rgb(var(--accent-rgb) / .38);
    color: #fff;
}

/* ---------------------------------------------------------------- */
/* Scrollbars                                                        */
/* ---------------------------------------------------------------- */
.scrollable {
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
    scrollbar-color: var(--surface-4) transparent;
}
.scrollable::-webkit-scrollbar { width: 10px; height: 10px; }
.scrollable::-webkit-scrollbar-track { background: transparent; }
.scrollable::-webkit-scrollbar-thumb {
    background: var(--surface-4);
    border: 3px solid transparent;
    background-clip: padding-box;
    border-radius: 99px;
}
.scrollable::-webkit-scrollbar-thumb:hover { background: #3B3F49; background-clip: padding-box; }

/* ---------------------------------------------------------------- */
/* Utilities                                                         */
/* ---------------------------------------------------------------- */
.sr-only {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

[hidden] { display: none !important; }

.truncate {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

.stack { display: flex; flex-direction: column; }
.row { display: flex; align-items: center; }
.grow { flex: 1 1 auto; min-width: 0; }

.muted { color: var(--text-dim); }
.faint { color: var(--text-faint); }

.eyebrow {
    font-size: .6875rem;
    font-weight: 700;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--text-faint);
}

.beam-text {
    background: var(--beam);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

/* ---------------------------------------------------------------- */
/* Brand mark                                                        */
/* ---------------------------------------------------------------- */
.mark {
    width: 100%;
    height: 100%;
    display: block;
    color: var(--accent-soft);
}
.mark__node {
    color: var(--accent-2);
    fill: var(--accent-2);
}
.mark__core { fill: currentColor; }

/* The node used to orbit the mark forever. A logo that never stops
   moving pulls the eye away from the conversation, so it only travels
   on the boot screen, once, while there is nothing else to look at. */
.boot__mark .mark__node {
    transform-origin: 24px 24px;
    animation: orbit 6s linear infinite;
}

@keyframes orbit {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}

/* ---------------------------------------------------------------- */
/* Boot screen                                                       */
/* ---------------------------------------------------------------- */
.boot {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: grid;
    place-content: center;
    justify-items: center;
    gap: 18px;
    background: var(--void);
    animation: fadeIn var(--mid) both;
}
.boot__mark { width: 62px; height: 62px; }
.boot__label {
    color: var(--text-faint);
    font-size: .8125rem;
    letter-spacing: .18em;
    text-transform: uppercase;
}
.boot__bar {
    width: 190px;
    height: 3px;
    border-radius: 99px;
    background: var(--surface-2);
    overflow: hidden;
}
.boot__bar span {
    display: block;
    width: 42%;
    height: 100%;
    border-radius: inherit;
    background: var(--beam);
    animation: sweep 1.25s var(--ease) infinite;
}
.boot.is-gone { animation: fadeOut var(--mid) both; pointer-events: none; }

@keyframes sweep {
    0%   { transform: translateX(-110%); }
    100% { transform: translateX(280%); }
}
@keyframes fadeIn  { from { opacity: 0; } to { opacity: 1; } }
@keyframes fadeOut { from { opacity: 1; } to { opacity: 0; visibility: hidden; } }

.spinner {
    display: inline-block;
    width: 14px; height: 14px;
    border: 2px solid var(--surface-4);
    border-top-color: var(--accent-2);
    border-radius: 50%;
    animation: spin .7s linear infinite;
    vertical-align: -2px;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Respect the OS setting and the in-app "reduce motion" preference. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .001ms !important;
    }
}
html[data-motion="reduced"] *,
html[data-motion="reduced"] *::before,
html[data-motion="reduced"] *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
}
