/* ============================================================================
   Cairn — v2 interface overlay.

   ADDITIVE ONLY. Load AFTER theme.css:
       <link rel="stylesheet" href="theme.css">
       <link rel="stylesheet" href="theme-v2.css">

   Nothing here changes a colour token. The palette in theme.css was contrast
   verified on 6 Jul 2026 and is reused untouched. This file adds:
     - a named type scale (the app currently sets ~14 ad-hoc inline sizes)
     - tabular figures on numeric readouts
     - a stronger focus ring that survives on dark panels
     - one status-pill vocabulary
     - the v2 sign-in layout
     - the v2 project card / filter styling
     - the v2 data-tree and measurement styling for the viewer

   Deleting this file and its <link> restores the current appearance exactly.
   ============================================================================ */

:root{
  /* type scale — named, so density stays consistent across pages */
  --fs-micro:10.5px; --fs-tiny:11px; --fs-small:11.5px; --fs-cap:12px;
  --fs-body:13px; --fs-md:15px; --fs-lg:19px; --fs-xl:26px;
  --track-label:.07em;
  /* two-tone focus ring: an inner ring in the page colour separates the outer
     accent ring from the control, so it stays visible on every panel shade.
     The existing 2px outline disappears against --bg-elev2. */
  --focus:0 0 0 2px var(--bg-app),0 0 0 4px var(--accent);
  --warning-soft:rgba(201,156,76,0.13); --info-soft:rgba(123,163,189,0.13);
}
[data-theme="light"]{
  --warning-soft:rgba(124,89,21,0.12); --info-soft:rgba(55,100,134,0.12);
}

/* Every number in this product is a measurement. Tabular figures stop
   coordinate readouts and counts reflowing as digits change, which is the
   cheapest precision cue available. */
.mono,.num,.v,.val,.ms-value,.statusbar .v,.point-coordinate-value,
.pcard .kv .v,.titem .val,dl.kv dd{
  font-variant-numeric:tabular-nums;
  font-feature-settings:"tnum" 1,"zero" 1;
}

:focus-visible{outline:none;box-shadow:var(--focus);border-radius:var(--r2);}

.label-cap{font-size:var(--fs-micro);letter-spacing:var(--track-label);
  text-transform:uppercase;color:var(--text-3);font-weight:600;}

