/* =====================================================================
   eplankton — views.css
   ----------------------------------------------------------------------------
   One section per view module under web/js/views/. Until EPL-544, each view
   injected its own block at import via `document.createElement('style')` — a
   runtime <style> *element*, the style-src-elem CSP sub-resource (distinct
   from style-src-attr, which EPL-472 closed off the style attribute). Moving
   every view's CSS to this static stylesheet drops 'unsafe-inline' from
   style-src-elem too, loaded once from index.html alongside components.css
   and charts.css.

   Each section below is scoped under its view's own block class (CONTRACT §9:
   a view gets exactly one) and is read only by the module named in its
   header. Additive; no class here is shared across views.
   ========================================================================== */

/* -- web/js/views/landing.js ------------------------------------------------- */
.v-landing { display: block; width: 100%; min-width: 0; }

.v-landing .lp-wrap {
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 var(--s5);
  min-width: 0;
}

.v-landing section { scroll-margin-top: 72px; }

/* --- top bar -------------------------------------------------------------- */
.v-landing .lp-top { border-bottom: 1px solid var(--line); background: var(--bg); }
.v-landing .lp-top-inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s4); min-height: 58px;
}
.v-landing .lp-mark {
  display: inline-flex; align-items: center; gap: var(--s2);
  font-family: var(--font-display); font-weight: 600; font-size: 20px;
  text-transform: none; letter-spacing: var(--track-display);
  color: var(--text-primary);
}
.v-landing .lp-mark svg { width: 20px; height: 20px; color: var(--accent); flex: 0 0 auto; }

/* --- sticky mini-nav ------------------------------------------------------ */
.v-landing .lp-subnav {
  position: fixed; inset: 0 0 auto 0; z-index: 45;
  border-bottom: 1px solid var(--line);
  background: var(--bg);
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  -webkit-backdrop-filter: saturate(1.5) blur(14px);
  backdrop-filter: saturate(1.5) blur(14px);
  opacity: 0; visibility: hidden; transform: translateY(-100%);
  transition: opacity var(--dur-2) var(--ease), transform var(--dur-2) var(--ease),
              visibility 0s linear var(--dur-2);
}
.v-landing .lp-subnav.on {
  opacity: 1; visibility: visible; transform: none; transition-delay: 0s;
}
.v-landing .lp-subnav-inner {
  display: flex; align-items: center; gap: var(--s4);
  min-height: 46px; overflow-x: auto; overscroll-behavior-x: contain;
}
.v-landing .lp-subnav .lp-mark { font-size: 16px; flex: 0 0 auto; }
.v-landing .lp-subnav .lp-mark svg { width: 15px; height: 15px; }
.v-landing .lp-navlinks { display: flex; align-items: center; gap: var(--s4); flex: 1 1 auto; }
.v-landing .lp-navlink {
  flex: 0 0 auto;
  font-family: var(--font-ui); font-size: var(--fs-eyebrow);
  text-transform: uppercase; letter-spacing: var(--track-eyebrow);
  color: var(--text-muted); white-space: nowrap;
  padding: 4px 0; border-bottom: 1px solid transparent;
}
.v-landing .lp-navlink:hover { color: var(--text-primary); }
.v-landing .lp-navlink.on { color: var(--text-primary); border-bottom-color: var(--accent); }
.v-landing .lp-subnav .btn { flex: 0 0 auto; }

/* --- hero ----------------------------------------------------------------- */
.v-landing .lp-hero { padding: clamp(26px, 5.5vw, 76px) 0 var(--s8); }

.v-landing .lp-band {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.45fr) minmax(0, 1fr);
  gap: clamp(18px, 3vw, 44px);
  align-items: center;
}
.v-landing .lp-band.solo { grid-template-columns: minmax(0, 1fr); }

/* The one place the editorial face appears: the hero thesis and the section
   openers. Everything else in the app is Google Sans Text and Google Sans Code. */
.v-landing .lp-headline {
  font-family: var(--font-editorial); font-weight: 400; text-transform: none;
  letter-spacing: -.012em; line-height: 1.08;
  font-size: clamp(32px, 5vw, var(--ds-2xl));
  color: var(--text-primary); margin: var(--s3) 0 0;
  text-wrap: balance;
}
.v-landing .lp-headline em { font-style: italic; font-weight: 300; color: var(--accent); }

.v-landing .lp-fp { width: 100%; max-width: 420px; margin: 0 auto; min-width: 0; }
.v-landing .lp-fp-tag { display: flex; justify-content: center; margin-top: var(--s2); }

/* the specimen strip */
.v-landing .lp-strip { display: grid; gap: var(--s2); min-width: 0; }
.v-landing .lp-strip-row { overflow: hidden; min-width: 0; }
.v-landing .lp-strip-track {
  display: flex; width: max-content;
  animation: lp-drift-a var(--lp-dur, 96s) linear infinite;
}
.v-landing .lp-strip-row.rev .lp-strip-track { animation-name: lp-drift-b; }
.v-landing .lp-strip-row:hover .lp-strip-track { animation-play-state: paused; }
.v-landing .lp-cell {
  flex: 0 0 auto;
  width: var(--lp-cell, 96px);
  margin-inline-end: var(--s2);
  cursor: default;
  pointer-events: none;
}
@keyframes lp-drift-a { from { transform: translate3d(0,0,0); }      to { transform: translate3d(-50%,0,0); } }
@keyframes lp-drift-b { from { transform: translate3d(-50%,0,0); }   to { transform: translate3d(0,0,0); } }

.v-landing .lp-hero-foot {
  display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
  gap: var(--s5) var(--s7); align-items: start;
  margin-top: clamp(24px, 4vw, 56px);
  padding-top: var(--s5); border-top: 1px solid var(--line);
}
.v-landing .lp-actions { display: flex; flex-wrap: wrap; gap: var(--s2); justify-content: flex-end; }
.v-landing .lp-caption {
  margin-top: var(--s5);
  font-family: var(--font-ui); font-variant-numeric: tabular-nums;
  font-size: var(--fs-tiny); line-height: 1.7; color: var(--text-muted);
  display: flex; flex-wrap: wrap; gap: 2px var(--s3); min-width: 0;
}
.v-landing .lp-caption b { font-weight: 400; color: var(--text-primary); }
.v-landing .lp-caption .lp-dot { color: var(--line-strong); }

/* --- section furniture ---------------------------------------------------- */
.v-landing .lp-sec { padding: clamp(40px, 6vw, 84px) 0; border-top: 1px solid var(--line); }
.v-landing .lp-sec-head { max-width: 78ch; margin-bottom: clamp(20px, 3vw, 40px); }
.v-landing .lp-sec-title {
  font-family: var(--font-display); font-weight: 600; text-transform: none;
  letter-spacing: var(--track-display); line-height: 1.14;
  font-size: clamp(23px, 3.2vw, var(--ds-lg));
  color: var(--text-primary); margin-top: var(--s2);
}
.v-landing .lp-sec-lede { margin-top: var(--s3); color: var(--text-secondary); max-width: 70ch; }

/* --- pipeline steps ------------------------------------------------------- */
.v-landing .lp-steps {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  border-top: 1px solid var(--line-strong);
}
.v-landing .lp-step {
  padding: var(--s5) var(--s4) var(--s6) 0;
  border-bottom: 1px solid var(--line);
  min-width: 0;
}
.v-landing .lp-step + .lp-step { padding-left: var(--s4); border-left: 1px solid var(--line); }
.v-landing .lp-step-n { color: var(--text-muted); }
.v-landing .lp-step-name { margin-top: var(--s1); }
.v-landing .lp-fig {
  display: flex; align-items: baseline; gap: var(--s2);
  margin: var(--s3) 0 var(--s4); min-width: 0;
}
.v-landing .lp-fig-v {
  font-family: var(--font-display); font-weight: 700; line-height: .9;
  font-size: clamp(30px, 3.6vw, var(--ds-lg));
  letter-spacing: var(--track-display); font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}
.v-landing .lp-fig-u {
  font-family: var(--font-ui); font-size: var(--fs-eyebrow);
  text-transform: uppercase; letter-spacing: var(--track-eyebrow);
  color: var(--text-muted); min-width: 0;
}
.v-landing .lp-step .kv { grid-template-columns: minmax(0, 1fr); gap: var(--s1) 0; }
.v-landing .lp-step .kv dd { margin-bottom: var(--s2); }
/* `.kv dt`'s base `white-space: nowrap` keeps a label beside its value on one
   line in the two-column layout; stacked single-column here, a long label
   (step 04's "Biovolume (…)" key names the whole model) instead overflows
   the step's own track with no wider box to catch it, which is what pushed
   `.lp-steps` past its column and scrolled the page sideways (EPL-1109). */
.v-landing .lp-step .kv dt { white-space: normal; overflow-wrap: anywhere; }

/* --- chart pairs ---------------------------------------------------------- */
.v-landing .lp-pair {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s4);
  align-items: start;
}
.v-landing .lp-chart { min-width: 0; }

/* --- calibration ---------------------------------------------------------- */
.v-landing .lp-cal {
  display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  gap: clamp(20px, 3vw, 44px); align-items: start;
}
.v-landing .lp-honest { display: grid; gap: var(--s4); min-width: 0; }
.v-landing .lp-honest p { color: var(--text-secondary); max-width: 60ch; }

