/* SatSafe · SkyMapper design system (Brand Guidelines FEB2026)
   Eclipse Indigo console, Twilight Orchid → Sky Whisper accents,
   Moon Ash text, crescent mark, grain + faint radar rings. */

@import url('https://fonts.googleapis.com/css2?family=Geist:wght@100..900&display=swap');

:root {
    /* ---- Brand palette ---- */
    --eclipse-indigo: #07052E;   /* primary dark ground */
    --twilight-orchid: #633dbc;  /* primary accent (purple) */
    --sky-whisper: #7992E3;      /* primary accent (blue) */
    --moon-ash: #D7E0F2;         /* primary light / text */
    --stellar-flare: #BAE03D;    /* secondary — success */
    --solar-ember: #E8562E;      /* secondary — error/danger */
    --nebula-shadow: #6D7285;    /* secondary — muted */

    /* ---- Semantic tokens ---- */
    --bg: #07052E;
    --bg-raise: #100c3d;
    --panel: rgba(20, 15, 62, 0.66);
    --border: rgba(215, 224, 242, 0.1);
    --border-strong: rgba(215, 224, 242, 0.2);

    --text: #D7E0F2;
    --text-2: #aeb9dc;
    --muted: #8188a0;

    /* accent scale (purple ↔ blue) */
    --accent: #8aa0ec;           /* bright highlight */
    --accent-deep: #633dbc;      /* twilight orchid */
    --blue: #7992E3;             /* sky whisper */
    --green: #BAE03D;            /* stellar flare */
    --amber: #E8562E;            /* solar ember (warn) */
    --red: #E8562E;              /* solar ember (error) */

    --font: "Geist", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
    --radius: 14px;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html {
    color-scheme: dark;
    scroll-padding-top: 88px; /* fixed header offset for in-page anchors */
}

body {
    position: relative;
    font-family: var(--font);
    font-size: 14px;
    line-height: 1.5;
    color: var(--text);
    padding-top: 68px; /* clears the fixed header */
    background:
        radial-gradient(1100px 520px at 72% -12%, rgba(99, 61, 188, 0.28), transparent 62%),
        radial-gradient(900px 500px at 8% 4%, rgba(121, 146, 227, 0.14), transparent 60%),
        var(--bg);
    min-height: 100vh;
}

/* Brand grain + faint concentric radar rings over the whole ground */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background:
        repeating-radial-gradient(circle at 82% 0%,
            rgba(121, 146, 227, 0.05) 0 1px,
            transparent 1px 78px),
        url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
    opacity: 0.5;
}

body > * { position: relative; z-index: 1; }

/* ---------- Site header (fixed, transparent, blurred) ---------- */

.site-header {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 50;
    height: 68px;
    background: rgba(12, 8, 46, 0.32);
    -webkit-backdrop-filter: blur(30px);
    backdrop-filter: blur(30px);
    border-bottom: 1px solid var(--border);
}

.header-inner {
    position: relative;
    z-index: 1;
    max-width: 1240px;
    height: 100%;
    margin: 0 auto;
    padding: 0 28px;
    display: flex;
    align-items: center;
    gap: 26px;
}

/* The brand lockup is a single asset - crescent and wordmark come together in
   the file, so nothing here draws or spaces them. */
.wordmark {
    display: flex;
    align-items: center;
    flex: none;
    text-decoration: none;
}

/* The asset carries ~12% empty space along its bottom edge, so the box is set
   a touch taller than the mark should read and nudged down to sit optically
   centred in the header. */
.wordmark img {
    display: block;
    height: 40px;
    width: auto;
    transform: translateY(2px);
}

.topbar-meta {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-left: auto;
    color: var(--muted);
    font-size: 12px;
}

.job-chip {
    font-variant-numeric: tabular-nums;
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 4px 12px;
    color: var(--text-2);
    background: var(--bg-raise);
    cursor: pointer;
    user-select: none;
    transition: border-color 0.15s ease, color 0.15s ease;
}

.job-chip:hover {
    border-color: rgba(121, 146, 227, 0.5);
    color: var(--text);
}

/* ---------- Layout ---------- */

.console {
    max-width: 1240px;
    margin: 0 auto;
    padding: 36px 28px 72px;
}

.micro-label {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--muted);
}

/* ---------- Run status ---------- */

.run-status {
    padding-bottom: 28px;
    border-bottom: 1px solid var(--border);
}

.run-head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 24px;
    margin-top: 10px;
}

.run-title {
    display: flex;
    align-items: center;
    gap: 12px;
    font-size: 22px;
    font-weight: 600;
    letter-spacing: -0.01em;
}

.status-dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--accent);
    box-shadow: 0 0 0 0 rgba(138, 160, 236, 0.5);
    animation: dot-pulse 2s ease-out infinite;
    flex: none;
}

.status-dot.done {
    animation: none;
    background: var(--green);
    box-shadow: none;
}

.status-dot.error {
    animation: none;
    background: var(--red);
}

