/* =========================================================
   ETHERIUM WORKSPACE
   A GIS workspace over the globe: toolbar, Contents (layers + sites),
   Inspector (the selected site), status bar. The globe and its galaxy
   stay full-bleed underneath; panels are ink sheets over them.
   Geist throughout, with Geist Mono for coordinates and measurements.
========================================================= */

:root {
    --ink: rgba(0, 0, 0, 0.6);             /* panel sheets: glassy black */
    --ink-solid: #090c12;
    --raise: rgba(255, 255, 255, 0.045);   /* rows, inputs */
    --raise-hi: rgba(255, 255, 255, 0.08);
    --line: rgba(170, 186, 214, 0.13);
    --line-strong: rgba(170, 186, 214, 0.26);
    --text: #e7eaef;
    --muted: #9aa3b0;                      /* 7:1 on the ink */
    --site: #f4b860;                       /* sites on the map */
    --deep: #424447bf;                     /* actions: a translucent graphite over whatever is behind */
    --deep-hover: #55585cd9;
    --deep-line: rgba(255, 255, 255, 0.16);
    --focus: #8fb2ff;
    --offwhite: #ece9e3;                   /* toolbar buttons */
    --offwhite-hi: #fbf9f6;

    /* Provenance. Where a number came from is a state, so it gets a state
       colour: teal for anything the sensor measured, amber for anything the
       model inferred. The two are never mixed in one readout. */
    --sensor: #5cc3ae;
    --sensor-dim: rgba(92, 195, 174, 0.16);
    --model: #e0a24e;
    --model-dim: rgba(224, 162, 78, 0.14);

    --top: 56px;                           /* below the toolbar */
    --bottom: 38px;                        /* above the status bar */
    --left-w: 272px;
    --right-w: 360px;
    --stats-h: 0px;                        /* the statistics dock, when open */
    --gap: 10px;
    --ctrl-right: calc(var(--right-w) + var(--gap));
    --ease-out: cubic-bezier(0.16, 1, 0.3, 1);

    /* Where the tool group sits on the toolbar. auto centres it in the space
       left after the brand and the right-hand buttons; a length pins it that
       far from the brand instead. Either way the right-hand group stays put. */
    --tb-left: auto;
}

body.stats-open { --stats-h: 34vh; }

* { box-sizing: border-box; }
[hidden] { display: none !important; }

html, body {
    margin: 0;
    height: 100%;
    overflow: hidden;
    background: #000;
    color: var(--text);
    font-family: "Poppins", system-ui, sans-serif;
    font-size: 13px;
    line-height: 1.45;
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3, p, dl, dd, ul, figure { margin: 0; }
ul { padding: 0; list-style: none; }
button, input { font: inherit; color: inherit; }
button { cursor: pointer; }
svg { fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }

:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
::selection { background: rgba(53, 83, 168, 0.8); color: #fff; }


/* ---------- Sky + map ---------- */

.sky {
    position: fixed;
    inset: 0;
    z-index: 0;
    width: 100%;
    height: 100%;
    display: block;
    background: #000;
    pointer-events: none;
}

#globe {
    position: fixed;
    inset: 0;
    z-index: 1;
    background: transparent;
}

body[data-tool="identify"] #globe .maplibregl-canvas,
body[data-tool="measure"] #globe .maplibregl-canvas { cursor: crosshair; }
/* Ctrl held: the pointer is about to spend units on the outlined block */
body.ctrl-armed #globe .maplibregl-canvas { cursor: cell; }

#globe .maplibregl-canvas:focus-visible { outline: 2px solid var(--focus); outline-offset: -4px; }

/* scale bar and attribution: right-hand corner, clear of the inspector when it's open */
#globe .maplibregl-ctrl-bottom-right { bottom: var(--bottom); right: var(--ctrl-right); }

#globe .maplibregl-ctrl-attrib {
    background: rgba(0, 0, 0, 0.66);
    color: var(--muted);
    font-family: inherit;
    font-size: 11px;
}
#globe .maplibregl-ctrl-attrib a { color: var(--text); }

#globe .maplibregl-ctrl-scale {
    background: rgba(0, 0, 0, 0.55);
    border-color: var(--text);
    color: var(--text);
    font-family: inherit;
    font-size: 11px;
    font-variant-numeric: tabular-nums;
}

.map-msg {
    position: fixed;
    top: calc(var(--top) + 4px);
    left: 50%;
    z-index: 3;
    transform: translateX(-50%);
    padding: 6px 12px;
    border-radius: 6px;
    background: var(--ink);
    border: 1px solid var(--line);
    color: var(--text);
    font-size: 12px;
    white-space: nowrap;
}

/* identify popup */
#globe .maplibregl-popup-content {
    padding: 10px 12px;
    background: var(--ink-solid);
    color: var(--text);
    border: 1px solid var(--line-strong);
    border-radius: 6px;
    font-size: 12px;
    box-shadow: 0 8px 28px rgba(0, 0, 0, 0.5);
}
#globe .maplibregl-popup-tip { border-top-color: var(--ink-solid); border-bottom-color: var(--ink-solid); }
#globe .maplibregl-popup-close-button { color: var(--muted); font-size: 16px; padding: 0 6px; }
.popup-title { font-stretch: 115%; font-weight: 600; margin-bottom: 4px; }
.popup-grid { display: grid; grid-template-columns: auto auto; gap: 1px 12px; font-variant-numeric: tabular-nums; }
.popup-grid dt { color: var(--muted); }





/* ---------- Toolbar ---------- */

.toolbar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;                  /* full width, flush to the top edge */
    z-index: 5;
    height: var(--top);
    padding: 10px ;
    display: flex;
    
    align-items: center;
    gap: 14px;
    background: rgba(0, 0, 0, 0.82);
    border: 0;
    border-bottom: 1px solid var(--line);
    border-radius: 0;
    backdrop-filter: blur(18px) saturate(130%);
}

.brand {
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    flex: none;
    margin-right: 4px;
    border-radius: 8px;
    color: var(--text);
    text-decoration: none;
    font-stretch: 125%;
    font-weight: 700;
    font-size: 14px;
    letter-spacing: 0.02em;
}
.brand img { width: 24px; height: 24px; display: block; }
.brand:hover { background: rgba(255, 255, 255, 0.08); }

/* Place search: the same off-white vocabulary as the buttons beside it, so
   the bar reads as one control set. */
.tb-search {
    display: flex;
    align-items: center;
    flex: none;
    height: 32px;
    margin-left: 4px;
    border: 1px solid rgba(0, 0, 0, 0.16);
    border-radius: 7px;
    background: black;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.45), 0 3px 10px rgba(0, 0, 0, 0.3);
    transition: background 0.2s ease, box-shadow 0.2s ease;
}
.tb-search:focus-within { background: black; box-shadow: 0 0 0 2px var(--focus), 0 3px 10px rgba(0, 0, 0, 0.3); }