/* --- compare -------------------------------------------------------------- */
.v-landing .lp-ans { display: grid; gap: 2px; min-width: 0; }
.v-landing .lp-ans-key {
  font-size: var(--fs-eyebrow); text-transform: uppercase;
  letter-spacing: var(--track-eyebrow); color: var(--text-muted);
}
.v-landing .lp-ans-text { color: var(--text-secondary); font-size: var(--fs-small); line-height: 1.5; }
.v-landing .lp-compare .table td,
.v-landing .lp-compare .table th { vertical-align: top; padding-top: var(--s3); padding-bottom: var(--s3); }

/* --- footer --------------------------------------------------------------- */
.v-landing .lp-foot { border-top: 1px solid var(--line); padding: var(--s8) 0 var(--s9); }
.v-landing .lp-foot-grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--s6); align-items: start;
}
.v-landing .lp-links { display: grid; gap: var(--s2); }
.v-landing .lp-links a { color: var(--text-secondary); font-size: var(--fs-small); width: fit-content; }
.v-landing .lp-links a:hover { color: var(--text-primary); }

/* --- scroll reveal -------------------------------------------------------- */
.v-landing [data-reveal] {
  opacity: 0; transform: translate3d(0, 24px, 0);
  transition: opacity 520ms var(--ease), transform 520ms var(--ease);
  transition-delay: calc(var(--i, 0) * 60ms);
}
.v-landing [data-reveal].in { opacity: 1; transform: none; }

/* --- responsive ----------------------------------------------------------- */
@media (max-width: 1080px) {
  .v-landing .lp-band { grid-template-columns: minmax(0, 1fr); gap: var(--s6); }
  .v-landing .lp-band > .lp-copy { order: 1; }
  .v-landing .lp-band > .lp-strip-wrap { order: 2; }
  .v-landing .lp-band > .lp-fp-wrap { order: 3; }
  .v-landing .lp-fp { max-width: 360px; }
  .v-landing .lp-steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .v-landing .lp-step:nth-child(3) { padding-left: 0; border-left: 0; }
}
@media (max-width: 900px) {
  .v-landing .lp-pair,
  .v-landing .lp-cal { grid-template-columns: minmax(0, 1fr); }
  .v-landing .lp-foot-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 720px) {
  .v-landing .lp-hero-foot { grid-template-columns: minmax(0, 1fr); }
  .v-landing .lp-actions { justify-content: flex-start; }
}
@media (max-width: 640px) {
  .v-landing .lp-wrap { padding: 0 var(--s4); }
  .v-landing .lp-steps { grid-template-columns: minmax(0, 1fr); }
  .v-landing .lp-step { padding-right: 0; }
  .v-landing .lp-step + .lp-step { padding-left: 0; border-left: 0; }
  .v-landing .lp-foot-grid { grid-template-columns: minmax(0, 1fr); }
  .v-landing .lp-cell { --lp-cell: 84px; }
  /* three columns of prose do not fit 390px: the table scrolls in its own
     container instead of wrapping into a stack of single words (CONTRACT §8) */
  .v-landing .lp-compare .table { min-width: 660px; }
}
@media (max-width: 420px) {
  .v-landing .lp-wrap { padding: 0 var(--s3); }
  .v-landing .lp-headline { font-size: clamp(30px, 9vw, 44px); }
}

/* --- reduced motion ------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .v-landing .lp-strip-track { animation: none; }
  .v-landing .lp-strip-row { overflow-x: auto; }
  .v-landing [data-reveal] { opacity: 1; transform: none; transition: none; }
  .v-landing .lp-subnav { transition: none; }
}

/* -- web/js/views/auth.js ---------------------------------------------------- */
.v-auth{min-height:100dvh;display:grid;grid-template-columns:minmax(0,1fr);
  grid-template-rows:auto minmax(0,1fr);background:var(--bg);}
.v-auth-col{min-width:0;background:var(--surface-1);display:flex;flex-direction:column;
  justify-content:center;padding:var(--s7) var(--s5) var(--s8);}
.v-auth-inner{width:100%;max-width:412px;margin:0 auto;min-width:0;}
.v-auth-brand{display:inline-flex;align-items:baseline;gap:var(--s2);
  font-family:var(--font-display);font-weight:600;text-transform:none;
  letter-spacing:var(--track-display);font-size:var(--fs-2xl);line-height:1;
  color:var(--text-primary);text-decoration:none;}
.v-auth-brand:hover{color:var(--accent);}
.v-auth-brand:focus-visible{box-shadow:var(--ring);border-radius:var(--r-sm);}
.v-auth-head{margin:var(--s7) 0 var(--s6);}
.v-auth-head h1{margin:var(--s2) 0 0;}
.v-auth-lede{margin-top:var(--s3);color:var(--text-secondary);font-size:var(--fs-small);
  max-width:46ch;}
.v-auth-form{display:grid;gap:var(--s5);min-width:0;}
.v-auth-submit{width:100%;justify-content:center;}
.v-auth-alt{margin-top:var(--s6);padding-top:var(--s5);border-top:1px solid var(--line);
  color:var(--text-secondary);font-size:var(--fs-small);}
.v-auth-alt a{color:var(--accent);}
.v-auth-alt p+p{margin-top:var(--s2);}

/* --- ambient band / panel ------------------------------------------------ */
.v-auth-ambient{position:relative;overflow:hidden;min-width:0;background:var(--bg);
  border-bottom:1px solid var(--line);display:flex;flex-direction:column;
  justify-content:center;padding:var(--s4) var(--s5);}
.v-auth-sprite{position:absolute;pointer-events:none;opacity:.14;
  right:-56px;top:50%;width:200px;height:200px;transform:translateY(-50%);}
.v-auth-sprite>svg{width:100%;height:100%;transform-origin:50% 50%;
  animation:ep-auth-spin 240s linear infinite;}
.v-auth-facts{position:relative;z-index:1;display:flex;flex-wrap:nowrap;
  align-items:baseline;gap:var(--s5);overflow-x:auto;overflow-y:hidden;
  scrollbar-width:none;padding-right:120px;}
.v-auth-facts::-webkit-scrollbar{display:none;}
.v-auth-fact{display:flex;align-items:baseline;gap:var(--s2);flex:0 0 auto;min-width:0;}
.v-auth-fact-n{font-family:var(--font-ui);font-variant-numeric:tabular-nums;
  font-size:var(--fs-base);line-height:1.1;color:var(--text-primary);white-space:nowrap;}
.v-auth-fact-l{white-space:nowrap;}
.v-auth-facts>.ep-skeleton{width:min(240px,60vw);max-height:18px;overflow:hidden;}
.v-auth-badge{position:relative;z-index:1;margin-top:var(--s3);display:none;
  align-self:flex-start;max-width:100%;}
@keyframes ep-auth-spin{from{transform:rotate(0deg);}to{transform:rotate(360deg);}}

/* --- strength meter ------------------------------------------------------ */
.v-auth-meter{display:flex;gap:4px;margin-top:var(--s1);}
.v-auth-meter i{display:block;height:3px;flex:1 1 0;border-radius:var(--r-full);
  background:var(--line-strong);transition:background-color var(--dur-2) var(--ease);}
.v-auth-meter i.on{background:var(--accent);}

.v-auth-retry{display:grid;gap:var(--s3);border:1px solid var(--status-critical);
  border-radius:var(--r-md);padding:var(--s3);background:var(--status-critical-wash);}
.v-auth-retry p{font-size:var(--fs-small);color:var(--text-primary);}

@media (min-width:900px){
  .v-auth{grid-template-columns:minmax(0,1fr) minmax(0,1fr);grid-template-rows:minmax(0,1fr);}
  .v-auth-col{order:1;padding:var(--s9) var(--s8);border-right:1px solid var(--line);}
  .v-auth-ambient{order:2;border-bottom:0;justify-content:flex-end;
    padding:var(--s8) var(--s8) var(--s9);}
  .v-auth-sprite{right:auto;left:50%;top:44%;width:min(132%,1040px);height:auto;
    aspect-ratio:1/1;transform:translate(-50%,-50%);opacity:.16;}
  .v-auth-facts{flex-direction:column;align-items:flex-start;gap:var(--s6);
    overflow:visible;padding-right:0;}
  .v-auth-facts>.ep-skeleton{width:260px;max-height:none;}
  .v-auth-fact{flex-direction:column;align-items:flex-start;gap:var(--s1);}
  .v-auth-fact-n{font-size:var(--ds-md);line-height:1;}
  .v-auth-fact-l{white-space:normal;}
  .v-auth-badge{display:inline-flex;}
}
@media (min-width:1280px){
  .v-auth{grid-template-columns:minmax(0,520px) minmax(0,1fr);}
}
@media (prefers-reduced-motion:reduce){
  .v-auth-sprite>svg{animation:none;}
}

/* -- web/js/views/dashboard.js ----------------------------------------------- */
.v-dashboard .dash-id { min-width: 0; }
.v-dashboard .dash-sub { margin-top: var(--s2); color: var(--text-muted);
  font-family: var(--font-ui); font-size: var(--fs-eyebrow);
  letter-spacing: var(--track-eyebrow); text-transform: uppercase;
  font-variant-numeric: tabular-nums; }