/* NEW — the square grid backdrop used on sign-in and the projects header. */
.gridbg{position:relative;}
.gridbg::before{content:"";position:absolute;inset:0;pointer-events:none;z-index:0;
  background-image:linear-gradient(var(--border-soft) 1px,transparent 1px),
                   linear-gradient(90deg,var(--border-soft) 1px,transparent 1px);
  background-size:44px 44px;opacity:.55;
  mask-image:radial-gradient(130% 100% at 28% 26%,#000 18%,transparent 76%);
  -webkit-mask-image:radial-gradient(130% 100% at 28% 26%,#000 18%,transparent 76%);}
.gridbg>*{position:relative;z-index:1;}

/* NEW — one status vocabulary, used identically on every page. */
.pill{display:inline-flex;align-items:center;gap:6px;height:21px;padding:0 8px;
  border-radius:999px;font-size:var(--fs-tiny);font-weight:600;white-space:nowrap;
  border:1px solid transparent;}
.pill .dot{width:6px;height:6px;border-radius:50%;background:currentColor;flex:none;}
.pill .dot.pulse{animation:cairn-pulse 1.6s ease-in-out infinite;}
.pill-ok{background:var(--success-soft);color:var(--success);
  border-color:color-mix(in srgb,var(--success) 35%,transparent);}
.pill-warn{background:var(--warning-soft);color:var(--warning);
  border-color:color-mix(in srgb,var(--warning) 38%,transparent);}
.pill-err{background:var(--danger-soft);color:var(--danger);
  border-color:color-mix(in srgb,var(--danger) 38%,transparent);}
.pill-info{background:var(--info-soft);color:var(--info);
  border-color:color-mix(in srgb,var(--info) 35%,transparent);}
.pill-idle{background:var(--bg-elev);color:var(--text-3);border-color:var(--border);}
@keyframes cairn-pulse{0%,100%{opacity:1}50%{opacity:.35}}
@keyframes cairn-shimmer{0%{background-position:-380px 0}100%{background-position:380px 0}}
@media (prefers-reduced-motion:reduce){
  .pill .dot.pulse,.sk{animation:none!important;}
}

/* ============================ SIGN IN ==================================== */
body.v2-login{display:grid;grid-template-columns:minmax(0,1fr) minmax(410px,460px);
  height:100%;overflow-y:auto;align-items:stretch;justify-content:stretch;}
.lg-left{background:var(--bg-app);border-right:1px solid var(--border);
  padding:40px 44px;display:flex;flex-direction:column;overflow:hidden;}
.lg-logo{display:flex;align-items:center;gap:13px;}
.lg-logo img{height:34px;width:auto;max-width:210px;object-fit:contain;object-position:left center;}
.lg-tag{margin-top:26px;font-size:var(--fs-md);color:var(--text-2);letter-spacing:.005em;}
.lg-tag b{color:var(--text-1);font-weight:600;}
.lg-copy{margin-top:auto;padding-top:40px;display:flex;flex-direction:column;gap:20px;max-width:56ch;}
.lg-copy section{border-left:2px solid var(--border-strong);padding-left:14px;}
.lg-copy h2{margin:0 0 5px;font-size:var(--fs-micro);letter-spacing:var(--track-label);
  text-transform:uppercase;color:var(--accent);font-weight:600;}
.lg-copy p{margin:0;font-size:var(--fs-cap);line-height:1.6;color:var(--text-2);}
.lg-foot{margin-top:34px;padding-top:18px;border-top:1px solid var(--border-soft);
  display:flex;flex-wrap:wrap;align-items:center;gap:16px;font-size:var(--fs-tiny);color:var(--text-3);}
.lg-foot .ver{font-family:var(--font-mono);font-variant-numeric:tabular-nums;}
.lg-foot a{color:var(--text-2);text-decoration:none;border-bottom:1px solid var(--border-strong);padding-bottom:1px;}
.lg-foot a:hover{color:var(--accent);border-color:var(--accent);}

.lg-right{background:var(--bg-chrome);display:flex;flex-direction:column;
  justify-content:center;padding:40px 48px;overflow-y:auto;}
.lg-card{width:100%;max-width:360px;margin:0 auto;}
.lg-h{font-size:var(--fs-lg);font-weight:600;letter-spacing:-.015em;margin:0 0 6px;}
.lg-sub{font-size:var(--fs-cap);color:var(--text-2);line-height:1.55;margin:0 0 22px;}
.fgroup{margin-bottom:14px;}
.fgroup label{display:flex;align-items:baseline;justify-content:space-between;gap:10px;
  margin-bottom:6px;font-size:var(--fs-cap);font-weight:500;color:var(--text-2);}
.fgroup .hint{font-size:var(--fs-tiny);color:var(--text-3);font-weight:400;}
.fgroup input{width:100%;height:38px;background:var(--bg-elev);border:1px solid var(--border);
  border-radius:var(--r2);color:var(--text-1);padding:0 12px;outline:none;font-size:var(--fs-body);
  transition:border-color .12s,box-shadow .12s;}
.fgroup input:focus{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft);}
.fgroup input::placeholder{color:var(--text-3);}
.pw-wrap{position:relative;}
.pw-wrap input{padding-right:44px;}
.pw-reveal{position:absolute;right:4px;top:4px;width:30px;height:30px;border:none;
  border-radius:var(--r2);background:transparent;color:var(--text-3);cursor:pointer;
  display:flex;align-items:center;justify-content:center;}
.pw-reveal:hover{color:var(--text-1);background:var(--bg-hover);}
.lg-alert{display:flex;gap:10px;align-items:flex-start;border-radius:var(--r3);
  padding:11px 13px;font-size:var(--fs-cap);line-height:1.5;margin-bottom:16px;border:1px solid;}
.lg-alert svg{flex:none;margin-top:1px;}
.lg-alert .t{color:var(--text-1);font-weight:600;display:block;margin-bottom:2px;}
.alert-err{background:var(--danger-soft);border-color:color-mix(in srgb,var(--danger) 40%,transparent);color:var(--text-1);}
.alert-err svg{color:var(--danger);}
.alert-warn{background:var(--warning-soft);border-color:color-mix(in srgb,var(--warning) 40%,transparent);color:var(--text-1);}
.alert-warn svg{color:var(--warning);}
.alert-info{background:var(--info-soft);border-color:color-mix(in srgb,var(--info) 35%,transparent);color:var(--text-2);}
.alert-info svg{color:var(--info);}
.lg-actions{display:flex;flex-direction:column;gap:10px;margin-top:20px;}
.lg-actions button{height:40px;border:1px solid transparent;border-radius:var(--r2);
  background:var(--accent);color:var(--accent-fg);font-size:var(--fs-body);font-weight:600;cursor:pointer;}
.lg-actions button:hover{background:var(--accent-hover);}
.lg-actions button:disabled{opacity:.55;cursor:wait;}
.lg-links{display:flex;justify-content:space-between;align-items:center;gap:12px;
  margin-top:16px;font-size:var(--fs-small);}
.linkbtn{background:none;border:none;padding:0;color:var(--accent);
  font-size:var(--fs-small);font-weight:500;cursor:pointer;text-align:left;}
.linkbtn:hover{text-decoration:underline;}
@media (max-width:1000px){
  body.v2-login{grid-template-columns:1fr;}
  .lg-left{border-right:none;border-bottom:1px solid var(--border);padding:28px 24px;}
  .lg-copy{padding-top:26px;}
  .lg-right{padding:28px 24px 56px;}
}

/* ============================== DASHBOARD ================================
   The project rows are generated by src/dash/project-list.ts and carry inline
   font sizes, so this section deliberately does NOT fight them with
   !important. It improves the frame around the rows: spacing, hover, the
   thumbnail, the status badge and the column headings. Changing the columns
   themselves needs project-list.ts edited and the bundle rebuilt.
   ======================================================================== */
.v2-dash .dash-head{height:64px;}
.v2-dash .project-page-title>div:first-child{font-size:var(--fs-md);letter-spacing:-.012em;}
.v2-dash .th{font-size:var(--fs-micro);letter-spacing:var(--track-label);padding:10px 18px;}
.v2-dash .tbl{border-radius:var(--r4);overflow:hidden;}
.v2-dash .tr:not(.th){padding:13px 18px;transition:background .1s,box-shadow .1s;}
.v2-dash .tr:not(.th):hover{background:var(--bg-hover);}
.v2-dash .tr:not(.th):focus-visible{box-shadow:inset 0 0 0 2px var(--accent);}
.v2-dash .thumb{width:78px;height:50px;border-radius:var(--r2);}
/* the generated status chip: give it the same pill vocabulary as everywhere else */
.v2-dash .badge{height:21px;padding:0 9px;border:1px solid transparent;border-radius:999px;
  font-size:var(--fs-tiny);letter-spacing:.01em;}
.v2-dash .badge-ready{border-color:color-mix(in srgb,var(--success) 35%,transparent);}
.v2-dash .badge-error{border-color:color-mix(in srgb,var(--danger) 38%,transparent);}
.v2-dash .prog{height:4px;}
.v2-dash .dropzone{border-radius:var(--r4);}
.v2-dash .chip{font-size:var(--fs-micro);letter-spacing:.02em;}
/* filter segment reads as filter chips rather than a tab strip */
.v2-dash #filter button{height:27px;padding:0 12px;border-radius:999px;font-size:var(--fs-small);}
.v2-dash #filter{background:transparent;border:none;padding:0;gap:6px;}
.v2-dash #filter button[aria-pressed="true"]{background:var(--bg-active);
  color:var(--accent);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--accent) 45%,transparent);}
