/* Field-first styling: dark so the screen is readable in bright sun without
   burning battery, big enough targets to use with cold or gloved hands, and
   laid out for a phone held in one hand before anything else. */

:root {
  --bg: #0f1418;
  --bg-2: #161d23;
  --bg-3: #1e272f;
  --line: #2b3742;
  --rule: #3d4c58;
  --ink: #e8eef2;
  --ink-dim: #93a3af;
  --ink-faint: #647585;
  --accent: #ffc857;
  --accent-ink: #2a1f05;
  /* Bedding somebody measured, as against bedding a model produced. Green
     rather than another warm hue so it never reads as a variant of the
     accent: on this net the two sets of poles are different KINDS of thing,
     not two states of one. */
  --measured: #6ee7a5;
  --danger: #ff6b6b;
  --radius: 14px;
  --sheet-peek: calc(96px + env(safe-area-inset-bottom));
  --tap: 44px;

  /* The rest of the chrome. Every literal colour in this file is one of
     these, so the light theme below is a second list of the same names and
     nothing else. Named for what they paint, not for a hue. */
  --good: #7fd39b;
  --good-bg: rgba(127, 211, 155, .16);
  --danger-bg: rgba(255, 107, 107, .16);
  --danger-line: rgba(255, 107, 107, .4);
  --bad-text: #ffb08a;
  --bad-line: rgba(255, 140, 90, .45);
  --well: #0a0e12;            /* tracks and bars, darker than the panel */
  --well-2: #0c1216;          /* the compass face */
  --well-3: #121a20;          /* the compass face, pressed */
  --pressed: #26323b;
  --tick: #46545f;
  --tick-2: #5d6d79;
  --hair-1: rgba(255, 255, 255, .03);
  --hair-2: rgba(255, 255, 255, .07);
  --hair-3: rgba(255, 255, 255, .2);
  --glass: rgba(22, 29, 35, .86);        /* buttons floating over a canvas */
  --glass-2: rgba(15, 20, 24, .93);      /* chips and readouts over a canvas */
  --glass-soft: rgba(15, 20, 24, .6);
  --shadow: rgba(0, 0, 0, .45);
  --shadow-2: rgba(0, 0, 0, .55);
  --accent-tint: rgba(255, 200, 87, .12);
  --accent-glow: rgba(255, 200, 87, .45);
  --on-accent-tint: rgba(42, 31, 5, .16);
  --map-answer: #8ecae6;      /* the whole-map fit on the stereonet */
  --net-grid: rgba(232, 238, 242, .075);
  --net-planes: rgba(232, 238, 242, .3);
  --halo: rgba(12, 16, 20, .92);
  /* Canvases: read by js/ui/theme.js, never by a rule here. */
  --canvas: #10161b;          /* the field map behind its tiles */
  --canvas-2: #151c22;        /* a tile that is not there */
  --scene: #0f1418;           /* the 3D clear colour */
  --frame: rgba(255, 255, 255, .22);
  --frame-text: rgba(255, 255, 255, .85);
  --frame-text-dim: rgba(255, 255, 255, .5);
  --frame-text-faint: rgba(255, 255, 255, .4);
  --frame-grid: rgba(255, 255, 255, .16);
  --ground-line: #f0f4f6;     /* the ground profile on the cross section */
  --ground-halo: rgba(10, 14, 18, .6);
  color-scheme: dark;
}

/* The light theme: the same names, paper instead of slate. The accent goes
   to a goldenrod dark enough to read as text on white, with white on it. */
:root[data-theme="light"] {
  --bg: #f3f5f7;
  --bg-2: #ffffff;
  --bg-3: #e8edf1;
  --line: #cfd8df;
  --rule: #aab6bf;
  --ink: #14191e;
  --ink-dim: #4b5a66;
  --ink-faint: #74838f;
  --accent: #9c6f0a;
  --accent-ink: #ffffff;
  --measured: #1f7a4d;
  --danger: #c0392b;
  --good: #1f7a4d;
  --good-bg: rgba(31, 122, 77, .14);
  --danger-bg: rgba(192, 57, 43, .12);
  --danger-line: rgba(192, 57, 43, .45);
  --bad-text: #b3471d;
  --bad-line: rgba(179, 71, 29, .45);
  --well: #dfe5ea;
  --well-2: #f9fafb;
  --well-3: #eef1f4;
  --pressed: #d3dbe2;
  --tick: #b7c1c9;
  --tick-2: #93a0aa;
  --hair-1: rgba(0, 0, 0, .035);
  --hair-2: rgba(0, 0, 0, .09);
  --hair-3: rgba(0, 0, 0, .2);
  --glass: rgba(255, 255, 255, .88);
  --glass-2: rgba(255, 255, 255, .94);
  --glass-soft: rgba(255, 255, 255, .7);
  --shadow: rgba(0, 0, 0, .16);
  --shadow-2: rgba(0, 0, 0, .22);
  --accent-tint: rgba(156, 111, 10, .14);
  --accent-glow: rgba(156, 111, 10, .45);
  --on-accent-tint: rgba(255, 255, 255, .25);
  --map-answer: #1f6f9a;
  --net-grid: rgba(20, 25, 30, .1);
  --net-planes: rgba(20, 25, 30, .35);
  --halo: rgba(255, 255, 255, .92);
  --canvas: #e9ecef;
  --canvas-2: #dde2e6;
  --scene: #e2e7eb;
  --frame: rgba(0, 0, 0, .22);
  --frame-text: rgba(0, 0, 0, .85);
  --frame-text-dim: rgba(0, 0, 0, .55);
  --frame-text-faint: rgba(0, 0, 0, .45);
  --frame-grid: rgba(0, 0, 0, .14);
  --ground-line: #14191e;
  --ground-halo: rgba(255, 255, 255, .7);
  color-scheme: light;
}

* { box-sizing: border-box; }

/* Controls are not text. A firm press on iOS otherwise tries to select the
   strike-and-dip symbol, a slider or a button as though it were a word, and
   puts a callout over it. Selection is turned off for the whole app and
   turned back on only where there is text to select: fields, and the few
   lines a student may want to copy out. */
html, body, #app {
  -webkit-user-select: none; user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}
input, textarea, select, [contenteditable="true"],
.ctl-hint.stamp, .provenance, .coord-line, .about, .fatal pre, code {
  -webkit-user-select: text; user-select: text;
  -webkit-touch-callout: default;
}

html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
  background: var(--bg);
  color: var(--ink);
  font: 15px/1.45 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
}

#app { display: flex; flex-direction: column; height: 100%; }

.boot, .fatal {
  display: grid; place-content: center; height: 100%;
  color: var(--ink-dim); text-align: center; padding: 24px; gap: 12px;
}
.fatal pre {
  text-align: left; font-size: 12px; color: var(--ink-faint);
  max-width: 90vw; overflow: auto; background: var(--bg-2); padding: 12px; border-radius: 8px;
}

/* --- stage ---------------------------------------------------------------- */

/* The stage holds the block and, when it is up, the stereonet beside it.
   Which way "beside" runs depends on the shape of the screen, not its size: a
   phone in portrait stacks them, everything wider than it is tall sets them
   side by side. */