.v-dashboard .dash-stats { margin-bottom: var(--s5); }
.v-dashboard .dash-table { min-width: 0; margin-bottom: var(--s4); }
.v-dashboard .dash-flow { columns: 2 420px; column-gap: var(--s4);
  margin-bottom: var(--s5); }
.v-dashboard .dash-flow > * { break-inside: avoid; margin-bottom: var(--s4); }
.v-dashboard .dash-toolbar { display: flex; align-items: center; gap: var(--s3);
  flex-wrap: wrap; padding: var(--s2) var(--s4);
  border-bottom: 1px solid var(--line-faint); }
.v-dashboard .dash-toolbar .search { flex: 1 1 160px; }
.v-dashboard .dash-name { display: grid; gap: 1px; min-width: 0; }
.v-dashboard .dash-name > span:first-child { color: var(--text-primary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.v-dashboard .dash-station { font-family: var(--font-ui);
  font-size: var(--fs-micro); color: var(--text-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.v-dashboard .dash-chip { display: block; }
.v-dashboard .dash-post { display: flex; align-items: flex-start; gap: var(--s3);
  padding: var(--s3) var(--s4); border-bottom: 1px solid var(--line-faint);
  color: inherit; text-decoration: none; min-width: 0; }
.v-dashboard .dash-post:last-child { border-bottom: 0; }
.v-dashboard .dash-post:hover { background: var(--surface-hover); }
.v-dashboard .dash-post:focus-visible { box-shadow: var(--ring); border-radius: var(--r-sm); }
.v-dashboard .dash-post-main { min-width: 0; flex: 1 1 auto; display: grid; gap: 2px; }
.v-dashboard .dash-post-who { display: flex; align-items: baseline; gap: var(--s2);
  min-width: 0; flex-wrap: wrap; }
.v-dashboard .dash-post-body { color: var(--text-secondary);
  font-size: var(--fs-small); line-height: 1.45; display: -webkit-box;
  -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.v-dashboard .dash-model-foot { display: flex; align-items: center;
  justify-content: space-between; gap: var(--s3); flex-wrap: wrap; }
.v-dashboard .dash-first-steps { list-style: none; margin: 0; padding: 0;
  counter-reset: step; display: grid; gap: var(--s5);
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.v-dashboard .dash-first-step { counter-increment: step; min-width: 0;
  display: grid; gap: var(--s2); align-content: start; }
.v-dashboard .dash-first-step::before { content: counter(step, decimal-leading-zero);
  font-family: var(--font-ui); font-size: var(--fs-micro); color: var(--text-muted); }
.v-dashboard .dash-first-name { margin: 0; font-size: var(--fs-base); }
.v-dashboard .dash-first-step p { margin: 0; color: var(--text-secondary); line-height: 1.5; }
.v-dashboard .dash-first-step .btn { justify-self: start; }
.v-dashboard .dash-first-kinds { margin: 0; padding: 0; list-style: none; display: grid; gap: var(--s3); }
.v-dashboard .dash-first-kinds li { display: grid; gap: 2px; }
.v-dashboard .dash-first-kinds span { color: var(--text-secondary); font-size: var(--fs-small); line-height: 1.5; }
.v-dashboard .dash-first-foot:not(:empty) { margin-top: var(--s5); padding-top: var(--s4);
  border-top: 1px solid var(--line-faint); color: var(--text-secondary); }
.v-dashboard .dash-first-foot p { margin: 0; }
.v-dashboard .dash-first-foot a { color: var(--accent-text); }

/* -- web/js/views/samples.js ------------------------------------------------- */
.v-samples .s-filterbar { display: flex; align-items: center; gap: var(--s3); margin-bottom: var(--s3); }
.v-samples .s-filterbar:empty { display: none; }
.v-samples .s-toolbar { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap; }
.v-samples .s-toolbar .search { flex: 1 1 200px; }
.v-samples .s-toolbar .select { flex: 0 0 auto; width: auto; }
.v-samples .s-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(196px, 1fr));
  gap: var(--s4);
}
.v-samples .s-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s3);
  padding: var(--s4);
  text-align: center;
  text-decoration: none;
  color: inherit;
}
.v-samples .s-card-fp {
  width: 132px;
  max-width: 100%;
  aspect-ratio: 1 / 1;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--r-md);
  background: var(--surface-sunken);
  border: 1px solid var(--line-faint);
  overflow: hidden;
  line-height: 0;
}
.v-samples .s-card-fp svg { width: 100%; height: 100%; display: block; }
.v-samples .s-card-name {
  max-width: 100%;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-lg);
  line-height: 1.2;
  text-transform: none;
  letter-spacing: var(--track-display);
  color: var(--text-primary);
}
.v-samples .s-card-meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-family: var(--font-ui);
  font-size: var(--fs-eyebrow);
  letter-spacing: var(--track-eyebrow);
  text-transform: uppercase;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.v-samples .s-more { display: flex; justify-content: center; padding: var(--s5) 0 var(--s2); }
/* The imaging order (EPL-890): one block per adjudicated pair, read top to
   bottom. A refusal is as tall as an order on purpose — it carries a reason
   and a question, and both are the answer. */
.v-samples .s-ord:empty { display: none; }
.v-samples .s-ord { margin-top: var(--s5); }
.v-ord .ord-intro { margin: var(--s2) 0 0; max-width: 64ch; }
.v-ord .ord-said { margin: var(--s3) 0 0; max-width: 72ch; }
.v-ord .ord-pairs { list-style: none; margin: var(--s4) 0 0; padding: 0;
  display: flex; flex-direction: column; gap: var(--s4); }
.v-ord .ord-pair { border-top: 1px solid var(--line); padding-top: var(--s4); }
.v-ord .ord-order { margin: 0; font-size: var(--fs-lg); }
.v-ord .ord-order.ord-none { color: var(--text-muted); }
.v-ord .ord-day { margin: 2px 0 0; font-size: var(--fs-eyebrow); }
.v-ord .ord-basis,
.v-ord .ord-reason,
.v-ord .ord-flag,
.v-ord .ord-confirm { margin: var(--s2) 0 0; max-width: 72ch; }
.v-ord .ord-confirm { color: var(--text-primary); }
/* The prompt's two readings, one row per Acquisition: the clock as the
   instrument wrote it and the fallback date it sits on, so a person can tell
   which boot each came from before answering. */
.v-ord .ord-runs-label { margin: var(--s2) 0 0; }
.v-ord .ord-runs { list-style: none; margin: 2px 0 0; padding: 0 0 0 var(--s3); }
.v-ord .ord-run { margin: 2px 0 0; font-variant-numeric: tabular-nums; }
.v-ord .ord-unpaired { margin: var(--s4) 0 0; max-width: 72ch; }
/* What a person answered, beside the pair and under the question: quoted,
   with who and when, so it never reads as the order the files give. */
.v-ord .ord-asserted { margin: var(--s2) 0 0; max-width: 72ch; }
.v-ord .ord-asserted:focus { outline: none; }
.v-ord .ord-asserted:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.v-ord .ord-answer { margin: var(--s2) 0 0; display: flex; flex-wrap: wrap;
  align-items: center; gap: var(--s2); }
.v-ord .ord-answer-choices { display: flex; flex-wrap: wrap; gap: var(--s2); }
.v-ord .ord-answer-status { margin: 0; flex-basis: 100%; max-width: 72ch; }
.v-ord .ord-answer-status:empty { display: none; }
.v-ord .ord-answer-failed { color: var(--text-primary); }
.v-ord .ord-answer-status:focus { outline: none; }
.v-samples .s-count { font-variant-numeric: tabular-nums; }
.v-samples .s-cell-name { display: flex; align-items: center; gap: var(--s3); min-width: 0; }
.v-samples .s-cell-name .fingerprint-chip { width: 26px; height: 26px; }
.v-samples .s-cell-title { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.v-samples .s-cell-id { font-size: var(--fs-eyebrow); }
.v-samples .card-foot { justify-content: flex-start; }
.v-samples .s-note { font-size: var(--fs-tiny); line-height: 1.45; }

/* Projects (EPL-2630): the samples index's shell; only the members list is new. */
.v-project .p-members { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--s3); }
.v-project .p-member { align-items: center; }
/* What the table download counts (EPL-2848): a sentence row under the head;
   `.spread` keeps the end free for a "classify all" button. */
.v-project .p-coverage { padding: var(--s3) var(--s4); border-bottom: 1px solid var(--line); align-items: flex-start; gap: var(--s3); }
.v-project .p-coverage-say { min-width: 0; flex: 1 1 auto; display: flex; flex-direction: column; gap: var(--s1); }
.v-project .p-coverage-say p { margin: 0; }
.v-project .p-coverage-list { font-size: var(--fs-tiny); line-height: 1.45; overflow-wrap: anywhere; }
.v-project .p-batch { flex: 0 1 22rem; min-width: 0; margin-left: auto; display: flex; flex-direction: column; align-items: flex-end; gap: var(--s2); text-align: right; }
.v-project .p-batch[hidden] { display: none; }
.v-project .p-batch p { margin: 0; }
.v-project .p-batch .progress { align-self: stretch; }
.v-project .p-batch-left { margin: 0; padding: 0; list-style: none; font-size: var(--fs-tiny); line-height: 1.45; overflow-wrap: anywhere; }
.v-project .p-member-who { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; }
.v-projects .card-foot .row.spread,
.v-project .card-foot .row.spread { width: 100%; }
@media (max-width: 720px) { .v-projects .grid.cols-2, .v-project .grid.cols-2 { grid-template-columns: minmax(0, 1fr); } }
/* Teach (EPL-2652): eight specimen tiles, each with its answer under it, and
   the accuracy chart drawn as the replicate plot is. */