@keyframes dot-pulse {
    0% { box-shadow: 0 0 0 0 rgba(138, 160, 236, 0.45); }
    70% { box-shadow: 0 0 0 9px rgba(138, 160, 236, 0); }
    100% { box-shadow: 0 0 0 0 rgba(138, 160, 236, 0); }
}

.progress-pct {
    font-size: 22px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--accent);
}

.progress-track {
    margin-top: 16px;
    height: 6px;
    border-radius: 999px;
    background: rgba(215, 224, 242, 0.08);
    overflow: hidden;
}

.progress-fill {
    position: relative;
    height: 100%;
    width: 0;
    border-radius: inherit;
    background: linear-gradient(90deg, var(--blue), var(--accent-deep));
    transition: width 0.6s cubic-bezier(0.22, 1, 0.36, 1);
    overflow: hidden;
}

.progress-fill::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(105deg, transparent 25%, rgba(255, 255, 255, 0.35) 50%, transparent 75%);
    transform: translateX(-100%);
    animation: progress-sheen 1.8s ease-in-out infinite;
}

.progress-fill.done::after { animation: none; opacity: 0; }

.progress-fill.error {
    background: var(--red);
}

@keyframes progress-sheen {
    to { transform: translateX(100%); }
}

.run-substatus {
    margin-top: 14px;
    font-size: 13px;
    color: var(--text-2);
    font-variant-numeric: tabular-nums;
    min-height: 20px;
}

.error-banner {
    margin-top: 16px;
    padding: 12px 16px;
    border: 1px solid rgba(232, 86, 46, 0.5);
    border-radius: var(--radius);
    background: rgba(232, 86, 46, 0.1);
    color: #f3a58c;
    font-size: 13px;
}

/* ---------- Panels ---------- */

.panel {
    margin-top: 32px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--panel);
    backdrop-filter: blur(14px);
}

.panel-head {
    display: flex;
    align-items: baseline;
    gap: 14px;
    padding: 18px 22px 0;
}

.panel-head h2 {
    font-size: 15px;
    font-weight: 600;
    letter-spacing: -0.005em;
}

.plot-mount {
    position: relative;
    min-height: 420px;
    margin: 8px 6px 6px;
}

/* Fullscreen toggle in the panel header */
.panel-expand {
    margin-left: auto;
    align-self: center;
    width: 30px;
    height: 30px;
    display: grid;
    place-items: center;
    background: transparent;
    border: 1px solid var(--border);
    border-radius: 8px;
    color: var(--muted);
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease;
}

.panel-expand:hover {
    color: var(--text);
    border-color: var(--border-strong);
}

.panel-expand svg {
    width: 14px;
    height: 14px;
}

/* Search input in a table panel header */
.panel-search {
    margin-left: auto;
    align-self: center;
    width: 230px;
    padding: 7px 12px;
    font-size: 13px;
}

section.panel:fullscreen {
    margin: 0;
    border: none;
    border-radius: 0;
    background: var(--bg);
    padding: 20px 24px;
    display: flex;
    flex-direction: column;
}

section.panel:fullscreen .plot-mount {
    flex: 1;
    min-height: 0;
}

section.panel:-webkit-full-screen {
    margin: 0;
    border: none;
    border-radius: 0;
    background: var(--bg);
    padding: 20px 24px;
    display: flex;
    flex-direction: column;
}

section.panel:-webkit-full-screen .plot-mount {
    flex: 1;
    min-height: 0;
}

/* Loader overlay while a plot has no data yet */
.plot-mount.is-loading::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 34px;
    height: 34px;
    margin: -28px 0 0 -17px;
    border-radius: 50%;
    border: 2px solid rgba(138, 160, 236, 0.18);
    border-top-color: var(--accent);
    animation: loader-spin 0.9s linear infinite;
}

.plot-mount.is-loading::after {
    content: "Waiting for satellite data\2026";
    position: absolute;
    top: calc(50% + 20px);
    left: 0;
    right: 0;
    text-align: center;
    font-size: 12px;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--muted);
}

@keyframes loader-spin {
    to { transform: rotate(360deg); }
}

/* ---------- Observation windows ---------- */

.windows-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    margin-top: 32px;
    border-block: 1px solid var(--border);
}

.window-block {
    padding: 22px 26px;
}

.window-block + .window-block {
    border-left: 1px solid var(--border);
}

.window-block .result-copy {
    margin-top: 10px;
    font-size: 13.5px;
    line-height: 1.7;
    color: var(--text-2);
}

