/* pLannotate viewer — the "mcguffie" skin.
   Palette, type roles and label conventions lifted from the CV in the
   personal-website Figma file; the feel is old paper and melded bubbles rather
   than an instrument panel. Nothing here is hairlined, squared or engraved:
   surfaces are warm paper, every corner is generous, and things merge into
   each other instead of butting up against rules. */

:root {
  /* old paper, in three depths */
  --paper: #ece3cf;
  --paper-mid: #f2ebda;
  --paper-hi: #f8f4eb;

  /* from the CV */
  --ink: #272d25;
  --ink-soft: #5b6257;
  --sage: #6f7b67;
  --sage-hi: #7e8877;
  --bronze: #aa8b6a;

  /* Kept under its old name: .sbol-ring fills with it so origin glyphs punch a
     hole in the backbone. It must equal the map's own background. */
  --panel: var(--paper-hi);

  --danger: #a4533f;

  /* Recursive carries both roles from one family: MONO 1 + CASL 1 + a slant
     gives the rounded casual mono of the CV's name and section heads; MONO 0
     gives a soft humanist sans. Lato is the body face the CV actually uses. */
  --label: "Recursive", ui-monospace, SFMono-Regular, Menlo, monospace;
  --body: "Lato", "Segoe UI", Helvetica, Arial, sans-serif;
  --mono: "Recursive", ui-monospace, SFMono-Regular, Menlo, monospace;

  --r-sm: 12px;
  --r-md: 20px;
  --r-lg: 30px;
  --r-pill: 999px;
}
/* the strip is sized in real pixels by JS; these keep a stale measurement from
   pushing the page wider than the viewport */
#ruler { overflow: hidden; }
#ruler svg { display: block; max-width: 100%; }

.ru-axis { stroke: rgba(111, 123, 103, 0.35); }
.ru-tick { stroke: rgba(111, 123, 103, 0.35); }
.ru-tick-label {
  font-family: var(--mono);
  font-variation-settings: "MONO" 1, "CASL" 0.4;
  font-size: 10.5px;
  fill: var(--ink-soft);
  pointer-events: none;
}
/* the hit targets are wider than the bars so a 1 bp feature stays clickable —
   they must stay invisible, or they paint as black boxes */
.ru-hit { fill: transparent; cursor: pointer; }
/* No `stroke` here on purpose: a CSS declaration outranks a presentation
   attribute, so `stroke: none` would silently erase the outline that draws
   fragments hollow. Solid bars set stroke="none" on the element instead. */
.ru-bar {
  cursor: pointer;
  opacity: 0.92;
  transition: opacity 0.16s;
}
.ru-bar.hovered { opacity: 1; }
.ru-feature:focus-visible { outline: none; }
.ru-feature:focus-visible .ru-hit { stroke: var(--ink); stroke-width: 2; }
/* the pick is cloned into an unfiltered overlay, so it keeps hard edges while
   the melded layer behind it is faded as a whole */
.ru-bar.selected { opacity: 1; }
/* the feature's own name, seated inside its bar when it measures short enough */
.ru-name {
  font-family: var(--body);
  font-size: 10px;
  font-weight: 700;
  pointer-events: none;
}
/* a soft bronze thread dropped from the axis at each edge of the selected span */
.ru-guide {
  stroke: var(--bronze);
  stroke-width: 2;
  stroke-linecap: round;
  opacity: 0.7;
  pointer-events: none;
}
#focus { margin-top: 10px; }
#focus:not(.active) { display: none; }
#focus.active {
  background: var(--paper-mid);
  border-radius: var(--r-md);
  padding: 10px 12px;
  touch-action: none;
}
#focus.active .linear-svg { cursor: grab; }
#focus.panning,
#focus.panning * { cursor: grabbing !important; }

/* The svg always takes the full plate. A short plasmid draws small by opening
   its viewBox up around itself (PLOT_CORE.sizeScale/sizeViewBox), never by
   narrowing this — the drawing has to shrink *inside* its coordinate space, or
   the room it frees is somewhere the labels cannot be put. */
.plasmid-svg {
  width: 100%;
  height: auto;
  display: block;
  touch-action: none;
  cursor: grab;
  -webkit-user-select: none;
  user-select: none;
}
.plasmid-svg:active { cursor: grabbing; }
/* A feature the Fragments switch is hiding. `display: none` rather than a fade:
   it takes the hit target with it, so a hidden fragment cannot be hovered or
   picked off the plate — the sequence index is where it is still live. Applied
   by `PLOT_CORE.maskHidden` after the drawing is complete, which is what keeps
   the layout (and so the plate's size) the same in both states. */
.feat-hidden { display: none; }

/* A fragment on the schematic: present, but not part of what the plasmid *is*.
   It already draws hollow, like everywhere else; this drops it back a plane so
   the whole hits and the partial reads as a ghost of one. Selecting it brings
   it back to full strength — you asked about that one specifically. */