.tb-search input {
    width: 180px;
    height: 100%;
    padding: 0 4px 0 11px;
    border: 0;
    background: none;
    color: #ffffff;
    font: inherit;
    outline: none;
}
/* ---------- Search suggestions ----------
   The field is a combobox: the panel hangs under it, escaping the toolbar,
   and every row names a place in two registers - what it is, then where it is. */

.tb-search { position: relative; }

.ac {
    position: fixed;
    width: 330px;
    max-width: calc(100vw - 24px);
    z-index: 20;
    padding: 6px;
    background: var(--ink-solid);
    border: 1px solid var(--line-strong);
    border-radius: 10px;
    box-shadow: 0 10px 34px rgba(0, 0, 0, 0.62), 0 2px 6px rgba(0, 0, 0, 0.5);
}
.ac[hidden] { display: none; }

.ac-list {
    max-height: 332px;
    overflow-y: auto;
    margin: 0;
    padding: 0;
    list-style: none;
    scrollbar-width: thin;
    scrollbar-color: rgba(170, 186, 214, 0.25) transparent;
}

.ac-opt {
    display: grid;
    grid-template-columns: 17px 1fr;
    align-items: center;
    column-gap: 11px;
    padding: 8px 9px;
    border-radius: 7px;
    cursor: pointer;
    transition: background 0.15s ease;
}
.ac-opt svg {
    width: 15px;
    height: 15px;
    color: var(--muted);
    transition: color 0.15s ease;
}
.ac-opt:hover,
.ac-opt.is-active { background: var(--raise); }
.ac-opt.is-active svg { color: var(--focus); }