.window-block .result-copy b {
    color: var(--text);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.result-copy.is-loading {
    animation: loader-pulse 1.6s ease-in-out infinite;
}

@keyframes loader-pulse {
    50% { opacity: 0.4; }
}

/* Window blocks get the same spinner treatment as the plots:
   the placeholder text is collapsed (font-size: 0) and replaced by
   a centered ring + uppercase label until results arrive. */
.window-block .result-copy.is-loading {
    animation: none;
    position: relative;
    font-size: 0;
    min-height: 110px;
}

.window-block .result-copy.is-loading::before {
    content: "";
    position: absolute;
    top: calc(50% - 30px);
    left: 50%;
    width: 28px;
    height: 28px;
    margin-left: -14px;
    border-radius: 50%;
    border: 2px solid rgba(138, 160, 236, 0.18);
    border-top-color: var(--accent);
    animation: loader-spin 0.9s linear infinite;
}

.window-block .result-copy.is-loading::after {
    content: "Waiting for run results\2026";
    position: absolute;
    top: calc(50% + 8px);
    left: 0;
    right: 0;
    text-align: center;
    font-size: 12px;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--muted);
}

/* ---------- Tables ---------- */

.table-scroll {
    overflow: auto;
    max-height: 840px;
    margin: 14px 6px 6px;
}

table {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
    /* fixed layout: column widths must not depend on the currently
       rendered window of virtual rows, or they jump while scrolling */
    table-layout: fixed;
}

thead th:nth-child(1) { width: 23%; }
thead th:nth-child(2) { width: 10%; }
thead th:nth-child(3) { width: 17.5%; }
thead th:nth-child(4) { width: 17.5%; }
thead th:nth-child(5) { width: 17.5%; }
thead th:nth-child(6) { width: 14.5%; }

thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    padding: 10px 16px;
    text-align: left;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--muted);
    background: #120d44;
    border-bottom: 1px solid var(--border-strong);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    cursor: pointer;
    user-select: none;
}

tbody td {
    /* 12px padding + 20px line-height = 44px row, matching the virtual
       table's fixed rowHeight */
    padding: 12px 16px;
    color: var(--text-2);
    border-bottom: 1px solid var(--border);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    font-variant-numeric: tabular-nums;
}

tbody td:first-child {
    color: var(--text);
    font-weight: 500;
}

tbody tr:hover td {
    background: rgba(215, 224, 242, 0.04);
}

tbody tr.row-last td {
    border-bottom: none;
}

/* Virtual table spacer rows keep scroll height, never render as content */
tbody tr.v-spacer td,
tbody tr.v-spacer:hover td {
    height: auto;
    padding: 0;
    border: 0;
    background: transparent;
}

/* Sort affordance */
thead th.sortable {
    position: sticky;
    padding-right: 28px;
    transition: color 0.15s ease;
}

thead th.sortable:hover {
    color: var(--text);
}

thead th.sortable::after {
    content: "\21C5";
    position: absolute;
    right: 10px;
    top: 50%;
    transform: translateY(-50%);
    opacity: 0.35;
}

thead th.sortable[data-sort-dir="asc"]::after {
    content: "\2191";
    opacity: 0.95;
    color: var(--accent);
}

thead th.sortable[data-sort-dir="desc"]::after {
    content: "\2193";
    opacity: 0.95;
    color: var(--accent);
}

/* ---------- Phase intros ---------- */

.phase-intro {
    margin-top: 72px;
    padding-bottom: 30px;
}

.phase-intro:first-child {
    margin-top: 0;
}

.phase-intro h1 {
    margin-top: 10px;
    font-size: 26px;
    font-weight: 600;
    letter-spacing: -0.015em;
}

.phase-intro p {
    margin-top: 10px;
    max-width: 62ch;
    font-size: 14px;
    color: var(--text-2);
}

/* ---------- Form sections (numbered steps) ---------- */

/* Side-column layout: step header on the left, fields on the right,
   sections separated by hairlines. */
.form-section {
    display: grid;
    grid-template-columns: 220px 1fr;
    column-gap: 48px;
    row-gap: 20px;
    padding-block: 36px;
    border-top: 1px solid var(--border);
}

.form-section > .step-head {
    grid-column: 1;
}

.form-section > :not(.step-head) {
    grid-column: 2;
}

.step-head {
    margin-bottom: 0;
}

/* Thin display numeral, per brand section-number treatment */
.step-num {
    font-size: 44px;
    font-weight: 200;
    line-height: 1;
    letter-spacing: 0.02em;
    color: var(--text);
    font-variant-numeric: tabular-nums;
}

.step-head h2 {
    margin-top: 12px;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--text);
    transition: color 0.2s ease;
}

/* Hovering anywhere in a section highlights its title */
.form-section:hover .step-head h2 {
    color: var(--accent);
}

.step-tag {
    margin-top: 6px;
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 10.5px;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--muted);
}

/* ---------- Collapsible sections ---------- */

/* Two header states live in the same box and cross-fade: the tall step head
   (expanded) and a full-width bar (collapsed). Nothing reflows between them,
   so only continuous properties animate - grid-template-rows, opacity,
   padding - and the section height interpolates without a jump. */

