/* ===========================================================================
   gk-spatial.css  --  GK-SPATIAL's screens

   Lane owner: GK-SPATIAL. Linked by shell.html after gk.css, which is FROZEN.
   No colour literal belongs here: every colour is a token from gk-tokens.css
   (imported by gk.css), because light mode is a separate palette and a typed
   hex is invisible until it is on a projector.
   =========================================================================== */

/* ---- the datasets register ------------------------------------------- */

/* The header is exactly the tab bar's height (brief: the mockup gets this
   wrong). --ds-tab-h is MEASURED from #screens at draw time by
   drawDatasets(); the chrome height is only the fallback for the first paint. */
.ds-head {
  box-sizing: border-box;
  height: var(--ds-tab-h, var(--chrome-h));
  padding-top: 0; padding-bottom: 0;
}
.ds-head { flex-wrap: nowrap; overflow: hidden; }
.ds-clip { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.ds-counts { flex: 0 1 auto; }
.ds-title {
  white-space: nowrap; flex: 0 0 auto;
  background: transparent; border: 0; padding: 0; color: var(--ink);
  font: inherit; font-weight: 600; cursor: pointer; text-align: left;
}
.ds-title:hover { color: var(--accent2); }

/* The specification strip: four numbers that decide whether two surveys can
   be merged, plus who flew it. */
.ds-spec {
  display: flex; flex-wrap: wrap; gap: 4px calc(var(--gap) * 2);
  margin: 0; padding: var(--pad) var(--pad) calc(var(--pad) * 1.5);
  border-bottom: 1px solid var(--line); background: var(--panel);
}
.ds-spec > div { display: flex; gap: 6px; align-items: baseline; }
.ds-spec dt { color: var(--dim); font-size: var(--fs-small); }
.ds-spec dd { margin: 0; font-family: var(--mono); }
.ds-spec dd.none { color: var(--faint); font-family: var(--sans); font-style: italic; }

.ds-tablewrap { overflow: auto; }
.ds-grid tbody tr { cursor: pointer; }
.ds-grid tbody tr:hover { background: var(--soft); }
.ds-grid tbody tr[aria-selected="true"] { background: var(--soft);
  box-shadow: inset 2px 0 0 var(--accent); }
.ds-grid td:nth-child(7), .ds-grid td:nth-child(9) { font-family: var(--mono); }

/* State is carried by the WORD; colour only reinforces it (ADR-0074). A row
   for a product we do not have is drawn as plainly as one we do -- dimming it
   would be the silence this screen exists to prevent. */
.ds-state { font-weight: 600; }
.ds-rec .ds-state { color: var(--ok); }
.ds-nof .ds-state { color: var(--warn); }
.ds-nrc .ds-state { color: var(--accent); }
.ds-unr .ds-state { color: var(--dim); }

.ds-empty { color: var(--dim); font-style: italic; white-space: normal; }
.ds-pad { padding: var(--pad); }
.rail-list .ds-aside { font-style: italic; white-space: normal; }

/* ---- the samples screen ---------------------------------------------- */
.sm-grid .sm-where { font-family: var(--mono); }
.sm-pager { display: flex; gap: var(--gap); padding: var(--pad); }

/* ---- the map's sample legend ------------------------------------------ */
/* One line per sample type, wrapping rather than scrolling sideways: each
   type has its own breaks, and a legend cut off at the pane edge hides the
   top classes, which are the anomaly. */
.maplegends .samplelegend { flex-wrap: wrap; row-gap: 2px; }
.maplegends .samplelegend .label { font-weight: 600; }
.maplegends .samplelegends { flex-direction: column; align-items: flex-start; gap: 2px; }

/* ---- obligations (ADR-0085) ------------------------------------------- */
/* Overdue is said in words; colour only reinforces it (ADR-0074). */
.ob-grid tr.ob-overdue .ob-state, .ob-late { color: var(--accent); font-weight: 600; }
.ob-grid tr.ob-soon .ob-state { color: var(--warn); }
.ob-sub { margin: calc(var(--pad) * 2) var(--pad) 0; font-size: var(--fs); font-weight: 600; }
.rail-list .ob-project { padding-left: calc(var(--pad) * 2); text-transform: none; }
.rail-list .ob-grant { padding-left: calc(var(--pad) * 4); }
.rail-list .sm-count { display: flex; justify-content: space-between; gap: var(--gap);
  padding: 0 var(--pad) 0 calc(var(--pad) * 2); min-height: var(--row); align-items: center; }
.sm-estate tbody tr { cursor: pointer; }

/* ---- the wide assays (ADR-0086) ---------------------------------------- */
/* A picked cell keeps its value; the marker says there was more. The
   symbol carries the meaning, colour only reinforces it (ADR-0074). */
.sm-grid .as-chose .as-mark { color: var(--dim); }
.sm-grid .as-disagree { color: var(--accent); font-weight: 600; }
.sm-grid .as-disagree .as-mark { color: var(--accent); }
.as-loud { color: var(--accent); }

/* ---- Geology table (gk-geology.js) ------------------------------------- */
/* A reading continued from the row above: present, but not a new interval. */
.ge-grid .ge-carry { color: var(--dim); }
.ge-grid .as-chose { color: var(--dim); }
.ge-grid .as-disagree { color: var(--accent); font-weight: 600; }
.ge-subject { display: flex; align-items: center; gap: var(--gap); padding: 2px var(--pad); cursor: pointer; }
.ge-subject .meta { margin-left: auto; color: var(--dim); }
.ge-subject.ge-bad .id { color: var(--warn); }

/* ---- Observations on the map (gk-map.js) -------------------------------- */
.obs-sym { color: var(--map-ring); background: none; border: none; position: relative; }
.obs-sym .obs-dip { position: absolute; left: 16px; top: -2px; font-family: var(--mono); font-size: 11px; color: var(--map-ring); }

/* ---- Recording an observation (gk-observe.js) --------------------------- */
.obs-field { display: grid; grid-template-columns: 9em minmax(0, 1fr); gap: var(--gap); align-items: center; margin: 2px 0; }
/* A field never pushes the Selection panel wider than itself (visual sweep
   2026-11-09: at 1366 the Record form's boxes ran off the panel's edge and
   the panel scrolled sideways). */
.obs-field > input, .obs-field > select, .obs-field > textarea, .obs-field > .gk-date-wrap { min-width: 0; max-width: 100%; box-sizing: border-box; }
.obs-field > input:not([type=checkbox]):not([type=radio]), .obs-field > textarea { width: 100%; }
.obs-field > select { width: 100%; }
.obs-subject { margin: var(--pad) 0 2px; }
.obs-actions { display: flex; gap: var(--gap); margin-top: var(--pad); }
.mapbox.obs-recording { cursor: crosshair; }

/* The hole panel on the map (note 7): the chosen element down the hole, one
   row per interval, in the inspector's width. */
#insp dd.mh-wide { grid-column: 1 / -1; margin: 0; }
.mh-assay { max-height: 50vh; overflow: auto; }
.mh-table { width: 100%; border-collapse: collapse; font-size: 0.86em; }
.mh-table th, .mh-table td { padding: 2px 4px; border-bottom: 1px solid var(--line); text-align: left; white-space: nowrap; }
.mh-table th { position: sticky; top: 0; background: var(--panel); }
.mh-table .num { text-align: right; font-variant-numeric: tabular-nums; }
.mh-table tbody tr { cursor: pointer; }
.mh-table tbody tr:hover { background: var(--panel2); }
.mh-sw { display: inline-block; width: 0.7em; height: 0.7em; margin-right: 4px; border-radius: 50%; vertical-align: baseline; }

/* Imported GIS layers (Datasets > GIS layers; the map's reference-layer chip). */
.gl-switch { padding: var(--pad); gap: 6px; }
.gl-loadbtn { position: relative; cursor: pointer; }
.gl-loadbtn .gl-file { position: absolute; inset: 0; opacity: 0; cursor: pointer; width: 100%; }
.gl-load { padding-bottom: var(--pad); }
.gl-field { display: grid; grid-template-columns: minmax(9em, 14em) minmax(0, 28em) minmax(0, 1fr);
            gap: 8px; align-items: center; padding: 3px var(--pad); }
.gl-field .hint { font-size: var(--fs-small); }
.gl-actions { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.gl-match { margin-top: 6px; }
.gl-match div { margin: 2px 0; }
.gl-refchip { position: relative; }
.gl-refchip > summary { list-style: none; cursor: pointer; display: inline-flex; gap: 6px; align-items: center; }
.gl-refchip > summary::-webkit-details-marker { display: none; }
.gl-refmenu { position: absolute; z-index: 1000; top: 100%; left: 0; margin-top: 4px; min-width: 16em; max-height: 50vh;
              overflow: auto; background: var(--panel); border: 1px solid var(--line); padding: 6px; }
.gl-refitem { display: flex; gap: 6px; align-items: center; padding: 3px 2px; white-space: nowrap; cursor: pointer; }
.gl-sw { display: inline-block; width: 0.8em; height: 0.8em; border-radius: 2px; }
@media (max-width: 700px) { .gl-field { grid-template-columns: 1fr; } }
.gl-preview { height: 280px; max-width: 760px; border: 1px solid var(--line); }
.gl-preview-note { padding-left: 0; }

/* Hole entry from the map (230). */
.mh-acts { display: flex; flex-wrap: wrap; gap: var(--gap); }
.he-kind { margin: 0 0 var(--pad); }
.he-table { margin: 2px 0 var(--pad); min-width: 0; max-width: 100%; overflow-x: auto; }
.he-table .gk-ag { width: 100%; }
/* AG Grid keeps 150 px of body under a short auto-height grid (room for its
   "no rows" overlay): a collar with one position drew one row over a blank. */
.he-table .ag-layout-auto-height .ag-center-cols-viewport,
.he-table .ag-layout-auto-height .ag-center-cols-container,
.he-table .ag-layout-auto-height .ag-center-cols-clipper { min-height: 0 !important; }
.he-table tbody tr.he-aside td { color: var(--dim); text-decoration: line-through; }

/* The map's own Layers button (#29): Leaflet's control, our contents. */
.gk-layers.leaflet-control-layers { background: var(--panel); color: var(--ink); border: 1px solid var(--line); }
.gk-layers .leaflet-control-layers-toggle { background-color: var(--panel); }
.gk-layers-list { min-width: 15em; max-width: 22em; max-height: 60vh; overflow: auto; padding: 2px 4px; font-size: 0.9em; }
.gk-lyr-head { display: flex; align-items: center; justify-content: space-between; gap: var(--gap); margin-bottom: 2px; }
.gk-lyr-x { padding: 0 6px; line-height: 1.4; }
.gk-lyr-group { margin: 6px 0 2px; color: var(--dim); font-size: 0.85em; text-transform: uppercase; letter-spacing: 0.04em; }
.gk-lyr { display: flex; align-items: center; gap: 6px; padding: 1px 0; cursor: pointer; }
.gk-lyr .gk-lyr-name { flex: 1; }
.gk-lyr .meta { color: var(--dim); font-variant-numeric: tabular-nums; }
.gk-lyr-none { display: block; padding: 1px 0; }
.sm-links { display: contents; }
.ge-key { margin: 2px 0; }
.he-grid .ag-row.he-aside .ag-cell { color: var(--dim); text-decoration: line-through; }

/* #53: the Log's interval grid takes the whole of its pane, however the
   splitter divides the screen (the grid's own 70%-of-window cap was
   written for grids in a scrolling page, not a pane with a height). */
.pane.log-intervals { display: flex; flex-direction: column; overflow: hidden; }
.pane.log-intervals > .pane-head { flex: 0 0 auto; }
.pane.log-intervals > .gk-ag { flex: 1 1 auto; min-height: 0; height: auto !important; }

/* The log as a component (gkLogStrip / gkLogColumns): rows not yet saved. */
.band.draft { border-style: dashed; border-width: 1px; opacity: 0.85; cursor: default; }
.gk-strip .col { cursor: default; }          /* no pen here: a click picks, it does not draw */
.gk-strip > .cap.linkish { display: block; width: 100%; text-align: left; }

/* ---- the quieter map (2026-11-08) -------------------------------------- */
/* One line above the map; the legends sit in the layers panel, wrapped to
   its width rather than scrolled sideways as the old banner rows were. */
.gk-mapline { justify-content: space-between; }
.gk-mapline .hint { overflow: hidden; text-overflow: ellipsis; }
.gk-lyr-fold { display: block; width: 100%; border: 0; background: none; padding: 0; cursor: pointer; text-align: left; font: inherit; }
.gk-lyr-legend { max-height: 38vh; max-width: 340px; overflow: auto; border-bottom: 1px solid var(--line); padding-bottom: 4px; }
.gk-lyr-legend .maplegend, .gk-lyr-legend .legend { flex-wrap: wrap; white-space: normal; overflow-x: visible; background: transparent; border: 0; padding: 2px 0; row-gap: 2px; }
.gk-lyr-legend .samplelegends { flex-direction: column; align-items: flex-start; gap: 2px; }
.gk-lyr-legend .samplelegend .label { font-weight: 600; }

/* ---- the visual sweep (GK-SPATIAL, 2026-11-09; docs/sweep/visual.md) ---- */
/* THE SELECTION PANEL IS A TWO-COLUMN LIST (dl.kv: a dt, then its dd). A
   panel that draws anything else into it -- a heading, a form, a table, a
   "reading…" line -- put that in the label column, 70 px wide: the hole
   panel's tables drew 60 px wide beside a blank, and the Record form sat
   half a column across. Anything that is not a dt or a dd now spans the
   panel. dt/dd pairs are unchanged. */
#insp > :not(dt):not(dd) { grid-column: 1 / -1; min-width: 0; }
/* A sentence in the rail is said as a sentence (the rail's .group is a
   small-caps heading; written in it, "1 survey is in no programme" read as
   shouting). */
.rail-note { color: var(--dim); font-size: var(--fs-small); padding: 4px var(--pad) var(--pad);
  text-transform: none; letter-spacing: normal; font-style: normal; white-space: normal; line-height: 1.4; }
.rail-note .tool { margin-top: 4px; }
/* Leaflet's own sheet loads after the shell's and paints its attribution
   white on every theme, so in the dark theme it read 2.4:1. */
.leaflet-container .leaflet-control-attribution { background: var(--panel); color: var(--dim); }
.leaflet-container .leaflet-control-attribution a { color: var(--accent2); }
/* The same, for the rail notes other lanes wrote as "group ds-aside" (the
   class started here): Contractors, Monitoring, People. */
.group.ds-aside { text-transform: none; letter-spacing: normal; font-style: normal; line-height: 1.4; }
/* An empty grid spans its pane, so its "nothing here" line reads as the
   pane's answer rather than a stub of headings (Events, Risk register:
   a 440 px table on a 1,000 px pane). A grid with rows keeps its widths. */
table.grid:has(> tbody > tr > td.gk-empty) { width: 100%; }

/* #83: a hole's QC samples, folded under its intervals in the panel. */
.mh-qc { margin-top: 6px; }
.mh-qc-list { margin: 4px 0 0; padding-left: 1.2em; }
.mh-qc-list .linklike { background: none; border: 0; padding: 0; color: var(--accent2); cursor: pointer; font: inherit; text-align: left; }