.ac-text { min-width: 0; display: grid; }
.ac-name {
    font-size: 13px;
    line-height: 1.35;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.ac-where {
    font-size: 11.5px;
    line-height: 1.35;
    color: var(--muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* what you typed, inside what we found */
.ac-name mark {
    background: none;
    color: var(--focus);
    font-weight: 600;
}

/* Loading reads as the rows that are coming, not as a spinner over nothing. */
.ac-skel { padding: 8px 9px; display: grid; grid-template-columns: 17px 1fr; column-gap: 11px; align-items: center; }
.ac-skel span {
    height: 9px;
    border-radius: 4px;
    background: linear-gradient(90deg, var(--raise) 25%, var(--raise-hi) 50%, var(--raise) 75%) 0 0 / 240% 100%;
    animation: ac-shimmer 1.1s linear infinite;
}
.ac-skel .ac-skel-dot { width: 15px; height: 15px; border-radius: 50%; }
.ac-skel:nth-child(2) span:last-child { width: 78%; }
.ac-skel:nth-child(3) span:last-child { width: 58%; }
@keyframes ac-shimmer { to { background-position: -240% 0; } }

.ac-msg {
    padding: 9px 10px 7px;
    color: var(--muted);
    font-size: 12px;
    line-height: 1.45;
}
.ac-msg[hidden] { display: none; }
.ac-msg b { color: var(--text); font-weight: 500; }

.tb-search input::placeholder { color: #f8f9fabd; }
/* the native clear button ships black, which is invisible on a dark field */
.tb-search input::-webkit-search-cancel-button { filter: invert(1) opacity(0.45); }

.tb-search button {
    display: grid;
    place-items: center;
    width: 30px;
    height: 100%;
    padding: 0;
    border: 0;
    border-radius: 0 6px 6px 0;
    background: none;
    color: #ebecee;
    transition: background 0.2s ease, color 0.2s ease;
}
.tb-search button:hover:not(:disabled) { background: rgba(255, 255, 255, 0.1); color: #fff; }
.tb-search button:disabled { opacity: 0.4; cursor: default; }
.tb-search button svg { width: 16px; height: 16px; }
.tb-search[aria-busy="true"] button svg { animation: blink 1s ease-in-out infinite; }

/* the three map tools, centred on the bar */
.tb-sections { display: flex; gap: 14px; 
    justify-content: center;align-items: center;}

.tb-end { display: flex;
        gap: 14px;
        margin-left: auto;   /* hard right, whatever sits before it */
    }

.tb-btn {
    height: 32px;
    padding: 0 10px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    border: none;
    border-radius: 50%;
    background: transparent;
    color: #fdfeff;
    font-weight: 500;
    text-decoration: none;
    white-space: nowrap;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.45), 0 3px 10px rgba(0, 0, 0, 0.3);
    transition: background 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
}
.tb-btn svg { width: 16px; height: 16px; flex: none; }

/* the map tools are icon-only circles; their title still names them */
.tb-sections .tb-btn { width: 32px; padding: 0; }
.tb-sections .tb-btn span { display: none; }
/* the right-hand pair is text, so it keeps a pill and sizes to its label */
.tb-end .tb-btn { border-radius: 10px; }
.tb-btn.icon-only { width: 32px; padding: 0; justify-content: center; }
.tb-btn:hover {
    background: rgba(255, 255, 255, 0.24);
    transform: translateY(-1px);
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5), 0 6px 16px rgba(0, 0, 0, 0.38);
}
.tb-btn:active { transform: translateY(0); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); }
.tb-btn svg { color: #ffffff; }
.tb-btn[aria-pressed="true"] {
    background: var(--deep);
    border-color: var(--deep-line);
    color: #fff;
}
.tb-btn[aria-pressed="true"] svg { color: #c9d4f2; }

/* Model report and Back to site are chrome, not map tools. They carry no
   shadow and never lift, so the filled circle that rises stays the signal
   for "this acts on the map". Statistics keeps the tool hover: it toggles. */
.tb-chrome {
    border: none;
    background: transparent;
    color: white;
    box-shadow: none;
    transition: color 0.2s ease, border-color 0.2s ease;
}
.tb-chrome:hover {
    background: transparent;
    border-color: none;
    background-color: #ffffff2f;
    transform: none;
    box-shadow: none;
}

.tb-end a:hover{
    background: transparent;
    border-color: none;
    background-color: #f505055e;
    transform: none;
    box-shadow: none;
    
}
.tb-chrome:active { transform: none; box-shadow: none; }

/* ---------- Tile engine switch ----------
   Auto on means panning past zoom 13 spends processing units on its own, so the
   track goes amber: the colour this UI already uses for the model's own output.
   Off it is a plain neutral, because nothing is being spent. */

.tswitch {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    height: 32px;
    padding: 0 9px 0 7px;
    border: 0;
    border-radius: 16px;
    background: transparent;
    color: var(--muted);
    font: inherit;
    font-size: 11.5px;
    cursor: pointer;
    transition: background 0.2s ease, color 0.2s ease;
}
.tswitch:hover { background: rgba(255, 255, 255, 0.08); color: var(--text); }

.tswitch-track {
    position: relative;
    width: 30px;
    height: 17px;
    flex: none;
    border-radius: 9px;
    background: rgba(255, 255, 255, 0.16);
    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.5);
    transition: background 0.18s var(--ease-out);
}
.tswitch-knob {
    position: absolute;
    top: 2px;
    left: 2px;
    width: 13px;
    height: 13px;
    border-radius: 50%;
    background: #cfd4dc;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
    transition: transform 0.18s var(--ease-out), background 0.18s var(--ease-out);
}
.tswitch[aria-checked="true"] { color: var(--text); }
.tswitch[aria-checked="true"] .tswitch-track { background: var(--model); }
.tswitch[aria-checked="true"] .tswitch-knob { transform: translateX(13px); background: #fff; }

/* the wider of the two words, so swapping them never shifts the toolbar */
.tswitch-label { white-space: nowrap; min-width: 42px; text-align: left; }

.tb-count {
    min-width: 18px;
    padding: 0 5px;
    border-radius: 9px;
    background: var(--raise-hi);
    color: var(--text);
    font-size: 11px;
    line-height: 18px;
    text-align: center;
    font-variant-numeric: tabular-nums;
}
.tb-btn .chev { width: 14px; height: 14px; color: var(--muted); margin-left: -2px; }

/* the note under the Data layers list in the left dock */
.menu-hint { padding: 6px 8px 4px; color: var(--muted); font-size: 12px; }


/* ---------- Panes ---------- */

.pane {
    position: fixed;
    top: var(--top);
    bottom: var(--bottom);
    z-index: 4;
    display: flex;
    flex-direction: column;
    background: var(--ink);
    border: 0;
    border-left: 1px solid var(--line);
    border-radius: 0;
    backdrop-filter: blur(18px) saturate(130%);
    overflow: hidden;
    transition: right 0.3s var(--ease-out), opacity 0.3s ease;
}

.pane-right { right: 0; width: var(--right-w); overflow-y: auto; }
body.right-closed .pane-right { right: calc(-1 * var(--right-w)); }
body.right-closed { --ctrl-right: var(--gap); }

.pane, .report { scrollbar-width: thin; scrollbar-color: rgba(170, 186, 214, 0.25) transparent; }


.pane-sec { padding: 14px 14px 12px; border-bottom: 1px solid var(--line); }
.pane-sec:last-child { border-bottom: 0; }

.pane-title {
    margin-bottom: 10px;
    font-stretch: 118%;
    font-weight: 600;
    font-size: 13px;
    color: var(--text);
}

.hint { color: var(--muted); font-size: 12px; }


/* ---------- Layers ----------
   One row per layer: a real tile from the source, name and source, the
   eye. Raster rows open (native <details>) to opacity; the thumbnail
   follows the slider and goes grey when the layer is hidden. */

.layers { display: grid; gap: 2px; margin: 0 -6px; }

/* A layer is one button: press it to show or hide that layer. The accent bar
   and the greyed thumbnail carry the state, so there is no icon to decode. */
.layer { border-radius: 7px; display: grid; grid-template-columns: 1fr auto; align-items: center; }

.layer-btn {
    display: grid;
    grid-template-columns: 2px 44px 1fr;
    align-items: center;
    column-gap: 10px;
    width: 100%;
    padding: 6px;
    border: 0;
    border-radius: 7px;
    background: transparent;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
    transition: background 0.2s ease;
}
/* The bar is the layer's level: full when the layer is at full opacity, and it
   empties from the top as you hold and drag the row. */
.layer-btn::before {
    content: "";
    width: 2px;
    height: 26px;
    border-radius: 2px;
    background: linear-gradient(to top,
        var(--focus) calc(var(--op, 1) * 100%),
        rgba(143, 178, 255, 0.16) calc(var(--op, 1) * 100%));
    transition: background 0.2s ease;   /* the thickening is a state, not a move */
}
/* while you are setting it, the bar is the control, so it thickens */
.layer.is-adjusting .layer-btn::before { width: 4px; }
.layer.is-adjusting .layer-btn { background: var(--raise); cursor: ns-resize; }
.layer.is-adjusting .layer-src { color: var(--focus); font-variant-numeric: tabular-nums; }
.layer-btn { touch-action: pan-y; }
.layer.is-adjusting .layer-btn { touch-action: none; }
.layer-btn:hover { background: var(--raise); }
.layer-btn:active { background: var(--raise-hi); }

.layer-thumb {
    position: relative;
    width: 44px;
    height: 44px;
    overflow: hidden;
    border-radius: 6px;
    background: #121823 center / cover no-repeat;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
}
/* hairline inside the edge, so light tiles don't bleed into the panel */
.layer-thumb::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12);
}
.layer-thumb img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: filter 0.35s var(--ease-out), transform 0.45s var(--ease-out);
}
.layer-btn:hover .layer-thumb img { transform: scale(1.06); }

.layer-text { min-width: 0; display: grid; }
.layer-name {
    font-weight: 500;
    line-height: 1.3;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.layer-src {
    color: var(--muted);
    font-size: 11.5px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* hidden layers */
.layer.is-off .layer-btn::before { background: #2b3342; }   /* off is off, whatever the level */
.layer.is-off .layer-thumb img { filter: grayscale(1) brightness(0.45); }
.layer.is-off .layer-name { color: var(--muted); }

/* ---------- The Layers box is a picker ----------
   One basemap at a time, so its rows read as radio options rather than as
   on/off toggles: every thumbnail stays in full colour, and the chosen row is
   named in the accent colour with a filled dot. The dot carries the state, so
   the accent bar the derived rows use is dropped here. */

#layers .layer-btn {
    grid-template-columns: 44px 1fr 18px;
    padding: 7px 8px;
}
#layers .layer-btn::before { display: none; }
#layers .layer-btn::after {
    content: "";
    width: 16px;
    height: 16px;
    border-radius: 50%;
    border: 1.5px solid var(--line-strong);
    transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
#layers .layer-btn:hover::after { border-color: var(--muted); }

#layers .layer-btn[aria-pressed="true"] { background: var(--raise); }
#layers .layer-btn[aria-pressed="true"] .layer-name { color: var(--focus); }
#layers .layer-btn[aria-pressed="true"]::after {
    border-color: var(--focus);
    /* the ring, a gap, then the dot: one element, two inset shadows */
    box-shadow: inset 0 0 0 2.5px var(--ink-solid), inset 0 0 0 8px var(--focus);
}

/* an option that is not chosen is still an option: no greying out */
#layers .layer.is-off .layer-thumb img { filter: none; }
#layers .layer.is-off .layer-name { color: var(--text); }


/* analyses only: drop the layer altogether */
.layer-remove {
    width: 28px;
    height: 28px;
    margin-right: 4px;
    display: grid;
    place-items: center;
    border: 0;
    border-radius: 6px;
    background: transparent;
    color: var(--muted);
    transition: color 0.2s ease, background 0.2s ease;
}
.layer-remove:hover { color: #fff; background: var(--deep-hover); }
.layer-remove svg { width: 15px; height: 15px; }

/* ---------- Enhancing a file you bring ---------- */
.drop {
    display: grid;
    gap: 3px;
    justify-items: center;
    padding: 14px 10px;
    border: 1px dashed var(--line-strong);
    border-radius: 9px;
    background: rgba(255, 255, 255, 0.02);
    text-align: center;
    cursor: pointer;
    transition: border-color 0.2s ease, background 0.2s ease;
}
.drop:hover, .drop.is-over { border-color: var(--focus); background: var(--raise); }
.drop.is-busy { border-style: solid; cursor: progress; }
.drop-main { font-size: 12px; color: var(--text); }
.drop-sub { font-size: 11px; color: var(--muted); }

.drop-note {
    margin-top: 7px;
    padding: 7px 9px;
    border-radius: 7px;
    background: var(--model-dim);
    color: var(--text);
    font-size: 11px;
    line-height: 1.5;
}
.drop-note[hidden] { display: none; }
.drop-note b { color: var(--model); font-weight: 500; }
.drop-note a { color: var(--focus); }

.btn-small { height: 28px; padding: 0 10px; font-size: 12px; justify-self: start; }


/* ---------- Layer box: bottom-left corner ---------- */

.layer-box {
    position: fixed;
    left: 0;
    top: var(--top);
    bottom: var(--bottom);
    z-index: 4;
    width: var(--left-w);
    overflow-y: auto;
    padding: 4px 10px;
    background: var(--ink);
    border: 0;
    border-right: 1px solid var(--line);
    backdrop-filter: blur(18px) saturate(130%);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
    transition: left 0.3s var(--ease-out);
}
body.left-closed .layer-box { left: calc(-1 * var(--left-w)); }

.box-head {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 34px;
    list-style: none;
    cursor: pointer;
    font-stretch: 118%;
    font-weight: 600;
}
.box-head::-webkit-details-marker { display: none; }
.box-head svg { width: 16px; height: 16px; color: var(--muted); }
.box-head .chev { margin-left: auto; transition: transform 0.3s var(--ease-out); }
/* every box in the dock, so a new one needs no rule of its own */
.layer-box details:not([open]) .chev { transform: rotate(180deg); }


/* ---------- Dock handles: collapse either panel for room on the globe ---------- */

.dock-toggle {
    position: fixed;
    top: calc(var(--top) + (100vh - var(--top) - var(--bottom)) / 2 - 29px);
    z-index: 6;
    width: 22px;
    height: 58px;
    padding: 0;
    display: grid;
    place-items: center;
    background: var(--deep);
    border: 1px solid var(--deep-line);
    color: var(--text);
    transition: left 0.3s var(--ease-out), right 0.3s var(--ease-out), background 0.2s ease;
}
.dock-toggle:hover { background: var(--deep-hover); color: #fff; }
.dock-toggle svg { width: 15px; height: 15px; transition: transform 0.3s var(--ease-out); }

.dock-left  { left: var(--left-w);   border-radius: 0 6px 6px 0; border-left: 0; }
.dock-right { right: var(--right-w); border-radius: 6px 0 0 6px; border-right: 0; }
body.left-closed  .dock-left  { left: 0; }
body.right-closed .dock-right { right: 0; }

/* the chevron always points the way the panel will move */
.dock-left svg { transform: rotate(180deg); }
body.left-closed .dock-left svg { transform: rotate(0deg); }
body.right-closed .dock-right svg { transform: rotate(180deg); }

/* ---------- Basemap switcher: the square over the map, bottom left ----------
   One square showing the basemap you are on. Press it for the picker, the way
   Google Earth does it, so the choice costs a corner of the map and not a
   panel section. It rides the left dock, staying clear of it when it is open. */

.basemap {
    position: fixed;
    left: calc(var(--left-w) + var(--gap));
    bottom: calc(var(--bottom) + var(--gap));
    z-index: 4;
    display: grid;
    justify-items: start;
    gap: 8px;
    transition: left 0.3s var(--ease-out);
}
body.left-closed .basemap { left: var(--gap); }

.basemap-btn {
    width: 56px;
    height: 56px;
    padding: 0;
    overflow: hidden;
    border: 1px solid var(--line-strong);
    border-radius: 10px;
    background: #121823 center / cover no-repeat;
    background-image: var(--basemap-thumb, none);
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.45);
    cursor: pointer;
    transition: border-color 0.2s ease, transform 0.2s var(--ease-out), box-shadow 0.2s ease;
}
.basemap-btn:hover {
    border-color: var(--focus);
    transform: translateY(-1px);
    box-shadow: 0 8px 22px rgba(0, 0, 0, 0.55);
}
.basemap-btn[aria-expanded="true"] { border-color: var(--focus); }

.basemap-panel {
    width: 264px;
    max-width: calc(100vw - var(--gap) * 2);
    padding: 10px 12px 12px;
    background: var(--ink);
    border: 1px solid var(--line);
    border-radius: 10px;
    backdrop-filter: blur(18px) saturate(130%);
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
}
.basemap-panel[hidden] { display: none; }
.basemap-title {
    margin-bottom: 6px;
    font-stretch: 118%;
    font-weight: 600;
    font-size: 12.5px;
}


/* ---------- Map view controls: right-hand corner ---------- */

.map-ctrl {
    position: fixed;
    right: var(--ctrl-right);
    bottom: calc(var(--bottom) + 58px);   /* above the scale bar and attribution */
    z-index: 3;
    display: grid;
    background: var(--ink);
    border: 1px solid var(--line);
    border-radius: 8px;
    backdrop-filter: blur(18px) saturate(130%);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
    overflow: hidden;
}
.map-ctrl button {
    width: 38px;
    height: 38px;
    display: grid;
    place-items: center;
    border: 0;
    background: var(--deep);
    color: var(--text);
}
.map-ctrl button + button { border-top: 1px solid var(--deep-line); }
.map-ctrl button:hover { background: var(--deep-hover); }
.map-ctrl button:focus-visible { outline-offset: -3px; }
.map-ctrl svg { width: 17px; height: 17px; }
.needle { transition: transform 0.2s linear; }
.needle-n { fill: #e0695a; stroke: #e0695a; }

/* with nothing selected the inspector is short, so the controls take the true corner */
/*body:not(.has-selection) { --ctrl-right: var(--gap); }


/* ---------- Inspector ---------- */

.inspector-empty { padding: 14px; border-top: 1px solid var(--line); display: grid; gap: 10px; }
.inspector-empty p:not(.hint) { color: var(--muted); max-width: 32ch; }

.inspector-body { padding: 14px; border-top: 1px solid var(--line); display: grid; gap: 14px; }

.insp-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 8px; }
.insp-head h2 { font-stretch: 118%; font-weight: 700; font-size: 18px; line-height: 1.2; }
.insp-head p { color: var(--muted); font-size: 12px; margin-top: 2px; }

.icon-btn {
    width: 28px;
    height: 28px;
    flex: none;
    display: grid;
    place-items: center;
    border: 1px solid var(--deep-line);
    border-radius: 6px;
    background: var(--deep);
    color: var(--text);
}
.icon-btn:hover { color: #fff; background: var(--deep-hover); }
.icon-btn svg { width: 14px; height: 14px; }


/* The plate: the tile inside a neatline, its real edge coordinates on the ticks */

.plate {
    position: relative;
    padding: 18px 18px 0;
    border: 1px solid var(--line-strong);
    border-radius: 3px;
}

.tick {
    position: absolute;
    color: var(--muted);
    font-size: 10.5px;
    font-variant-numeric: tabular-nums;
    line-height: 18px;
    white-space: nowrap;
}
.tick-n { top: 0; left: 18px; }
.tick-s { bottom: 26px; right: 18px; }
.tick-w { left: 0; top: 18px; writing-mode: vertical-rl; transform: rotate(180deg); line-height: 18px; }
.tick-e { right: 0; bottom: 44px; writing-mode: vertical-rl; line-height: 18px; }

.compare {
    --pos: 50%;
    position: relative;
    aspect-ratio: 1;
    overflow: hidden;
    margin-bottom: 18px;   /* the band the south tick sits in */
    background: #000;
    outline: 1px solid rgba(255, 255, 255, 0.5);
}

.compare img, .compare-analysis {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    user-select: none;
}

.compare-after { position: absolute; inset: 0; clip-path: inset(0 0 0 var(--pos)); }

.compare-bar {
    position: absolute;
    top: 0;
    bottom: 0;
    left: var(--pos);
    width: 2px;
    transform: translateX(-1px);
    background: #fff;
    pointer-events: none;
}
.compare-bar span {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 26px;
    height: 26px;
    transform: translate(-50%, -50%);
    border: 2px solid #fff;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.6);
}

.compare-range {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    opacity: 0;
    cursor: ew-resize;
}
.compare:has(.compare-range:focus-visible) { outline: 2px solid var(--focus); outline-offset: 2px; }

/* an analysis covers the swipe */
.compare.is-analysis .compare-bar,
.compare.is-analysis .compare-range { display: none; }

.tile-empty {
    aspect-ratio: 1;
    margin-bottom: 18px;
    display: grid;
    place-items: center;
    padding: 24px;
    text-align: center;
    color: var(--muted);
    background: rgba(0, 0, 0, 0.4);
    outline: 1px dashed var(--line-strong);
}

.plate-cap {
    height: 26px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    color: var(--muted);
    font-size: 11.5px;
}


/* attribute table */
.attrs {
    display: grid;
    grid-template-columns: auto 1fr;
    border-top: 1px solid var(--line);
}
.attrs dt, .attrs dd {
    padding: 5px 0;
    border-bottom: 1px solid var(--line);
    font-size: 12px;
}
.attrs dt { color: var(--muted); padding-right: 16px; }
.attrs dd { font-variant-numeric: tabular-nums; text-align: right; }
.attrs .is-ready { color: #9bd3a6; }
.attrs .is-pending { color: var(--site); }


.seg {
    display: flex;
    flex-wrap: wrap;
    gap: 2px;
    padding: 2px;
    border-radius: 6px;
    background: var(--raise);
    border: 1px solid var(--line);
}
.seg button {
    flex: 1 1 auto;
    height: 28px;
    padding: 0 8px;
    border: 0;
    border-radius: 4px;
    background: transparent;
    color: var(--muted);
    font-size: 12px;
    font-stretch: 88%;
}
.seg button:hover { color: var(--text); }
.seg button[aria-pressed="true"] { background: var(--deep); color: #fff; }
.seg button:disabled { opacity: 0.4; cursor: default; }

.analysis-note { color: var(--muted); font-size: 12px; }

.legend { display: grid; gap: 3px; font-size: 12px; font-variant-numeric: tabular-nums; }
.legend:empty { display: none; }
.legend-row { display: flex; align-items: center; gap: 8px; }
.legend-row b { margin-left: auto; font-weight: 600; }
.swatch { width: 12px; height: 12px; border-radius: 2px; flex: none; }
.ramp { height: 8px; border-radius: 2px; }
.ramp-ends { display: flex; justify-content: space-between; color: var(--muted); font-size: 11px; }

.actions { display: flex; flex-wrap: wrap; gap: 6px; }
.actions-centre { justify-content: center; }


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

.btn {
    height: 32px;
    padding: 0 12px;
    border: 1px solid var(--line-strong);
    border-radius: 6px;
    background: var(--raise);
    color: var(--text);
    font-weight: 500;
    transition: background 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}
.btn:hover:not(:disabled) { background: var(--raise-hi); border-color: var(--focus); }
.btn-deep { background: var(--deep); border-color: var(--deep-line); color: #fff; }
.btn-deep:hover:not(:disabled) { background: var(--deep-hover); border-color: var(--focus); }
.btn:disabled { opacity: 0.4; cursor: default; }


/* ---------- Status bar ---------- */

.sb-cell, .popup-grid, .coord, .results td {
    font-family: "Geist Mono", ui-monospace, "Cascadia Mono", monospace;
    font-feature-settings: "tnum" 1;
}

.statusbar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 5;
    height: 28px;
    display: flex;
    align-items: stretch;
    background: var(--ink-solid);
    border-top: 1px solid var(--line);
    color: var(--muted);
    font-size: 11.5px;
    font-variant-numeric: tabular-nums;
}

.sb-cell {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 0 12px;
    border-right: 1px solid var(--line);
    white-space: nowrap;
}
.sb-coords { min-width: 220px; color: var(--text); }
/* prose, not data: the mandatory Copernicus line (§7.7) is not a measurement */
.sb-attrib { font-family: "Geist", system-ui, sans-serif; font-size: 11px; }
.sb-engine { margin-left: auto; border-left: 1px solid var(--line); }
.sb-measure { color: var(--site); }

.led { width: 7px; height: 7px; border-radius: 50%; background: #56606e; }
.sb-engine.is-busy .led { background: var(--site); animation: blink 1.2s ease-in-out infinite; }
.sb-engine.is-error .led { background: #e0695a; }
@keyframes blink { 50% { opacity: 0.3; } }


/* ---------- Model report ---------- */

.report {
    width: min(860px, calc(100vw - 32px));
    max-height: calc(100vh - 96px);
    padding: 22px 26px 26px;
    border: 1px solid var(--line-strong);
    border-radius: 8px;
    background: var(--ink-solid);
    color: var(--text);
    overflow-y: auto;
}
.report::backdrop { background: rgba(0, 0, 0, 0.55); backdrop-filter: blur(2px); }
.report[open] { animation: rise 0.4s var(--ease-out); }

.report-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; }
.report-head h2 { font-stretch: 125%; font-weight: 700; font-size: 22px; }
.report-lede { color: var(--muted); max-width: 68ch; margin-bottom: 18px; font-size: 14px; }
.report h3 { font-stretch: 115%; font-weight: 600; font-size: 14px; margin: 18px 0 6px; }
.report .hint { max-width: 72ch; margin-top: 6px; }

.results { width: 100%; border-collapse: collapse; margin-top: 8px; font-variant-numeric: tabular-nums; }
.results th, .results td { padding: 7px 10px; border-bottom: 1px solid var(--line); text-align: right; }
.results th[scope="row"], .results thead th:first-child { text-align: left; font-weight: 500; }
.results thead th { color: var(--muted); font-weight: 500; font-size: 12px; }
.results .is-best { background: rgba(27, 47, 110, 0.45); }

.report-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 0 32px; }
.terms dt { font-weight: 600; margin-top: 8px; }
.terms dd { color: var(--muted); }
.caveats { display: grid; gap: 4px; color: var(--muted); }
.caveats li::before { content: "-"; margin-right: 8px; }


/* =========================================================
   TOOLS RAIL
   Each tool is a <details> section sharing the left dock's head
   vocabulary, so a panel reads the same wherever it is docked.
========================================================= */

.tool { border-bottom: 1px solid var(--line); }
.tool:last-of-type { border-bottom: 0; }

.tool-head {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 11px 14px;
    list-style: none;
    cursor: pointer;
    font-weight: 600;
    font-size: 12.5px;
    letter-spacing: 0.01em;
    transition: background 0.2s ease;
}
.tool-head::-webkit-details-marker { display: none; }
.tool-head:hover { background: var(--raise); }
.tool-head > svg:first-child { width: 16px; height: 16px; flex: none; color: var(--muted); }
.tool-head .chev { width: 15px; height: 15px; margin-left: auto; color: var(--muted); transition: transform 0.3s var(--ease-out); }
.tool:not([open]) .tool-head .chev { transform: rotate(-90deg); }

.tool-body { display: grid; gap: 11px; padding: 2px 14px 16px; }

.sub-title {
    margin: 4px 0 -4px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--muted);
}


/* ---------- Fields ---------- */

.field { display: grid; gap: 5px; }
.field-label {
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--muted);
    font-size: 11.5px;
}

.pane select {
    height: 32px;
    width: 100%;
    padding: 0 30px 0 10px;
    border: 1px solid var(--line-strong);
    border-radius: 6px;
    background: var(--raise) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239aa3b0' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m7 10 5 5 5-5'/%3E%3C/svg%3E") no-repeat right 8px center / 15px;
    color: var(--text);
    font: inherit;
    appearance: none;
    transition: border-color 0.2s ease, background-color 0.2s ease;
}
.pane select:hover:not(:disabled) { border-color: var(--focus); }
.pane select:disabled { opacity: 0.45; cursor: default; }
.pane select option { background: var(--ink-solid); color: var(--text); }

.check { display: flex; align-items: center; gap: 9px; color: var(--text); font-size: 12px; cursor: pointer; }
.check input { width: 15px; height: 15px; accent-color: var(--deep-line); flex: none; }
.check:has(input:disabled) { color: var(--muted); cursor: default; }

.link-btn {
    padding: 0;
    border: 0;
    background: none;
    color: var(--focus);
    font-size: 11.5px;
    text-decoration: underline;
    text-underline-offset: 3px;
}
.link-btn:hover { color: #fff; }


/* ---------- "Not on this server yet" ----------
   A missing endpoint names itself instead of leaving a dead control, so the
   rail doubles as the contract for dashboard.md §5. */

.route-note {
    display: grid;
    gap: 2px;
    padding: 8px 10px;
    border-radius: 6px;
    border: 1px dashed var(--line-strong);
    background: rgba(255, 255, 255, 0.025);
    color: var(--muted);
    font-size: 11.5px;
}
.route-note b {
    font-family: "Geist Mono", ui-monospace, monospace;
    font-weight: 500;
    color: var(--text);
}


/* ---------- Area of interest ---------- */


.attrs-tight dt, .attrs-tight dd { padding: 2px 0; border: 0; font-size: 11.5px; }

.aoi-place {
    font-size: 13.5px;
    font-weight: 500;
    line-height: 1.35;
    color: var(--text);
}
.aoi-place.is-waiting { color: var(--muted); font-weight: 400; font-size: 12px; }
.aoi-where { display: flex; align-items: baseline; gap: 8px; margin-top: 2px; color: var(--muted); font-size: 11.5px; }
.aoi-where .link-btn { margin-left: auto; }

.meter { display: grid; gap: 5px; }
.meter-head { display: flex; justify-content: space-between; color: var(--muted); font-size: 11.5px; }
.meter-head b { color: var(--text); font-weight: 500; }
.meter-track { height: 4px; border-radius: 2px; background: var(--raise-hi); overflow: hidden; }
.meter-track span {
    display: block;
    height: 100%;
    width: 0;
    border-radius: 2px;
    background: var(--deep-line);
    transition: width 0.4s var(--ease-out), background 0.3s ease;
}
.meter.is-high .meter-track span { background: var(--site); }
.meter.is-full .meter-track span { background: #e0695a; }


/* ---------- Dates ---------- */

/* ---------- Search window ----------
   Four stops on a rail. The fill shows how much of the range is in play, because
   the cost of widening it is real: more frames, and a composite that drifts. */
.win { margin-bottom: 12px; }
.win-head {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin-bottom: 5px;
    color: var(--muted);
    font-size: 11.5px;
}
.win-head b { margin-left: auto; color: var(--text); font-weight: 500; }

.win input {
    width: 100%;
    height: 16px;
    margin: 0;
    appearance: none;
    background: transparent;
    cursor: pointer;
}
.win input::-webkit-slider-runnable-track {
    height: 3px;
    border-radius: 2px;
    background: linear-gradient(to right,
        var(--sensor) calc(var(--win, 1) * 100%),
        var(--line-strong) calc(var(--win, 1) * 100%));
}
.win input::-moz-range-track { height: 3px; border-radius: 2px; background: var(--line-strong); }
.win input::-moz-range-progress { height: 3px; border-radius: 2px; background: var(--sensor); }
.win input::-webkit-slider-thumb {
    appearance: none;
    width: 13px;
    height: 13px;
    margin-top: -5px;
    border-radius: 50%;
    background: var(--text);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
}
.win input::-moz-range-thumb { width: 13px; height: 13px; border: 0; border-radius: 50%; background: var(--text); }

.win-ticks {
    display: flex;
    justify-content: space-between;
    padding: 0 1px;
    color: var(--muted);
    font-size: 10px;
    font-variant-numeric: tabular-nums;
}
.win-note { margin-top: 5px; color: var(--muted); font-size: 11px; line-height: 1.5; }


/* ---------- The Sentinel-2 archive ----------
   Eleven years of passes is not a list, it is an archive: stand in a year, then
   read its dates. Cloud cover decides which are worth anything, so every row
   carries it as a bar you can scan without reading a number. */

/* the month you are reading, and the way to any other */
.cal-nav {
    display: flex;
    align-items: center;
    gap: 4px;
    margin-bottom: 9px;
}
.cal-step {
    width: 28px;
    height: 28px;
    flex: none;
    display: grid;
    place-items: center;
    border: 0;
    border-radius: 7px;
    background: transparent;
    color: var(--muted);
    cursor: pointer;
    transition: background 0.18s ease, color 0.18s ease;
}
.cal-step svg { width: 16px; height: 16px; }
.cal-step:hover:not(:disabled) { background: var(--raise); color: var(--text); }
.cal-step:disabled { color: #4b525e; cursor: default; }

.cal-title {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    height: 28px;
    border: 0;
    border-radius: 7px;
    background: transparent;
    color: var(--text);
    font: inherit;
    font-size: 12.5px;
    font-weight: 500;
    cursor: pointer;
    transition: background 0.18s ease;
}
.cal-title:hover { background: var(--raise); }
.cal-title .chev { width: 14px; height: 14px; color: var(--muted); transition: transform 0.2s var(--ease-out); }
.cal-title[aria-expanded="true"] .chev { transform: rotate(180deg); }

.cal-picker {
    margin-bottom: 10px;
    padding: 8px;
    border: 1px solid var(--line);
    border-radius: 9px;
    background: rgba(255, 255, 255, 0.03);
}
.cal-picker[hidden] { display: none; }
.cal-nav-year { margin-bottom: 6px; }
.cal-year { flex: 1; text-align: center; font-size: 12.5px; font-variant-numeric: tabular-nums; }

.cal-months { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; }
.cal-mon {
    display: grid;
    gap: 1px;
    padding: 6px 4px;
    border: 1px solid transparent;
    border-radius: 6px;
    background: rgba(255, 255, 255, 0.04);
    color: var(--text);
    font: inherit;
    font-size: 11.5px;
    cursor: pointer;
    transition: background 0.18s ease, border-color 0.18s ease;
}
.cal-mon b { color: var(--muted); font-weight: 400; font-size: 10px; font-variant-numeric: tabular-nums; }
.cal-mon:hover:not(:disabled) { background: var(--raise-hi); }
.cal-mon[aria-current="true"] { border-color: var(--sensor); color: var(--sensor); }
.cal-mon[aria-current="true"] b { color: var(--sensor); }
.cal-mon:disabled { color: #4b525e; cursor: default; background: none; }
.cal-mon:disabled b { color: #3f4650; }

/* in the tool head, where the active date used to be printed */
.tool-head .date-mode { margin-left: auto; height: 26px; padding: 0 8px 0 5px; }
.tool-head .date-mode + .chev { margin-left: 0; }
.date-mode .tswitch-track { width: 26px; height: 15px; }
.date-mode .tswitch-knob { width: 11px; height: 11px; }
.date-mode[aria-checked="true"] .tswitch-knob { transform: translateX(11px); }
.date-mode .tswitch-label { min-width: 0; }

.date-auto {
    margin-bottom: 10px;
    color: var(--muted);
    font-size: 11.5px;
    line-height: 1.55;
}
.date-auto[hidden] { display: none; }
.tswitch:disabled { cursor: default; opacity: 0.55; }
.tswitch:disabled:hover { background: transparent; color: var(--muted); }

/* the picker, put away rather than taken away */
.date-picker { transition: opacity 0.2s ease; }
.date-picker.is-locked { opacity: 0.35; pointer-events: none; }
.date-picker.is-locked * { cursor: default; }

.date-locked {
    margin: -4px 0 10px;
    color: var(--muted);
    font-size: 11px;
    line-height: 1.5;
}
.date-locked[hidden] { display: none; }

/* The filter that protects the model. It is the toolbar's switch, so the two read
   as one control vocabulary, plus a hold: the track fills over two seconds before
   it will let cloudy dates through. */
.date-filter {
    width: 100%;
    margin-bottom: 8px;
    padding: 5px 8px 5px 6px;
    border-radius: 8px;
    touch-action: none;                 /* a hold must not scroll the panel */
    -webkit-user-select: none;
    user-select: none;
}
/* The counter doubles as the hold meter: it already tells you how much of the
   archive is clear, so it is where the cost of dropping the filter belongs. */
.hold-meter {
    position: relative;
    margin-left: auto;
    padding: 2px 7px;
    overflow: hidden;
    border: 1px solid transparent;
    border-radius: 999px;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
    transition: border-color 0.18s ease, color 0.18s ease;
}
.hold-fill {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: calc(var(--hold, 0) * 100%);
    background: var(--model);
    opacity: 0.9;
}
.hold-text { position: relative; }
.date-filter.is-holding .hold-meter { border-color: var(--model); color: var(--text); }

.date-warn {
    margin: -2px 0 10px;
    padding: 7px 9px;
    border-radius: 7px;
    background: var(--model-dim);
    color: var(--text);
    font-size: 11px;
    line-height: 1.5;
}
.date-warn[hidden] { display: none; }
.date-warn b { color: var(--model); font-weight: 500; }


.date-summary {
    margin-top: 8px;
    color: var(--muted);
    font-size: 11px;
    line-height: 1.5;
}
.date-summary[hidden] { display: none; }

/* ---------- The archive as a calendar ----------
   A year at a time, month by month, so a season is visible as a shape. Every day
   the satellite passed is a tile, and the cloud it saw fills that tile from the
   bottom: a nearly empty tile is a clear day. The number is in the label, not on
   the face, because you pick a date by scanning, not by reading. */

.cal { display: grid; gap: 14px; }

.cal-week {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 3px;
    padding: 0 2px;
    color: var(--muted);
    font-size: 9.5px;
    text-align: center;
    letter-spacing: 0.04em;
}

.cal-grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 3px;
}

/* a day the satellite did not pass: present, so the gaps in a monsoon read as gaps */
.cal-day {
    position: relative;
    aspect-ratio: 1;
    display: grid;
    place-items: center;
    border-radius: 5px;
    background: rgba(255, 255, 255, 0.03);
    color: #59616d;
    font-size: 10.5px;
    font-variant-numeric: tabular-nums;
}
.cal-day.is-blank { background: none; }

/* a day it did pass */
button.cal-day {
    border: 1px solid var(--line);
    background: rgba(255, 255, 255, 0.05);
    color: var(--text);
    font: inherit;
    font-size: 10.5px;
    font-variant-numeric: tabular-nums;
    cursor: pointer;
    overflow: hidden;
    transition: border-color 0.18s ease, transform 0.18s var(--ease-out);
}
/* the cloud it saw, filling from the bottom */
.cal-fill {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    background: var(--model-dim);
    border-top: 1px solid rgba(224, 162, 78, 0.45);
}
.cal-num { position: relative; }

button.cal-day:hover { border-color: var(--focus); transform: translateY(-1px); }
button.cal-day.is-clear { border-color: rgba(92, 195, 174, 0.5); }
button.cal-day.is-clear .cal-fill { background: var(--sensor-dim); border-top-color: rgba(92, 195, 174, 0.5); }

/* already generated on this date */
button.cal-day.is-cached::after {
    content: "";
    position: absolute;
    top: 3px;
    right: 3px;
    width: 4px;
    height: 4px;
    border-radius: 50%;
    background: var(--sensor);
}

/* the date the engine stands on */
button.cal-day[aria-pressed="true"] {
    border-color: var(--sensor);
    box-shadow: 0 0 0 1px var(--sensor);
    color: #fff;
    font-weight: 600;
}




/* =========================================================
   STATISTICS DOCK
   One row per region. Rises over the map between the two side
   docks, so the map keeps its full width when it is closed.
========================================================= */

.stats-dock {
    position: fixed;
    left: 0;
    right: var(--right-w);
    bottom: var(--bottom);
    z-index: 4;
    height: var(--stats-h);
    display: flex;
    flex-direction: column;
    background: var(--ink);
    border-top: 1px solid var(--line);
    border-right: 1px solid var(--line);
    backdrop-filter: blur(18px) saturate(130%);
    contain: layout paint;
    transition: height 0.3s var(--ease-out), right 0.3s var(--ease-out);
}
body.right-closed .stats-dock { right: 0; }

.stats-head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 12px 9px 14px;
    border-bottom: 1px solid var(--line);
}
.stats-head .pane-title { margin: 0; }
.stats-count { margin-left: auto; color: var(--muted); font-size: 11.5px; }

.stats-scroll { flex: 1; overflow: auto; scrollbar-width: thin; scrollbar-color: rgba(170, 186, 214, 0.25) transparent; }

.stats-table { width: 100%; border-collapse: collapse; font-size: 12px; }
.stats-table th, .stats-table td { padding: 6px 14px; text-align: right; border-bottom: 1px solid var(--line); }
.stats-table th:first-child, .stats-table td:first-child { text-align: left; }
.stats-table td { font-family: "Geist Mono", ui-monospace, monospace; font-feature-settings: "tnum" 1; }

.stats-table thead th { position: sticky; top: 0; z-index: 1; padding: 0; background: var(--ink-solid); }
.stats-table thead button {
    width: 100%;
    padding: 7px 14px;
    border: 0;
    background: none;
    color: var(--muted);
    font-size: 11.5px;
    font-weight: 500;
    text-align: inherit;
    transition: color 0.2s ease;
}
.stats-table thead button:hover { color: var(--text); }
.stats-table thead button::after { content: ""; display: inline-block; width: 0; }
.stats-table thead [aria-sort="ascending"]::after  { content: " ↑"; width: auto; }
.stats-table thead [aria-sort="descending"]::after { content: " ↓"; width: auto; }
.stats-table tbody tr:hover { background: var(--raise); }
.stats-table tbody tr.is-hot { background: rgba(27, 47, 110, 0.45); }

.stats-empty { padding: 18px 14px; color: var(--muted); font-size: 12px; max-width: 62ch; }
.stats-table:has(tbody:empty) + .stats-empty { display: block; }
.stats-table:not(:has(tbody:empty)) ~ .stats-empty { display: none; }

/* the map furniture steps up over the open dock */
body.stats-open #globe .maplibregl-ctrl-bottom-right { bottom: calc(var(--bottom) + var(--stats-h)); }
body.stats-open .map-ctrl { bottom: calc(var(--bottom) + var(--stats-h) + var(--gap)); }
body.stats-open .dock-left { top: calc(var(--top) + (100vh - var(--top) - var(--bottom) - var(--stats-h)) / 2 - 29px); }


/* ---------- Index and confidence legends ---------- */

.legend-head { display: flex; align-items: center; gap: 8px; font-size: 11.5px; color: var(--muted); }

/* §7.1: an index is never smoothed to look sharper than the sensor was */
.ramp.is-stepped { image-rendering: pixelated; }


/* ---------- One entrance: panels settle in from their edges ---------- */

@keyframes from-left { from { transform: translateX(-24px); opacity: 0; } }
@keyframes from-right { from { transform: translateX(24px); opacity: 0; } }
@keyframes from-top { from { transform: translateY(-12px); opacity: 0; } }
@keyframes rise { from { transform: translateY(12px); opacity: 0; } }

.toolbar { animation: from-top 0.7s var(--ease-out) both; }
.layer-box { animation: from-left 0.8s 0.1s var(--ease-out) both; }
.pane-right { animation: from-right 0.8s 0.18s var(--ease-out) both; }

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after { animation: none !important; transition: none !important; }
}


/* ---------- Smaller screens ----------
   Contents becomes an overlay (closed by default), the inspector a bottom
   sheet that only shows with a site selected. */

@media (max-width: 1100px) {
    :root { --right-w: 322px; --left-w: 260px; }
    .tb-btn { padding: 0 8px; }
}

@media (max-width: 800px) {
    /* the left panel's own width IS the handle's anchor, so they cannot drift */
    :root { --gap: 8px; --left-w: 84vw; }
    .tb-end a { display: none; }
    .toolbar { gap: 2px; padding: 0 6px; overflow-x: auto; }
    :root { --tb-left: 6px; }   /* on a phone the tools sit next to the brand */
    .tb-search input { width: 110px; }
    .tb-sections { padding-left: 6px; }
    .tb-btn span { display: none; }
    .tb-end .tb-btn span { display: inline; }
    .layer-box { z-index: 6; }
    /* the dock is an overlay at this width, so the square sits at the map edge */
    .basemap { left: var(--gap); }

    /* The rail becomes a bottom sheet with a fixed height, so closing it can
       slide it down by a known distance and leave its first heading peeking:
       a sheet you can see is a sheet you can find again. Sliding uses bottom,
       never transform, because the entrance animation owns transform. */
    .pane-right {
        top: auto;
        left: 0;
        right: 0;
        width: auto;
        height: 62vh;
        border-left: 0;
        border-top: 1px solid var(--line);
    }
    body.right-closed .pane-right { right: 0; bottom: calc(var(--bottom) - 62vh + 44px); }
    body { --ctrl-right: var(--gap); }
    .map-ctrl { bottom: calc(var(--bottom) + 62vh + var(--gap)); }
    body.right-closed .map-ctrl { bottom: calc(var(--bottom) + 44px + var(--gap)); }

    /* a grab tab centred on the sheet's top edge; left + width beats right */
    .dock-toggle.dock-right {
        top: auto;
        bottom: calc(var(--bottom) + 62vh);
        left: 50%;
        margin-left: -29px;
        width: 58px;
        height: 22px;
        border-radius: 6px 6px 0 0;
        border: 1px solid var(--deep-line);
        border-bottom: 0;
    }
    body.right-closed .dock-toggle.dock-right { bottom: calc(var(--bottom) + 44px); }
    .dock-right svg { transform: rotate(-90deg); }
    body.right-closed .dock-right svg { transform: rotate(90deg); }

    /* one bottom surface at a time: opening statistics closes the sheet */
    body.stats-open { --stats-h: calc(100vh - var(--top) - var(--bottom)); }
    .stats-dock { right: 0; }
    .sb-cell:not(.sb-coords):not(.sb-engine):not(.sb-measure) { display: none; }
    .sb-coords { min-width: 0; flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; display: block; line-height: 28px; }
    .sb-engine { margin-left: 0; }
    body[data-tool="measure"] .sb-engine { display: none; }
    .report-cols { grid-template-columns: 1fr; }
}