.form-section.is-collapsible {
    position: relative;
    padding-block: 36px;
    transition:
        padding-top var(--collapse-dur) var(--collapse-ease),
        padding-bottom var(--collapse-dur) var(--collapse-ease);
    --collapse-dur: 0.34s;
    --collapse-ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

.form-section.is-collapsible.is-collapsed {
    padding-block: 30px;   /* collapsed section is exactly 60px tall */
    row-gap: 0;
}

/* ---- expanded header ---- */

.form-section > .step-head-wrap {
    grid-column: 1;
    display: grid;
    grid-template-rows: 1fr;
    opacity: 1;
    visibility: visible;
    transition:
        grid-template-rows var(--collapse-dur) var(--collapse-ease),
        opacity 0.2s ease 0.1s,
        visibility 0s;
}

.step-head-wrap > .step-head {
    min-height: 0;
    overflow: hidden;
    cursor: pointer;
    user-select: none;
}

.step-head-wrap > .step-head:focus-visible {
    outline: 1px solid var(--accent);
    outline-offset: 10px;
    border-radius: 6px;
}

.form-section.is-collapsed > .step-head-wrap {
    grid-template-rows: 0fr;
    opacity: 0;
    visibility: hidden;
    transition:
        grid-template-rows var(--collapse-dur) var(--collapse-ease),
        opacity 0.16s ease,
        visibility 0s linear var(--collapse-dur);
}


/* ---- collapsed bar (absolutely positioned: never affects layout) ---- */

/* An abspos child of a grid container gets its containing block from its grid
   AREA whenever it has a definite placement - which the generic
   `.form-section > :not(.step-head)` rule would hand it, pinning the bar to
   column 2. Forcing auto placement puts the containing block back on the
   section's padding box, so `left: 0` is the section's left edge. */
.form-section.is-collapsible > .step-bar,
.form-section.is-collapsible > .step-chevron {
    grid-column: auto;
    grid-row: auto;
}

/* The bar fills the whole collapsed row rather than hugging its text, so the
   entire 60px strip is the hit area. The text stays vertically centred through
   align-content - the row itself is centred while the words inside it keep
   their shared baseline. The chevron is a later sibling, so it still sits on
   top of the bar and keeps its own hover state. */
.step-bar {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: baseline;
    align-content: center;
    flex-wrap: wrap;
    gap: 4px 18px;
    margin: 0;
    padding: 0 44px 0 0; /* keeps a long title from running under the chevron */
    border: 0;
    background: none;
    font: inherit;
    color: inherit;
    text-align: left;
    cursor: pointer;
    user-select: none;
    opacity: 1;
    visibility: visible;
    transition: opacity 0.22s ease 0.1s, visibility 0s;
}

.form-section.is-collapsible:not(.is-collapsed) > .step-bar {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 0.16s ease, visibility 0s linear 0.16s;
}

/* The ring is inset: the bar now spans the whole row, so an outward offset
   would draw a box around the entire section. */
.step-bar:focus-visible {
    outline: 1px solid var(--accent);
    outline-offset: -6px;
    border-radius: 10px;
}

.step-bar-num {
    font-size: 20px;
    font-weight: 200;
    line-height: 1;
    letter-spacing: 0.02em;
    color: var(--text);
    font-variant-numeric: tabular-nums;
}

.step-bar-title {
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--text);
    transition: color 0.2s ease;
}

.step-bar-tag {
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 10.5px;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--muted);
}

.step-bar-tag::before {
    content: "";
    display: inline-block;
    width: 3px;
    height: 3px;
    margin-right: 18px;
    border-radius: 50%;
    background: var(--border-strong);
    vertical-align: middle;
}

.form-section.is-collapsible:hover .step-bar-title {
    color: var(--accent);
}

/* ---- chevron: fixed anchor in the section's top-right corner.
       The section only ever grows downward, so a constant `top` keeps the
       chevron pinned in place - it rotates, it never travels. ---- */

.step-chevron {
    position: absolute;
    top: 17px;    /* centred in the 60px collapsed bar */
    right: 0;
    display: grid;
    place-items: center;
    width: 26px;
    height: 26px;
    padding: 0;
    font: inherit;
    background: none;
    border: 1px solid var(--border);
    border-radius: 50%;
    color: var(--muted);
    cursor: pointer;
    transition:
        transform var(--collapse-dur) var(--collapse-ease),
        border-color 0.2s ease,
        background-color 0.2s ease,
        color 0.2s ease;
}

.step-chevron::before {
    content: "";
    width: 7px;
    height: 7px;
    margin-top: -2px;
    border-right: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
    transform: rotate(45deg);
}

.form-section.is-collapsed > .step-chevron {
    transform: rotate(-90deg);
}

.form-section.is-collapsible:hover > .step-chevron {
    border-color: var(--border-strong);
    color: var(--text-2);
    background: rgba(215, 224, 242, 0.04);
}

/* Pointing at the chevron itself commits harder than hovering the section.
   Needs the full section prefix to outrank the section-hover rule above. */
.form-section.is-collapsible > .step-chevron:hover {
    border-color: rgba(121, 146, 227, 0.6);
    color: var(--text);
    background: rgba(121, 146, 227, 0.14);
}

.step-chevron:focus-visible {
    outline: 1px solid var(--accent);
    outline-offset: 4px;
}