.v-teach .tc-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--s4); }
.v-teach .tc-tile { display: flex; flex-direction: column; gap: var(--s2); min-width: 0; }
.v-teach .tc-pic { cursor: default; }
.v-teach .tc-tile[data-state="answered"] .tc-pic,
.v-teach .tc-tile[data-state="closed"] .tc-pic { border-color: var(--line-strong); }
.v-teach .tc-size { font-size: var(--fs-eyebrow); }
.v-teach .tc-body { display: flex; flex-direction: column; gap: var(--s2); min-width: 0; }
.v-teach .tc-guess { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.v-teach .tc-guess .taxon,
.v-teach .tc-answer .taxon { overflow-wrap: anywhere; }
.v-teach .tc-answer { display: flex; flex-direction: column; gap: 1px; }
.v-teach .tc-answer .ep-ic-check { margin-right: 4px; }
.v-teach .tc-model .tc-left { display: block; margin-top: 2px; }
.v-teach .tc-hint { font-size: var(--fs-tiny); }
.v-teach .tc-choose { display: flex; flex-direction: column; gap: var(--s1); min-width: 0; }
.v-teach .tc-chips { display: flex; flex-wrap: wrap; gap: var(--s1); }
.v-teach .tc-chip { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.v-teach .tc-actions { flex-wrap: wrap; }
.v-teach .tc-status { font-size: var(--fs-tiny); }
.v-teach .tc-note p { margin: 0; }
.v-teach .tc-batch .card-foot .row.spread { width: 100%; }
.v-teach .tc-below { margin-top: var(--s6); align-items: start; }
.v-teach .tc-wait { height: 3px; overflow: hidden; border-radius: 2px; background: var(--surface-2); }
.v-teach .tc-wait > span {
  display: block; width: 30%; height: 100%; background: var(--accent);
  animation: ep-teach-wait 1.6s var(--ease) infinite;
}
@keyframes ep-teach-wait { from { transform: translateX(-100%); } to { transform: translateX(340%); } }
@media (prefers-reduced-motion: reduce) { .v-teach .tc-wait > span { animation: none; width: 100%; opacity: 0.4; } }
.v-teach .ta-plot { display: block; width: 100%; height: auto; }
.v-teach .ta-bar { stroke: var(--text-primary); stroke-width: 1.5px; }
.v-teach .ta-dot { fill: var(--surface-1); stroke: var(--series-1); stroke-width: 2px; }
.v-teach .ta-latest .ta-dot { fill: var(--series-1); }
.v-teach .ta-line { fill: none; stroke: var(--series-1); stroke-width: 1.5px; opacity: 0.6; }
.v-teach .ta-reason,
.v-teach .ta-note { margin: 0; }
.v-teach .ta-note { margin-top: var(--s2); font-size: var(--fs-tiny); color: var(--text-secondary); }
@media (max-width: 980px) { .v-teach .tc-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 720px) { .v-teach .grid.cols-2 { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 560px) {
  .v-samples .s-grid { grid-template-columns: repeat(auto-fill, minmax(146px, 1fr)); }
  .v-samples .s-card-fp { width: 116px; }
}

/* -- web/js/views/sample.js -------------------------------------------------- */
.v-sample .sv-hero {
  display: grid;
  grid-template-columns: minmax(0, 380px) minmax(0, 1fr);
  gap: var(--s4);
  align-items: start;
}
.v-sample .sv-hero-after { margin-top: var(--s4); }
/* The acquisition record's two lists: side by side where both fit with their
   labels on one line, one under the other below that. */
.v-sample .sv-acq {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 400px), 1fr));
  gap: var(--s2) var(--s6);
  align-items: start;
}
.v-sample .sv-fp-cap {
  margin: var(--s3) 0 0;
  font-size: var(--fs-small);
  line-height: 1.5;
  color: var(--text-secondary);
}
.v-sample .sv-biovolume-top-sentence {
  margin: 0;
  font-size: var(--fs-small);
  line-height: 1.5;
  color: var(--text-secondary);
}
/* `--cell` is `.thumbstrip .imgcell`'s own sizing hook (components.css,
   the same one `.imgrid`/imagegrid.js use) — set once here rather than
   hardcoding the image's and the tile wrapper's widths separately. */
.v-sample .sv-biovolume-strip { --cell: 104px; }
.v-sample .sv-bv-tile {
  flex: 0 0 auto;
  width: var(--cell);
  display: flex;
  flex-direction: column;
  gap: var(--s1);
}
.v-sample .sv-bv-cap {
  display: flex;
  flex-direction: column;
  font-family: var(--font-ui);
  font-size: var(--fs-micro);
  line-height: 1.4;
  color: var(--text-secondary);
  text-align: center;
}
.v-sample .sv-bv-shape { color: var(--text-primary); }
.v-sample .sv-bv-ratio { color: var(--text-muted); }
.v-sample .sv-engine-card { margin-top: var(--s4); }
.v-sample .sv-engine-methods { flex: 0 0 auto; font-size: var(--fs-small); }
.v-sample .sv-engine { grid-template-columns: minmax(160px, max-content) minmax(0, 1fr); }
.v-sample .sv-engine dt { white-space: normal; }
.v-sample .sv-engine-figure { color: var(--text-primary); }
.v-sample .sv-engine-worth,
.v-sample .sv-engine-weak {
  display: block;
  font-family: var(--font-body);
  font-size: var(--fs-small);
  line-height: 1.5;
  color: var(--text-secondary);
}
.v-sample .sv-engine-note {
  margin: var(--s3) 0 0;
  font-size: var(--fs-small);
  line-height: 1.5;
  color: var(--text-secondary);
}
.v-sample .sv-engine-note:first-child { margin-top: 0; }
@media (max-width: 640px) {
  .v-sample .sv-engine { grid-template-columns: minmax(0, 1fr); }
}
/* Runs of this water: the plot, the spread beside it, then the runs. */
.v-sample .sv-replicates-card { margin-top: var(--s4); }
.v-sample .rp-layout {
  display: grid;
  grid-template-columns: minmax(0, 440px) minmax(0, 1fr);
  gap: var(--s5);
  align-items: start;
}
.v-sample .rp-plot { display: block; width: 100%; height: auto; }
.v-sample .rp-bar { stroke: var(--text-primary); stroke-width: 1.5px; }
.v-sample .rp-point { fill: var(--surface-1); stroke: var(--series-1); stroke-width: 2px; }
.v-sample .rp-current .rp-point { fill: var(--series-1); }
.v-sample .rp-label {
  font-family: var(--font-ui);
  font-size: 10.5px;
  fill: var(--text-primary);
}
.v-sample .rp-facts { grid-template-columns: minmax(0, max-content) minmax(0, 1fr); column-gap: var(--s4); }
.v-sample .rp-facts dt { white-space: normal; }
.v-sample .rp-facts dd { color: var(--text-primary); }
.v-sample .rp-worth {
  display: block;
  font-family: var(--font-body);
  font-size: var(--fs-small);
  line-height: 1.5;
  color: var(--text-secondary);
}
.v-sample .rp-runs {
  margin: var(--s4) 0 0;
  padding-left: var(--s5);
  display: flex;
  flex-direction: column;
  gap: var(--s1);
  font-size: var(--fs-small);
  line-height: 1.5;
}
.v-sample .rp-runs li > * + * { margin-left: var(--s2); }
.v-sample .rp-run-figures { color: var(--text-secondary); font-variant-numeric: tabular-nums; }
.v-sample .rp-note {
  margin: var(--s3) 0 0;
  font-size: var(--fs-small);
  line-height: 1.5;
  color: var(--text-secondary);
}
.v-sample .card-body > .rp-note:first-child { margin-top: 0; }
.v-sample .rp-agreement,
.v-sample .rp-richness {
  margin-top: var(--s5);
  padding-top: var(--s4);
  border-top: 1px solid var(--line-faint);
}
.v-sample .rp-subhead { display: flex; align-items: center; gap: var(--s2); margin: 0; }
.v-sample .rp-pairs {
  margin: var(--s3) 0 0;
  padding-left: var(--s5);
  display: flex;
  flex-direction: column;
  gap: var(--s2);
  font-size: var(--fs-small);
  line-height: 1.5;
}
.v-sample .rp-pairs li > .rp-verdict { margin-left: var(--s2); color: var(--text-primary); font-weight: 600; }
.v-sample .rp-pairs .rp-worth { font-variant-numeric: tabular-nums; }
/* The spread's pairs are one line each, under the range they make up. */
.v-sample .rp-spread-pairs { margin-top: var(--s2); gap: var(--s1); }
@media (max-width: 760px) {
  .v-sample .rp-layout { grid-template-columns: minmax(0, 1fr); }
}
/* Bead study: the certificate fields, then the operator's statements in a
   box of their own, so a tick is never read as one more certificate field. */