.stage { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
/* Clipped, so that pulling the stereonet up over the whole stage takes the
   compass and the undo buttons with it rather than leaving them floating on
   top of the net. */
.block-pane {
  position: relative; flex: 1 1 auto; min-width: 0; min-height: 0;
  overflow: hidden;
}
.viewport { display: block; width: 100%; height: 100%; touch-action: none; }

.hud {
  position: absolute; top: calc(10px + env(safe-area-inset-top));
  display: flex; gap: 8px; z-index: 5;
}
.hud-left { left: calc(10px + env(safe-area-inset-left)); }
.hud-right { right: calc(10px + env(safe-area-inset-right)); }

/* Three things want the top of the stage: the section switch in the middle,
   and a cluster of round buttons in each upper corner. Between them they need
   about 440px, and a phone held in portrait does not have it — so on a narrow
   screen the switch keeps the line and the corners drop to the row beneath it.
   Overlapping controls are worse than a second row: a full-screen button
   sitting on top of "Strata" is two controls one tap can hit.

   Only the left cluster drops: the right-hand one is a column under the
   rose, 56px wide, which clears a centred 198px switch on any phone.
   The threshold is where the left cluster (undo, redo, clear, and a chip
   or two) genuinely stops fitting. */
@media (max-width: 560px) {
  .hud-left { top: calc(62px + env(safe-area-inset-top)); }
  /* Down here the switch already has the first row to itself, so the left
     cluster has the whole width and the cap below is not needed. */
  .hud-left { max-width: none; }
}
/* The right-hand cluster is a column under the rose on both the block and
   the map: one shape for the same controls. */
.hud-right { flex-direction: column; align-items: center; }

/* A chip beside undo and redo makes the left cluster two or three times its
   usual width, which is enough to reach a centred switch on a window that is
   nowhere near narrow enough to trip the rule above — and two chips at once is
   possible, since a block can be in map view AND wound back in time. So the
   cluster is capped at the room it actually has and a chip that will not fit
   drops to a second line rather than sliding under "Block". The number is the
   switch's half-width (99), plus this cluster's own inset from the edge (10),
   plus a gap the width of the one between the buttons (8). */
.hud-left { flex-wrap: wrap; max-width: calc(50% - 117px); }

.icon-btn {
  width: var(--tap); height: var(--tap);
  display: grid; place-items: center;
  font-size: 20px; color: var(--ink);
  background: var(--glass); border: 1px solid var(--line);
  border-radius: 12px; cursor: pointer;
  backdrop-filter: blur(8px);
}
.icon-btn:disabled { opacity: .32; cursor: default; }
.icon-btn.clear-btn { font-size: 26px; line-height: 1; color: var(--danger); }
.icon-btn:active:not(:disabled) { background: var(--bg-3); }

.compass { width: 56px; height: 56px; cursor: pointer; outline: none; -webkit-tap-highlight-color: transparent; }
.compass:active .compass-face { fill: var(--bg-3); }
/* iOS drew its focus ring round the rose after a tap and left it there. */
.compass:focus { outline: none; }
/* Over the map the same rose turns with the sheet; its rim lights when the
   sheet is off north, which is when tapping it does something. */
.compass.turned .compass-face { stroke: var(--accent); }
.compass-face { fill: var(--glass); stroke: var(--line); }
.needle-n { fill: var(--danger); }
.needle-s { fill: var(--tick-2); }
.compass-n { fill: var(--ink); font-size: 10px; font-weight: 700; }

.scale-chip {
  position: absolute; z-index: 5;
  left: calc(12px + env(safe-area-inset-left));
  bottom: calc(10px + env(safe-area-inset-bottom));
  font-size: 11.5px; color: var(--ink-faint); font-variant-numeric: tabular-nums;
  padding: 4px 9px; border-radius: 8px;
  background: var(--glass-soft); pointer-events: none;
}

/* --- identify readout ----------------------------------------------------- */

.readout {
  position: absolute; left: 50%; transform: translateX(-50%);
  bottom: 14px; z-index: 6;
  display: flex; align-items: flex-start; gap: 10px;
  max-width: min(420px, calc(100% - 24px));
  padding: 10px 12px;
  background: var(--glass-2); border: 1px solid var(--line);
  border-radius: var(--radius); backdrop-filter: blur(10px);
  box-shadow: 0 10px 30px var(--shadow);
}
.readout.hidden { display: none; }
.readout-text { min-width: 0; }
.readout-name { font-weight: 650; }
.readout-sub { color: var(--ink-dim); font-size: 12.5px; }
.readout-orient { margin-top: 4px; font-size: 13.5px; color: var(--accent); }
.readout-orient strong { font-variant-numeric: tabular-nums; letter-spacing: .3px; }
.readout-orient span { color: var(--ink-dim); }
.readout-orient.dim { color: var(--ink-faint); }
.readout-xyz {
  margin-top: 2px; font-size: 11.5px; color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}
.readout-close {
  margin-left: auto; background: none; border: 0; color: var(--ink-faint);
  font-size: 22px; line-height: 1; cursor: pointer; padding: 0 2px;
}

/* --- bottom sheet --------------------------------------------------------- */

.sheet {
  flex: 0 0 auto;
  display: flex; flex-direction: column;
  background: var(--bg-2);
  border-top: 1px solid var(--line);
  border-radius: 18px 18px 0 0;
  box-shadow: 0 -12px 34px var(--shadow);
  transition: height .22s cubic-bezier(.2, .8, .3, 1);
  min-height: 0;
}
.sheet.peek { height: var(--sheet-peek); }
.sheet.half { height: 48vh; }
.sheet.full { height: 86vh; }

.sheet-handle {
  flex: 0 0 auto; height: 24px; border: 0; background: none; cursor: pointer;
  display: grid; place-items: center; padding: 0;
}
.sheet-handle::before {
  content: ''; width: 42px; height: 4px; border-radius: 2px; background: var(--line);
}

.tabbar {
  flex: 0 0 auto;
  /* Auto columns rather than a fixed count, so adding a tab never needs the
     stylesheet edited to match. */
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  border-bottom: 1px solid var(--line);
  padding: 0 4px;
}
.tab {
  appearance: none; border: 0; background: none; cursor: pointer;
  padding: 8px 4px 10px; color: var(--ink-faint);
  display: grid; gap: 2px; justify-items: center;
  border-bottom: 2px solid transparent;
  font-size: 11px; font-weight: 600; letter-spacing: -.1px;
}
.tab-icon { display: grid; place-items: center; }
.tabicon { width: 21px; height: 21px; display: block; }
.tabicon-fill { fill: currentColor; stroke: none; }
.tabicon-line {
  fill: none; stroke: currentColor; stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
}
.tab.active { color: var(--accent); border-bottom-color: var(--accent); }

.sheet-body {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch;
  padding: 4px 14px calc(28px + env(safe-area-inset-bottom));
  overscroll-behavior: contain;
  /* The station list swaps cards in and out above the viewport as it
     scrolls; left on, scroll anchoring would shift the scroll by a card
     every time it did. */
  overflow-anchor: none;
}

/* --- generic panel furniture ---------------------------------------------- */

.section-head { padding: 14px 0 8px; }
.section-head h2 { margin: 0; font-size: 15px; letter-spacing: .01em; }
.section-head p { margin: 3px 0 0; font-size: 12.5px; color: var(--ink-dim); }

.sub-head {
  margin: 20px 0 6px; padding-top: 12px; border-top: 1px solid var(--line);
  font-size: 12px; text-transform: uppercase; letter-spacing: .08em; color: var(--ink-faint);
  font-weight: 700;
}

.ctl { margin: 12px 0; }
.ctl-inline { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.ctl-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.ctl-label { font-size: 13px; color: var(--ink-dim); font-weight: 600; }
.ctl-value { display: flex; align-items: baseline; gap: 3px; }
.ctl-hint { font-size: 11.5px; color: var(--ink-faint); margin-top: 3px; }
.ctl-hint.standalone { margin: 0 0 10px; }
/* The build and the project's fingerprint, quoted between devices — read off a
   screen and typed into a message, so the digits are tabular and selectable
   rather than styled to be skimmed past. */
.ctl-hint.stamp {
  font-variant-numeric: tabular-nums; letter-spacing: .02em;
  color: var(--ink); user-select: text; -webkit-user-select: text;
}
.ctl-hint.warn { color: var(--accent); }
.ctl-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 0 12px; }

.num {
  width: 62px; text-align: right;
  background: var(--bg-3); border: 1px solid var(--line); border-radius: 8px;
  color: var(--ink); padding: 5px 7px; font-size: 14px;
  font-variant-numeric: tabular-nums;
}
.num-wide { width: 70px; }
.num::-webkit-outer-spin-button, .num::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.num[type=number] { -moz-appearance: textfield; }
.unit { color: var(--ink-faint); font-size: 12px; }

/* The track must contrast with BOTH panel backgrounds — event and layer cards
   sit on --bg-3, so the track cannot also be --bg-3 or it vanishes. */
.range {
  --p: 0;                       /* 0..1, set from JS */
  --thumb: 22px;
  --fill: calc(var(--thumb) / 2 + var(--p) * (100% - var(--thumb)));
  --track: var(--well);
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 30px; margin: 2px 0 0; background: none; cursor: pointer;
}
.range::-webkit-slider-runnable-track {
  height: 7px; border-radius: 4px;
  border: 1px solid var(--hair-2);
  background: linear-gradient(to right,
    var(--accent) 0 var(--fill), var(--track) var(--fill) 100%);
}
.range::-moz-range-track {
  height: 7px; border-radius: 4px;
  border: 1px solid var(--hair-2);
  background: linear-gradient(to right,
    var(--accent) 0 var(--fill), var(--track) var(--fill) 100%);
}
.range::-webkit-slider-thumb {
  -webkit-appearance: none; width: 22px; height: 22px; margin-top: -8.5px;
  border-radius: 50%; background: var(--accent); border: 2px solid var(--bg-2);
  box-shadow: 0 1px 3px var(--shadow);
}
.range::-moz-range-thumb {
  width: 22px; height: 22px; border-radius: 50%; background: var(--accent);
  border: 2px solid var(--bg-2); box-shadow: 0 1px 3px var(--shadow);
}

.select, .name-input {
  width: 100%; margin-top: 5px;
  background: var(--bg-3); border: 1px solid var(--line); border-radius: 9px;
  color: var(--ink); padding: 9px 10px; font-size: 14px;
}

.toggle {
  flex: 0 0 auto; width: 50px; height: 30px; border-radius: 15px;
  background: var(--bg-3); border: 1px solid var(--line); cursor: pointer;
  position: relative; padding: 0; transition: background .15s;
}
.toggle .knob {
  position: absolute; top: 3px; left: 3px; width: 22px; height: 22px;
  border-radius: 50%; background: var(--ink-faint); transition: transform .15s, background .15s;
}
.toggle.on { background: var(--accent-tint); border-color: var(--accent); }
.toggle.on .knob { transform: translateX(20px); background: var(--accent); }

.btn {
  appearance: none; cursor: pointer;
  background: var(--bg-3); border: 1px solid var(--line); border-radius: 10px;
  color: var(--ink); padding: 10px 14px; font-size: 13.5px; font-weight: 600;
  min-height: var(--tap);
}
.btn:active:not(:disabled) { background: var(--pressed); }
.btn:disabled { opacity: .35; cursor: default; }
.btn.small { padding: 7px 11px; font-size: 12.5px; min-height: 38px; }
.btn.wide { width: 100%; margin-top: 8px; }
.btn.primary { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.btn.danger { color: var(--danger); border-color: var(--danger-line); }

.row-actions { display: flex; gap: 8px; margin-top: 14px; flex-wrap: nowrap; }
.row-actions.wrap { flex-wrap: wrap; }
.row-actions .btn { flex: 1 1 auto; }

.panel-foot {
  display: flex; align-items: center; gap: 12px;
  margin-top: 14px; flex-wrap: wrap;
}
.foot-note { font-size: 12px; color: var(--ink-faint); }

.empty { padding: 24px 6px; text-align: center; color: var(--ink-dim); }
.empty p { margin: 0 0 6px; }
.empty .dim { font-size: 12.5px; color: var(--ink-faint); }

.about { margin-top: 22px; font-size: 12px; color: var(--ink-faint); line-height: 1.55; }
.about p { margin: 0 0 7px; }
.about-rule { height: 1px; background: var(--line); margin: 16px 0 12px; }
.about-title { color: var(--ink-dim); font-weight: 650; }
.about strong { color: var(--ink-dim); font-weight: 650; }
.about a { color: var(--accent); text-decoration: none; }
.about a:hover { text-decoration: underline; }
.about-link {
  display: inline-block; margin-top: 2px;
  padding: 7px 12px; border-radius: 9px;
  border: 1px solid var(--line); background: var(--bg-3);
}
.about-dim { color: var(--ink-faint); margin-top: 10px; }

/* --- layer list ------------------------------------------------------------ */

.layer-list { display: flex; flex-direction: column; gap: 6px; }

.layer-row, .event-row {
  background: var(--bg-3); border: 1px solid var(--line); border-radius: 12px; overflow: hidden;
}
.layer-head, .event-head {
  width: 100%; display: flex; align-items: center; gap: 11px;
  background: none; border: 0; color: inherit; text-align: left;
  padding: 9px 11px; cursor: pointer; min-height: 56px;
}
.layer-head.static { cursor: default; }
.layer-head.open, .event-head.open { background: var(--accent-tint); }
.layer-title, .event-title { flex: 1 1 auto; min-width: 0; }
.layer-name, .event-name {
  font-size: 14px; font-weight: 620;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.layer-sub, .event-sub {
  font-size: 11.5px; color: var(--ink-dim); font-variant-numeric: tabular-nums;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.chev { color: var(--ink-faint); font-size: 13px; }
.layer-body, .event-body { padding: 4px 12px 14px; border-top: 1px solid var(--line); }
.layer-row.basement { opacity: .72; }

.swatch {
  flex: 0 0 auto; width: 38px; height: 38px; border-radius: 8px; display: block;
}
.swatch.small { width: 32px; height: 32px; }

.unc-divider { display: flex; align-items: center; }
.unc-grip {
  flex: 0 0 auto; width: 30px; border: 0; padding: 0;
  background: none; color: var(--ink-faint); cursor: grab;
  font-size: 15px; line-height: 1; touch-action: none;
}
.unc-grip:active { cursor: grabbing; color: var(--accent); }
.unc-body {
  flex: 1 1 auto; min-width: 0;
  display: flex; align-items: center; gap: 8px;
  background: none; border: 0; cursor: pointer;
  padding: 2px 4px; color: var(--ink-dim);
}
.unc-wave { flex: 1 1 auto; height: 15px; }
.unc-wave path { stroke: var(--ink-faint); stroke-width: 1.6; }
.unc-label {
  font-size: 11px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-faint); white-space: nowrap;
}
.unc-divider.dragging { position: relative; z-index: 3; }
.unc-divider.dragging .unc-wave path { stroke: var(--accent); }
.unc-divider.dragging .unc-label,
.unc-divider.dragging .unc-grip { color: var(--accent); }

/* Which units ended up on each side of an unconformity. */
.unc-split {
  margin: 10px 0 2px; padding: 9px 11px;
  background: var(--bg-2); border: 1px solid var(--line); border-radius: 10px;
  display: flex; flex-direction: column; gap: 6px;
}
.unc-split-row { display: flex; gap: 10px; align-items: baseline; }
.unc-split-key {
  flex: 0 0 106px; font-size: 10.5px; text-transform: uppercase;
  letter-spacing: .03em; color: var(--ink-faint);
}
.unc-split-val { flex: 1 1 auto; font-size: 12.5px; color: var(--ink); }

.rock-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(74px, 1fr));
  gap: 6px; margin-top: 8px;
}
.rock-group {
  grid-column: 1 / -1; font-size: 10.5px; text-transform: uppercase;
  letter-spacing: .07em; color: var(--ink-faint); margin-top: 6px; font-weight: 700;
}
.rock-strip { display: flex; gap: 6px; margin-top: 8px; flex-wrap: wrap; }
.rock-strip .rock-btn { width: 76px; }
.rock-btn {
  display: grid; justify-items: center; gap: 4px;
  background: var(--bg-2); border: 1px solid var(--line); border-radius: 9px;
  padding: 6px 4px; cursor: pointer; color: var(--ink-dim); font-size: 10.5px;
}
.rock-btn.active { border-color: var(--accent); color: var(--ink); background: var(--accent-tint); }
.rock-swatch { width: 100%; height: 30px; border-radius: 5px; display: block; }

.color-strip { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; align-items: center; }
.color-dot {
  width: 28px; height: 28px; border-radius: 50%; cursor: pointer;
  border: 2px solid transparent; padding: 0;
}
.color-dot.active { border-color: var(--ink); }
.color-input {
  width: 34px; height: 30px; padding: 0; border: 1px solid var(--line);
  border-radius: 8px; background: var(--bg-3); cursor: pointer;
}

/* --- history -------------------------------------------------------------- */

.add-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
  gap: 6px; margin-bottom: 14px;
}
.add-btn {
  display: flex; align-items: center; gap: 7px;
  background: var(--bg-3); border: 1px solid var(--line); border-radius: 10px;
  color: var(--ink); padding: 9px 10px; cursor: pointer; font-size: 12.5px;
  font-weight: 600; min-height: 42px; text-align: left;
}
.add-btn:disabled { opacity: .35; }
.add-icon { color: var(--accent); font-size: 15px; }