.v2-dash #filter button[aria-pressed="false"]{box-shadow:inset 0 0 0 1px var(--border);}
/* map pane */
.v2-dash #map-body.project-map #map{border-radius:var(--r4);}
.v2-dash #map-body .map-caption{font-size:var(--fs-micro);line-height:1.5;}

/* --------------------------------------------------------------------------
   TEMPORARY dark basemap (brief 2 item 4, 29 Jul 2026).

   Standard OSM raster tiles are light and fight the dark chrome. Protomaps —
   the real fix, a self-hosted vector basemap with a dark flavour tuned to
   these tokens — is blocked on download approval (CHANGE-CHECKLIST §E.5), so
   this filters the raster tiles in place. No new dependency, no network call.

   REPLACE THIS when the .pmtiles basemap lands: the dark flavour then comes
   from the map style itself and this whole block should be deleted, along
   with nothing else — the .tile-layer element it targets is still the right
   place for tiles.

   Scoped to the dark theme only. In the light theme the tiles already suit
   the chrome, and inverting them there would produce a dark map on a light
   page, which is the exact problem this is meant to solve, upside down.

   Applied to .tile-layer, NOT the pan layer: project markers are siblings of
   this element (see src/dash/map.ts), so they keep their true colours. Invert
   plus a 180deg hue rotation is what keeps land/water plausible rather than
   photo-negative; the brightness/contrast/saturate trim stops the result
   glaring against --bg-panel.
   -------------------------------------------------------------------------- */
