/* ============================================================ NeatureBase
   Two rooms, one house:
   App A (Catalogue)  — archival paper, ink, verdigris
   App B (Portfolio)  — darkroom charcoal, silver text, verdigris glow
   ============================================================ */

@font-face { font-family: 'Bricolage Grotesque'; font-weight: 400; font-display: swap; src: url('/vendor/fonts/bricolage-400.woff2') format('woff2'); }
@font-face { font-family: 'Bricolage Grotesque'; font-weight: 600; font-display: swap; src: url('/vendor/fonts/bricolage-600.woff2') format('woff2'); }
@font-face { font-family: 'Bricolage Grotesque'; font-weight: 700; font-display: swap; src: url('/vendor/fonts/bricolage-700.woff2') format('woff2'); }
@font-face { font-family: 'Bricolage Grotesque'; font-weight: 800; font-display: swap; src: url('/vendor/fonts/bricolage-800.woff2') format('woff2'); }
@font-face { font-family: 'Instrument Sans'; font-weight: 400; font-display: swap; src: url('/vendor/fonts/instrument-400.woff2') format('woff2'); }
@font-face { font-family: 'Instrument Sans'; font-weight: 500; font-display: swap; src: url('/vendor/fonts/instrument-500.woff2') format('woff2'); }
@font-face { font-family: 'Instrument Sans'; font-weight: 700; font-display: swap; src: url('/vendor/fonts/instrument-700.woff2') format('woff2'); }
@font-face { font-family: 'IBM Plex Mono'; font-weight: 400; font-display: swap; src: url('/vendor/fonts/plexmono-400.woff2') format('woff2'); }
@font-face { font-family: 'IBM Plex Mono'; font-weight: 600; font-display: swap; src: url('/vendor/fonts/plexmono-600.woff2') format('woff2'); }

:root {
  --font-display: 'Bricolage Grotesque', system-ui, sans-serif;
  --font-body: 'Instrument Sans', system-ui, sans-serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, monospace;

  /* App A: paper + ink */
  --paper: #F7F6F2;
  --paper-2: #EFEDE6;
  --card: #FFFFFF;
  --ink: #1C2127;
  --ink-2: #4A5058;
  --ink-3: #7C8289;
  --hair: #D9D6CC;
  --hair-2: #E7E4DB;
  --accent: #257D69;
  --accent-ink: #FFFFFF;
  --accent-soft: #DFEDE8;
  --amber: #C98A2B;
  --amber-soft: #F5E9D4;
  --danger: #B4483C;
  --danger-soft: #F4E0DD;
  --shadow: 0 1px 2px rgba(28,33,39,.06), 0 6px 24px -12px rgba(28,33,39,.18);
  --shadow-lift: 0 2px 6px rgba(28,33,39,.10), 0 18px 44px -18px rgba(28,33,39,.28);
  --radius: 10px;
  --radius-sm: 6px;
  --wrap: 1320px;
}

body[data-app="b"] {
  --paper: #14161A;
  --paper-2: #1B1E24;
  --card: #1E2229;
  --ink: #ECEDEA;
  --ink-2: #B4B8BC;
  --ink-3: #7E848B;
  --hair: #2A2E36;
  --hair-2: #23272E;
  --accent: #3EA98F;
  --accent-ink: #0E1410;
  --accent-soft: #1D3A33;
  --amber: #D99C43;
  --amber-soft: #3A2E17;
  --danger: #D2685C;
  --danger-soft: #3B221F;
  --shadow: 0 1px 2px rgba(0,0,0,.4), 0 8px 28px -14px rgba(0,0,0,.7);
  --shadow-lift: 0 2px 8px rgba(0,0,0,.5), 0 22px 52px -20px rgba(0,0,0,.8);
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0; background: var(--paper); color: var(--ink);
  font-family: var(--font-body); font-size: 15px; line-height: 1.55;
  transition: background .35s ease, color .35s ease;
}
body[data-app="a"] {
  background-image: radial-gradient(rgba(28,33,39,.028) 1px, transparent 1px);
  background-size: 22px 22px;
}
h1,h2,h3,h4 { font-family: var(--font-display); line-height: 1.12; margin: 0 0 .4em; letter-spacing: -0.015em; }
h1 { font-size: clamp(26px, 4vw, 40px); font-weight: 800; }
h2 { font-size: clamp(20px, 2.6vw, 26px); font-weight: 700; }
h3 { font-size: 17px; font-weight: 700; }
p { margin: 0 0 .8em; }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 2px; }
code, .mono { font-family: var(--font-mono); font-size: .92em; }
::selection { background: var(--accent); color: var(--accent-ink); }
button { font: inherit; }
input, select, textarea { font: inherit; color: inherit; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 3px; }

.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 clamp(14px, 3vw, 32px); }
.muted { color: var(--ink-3); }
.small { font-size: 13px; }
.hidden { display: none !important; }
.right { margin-left: auto; }
.row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.stack { display: flex; flex-direction: column; gap: 10px; }
hr.hair { border: 0; border-top: 1px solid var(--hair); margin: 18px 0; }

/* ------------------------------------------------------------ header ----- */
.topbar {
  position: sticky; top: 0; z-index: 60;
  background: color-mix(in srgb, var(--paper) 86%, transparent);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--hair);
}
.topbar-inner { display: flex; align-items: center; gap: 18px; height: 58px; }
.brand { display: flex; align-items: center; gap: 10px; font-family: var(--font-display); font-weight: 800; font-size: 19px; color: var(--ink); letter-spacing: -0.02em; }
.brand:hover { text-decoration: none; }
.brand .mark {
  width: 26px; height: 26px; border-radius: 7px; flex: none;
  background: linear-gradient(135deg, var(--accent), color-mix(in srgb, var(--accent) 55%, var(--ink)));
  display: grid; place-items: center; color: #fff; font-size: 13px; font-weight: 800;
}
/* a logo of your own: shown whole, at whatever shape it happens to be */
.brand img.mark.logo { width: auto; max-width: 132px; height: 30px; background: none; border-radius: 0; object-fit: contain; }
.topnav { display: flex; gap: 2px; align-items: center; }
.topnav a {
  padding: 7px 12px; border-radius: 8px; color: var(--ink-2); font-weight: 500; font-size: 14px;
}
.topnav a:hover { background: var(--paper-2); color: var(--ink); text-decoration: none; }
.topnav a.active { color: var(--ink); background: var(--paper-2); }

/* the little app-side switch */
.appside { display:flex; border:1px solid var(--hair); border-radius: 999px; overflow:hidden; font-size:12.5px; }
.appside a { padding: 5px 12px; color: var(--ink-3); font-weight:600; }
.appside a.active { background: var(--ink); color: var(--paper); }
.appside a:hover { text-decoration:none; }

/* ------------------------------------------------------------ buttons ---- */
.btn {
  display: inline-flex; align-items: center; gap: 7px; cursor: pointer; user-select: none;
  border: 1px solid var(--hair); background: var(--card); color: var(--ink);
  padding: 7px 14px; border-radius: var(--radius-sm); font-weight: 600; font-size: 14px;
  transition: transform .06s ease, box-shadow .15s ease, background .15s ease;
}
.btn:hover { box-shadow: var(--shadow); }
.btn:active { transform: translateY(1px); }
.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.btn.primary:hover { background: color-mix(in srgb, var(--accent) 88%, var(--ink)); }
.btn.ghost { background: transparent; border-color: transparent; color: var(--ink-2); }
.btn.ghost:hover { background: var(--paper-2); box-shadow: none; color: var(--ink); }
.btn.danger { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 40%, var(--hair)); }
.btn.danger:hover { background: var(--danger-soft); }
.btn.small { padding: 4px 10px; font-size: 13px; }
.btn.icon { padding: 7px 9px; }
.btn[disabled] { opacity: .5; pointer-events: none; }

/* --------------------------------------------------------- specimen tag --- */
/* The signature element: item / label codes rendered as little archive tags */
.tag-id {
  font-family: var(--font-mono); font-weight: 600; font-size: 12.5px; letter-spacing: .04em;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 2px 9px 2px 7px; border: 1px solid var(--hair); border-radius: 4px;
  background: var(--card); color: var(--ink); position: relative; white-space: nowrap;
}
.tag-id::before { content: ''; width: 5px; height: 5px; border-radius: 50%; background: var(--accent); flex: none; }
.tag-id.tentative::before { background: var(--amber); }
.tag-id.plain::before { background: var(--ink-3); }
a.tag-id:hover { text-decoration: none; border-color: var(--accent); box-shadow: var(--shadow); }

.chip {
  display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; font-weight: 600;
  padding: 3px 10px; border-radius: 999px; border: 1px solid var(--hair);
  background: var(--card); color: var(--ink-2); cursor: pointer; user-select: none;
}
.chip:hover { border-color: var(--accent); color: var(--ink); }
.chip.on { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.chip .n { opacity: .65; font-weight: 500; }
.chip.amber { background: var(--amber-soft); border-color: transparent; color: var(--ink); }
/* a chip with its own clear button: the ✕ does what it looks like it does */
.chip.withx { padding: 0 4px 0 0; gap: 0; }
.chip.withx .cx-main { border: 0; background: none; color: inherit; font: inherit; font-weight: 600; cursor: pointer; padding: 3px 6px 3px 10px; border-radius: 999px; }
.chip.withx .cx-off { border: 0; background: none; color: inherit; font: inherit; cursor: pointer; padding: 2px 6px; border-radius: 999px; opacity: .75; line-height: 1; }
.chip.withx .cx-off:hover { opacity: 1; background: rgba(255,255,255,.22); }

.pill-status { font-size: 11.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .07em; padding: 2px 8px; border-radius: 4px; }
.pill-status.confirmed { background: var(--accent-soft); color: var(--accent); }
.pill-status.tentative { background: var(--amber-soft); color: var(--amber); }
.pill-status.unlabelled { background: var(--paper-2); color: var(--ink-3); }

/* ------------------------------------------------------------- cards ----- */
.card { background: var(--card); border: 1px solid var(--hair); border-radius: var(--radius); box-shadow: var(--shadow); }
.card.pad { padding: 18px; }

/* landing tiles */
.tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 16px; }
.tile {
  display: flex; flex-direction: column; border-radius: var(--radius); overflow: hidden;
  background: var(--card); border: 1px solid var(--hair); color: var(--ink);
  transition: transform .16s ease, box-shadow .16s ease;
}
.tile:hover { transform: translateY(-3px); box-shadow: var(--shadow-lift); text-decoration: none; }
.tile .cover { aspect-ratio: 8/5; background: var(--paper-2); position: relative; overflow: hidden; }
.tile .cover img { width: 100%; height: 100%; object-fit: cover; display: block; }
.tile .cover .ph { position:absolute; inset:0; display:grid; place-items:center; color: var(--ink-3); font-family: var(--font-display); font-size: 34px; font-weight: 800; opacity:.5; }
.tile .meta { padding: 13px 15px 15px; display:flex; flex-direction: column; gap: 3px; }
.tile .meta h3 { margin: 0; }
.tile .kicker { font-size: 11px; text-transform: uppercase; letter-spacing: .1em; color: var(--accent); font-weight: 700; }

/* ------------------------------------------------------------- forms ----- */
label.f { display: flex; flex-direction: column; gap: 5px; font-size: 13px; font-weight: 600; color: var(--ink-2); }
input.f, select.f, textarea.f, label.f input, label.f select, label.f textarea {
  width: 100%; padding: 8px 11px; border: 1px solid var(--hair); border-radius: var(--radius-sm);
  background: var(--card); color: var(--ink); font-size: 14px; font-weight: 400;
}
label.f input:focus, label.f select:focus, label.f textarea:focus, input.f:focus, select.f:focus, textarea.f:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
textarea.f, label.f textarea { min-height: 84px; resize: vertical; }
.f-inline { display:flex; gap:10px; }
.f-inline > * { flex: 1; }
.check { display:flex; gap:8px; align-items:center; font-size:14px; cursor:pointer; }
.check input { width: 16px; height: 16px; accent-color: var(--accent); }

/* editable value (edit-mode inline editing) */
.ev { border-bottom: 1px dashed transparent; border-radius: 3px; }
body.editing .ev { border-bottom-color: var(--hair); cursor: text; }
body.editing .ev:hover { background: var(--accent-soft); border-bottom-color: var(--accent); }
.ev:focus { outline: none; background: var(--accent-soft); border-bottom-color: var(--accent); }