.timeline { position: relative; padding-left: 14px; }
.timeline::before {
  content: ''; position: absolute; left: 4px; top: 16px; bottom: 16px;
  width: 2px; background: linear-gradient(var(--accent), var(--line));
  border-radius: 1px; opacity: .5;
}
.time-cap {
  display: block; font-size: 10px; text-transform: uppercase; letter-spacing: .09em;
  color: var(--ink-faint); padding: 2px 0;
}
.event-list { display: flex; flex-direction: column; gap: 6px; margin: 4px 0; }
.event-icon {
  flex: 0 0 auto; width: 34px; height: 34px; border-radius: 8px;
  display: grid; place-items: center;
  background: var(--bg-2); border: 1px solid var(--line);
}
.evicon { width: 24px; height: 24px; display: block; }
.evicon-frame { fill: none; stroke: var(--ink-faint); stroke-width: 1.2; opacity: .75; }
.evicon-line {
  fill: none; stroke: var(--accent); stroke-width: 1.5;
  stroke-linecap: round; stroke-linejoin: round;
}
.evicon-line.strong { stroke-width: 2.1; }
.evicon-fill { fill: var(--accent); opacity: .8; stroke: none; }
.add-icon { display: grid; place-items: center; }
.add-icon .evicon { width: 20px; height: 20px; }
.event-head.off { opacity: .45; }
.event-head.off .event-name { text-decoration: line-through; }

.sense-note {
  font-size: 12.5px; color: var(--accent); font-weight: 600;
  margin: -4px 0 4px; font-variant-numeric: tabular-nums;
}

/* Fault type picker */
.segmented {
  display: grid; grid-template-columns: 1fr 1fr; gap: 5px; margin-top: 6px;
}
.seg {
  background: var(--bg-2); border: 1px solid var(--line); border-radius: 9px;
  color: var(--ink-dim); padding: 9px 8px; font-size: 12.5px; font-weight: 650;
  cursor: pointer; min-height: 40px;
}
.seg.active {
  border-color: var(--accent); color: var(--accent);
  background: var(--accent-tint);
}

.ctl-ends {
  display: flex; justify-content: space-between;
  font-size: 11px; color: var(--ink-faint); margin-top: -2px;
}

/* Drag-to-reorder — the timeline and the stratigraphic column share this. */
.event-main, .layer-main { display: flex; align-items: stretch; }
.event-grip, .layer-grip {
  flex: 0 0 auto; width: 30px; border: 0; padding: 0;
  background: none; color: var(--ink-faint); cursor: grab;
  font-size: 15px; line-height: 1; touch-action: none;
  border-right: 1px solid var(--line);
}
.event-grip:active, .layer-grip:active { cursor: grabbing; color: var(--accent); }
.layer-grip.spacer { cursor: default; }
.event-main .event-head, .layer-main .layer-head { flex: 1 1 auto; min-width: 0; }
.event-row.dragging, .layer-row.dragging {
  position: relative; z-index: 3; opacity: .92;
  box-shadow: 0 10px 26px var(--shadow-2);
  border-color: var(--accent);
}
.drop-line {
  height: 3px; border-radius: 2px; background: var(--accent);
  margin: 2px 0; box-shadow: 0 0 8px var(--accent-glow);
}

/* --- dials ---------------------------------------------------------------- */

.dial { display: flex; align-items: center; gap: 14px; margin: 14px 0; }
.dial-svg { width: 108px; height: 108px; flex: 0 0 auto; touch-action: none; cursor: grab; }
.prot-svg { width: 112px; height: 88px; flex: 0 0 auto; touch-action: none; cursor: grab; }
.dial-side { min-width: 0; }
.dial-readout { font-size: 12px; color: var(--ink-faint); margin-top: 3px; }

.dial-face { fill: var(--bg-3); stroke: var(--line); stroke-width: 1.5; }
.tick { stroke: var(--ink-faint); stroke-width: 1; }
.tick.major { stroke: var(--ink-dim); stroke-width: 1.6; }
.dial-card { fill: var(--ink-faint); font-size: 11px; font-weight: 700; }
.dial-strike { stroke: var(--accent); stroke-width: 3; stroke-linecap: round; }
.dial-dip { stroke: var(--accent); stroke-width: 3; stroke-linecap: round; opacity: .85; }
.dial-knob { fill: var(--accent); stroke: var(--bg-2); stroke-width: 2; }

.prot-horizon { stroke: var(--ink-faint); stroke-width: 1.5; }
.prot-arc { fill: none; stroke: var(--ink-faint); stroke-width: 1.2; opacity: .55; }
.prot-wedge { fill: var(--accent-tint); }
.prot-ray { stroke: var(--accent); stroke-width: 3; stroke-linecap: round; }

/* --- presets & view -------------------------------------------------------- */

.preset-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 7px; }
.preset-btn {
  display: grid; gap: 3px; text-align: left; cursor: pointer;
  background: var(--bg-3); border: 1px solid var(--line); border-radius: 11px; padding: 11px;
}
.preset-name { font-size: 13.5px; font-weight: 650; color: var(--ink); }
.preset-blurb { font-size: 11.5px; color: var(--ink-dim); line-height: 1.35; }

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

.update-banner {
  position: fixed; z-index: 50;
  left: 50%; transform: translateX(-50%);
  /* Below the section switch, not over it. An update notice is worth showing
     and is never worth burying the control that changes what the app is. */
  top: calc(58px + env(safe-area-inset-top));
  display: flex; align-items: center; gap: 12px;
  padding: 9px 10px 9px 15px; border-radius: 999px;
  background: var(--accent); color: var(--accent-ink);
  font-size: 13px; font-weight: 600;
  box-shadow: 0 8px 24px var(--shadow);
}
.update-banner button {
  border: 0; border-radius: 999px; cursor: pointer;
  background: var(--accent-ink); color: var(--accent);
  padding: 6px 14px; font-size: 13px; font-weight: 700;
}

/* --- wide screens ---------------------------------------------------------- */

@media (min-width: 900px) {
  #app { flex-direction: row; }
  .stage { flex: 1 1 auto; }
  .sheet {
    flex: 0 0 400px; height: 100% !important;
    border-radius: 0; border-top: 0; border-left: 1px solid var(--line);
    box-shadow: none;
  }
  .sheet-handle { display: none; }
  .sheet-body { padding-bottom: 32px; }
  .readout { bottom: 20px; }
}

/* --- strike and dip markers ----------------------------------------------- */

/* Live reading for the selected marker. Sits under the HUD row rather than at
   the bottom, so it never fights the identify readout for the same strip. */
.marker-chip {
  position: absolute; z-index: 6;
  top: calc(10px + env(safe-area-inset-top) + var(--tap) + 8px);
  left: 50%; transform: translateX(-50%);
  display: flex; align-items: center; gap: 4px;
  max-width: calc(100% - 24px);
  padding: 6px 6px 6px 11px; border-radius: 999px;
  background: var(--glass-2); border: 1px solid var(--line);
  backdrop-filter: blur(10px);
  font-size: 13px; white-space: nowrap;
}
.marker-chip.hidden { display: none; }
.marker-chip strong {
  color: var(--accent); font-variant-numeric: tabular-nums; letter-spacing: .3px;
}
.marker-chip span { color: var(--ink-dim); font-size: 12px; }
.chip-close {
  background: none; border: 0; color: var(--ink-faint);
  font-size: 19px; line-height: 1; cursor: pointer; padding: 0 5px;
}

/* Armed-placement banner: hard to miss, because a mode that silently stays on
   is a mode students get lost in. */