/* ---- fields column ---- */

.section-body {
    display: grid;
    grid-template-rows: 1fr;
    opacity: 1;
    transition:
        grid-template-rows var(--collapse-dur) var(--collapse-ease),
        opacity 0.22s ease 0.08s;
}

.section-body-inner {
    min-height: 0;
    overflow: hidden;
    display: grid;
    row-gap: 20px;
}

.form-section.is-collapsed > .section-body {
    grid-template-rows: 0fr;
    opacity: 0;
    transition:
        grid-template-rows var(--collapse-dur) var(--collapse-ease),
        opacity 0.16s ease;
}

.grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 18px 20px;
}

.form-section .grid + .grid {
    margin-top: 0; /* the section's row-gap provides the rhythm */
}

.field label {
    display: block;
    margin-bottom: 7px;
    font-size: 13px;
    font-weight: 500;
    color: var(--text-2);
}

.field:has(input[required], select[required]) > label::after {
    content: " *";
    color: var(--red);
    font-weight: 600;
}

.field small {
    display: block;
    margin-top: 7px;
    font-size: 12px;
    color: var(--muted);
}

input,
select {
    width: 100%;
    padding: 10px 12px;
    font: inherit;
    color: var(--text);
    background: var(--bg-raise);
    border: 1px solid var(--border);
    border-radius: 10px;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

/* Example values sit clearly below the entered-value hue, so a placeholder is
   never mistaken for a filled field */
input::placeholder {
    color: var(--muted);
    opacity: 1; /* Firefox dims placeholders on top of the colour */
}

input:hover,
select:hover {
    border-color: var(--border-strong);
}

input:focus,
select:focus {
    outline: none;
    border-color: var(--sky-whisper);
    box-shadow: 0 0 0 3px rgba(121, 146, 227, 0.22);
}

select {
    appearance: none;
    padding-right: 36px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%238188a0' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 14px center;
    cursor: pointer;
}

select option {
    background: #120d44;
    color: var(--text);
}

/* ---------- Location lookup ---------- */

/* The bar and its status line are wrapped in one element so the section grid
   treats them as a single row rather than two full-width items. */
.locator {
    display: block;
}

/* Search field and both actions share one bordered shell, so the row reads as
   a single control instead of three competing boxes. */
.locator-bar {
    position: relative; /* anchors the suggestion list */
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 5px 5px 5px 14px;
    background: var(--bg-raise);
    border: 1px solid var(--border);
    border-radius: 12px;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.locator-bar:hover {
    border-color: var(--border-strong);
}

.locator-bar:focus-within {
    border-color: var(--sky-whisper);
    box-shadow: 0 0 0 3px rgba(121, 146, 227, 0.22);
}

.locator-icon {
    width: 16px;
    height: 16px;
    flex: none;
}

.locator-glyph {
    color: var(--muted);
}

/* The shell carries the border and focus ring, so the input itself is bare */
.locator-input {
    flex: 1 1 auto;
    width: auto; /* the base input rule is width:100%, which skews flex sizing */
    min-width: 0;
    padding: 8px 0;
    font-size: 14.5px;
    line-height: 1.5;
    background: none;
    border: none;
    border-radius: 0;
}

.locator-input:hover,
.locator-input:focus {
    border: none;
    box-shadow: none;
}

.locator-input::placeholder {
    color: var(--muted);
}

.locator-sep {
    flex: none;
    width: 1px;
    height: 22px;
    background: var(--border);
}

/* Suggestion list: same surface as the date picker popup, so both overlays
   read as one family. It spans the whole bar rather than just the input, which
   keeps long addresses on one line. */
.locator-suggest {
    position: absolute;
    z-index: 30;
    top: calc(100% + 8px);
    left: -1px;
    right: -1px;
    max-height: 288px;
    overflow-y: auto;
    padding: 6px;
    margin: 0;
    list-style: none;
    background: rgba(18, 13, 68, 0.96);
    -webkit-backdrop-filter: blur(24px);
    backdrop-filter: blur(24px);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    box-shadow: 0 24px 60px rgba(3, 2, 18, 0.6);
    animation: dtp-in 0.14s ease;
}

.locator-suggest[hidden] { display: none; }

.locator-suggest-item {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 8px 10px;
    border-radius: 9px;
    cursor: pointer;
}

/* Keyboard and pointer share one highlight, so the list never shows two */
.locator-suggest-item.is-active {
    background: rgba(121, 146, 227, 0.16);
}

.locator-suggest-name {
    font-size: 13.5px;
    color: var(--text);
}

/* The administrative tail is context, not the answer - one line, clipped */
.locator-suggest-detail {
    font-size: 12px;
    color: var(--muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.locator-suggest-detail:empty { display: none; }

.locator-ghost,
.locator-find {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 9px 16px;
    font: inherit;
    font-size: 13.5px;
    border-radius: 8px;
    white-space: nowrap;
    cursor: pointer;
    border: none;
}

/* Secondary action: quiet until hovered, so "Find" stays the obvious one */
.locator-ghost {
    position: relative;
    font-weight: 500;
    color: var(--text-2);
    background: none;
    transition: color 0.15s ease, background 0.15s ease, box-shadow 0.2s ease;
}

.locator-ghost:hover {
    color: var(--text);
    background: rgba(121, 146, 227, 0.12);
}

/* Locking on: the crosshair sweeps while the fix is being acquired */
@keyframes locator-sweep {
    to { transform: rotate(360deg); }
}

.locator-ghost.is-busy .locator-pin-ring {
    transform-box: fill-box;
    transform-origin: center;
    animation: locator-sweep 1.4s linear infinite;
}

.locator-ghost.is-busy {
    color: var(--text);
    background: rgba(121, 146, 227, 0.12);
}

/* Fix acquired: the button holds an "active source" state so the choice stays
   readable after the spinner stops. Only the crosshair centre goes to the
   brand success colour - the chrome keeps the accent hue. Editing a coordinate
   by hand drops the class and the button goes quiet again. */
.locator-ghost.is-active {
    color: #dfe6ff;
    background: rgba(121, 146, 227, 0.16);
    box-shadow: inset 0 0 0 1px rgba(121, 146, 227, 0.4);
}

.locator-ghost.is-active .locator-pin-dot {
    fill: var(--green);
    stroke: var(--green);
}

.locator-find {
    padding-inline: 20px;
    font-weight: 600;
    color: #fff;
    background-image: linear-gradient(180deg, var(--sky-whisper), var(--accent-deep));
    transition: filter 0.15s ease;
}

.locator-find:hover { filter: brightness(1.08); }

/* The gradient button carries no icon: it breathes instead of growing a
   spinner, which would widen the button and shift the bar mid-request */
@keyframes locator-find-pulse {
    0%, 100% { filter: brightness(1); }
    50% { filter: brightness(1.28); }
}

.locator-find.is-busy {
    animation: locator-find-pulse 1s ease-in-out infinite;
}

.locator-ghost:focus-visible,
.locator-find:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(121, 146, 227, 0.28);
}

/* A busy button keeps full contrast - its spinner is the feedback, not dimming */
.locator-ghost[disabled],
.locator-find[disabled] {
    cursor: progress;
}

.locator-ghost[disabled]:not(.is-busy),
.locator-find[disabled]:not(.is-busy) {
    opacity: 0.55;
}

/* A quiet caption rather than a full-width pill: the section grid stretches
   any direct child, and a stretched pill dwarfs its own text. */
.locator-status {
    display: flex;
    align-items: flex-start;
    gap: 9px;
    margin: 12px 0 0;
    padding-inline: 3px;
    font-size: 12.5px;
    line-height: 1.6;
    color: var(--text-2);
}

.locator-status::before {
    content: "";
    flex: none;
    width: 6px;
    height: 6px;
    margin-top: 7px;
    border-radius: 50%;
    background: var(--sky-whisper);
}

.locator-status.is-error {
    color: #f3a58c;
}

.locator-status.is-error::before {
    background: var(--red);
}

/* Matches the button: green while the fix is what the form holds */
.locator-status.is-located:not(.is-error)::before {
    background: var(--green);
}

/* Each new message slides in, so a changed line is not missed */
@keyframes locator-status-in {
    from { opacity: 0; transform: translateY(-4px); }
    to { opacity: 1; transform: none; }
}

.locator-status.is-fresh {
    animation: locator-status-in 0.28s ease-out;
}

/* Pending: the marker breathes until the lookup resolves */
@keyframes locator-dot-pulse {
    0%, 100% { transform: scale(0.7); opacity: 0.5; }
    50% { transform: scale(1.15); opacity: 1; }
}

.locator-status.is-busy {
    color: var(--muted);
}

.locator-status.is-busy::before {
    animation: locator-dot-pulse 1.1s ease-in-out infinite;
}

.locator-status:empty { display: none; }

@media (prefers-reduced-motion: reduce) {
    .locator-status.is-fresh,
    .locator-status.is-busy::before,
    .locator-ghost.is-busy .locator-pin-ring,
    .locator-find.is-busy {
        animation: none;
    }
}

@media (max-width: 640px) {
    /* Narrow shell: the field takes its own row, the actions share the next */
    .locator-bar {
        flex-wrap: wrap;
        padding: 8px;
    }

    .locator-glyph { margin-left: 6px; }
    .locator-input { flex: 1 1 60%; }
    .locator-sep { display: none; }

    .locator-ghost,
    .locator-find {
        flex: 1 1 auto;
        justify-content: center;
    }
}

/* ---------- Buttons ---------- */

.button-row {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-top: 28px;
    flex-wrap: wrap;
}

/* Standard action footer: hairline on top, note on the left, button on the right */
.action-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 24px;
    padding-block: 26px;
    border-top: 1px solid var(--border);
    flex-wrap: wrap;
}

.action-note {
    font-size: 12.5px;
    line-height: 1.7;
    color: var(--muted);
    max-width: 60ch;
}

.btn-primary,
.btn-secondary {
    padding: 11px 22px;
    font: inherit;
    font-weight: 600;
    border-radius: 10px;
    border: 1px solid transparent;
    cursor: pointer;
    transition: filter 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}

.btn-primary {
    color: #fff;
    background-image: linear-gradient(180deg, var(--sky-whisper), var(--accent-deep));
    /* no transparent border over the gradient (it renders as a lighter rim);
       padding compensates to keep the same box size as the other buttons */
    border: none;
    padding: 12px 23px;
}

.btn-primary:hover { filter: brightness(1.08); }

.btn-secondary {
    color: var(--text);
    background: transparent;
    border-color: var(--border-strong);
}

/* Dimmed rather than hidden: the caption beside it explains why there is
   nothing to fetch, and the button reappearing later would be a surprise */
.btn-secondary[disabled] {
    opacity: 0.45;
    cursor: default;
}

.btn-secondary:hover {
    border-color: rgba(121, 146, 227, 0.6);
    background: var(--bg-raise);
}

/* Filled vertical gradient (soft-blue → purple), white label */
.btn-outline {
    padding: 12px 23px;
    font: inherit;
    font-weight: 600;
    color: #fff;
    cursor: pointer;
    border: none;
    border-radius: 10px;
    background-image: linear-gradient(180deg, var(--sky-whisper), var(--accent-deep));
    transition: filter 0.15s ease;
}

.btn-outline:hover { filter: brightness(1.08); }

.btn-outline:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(121, 146, 227, 0.28);
}

/* the label span keeps its class but renders as solid white on the fill */
.text-gradient {
    -webkit-text-fill-color: #fff;
    color: #fff;
    background: none;
}

.btn-primary:focus-visible,
.btn-secondary:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(121, 146, 227, 0.28);
}