[data-theme="dark"] .v2-dash #map .tile-layer{
  filter:invert(1) hue-rotate(180deg) brightness(.86) contrast(1.08) saturate(.55);
}
/* empty state */
.v2-dash .empty{border-style:dashed;}
.v2-dash .empty .ic{width:64px;height:64px;}

/* =============================== VIEWER ==================================
   The docked panel keeps its existing behaviour: the .handle collapse, the
   #scan-resize-handle drag, #dock-left rail-only mode and the floating trays
   are all untouched. This section restyles the group headings, the counts and
   the measurement warning only.
   ======================================================================== */
/* Group headings follow the reference's .thead: sentence case, not the
   uppercase tracking the panel used to carry. The label reads as a name
   ("Scan stations"), the count as data beside it. */
.v2-viewer .pcollapse{font-size:var(--fs-small);letter-spacing:.02em;padding:7px 8px;
  font-weight:600;text-transform:none;color:var(--text-2);}
.v2-viewer .pgroup{border-bottom:none;}
.v2-viewer .pbody{padding-left:8px;}
/* Counts sit plain at the right, as in the reference — the pill treatment
   read as a badge and fought the row it belonged to. */
.v2-count{margin-left:auto;font-family:var(--font-mono);font-variant-numeric:tabular-nums;
  font-size:var(--fs-micro);color:var(--text-3);padding-left:8px;}
.v2-count.warn{color:var(--warning);}
.v2-count.err{color:var(--danger);}
.v2-viewer .pcollapse:hover .v2-count{color:var(--text-2);}

/* (The Section/Measure/Colour/Views rail captions the reference shows were
   built and then removed at John's request — the icons and their tooltips
   carry it, and the words crowded a 46px rail.) */

/* Panel title. The docked panel had no heading at all, so nothing named what
   the tree was. Matches the reference's .dock-hd. */
.v2-viewer .dock-hd{height:36px;flex:none;display:flex;align-items:center;gap:8px;
  padding:0 12px;border-bottom:1px solid var(--border);position:sticky;top:0;
  background:var(--bg-panel);z-index:2;}
.v2-viewer .dock-hd .label{flex:1;font-size:var(--fs-micro);
  letter-spacing:var(--track-label);text-transform:uppercase;color:var(--text-3);font-weight:600;}
.v2-viewer .sec-label{font-size:var(--fs-micro);letter-spacing:var(--track-label);}

/* Measurement warning. Same element, same id, same text written by the
   bundle — restyled into the standing warning treatment used elsewhere.
   theme.css already gives it a border and tint; this adds the accent edge,
   the heading weight and readable line length. */
.v2-viewer #measure-warning{
  border-left:3px solid var(--warning)!important;
  border-radius:var(--r2)!important;
  padding:10px 11px!important;
  font-size:var(--fs-small)!important;
  line-height:1.5!important;
  color:var(--text-2)!important;
}
.v2-viewer .client-measure-note{
  border:1px solid color-mix(in srgb,var(--warning) 34%,transparent);
  border-left:3px solid var(--warning);
  background:var(--warning-soft);
  border-radius:var(--r2);padding:9px 10px;font-size:var(--fs-small);line-height:1.5;
}
/* measurement rows: tabular figures and a calmer value colour ramp */
.v2-viewer .ms{padding:8px;border-radius:var(--r2);}
.v2-viewer .ms-value,.v2-viewer .point-coordinate-value .coord-number{
  font-variant-numeric:tabular-nums;}
.v2-viewer .pl-tool{font-size:var(--fs-small);border-radius:var(--r2);}
/* status bar: tabular figures stop the coordinate readout jittering */
.v2-viewer .statusbar{font-size:var(--fs-tiny);}
.v2-viewer .statusbar .v{font-variant-numeric:tabular-nums;}
/* keycaps already look right; just tighten the type */
.v2-viewer .keycap{font-size:var(--fs-tiny);}