.mode-banner {
  position: absolute; z-index: 6;
  bottom: 14px; left: 50%; transform: translateX(-50%);
  display: flex; align-items: center; gap: 10px;
  max-width: calc(100% - 24px);
  padding: 7px 7px 7px 14px; border-radius: 999px;
  background: var(--accent); color: var(--accent-ink);
  font-size: 13px; font-weight: 600;
  box-shadow: 0 8px 24px var(--shadow);
}
.mode-banner.hidden { display: none; }
.banner-done {
  border: 0; border-radius: 999px; cursor: pointer;
  background: var(--on-accent-tint); color: inherit;
  font: inherit; padding: 5px 12px; min-height: 30px;
}

.marker-list { display: grid; gap: 6px; margin-top: 10px; }
.marker-row {
  display: flex; align-items: stretch; gap: 4px;
  background: var(--bg-3); border: 1px solid transparent; border-radius: 10px;
}
.marker-row.selected { border-color: var(--accent); }
.marker-main {
  flex: 1 1 auto; min-width: 0;
  display: flex; align-items: center; gap: 10px;
  background: none; border: 0; color: inherit; font: inherit; text-align: left;
  padding: 8px 4px 8px 10px; min-height: var(--tap); cursor: pointer;
}
.marker-mark { flex: 0 0 auto; display: grid; place-items: center; }
.sd-mark { width: 26px; height: 26px; display: block; color: var(--ink); }
.sd-line {
  fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round;
}
.marker-row.selected .sd-mark { color: var(--accent); }
.marker-text { min-width: 0; }
.marker-value {
  font-weight: 650; font-variant-numeric: tabular-nums; letter-spacing: .3px;
}
.marker-sub {
  font-size: 11.5px; color: var(--ink-dim);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.marker-del {
  flex: 0 0 auto; width: 38px;
  background: none; border: 0; color: var(--ink-faint);
  font-size: 21px; line-height: 1; cursor: pointer;
}
.marker-del:active { color: var(--danger); }

/* Map-view escape hatch, parked beside undo/redo. */
.map-chip {
  display: flex; align-items: center; gap: 6px;
  height: var(--tap); padding: 0 12px;
  border-radius: 999px; border: 1px solid var(--accent);
  background: var(--accent-tint); color: var(--accent);
  font: inherit; font-size: 12.5px; font-weight: 650; cursor: pointer;
  white-space: nowrap;
}
.map-chip.hidden { display: none; }
.map-chip .chip-x { font-size: 17px; line-height: 1; opacity: .8; }

.btn.armed {
  background: var(--accent); color: var(--accent-ink); border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-tint);
}
.empty-note { color: var(--ink-faint); font-size: 13px; margin: 12px 2px; }

/* --- stereonet ------------------------------------------------------------ */

/* A pane, not a page. It shares the stage with the block so that a change to
   the geology and its effect on the net can be watched at the same time. */
.stereo-panel {
  flex: 0 0 var(--net-split, 46%); min-height: 0; min-width: 0;
  display: flex; flex-direction: column;
  background: var(--bg);
  border-top: 1px solid var(--line);
}
.stereo-panel.hidden { display: none; }

/* Same pill as the bottom sheet's handle, because it does the same job. */
.stereo-grip {
  flex: 0 0 auto; height: 22px; padding: 0;
  border: 0; background: none; cursor: ns-resize; touch-action: none;
  display: grid; place-items: center;
}
.stereo-grip::before {
  content: ''; width: 42px; height: 4px; border-radius: 2px; background: var(--line);
}
.stereo-grip:active::before { background: var(--accent); }

@media (min-aspect-ratio: 4/3) {
  .stage { flex-direction: row; }
  .stereo-panel {
    /* Side by side there is room for both, so the split is fixed and the grip
       has nothing to do. */
    flex: 0 0 clamp(300px, 40%, 470px);
    border-top: 0; border-left: 1px solid var(--line);
  }
  .stereo-grip { display: none; }
  .stereo-head { padding-top: calc(10px + env(safe-area-inset-top)); }
}

.stereo-head {
  flex: 0 0 auto; display: flex; align-items: baseline; gap: 9px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--line);
}
.stereo-head h2 { margin: 0; font-size: 16px; }
.stereo-sub { font-size: 12px; color: var(--ink-faint); }
.stereo-close {
  margin-left: auto; width: var(--tap); height: 34px;
  background: none; border: 0; color: var(--ink-dim);
  font-size: 26px; line-height: 1; cursor: pointer;
}

.stereo-body {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  display: flex; flex-wrap: wrap; align-content: flex-start; gap: 6px 20px;
  padding: 12px 14px calc(20px + env(safe-area-inset-bottom));
}
.stereo-figure {
  flex: 1 1 260px; min-width: 200px; display: grid; place-items: start center;
}
/* Bounded by the viewport height as well as its width, so that on a phone in
   landscape the net shrinks and the answer comes up beside it rather than a
   screen further down. */
.stereo-net { width: 100%; max-width: min(430px, 52vh); height: auto; display: block; }
.stereo-side { flex: 1 1 240px; min-width: 200px; }

/* --- the plot ------------------------------------------------------------- */

.net-face { fill: var(--bg-2); }
.net-grid path { fill: none; stroke: var(--net-grid); stroke-width: 1; }
.net-ticks line { stroke: var(--ink-faint); stroke-width: 1; }
.net-ticks line.major { stroke: var(--ink-dim); stroke-width: 2; }
.net-rim { fill: none; stroke: var(--ink-dim); stroke-width: 1.5; }
.net-card { fill: var(--ink-dim); font-size: 13px; font-weight: 700; }

.net-planes path { fill: none; stroke: var(--net-planes); stroke-width: 1.2; }
.net-planes path.selected { stroke: var(--accent); stroke-width: 2; }

.net-girdle {
  fill: none; stroke: var(--accent); stroke-width: 2.2; stroke-dasharray: 7 4;
}
.net-girdle.map { stroke: var(--map-answer); stroke-width: 1.8; stroke-dasharray: 2 5; }
/* The measured set. A different hue AND a different mark, so the two are told
   apart by shape as well as colour. */
.net-girdle.measured { stroke: var(--measured); stroke-width: 2.2; stroke-dasharray: 7 4; }
.net-measured path {
  fill: none; stroke: var(--measured); stroke-width: 2.4; stroke-linecap: round;
  pointer-events: none;
}

.net-pole { fill: var(--ink); stroke: var(--bg); stroke-width: 1.5; }
.net-pole.selected { fill: var(--accent); stroke-width: 2; }
.net-hit { fill: transparent; cursor: pointer; }

.net-axis path { fill: none; stroke: var(--accent); stroke-width: 2.5; }
.net-axis .dot { fill: var(--accent); stroke: none; }
.net-axis.map path { stroke: var(--map-answer); stroke-width: 2; }
.net-axis.map .dot { fill: var(--map-answer); }
.net-axis.measured path { stroke: var(--measured); stroke-width: 2.5; }
.net-axis.measured .dot { fill: var(--measured); }
.net-mean { fill: none; stroke: var(--accent); stroke-width: 2.5; }
.net-cone {
  fill: none; stroke: var(--accent); stroke-width: 2.2; stroke-dasharray: 7 4;
}

/* --- the readout ---------------------------------------------------------- */

.stereo-verdict {
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 12px 13px; background: var(--bg-2);
}
.stereo-verdict.girdle { border-color: var(--accent-glow); }
.stereo-verdict p { margin: 8px 0 0; font-size: 12.5px; color: var(--ink-dim); }
.stereo-title {
  font-size: 12px; text-transform: uppercase; letter-spacing: .08em;
  color: var(--ink-faint);
}
.stereo-answer { margin-top: 3px; }
.stereo-answer strong {
  font-size: 25px; font-variant-numeric: tabular-nums; letter-spacing: .5px;
  color: var(--accent);
}
.stereo-answer span { font-size: 12px; color: var(--ink-faint); margin-left: 7px; }
.stereo-check {
  margin-top: 10px !important; padding-top: 9px; border-top: 1px solid var(--line);
}
.stereo-check strong {
  color: var(--map-answer); font-variant-numeric: tabular-nums; letter-spacing: .4px;
}

.stereo-count { margin: 10px 2px 0; font-size: 12px; color: var(--ink-faint); }
.stereo-legend { margin: 10px 2px 0; display: grid; gap: 5px; }
.legend-row {
  display: flex; align-items: center; gap: 9px;
  font-size: 12px; color: var(--ink-dim);
}
.legend-mark { flex: 0 0 auto; width: 14px; height: 14px; border-radius: 50%; }
.legend-mark.pole { background: var(--ink); box-shadow: 0 0 0 1.5px var(--bg); }
.legend-mark.girdle {
  border-radius: 0; height: 0; border-top: 2px dashed var(--accent);
}
.legend-mark.axis {
  border-radius: 2px; border: 2px solid var(--accent); transform: rotate(45deg);
  width: 11px; height: 11px;
}
.legend-mark.mean { border: 2.5px solid var(--accent); background: none; }
.legend-mark.cone {
  border: 2px dashed var(--accent); background: none;
}
.legend-mark.map {
  border-radius: 2px; border: 2px solid var(--map-answer); transform: rotate(45deg);
  width: 11px; height: 11px;
}
.legend-mark.measured {
  border-radius: 0; background: none; position: relative;
}
/* An actual cross, drawn the way the net draws it, so the legend and the plot
   are the same mark rather than two things that have to be matched up. */
.legend-mark.measured::before,
.legend-mark.measured::after {
  content: ''; position: absolute; left: 0; right: 0; top: 50%;
  border-top: 2.4px solid var(--measured);
}
.legend-mark.measured::before { transform: rotate(45deg); }
.legend-mark.measured::after { transform: rotate(-45deg); }
.legend-mark.girdle-measured {
  border-radius: 0; height: 0; border-top: 2px dashed var(--measured);
}

/* A caption over one of the two verdict boxes, naming whose poles it is
   about. Without these the pane reads as one answer that contradicts itself. */
.stereo-band {
  margin: 14px 2px 6px; font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .09em; color: var(--ink-faint);
}
.stereo-band:first-child { margin-top: 0; }
.stereo-check-box {
  margin-top: 10px; padding: 11px 13px; border-radius: var(--radius);
  border: 1px solid var(--line); border-left: 3px solid var(--measured);
  background: var(--bg-2);
}
.stereo-check-box p { margin: 7px 0 0; font-size: 12.5px; color: var(--ink-dim); }
.stereo-check-box p.dim { color: var(--ink-faint); font-size: 12px; }
.stereo-check-box strong { color: var(--ink); font-variant-numeric: tabular-nums; }

/* Text sitting on the net beside a mark. Painted stroke-first so the numbers
   stay readable wherever they land — over the graticule, over a pole, or over
   another curve. */