.stylized-faint { opacity: 0.4; }
.stylized-faint.selected { opacity: 1; }
.leader-line.stylized-faint { opacity: 0.22; }

/* the schematic has no zoom or pan to offer — a grab cursor would promise one */
.stylized-svg, .stylized-svg:active { cursor: default; }
/* The size is chosen in `plot-stylized.js` (the plate, up to GROW_MAX times the
   drawing's natural width) and written to the width/height attributes. This is
   what keeps it honest between renders: nothing re-renders on window resize, so
   `max-width` is what shrinks the drawing when the window narrows, and
   `height: auto` is what makes the box follow it instead of letterboxing the
   content inside a box that kept its height. Every stroke is in viewBox units
   for the same reason — see the INK_PX comment. */
.stylized-svg { width: auto; height: auto; max-width: 100%; margin: 0 auto; }
.legend-row {
  display: grid;
  grid-template-columns: 12px minmax(0, 1fr) auto;
  align-items: center;
  gap: 10px;
  padding: 5px 0;
  font-size: 0.85rem;
}
/* round, like everything else — the map's own glyphs are the only squared thing */
.legend-swatch {
  width: 12px;
  height: 12px;
  border-radius: var(--r-pill);
  flex: none;
  box-shadow: 0 0 0 1.5px rgba(248, 244, 235, 0.45);
}
.legend-text { color: var(--paper-hi); min-width: 0; }
.legend-count {
  font-family: var(--mono);
  font-variation-settings: "MONO" 1, "CASL" 0.4;
  font-size: 0.82rem;
  color: rgba(248, 244, 235, 0.7);
}

/* ---------- map typography (on the paper plate) ---------- */
/* Every size here is the declared size times `--tz`, the type zoom the renderer
   sets on the drawing's own svg (PLOT_CORE.typeSvg). A view that draws a short
   plasmid smaller shrinks its type along with everything else in the viewBox,
   and `--tz` is the exact inverse of that, so what reaches the screen is one
   size on every plasmid. It is set per svg and never on an ancestor, which is
   what leaves the zoom panel, the measuring ruler and the sequence-index strip
   -- none of which is size-scaled -- on the default of 1. */
.feature-label {
  font-family: var(--body);
  font-size: calc(13px * var(--tz, 1));
  fill: var(--ink);
  cursor: zoom-in;
}
/* a name seated inside its own feature: same face, a little more weight to hold
   its own against the fill, and transparent to the pointer so the glyph
   underneath keeps the hover and the click. Its colour is set per feature (the
   palette is not uniformly dark), so no fill here. */
.inline-label {
  font-family: var(--body);
  font-size: calc(12.5px * var(--tz, 1));
  font-weight: 600;
  pointer-events: none;
}
/* what a faint fragment's in-block name sits on, so the backbone running through
   the block doesn't strike the word out. Same fill the ori ring uses to hide the
   backbone behind itself — it must equal the plate. */
.inline-patch {
  fill: var(--panel);
  /* not quite opaque: at full strength the backbone stops dead on either side of
     the word and the patch reads as a chip laid on the block. Letting a quarter
     of the line through keeps it one continuous line, dimmed where the name
     crosses it, which is what a label on a wire actually looks like. Below ~0.6
     the line starts striking the word out again. */
  fill-opacity: 0.75;
  pointer-events: none;
}
/* a picked fragment comes back to full opacity, so its own white fill hides the
   backbone again and the patch has nothing left to do but show as a beige chip */
.inline-patch.selected { display: none; }
/* the off-screen ruler used to measure whether a name fits inside its feature */
.measure-svg {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
  visibility: hidden;
}
.bp-label,
.lin-tick-label {
  font-family: var(--mono);
  font-variation-settings: "MONO" 1, "CASL" 0.4;
  font-size: calc(10.5px * var(--tz, 1));
  fill: var(--ink-soft);
  pointer-events: none;
}
.center-label {
  font-family: var(--mono);
  font-variation-settings: "MONO" 1, "CASL" 0.4;
  font-size: calc(13px * var(--tz, 1));
  fill: var(--ink-soft);
  pointer-events: none;
}
/* Never uppercased: gene names are case-significant, so lacZα must not become
   LACZΑ (and the Greek would be transformed too). */
.detail-caption {
  font-family: var(--label);
  font-variation-settings: "MONO" 1, "CASL" 1, "slnt" -12;
  font-size: calc(12px * var(--tz, 1));
  font-weight: 700;
  fill: var(--sage);
  pointer-events: none;
}

.feature-patch {
  cursor: zoom-in;
  stroke-linejoin: round;
  /* No transition on stroke-width: the zoom rewrites it on every tick, and an
     80ms ease made the outline lag the map it belongs to. */
  transition: opacity 0.12s;
}
/* Emphasis is measured against the base outline, which is now the backbone's own
   4.5 — anything lighter reads as the feature going *thinner* on hover. It has to
   ride --zw too: a CSS declaration outranks the presentation attribute the zoom
   handler writes, so a flat value here would snap the outline back to 1x weight
   the moment you touched a feature on a zoomed map. */