/* edit-mode master switch */
.editswitch { display:flex; align-items:center; gap:8px; font-size:13px; font-weight:600; color: var(--ink-2); cursor:pointer; }
.editswitch .track { width: 34px; height: 19px; border-radius: 999px; background: var(--hair); position: relative; transition: background .18s; flex:none; }
.editswitch .track::after { content:''; position:absolute; top:2px; left:2px; width:15px; height:15px; border-radius:50%; background:#fff; box-shadow: 0 1px 2px rgba(0,0,0,.3); transition: left .18s; }
body.editing .editswitch .track { background: var(--amber); }
body.editing .editswitch .track::after { left: 17px; }
body.editing .topbar { box-shadow: inset 0 -2px 0 var(--amber); }

/* ------------------------------------------------------------ toolbar ---- */
.toolbar { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin: 14px 0; }
.search {
  flex: 1 1 260px; max-width: 460px; display: flex; align-items: center; gap: 8px;
  border: 1px solid var(--hair); border-radius: 999px; background: var(--card); padding: 7px 14px;
}
.search input { border: 0; outline: none; background: transparent; flex: 1; font-size: 14px; color: var(--ink); }
.search svg { flex: none; color: var(--ink-3); }

.tabbar { display: inline-flex; background: var(--paper-2); border: 1px solid var(--hair); border-radius: 8px; padding: 3px; gap: 2px; }
.tabbar button { border: 0; background: transparent; padding: 5px 14px; border-radius: 6px; font-weight: 600; font-size: 13.5px; color: var(--ink-2); cursor: pointer; }
.tabbar button.on { background: var(--card); color: var(--ink); box-shadow: var(--shadow); }

.facets { display: flex; gap: 14px; flex-wrap: wrap; padding: 10px 0 2px; }
/* The filters fold away — on a phone because eight groups of chips is most of
   the screen before a single record is visible, and on a desktop because
   sometimes you have set the filter you wanted and would rather look at the
   records. Which way it sits is remembered per browser. */
details.facets-fold { margin: 4px 0 2px; }
details.facets-fold > summary {
  list-style: none; cursor: pointer; display: inline-flex; align-items: center; gap: 8px;
  font-size: 12.5px; font-weight: 700; color: var(--ink-3); width: fit-content;
  padding: 4px 2px; border-radius: 20px;
}
details.facets-fold > summary:hover { color: var(--accent); }
details.facets-fold > summary::-webkit-details-marker { display: none; }
details.facets-fold > summary::after { content: '▾'; font-size: 11px; }
details.facets-fold[open] > summary::after { content: '▴'; }
details.facets-fold .fcount {
  background: var(--accent); color: #fff; border-radius: 20px; padding: 0 7px; font-size: 11px; font-weight: 700;
}
details.facets-fold .facets { padding-top: 4px; }
.facet-group { display: flex; gap: 6px; align-items: baseline; flex-wrap: wrap; }
.facet-group .fname { font-size: 11.5px; text-transform: uppercase; letter-spacing: .08em; color: var(--ink-3); font-weight: 700; margin-right: 2px; }

/* ------------------------------------------------------------- table ----- */
/* When the table is wider than the window there is more to the right, and a
   hard edge reads as "cut off" rather than "scroll". A soft fade says which
   it is, and disappears when there is nothing more to see. */
.tablewrap {
  overflow-x: auto; border: 1px solid var(--hair); border-radius: var(--radius);
  background: var(--card); box-shadow: var(--shadow);
  background-image: linear-gradient(to right, transparent calc(100% - 44px), rgba(0,0,0,.055));
  background-repeat: no-repeat; background-attachment: local, scroll;
}
.tablewrap:not(.scrolls) { background-image: none; }
table.grid { border-collapse: collapse; width: 100%; font-size: 13.5px; }
table.grid th, table.grid td { padding: 9px 12px; text-align: left; border-bottom: 1px solid var(--hair-2); vertical-align: top; }
/* A long unbroken run — a URL, a station code, a filename — used to widen its
   column past the table rather than wrap, which is what put the rightmost
   column's text over the edge. It wraps now, wherever it has to. */
table.grid td { overflow-wrap: anywhere; }
/* and the last column always finishes where the table does */
table.grid th:last-child, table.grid td:last-child { padding-right: 14px; }
table.grid th {
  font-size: 11.5px; text-transform: uppercase; letter-spacing: .07em; color: var(--ink-3);
  position: sticky; top: 0; background: var(--card); z-index: 2; cursor: pointer; user-select: none;
  /* a narrowed column wraps its heading over two lines rather than clipping it */
  white-space: normal; overflow-wrap: break-word; line-height: 1.25;
}
table.grid th .dir { color: var(--accent); }
table.grid tbody tr:hover { background: color-mix(in srgb, var(--accent) 5%, var(--card)); }
table.grid tbody tr { cursor: pointer; }
/* picking rows: the whole row is the target, and the checkbox column is a
   generous full-height strip rather than a 16px square to hit */
table.grid td.selcol, table.grid th.selcol { padding: 0; text-align: center; vertical-align: middle; }
table.grid td.selcol .rowpick {
  display: flex; align-items: center; justify-content: center;
  width: 100%; height: 100%; min-height: 42px; cursor: pointer;
}
table.grid tr.picking { cursor: pointer; user-select: none; }
table.grid tr.picking:hover td.selcol { background: var(--accent-soft); }
table.grid tr.picking td.selcol { border-right: 1px solid var(--hair-2); }

/* Row thumbnails: large enough to recognise a specimen at a glance, and a
   little wider than tall, because most specimen photographs are lateral. */
table.grid td .thumb-s { width: 74px; height: 50px; object-fit: cover; border-radius: 5px; border: 1px solid var(--hair); display: block; background: var(--paper-2); }
.thumbs-small table.grid td .thumb-s { width: 46px; height: 32px; }
.thumbs-large table.grid td .thumb-s { width: 112px; height: 74px; }
table.grid td:has(.thumb-s) { padding-top: 6px; padding-bottom: 6px; }
/* whole-photo modes: a long specimen is letterboxed rather than cropped, on
   the same background the gallery uses, so nothing is cut off in a list */
body.tiles-fit table.grid td .thumb-s { object-fit: contain; background: var(--paper-2); }
body.tiles-fitblack table.grid td .thumb-s { object-fit: contain; background: #000; border-color: #000; }
table.grid td.num { font-family: var(--font-mono); font-size: 12.5px; }

.pager { display: flex; align-items: center; gap: 12px; padding: 12px 2px; font-size: 13.5px; color: var(--ink-2); }

/* ------------------------------------------------------------ gallery ---- */
.gallery { display: flex; flex-wrap: wrap; gap: 8px; }
.gallery .gi {
  position: relative; flex-grow: 1; height: 208px; border-radius: 8px; overflow: hidden;
  background: var(--paper-2); cursor: pointer; border: 1px solid var(--hair);
}
.gallery .gi img { height: 100%; width: 100%; object-fit: cover; display: block; transition: transform .25s ease; }
.gallery .gi:hover img { transform: scale(1.035); }
.gallery .gi .cap {
  position: absolute; inset: auto 0 0 0; padding: 22px 10px 8px; font-size: 12px; color: #fff;
  background: linear-gradient(transparent, rgba(10,12,14,.72)); opacity: 0; transition: opacity .18s;
  display: flex; align-items: flex-end; gap: 6px;
}
.gallery .gi:hover .cap, .gallery .gi:focus-visible .cap { opacity: 1; }
.gallery .gi .badge { position: absolute; top: 7px; left: 7px; display: flex; gap: 5px; }
.gallery .gi .badge span { background: rgba(10,12,14,.62); color: #fff; font-size: 10.5px; font-weight: 700; padding: 2px 7px; border-radius: 4px; letter-spacing: .05em; backdrop-filter: blur(3px); }
.gallery .gi.sel { outline: 3px solid var(--accent); outline-offset: -3px; }
.gallery .spacer { flex-grow: 10; height: 0; }

/* portfolio hero band (kind=portfolio) */
.hero-b { padding: clamp(30px, 7vw, 84px) 0 clamp(18px, 4vw, 44px); }
.hero-b .kicker { color: var(--accent); font-weight: 700; letter-spacing: .14em; text-transform: uppercase; font-size: 12px; }
.hero-b h1 { max-width: 15ch; }
.hero-b p.lede { max-width: 58ch; color: var(--ink-2); font-size: 16.5px; }

/* ------------------------------------------------------------ lightbox --- */
.lb { position: fixed; inset: 0; z-index: 5000; display: flex; background: rgba(10,12,15,.92); backdrop-filter: blur(6px); }
.lb .stage { flex: 1; display: grid; place-items: center; position: relative; min-width: 0; }
.lb .stage img { max-width: min(96%, 1800px); max-height: 94vh; object-fit: contain; border-radius: 4px; box-shadow: 0 24px 80px rgba(0,0,0,.6); }
.lb .nav { position: absolute; top: 50%; transform: translateY(-50%); background: rgba(20,22,26,.65); color: #fff; border: 0; border-radius: 50%; width: 44px; height: 44px; font-size: 20px; cursor: pointer; display:grid; place-items:center; }
.lb .nav:hover { background: rgba(20,22,26,.9); }
.lb .nav.prev { left: 16px; } .lb .nav.next { right: 16px; }
.lb .close { position: absolute; top: 14px; right: 16px; z-index: 2; }
.lb .info {
  width: min(390px, 92vw); flex: none; background: var(--card); color: var(--ink);
  border-left: 1px solid var(--hair); overflow-y: auto; padding: 20px;
}
.lb .info h3 { margin-bottom: 2px; }
.lb .kv { display: grid; grid-template-columns: 108px 1fr; gap: 6px 12px; font-size: 13.5px; margin: 12px 0; }
.lb .kv dt { color: var(--ink-3); } .lb .kv dd { margin: 0; }
@media (max-width: 860px) { .lb { flex-direction: column; } .lb .info { width: 100%; border-left: 0; border-top: 1px solid var(--hair); max-height: 46vh; } }

/* stars */
.stars { display: inline-flex; gap: 2px; }
.stars button, .stars span.s { background: none; border: 0; padding: 0; cursor: pointer; font-size: 16px; color: var(--hair); line-height: 1; }
.stars .on { color: var(--amber); }
.stars.readonly button { cursor: default; }

.gradepick { display: inline-flex; gap: 4px; }
.gradepick button { width: 28px; height: 24px; border-radius: 5px; border: 1px solid var(--hair); background: var(--card); font-weight: 700; font-size: 12.5px; cursor: pointer; color: var(--ink-3); }
.gradepick button.on { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }

/* ------------------------------------------------------------- map ------- */
.mapbox { height: min(66vh, 640px); border-radius: var(--radius); border: 1px solid var(--hair); overflow: hidden; box-shadow: var(--shadow); background: var(--paper-2); }
.mapbox.small { height: 260px; }
.leaflet-container { background: var(--paper-2); font: inherit; }
body[data-app="b"] .leaflet-container { background: #10151c; }
.map-pop { font-family: var(--font-body); font-size: 13px; display: block; }
.map-pop img { width: 100%; max-width: 210px; aspect-ratio: 4/3; object-fit: cover; border-radius: 6px; display: block; margin-bottom: 7px; background: var(--paper-2); }
.map-pop .mp-id { margin-bottom: 3px; }
.map-pop .mp-name { font-weight: 600; font-size: 13.5px; color: var(--ink); line-height: 1.3; }
.map-pop .mp-meta { color: var(--ink-3); font-size: 12px; line-height: 1.35; }
.map-pop .mp-go { display: inline-block; margin-top: 6px; color: var(--accent); font-weight: 600; font-size: 12.5px; }
a.mp-link { color: inherit; display: block; }
a.mp-link:hover { text-decoration: none; }
a.mp-link:hover .mp-go { text-decoration: underline; text-underline-offset: 2px; }
.leaflet-popup-content { margin: 10px 12px; }
.leaflet-popup-content-wrapper { border-radius: 9px; background: var(--card); color: var(--ink); box-shadow: var(--shadow-lift); }
.leaflet-popup-tip { background: var(--card); }

/* -------------------------------------------------------------- item ----- */
.item-head { display: flex; gap: 18px; align-items: flex-start; flex-wrap: wrap; margin: 20px 0 6px; }
.item-head h1 { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.breadcrumb { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; font-size: 13.5px; }
.breadcrumb a { color: var(--ink-2); }
.breadcrumb .sep { color: var(--ink-3); }
.detail-grid { display: grid; grid-template-columns: minmax(0, 1.5fr) minmax(300px, 1fr); gap: 20px; align-items: start; margin: 16px 0 40px; }
@media (max-width: 940px) { .detail-grid { grid-template-columns: 1fr; } }
.kvlist { display: grid; grid-template-columns: 150px 1fr; gap: 8px 14px; font-size: 14px; }
.kvlist dt { color: var(--ink-3); } .kvlist dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
.imgstrip { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; }
.imgstrip figure { margin: 0; cursor: pointer; }
.imgstrip img { width: 100%; aspect-ratio: 4/3; object-fit: cover; border-radius: 7px; border: 1px solid var(--hair); background: var(--paper-2); display: block; }
.imgstrip figcaption { font-size: 12px; color: var(--ink-3); padding: 4px 2px 0; display:flex; gap:6px; align-items:center; }

/* ------------------------------------------------------------- admin ----- */
.admin-layout { display: grid; grid-template-columns: 218px 1fr; gap: 26px; align-items: start; margin: 22px 0 60px; }
@media (max-width: 880px) { .admin-layout { grid-template-columns: 1fr; } }
.admin-nav { position: sticky; top: 74px; display: flex; flex-direction: column; gap: 2px; }
.admin-nav a { padding: 8px 12px; border-radius: 7px; color: var(--ink-2); font-weight: 500; font-size: 14px; }
.admin-nav a.active { background: var(--paper-2); color: var(--ink); font-weight: 600; }
.admin-nav a:hover { text-decoration: none; background: var(--paper-2); }
.admin-nav .sect { font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3); font-weight: 700; margin: 14px 12px 4px; }

/* hierarchy tree */
.htree { font-size: 14px; }
.htree ul { list-style: none; margin: 0; padding-left: 20px; border-left: 1px solid var(--hair-2); }
.htree > ul { padding-left: 0; border: 0; }
.htree li { margin: 1px 0; }
.htree .noderow { display: flex; align-items: center; gap: 7px; padding: 3px 7px; border-radius: 6px; }
.htree .noderow:hover { background: var(--paper-2); }
.htree .noderow.sel { background: var(--accent-soft); }
.htree .tw { width: 17px; height: 17px; display: grid; place-items: center; cursor: pointer; color: var(--ink-3); flex: none; border: 0; background: none; font-size: 10px; padding: 0; }
.htree .nm { cursor: pointer; }
.htree .cnt { font-size: 11.5px; color: var(--ink-3); }
.htree .code { font-family: var(--font-mono); font-size: 11px; color: var(--accent); }
.htree .tools { display: none; gap: 2px; margin-left: auto; }
.htree .noderow:hover .tools, .htree .noderow.sel .tools { display: inline-flex; }

/* dialogs */
dialog.dlg { border: 1px solid var(--hair); border-radius: 14px; box-shadow: var(--shadow-lift); background: var(--card); color: var(--ink); padding: 0; max-width: min(660px, 94vw); width: 100%; }
dialog.dlg.wide { max-width: min(920px, 96vw); }
dialog.dlg::backdrop { background: rgba(15,18,22,.45); backdrop-filter: blur(3px); }
.dlg-h { padding: 16px 20px 0; display:flex; align-items:center; gap: 10px; }
.dlg-b { padding: 14px 20px 20px; max-height: 72vh; overflow-y: auto; }
.dlg-f { padding: 13px 20px; border-top: 1px solid var(--hair); display: flex; gap: 10px; justify-content: flex-end; background: var(--paper-2); border-radius: 0 0 14px 14px; }

/* preview diff panel for staged hierarchy edits + imports */
.staged { border: 1px solid var(--amber); background: var(--amber-soft); border-radius: var(--radius); padding: 14px 16px; }
.staged h4 { margin: 0 0 6px; display:flex; align-items:center; gap:8px; }
.staged ul { margin: 6px 0 0; padding-left: 20px; font-size: 13.5px; }
.staged .impact { font-size: 13px; }

/* toasts */
#toasts { position: fixed; bottom: 18px; right: 18px; z-index: 300; display: flex; flex-direction: column; gap: 8px; }
.toast { background: var(--ink); color: var(--paper); padding: 10px 16px; border-radius: 9px; font-size: 14px; box-shadow: var(--shadow-lift); max-width: 380px; animation: pop .18s ease; }
body[data-app="b"] .toast { background: var(--card); color: var(--ink); border: 1px solid var(--hair); }
.toast.err { background: var(--danger); color: #fff; }
@keyframes pop { from { transform: translateY(8px); opacity: 0; } }

/* skeleton + spinners */
.skel { background: linear-gradient(100deg, var(--paper-2) 40%, color-mix(in srgb, var(--paper-2) 60%, var(--card)) 50%, var(--paper-2) 60%); background-size: 200% 100%; animation: sh 1.1s infinite linear; border-radius: 8px; }
@keyframes sh { to { background-position: -200% 0; } }
.spin { width: 15px; height: 15px; border: 2px solid var(--hair); border-top-color: var(--accent); border-radius: 50%; animation: rot .7s linear infinite; display:inline-block; vertical-align: -2px; }
@keyframes rot { to { transform: rotate(360deg); } }

.progressbar { height: 7px; border-radius: 99px; background: var(--paper-2); overflow: hidden; border: 1px solid var(--hair); }
.progressbar > div { height: 100%; background: var(--accent); transition: width .3s ease; }

.empty { text-align: center; color: var(--ink-3); padding: 60px 16px; }
.empty .big { font-size: 40px; opacity: .4; }

footer.site { border-top: 1px solid var(--hair); margin-top: 60px; padding: 22px 0 34px; color: var(--ink-3); font-size: 13px; }

/* auth card */
.auth { max-width: 400px; margin: 9vh auto; }
.auth .card { padding: 26px; }

/* ------------------------------------------------------ types overview --- */
.subtag {
  font-family: var(--font-mono); font-size: 11px; font-weight: 600; letter-spacing: .03em;
  margin-left: 8px; padding: 1px 7px; border-radius: 4px;
  border: 1px dashed color-mix(in srgb, var(--accent) 55%, var(--hair));
  color: var(--accent); background: color-mix(in srgb, var(--accent-soft) 55%, transparent);
  white-space: nowrap;
}
.subtag.light { border-color: rgba(255,255,255,.55); color: #fff; background: rgba(255,255,255,.14); }

.types-list td { vertical-align: middle; }
.trep { width: 52px; height: 40px; object-fit: cover; border-radius: 5px; border: 1px solid var(--hair); background: var(--paper-2); display: block; }
.trep.ph { display: grid; place-items: center; font-family: var(--font-display); font-weight: 800; color: var(--ink-3); }
.chosen-dot { display: block; width: 6px; height: 6px; border-radius: 50%; background: var(--amber); margin: 3px auto 0; }
.tname strong { font-size: 14.5px; }

.typegrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 12px; }
.ttile {
  position: relative; border-radius: var(--radius); overflow: hidden; cursor: pointer;
  border: 1px solid var(--hair); background: var(--paper-2); aspect-ratio: 4/3;
  transition: transform .16s ease, box-shadow .16s ease;
}
.ttile:hover { transform: translateY(-2px); box-shadow: var(--shadow-lift); }
.ttile .trep.big { width: 100%; height: 100%; border: 0; border-radius: 0; }
.ttile .trep.ph.big { font-size: 40px; opacity: .55; }
.ttile .tbar {
  position: absolute; inset: auto 0 0 0; padding: 26px 11px 9px; color: #fff;
  background: linear-gradient(transparent, rgba(10,12,14,.78));
  display: flex; align-items: flex-end; justify-content: space-between; gap: 8px;
}
.ttile .tbar .tt { min-width: 0; line-height: 1.25; }
.ttile .tbar strong { font-size: 14px; display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; }
.ttile .tbar .tn { font-size: 11.5px; opacity: .85; white-space: nowrap; }
.ttile .tstar {
  color: var(--amber);
  background: rgba(10,12,14,.62); border-radius: 4px; padding: 1px 6px; font-size: 12px; backdrop-filter: blur(3px);
}

.repgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 10px; }
.repopt { position: relative; border: 2px solid var(--hair); border-radius: 8px; overflow: hidden; padding: 0; cursor: pointer; background: var(--paper-2); }
.repopt img { width: 100%; aspect-ratio: 4/3; object-fit: cover; display: block; }
.repopt .cap { display: block; font-size: 11.5px; color: var(--ink-2); padding: 4px 7px; text-align: left; font-family: var(--font-mono); }
.repopt:hover { border-color: var(--accent); }
.repopt.on { border-color: var(--amber); box-shadow: 0 0 0 3px color-mix(in srgb, var(--amber) 25%, transparent); }
.repopt.on::after { content: '★'; position: absolute; top: 6px; right: 6px; color: var(--amber); background: rgba(10,12,14,.6); border-radius: 4px; padding: 0 5px; font-size: 12px; }

/* ------------------------------------------------------ depth explorer --- */
.depthx { display: grid; grid-template-columns: 138px minmax(0, 1fr); gap: 22px; align-items: start; margin-top: 8px; }
.depthx .rail {
  position: sticky; top: 76px; max-height: calc(100vh - 100px);
  display: flex; flex-direction: column; gap: 6px;
  border-left: 2px solid var(--hair); padding-left: 10px;
}
.depthx .rlegend { font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3); }
.depthx .rbins { display: flex; flex-direction: column; flex: 1; min-height: 0; overflow: hidden auto; scrollbar-width: thin; }
.depthx .rung {
  display: grid; grid-template-columns: 42px 1fr 20px; align-items: center; gap: 6px;
  border: 0; background: none; padding: 1px 0; cursor: pointer; text-align: left;
  min-height: 15px; flex: 1 0 auto; color: var(--ink-2); border-radius: 4px;
}
.depthx .rung:hover { background: var(--paper-2); }
.depthx .rung.empty { cursor: default; opacity: .55; }
.depthx .rung .rl { font-size: 10.5px; color: var(--ink-3); text-align: right; }
.depthx .rung .rn { font-size: 10px; color: var(--ink-3); }
.depthx .rung .rbar { height: 7px; border-radius: 99px; background: var(--paper-2); overflow: hidden; }
.depthx .rung .rbar span { display: block; height: 100%; background: color-mix(in srgb, var(--accent) 55%, var(--hair)); border-radius: 99px; transition: background .15s; }
.depthx .rung.on { background: var(--accent-soft); }
.depthx .rung.on .rl, .depthx .rung.on .rn { color: var(--accent); font-weight: 600; }
.depthx .rung.on .rbar span { background: var(--accent); }
.depthx .rung.sea { border-bottom: 1px dashed color-mix(in srgb, var(--accent) 60%, var(--hair)); border-radius: 0; }

.dsecs { min-width: 0; }
.dsec { padding: 6px 0 18px; scroll-margin-top: 76px; }
.dsec header { display: flex; align-items: baseline; gap: 12px; margin: 0 0 8px; border-bottom: 1px solid var(--hair-2); padding-bottom: 5px; }
.dsec .drange { font-size: 14px; font-weight: 600; color: var(--ink); letter-spacing: .02em; }
.sealine { display: flex; align-items: center; gap: 12px; color: var(--accent); font-size: 12px; letter-spacing: .18em; text-transform: uppercase; margin: 6px 0 14px; }
.sealine::before, .sealine::after { content: ''; flex: 1; border-top: 1px dashed color-mix(in srgb, var(--accent) 55%, var(--hair)); }
@media (max-width: 760px) {
  .depthx { grid-template-columns: 86px 1fr; gap: 12px; }
  .depthx .rung { grid-template-columns: 32px 1fr; }
  .depthx .rung .rn { display: none; }
}

/* ------------------------------------------------------ data entry ------- */
.entry-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; align-items: start; }
@media (max-width: 720px) { .entry-grid { grid-template-columns: 1fr; } }

/* print: the table is the point */
@media print {
  .topbar, .toolbar, .facets, .pager, footer.site, #toasts { display: none !important; }
  body { background: #fff; }
  .tablewrap { border: 0; box-shadow: none; }
}

/* ------------------------------------------------------ smart label input - */
.lta { position: relative; }
.lta input.ok { border-color: color-mix(in srgb, var(--accent) 60%, var(--hair)); }
.lta .ok-path { color: var(--accent); font-size: 12.5px; }
.lta-drop {
  position: absolute; z-index: 40; inset: auto 0 auto 0; top: calc(100% - 2px);
  background: var(--paper); border: 1px solid var(--hair); border-radius: 0 0 8px 8px;
  box-shadow: var(--shadow-lift); max-height: min(42vh, 380px); overflow: auto;
}
.lta-opt { display: block; width: 100%; text-align: left; border: 0; background: none; padding: 7px 10px; cursor: pointer; font-size: 13.5px; }
.lta-opt:hover { background: var(--paper-2); }
.lta-opt.new { color: var(--accent); border-top: 1px dashed var(--hair); }
.linklike { border: 0; background: none; padding: 0; color: var(--accent); text-decoration: underline; cursor: pointer; font: inherit; font-size: inherit; }

/* ------------------------------------------------------ facet popovers ---- */
.facet-group { position: relative; }
.fpop {
  position: absolute; z-index: 35; top: calc(100% + 4px); left: 0; min-width: 240px;
  background: var(--paper); border: 1px solid var(--hair); border-radius: 10px;
  box-shadow: var(--shadow-lift); padding: 12px;
}
.fpop label.f.small { font-size: 12px; }
.frow { padding: 6px 8px; border: 1px dashed var(--hair); border-radius: 8px; background: var(--paper); }
.frow .fname { font-size: 12.5px; font-weight: 600; color: var(--ink-2); }

/* ------------------------------------------------------ batch entry ------- */
.entry-batch th { position: sticky; top: 0; background: var(--paper); z-index: 2; }
.entry-batch td { padding: 4px 8px; }
.entry-batch input.f, .entry-batch select.f, .entry-batch textarea.f { padding: 5px 8px; font-size: 13px; min-width: 110px; }
.entry-batch tr.sel td { background: color-mix(in srgb, var(--accent-soft) 45%, transparent); }
.entry-batch .saved { outline: 2px solid color-mix(in srgb, var(--accent) 55%, transparent); transition: outline .8s; }
.cellbtn { border: 1px dashed var(--hair); background: none; border-radius: 6px; padding: 5px 9px; cursor: pointer; font-size: 13px; color: var(--ink-2); }
.cellbtn.ok { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 55%, var(--hair)); }
.cellbtn.working { color: var(--amber); border-color: color-mix(in srgb, var(--amber) 55%, var(--hair)); }
.labelcell { display: inline-flex; align-items: baseline; gap: 7px; max-width: 240px; text-align: left; }
.labelcell .lcname { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.labelcell .lcflag { flex: none; font-size: 10px; text-transform: uppercase; letter-spacing: .07em; opacity: .8; }
.applybar { background: var(--paper-2); border: 1px solid var(--hair); border-radius: 10px; padding: 8px 10px; gap: 8px; }
.colrow { border: 1px solid var(--hair-2); border-radius: 8px; padding: 4px 8px; background: var(--paper); }

/* ------------------------------------------------------ media workbench --- */
.wbgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; }
.wbtile { position: relative; border: 2px solid var(--hair); border-radius: 9px; overflow: hidden; cursor: pointer; background: var(--paper-2); }
.wbtile img, .wbtile .ph { width: 100%; aspect-ratio: 4/3; object-fit: cover; display: block; }
.wbtile .ph { display: grid; place-items: center; color: var(--ink-3); font-size: 22px; }
.wbtile.sel { border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent); }
.wbtile.sel::after { content: '✓'; position: absolute; top: 6px; left: 6px; background: var(--accent); color: #fff; border-radius: 5px; padding: 0 6px; font-size: 12px; }
.wbtile .wbcap { padding: 5px 8px 7px; display: grid; gap: 1px; font-size: 11.5px; }
.wbtile .wbcap .mono { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wbtile .wbi { position: absolute; top: 5px; right: 5px; opacity: 0; padding: 1px 7px; }
.wbtile:hover .wbi { opacity: 1; }
.trep.ph.gap { border-style: dashed; color: var(--ink-3); background: repeating-linear-gradient(45deg, var(--paper-2), var(--paper-2) 6px, var(--paper) 6px, var(--paper) 12px); }

/* ------------------------------------------------------ scan report ------- */
.replist { display: flex; flex-direction: column; gap: 2px; max-height: 260px; overflow: auto; margin-top: 6px; }
.repent { border: 0; background: none; text-align: left; padding: 4px 8px; border-radius: 6px; cursor: pointer; font-size: 12.5px; }
.repent:hover { background: var(--paper-2); }

/* Leaflet panes (z 200–1000) must never float over overlays: give every map
   its own stacking context, pinned to the page layer. */
.mapbox { position: relative; z-index: 0; isolation: isolate; }

/* tile fit: whole photo visible (letterboxed) instead of cropped-to-fill */
.gallery.fit .gi img, .typegrid.fit .ttile img.trep { object-fit: contain; background: var(--paper-2); }
[data-app="b"] .gallery.fit .gi img { background: #14171c; }
.grid tr.sel td { background: color-mix(in srgb, var(--accent-soft) 45%, transparent); }

/* letterboxed-on-black tile mode */
.gallery.fitblack .gi img, .typegrid.fitblack .ttile img.trep { object-fit: contain; background: #000; }

/* draggable column widths */
.grid th { position: relative; }
.colgrip { position: absolute; top: 0; right: -4px; width: 9px; height: 100%; cursor: col-resize; touch-action: none; }
.colgrip::after { content: ''; position: absolute; top: 22%; bottom: 22%; right: 4px; width: 1px; background: var(--hair); }
.grid th:hover .colgrip::after { background: var(--accent); }

/* Manage → Views as cover tiles */
.viewgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 14px; }
.viewcard { border: 1px solid var(--hair); border-radius: var(--radius); overflow: hidden; background: var(--card); display: flex; flex-direction: column; }
.viewcard .vcover { display: block; aspect-ratio: 16/9; background: var(--paper-2); position: relative; }
.viewcard .vcover img { width: 100%; height: 100%; object-fit: cover; display: block; }
.viewcard .vcover .ph { position: absolute; inset: 0; display: grid; place-items: center; font-family: var(--font-display); font-size: 40px; font-weight: 800; color: var(--ink-3); opacity: .5; }
.viewcard .vbadges { position: absolute; left: 8px; bottom: 8px; display: flex; gap: 5px; }
.viewcard .vb { background: rgba(20,22,26,.72); color: #fff; font-size: 10.5px; padding: 2px 7px; border-radius: 20px; letter-spacing: .04em; }
.viewcard .vb.pub { background: var(--accent); }
.viewcard .vmeta { padding: 10px 12px 12px; display: flex; flex-direction: column; gap: 2px; }

/* ------------------------------------------------------ compare viewer --- */
/* Black, edge to edge, and as much photograph as the screen will give. */
.cmp {
  position: fixed; inset: 0; z-index: 6000; background: #08090b; color: #ECEDEA;
  display: flex; flex-direction: column; font-family: var(--font-body);
}
.cmp-bar {
  flex: none; display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 9px 14px; border-bottom: 1px solid #23262c; background: #0e1013; font-size: 13.5px;
}
.cmp-bar strong { font-family: var(--font-display); font-size: 15px; }
.cmp-ctl { display: flex; align-items: center; gap: 6px; font-size: 12px; text-transform: uppercase;
  letter-spacing: .07em; color: #8b9098; }
.cmp-ctl select {
  background: #191c21; color: #ECEDEA; border: 1px solid #2c3037; border-radius: 6px;
  padding: 4px 8px; font-size: 13px; text-transform: none; letter-spacing: 0;
}
.cmp-btn {
  background: #191c21; color: #C9CDD3; border: 1px solid #2c3037; border-radius: 6px;
  padding: 4px 11px; font-size: 13px; font-weight: 600; cursor: pointer;
}
.cmp-btn:hover { background: #23262c; color: #fff; }
.cmp-btn.on { background: var(--accent); border-color: var(--accent); color: #fff; }
.cmp-btn.close { margin-left: 6px; }
.cmp-sp { margin-left: auto; }
.cmp-hint { color: #6c727a; font-size: 12px; }
.cmp-warn { color: var(--amber); font-size: 12.5px; }

.cmp-grid { flex: 1; min-height: 0; display: grid; gap: 6px; padding: 6px; overflow: auto; }
.cmp-grid.fitted { overflow: hidden; }
.cmp-panel {
  margin: 0; position: relative; background: #000; border: 1px solid #1b1e23; border-radius: 8px;
  overflow: hidden; display: flex; flex-direction: column; min-height: 0;
}
.cmp-grid:not(.fitted) .cmp-panel { min-height: 240px; }
/* nothing in here is text to be selected; a drag is always a drag */
.cmp, .cmp-panel, .cmp-stage { user-select: none; -webkit-user-select: none; }
.cmp-stage img { -webkit-user-drag: none; user-drag: none; pointer-events: none; }
.cmp-panel.big { grid-column: span 2; grid-row: span 2; }
.cmp-stage { flex: 1; min-height: 0; overflow: hidden; display: grid; place-items: center; cursor: grab; touch-action: none; }
.cmp-stage.grabbing { cursor: grabbing; }
.cmp-stage img { max-width: 100%; max-height: 100%; object-fit: contain; display: block; transform-origin: center; will-change: transform; }
.cmp-none { color: #565c64; font-size: 13px; letter-spacing: .04em; }
.cmp-panel figcaption {
  flex: none; display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 6px 9px; background: #0e1013; border-top: 1px solid #1b1e23; font-size: 12.5px;
}
.cmp-panel figcaption .tag-id { background: #191c21; border-color: #2c3037; color: #ECEDEA; }
.cmp-name { font-weight: 600; }
.cmp-where, .cmp-tag { color: #7c828a; font-size: 11.5px; }
.cmp-tag { margin-left: auto; text-transform: uppercase; letter-spacing: .07em; }
.cmp.nometa .cmp-panel figcaption { display: none; }
@media (max-width: 700px) { .cmp-grid { grid-template-columns: 1fr !important; } .cmp-hint { display: none; } }

/* the overview's per-type actions */
.types-list td.tacts { width: 120px; white-space: nowrap; text-align: right; }
/* Top right is "look at this one", bottom right is "compare them all" — the
   same places they sit on a gallery tile, so the habit carries between the two
   grids instead of having to be relearned. */
/* One row, packed from the right — see the note where it is built. Nothing
   here counts pixels per button, so a tile that has no ⧉ and no ✎ still puts
   ⛶ in exactly the same corner. */
.ttile .tacts-top {
  position: absolute; top: 7px; right: 7px; z-index: 2;
  display: flex; align-items: center; gap: 5px;
  opacity: 0; transition: opacity .15s;
}
.ttile:hover .tacts-top, .ttile:focus-within .tacts-top { opacity: 1; }
.ttile .tacts-top .btn { padding: 2px 8px; }
/* the star says something about the tile rather than doing something, so it
   stays readable when the buttons beside it have faded out */
.ttile .tacts-top:has(.tstar) { opacity: 1; }
.ttile .tacts-top:has(.tstar) .btn { opacity: 0; transition: opacity .15s; }
.ttile:hover .tacts-top .btn, .ttile:focus-within .tacts-top .btn,
.ttile.armed .tacts-top .btn { opacity: 1; }

/* A named place on the map: a small ring with the name beside it, sitting
   above the specimen pins because it labels them rather than competing. The
   marker's own box is 10px so the label can overflow it freely without
   affecting where the point actually is. */
.sitepin { overflow: visible; }
.sitepin .sp {
  position: absolute; left: 0; top: 0;
  display: flex; align-items: center; gap: 5px; white-space: nowrap;
  transform: translate(-5px, -50%);
  pointer-events: none;
}
.sitepin .sp::before {
  content: ''; width: 9px; height: 9px; flex: none; border-radius: 50%;
  background: #fff; border: 2.5px solid var(--accent);
  box-shadow: 0 0 0 1.5px rgba(0,0,0,.35);
}
.sitepin .sp b {
  font-size: 11.5px; font-weight: 700; letter-spacing: .01em; color: #fff;
  background: rgba(12,16,20,.66); padding: 1px 6px; border-radius: 4px;
  backdrop-filter: blur(3px); text-shadow: 0 1px 2px rgba(0,0,0,.55);
}
.sitepin .sp em {
  font-style: normal; font-size: 10px; color: #fff; opacity: .82;
  background: rgba(12,16,20,.5); padding: 0 4px; border-radius: 3px;
}
/* a site in the list that nothing in this view came from — present, not loud */
.sitepin.quiet .sp::before { background: rgba(255,255,255,.6); border-color: rgba(255,255,255,.75); }
.sitepin.quiet .sp b { background: rgba(12,16,20,.4); font-weight: 600; opacity: .8; }

/* the "just show me the photograph" button on a gallery tile */
.gi .gphoto {
  position: absolute; top: 7px; right: 7px; z-index: 2;
  opacity: 0; transition: opacity .15s; padding: 2px 8px; line-height: 1.5;
}
.gi:hover .gphoto, .gi:focus-within .gphoto { opacity: 1; }

/* a section that stays shut until it is wanted */
details.quiet > summary { cursor: pointer; font-weight: 700; font-size: 14px; color: var(--ink-2); list-style: revert; }
details.quiet > summary:hover { color: var(--accent); }
details[open].quiet > summary { margin-bottom: 4px; }

/* a photo being turned round in the gallery */
.gallery .gi.working { opacity: .55; }
.gallery .gi .badge .flipbadge { background: var(--accent); }

/* ------------------------------------------------- notes from the field --- */
.fbbtn { position: relative; color: var(--ink-3); padding: 6px 8px; }
.fbbtn:hover { color: var(--accent); background: var(--paper-2); }
.fbbtn svg { display: block; }
.fbdot {
  position: absolute; top: 4px; right: 4px; width: 7px; height: 7px; border-radius: 50%;
  background: var(--amber); box-shadow: 0 0 0 2px var(--paper);
}
.fbdot[hidden] { display: none; }
.navcount {
  margin-left: 7px; background: var(--amber); color: #fff; font-size: 10.5px; font-weight: 700;
  padding: 0 6px; border-radius: 999px; vertical-align: 1px;
}

.fbcard { padding: 13px 15px; }
.fbcard.fresh { border-left: 3px solid var(--accent); }
.fbcard.settled { opacity: .62; }
.fbkind {
  flex: none; font-size: 10.5px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  padding: 3px 8px; border-radius: 4px; background: var(--paper-2); color: var(--ink-3); margin-top: 2px;
}
.fbkind.k-bug { background: var(--danger-soft); color: var(--danger); }
.fbkind.k-improvement { background: var(--amber-soft); color: var(--amber); }
.fbkind.k-feature { background: var(--accent-soft); color: var(--accent); }
.fbtitle {
  border: 0; background: none; padding: 0; text-align: left; cursor: pointer; font: inherit;
  font-weight: 600; font-size: 15px; color: var(--ink); flex: 1 1 300px; min-width: 0;
}
.fbtitle:hover { color: var(--accent); }
.fbstatus { max-width: 140px; padding: 4px 8px; font-size: 12.5px; }

/* a dialog whose whole job is “search, then read the results”: tall to begin
   with, and draggable taller by the bar above its buttons */
dialog.dlg.roomy .dlg-b { min-height: min(46vh, 420px); overflow: auto; }
.dlg-grab { height: 14px; cursor: ns-resize; display: grid; place-items: center; touch-action: none; }
.dlg-grab::after { content: ''; width: 46px; height: 3px; border-radius: 99px; background: var(--hair); transition: background .15s; }
.dlg-grab:hover::after, .dlg-grab:active::after { background: var(--accent); }

/* “you are looking at an older version of the app than the one installed” */
.stalebar {
  position: fixed; left: 16px; bottom: 16px; z-index: 400; max-width: min(460px, calc(100vw - 32px));
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  background: var(--card); color: var(--ink); border: 1px solid var(--amber);
  border-left: 4px solid var(--amber); border-radius: 10px; padding: 11px 14px;
  box-shadow: var(--shadow-lift); font-size: 13.5px;
}

/* ------------------------------------------------- column layout editor --- */
.collist .colrow { gap: 8px; cursor: grab; user-select: none; }
.collist .colrow.dragging { opacity: .45; cursor: grabbing; }
.collist .colrow.shown { background: var(--card); border-color: var(--hair); }
.collist .colrow.over-a { box-shadow: inset 0 2px 0 var(--accent); }
.collist .colrow.over-b { box-shadow: inset 0 -2px 0 var(--accent); }
.colgrab { color: var(--ink-3); font-size: 13px; letter-spacing: -1px; cursor: grab; flex: none; }

.presetbox { gap: 6px; padding: 8px 10px; background: var(--paper-2); border: 1px solid var(--hair); border-radius: 10px; }
.presetchip {
  display: inline-flex; align-items: center; gap: 4px; border: 1px solid var(--hair);
  background: var(--card); border-radius: 999px; padding: 1px 4px 1px 2px; font-size: 12.5px;
}
.presetchip .pname { border: 0; background: none; padding: 3px 8px; border-radius: 999px; cursor: pointer; font: inherit; font-weight: 600; color: var(--ink-2); }
.presetchip .pname:hover { color: var(--accent); }
.presetchip .ptag { font-size: 9.5px; letter-spacing: .08em; text-transform: uppercase; color: var(--accent); }
.presetchip .pdel { border: 0; background: none; cursor: pointer; color: var(--ink-3); padding: 0 5px; font-size: 11px; }
.presetchip .pdel:hover { color: var(--danger); }
select.f.layoutsel { width: auto; max-width: 210px; padding: 4px 8px; font-size: 13px; }

/* The right-hand group of the first row. The tab bar is last and the group
   hugs the right edge, so a longer count or an extra button grows leftwards
   and the tabs themselves never move. */
.toolbar .topright { margin-left: auto; display: flex; align-items: center; gap: 10px; flex-wrap: nowrap; }
.toolbar .topright > .muted { white-space: nowrap; }
@media (max-width: 900px) { .toolbar .topright { flex-wrap: wrap; margin-left: 0; } }

/* a grade button with a word on it rather than a single letter */
.gradepick button.wide { width: auto; padding: 0 9px; }

/* the second control row: only what belongs to the tab you are on */
.viewbar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 8px 10px; margin: 0 0 4px; border: 1px solid var(--hair-2);
  border-radius: 10px; background: var(--paper-2);
}
.viewbar label.ctl { display: flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3); }
.viewbar label.ctl select.f { width: auto; padding: 4px 8px; font-size: 13px; font-weight: 400;
  text-transform: none; letter-spacing: 0; color: var(--ink); }
.viewbar .tabbar button { padding: 4px 11px; font-size: 13px; }

/* the table using the whole window rather than the reading column */
.wrap.wide { max-width: none; }

/* editing values where they sit */
.grid.inline-edit tbody tr { cursor: default; }
.grid.inline-edit td .ev { display: inline-block; min-width: 34px; min-height: 1.2em;
  border-bottom: 1px dashed var(--hair); border-radius: 3px; padding: 0 2px; cursor: text; }
.grid.inline-edit td .ev:hover { background: var(--accent-soft); border-bottom-color: var(--accent); }
.grid.inline-edit td .ev:focus { background: var(--accent-soft); border-bottom-color: var(--accent); outline: none; }
.grid.inline-edit .cellpick { cursor: pointer; border-bottom: 1px dashed var(--hair); display: inline-block; }
.grid.inline-edit .cellpick:hover { background: var(--accent-soft); border-bottom-color: var(--accent); }
select.f.cellsel { width: auto; min-width: 90px; padding: 3px 6px; font-size: 13px; }

/* gallery captions pinned open (the toggle in the gallery toolbar) */
body.showcaps .gallery .gi .cap { opacity: 1; padding-top: 16px; }
body.showcaps .gallery .gi:hover img { transform: none; }

/* ------------------------------------------------------ small screens ----- */
@media (max-width: 760px) {
  .wrap { padding: 0 12px; }
  .toolbar { flex-wrap: wrap; row-gap: 8px; }
  .toolbar .right { margin-left: 0; }
  .gallery { grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); gap: 8px; }
  .typegrid { grid-template-columns: repeat(auto-fill, minmax(155px, 1fr)); }
  /* Two, deliberately, on a phone held upright. auto-fill would give three on a
     wider handset, and three 120px tiles is a contact sheet rather than
     something you can compare an animal against. */
  @media (orientation: portrait) { .typegrid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
  .wbgrid { grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); }
  .detail-grid { grid-template-columns: 1fr !important; }
  .kvlist { grid-template-columns: 120px 1fr; }
  .entry-grid { grid-template-columns: 1fr !important; }
  .f-inline { flex-direction: column; align-items: stretch; }
  .dialog, dialog { width: calc(100vw - 20px) !important; max-width: none; max-height: 92vh; overflow: auto; }
  .lb { flex-direction: column; }
  .lb .info { max-width: none; width: 100%; max-height: 44vh; overflow: auto; }
  .lb .stage img { max-height: 50vh; }
  .lb .nav.prev { left: 8px; } .lb .nav.next { right: 8px; }
  .admin-layout { grid-template-columns: 1fr !important; }
  .admin-nav { flex-direction: row; overflow-x: auto; gap: 4px; padding-bottom: 8px; position: static; }
  .admin-nav .sect { display: none; }
  .admin-nav a { white-space: nowrap; }
  .htree { font-size: 13px; }
  .tablewrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .grid td, .grid th { padding: 7px 8px; font-size: 13px; }
  .btn, .chip { min-height: 34px; }
  h1 { font-size: 26px; }
  .tabbar button { padding: 6px 10px; }
}

/* smoke */

/* ===================================================== the front door ===== */
/* Arriving signed out should look like a way in, not a room that failed to
   load: the mark at a proper size, the tagline, and the form itself. */
.welcome { max-width: 460px; margin: 0 auto; padding: 46px 0 28px; text-align: center; }
.welcome-mark { margin-bottom: 14px; }
.welcome-mark img { max-height: 132px; max-width: 300px; object-fit: contain; }
.welcome-mark .mark.big {
  display: inline-grid; place-items: center; width: 92px; height: 92px; border-radius: 20px;
  background: var(--accent); color: #fff; font-size: 46px; font-weight: 700;
}
.welcome h1 { margin: 6px 0 2px; }
.welcome .lede { margin: 0 0 22px; }
.welcome .signin { text-align: left; }
.btn.wide { width: 100%; justify-content: center; }
.danger-text { color: var(--danger, #a03030); }

/* the mark beside the title, at whatever size has been chosen */
.topbar .brand .mark { transition: width .12s ease, height .12s ease; }
.topbar .brand img.mark.logo {
  height: calc(30px * var(--logo-scale, 1));
  max-width: calc(160px * var(--logo-scale, 1));
  width: auto; object-fit: contain; border-radius: 8px;
}
.topbar .brand span.mark {
  width: calc(30px * var(--logo-scale, 1)); height: calc(30px * var(--logo-scale, 1));
  font-size: calc(15px * var(--logo-scale, 1));
}
.topbar.bigmark .topbar-inner { padding-top: 8px; padding-bottom: 8px; }
.topbar.bigmark .brand span:not(.mark) { font-size: 1.08em; }

/* a quiet way through to the bench, for the accounts that have it */
.benchcard {
  display: flex; align-items: center; gap: 12px; margin: 30px 0 6px; padding: 12px 16px;
  border: 1px solid var(--line); border-radius: 12px; background: var(--paper-2);
  text-decoration: none; color: inherit;
}
.benchcard:hover { border-color: var(--accent); }
.benchcard .bicon { font-size: 22px; opacity: .8; }
.benchcard strong { display: block; }

/* ===================================================== molecular bench ==== */
.mol .molhead { padding: 24px 0 0; }
.molnav { display: flex; gap: 2px; flex-wrap: wrap; border-bottom: 1px solid var(--line); margin-bottom: 18px; }
.molnav a {
  padding: 8px 14px; text-decoration: none; color: var(--ink-2); font-size: 14px; font-weight: 600;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.molnav a:hover { color: var(--ink); }
.molnav a.on { color: var(--accent); border-bottom-color: var(--accent); }
.molnav .moln {
  display: inline-block; margin-left: 6px; padding: 0 6px; border-radius: 8px;
  background: var(--paper-2); font-size: 11px; font-weight: 600; color: var(--ink-2);
}
.molbar { gap: 10px; flex-wrap: wrap; margin: 10px 0; align-items: center; }

/* the plate: column numbers across, row letters down, wells between */
.platewrap { overflow-x: auto; padding: 2px; }
.plate {
  display: grid; gap: 3px; min-width: max-content;
  grid-template-columns: 26px repeat(var(--cols), minmax(76px, 1fr));
}
.plate.compact { grid-template-columns: 20px repeat(var(--cols), minmax(52px, 1fr)); gap: 2px; }
.plate .pcorner { }
.plate .phead {
  display: grid; place-items: center; font-size: 11px; font-weight: 700; color: var(--ink-2);
  cursor: pointer; user-select: none; border-radius: 4px;
}
.plate .phead:hover { background: var(--paper-2); color: var(--accent); }
.plate .well {
  position: relative; min-height: 52px; border: 1px solid var(--line); border-radius: 7px;
  background: var(--paper); padding: 3px 4px; cursor: pointer; overflow: hidden;
  display: flex; flex-direction: column; justify-content: flex-start; gap: 1px;
}
.plate.compact .well { min-height: 34px; font-size: 11px; }
.plate .well:hover { border-color: var(--accent); }
.plate .well.filled { border-color: var(--ink-3, #bbb); }
.plate .well.picked { outline: 2px solid var(--accent); outline-offset: -2px; }
.plate .well.over { border-color: var(--accent); background: var(--paper-2); }
.plate .well.carried { background: #eaf3ee; }
.plate .well .wname { font-size: 9px; color: var(--ink-3, #999); line-height: 1; letter-spacing: .04em; }
.plate .well .wcode { font-size: 12px; font-weight: 600; line-height: 1.15; word-break: break-all; }
.plate.compact .well .wcode { font-size: 10px; }
.plate .well .wto { font-size: 9px; color: var(--accent); font-weight: 700; }
.plate .well .wprimer {
  font-size: 9px; font-weight: 700; color: var(--pc); line-height: 1.1;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.plate .well .wthumb { width: 100%; height: 26px; object-fit: cover; border-radius: 3px; margin-top: 1px; }
.plate .well .wdot { position: absolute; top: 2px; right: 3px; color: var(--accent); font-size: 14px; line-height: 1; }
.plate .well.extra .wcode { color: #b04a3a; }

.primer-chip {
  display: inline-block; padding: 1px 8px; border-radius: 20px; font-size: 11px; font-weight: 700;
  color: #fff; background: var(--pc, #777); white-space: nowrap;
}
.plegend { display: flex; gap: 5px; flex-wrap: wrap; align-items: center; }
.gelkey {
  padding: 1px 7px; border-radius: 4px; font-size: 10px; color: #333;
  border: 1px solid rgba(0, 0, 0, .12);
}

.pickgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 6px; }
.pickrow {
  display: flex; align-items: center; gap: 7px; padding: 5px 7px; border: 1px solid var(--line);
  border-radius: 8px; background: var(--paper); cursor: pointer; text-align: left; font: inherit;
}
.pickrow.on { border-color: var(--accent); background: var(--paper-2); box-shadow: inset 0 0 0 1px var(--accent); }
.pickrow img, .pickrow .ph {
  width: 30px; height: 30px; border-radius: 5px; object-fit: cover; flex: 0 0 auto;
  background: var(--paper-2); display: grid; place-items: center; font-weight: 700; color: var(--ink-3, #999);
}
.pickrow .pc { font-weight: 600; font-size: 12px; }
.pickrow .pn { font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.grid2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 10px 16px; }
.mmtable td { padding-top: 5px; padding-bottom: 5px; }
.mmtable tr.total td { border-top: 2px solid var(--line); }
.warnbox {
  border: 1px solid #e0c07a; background: #fdf6e5; border-radius: 8px; padding: 8px 12px; font-size: 13px;
}
.warnbox ul { margin: 4px 0 0; padding-left: 18px; }
.colpick { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 2px 14px; }
tr.dim td { opacity: .5; }
tr.clickrow { cursor: pointer; }

/* ============================================== the bench, second pass ==== */
/* Wells read as wells: an outline on every one, filled or not, so the grid of
   positions is visible rather than inferred from the labels that happen to be
   in it. */
.plate .well { border: 1px solid var(--line); background: var(--paper); }
.plate .well:not(.filled) { border-style: dashed; opacity: .75; }
.plate.withphotos .well { min-height: 92px; }
.plate.withphotos .well .wthumb { height: 46px; }
.plate .well .winline {
  width: 100%; border: 1px solid var(--accent); border-radius: 4px; padding: 1px 3px;
  font: 600 12px/1.2 inherit; background: var(--paper);
}
/* a well carried across in a transfer wears its block's colour */
.plate .well[data-block]:not([data-block=""]) {
  box-shadow: inset 0 0 0 2px var(--bc);
  border-color: var(--bc);
}
.plate .well.src.filled:not([data-block]):not(.picked) { opacity: .6; }
.plate .well .wto { font-size: 9px; font-weight: 700; }

.molbar { row-gap: 8px; }
.paintpick { display: flex; gap: 4px; flex-wrap: wrap; align-items: center; }
.paintpick .gelkey, .paintpick .primer-chip { cursor: pointer; border: 2px solid transparent; }
.paintpick .gelkey.on, .paintpick .primer-chip.on { border-color: var(--ink); }
.pickcount {
  padding: 2px 9px; border-radius: 20px; background: var(--accent); color: #fff;
  font-size: 11px; font-weight: 700;
}
.stagebar { gap: 10px; flex-wrap: wrap; align-items: center; margin: 8px 0 4px; }
.stages { display: flex; gap: 0; flex-wrap: wrap; }
.stagestep {
  border: 1px solid var(--line); background: var(--paper); color: var(--ink-2);
  padding: 4px 12px; font-size: 12px; font-weight: 600; cursor: pointer;
  border-right-width: 0;
}
.stages .stagestep:first-child { border-radius: 7px 0 0 7px; }
.stages .stagestep:last-child { border-radius: 0 7px 7px 0; border-right-width: 1px; }
.stagestep:hover { background: var(--paper-2); }
.stagestep.past { background: var(--paper-2); color: var(--ink-3, #999); }
.stagestep.on { background: var(--accent); border-color: var(--accent); color: #fff; }

.srcplate { margin-top: 10px; }
.blockkey { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; }
.blockchip {
  font-size: 11px; padding: 2px 9px; border-radius: 20px;
  border: 2px solid var(--bc); color: var(--ink); background: var(--paper);
}
.swatch { width: 22px; height: 22px; border-radius: 5px; border: 1px solid var(--line); cursor: pointer; padding: 0; }

.mmlist { display: grid; grid-template-columns: repeat(auto-fill, minmax(310px, 1fr)); gap: 12px; align-items: start; }
.mmcard { margin: 0; }

/* the catalogue, folded into a plate page */
.molbrowse { margin-top: 14px; }
.molbrowse-body { margin-top: 10px; max-height: 62vh; overflow: auto; }
.molpick {
  width: 26px; height: 26px; border-radius: 7px; border: 1px solid var(--line);
  background: var(--paper); cursor: pointer; font-weight: 700; color: var(--ink-2); line-height: 1;
}
.molpick.on { background: var(--accent); border-color: var(--accent); color: #fff; }
.molgi { position: relative; border: 0; padding: 0; background: none; cursor: pointer; font: inherit; }
.molgi .tick {
  position: absolute; top: 6px; right: 6px; width: 24px; height: 24px; border-radius: 50%;
  display: grid; place-items: center; background: rgba(0,0,0,.5); color: #fff; font-weight: 700; font-size: 13px;
}
.molgi.picked .tick { background: var(--accent); }
.molgi.picked { outline: 3px solid var(--accent); outline-offset: -3px; border-radius: 10px; }

/* ======================================================= on a phone ======= */
/* The app is used in the field, one-handed, on a screen a third the width of a
   laptop's. Everything below is about that: targets big enough to hit while
   holding a specimen, no accidental zoom when a field is focused, dialogs that
   behave like sheets rather than little floating windows, and a table that can
   be read by scrolling sideways with the ID column staying put. */

/* iOS zooms the page when a focused field is under 16px. That is never what
   you want, and it is the single biggest cause of "the phone version feels
   broken" — so every control is at least that size on a small screen. */
@media (max-width: 760px) {
  input, select, textarea, .ev, .winline { font-size: 16px !important; }
  .btn, button.chip, .tabbar button { min-height: 38px; }
  .btn.small { min-height: 34px; padding: 7px 12px; }
}

/* safe areas, so nothing hides under the notch or the home indicator */
@supports (padding: max(0px)) {
  .topbar-inner { padding-left: max(12px, env(safe-area-inset-left)); padding-right: max(12px, env(safe-area-inset-right)); }
  footer.site { padding-bottom: max(18px, env(safe-area-inset-bottom)); }
}

@media (max-width: 760px) {
  /* --- the header: mark and title, then everything else on one scrollable row.
         Its height must be free: it is sticky, and a fixed 58px with wrapped
         rows inside it is exactly how a header comes to sit on top of the page. */
  .topbar-inner { flex-wrap: wrap; row-gap: 6px; height: auto; min-height: 52px; padding-top: 8px; padding-bottom: 8px; }
  .topbar .brand span:not(.mark) { font-size: 15px; }
  .topbar .appside { order: 3; }
  .topbar .topnav.right {
    order: 4; width: 100%; margin-left: 0; overflow-x: auto; gap: 14px;
    -webkit-overflow-scrolling: touch; scrollbar-width: none; padding-bottom: 2px;
  }
  .topbar .topnav.right::-webkit-scrollbar { display: none; }
  .topbar .topnav.right a { white-space: nowrap; }

  /* --- headings and spacing get out of the way */
  h1 { font-size: 26px; line-height: 1.15; }
  h2 { font-size: 20px; }
  .lede { font-size: 15px; }
  .wrap { padding: 0 12px; }

  /* --- toolbars stack, and the search takes the full width */
  .toolbar { gap: 8px; }
  .toolbar > input, .toolbar .searchwrap { width: 100%; order: -1; }
  .toolbar .topright { width: 100%; justify-content: flex-start; overflow-x: auto; }
  .viewbar { overflow-x: auto; padding-bottom: 4px; }
  /* on a phone the fold is a proper pill, since it is the only way to get the
     filters out of the way of the records */
  details.facets-fold > summary { padding: 7px 14px; border: 1px solid var(--line); border-radius: 20px; background: var(--paper); }
  .facet-group { flex-wrap: wrap; }

  /* --- the table: scroll sideways, but keep the ID where you can see it */
  .tablewrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  table.grid td, table.grid th { padding: 10px 8px; }
  table.grid td .tag-id { padding: 4px 8px; }
  .selcol, .rowpick { min-width: 40px; }

  /* --- dialogs behave as sheets: they come up from the bottom, full width */
  /* A sheet, not a little floating window: full bleed, up from the bottom
     edge. 100vw rather than 100% because the browser's own dialog rules
     reserve a gutter that looks like a mistake at this width. */
  dialog.dlg, dialog.dlg.wide, dialog.dlg.roomy {
    max-width: 100vw; width: 100vw; margin: 0; margin-top: auto; inset: auto 0 0 0;
    border-radius: 16px 16px 0 0; border-bottom: 0; max-height: 94vh;
  }
  /* Forms whose buttons live in the body rather than a footer — the new-record
     sheet among them — pin that row too, so Save is always under the thumb. */
  dialog.dlg .entry-actions {
    position: sticky; bottom: 0; z-index: 2; margin: 12px -20px -20px; padding: 10px 16px;
    padding-bottom: max(12px, env(safe-area-inset-bottom));
    background: var(--paper); border-top: 1px solid var(--line); gap: 8px; flex-wrap: wrap;
  }
  dialog.dlg .entry-actions .btn { flex: 1 1 auto; justify-content: center; }
  dialog.dlg .entry-actions .right { display: none; }
  dialog.dlg .dlg-b { max-height: 74vh; padding-bottom: max(16px, env(safe-area-inset-bottom)); }
  dialog.dlg .dlg-f {
    position: sticky; bottom: 0; background: var(--paper); border-top: 1px solid var(--line);
    flex-wrap: wrap; gap: 8px; padding-bottom: max(12px, env(safe-area-inset-bottom));
  }
  dialog.dlg .dlg-f .btn { flex: 1 1 auto; justify-content: center; }
  .grid2 { grid-template-columns: 1fr; }
  .colpick { grid-template-columns: 1fr; }

  /* --- data entry, which is the thing worth getting right on a phone.
         One column, generous fields, and the save buttons always reachable. */
  .entry-grid { grid-template-columns: 1fr !important; gap: 14px; }
  .entry-grid > .stack { gap: 12px; }
  label.f { font-size: 13px; }
  label.f > input, label.f > select, label.f > textarea { padding: 11px 12px; }
  .f-inline { flex-direction: column; align-items: stretch; gap: 8px; }
  .fillgrid { display: block; }
  .fillgrid .fillrow {
    display: grid; grid-template-columns: 1fr; gap: 6px;
    border: 1px solid var(--line); border-radius: 10px; padding: 10px; margin-bottom: 8px;
  }

  /* --- the front door */
  .welcome { padding: 26px 0 20px; }
  .welcome-mark img { max-height: 96px; }
  .welcome-mark .mark.big { width: 74px; height: 74px; font-size: 38px; }

  /* --- galleries and tiles */
  .gallery { gap: 6px; }
  .tiles { grid-template-columns: 1fr; }
  .benchcard { margin-top: 20px; }

  /* --- the bench: plates scroll sideways, controls wrap */
  .plate { grid-template-columns: 22px repeat(var(--cols), minmax(64px, 1fr)); }
  .plate.compact { grid-template-columns: 18px repeat(var(--cols), minmax(46px, 1fr)); }
  .molnav { overflow-x: auto; flex-wrap: nowrap; }
  .molnav a { white-space: nowrap; padding: 10px 12px; }
  .molhead { padding-top: 14px; }
  .molacts { width: 100%; justify-content: flex-start; overflow-x: auto; padding-bottom: 4px; }
  .molbrowse-body { max-height: none; }
  .mmlist { grid-template-columns: 1fr; }

  /* --- the item page */
  .item-head h1 { font-size: 22px; }
  .kvlist { grid-template-columns: 108px 1fr; font-size: 14px; }
  .lb .info { max-height: 50vh; }
}

/* Narrow phones: the table becomes a list of cards, because eight columns at
   320px is not a table any more, it is a puzzle. */
@media (max-width: 560px) {
  table.grid.ascards, table.grid.ascards thead { display: none; }
  .cardlist { display: grid; gap: 8px; }
  .cardrow {
    display: grid; grid-template-columns: 54px 1fr auto; gap: 10px; align-items: center;
    border: 1px solid var(--line); border-radius: 12px; padding: 10px; background: var(--paper);
  }
  .cardrow img.thumb-s { width: 54px; height: 54px; border-radius: 8px; object-fit: cover; }
  .cardrow .cr-main { min-width: 0; }
  .cardrow .cr-main strong { display: block; }
  .cardrow .cr-sub { font-size: 12px; color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .plate { grid-template-columns: 20px repeat(var(--cols), minmax(58px, 1fr)); }
}

/* Standing on its own on the home screen there is no browser bar, so the app's
   own header is the only thing between the content and the clock. */
@media (display-mode: standalone) {
  .topbar { padding-top: max(6px, env(safe-area-inset-top)); }
  body { overscroll-behavior-y: none; }
}

/* A wide table on a narrow screen: fold each row into a small card, with every
   value carrying the heading it belongs to. Only tables marked `stackable`,
   so the plates and the short admin lists are left as they are. */
@media (max-width: 560px) {
  table.grid.stackable, table.grid.stackable tbody, table.grid.stackable tr, table.grid.stackable td { display: block; width: auto; }
  table.grid.stackable thead { display: none; }
  table.grid.stackable tr {
    border: 1px solid var(--line); border-radius: 12px; margin-bottom: 8px; padding: 8px 10px;
    background: var(--paper); position: relative;
  }
  table.grid.stackable tr.sel { outline: 2px solid var(--accent); outline-offset: -2px; }
  table.grid.stackable td {
    border: 0; padding: 4px 0; display: grid; grid-template-columns: 104px 1fr; gap: 10px; align-items: center;
  }
  table.grid.stackable td::before {
    content: attr(data-label); font-size: 11px; font-weight: 700; letter-spacing: .04em;
    text-transform: uppercase; color: var(--ink-3, #999);
  }
  table.grid.stackable td[data-label=""]::before, table.grid.stackable td:not([data-label])::before { content: none; }
  table.grid.stackable td[data-label=""], table.grid.stackable td:not([data-label]) { display: block; }
  /* the photograph heads the card rather than becoming a labelled row of its own */
  table.grid.stackable td:has(> img.thumb-s), table.grid.stackable td:has(> span.thumb-s) {
    display: block; float: right; margin: 0 0 4px 10px; width: 62px;
  }
  table.grid.stackable td > img.thumb-s { width: 62px; height: 62px; border-radius: 9px; object-fit: cover; }
  table.grid.stackable tr::after { content: ''; display: block; clear: both; }
  table.grid.stackable td.num { justify-items: start; }
  table.grid.stackable td.selcol { position: absolute; top: 6px; right: 6px; padding: 0; }
  table.grid.stackable .rowpick { width: 30px; height: 30px; }
  /* the batch entry grid is the same shape, and wants its ID prominent */
  table.grid.entry-batch tr { padding: 10px 12px; }
  table.grid.entry-batch td .cellbtn, table.grid.entry-batch td input, table.grid.entry-batch td select { width: 100%; }
}

/* ============================================ the bench, third pass ======= */
/* µL is a unit, not a word: this heading opts out of the uppercase treatment
   that would otherwise render it "ML". */
table.grid th.asis { text-transform: none; letter-spacing: 0; }

/* A well is a drag handle first. Selecting the text inside one turns every
   attempted drag into a highlight, which is what made a plate with no
   photographs on it feel stuck. */
.plate .well { user-select: none; -webkit-user-select: none; touch-action: manipulation; }
.plate .well.filled { cursor: grab; }
.plate .well.filled:active { cursor: grabbing; }
.plate .well.dragging { opacity: .4; }
/* the ID itself is the one part that means "change me" */
.plate .well .wcode { cursor: text; border-radius: 3px; padding: 0 2px; margin: 0 -2px; }
.plate .well.filled .wcode:hover { background: color-mix(in srgb, var(--accent) 16%, transparent); }

/* The editor is laid over the well, so nothing on the plate moves while you
   type. A grid that shuffles under the cursor is much harder to work in. */
.plate .well { position: relative; }
.plate .well .winline {
  position: absolute; inset: 14px 3px 3px; width: auto; z-index: 3;
  border: 1px solid var(--accent); border-radius: 4px; padding: 1px 3px;
  font: 600 12px/1.2 inherit; background: var(--paper); box-shadow: 0 2px 8px rgba(0,0,0,.12);
}
.plate .well.editing { z-index: 4; }

/* a note is worth seeing from across the plate */
.plate .well .wnote {
  position: absolute; top: 2px; right: 2px; width: 15px; height: 15px; padding: 0; line-height: 1;
  border: 0; border-radius: 4px; background: var(--accent); color: #fff; font-size: 9px; cursor: pointer;
}
.plate.compact .well .wnote { width: 12px; height: 12px; font-size: 8px; }
.plate .well.hasnote { border-color: var(--accent); }

/* One outline round a whole block, not one round each of its cells. A block
   runs down a column, so the sides are always edges and only the ends vary. */
.plate .well[data-block]:not([data-block=""]) {
  box-shadow: none;
  border-color: var(--bc);
  border-left: 2px solid var(--bc); border-right: 2px solid var(--bc);
  border-top: 2px solid transparent; border-bottom: 2px solid transparent;
  border-radius: 0;
}
/* these must out-specify the rule above, which opens the middles */
.plate .well[data-block]:not([data-block=""])[data-edge*="t"] { border-top: 2px solid var(--bc); border-radius: 7px 7px 0 0; }
.plate .well[data-block]:not([data-block=""])[data-edge*="b"] { border-bottom: 2px solid var(--bc); border-radius: 0 0 7px 7px; }
.plate .well[data-block]:not([data-block=""])[data-edge*="t"][data-edge*="b"] { border-radius: 7px; }

/* Picking must never look like a block colour, or you cannot tell whether a
   coloured well is one you have just chosen. So it is a dashed accent ring
   plus a lift, which no block ever wears. */
.plate .well.picked {
  outline: 3px dashed var(--ink); outline-offset: -3px;
  box-shadow: 0 2px 10px rgba(0,0,0,.22); z-index: 2;
}
.plate .well.picked::after {
  content: '✓'; position: absolute; left: 2px; bottom: 1px; font-size: 10px; font-weight: 800; color: var(--ink);
}

/* Photographs sit on black, as they do everywhere else in the app — that is
   what these are lit and shot for. Taller, never wider: a plate that needs
   scrolling to see both ends is worse than one with smaller pictures. */
.plate.withphotos .well { min-height: 84px; }
.plate.withphotos .well .wthumb {
  height: 40px; width: 100%; object-fit: contain; background: #000; border-radius: 3px;
}
.plate.compact.withphotos .well { min-height: 62px; }
.plate.compact.withphotos .well .wthumb { height: 28px; }
/* the plate may use the whole window rather than the reading column */
.mol .platewrap { margin-left: calc(50% - 50vw + 12px); margin-right: calc(50% - 50vw + 12px); padding: 2px 12px; }
.mol .srcplate .platewrap { margin-left: 0; margin-right: 0; padding: 2px; }
@media (max-width: 1100px) { .mol .platewrap { margin-left: 0; margin-right: 0; padding: 2px; } }

/* the browser's tiles on black too */
.molgi img { background: #000; }

/* ===================================== the taxon overview, adjusted ======= */
/* The count sits above and the name gets the whole bottom line, which is what
   a long binomial needs on a narrow tile. */
.ttile .tbar { display: flex; flex-direction: column; align-items: flex-start; gap: 1px; }
.ttile .tbar .tn { font-size: 10.5px; opacity: .8; }
.ttile .tbar .tt { width: 100%; }
.ttile .tbar .tt strong { display: block; line-height: 1.15; }

/* On a touch screen the first tap arms a tile — showing what it offers — and
   the second opens it. Armed, its buttons come forward. */
.ttile.armed { outline: 2px solid var(--accent); outline-offset: -2px; }
.ttile.armed .tacts-top { opacity: 1; transform: none; }

/* the back chip stands slightly apart from the filters beside it */
.chip.back { font-weight: 700; border-color: var(--accent); color: var(--accent); }

@media (max-width: 760px) {
  .ttile .tbar .tt strong { font-size: 12.5px; }
  .ttile .tbar .tn { font-size: 10px; }
  /* Not forced visible any more. A touch device arms a tile on the first tap
     (see typesView) and the buttons appear then — which is what the wider
     layout has always done, and what makes a 180px tile readable at all: three
     controls drawn permanently over a small photograph cover most of the
     animal you are trying to look at. */
  .typegrid { gap: 10px; }
  /* A button that only appears on hover is invisible on a touch screen, and an
     invisible button is not a button. Same treatment as the tile's own. */
  .gi .gphoto { opacity: .92; }
}

/* ================================== the phone, second pass =============== */
/* iOS zooms whenever a focused control is under 16px, and does not zoom back
   out afterwards. The earlier rule missed the ones that only exist inside a
   plate or an inline editor, which is exactly where a lot of typing happens. */
@media (max-width: 900px) {
  input, select, textarea, button, .ev, .winline, .cellbtn,
  .plate .well .winline, table.grid td input, table.grid td select, dialog input, dialog select, dialog textarea {
    font-size: 16px !important;
  }
  /* the well's own text may stay small — it is not a form control */
  .plate .well .wcode, .plate .well .wname, .plate .well .wprimer { font-size: inherit !important; }
  .plate .well .wcode { font-size: 12px !important; }
  .plate .well .wname { font-size: 9px !important; }
  .plate .well .wprimer { font-size: 9px !important; }
}

/* Landscape on a notched iPhone: the Dynamic Island eats into one side, so the
   whole page — not just the header — keeps clear of both insets. */
@supports (padding: max(0px)) {
  /* Phones only. Without the width bound this applied to every desktop window
     in landscape — which is all of them — and pushed dialogs to the left edge. */
  @media (orientation: landscape) and (max-width: 960px) and (hover: none) {
    body { padding-left: env(safe-area-inset-left); padding-right: env(safe-area-inset-right); }
    .topbar-inner, .wrap { padding-left: max(12px, 4px); padding-right: max(12px, 4px); }
    dialog.dlg, dialog.dlg.wide, dialog.dlg.roomy {
      width: calc(100vw - env(safe-area-inset-left) - env(safe-area-inset-right));
      margin-left: env(safe-area-inset-left);
    }
    #cmp { padding-left: env(safe-area-inset-left); padding-right: env(safe-area-inset-right); }
    #toasts { right: max(16px, env(safe-area-inset-right)); }
  }
}

/* Zooming in the compare viewer, for a finger: the wheel is not available, so
   there are buttons — and a pinch is wired up in the viewer itself. */
.cmp-zoom { display: inline-flex; gap: 2px; }
.cmp-zoom .cmp-btn { min-width: 34px; justify-content: center; }
@media (hover: none) { .cmp-hint { display: none; } .cmp-zoom { display: inline-flex; } }
/* a pinch must reach the viewer rather than zooming the whole page */
.cmp-stage { touch-action: none; }

/* ============================================ the plate, fourth pass ===== */
/* An empty well should read as a place, not as a warning. A hairline and a
   faintly recessed ground says "nothing here yet" far more quietly than a
   thick dashed box, and lets the filled wells and the block outlines carry
   all the emphasis on the plate. */
.plate .well {
  border: 1px solid var(--hair, #e4e2dc);
  background: color-mix(in srgb, var(--ink) 3%, transparent);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .5);
}
.plate .well:not(.filled) { border-style: solid; opacity: 1; }
.plate .well.filled {
  background: var(--paper);
  border-color: color-mix(in srgb, var(--ink) 22%, transparent);
  box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
}
.plate .well:hover { border-color: var(--accent); }
/* the row and column heads keep their distance rather than shouting */
.plate .phead { color: var(--ink-3, #9a9a94); font-weight: 600; }

/* what a specimen is called, for reading sequences back against the plate */
.plate .well .wname2 {
  font-size: 9px; font-style: italic; color: var(--ink-2); line-height: 1.1;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.plate.compact .well .wname2 { font-size: 8px; }

/* how wide the plate is allowed to be */
.mol .platewrap.pw-full { margin-left: calc(50% - 50vw + 12px); margin-right: calc(50% - 50vw + 12px); }
.mol .platewrap.pw-wide { margin-left: calc(50% - 42vw); margin-right: calc(50% - 42vw); }
.mol .platewrap.pw-plate { margin-left: auto; margin-right: auto; max-width: 1080px; }
.mol .platewrap.pw-narrow { margin-left: auto; margin-right: auto; max-width: 840px; }
@media (max-width: 1100px) {
  .mol .platewrap.pw-full, .mol .platewrap.pw-wide { margin-left: 0; margin-right: 0; }
}

/* the comparison basket in the catalogue panel */
.molvs {
  width: 26px; height: 26px; border-radius: 7px; border: 1px solid var(--line);
  background: var(--paper); cursor: pointer; font-size: 12px; color: var(--ink-3, #999); line-height: 1;
}
.molvs.on { background: var(--ink); border-color: var(--ink); color: #fff; }
.molgi .vs {
  position: absolute; top: 6px; left: 6px; width: 24px; height: 24px; border-radius: 50%;
  display: grid; place-items: center; background: rgba(0,0,0,.5); color: #fff; font-size: 12px; cursor: pointer;
}
.molgi.inversus .vs { background: var(--ink); }
.molgi.inversus { outline: 3px solid var(--ink); outline-offset: -3px; border-radius: 10px; }
.vscount {
  padding: 2px 9px; border-radius: 20px; background: var(--ink); color: #fff; font-size: 11px; font-weight: 700;
}

/* rename, from the list */
.renamebtn {
  border: 0; background: none; cursor: pointer; color: var(--ink-3, #aaa); font-size: 12px;
  padding: 0 4px; opacity: 0; transition: opacity .12s;
}
tr:hover .renamebtn { opacity: 1; }
.renamebtn:hover { color: var(--accent); }

.mmcard.livecard { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
/* the photo-view selector holds its place when photographs are off, so the
   checkbox beside it never moves out from under the cursor */
.stagebar .phview.idle { visibility: hidden; pointer-events: none; }
.stagebar { flex-wrap: wrap; }

/* ================================================== the site around it ==== */
/* The front page is a hall, not a room: three doors and as little else as it
   can get away with. Deliberately unlike the catalogue's chrome, so that
   arriving here does not feel like arriving in the catalogue by mistake. */
.sitebar { border-bottom: 1px solid var(--line); background: var(--paper); }
.sitebar .row { align-items: center; gap: 16px; padding: 14px 0; }
.sitemark { display: flex; align-items: center; gap: 10px; text-decoration: none; color: inherit; font-weight: 650; }
.sitemark img { height: 30px; max-width: 140px; object-fit: contain; border-radius: 7px; }
.sitemark .mark {
  display: grid; place-items: center; width: 30px; height: 30px; border-radius: 9px;
  background: var(--accent); color: #fff; font-weight: 700; font-size: 15px;
}
.sitefront { padding-bottom: 46px; }
.sitehead { padding: 54px 0 30px; max-width: 62ch; }
.sitehead h1 { margin: 0 0 6px; font-size: clamp(30px, 5vw, 46px); }
.sitehead .lede { margin: 0; }

.panels { display: grid; gap: 18px; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); }
.panel {
  display: flex; flex-direction: column; gap: 6px; min-height: 210px; padding: 22px 22px 18px;
  border: 1px solid var(--line); border-radius: 16px; background: var(--paper-2);
  text-decoration: none; color: inherit; position: relative; overflow: hidden;
  transition: transform .12s ease, box-shadow .12s ease, border-color .12s ease;
}
.panel::before { content: ''; position: absolute; inset: 0 0 auto; height: 4px; background: var(--accent); }
.panel:hover { transform: translateY(-3px); box-shadow: var(--shadow-lift); border-color: var(--accent); text-decoration: none; }
.panel .pglyph { font-size: 26px; color: var(--accent); line-height: 1; margin-bottom: 4px; }
.panel h2 { margin: 0; font-size: 21px; }
.panel p { margin: 0; font-size: 14px; }
.panel .pend { margin-top: auto; padding-top: 14px; display: block; }
.panel .pfoot { display: block; font-weight: 600; color: var(--accent); }
.panel .pguest { display: block; font-size: 12.5px; line-height: 18px; height: 18px; color: var(--ink-3); margin-top: 4px; }
.panel .pguest a { color: inherit; text-decoration: none; }
.panel .pguest a:hover { color: var(--accent); text-decoration: underline; }
/* a door you have not been given a key to: still named, plainly shut */
.panel.shut { opacity: .55; cursor: default; }
.panel.shut:hover { transform: none; box-shadow: none; border-color: var(--line); }
.panel.shut .pfoot { color: var(--ink-3); font-weight: 500; }
.centre { text-align: center; }

/* tools */
.toolgrid.dimmed { opacity: .5; }
.tile.tool.shut { cursor: default; }
.tile.tool.shut:hover { transform: none; box-shadow: none; }
.toolpage .toolhead { align-items: flex-start; padding: 26px 0 0; gap: 12px; }
.toolpage .mol { padding: 0; }
.toolpage .molnav { margin-top: 14px; }
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
/* A tick-list of accounts. Named for what it is rather than reusing .chip,
   which the catalogue's filter bar already owns — the first version of this
   rule redefined that class and quietly changed every filter chip in the app. */
.ticklist { display: flex; flex-wrap: wrap; gap: 6px; }
.ticklist label {
  display: inline-flex; align-items: center; gap: 5px; padding: 4px 9px; font-size: 13px;
  border: 1px solid var(--hair); border-radius: 999px; background: var(--paper);
}
/* a picked sample row reads like a picked well */
tr.clickrow.picked > td { background: color-mix(in srgb, var(--accent) 9%, transparent); }

@media (max-width: 700px) {
  .sitehead { padding: 34px 0 22px; }
  .panels { grid-template-columns: 1fr; }
  .panel { min-height: 0; }
}

/* ============================================ maps, second pass =========== */
.mapctl { display: flex; flex-direction: column; gap: 6px; align-items: flex-start; }

/* The coordinate picker's own corner: locate, and what is currently chosen.
   Inside the map so it survives any window the dialog finds itself in. */
.coordhud {
  display: flex; align-items: center; gap: 6px;
  background: rgba(255,255,255,.92); backdrop-filter: blur(4px);
  border: 1px solid var(--hair); border-radius: 8px; padding: 4px 6px;
  box-shadow: 0 1px 4px rgba(0,0,0,.18);
}
.coordhud .coordnow { font-size: 11.5px; color: var(--ink-2); white-space: nowrap; }
@media (max-width: 760px), (max-height: 560px) {
  .coordhud { padding: 3px 5px; gap: 5px; }
  .coordhud .coordnow { font-size: 10.5px; }
}

/* The credit line.

   Leaflet lets it grow to whatever the text needs, and "Sentinel-2 cloudless
   2020 by EOX (CC BY-NC-SA 4.0), contains Copernicus data" needs two lines
   across the whole width of a phone — landing on top of the basemap and pin
   controls in the opposite corner. It has to stay legible and present, because
   these providers require the credit; it does not have to eat the map. So on a
   small screen it is one line, clipped, and a tap opens it out. */
.leaflet-control-attribution { max-width: 60%; }
@media (max-width: 760px), (max-height: 560px) {
  .leaflet-control-attribution {
    max-width: 54vw; font-size: 9.5px; line-height: 1.35; padding: 1px 5px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .leaflet-control-attribution.open {
    white-space: normal; max-width: 76vw; font-size: 10.5px;
  }
  /* and the controls sit clear of it either way */
  .leaflet-bottom.leaflet-left .mapctl { margin-bottom: 22px; }
}
.basepick {
  display: flex; gap: 4px; align-items: center; padding: 4px;
  background: color-mix(in srgb, var(--card) 88%, transparent); border-radius: 10px;
  border: 1px solid var(--hair); backdrop-filter: blur(4px);
}
.basepick .btn { padding: 2px 9px; font-size: 12px; }
.basepick .pinsize { width: 84px; margin: 0 4px; }

/* a specimen shown where it was collected */
.photopin { background: none; border: 0; }
.photopin .pp {
  display: block; border-radius: 7px; overflow: hidden; background: #0b0d10;
  border: 2px solid rgba(255,255,255,.9); box-shadow: 0 2px 8px rgba(0,0,0,.35);
}
.photopin .pp img { width: 100%; height: 100%; object-fit: contain; display: block; }
.photopin:hover .pp { border-color: var(--accent); z-index: 500; }

/* the popup photograph, letterboxed on black like everywhere else */
.map-pop .mp-shot {
  width: 100%; max-width: 210px; aspect-ratio: 4/3; background: #0b0d10;
  border-radius: 6px; margin-bottom: 7px; display: grid; place-items: center; overflow: hidden;
}
.map-pop .mp-shot img { width: 100%; height: 100%; object-fit: contain; margin: 0; border-radius: 0; background: none; }

/* picking a place */
.coordmap { height: min(62vh, 560px); min-height: 240px; border-radius: 10px; overflow: hidden; border: 1px solid var(--hair); }
@media (max-width: 760px) { .coordmap { height: 52vh; } }
/* A phone held sideways is 390px tall. A 320px minimum plus a heading, a line
   of help, a readout and a button row does not fit in that, so the map grew
   past the window and carried the buttons under it. Height has to answer to
   the *short* side — which is a question about height, not width: a landscape
   phone is 852px wide and matched none of the phone rules. */
@media (max-height: 560px) {
  /* Deliberately shorter than the body that holds it. The map used to be
     taller than the space it had, so the basemap buttons in its bottom corner
     sat below the fold and the dialog had to be scrolled to reach them — on
     the one screen where scrolling is least obvious. */
  .coordmap { height: 50vh; min-height: 140px; }
  /* the instruction and the readout both live in the map's corner too, so on a
     390px-tall window the map gets their space instead */
  .coordhelp, .coordfoot { display: none; }
  dialog.dlg .dlg-h { padding-top: 10px; padding-bottom: 6px; }
  dialog.dlg .dlg-h h3 { font-size: 16px; }
  dialog.dlg .dlg-b { max-height: 62vh; overflow: auto; }
  dialog.dlg .dlg-f {
    position: sticky; bottom: 0; background: var(--paper); z-index: 2;
    border-top: 1px solid var(--line); padding-bottom: max(10px, env(safe-area-inset-bottom));
  }
  dialog.dlg .entry-actions {
    position: sticky; bottom: 0; z-index: 2; background: var(--paper);
    border-top: 1px solid var(--line); padding: 8px 0;
  }
  dialog.dlg .dlg-grab { display: none; }
}


/* ================================== the offline probe ==================== */
/* A measuring instrument: a list of readings, each with what it means beside
   it. Deliberately plain — it is read once on a phone in a hurry. */
.probe { display: grid; gap: 2px; }
.probe-row {
  display: grid; grid-template-columns: 190px minmax(120px, auto) 1fr;
  gap: 10px; align-items: baseline; padding: 6px 0; border-bottom: 1px solid var(--hair);
}
.probe-row:last-child { border-bottom: 0; }
.probe-k { font-weight: 600; font-size: 13.5px; color: var(--ink-2); }
.probe-v { font-size: 14px; }
.probe-bar { height: 8px; border-radius: 5px; background: var(--paper-2); overflow: hidden; border: 1px solid var(--hair); }
.probe-bar i { display: block; height: 100%; width: 0; background: var(--accent); transition: width .15s linear; }
@media (max-width: 760px) {
  .probe-row { grid-template-columns: 1fr; gap: 1px; padding: 8px 0; }
  .probe-k { font-size: 12.5px; }
}

/* Reading a stored copy rather than the catalogue. Says so once, at the foot
   of the screen, and can be put away — it is information, not an alarm. */
.offbar {
  position: fixed; left: 12px; right: 12px; bottom: max(12px, env(safe-area-inset-bottom));
  z-index: 60; display: flex; gap: 10px; align-items: center; justify-content: center;
  background: var(--ink); color: var(--paper); border-radius: 10px;
  padding: 9px 12px; font-size: 13.5px; box-shadow: 0 6px 20px rgba(0,0,0,.25);
}
.offbar .btn { color: var(--paper); border-color: rgba(255,255,255,.35); }
@media (min-width: 761px) { .offbar { left: auto; right: 16px; max-width: 460px; } }