.button-link {
    font-size: 14px;
    color: var(--text-2);
    text-decoration: none;
    transition: color 0.15s ease;
}

.button-link:hover { color: var(--accent); }

/* ---------- Status pill ---------- */

.status-pill {
    display: inline-block;
    margin-top: 14px;
    padding: 8px 14px;
    font-size: 13px;
    color: var(--text-2);
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--bg-raise);
}

.status-pill.error {
    color: #f3a58c;
    border-color: rgba(232, 86, 46, 0.5);
    background: rgba(232, 86, 46, 0.1);
}

.status-pill:empty { display: none; }

/* ---------- Validation result ---------- */

#validation_result .panel {
    padding: 22px 26px;
    margin-top: 24px;
}

.section-title {
    font-size: 15px;
    font-weight: 600;
    margin-bottom: 14px;
}

.result-copy {
    font-size: 13.5px;
    line-height: 1.7;
    color: var(--text-2);
}

.result-copy b {
    color: var(--text);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.result-copy h4 {
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--muted);
    margin-bottom: 8px;
}

.two-column {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 20px;
}

.two-column img {
    max-width: 100%;
    border: 1px solid var(--border);
    border-radius: 10px;
    margin-top: 8px;
}

.spacer-top { margin-top: 20px; }

/* ---------- UTC date-time picker ---------- */