.v-sample .sv-bead-form { display: flex; flex-direction: column; gap: var(--s4); }
.v-sample .sv-bead-fields {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--s3) var(--s4);
  max-width: 900px;
}
.v-sample .sv-bead-conc { display: flex; gap: var(--s2); min-width: 0; }
.v-sample .sv-bead-conc .input { flex: 1 1 auto; }
.v-sample .sv-bead-conc .select { flex: 0 0 auto; width: auto; }
.v-sample .sv-bead-statements {
  display: flex;
  flex-direction: column;
  gap: var(--s3);
  margin: 0;
  max-width: 900px;
  padding: var(--s3) var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-2);
}
.v-sample .sv-bead-statements legend { padding: 0 var(--s1); }
.v-sample .sv-bead-statements > .field-hint { margin: 0; }
.v-sample .sv-bead-statement {
  display: flex;
  align-items: flex-start;
  gap: var(--s3);
  cursor: pointer;
}
.v-sample .sv-bead-statement .checkbox { margin-top: 3px; }
.v-sample .sv-bead-statement > span { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.v-sample .sv-bead-statement-text {
  font-size: var(--fs-small);
  line-height: 1.5;
  color: var(--text-primary);
}
.v-sample .sv-bead-results:not(:empty) { margin-top: var(--s5); }
.v-sample .sv-bead-compare { margin-top: var(--s4); display: flex; flex-direction: column; gap: var(--s2); }
.v-sample .sv-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s1) var(--s3);
  margin-top: var(--s2);
  font-family: var(--font-ui);
  font-size: var(--fs-micro);
  letter-spacing: .02em;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.v-sample .sv-pop:not(:empty) { margin-top: var(--s2); }
.v-sample .sv-next { margin: var(--s3) 0 0; font-size: var(--fs-small); }
.v-sample .sv-next .eyebrow { display: inline; margin-right: var(--s2); }
.v-sample .sv-next a { color: var(--accent-text); }
.v-sample .sv-sep { color: var(--line-strong); }
.v-sample .sv-hash-wrap { display: inline-flex; align-items: center; gap: var(--s1); }
.v-sample .sv-hash-copy {
  font: inherit;
  letter-spacing: inherit;
  color: var(--accent-text);
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
}
.v-sample .sv-hash-copy:hover { text-decoration: underline; }
.v-sample .sv-hash-copy:focus-visible { box-shadow: var(--ring); border-radius: 2px; }
.v-sample .sv-pipeline {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 2px;
}
.v-sample .sv-pipeline li {
  display: flex;
  align-items: baseline;
  gap: var(--s2);
  font-family: var(--font-ui);
  font-size: var(--fs-tiny);
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
.v-sample .sv-pipe-n {
  flex: 0 0 auto;
  min-width: 12px;
  color: var(--text-muted);
  font-size: var(--fs-eyebrow);
}
.v-sample .sv-pipe-args { color: var(--text-muted); overflow-wrap: anywhere; }
.v-sample .sv-raw-title {
  font-family: var(--font-display);
  font-weight: 600;
  text-transform: none;
  letter-spacing: var(--track-display);
  font-size: clamp(19px, 2.6vw, 28px);
  line-height: 1.2;
  color: var(--text-primary);
  margin: 0;
}
.v-sample .sv-raw-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s2) var(--s3);
  margin-top: var(--s4);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.v-sample .sv-tools {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  gap: var(--s3);
  flex-wrap: wrap;
}
.v-sample .sv-tools .select { flex: 0 0 auto; width: auto; }
.v-sample .sv-tools .search { flex: 0 1 200px; }
.v-sample .sv-tools .rangef { flex: 1 0 100%; }
.v-sample .sv-count { margin-left: auto; }
.v-sample .sv-specks {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  font-size: var(--fs-small);
  cursor: pointer;
}
.v-sample .sv-specks.disabled { opacity: 0.55; cursor: not-allowed; }
.v-sample .sv-specks.disabled .switch,
.v-sample .sv-specks.disabled .switch input { cursor: not-allowed; }
/* The population note sits under the count, at the count's edge. */
.v-sample .sv-pop-note {
  flex: 1 0 100%;
  margin-top: calc(-1 * var(--s2));
  text-align: right;
  font-size: var(--fs-tiny);
}
.v-sample .sv-pop-note:empty { display: none; }
/* The sort's description keeps two lines' height whatever the measurement, so
   choosing another one never moves the tiles; a longer sentence is clipped
   and kept whole in the hover. */
.v-sample .sv-tools .sortc-about {
  flex: 1 0 100%;
  min-height: calc(2 * 1.45em);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}
.v-sample .sv-size {
  display: flex;
  align-items: center;
  gap: var(--s2);
  font-family: var(--font-ui);
  font-size: var(--fs-eyebrow);
  text-transform: uppercase;
  letter-spacing: var(--track-eyebrow);
  color: var(--text-muted);
}
.v-sample .sv-size input[type="range"] {
  width: 104px;
  accent-color: var(--accent);
  cursor: pointer;
}
.v-sample .sv-sentinel { height: 1px; }
.v-sample .sv-like { margin-bottom: var(--s3); }
.v-sample .sv-like[hidden] { display: none; }
/* Set aside while the grid shows neighbours: inert, and visibly so. */
.v-sample .sv-set-aside { opacity: 0.45; }
.v-sample .sv-like-line {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s1) var(--s3);
  padding: var(--s2) var(--s3);
  border: 1px solid var(--accent);
  border-radius: var(--r-md);
  background: var(--accent-wash);
}
.v-sample .sv-like-text { flex: 1 1 32ch; font-size: var(--fs-small); color: var(--text-secondary); }
.v-sample .sv-brush { margin-top: var(--s3); align-items: baseline; }
.v-sample .sv-brush-note { font-size: var(--fs-tiny); max-width: 62ch; }
/* the organisms of the clicked morphospace cells (components/cell-panel.js) */
.v-sample .sv-cell { margin-top: var(--s3); }
.v-sample .sv-cell-title { font-size: var(--fs-small); }
.v-sample .sv-cell-taxa { font-size: var(--fs-tiny); }
.v-sample .sv-cell-thumbs {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));
  gap: var(--s2);
  max-height: 240px;
  overflow-y: auto;
}
.v-sample .sv-cell-thumb {
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 4px;
  /* the whole specimen on its imaging ground, as in the grid (components.css) */
  --specimen-bg: #fff;
  background: var(--specimen-bg);
  aspect-ratio: 1;
  cursor: pointer;
}
.v-sample .sv-cell-thumb:hover,
.v-sample .sv-cell-thumb:focus-visible { border-color: var(--accent); }
.v-sample .sv-cell-thumb img {
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}
/* thumbfit.js: a small picture padded back to the scale of its square, so
   the sizes in the panel compare as in the grid (a percentage is of the tile) */
.v-sample .sv-cell-thumb img[data-thumb-fill] { padding: calc((1 - var(--thumb-fill, 1)) * 50%); }
.v-sample .sv-menu-wrap { position: relative; display: inline-flex; }
.v-sample .sv-menu {
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  z-index: 40;
  min-width: 194px;
  padding: var(--s1);
  box-shadow: var(--shadow-2);
}
.v-sample .sv-menu-item {
  display: block;
  width: 100%;
  padding: var(--s2) var(--s3);
  border-radius: var(--r-sm);
  font-size: var(--fs-small);
  color: var(--text-primary);
  white-space: nowrap;
}
.v-sample .sv-menu-item:hover { background: var(--surface-hover); }
.v-sample .sv-menu-item:focus-visible { box-shadow: var(--ring); }
.v-sample .sv-menu-item.danger { color: var(--status-critical); }
.v-sample .sv-shot {
  display: flex;
  align-items: center;
  justify-content: center;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  min-height: 200px;
  padding: var(--s2);
  overflow: hidden;
}
/* The detail picture: the component sizes it (specimen.js); here it is only
   centred. Not under .v-sample: the specimen panel is a modal, mounted
   outside the view root. */