.net-label {
  fill: var(--accent); font-size: 15px; font-weight: 700;
  font-variant-numeric: tabular-nums; letter-spacing: .3px;
  paint-order: stroke;
  stroke: var(--halo); stroke-width: 4px; stroke-linejoin: round;
}

/* The same finding, out in the Field panel where it outlives the overlay. */
.net-summary {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 9px;
  margin-top: 10px; padding: 10px 12px;
  background: var(--bg-3); border-radius: 10px;
  border-left: 3px solid var(--accent);
}
.net-summary.scattered, .net-summary.cluster, .net-summary.conical {
  border-left-color: var(--line);
}
.net-summary .kind {
  font-size: 11px; text-transform: uppercase; letter-spacing: .07em;
  color: var(--ink-faint); flex: 1 0 100%;
}
.net-summary strong {
  font-size: 19px; color: var(--accent);
  font-variant-numeric: tabular-nums; letter-spacing: .4px;
}
.net-summary.scattered strong, .net-summary.cluster strong,
.net-summary.conical strong { color: var(--ink); }
.net-summary .note { font-size: 11.5px; color: var(--ink-faint); }

.chip-row { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 8px; }
.chip {
  border: 1px solid var(--line); border-radius: 999px; cursor: pointer;
  background: var(--bg-3); color: var(--ink-dim);
  font: inherit; font-size: 12.5px; padding: 8px 13px; min-height: 38px;
}
.chip.on { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }

/* The one panel that offers the fit a choice. Quiet until opened, because a
   student building their first block should not need an opinion about it. */
.advanced { margin: 14px 0 4px; border-top: 1px solid var(--line); padding-top: 10px; }
.advanced > summary {
  cursor: pointer; font-size: 12px; color: var(--ink-dim);
  text-transform: uppercase; letter-spacing: .07em;
}
.advanced .ctl-hint { margin-top: 8px; }
.check-row {
  display: flex; align-items: flex-start; gap: 10px; margin-top: 12px;
  font-size: 13.5px; color: var(--ink); cursor: pointer;
}
.check-row input {
  flex: 0 0 auto; width: 18px; height: 18px; margin: 1px 0 0;
  accent-color: var(--accent); cursor: pointer;
}

.stereo-numbers { margin-top: 14px; font-size: 12px; color: var(--ink-faint); }
.stereo-numbers summary { cursor: pointer; color: var(--ink-dim); }
.stereo-numbers p { margin: 7px 0 0; font-variant-numeric: tabular-nums; }
.stereo-numbers p.dim { color: var(--ink-faint); font-variant-numeric: normal; }

@media (prefers-reduced-motion: reduce) {
  .sheet { transition: none; }
}

/* --- sections: block vs map ---------------------------------------------- */

/* Two whole sections sharing one shell. The switch sits over the stage rather
   than in the sheet, because the sheet is where the work happens and a control
   that changes the entire screen should not be in among the ones that change a
   dip by two degrees. */
.mode-switch {
  position: absolute; z-index: 7;
  top: calc(10px + env(safe-area-inset-top)); left: 50%; transform: translateX(-50%);
  display: flex; gap: 2px; padding: 3px;
  background: var(--glass); border: 1px solid var(--line);
  border-radius: 12px; backdrop-filter: blur(8px);
}
.mode-btn {
  appearance: none; border: 0; cursor: pointer;
  background: none; color: var(--ink-dim);
  padding: 6px 15px; border-radius: 9px;
  font-size: 12.5px; font-weight: 650; letter-spacing: .01em;
  min-height: 32px;
}
.mode-btn.on { background: var(--accent); color: var(--accent-ink); }

.map-pane {
  position: relative; flex: 1 1 auto; min-width: 0; min-height: 0;
  overflow: hidden; display: none;
  /* The pane paints the map's own ground, so a canvas caught a frame
     behind a resize never shows the page through. */
  background: var(--canvas);
}
.mode-map .map-pane { display: block; }
.mode-map .block-pane, .mode-map .stereo-panel { display: none !important; }

.mapview { display: block; position: absolute; inset: 0; width: 100%; height: 100%; touch-action: none; }
/* Behind the map the page is the map's own ground: whatever the phone
   leaves unpainted at the edge of the screen, under the home indicator,
   reads as map rather than as a stripe of page. */
/* What reaches the bottom of the screen: the sheet, or in full screen the
   map or the block. */
body { background: var(--bg-2); }
body.full-map { background: var(--canvas); }
body.full-block { background: var(--scene); }

.hud-icon { width: 22px; height: 22px; display: block; }
.icon-btn.on { background: var(--accent); border-color: var(--accent); }
.icon-btn.on .hud-icon .tabicon-line { stroke: var(--accent-ink); }

/* Scale bar: a drawn rule with a round number under it, because a bar with no
   rule is just a number floating over a photograph. */
.map-scale { display: flex; align-items: center; gap: 7px; pointer-events: none; }
.scale-rule {
  height: 7px; border: 1px solid var(--ink-dim); border-top: 0;
  display: inline-block;
}
/* Bottom left, above the scale bar, well away from the button column on the
   right, and small: it is a credit, not a control. */
.map-attrib {
  position: absolute; z-index: 5;
  left: calc(12px + env(safe-area-inset-left));
  bottom: calc(36px + env(safe-area-inset-bottom));
  font-size: 9px; line-height: 1.2; color: var(--ink-faint);
  background: var(--glass-soft); padding: 2px 6px; border-radius: 5px;
  pointer-events: none; max-width: 60%; text-align: left;
}

/* Everything transient along the bottom of the map, in one column, clear of
   the scale bar and the attribution in the corners. */
/* Stretched across the pane and inset, rather than centred by a transform and
   left to shrink-wrap its children.
   Shrink-wrapping looks equivalent and is not. Each chip in here caps itself
   at a percentage of its parent, for the days it is not in a stack at all; a
   shrink-to-fit parent is sized BY those children, so the percentage would be
   measured against a width the cap itself decides, and it settles a little
   narrower than the text every time. That is what put a station's unit on its
   own line with the separator dot stranded above it, and wrapped "4 tiles
   loading" in half. Two fixed edges give the percentages something real to be
   a percentage of, and align-items keeps every chip its own width. */
.map-bottom {
  position: absolute; z-index: 6; left: 12px; right: 12px;
  bottom: calc(38px + env(safe-area-inset-bottom));
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  pointer-events: none;
}
.map-bottom > * { pointer-events: auto; }
.map-bottom .map-status,
.map-bottom .map-readout,
.map-bottom .mode-banner, .strat-bottom .mode-banner {
  position: static; transform: none; left: auto; right: auto; top: auto; bottom: auto;
}

/* The message the whole feature exists to be able to show. */
.map-status {
  font-size: 12px; font-weight: 600;
  padding: 6px 11px; border-radius: 9px;
  background: var(--glass-2); border: 1px solid var(--line);
  color: var(--ink-dim); backdrop-filter: blur(8px); pointer-events: none;
  max-width: calc(100% - 32px); text-align: center;
}
.map-status.hidden { display: none; }
.map-status.bad { color: var(--bad-text); border-color: var(--bad-line); }