/* The text field keeps its own look; the wrapper only adds the trigger and
   anchors the popup. */
.dtp-field {
    position: relative;
}

.dtp-input {
    padding-right: 42px; /* clears the trigger */
    font-variant-numeric: tabular-nums;
}

.dtp-trigger {
    position: absolute;
    top: 50%;
    right: 6px;
    transform: translateY(-50%);
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    padding: 0;
    color: var(--muted);
    background: transparent;
    border: 0;
    border-radius: 8px;
    cursor: pointer;
    transition: color 0.15s ease, background 0.15s ease;
}

.dtp-trigger svg {
    width: 16px;
    height: 16px;
}

.dtp-trigger:hover,
.dtp-field.is-open .dtp-trigger {
    color: var(--text);
    background: rgba(121, 146, 227, 0.12);
}

.dtp-trigger:focus-visible {
    outline: 2px solid var(--sky-whisper);
    outline-offset: 1px;
}

.dtp-pop {
    position: absolute;
    z-index: 40;
    top: calc(100% + 8px);
    left: 0;
    width: 286px;
    max-width: calc(100vw - 32px);
    padding: 14px;
    background: rgba(18, 13, 68, 0.96);
    -webkit-backdrop-filter: blur(24px);
    backdrop-filter: blur(24px);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    box-shadow: 0 24px 60px rgba(3, 2, 18, 0.6);
    animation: dtp-in 0.14s ease;
}

/* Flip classes are set from JS once the popup has been measured */
.dtp-pop.is-above {
    top: auto;
    bottom: calc(100% + 8px);
}

.dtp-pop.is-right {
    left: auto;
    right: 0;
}

@keyframes dtp-in {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: none; }
}

.dtp-head {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 10px;
}

.dtp-title {
    flex: 1;
    text-align: center;
    font-size: 13px;
    font-weight: 500;
    color: var(--text);
}