.sv-shot { text-align: center; }
.sv-shot .specimen-figure img { display: block; max-width: none; max-height: none; }
.v-sample .sv-shot img {
  max-width: 100%;
  max-height: 44vh;
  width: auto;
  height: auto;
  display: block;
}
.v-sample .sv-top3 { display: grid; gap: var(--s2); margin: 0; padding: 0; list-style: none; }
.v-sample .sv-top3 li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 54px;
  gap: var(--s3);
  align-items: center;
  font-size: var(--fs-small);
}
.v-sample .sv-inspect {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 300px);
  gap: var(--s4);
}
@media (max-width: 900px) {
  .v-sample .sv-hero { grid-template-columns: minmax(0, 1fr); }
  .v-sample .sv-inspect { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 640px) {
  .v-sample .sv-count { margin-left: 0; }
  .v-sample .sv-pop-note { text-align: left; }
}

/* -- web/js/views/explore.js ------------------------------------------------- */
.v-explore .x-map { position: relative; min-width: 0; }
.v-explore .x-maphost { min-width: 0; }
.v-explore .x-pincard {
  position: absolute;
  z-index: 4;
  top: 52px;
  width: min(272px, calc(100% - 24px));
  padding: var(--s3) var(--s4) var(--s4);
  background: var(--surface-1);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-3);
}
.v-explore .x-pincard[data-side="left"]  { left: 12px; }
.v-explore .x-pincard[data-side="right"] { right: 12px; }
.v-explore .x-pinhead { display: flex; align-items: flex-start; gap: var(--s3); min-width: 0; }
.v-explore .x-pinfp {
  flex: 0 0 auto; width: 64px; height: 64px; border-radius: var(--r-md);
  background: var(--surface-sunken); border: 1px solid var(--line-faint);
  overflow: hidden; line-height: 0;
}
.v-explore .x-pinfp svg { width: 100%; height: 100%; display: block; }
.v-explore .x-pinname {
  font-family: var(--font-display); font-weight: 600; font-size: var(--fs-lg);
  line-height: 1.2; text-transform: none; letter-spacing: var(--track-display);
  color: var(--text-primary);
}
.v-explore .x-pinclose { position: absolute; top: 6px; right: 6px; }
.v-explore .x-caption {
  padding: var(--s2) 0 0;
  font-family: var(--font-ui); font-size: var(--fs-micro); line-height: 1.5;
  color: var(--text-muted);
}
.v-explore .x-filterbar { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; }
.v-explore .x-toolbar { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap; }
.v-explore .x-toolbar .search { flex: 1 1 200px; }
.v-explore .x-note {
  font-family: var(--font-ui); font-size: var(--fs-micro); line-height: 1.55;
  color: var(--text-muted); font-variant-numeric: tabular-nums;
}
.v-explore .x-taxoncell { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.v-explore .x-groupcell { display: inline-flex; align-items: center; gap: var(--s2); min-width: 0; }
.v-explore .x-obscell { min-width: 220px; }
.v-explore .x-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(196px, 1fr));
  gap: var(--s4);
}
.v-explore .x-card {
  display: flex; flex-direction: column; align-items: center; gap: var(--s3);
  padding: var(--s4); text-align: center; text-decoration: none; color: inherit;
}
.v-explore .x-card-fp {
  width: 132px; max-width: 100%; aspect-ratio: 1 / 1;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--r-md); background: var(--surface-sunken);
  border: 1px solid var(--line-faint); overflow: hidden; line-height: 0;
}
.v-explore .x-card-fp svg { width: 100%; height: 100%; display: block; }
.v-explore .x-card-name {
  max-width: 100%;
  font-family: var(--font-display); font-weight: 600; font-size: var(--fs-lg);
  line-height: 1.2; text-transform: none; letter-spacing: var(--track-display);
  color: var(--text-primary);
}
.v-explore .x-card-meta {
  display: flex; flex-direction: column; gap: 2px;
  font-family: var(--font-ui); font-size: var(--fs-eyebrow);
  letter-spacing: var(--track-eyebrow); text-transform: uppercase;
  color: var(--text-muted); font-variant-numeric: tabular-nums;
}
.v-explore .x-provenance { display: grid; gap: var(--s3); }
.v-explore .x-provenance p { margin: 0; max-width: 74ch; }
@media (max-width: 560px) {
  .v-explore .x-pincard {
    top: auto; bottom: 12px; left: 12px; right: 12px; width: auto;
  }
  .v-explore .x-grid { grid-template-columns: repeat(auto-fill, minmax(146px, 1fr)); }
  .v-explore .x-card-fp { width: 116px; }
}

/* -- web/js/views/validate.js ------------------------------------------------ */
.v-validate { --rail-w: 252px; --insp-w: 328px; }

.v-validate .v-work {
  display: grid;
  grid-template-columns: var(--rail-w) minmax(0, 1fr) var(--insp-w);
  gap: var(--s4);
  align-items: start;
  min-width: 0;
}

.v-validate .v-rail,
.v-validate .v-inspector {
  position: sticky;
  top: calc(var(--topbar-h) + var(--s3));
  display: flex;
  flex-direction: column;
  gap: var(--s3);
  min-width: 0;
  max-height: calc(100vh - var(--topbar-h) - var(--s6));
  overflow-y: auto;
  overscroll-behavior: contain;
}

.v-validate .v-centre { min-width: 0; display: flex; flex-direction: column; gap: var(--s3); }

.v-validate .v-block { padding: var(--s3); display: flex; flex-direction: column; gap: var(--s2); }
/* The search box is a row of its own here, not a share of a toolbar; its
   count keeps one line while empty, so a count arriving moves nothing. */
.v-validate .v-block .search { flex: 0 0 auto; max-width: none; }
.v-validate .v-search-count { min-height: 1.45em; }
/* The rail is narrow and its own column: the measurement takes a row, the
   bounds the next, and the list of ranges wraps instead of clipping. */
.v-validate .v-rail .rangef-edit .select { flex: 1 0 100%; }
.v-validate .v-rail .rangef-edit .input.num { width: 72px; }
.v-validate .v-rail .rangef-line { flex-wrap: wrap; }
.v-validate .v-rail .rangef-summary { white-space: normal; flex-basis: 100%; }
/* every panel head in this view is a two-slot eyebrow: name on the left, the
   number or the badge on the right. */
.v-validate .panel > .eyebrow {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--s2); flex-wrap: wrap; min-width: 0;
}

.v-validate .v-prog-value { display: flex; align-items: baseline; gap: var(--s2); }
.v-validate .v-prog-value .display-md { line-height: 1; }

.v-validate .v-frows { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.v-validate .v-frow {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s2);
  width: 100%; padding: 5px var(--s2); border: 1px solid transparent;
  border-radius: var(--r-sm); background: none; cursor: pointer; text-align: left;
  font-family: var(--font-body); font-size: var(--fs-tiny);
  color: var(--text-secondary); min-width: 0;
}
.v-validate .v-frow:hover { background: var(--surface-3); color: var(--text-primary); }
.v-validate .v-frow:focus-visible { box-shadow: var(--ring); }
.v-validate .v-frow[aria-pressed="true"] {
  background: var(--accent-wash); border-color: var(--accent-dim); color: var(--text-primary);
}
.v-validate .v-frow > span:first-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.v-validate .v-frow .num { flex: 0 0 auto; color: var(--text-muted); }
.v-validate .v-frow .truncate { min-width: 0; }

.v-validate .v-scrolly { max-height: 232px; overflow-y: auto; overscroll-behavior: contain; min-width: 0; }

.v-validate .v-key {
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  width: 17px; height: 17px; border: 1px solid var(--line-strong); border-radius: 3px;
  background: var(--surface-sunken); color: var(--text-muted);
  font-family: var(--font-ui); font-size: var(--fs-eyebrow); line-height: 1;
}
.v-validate .v-frow[aria-pressed="true"] .v-key { border-color: var(--accent-dim); color: var(--text-primary); }

.v-validate .v-pair { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s2); }
.v-validate .v-pair .input { text-align: right; }

.v-validate .v-actionbar { z-index: 22; gap: var(--s2); }
.v-validate .v-count {
  font-family: var(--font-ui); font-size: var(--fs-tiny); font-variant-numeric: tabular-nums;
  color: var(--text-primary); white-space: nowrap;
}
.v-validate .v-picker { flex: 1 1 190px; max-width: 260px; min-width: 150px; }

.v-validate .v-photo {
  --specimen-bg: #fff;
  position: relative; display: flex; align-items: center; justify-content: center;
  width: 100%; aspect-ratio: 1 / 1; overflow: hidden;
  background: var(--specimen-bg); border: 1px solid var(--line); border-radius: var(--r-md);
}
.v-validate .v-photo img { width: 100%; height: 100%; object-fit: contain; filter: none; }

.v-validate .v-top3 { display: flex; flex-direction: column; gap: var(--s1); }
.v-validate .v-t3 {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center;
  gap: 2px var(--s2); width: 100%; padding: var(--s2); border: 1px solid var(--line);
  border-radius: var(--r-sm); background: var(--surface-2); cursor: pointer; text-align: left;
  font-family: var(--font-body); font-size: var(--fs-tiny); color: var(--text-secondary);
}
.v-validate .v-t3:hover { border-color: var(--line-strong); color: var(--text-primary); }
.v-validate .v-t3:focus-visible { box-shadow: var(--ring); }
.v-validate .v-t3[disabled] { cursor: not-allowed; opacity: .5; }
.v-validate .v-t3 > .conf-bar { grid-column: 1 / -1; }
.v-validate .v-t3 .num { font-family: var(--font-ui); font-variant-numeric: tabular-nums; color: var(--text-primary); }

.v-validate .v-thread { display: flex; flex-direction: column; min-width: 0; }
.v-validate .v-ann { display: flex; flex-direction: column; gap: 3px; padding: var(--s3) 0; border-top: 1px solid var(--line-faint); min-width: 0; }
.v-validate .v-ann:first-child { border-top: 0; }
.v-validate .v-ann-note { font-size: var(--fs-tiny); line-height: 1.55; color: var(--text-secondary); overflow-wrap: anywhere; }

.v-validate .v-stale {
  display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap;
  font-family: var(--font-ui); font-size: var(--fs-micro); color: var(--text-muted);
}

.v-validate .v-sheet-handle { display: none; }
.v-validate .v-gridwrap { min-width: 0; }