.map-readout {
  display: flex; align-items: center; gap: 8px;
  max-width: min(420px, calc(100% - 24px));
  padding: 8px 12px; font-size: 13.5px;
  background: var(--glass-2); border: 1px solid var(--line);
  border-radius: var(--radius); backdrop-filter: blur(10px);
}
.map-readout.hidden { display: none; }
/* The readout's text is a button that opens the station on its tab. */
.readout-open {
  flex: 1 1 auto; min-width: 0; text-align: left; padding: 0; margin: 0;
  background: none; border: 0; color: inherit; font: inherit; cursor: pointer;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* The station list only builds the cards near the viewport; these hold the
   height of the ones it has not. */
.vlist { display: block; }
.vspace { display: block; height: 0; }
.map-readout strong { color: var(--accent); font-variant-numeric: tabular-nums; letter-spacing: .3px; }
.map-readout span { color: var(--ink-dim); }

/* --- field panels --------------------------------------------------------- */

.stats {
  display: grid; grid-template-columns: 1fr 1fr; gap: 6px 14px;
  margin: 10px 0 4px;
}
.stat { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.stat-label { font-size: 12px; color: var(--ink-faint); }
.stat-value {
  font-size: 13.5px; font-weight: 650; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.stat-value.good { color: var(--good); }
.stat-value.warn { color: var(--accent); }
.stat-value.bad { color: var(--danger); }
.stat-value.dim { color: var(--ink-faint); font-weight: 500; }

.coord-line {
  font-size: 11.5px; color: var(--ink-faint);
  font-variant-numeric: tabular-nums; white-space: pre-line;
  margin: 4px 0 2px;
}

.chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.chip {
  appearance: none; cursor: pointer;
  background: var(--bg-3); border: 1px solid var(--line); border-radius: 999px;
  color: var(--ink-dim); padding: 8px 13px; font-size: 12.5px; font-weight: 600;
  min-height: 38px;
}
.chip.on { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }

.note-input { resize: vertical; min-height: 64px; font-family: inherit; line-height: 1.4; }

/* The live compass reading. Big, because it is read at arm's length with the
   phone lying on a rock. */
.live { margin: 10px 0 4px; }
.reading {
  background: var(--bg-3); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 14px; text-align: center;
}
.reading-big {
  font-size: 34px; font-weight: 700; letter-spacing: .5px;
  font-variant-numeric: tabular-nums; color: var(--accent); line-height: 1.1;
}
.reading-sub { font-size: 13px; color: var(--ink-dim); margin-top: 2px; }
.reading-scatter { font-size: 12px; color: var(--ink-faint); margin-top: 6px; }
.reading-scatter.good { color: var(--good); }
.reading-scatter.warn { color: var(--accent); }

/* "Hold still" as something you watch happen rather than a word on a screen. */
.steady {
  height: 5px; border-radius: 3px; background: var(--well);
  margin-top: 10px; overflow: hidden;
}
.steady-fill {
  display: block; height: 100%; width: 0;
  background: var(--accent); transition: width .12s linear;
}
.steady.ready .steady-fill { background: var(--good); }

.notice {
  background: var(--bg-3); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 12px 14px; margin: 10px 0;
}
.notice p { margin: 0 0 5px; font-size: 13px; }
.notice p:last-child { margin: 0; }
.notice .dim { color: var(--ink-faint); font-size: 12.5px; }
.notice.warn { border-color: var(--accent-glow); }

.card {
  background: var(--bg-3); border: 1px solid var(--line);
  border-radius: var(--radius); margin: 8px 0; overflow: hidden;
}
.card.selected { border-color: var(--accent); }
.card-main {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 11px 12px; background: none; border: 0; cursor: pointer;
  color: var(--ink); text-align: left; font: inherit; min-height: var(--tap);
}
.card-main.static { cursor: default; }
.card-swatch { flex: 0 0 auto; display: grid; place-items: center; }
.card-swatch .swatch.small { width: 26px; height: 26px; border-radius: 6px; }
.card-text { display: grid; gap: 2px; min-width: 0; flex: 1 1 auto; }
.card-title {
  font-size: 14px; font-weight: 650;
  font-variant-numeric: tabular-nums; letter-spacing: .2px;
}
.card-sub {
  font-size: 12px; color: var(--ink-faint);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.card-body { padding: 2px 12px 12px; border-top: 1px solid var(--line); }

.pill {
  flex: 0 0 auto; font-size: 11px; font-weight: 700;
  padding: 4px 9px; border-radius: 999px;
  background: var(--hair-2); color: var(--ink-dim);
}
.pill.good { background: var(--good-bg); color: var(--good); }
.pill.warn { background: var(--accent-tint); color: var(--accent); }
.pill.bad { background: var(--danger-bg); color: var(--danger); }
.pill.dim { color: var(--ink-faint); }

.area-card .row-actions, .unit-card .row-actions { padding: 0 12px 12px; margin-top: 0; }

.progress { margin: 12px 0 8px; }
.progress-bar {
  height: 7px; border-radius: 4px; background: var(--well);
  border: 1px solid var(--hair-2); overflow: hidden;
}
.progress-bar span {
  display: block; height: 100%; width: 0; background: var(--accent);
  transition: width .2s linear;
}
.progress-text {
  margin-top: 6px; font-size: 12px; color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}

/* Where a reading came from and how much to trust it, kept with the reading. */
.provenance {
  font-size: 11.5px; color: var(--ink-faint); line-height: 1.5;
  margin: 10px 0 2px; padding-top: 8px; border-top: 1px solid var(--line);
}

/* On a wide screen the sheet moves beside the map rather than under it, the
   same way the stereonet does. */
@media (min-aspect-ratio: 1/1) and (min-width: 760px) {
  .stats { grid-template-columns: 1fr 1fr 1fr 1fr; }
}

/* --- the full-screen clinometer ------------------------------------------- */

/* Covers everything, including the sheet and the map. A reading is taken with
   the phone flat on rock and read at arm's length; nothing else on screen is
   useful at that moment, and the map underneath was actively in the way. */
.measure-full {
  position: fixed; inset: 0; z-index: 60;
  display: flex; flex-direction: column;
  background: var(--bg);
  padding: calc(8px + env(safe-area-inset-top)) calc(14px + env(safe-area-inset-right))
           calc(10px + env(safe-area-inset-bottom)) calc(14px + env(safe-area-inset-left));
  gap: 6px;
  overflow: hidden;
}

.mf-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.mode-switch.inline {
  position: static; transform: none; backdrop-filter: none;
  background: var(--bg-2);
}
.mf-close {
  flex: 0 0 auto; width: 40px; height: 40px; border-radius: 12px;
  background: var(--bg-2); border: 1px solid var(--line); color: var(--ink-dim);
  font-size: 26px; line-height: 1; cursor: pointer; padding: 0;
}

/* Between the header and the buttons everything scrolls: the dial, the
   readout, and the details of the station being recorded. The buttons stay
   put at the foot so Save is never off the bottom of a long form. */
.mf-scroll {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch;
  display: flex; flex-direction: column; gap: 6px;
  overscroll-behavior: contain;
}
.mf-dial-wrap {
  flex: 0 0 auto; height: min(64vw, 36vh); min-height: 140px;
  display: grid; place-items: center;
}
.mf-dial { width: 100%; height: 100%; display: block; }
.mf-details { border-top: 1px solid var(--line); margin-top: 4px; padding-top: 2px; }
.mf-details .ctl { margin: 8px 0; }
.mf-actions { flex: 0 0 auto; display: grid; gap: 6px; padding-top: 4px; }

.mf-face { fill: var(--well-2); stroke: var(--line); stroke-width: 1.5; }
.mf-inner { fill: none; stroke: var(--hair-2); stroke-width: 1; }
.mf-tick { stroke: var(--tick); stroke-width: 1; }
.mf-tick.mid { stroke: var(--tick-2); stroke-width: 1.3; }
.mf-tick.major { stroke: var(--ink-dim); stroke-width: 2; }
.mf-card { fill: var(--ink); font-size: 13px; font-weight: 800; }
.mf-deg { fill: var(--ink-faint); font-size: 9px; font-weight: 600; }
.mf-hub { fill: var(--accent); }
.mf-lubber { fill: var(--ink-dim); }
.mf-card-g { transition: transform .08s linear; transform-box: view-box; }

.mf-spin { transition: opacity .15s; }
.mf-strike { stroke: var(--accent); stroke-width: 4; stroke-linecap: round; }
.mf-dip { stroke: var(--accent); stroke-width: 4; stroke-linecap: round; }
.mf-arrow {
  fill: none; stroke: var(--accent); stroke-width: 4;
  stroke-linecap: round; stroke-linejoin: round;
}
.mf-diplabel { fill: var(--accent); font-size: 13px; font-weight: 700; }

.mf-readout { display: flex; align-items: center; gap: 14px; }
.mf-numbers { flex: 1 1 auto; min-width: 0; }
.mf-big {
  font-size: 40px; font-weight: 700; letter-spacing: .5px; line-height: 1.05;
  color: var(--accent); font-variant-numeric: tabular-nums;
}
.mf-sub { font-size: 13px; color: var(--ink-dim); margin-top: 1px; }
.mf-units {
  font-size: 10.5px; color: var(--ink-faint); text-transform: uppercase;
  letter-spacing: .09em; font-weight: 700; margin-top: 2px;
}

/* A plan view cannot show a dip, so the tilt gets a side elevation of its own. */
.mf-incl-wrap { flex: 0 0 auto; width: 118px; }
.mf-incl { width: 100%; height: auto; display: block; }
.mf-horizon { stroke: var(--tick); stroke-width: 1.5; stroke-dasharray: 3 3; }
.mf-ray { stroke: var(--accent); stroke-width: 3.5; stroke-linecap: round; }
.mf-arc { fill: var(--accent-tint); stroke: none; }

.mf-steady {
  flex: 0 0 auto; height: 6px; border-radius: 3px; background: var(--well); overflow: hidden;
}
.mf-steady-fill {
  display: block; height: 100%; width: 0;
  background: var(--accent); transition: width .12s linear;
}
.mf-steady.ready .mf-steady-fill { background: var(--good); }
.mf-steady-text {
  font-size: 11.5px; color: var(--ink-faint); text-align: center;
  font-variant-numeric: tabular-nums;
}

.mf-chips { justify-content: center; margin: 0; }
.mf-chips .chip { padding: 7px 11px; font-size: 12px; min-height: 34px; }

.mf-hold, .mf-save { flex: 0 0 auto; margin-top: 0; }
.mf-why { font-size: 11.5px; color: var(--accent); text-align: center; min-height: 0; }
.mf-foot {
  font-size: 11px; color: var(--ink-faint); text-align: center;
  font-variant-numeric: tabular-nums;
}
.mf-foot.warn { color: var(--accent); }

/* --- the map's stereonet ------------------------------------------------- */

/* Same full-screen frame as the compass. The net takes the top, the verdict,
   the filters and the station rows scroll under it. */
.net-full .mf-scroll { gap: 10px; }
.net-title { margin: 0; font-size: 16px; flex: 0 0 auto; }
.net-full .mf-head .stereo-sub { flex: 1 1 auto; text-align: center; }
.net-figure { flex: 0 0 auto; display: grid; place-items: center; }
.net-figure .stereo-net { max-width: min(430px, 46vh); }
.net-side { flex: 0 0 auto; }
.net-rows { display: grid; gap: 4px; margin: 6px 0 10px; }
.net-row {
  display: grid; grid-template-columns: 16px auto auto 1fr; gap: 8px; align-items: baseline;
  width: 100%; text-align: left; padding: 6px 8px; border-radius: 8px;
  background: var(--hair-1); border: 1px solid transparent; color: var(--ink);
  font: inherit; font-size: 13px; cursor: pointer;
}
.net-row.off { color: var(--ink-faint); }
.net-row:disabled { cursor: default; }
.net-row.selected { border-color: var(--accent); }
.net-row-mark { color: var(--accent); font-size: 11px; }
.net-row.off .net-row-mark { color: var(--ink-faint); }
.net-row-name { font-weight: 650; font-variant-numeric: tabular-nums; }
.net-row-att { font-variant-numeric: tabular-nums; }
.net-row-sub { color: var(--ink-dim); font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@media (min-aspect-ratio: 1/1) {
  .net-full .mf-scroll { grid-template-columns: minmax(0, 1fr) minmax(300px, 420px); }
  .net-figure { grid-column: 1; grid-row: 1 / span 6; position: sticky; top: 0; height: auto; }
  .net-figure .stereo-net { max-width: min(520px, 80vh); }
  .net-side { grid-column: 2; }
}

/* What came back through the door, shown on the Measure panel. */
.held-reading {
  font-size: 15px; color: var(--accent); margin-bottom: 8px;
  font-variant-numeric: tabular-nums;
}
.held-reading.empty { display: none; }
.held-reading strong { font-size: 19px; letter-spacing: .3px; }
.held-reading span { color: var(--ink-dim); font-size: 12.5px; }
.held-reading .held-scatter { color: var(--ink-faint); }

/* Landscape, or a tablet: the dial goes beside the controls rather than
   shrinking to a coin above them, and stays put while the details scroll. */
@media (min-aspect-ratio: 1/1) {
  .mf-scroll {
    display: grid; gap: 6px 22px;
    grid-template-columns: minmax(0, 1fr) minmax(280px, 380px);
    align-content: start;
  }
  .mf-dial-wrap {
    grid-column: 1; grid-row: 1 / span 6; height: auto; max-height: 62vh;
    position: sticky; top: 0;
  }
  .mf-readout, .mf-steady, .mf-steady-text, .mf-chips, .mf-details { grid-column: 2; }
  .mf-actions { grid-template-columns: 1fr 1fr; }
  .mf-why, .mf-foot { grid-column: 1 / -1; }
}

/* The dial is a tap target as well as a picture. */
.mf-dial-wrap { cursor: pointer; -webkit-tap-highlight-color: transparent; }
.mf-dial-wrap:active .mf-face { fill: var(--well-3); }

/* The same reading stated the other way round: a plane's dip line, or the
   plane a measured line is lying in. */
.mf-derived {
  font-size: 11.5px; color: var(--ink-faint); margin-top: 3px;
  font-variant-numeric: tabular-nums;
}

.card-note { padding: 0 12px 12px; margin: 0; }

/* --- map HUD layout ------------------------------------------------------- */

/* The map's own buttons stack down the right edge instead of running along the
   top. Three of them in a row, plus undo and redo on the left, left the
   Block/Map switch nowhere to sit on a phone held upright — they overlapped.
   A column is also what every other map puts there. The block section keeps
   its compass in the corner and is untouched. */


/* Full-screen map: the panel goes away entirely, the same way the map goes
   away when the clinometer is open. Whichever one is being used gets the
   screen. */
.map-full .sheet { display: none; }
/* The block half's equivalent. Same rule, same reason: on a phone the block
   and the panel do not both fit, and a block you cannot turn is not a block
   diagram. Worth more here than on the map, because with the stereonet or the
   ground map open the block is already down to a third of the screen. */
.block-full .sheet { display: none; }

.mf-target {
  flex: 1 1 auto; text-align: center; min-width: 0;
  font-size: 12px; font-weight: 650; color: var(--accent);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* The base-layer menu, level with the layer button in the map's right-hand
   column; the button sets top and right when it opens. */
.layer-menu {
  position: absolute; z-index: 6;
  display: grid; gap: 2px; padding: 4px; min-width: 120px;
  background: var(--glass-2); border: 1px solid var(--line); border-radius: 12px;
  backdrop-filter: blur(8px); box-shadow: 0 8px 24px var(--shadow);
}
.layer-menu.hidden { display: none; }
.layer-item {
  display: block; width: 100%; text-align: left; padding: 8px 12px; border-radius: 8px;
  background: none; border: 0; color: var(--ink); font: inherit; font-size: 14px; cursor: pointer;
}
.layer-item.on { background: var(--accent); color: var(--accent-ink); font-weight: 600; }

/* --- drawing a line ------------------------------------------------------- */

.draw-bar {
  display: flex; align-items: center; gap: 6px;
  padding: 6px 8px 6px 14px; border-radius: 999px;
  background: var(--glass-2); border: 1px solid var(--line);
  backdrop-filter: blur(10px); box-shadow: 0 8px 24px var(--shadow);
}
.draw-bar.hidden { display: none; }
.draw-count {
  font-size: 12.5px; font-weight: 650; color: var(--ink-dim);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.draw-btn {
  appearance: none; cursor: pointer; border: 1px solid var(--line);
  background: var(--bg-3); color: var(--ink);
  border-radius: 999px; padding: 6px 12px; font-size: 12.5px; font-weight: 600;
  min-height: 34px;
}
.draw-btn.primary { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.draw-btn:disabled { opacity: .35; cursor: default; }

.line-swatch {
  flex: 0 0 auto; width: 26px; height: 4px; border-radius: 2px;
  box-shadow: 0 0 0 1px var(--hair-3);
}

/* Which project is open, and what is in the others. */
.project-card .card-main:disabled { opacity: 1; cursor: default; }
.project-dot {
  flex: 0 0 auto; width: 10px; height: 10px; border-radius: 50%;
  border: 2px solid var(--ink-faint); background: none;
}
.project-dot.on { border-color: var(--accent); background: var(--accent); }

/* --- the ground map beside the block -------------------------------------- */

/* Shares .stereo-panel's layout on purpose: it does the same job in the same
   slot, and a second set of split rules would drift away from the first. */
.ground-body {
  flex: 1 1 auto; min-height: 0; min-width: 0;
  position: relative; padding: 6px 10px 0;
}
.ground-canvas { display: block; width: 100%; height: 100%; }

.ground-legend {
  flex: 0 0 auto; display: flex; gap: 8px; flex-wrap: wrap;
  padding: 8px 14px calc(10px + env(safe-area-inset-bottom));
}
.ground-toggle {
  font: inherit; font-size: 12px; line-height: 1;
  padding: 6px 11px; border-radius: 999px; cursor: pointer;
  background: transparent; color: var(--ink-faint);
  border: 1px solid var(--line);
}
.ground-toggle.on { color: var(--ink); border-color: var(--ink-faint); }

/* Per-station unit disagreements: a short list, not a table. */
.unit-check { display: grid; gap: 4px; margin: 6px 0 2px; }
.unit-check .stat-value { font-weight: 600; font-size: 12.5px; }

/* --- map units ------------------------------------------------------------ */

.unit-dot {
  width: 12px; height: 12px; border-radius: 3px; flex: 0 0 auto;
  border: 1px solid var(--hair-3);
}

/* Pick the unit, then tap — so the chips read as a palette rather than a list. */
.unit-chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 2px 0 8px; }
.unit-chip {
  display: inline-flex; align-items: center; gap: 7px;
  font: inherit; font-size: 13px; line-height: 1;
  padding: 7px 12px; border-radius: 999px; cursor: pointer;
  background: transparent; color: var(--ink-dim);
  border: 1px solid var(--line);
}
.unit-chip.on {
  color: var(--accent-ink); background: var(--accent); border-color: var(--accent);
}
.unit-chip.on .unit-dot { border-color: rgba(0, 0, 0, .3); }

.unit-new { margin-bottom: 8px; }

/* One line per shaded area: colour, name, size, remove. */
.unit-list { display: grid; gap: 4px; margin: 10px 0 4px; }
.unit-row {
  display: flex; align-items: center; gap: 9px;
  padding: 5px 6px 5px 8px; border-radius: 8px;
  background: var(--hair-1);
}
.unit-row.warn { box-shadow: inset 0 0 0 1px var(--accent-glow); }
.unit-row .line-sub { margin-left: auto; white-space: nowrap; }

.unit-swatch {
  width: 22px; height: 22px; flex: 0 0 auto; padding: 0; cursor: pointer;
  background: none; border: 1px solid var(--line); border-radius: 5px;
}
.unit-swatch:disabled { opacity: .35; cursor: default; }
.unit-swatch::-webkit-color-swatch-wrapper { padding: 2px; }
.unit-swatch::-webkit-color-swatch { border: 0; border-radius: 3px; }

.unit-name-input {
  flex: 1 1 auto; min-width: 0;
  font: inherit; font-size: 13.5px; color: var(--ink);
  background: transparent; border: 0; border-bottom: 1px dashed transparent;
  padding: 2px 0;
}
.unit-name-input:hover { border-bottom-color: var(--line); }
.unit-name-input:focus { outline: none; border-bottom-color: var(--accent); }
.unit-name-input::placeholder { color: var(--ink-faint); font-style: italic; }


/* --- the Strata section --------------------------------------------------- */

/* The third sibling. Same shape as the map's pane — hidden until its mode is
   on, filling the stage when it is — and scrolling in one direction only,
   because a stratigraphic column is a tall narrow thing and fitting it to the
   width is the whole reason it is drawn to a scale. */
.strat-pane {
  position: relative; flex: 1 1 auto; min-width: 0; min-height: 0;
  overflow: hidden; display: none;
}
.mode-strata .strat-pane { display: block; }
.mode-strata .block-pane,
.mode-strata .map-pane,
.mode-strata .stereo-panel { display: none !important; }

.strat-scroll {
  position: absolute; inset: 0;
  overflow-y: auto; overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  padding: calc(52px + env(safe-area-inset-top)) 0 calc(56px + env(safe-area-inset-bottom));
}
/* The section is drawn UNDER the HUD rather than beside it, so when the corner
   buttons drop to a second row its top padding has to follow them down —
   otherwise undo and redo sit on the grain-size axis. */
@media (max-width: 460px) {
  .strat-scroll { padding-top: calc(116px + env(safe-area-inset-top)); }
}
.strat-sheet { display: block; padding: 0 8px; }

/* The drawing fills the width and takes whatever height its scale gives it.
   `touch-action: pan-y` is load-bearing: a drag over the section scrolls it,
   and only an armed mode takes that gesture away. */
.strat-svg {
  display: block; width: 100%; height: auto; max-width: 640px;
  margin: 0 auto; touch-action: pan-y;
}
.strat-svg text { font-family: inherit; }

.strat-empty {
  padding: 40px 22px; text-align: center; color: var(--ink-dim);
  max-width: 420px; margin: 0 auto;
}
.strat-empty p { margin: 0 0 8px; }
.strat-empty .dim { font-size: 12.5px; color: var(--ink-faint); line-height: 1.6; }

.strat-scale {
  position: absolute; z-index: 5;
  left: calc(10px + env(safe-area-inset-left));
  bottom: calc(10px + env(safe-area-inset-bottom));
  pointer-events: none; font-variant-numeric: tabular-nums;
}
/* Two fixed edges rather than a centring transform, for the reason .map-bottom
   has them. */
.strat-bottom {
  position: absolute; z-index: 6; left: 12px; right: 12px;
  bottom: calc(38px + env(safe-area-inset-bottom));
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  pointer-events: none;
}
.strat-bottom > * { pointer-events: auto; }

/* A selected unit is outlined in the drawing; its whole row lifts slightly so
   the selection reads even where the box is only a few pixels tall. */
.strat-unit .strat-hit { cursor: pointer; }
.strat-unit.selected .strat-lith { filter: brightness(1.12); }
.strat-unit.unknown .strat-lith { opacity: .72; }

/* Symbols. One rule serves the drawing, the palette and the legend; the
   exported file carries its own copy, because a stylesheet is exactly what a
   saved drawing does not take with it. */
.sym-line { fill: none; stroke: currentColor; stroke-width: 1.3;
  stroke-linecap: round; stroke-linejoin: round; }
.sym-fill { fill: currentColor; stroke: none; }
.sym-fill.soft { fill: currentColor; fill-opacity: .12; }
.strat-sym { color: var(--ink); }

.sym-icon { width: 22px; height: 22px; display: block; color: var(--ink); }
.card-sym { width: 24px; height: 24px; }
.legend-sym { width: 20px; height: 20px; flex: 0 0 auto; }

/* The palette: a grid of tap targets big enough for a thumb, each with its
   name under it — a symbol nobody can name is a symbol nobody will use. */
.sym-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(78px, 1fr));
  gap: 6px; margin: 8px 0 4px;
}
.sym-btn {
  display: grid; justify-items: center; gap: 4px;
  padding: 8px 4px 6px; min-height: 64px;
  background: var(--bg-3); border: 1px solid var(--line); border-radius: 10px;
  color: var(--ink-dim); cursor: pointer; font: inherit;
}
.sym-btn:active { background: var(--pressed); }
.sym-btn.on { border-color: var(--accent); background: var(--accent-tint); color: var(--accent); }
.sym-name {
  font-size: 9.5px; line-height: 1.2; text-align: center; color: var(--ink-faint);
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.sym-btn.on .sym-name { color: var(--accent); }

/* The legend, in the panel. */
.legend-list { display: grid; gap: 5px; margin: 8px 0 4px; }
.legend-row {
  display: flex; align-items: center; gap: 10px;
  padding: 5px 8px; border-radius: 8px;
  background: var(--hair-1);
}
.legend-row .swatch.small { width: 22px; height: 16px; border-radius: 4px; flex: 0 0 auto; }
.legend-label { flex: 1 1 auto; font-size: 13px; color: var(--ink); }
.legend-count { font-size: 11.5px; color: var(--ink-faint); font-variant-numeric: tabular-nums; }

/* The column list. Dragged by a grip, exactly as the block's layers and its
   timeline are — same gesture, same handle, same drop line, because they are
   the same act on three lists and learning it once should be enough. */
.unit-stack { margin: 4px 0; }
.card.split { display: flex; align-items: stretch; }
.card.split .card-main { flex: 1 1 auto; min-width: 0; }
.unit-grip {
  flex: 0 0 auto; width: 30px; border: 0; padding: 0;
  background: none; color: var(--ink-faint); cursor: grab;
  font-size: 15px; line-height: 1; touch-action: none;
  border-right: 1px solid var(--line);
}
.unit-grip:active { cursor: grabbing; color: var(--accent); }
.card.unit-row.dragging {
  position: relative; z-index: 3; opacity: .92;
  box-shadow: 0 10px 26px var(--shadow-2);
  border-color: var(--accent);
}
.card-side {
  flex: 0 0 auto; display: flex; flex-direction: column;
  border-left: 1px solid var(--line);
}
.mini {
  flex: 1 1 auto; width: 36px; min-height: 26px;
  background: none; border: 0; color: var(--ink-faint);
  font-size: 14px; line-height: 1; cursor: pointer;
}
.mini:active { background: var(--hair-2); color: var(--ink); }
.card.group { border-style: dashed; }
.group-mark { font-size: 20px; color: var(--ink-faint); line-height: 1; }
.flag {
  flex: 0 0 auto; font-size: 15px; font-weight: 700; padding: 0 4px;
}
.flag.warn { color: var(--accent); }

.editor { margin-top: 10px; padding-top: 4px; }
.swatch-pair { display: flex; align-items: center; gap: 8px; }
.swatch-pair .swatch.small { width: 26px; height: 26px; border-radius: 6px; }

/* The grain profile, as rows of height and size. */
.grain-list { display: grid; gap: 5px; margin: 8px 0 4px; }
.grain-row {
  display: flex; align-items: center; gap: 8px;
  padding: 4px 6px; border-radius: 8px; background: var(--hair-1);
}
.grain-row .num { width: 52px; }
.grain-select { margin-top: 0; flex: 1 1 auto; min-width: 0; }

/* Full screen: the same deal the block and the map have. */
.strat-full .sheet { pointer-events: auto; }

/* The field-ready check: the one question asked in a parking lot, not a lab. */
.ready-card {
  margin: 4px 0 16px; padding: 12px;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--hair-1);
}
.ready-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.ready-title { font-size: 13.5px; font-weight: 700; color: var(--ink); }
.ready-summary { margin: 8px 0 2px; font-size: 12.5px; color: var(--ink-dim); line-height: 1.5; }
.ready-row { padding: 8px 0 0; border-top: 1px solid var(--line); margin-top: 8px; }
.ready-row-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.ready-label { font-size: 12.5px; color: var(--ink-dim); }
.ready-detail {
  margin: 5px 0 2px; font-size: 11.5px; line-height: 1.5; color: var(--ink-faint);
}

/* A line that passed, but only because the check changed something. */
.ready-detail.changed { color: var(--accent); }

/* --- the cross section beside the block ----------------------------------- */

/* Another occupant of the stereonet's slot, so it inherits the split, the grip
   and the stacked-vs-side-by-side rules rather than growing its own. */
/* Everything below the head has to survive the pane being dragged down to a
   third of a phone screen, so nothing in here has a height it will not give
   up, and the pane clips rather than spilling its section over the sheet. */
.xs-panel { overflow: hidden; }
.xs-body {
  flex: 1 1 auto; min-height: 0; min-width: 0; overflow: hidden;
  display: flex; flex-direction: column; gap: 8px;
  padding: 8px 12px 0;
}
/* The locator is a control, not the picture — it gets a strip and the section
   takes everything else, because the section is what is being read. It is the
   first thing to give ground when there is not enough. */
.xs-locator {
  flex: 0 1 110px; min-height: 56px;
  position: relative; touch-action: none; cursor: crosshair;
}
.xs-map { display: block; width: 100%; height: 100%; }
/* The section outranks the locator for space. Giving the plot the larger
   minimum is what expresses that: when the pane is dragged short, the strip
   that only has to be aimed at gives way, and the picture being read does not. */
.xs-plotwrap { flex: 1 1 auto; min-height: 130px; position: relative; }
.xs-plot { display: block; width: 100%; height: 100%; }

@media (min-aspect-ratio: 4/3) {
  .xs-locator { flex: 0 1 190px; }
}

.xs-note {
  flex: 0 0 auto;
  padding: 3px 14px 0; font-size: 12.5px; color: var(--ink-dim);
}
.xs-note:empty { display: none; }
.xs-note strong { color: var(--ink); font-weight: 650; }

.xs-legend {
  flex: 0 0 auto; display: flex; flex-wrap: wrap; gap: 3px 12px;
  padding: 4px 14px 0; font-size: 11.5px; color: var(--ink-dim);
}
.xs-key { display: inline-flex; align-items: center; gap: 5px; }

.xs-foot {
  flex: 0 0 auto; display: flex; gap: 6px; flex-wrap: wrap; align-items: center;
  padding: 8px 14px calc(10px + env(safe-area-inset-bottom));
}

/* Built as a pill so it sits in the same row as the buttons beside it rather
   than dropping a system control into the middle of them. The select itself is
   stripped bare and the pill draws the border and the caret. */
.xs-ve-wrap {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 0 9px 0 11px; border-radius: 999px;
  border: 1px solid var(--line); cursor: pointer;
}
.xs-ve-label { font-size: 11px; color: var(--ink-faint); letter-spacing: .3px; }
.xs-ve {
  appearance: none; -webkit-appearance: none;
  background: none; border: 0; outline: 0; cursor: pointer;
  font: inherit; font-size: 12px; line-height: 1; color: var(--ink);
  padding: 6px 0; margin: 0;
}
.xs-ve-caret { font-size: 9px; color: var(--ink-faint); pointer-events: none; }

/* --- the horizontal slicer ------------------------------------------------ */

/* Pinned to the foot of the stage rather than put in the panel: what it moves
   is on the block, and a control you cannot watch while you drag it is not a
   control, it is a guess. */
.slice-bar {
  position: absolute; z-index: 6;
  left: calc(10px + env(safe-area-inset-left));
  right: calc(10px + env(safe-area-inset-right));
  bottom: calc(8px + env(safe-area-inset-bottom));
  padding: 8px 12px 10px;
  border-radius: var(--radius);
  background: var(--glass-2);
  border: 1px solid var(--line);
  backdrop-filter: blur(6px);
}
.slice-bar.hidden { display: none; }
/* The two things that also live down here move up out of its way. */
.block-pane.has-slice .scale-chip { bottom: calc(98px + env(safe-area-inset-bottom)); }
.block-pane.has-slice .readout { bottom: 102px; }

.slice-top { display: flex; align-items: baseline; gap: 8px; }
.slice-read { flex: 1 1 auto; min-width: 0; font-size: 12.5px; color: var(--ink-dim); }
.slice-read strong {
  color: var(--accent); font-size: 14px; font-variant-numeric: tabular-nums;
}
.slice-close {
  flex: 0 0 auto; width: 30px; height: 26px; margin: -4px -6px 0 0;
  background: none; border: 0; color: var(--ink-dim);
  font-size: 22px; line-height: 1; cursor: pointer;
}

.slice-row { display: flex; align-items: center; gap: 6px; margin-top: 4px; }
.slice-step {
  flex: 0 0 auto; width: 32px; height: 30px;
  border-radius: 8px; border: 1px solid var(--line);
  background: var(--bg-2); color: var(--ink-dim);
  font-size: 11px; line-height: 1; cursor: pointer;
}
.slice-step:active { background: var(--bg-3); color: var(--ink); }

.slice-track { flex: 1 1 auto; min-width: 0; position: relative; padding-bottom: 7px; }
/* The stops, as a ruler beneath the track rather than marks on it. On the
   track they would be lost the moment the accent fill or the thumb passed over
   them, which is exactly when a student is looking for the next one. Inset by
   half a thumb at each end, the way the fill is, so a tick lines up with the
   knob that lands on it. */
.slice-ticks {
  position: absolute; left: 11px; right: 11px; bottom: 0;
  height: 7px; pointer-events: none;
}
.slice-tick {
  position: absolute; top: 0; width: 2px; height: 7px; margin-left: -1px;
  border-radius: 1px; background: var(--ink-faint);
}
.slice-tick.on { background: var(--accent); height: 7px; }
.slice-range { width: 100%; }


/* --- the time machine ----------------------------------------------------- */

.time-machine {
  margin: 4px 0 14px; padding: 11px 12px 9px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--bg-2);
}
.time-head { display: flex; align-items: baseline; gap: 9px; }
.time-head .ctl-label { flex: 0 0 auto; }
.time-read {
  flex: 1 1 auto; min-width: 0; text-align: right;
  font-size: 12.5px; color: var(--ink-dim);
}
.time-read strong { color: var(--accent); font-weight: 650; }

.time-row { display: flex; align-items: center; gap: 9px; margin-top: 2px; }
.time-play {
  flex: 0 0 auto; width: 34px; height: 30px;
  border-radius: 8px; border: 1px solid var(--line);
  background: var(--bg-3); color: var(--ink-dim);
  font-size: 11px; line-height: 1; cursor: pointer;
}
.time-play.on { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.time-range { flex: 1 1 auto; min-width: 0; }

/* The units an unconformity has not laid down yet. Only present while the
   slider is behind one, which is when it is the whole point. */
.time-pending {
  margin-top: 5px; font-size: 12px; color: var(--measured);
}
.time-pending:empty { display: none; }

/* An event on the list but not yet in the block. Struck through would say
   "disabled", which is a different thing and already spoken for. */
.event-row.ahead .event-head { opacity: .38; }
.event-row.ahead .event-icon { filter: grayscale(1); }

/* The one sign a rewound block gives on the block itself. Same shape as the
   map chip because it does the same job: naming a state you can enter without
   noticing, and offering the way out. */
.time-chip {
  display: flex; align-items: center; gap: 6px;
  height: var(--tap); padding: 0 12px;
  border-radius: 999px; border: 1px solid var(--accent);
  background: var(--accent-tint); color: var(--accent);
  font: inherit; font-size: 12.5px; font-weight: 650; cursor: pointer;
  white-space: nowrap;
}
.time-chip.hidden { display: none; }
.time-chip .chip-x { font-size: 17px; line-height: 1; opacity: .8; }