.dtp-nav {
    display: grid;
    place-items: center;
    width: 26px;
    height: 26px;
    flex: none;
    padding: 0;
    color: var(--text-2);
    background: transparent;
    border: 1px solid var(--border);
    border-radius: 8px;
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}

.dtp-nav svg {
    width: 14px;
    height: 14px;
}

.dtp-nav:hover {
    color: var(--text);
    border-color: var(--border-strong);
    background: rgba(121, 146, 227, 0.1);
}

.dtp-week,
.dtp-grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 2px;
}

.dtp-week {
    margin-bottom: 4px;
    font-size: 10.5px;
    font-weight: 500;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--muted);
    text-align: center;
}

.dtp-day {
    aspect-ratio: 1;
    padding: 0;
    font: inherit;
    font-size: 12.5px;
    font-variant-numeric: tabular-nums;
    color: var(--text-2);
    background: transparent;
    border: 1px solid transparent;
    border-radius: 8px;
    cursor: pointer;
    transition: color 0.12s ease, background 0.12s ease, border-color 0.12s ease;
}

.dtp-day:hover {
    color: var(--text);
    background: rgba(121, 146, 227, 0.12);
}

/* Today is marked by an outline, the selection by a fill, so both can show
   on the same cell without competing. */
.dtp-day.is-today {
    border-color: rgba(121, 146, 227, 0.45);
}

.dtp-day.is-selected {
    color: #fff;
    background: linear-gradient(135deg, var(--accent-deep), var(--sky-whisper));
    border-color: transparent;
}

.dtp-day:focus-visible {
    outline: 2px solid var(--sky-whisper);
    outline-offset: 1px;
}

.dtp-time {
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px solid var(--border);
}

.dtp-time-label {
    margin-bottom: 7px;
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--muted);
}

.dtp-time-row {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 6px 8px;
    background: var(--bg-raise);
    border: 1px solid var(--border);
    border-radius: 10px;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.dtp-time-row:focus-within {
    border-color: var(--sky-whisper);
    box-shadow: 0 0 0 3px rgba(121, 146, 227, 0.22);
}

/* The units share one shell, so each box drops its own chrome */
.dtp-num {
    width: 2.4ch;
    padding: 2px 0;
    font: inherit;
    font-size: 13.5px;
    font-variant-numeric: tabular-nums;
    text-align: center;
    color: var(--text);
    background: transparent;
    border: 0;
    border-radius: 4px;
}

.dtp-num.is-ms {
    width: 3.4ch;
}

/* The shared shell already shows the focus ring, so the inner box only tints */
.dtp-num:focus {
    outline: none;
    box-shadow: none;
    background: rgba(121, 146, 227, 0.16);
}

.dtp-sep {
    font-size: 13.5px;
    color: var(--muted);
}

.dtp-foot {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 10px;
    margin-top: 12px;
}

.dtp-hint-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-top: 7px;
}

.dtp-hint-row small {
    margin-top: 0;
}

.dtp-now {
    flex: none;
    margin-left: auto; /* holds the right edge when the field has no hint */
    padding: 4px 12px;
    font-size: 12px;
}

.dtp-ghost,
.dtp-done {
    padding: 7px 14px;
    font: inherit;
    font-size: 12.5px;
    font-weight: 500;
    border-radius: 999px;
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease, filter 0.15s ease;
}

.dtp-ghost {
    color: var(--text-2);
    background: transparent;
    border: 1px solid var(--border);
}

.dtp-ghost:hover {
    color: var(--text);
    border-color: var(--border-strong);
}

.dtp-done {
    color: #fff;
    background: linear-gradient(135deg, var(--accent-deep), var(--sky-whisper));
    border: 1px solid transparent;
}

.dtp-done:hover {
    filter: brightness(1.08);
}

.dtp-ghost:focus-visible,
.dtp-done:focus-visible {
    outline: 2px solid var(--sky-whisper);
    outline-offset: 2px;
}

/* ---------- Utility ---------- */

.hidden { display: none !important; }

@media (max-width: 900px) {
    .form-section {
        grid-template-columns: 1fr;
    }
    .form-section > .step-head,
    .form-section > :not(.step-head) {
        grid-column: 1;
    }
}

@media (max-width: 760px) {
    .header-inner { padding: 0 16px; }
    .console { padding: 24px 16px 56px; }
    .windows-row { grid-template-columns: 1fr; }
    .window-block + .window-block {
        border-left: none;
        border-top: 1px solid var(--border);
    }
    .plot-mount { min-height: 320px; }
}

@media (prefers-reduced-motion: reduce) {
    .form-section.is-collapsible { --collapse-dur: 0.01s; }
    .dtp-pop,
    .locator-suggest { animation: none; }
    .progress-fill { transition: none; }
    .progress-fill::after,
    .status-dot,
    .plot-mount.is-loading::before,
    .window-block .result-copy.is-loading::before,
    .result-copy.is-loading { animation: none; }
}