@media (max-width: 1199px) {
  .v-validate .v-work { grid-template-columns: minmax(0, 1fr); }

  /* Static, not sticky: the action bar already sticks at --topbar-h, and two
     sticky bands at the same offset would sit one over the other. On a narrow
     screen you set the filter once, then work the grid. */
  .v-validate .v-rail {
    position: static; top: auto;
    flex-direction: row; align-items: stretch;
    max-height: none; overflow-x: auto; overflow-y: hidden;
    padding: 0 0 var(--s3); margin: 0;
    border-bottom: 1px solid var(--line);
  }
  .v-validate .v-rail > * { flex: 0 0 auto; width: 244px; }
  /* A toolbar is a band, not a page: the lists scroll inside themselves and
     the histogram — a luxury, not the control — stands down. The two number
     fields and the threshold chip carry exactly the same setting. */
  .v-validate .v-rail .chart { display: none; }
  .v-validate .v-scrolly { max-height: 124px; }
  .v-validate .v-rail .v-frows {
    max-height: 124px; overflow-y: auto; overscroll-behavior: contain;
  }

  .v-validate .v-inspector {
    position: fixed; inset: auto 0 0 0; top: auto; z-index: 40;
    max-height: min(62vh, 560px);
    padding: 0 var(--s4) var(--s4);
    gap: var(--s3);
    background: var(--surface-1);
    border-top: 1px solid var(--line-strong);
    border-radius: var(--r-lg) var(--r-lg) 0 0;
    box-shadow: var(--shadow-3);
  }
  .v-validate .v-inspector[data-open="0"] { max-height: 46px; overflow: hidden; padding-bottom: 0; }
  .v-validate .v-sheet-handle {
    position: sticky; top: 0; z-index: 1;
    /* flex-shrink would let the collapsed sheet squeeze the handle and show a
       slice of the specimen photo under it. */
    flex: 0 0 auto;
    display: flex; align-items: center; justify-content: space-between; gap: var(--s2);
    height: 46px; min-height: 46px; margin: 0 calc(var(--s4) * -1); padding: 0 var(--s4);
    background: var(--surface-1); border-bottom: 1px solid var(--line-faint);
  }
  .v-validate .v-centre { padding-bottom: 64px; }
}

@media (max-width: 720px) {
  .v-validate .v-inspector { bottom: calc(58px + env(safe-area-inset-bottom, 0px)); }
  /* every row of a wrapped action bar costs a phone 44 px of grid — the cell
     size stepper is the one control worth dropping. */
  .v-validate .v-actionbar .segmented { display: none; }
}

@media (max-width: 480px) {
  .v-validate .v-rail > * { width: 216px; }
}

@media (prefers-reduced-motion: reduce) {
  .v-validate .v-frow, .v-validate .v-t3 { transition: none; }
}

/* -- web/js/views/classify.js ------------------------------------------------ */
/* "First predictions": a name with no confidence figure beside it may take
   two lines of its 96 px cell, so "Image too soft to name" (the owners' words,
   EPL-2255) is read whole. A name sharing its row with a figure keeps the
   grid's one-line ellipsis: at half a cell, two lines would split the word. */
.first-predictions .imgcell-meta > .ep-ic-label:only-child {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  white-space: normal;
}

/* -- web/js/views/model.js --------------------------------------------------- */
.v-model .mc-hero{display:flex;flex-wrap:wrap;align-items:flex-start;gap:var(--s5);
  justify-content:space-between}
.v-model .mc-hero-main{min-width:min(100%,420px);flex:1 1 420px}
.v-model .mc-arch{font-family:var(--font-ui);font-size:var(--fs-tiny);
  color:var(--text-muted);margin-top:var(--s2);line-height:1.55}
.v-model .mc-constraint{border:1px solid var(--status-warning);
  background:var(--status-warning-wash);border-radius:var(--r-lg);
  padding:var(--s5);display:grid;gap:var(--s3)}
.v-model .mc-constraint h3{margin:0;font-size:var(--fs-lg);font-weight:600;
  letter-spacing:var(--track-display)}
.v-model .mc-constraint p{margin:0;font-size:var(--fs-base);line-height:1.6;
  color:var(--text-secondary);max-width:78ch}
.v-model .mc-constraint dl{margin:0;display:grid;grid-template-columns:auto 1fr;
  gap:var(--s1) var(--s4);font-family:var(--font-ui);font-size:var(--fs-tiny)}
.v-model .mc-constraint dt{color:var(--text-muted);text-transform:uppercase;
  letter-spacing:var(--track-eyebrow)}
.v-model .mc-constraint dd{margin:0;color:var(--text-primary)}
.v-model .mc-two{display:grid;gap:var(--s5);grid-template-columns:1fr 1fr}
@media (max-width:1040px){.v-model .mc-two{grid-template-columns:1fr}}
.v-model .mc-steps{margin:0;padding:0;list-style:none;counter-reset:step;
  display:grid;gap:0}
.v-model .mc-steps li{counter-increment:step;display:grid;
  grid-template-columns:34px 1fr;gap:var(--s3);padding:var(--s3) 0;
  border-top:1px solid var(--line-faint);align-items:baseline}
.v-model .mc-steps li:first-child{border-top:0}
.v-model .mc-steps li::before{content:counter(step,decimal-leading-zero);
  font-family:var(--font-ui);font-size:var(--fs-micro);color:var(--text-muted)}
.v-model .mc-steps code{font-family:var(--font-mono);font-size:var(--fs-tiny);
  color:var(--text-primary)}
.v-model .mc-steps span{display:block;font-size:var(--fs-tiny);
  color:var(--text-muted);margin-top:2px;line-height:1.5}
.v-model .mc-weak-note{font-size:var(--fs-base);line-height:1.6;
  color:var(--text-secondary);max-width:78ch;margin:0 0 var(--s4)}
.v-model .mc-f1{display:flex;align-items:center;gap:var(--s2);justify-content:flex-end}
.v-model .mc-f1-track{width:64px;height:4px;border-radius:2px;
  background:var(--surface-3);overflow:hidden;flex:none}
.v-model .mc-f1-fill{display:block;height:100%;border-radius:2px}

/* -- web/js/views/settings.js ------------------------------------------------ */
.v-settings{display:block;}
.v-settings .v-set-section{margin-bottom:var(--s7);}
.v-settings .v-set-grid{display:grid;gap:var(--s6);grid-template-columns:minmax(0,1fr);}
.v-settings .v-set-fields{display:grid;gap:var(--s5);min-width:0;}
.v-settings .v-set-pair{display:grid;gap:var(--s5);grid-template-columns:minmax(0,1fr);}
.v-settings .v-set-aside{display:flex;flex-direction:column;align-items:center;
  gap:var(--s4);padding:var(--s5);min-width:0;}
.v-settings .v-set-avatar{width:112px;height:112px;--avatar-size:112px;}
.v-settings .v-set-hue{display:grid;gap:var(--s2);width:100%;}
.v-settings input[type="range"]{width:100%;height:22px;margin:0;padding:0;
  background:transparent;accent-color:var(--accent);cursor:pointer;}
.v-settings input[type="range"]:focus-visible{outline:none;box-shadow:var(--ring);
  border-radius:var(--r-full);}
.v-settings .v-set-count{font-family:var(--font-ui);font-size:var(--fs-tiny);
  color:var(--text-muted);text-align:right;font-variant-numeric:tabular-nums;}
.v-settings .v-set-swatches{display:flex;flex-wrap:wrap;gap:var(--s2) var(--s4);
  margin-top:var(--s4);}
.v-settings .v-set-retry{display:grid;gap:var(--s3);border:1px solid var(--status-critical);
  border-radius:var(--r-md);padding:var(--s3);background:var(--status-critical-wash);}
.v-settings .v-set-name{display:flex;align-items:center;gap:var(--s3);min-width:0;}
.v-settings .v-set-name a{color:var(--text-primary);text-decoration:none;}
.v-settings .v-set-name a:hover{color:var(--accent);}
.v-settings .v-set-chip{flex:0 0 auto;display:inline-flex;width:26px;height:26px;
  border-radius:var(--r-sm);overflow:hidden;background:var(--surface-sunken);
  box-shadow:inset 0 0 0 1px var(--line);}
.v-settings .v-set-chip svg{width:100%;height:100%;}
.v-settings .v-set-foot{display:flex;align-items:center;justify-content:space-between;
  gap:var(--s3);flex-wrap:wrap;}
@media (min-width:820px){
  .v-settings .v-set-grid{grid-template-columns:minmax(0,1fr) 232px;}
  .v-settings .v-set-pair{grid-template-columns:minmax(0,1fr) minmax(0,1fr);}
}

/* ==========================================================================
   results — the diversity section (EPL-1475)
   ========================================================================== */
/* `…/results#diversity` lands the section under the sticky top bar, not behind it. */
.v-results section[id] { scroll-margin-top: calc(var(--topbar-h) + var(--s4)); }
.v-results details > summary {
  align-self: flex-start; max-width: 100%;
  /* .btn is one nowrap line; the label names five things and wraps on a phone. */
  height: auto; min-height: 26px; padding-block: var(--s1);
  white-space: normal; line-height: 1.35; text-align: left;
}
.v-results details > summary::before { content: '▸'; margin-right: var(--s2); }
.v-results details[open] > summary::before { content: '▾'; }
/* The abundance table behind the composition card. */
.v-results details.abundance { margin-top: var(--s4); }
.v-results .abundance-controls { flex-wrap: wrap; }
.v-results .abundance-controls .search { flex: 1 1 18rem; max-width: 32rem; }
.v-results .abundance-controls .search .input { width: 100%; }
.v-results .abundance-note { margin: 0; max-width: 80ch; font-size: var(--fs-small); }
/* Its Bars view: a dot at each figure, a line over its 95% range; an open
   dot where the engine measured no range. */