.feature-patch:hover,
/* the ncRNA wave is a stroke, so it is hovered through the fat transparent twin
   beside it rather than directly — same emphasis, applied by class */
.feature-patch.hovered { stroke-width: calc(6px * var(--zw, 1)); }
.rna-hit { cursor: zoom-in; }
/* The schematic draws its wave in ink rather than in the type's fill, since it
   is a symbol there alongside the bent arrow, the T and the ring — all of which
   are ink. Same highlight behaviour as those, via --hl. */
.rna-wave.rna-ink { stroke: var(--ink); transition: stroke 0.12s; }
.rna-wave.rna-ink.hovered,
.rna-wave.rna-ink.selected,
.selected .rna-wave.rna-ink { stroke: var(--hl); }
/* ...and its emphasis is the colour alone, as it is for every other symbol on
   this drawing. `.feature-patch` would fatten it to 6 px hovered and 7 selected,
   which is a third and a half again on a block's 4.5 but closes a 3.5 px wave's
   humps into a scalloped ribbon — the one thing the density cannot survive.
   `--rw` carries the weight the glyph is actually struck at so this can hold it
   rather than restate the number. */
.rna-wave.rna-ink:hover,
.rna-wave.rna-ink.hovered,
.rna-wave.rna-ink.selected,
.selected .rna-wave.rna-ink {
  stroke-width: calc(var(--rw, 3.5) * 1px * var(--zw, 1));
}

.leader-line {
  /* the palette lost chroma when it was warmed toward the paper, so the leaders
     need a little more of themselves to stay readable at this weight */
  opacity: 0.5;
  transition: opacity 0.12s;
}

.lin-tick { stroke: var(--ink); opacity: 0.3; stroke-width: 1.5; }
.linear-svg { cursor: default; }

/* SBOL glyphs (promoter bent-arrow, terminator "T") drawn as strokes, plus the
   backbone-span highlight they reveal on hover / while selected */
.sbol-glyph {
  fill: var(--ink);
  stroke: none;
  cursor: zoom-in;
  transition: fill 0.12s;
}
.sbol-glyph.hovered,
.sbol-glyph.selected,
.selected .sbol-glyph { fill: var(--hl); }
.sbol-glyph.selected,
.selected .sbol-glyph { cursor: zoom-out; }

/* the hook nested around an ssDNA origin's ring. Stroked, unlike every other
   SBOL glyph here, because it is a line — a strand peeling off the circle —
   rather than a shape. Being unfilled, it is also the one origin mark the
   export does not have to punch out of the backbone (see punchBackbone). */
.sbol-arc {
  fill: none;
  stroke: var(--ink);
  stroke-linecap: round;
  cursor: zoom-in;
  transition: stroke 0.12s;
}
.sbol-arc.hovered,
.sbol-arc.selected,
.selected .sbol-arc { stroke: var(--hl); }
.sbol-arc.selected,
.selected .sbol-arc { cursor: zoom-out; }

/* origin of replication: a circle filled with the plate background (so it sits
   over the backbone), outlined black until highlighted */
.sbol-ring {
  fill: var(--panel);
  stroke: var(--ink);
  cursor: zoom-in;
  transition: stroke 0.12s;
}
.sbol-ring.hovered,
.sbol-ring.selected,
.selected .sbol-ring { stroke: var(--hl); }
.sbol-ring.selected,
.selected .sbol-ring { cursor: zoom-out; }
.sbol-hit { cursor: zoom-in; }
.sbol-extent {
  fill: none;
  opacity: 0;
  transition: opacity 0.12s;
  pointer-events: none;
}
.sbol-extent.shown { opacity: 1; }

/* click-to-focus: the whole map is faded as one layer in JS (so the backbone
   stays occluded behind the features rather than showing through) and the
   selected feature is lifted back to full opacity with the emphasis below */
.feature-patch.selected {
  stroke-width: calc(7px * var(--zw, 1));
  cursor: zoom-out;
}
.feature-label.selected {
  font-weight: 700;
  opacity: 1;
  cursor: zoom-out;
}
.leader-line.selected { opacity: 0.9; }

/* ---------- tooltip: a paper bubble ---------- */
.plasmid-tooltip {
  position: absolute;
  pointer-events: none;
  opacity: 0;
  background: var(--paper-hi);
  border-radius: var(--r-md);
  padding: 10px 14px;
  font-size: 0.85rem;
  color: var(--ink);
  box-shadow: 0 6px 22px rgba(39, 45, 37, 0.18);
  max-width: 268px;
  z-index: 50;
  transition: opacity 0.08s;
}
.tt-id {
  font-family: var(--mono);
  font-variation-settings: "MONO" 1, "CASL" 0.4;
  color: var(--bronze);
  font-size: 0.8rem;
  margin-left: 5px;
}
.tt-blurb { color: var(--ink-soft); font-size: 0.8rem; margin-top: 4px; line-height: 1.5; }