.v-results .ar-range { stroke: var(--series-1); stroke-width: 1.5px; }
.v-results .ar-dot { fill: var(--series-1); stroke: var(--surface-1); stroke-width: 1px; }
.v-results .ar-dot.ar-open { fill: var(--surface-1); stroke: var(--series-1); stroke-width: 1.5px; }
.v-results .abundance-unmeasured p { margin: 0 0 var(--s1); }
.v-results .abundance-unmeasured ul { margin: 0; padding-left: var(--s5); }
/* Rows the diversity indices did not count: below the living bars' divider,
   greyed, so detritus never reads as one more species row. */
.v-results .excluded-rows { color: var(--text-muted); font-size: var(--fs-small); }
.v-results .excluded-rows hr { margin: var(--s4) 0 var(--s3); }
.v-results .excluded-rows-label { margin: 0 0 var(--s2); }
.v-results .excluded-rows ul {
  list-style: none; margin: 0; padding: 0;
  columns: 15rem auto; column-gap: var(--s5);
}
.v-results .excluded-rows li {
  display: flex; justify-content: space-between; gap: var(--s3);
  break-inside: avoid; padding-block: 1px;
}
.v-results .excluded-rows .num { color: inherit; }

/* ==========================================================================
   results — the watchlist across the runs of one water (#537)
   ========================================================================== */
.v-results .rw-runs > summary { cursor: pointer; padding-block: 0; min-height: 0; }
.v-results .rw-per-run { margin: var(--s1) 0 0; padding-left: var(--s5); }
.v-results .rw-per-run li { font-variant-numeric: tabular-nums; }
.v-results .rw-note { margin-top: var(--s4); padding-top: var(--s3); border-top: 1px solid var(--line); }
.v-results .rw-note .field-label { display: flex; align-items: center; gap: var(--s2); }
.v-results .rw-absent .flag-label { margin-right: var(--s1); }

/* ==========================================================================
   admin — the team's pages (/app/admin)
   ========================================================================== */
.v-admin .adm-panel { padding-top: var(--s5); min-width: 0; }
.v-admin .adm-intro { margin: 0; max-width: 80ch; color: var(--text-secondary); font-size: var(--fs-small); }
.v-admin .adm-problem p { margin: 0; color: var(--text-secondary); font-size: var(--fs-small); }

/* feedback: the words on the left, the pictures on the right; one column on
   a narrow screen */
.v-admin .adm-fb-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 360px);
  gap: var(--s5);
  align-items: start;
}
@media (max-width: 900px) { .v-admin .adm-fb-grid { grid-template-columns: minmax(0, 1fr); } }
.v-admin .adm-note {
  margin: 0;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  font-size: var(--fs-small);
  line-height: 1.55;
  color: var(--text-primary);
}
.v-admin .adm-where { column-gap: var(--s4); }
.v-admin .adm-picked {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.v-admin .adm-reason { margin: 0; font-size: var(--fs-small); color: var(--text-secondary); }
.v-admin .adm-shots { display: grid; gap: var(--s3); }
.v-admin .adm-shot { margin: 0; }
.v-admin .adm-shot img {
  width: 100%;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-2);
}
.v-admin .adm-shot figcaption { margin-top: var(--s1); }

/* team */
.v-admin .adm-prose { margin: 0; max-width: 80ch; font-size: var(--fs-small); line-height: 1.6; color: var(--text-secondary); }
.v-admin .adm-list { list-style: disc; padding-left: var(--s5); max-width: 80ch;
  font-size: var(--fs-small); line-height: 1.55; color: var(--text-secondary); }
.v-admin .adm-list li + li { margin-top: var(--s2); }
.v-admin .adm-list strong, .v-admin .adm-prose strong { font-weight: 600; color: var(--text-primary); }
.v-admin .adm-quota { list-style: none; padding-left: 0; font-size: var(--fs-base); color: var(--text-primary); }
.v-admin .adm-burn td { vertical-align: top; }

/* notes: a folded card per note; the summary is the card's head */
.v-admin .adm-note.card > summary { border-bottom: 0; }
.v-admin .adm-note.card[open] > summary { border-bottom: 1px solid var(--line); }
.v-admin .adm-note-body { padding: var(--s4); }
.v-admin .adm-note:not([open]) > .adm-note-body { display: none; }

/* decisions */
.v-admin .adm-console {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--s3);
}
.v-admin .adm-console p { margin: 0; max-width: 72ch; font-size: var(--fs-small); color: var(--text-primary); }
.v-admin .adm-qs { margin-top: var(--s4); }
.v-admin .adm-q { padding: var(--s3) 0; border-top: 1px solid var(--line-faint); }
.v-admin .adm-q:first-child { border-top: 0; padding-top: 0; }
.v-admin .adm-q .badge { flex: 0 0 auto; margin-top: 1px; }
.v-admin .adm-q-text { display: grid; gap: var(--s1); min-width: 0; }
.v-admin .adm-q-question { margin: 0; font-size: var(--fs-small); color: var(--text-primary); }
.v-admin .adm-q-answer { margin: 0; font-size: var(--fs-small); color: var(--text-secondary); }
.v-admin .adm-done { margin-top: var(--s4); padding-top: var(--s3); border-top: 1px solid var(--line-faint); }
.v-admin .adm-done > summary { font-size: var(--fs-small); color: var(--text-secondary); }
.v-admin .adm-done > summary::before { content: '▸'; margin-right: var(--s2); }
.v-admin .adm-done[open] > summary::before { content: '▾'; }
.v-admin .adm-done[open] > summary { margin-bottom: var(--s3); color: var(--text-primary); }

/* a card answered in place: the console's options, one button each */
.v-admin .adm-ans { margin-top: var(--s2); }
.v-admin .adm-ans > summary { font-size: var(--fs-small); color: var(--accent); cursor: pointer; }
.v-admin .adm-ans > summary::before { content: '▸'; margin-right: var(--s2); }
.v-admin .adm-ans[open] > summary::before { content: '▾'; }
.v-admin .adm-ans-body { display: grid; gap: var(--s3); margin-top: var(--s3); max-width: 72ch; }
.v-admin .adm-ans-body .adm-prose { margin: 0; }
.v-admin .adm-opts { display: grid; gap: var(--s2); }
.v-admin .adm-opt {
  display: grid; gap: var(--s1); text-align: left; padding: var(--s2) var(--s3);
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface-1); color: var(--text-primary); font: inherit; cursor: pointer;
}
.v-admin .adm-opt:hover { background: var(--surface-hover); }
.v-admin .adm-opt:focus-visible { outline: none; box-shadow: var(--ring); }
.v-admin .adm-opt[aria-pressed="true"] { border-color: var(--accent); box-shadow: inset 3px 0 0 var(--accent); }
.v-admin .adm-opt-label {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2);
  font-size: var(--fs-small); font-weight: 600;
}
.v-admin .adm-opt-body { font-size: var(--fs-small); color: var(--text-secondary); }
.v-admin .adm-ans-field { display: grid; gap: var(--s1); font-size: var(--fs-small); color: var(--text-secondary); }
.v-admin .adm-ans-field[hidden] { display: none; }
.v-admin .adm-ans-line { margin: 0; font-size: var(--fs-small); color: var(--text-secondary); }
.v-admin .adm-ans-refused { color: var(--status-serious); }
=======
/* -- web/js/views/methods.js ------------------------------------------------- */
.v-methods { min-height: 100dvh; background: var(--bg); }
.v-methods .mt-top {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s4);
  max-width: 860px; margin: 0 auto; padding: var(--s4) var(--s7) 0;
}
.v-methods .mt-mark {
  font-family: var(--font-display); font-weight: 600; font-size: var(--fs-2xl);
  letter-spacing: var(--track-display); color: var(--text-primary); text-decoration: none;
}
.v-methods .mt-mark:hover { color: var(--accent); }
.v-methods .mt-sec { margin-top: var(--s4); scroll-margin-top: var(--s4); }
.v-methods .mt-prose { margin: 0 0 var(--s3); max-width: 72ch; line-height: 1.6; color: var(--text-secondary); }
.v-methods .mt-kv { margin-top: var(--s2); column-gap: var(--s4); }
.v-methods .mt-kv dt { white-space: normal; }
.v-methods .mt-states { display: inline-flex; flex-wrap: wrap; gap: var(--s2); }
.v-methods .mt-list { margin: 0 0 var(--s3); padding-left: var(--s5); color: var(--text-secondary); line-height: 1.6; }
.v-methods .mt-where { margin: var(--s3) 0 0; font-size: var(--fs-small); color: var(--text-muted); }
.v-methods a.badge { text-decoration: none; }
@media (max-width: 640px) {
  .v-methods .mt-top { padding: var(--s4) var(--s5) 0; }
  .v-methods .mt-kv { grid-template-columns: minmax(0, 1fr); }
}
