/* Integration layer: everything needed to seat the standalone panel inside the
   site, and nothing else. Loaded between the panel's own CSS and style.css, so
   the site still wins any argument. */

/* ---- the sheet becomes an overlay, not a ground -------------------------
   Standalone the panel painted its own near-black. Here the section's own
   background must show through - and so must the DNA helix, which is a fixed
   full-page canvas at z-index 0 behind everything. Transparent, the drawing
   reads as an overlay ON the helix; opaque, it punches a hole in it. */
#structures .app { background: none; }
#structures .sheet { background: none; }
#structures { position: relative; z-index: 1; padding: 0; min-height: 0; }

/* The site's --bg is the panel's ground token. Rebind the panel's ink to the
   site's own text colour so light mode carries through for free.

   --mono is rebound too, to the site's Inter. The drawing shipped in a system
   monospace, which read as a foreign object against a page set entirely in
   Inter - and the mono was never the more correct choice anyway: ISO 3098
   drafting lettering is a single-stroke SANS, not a fixed-pitch face. One
   typeface now runs from the About copy through the sheet to the detail panel.

   Rebound HERE rather than in the panel, because the standalone sheet does not
   load Inter and should keep its own stack. The panel already re-measures on a
   webfont swap - document.fonts.ready.then(relayout) - so labels laid out
   against the fallback are corrected once Inter arrives, and every label width
   is measured from a probe element rather than assumed from a mono advance. */
#structures {
  --bg: transparent;
  --ink: var(--text-color);
  --mono: 'Inter', ui-sans-serif, system-ui, -apple-system, sans-serif;
}

/* A proportional face loses the one thing the drawing borrowed a monospace for:
   columns that line up. Inter's tabular figures give it back, so the title
   block, the zone rail and the caption metadata still align digit for digit. */
#structures .tblock,
#structures .rail-lbl,
#structures .cap-met,
#structures .cap-zn,
#structures .detail figcaption,
#structures .detail .d-ref .m {
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
}

/* The title block is the one thing that must stay legible over the helix, so it
   keeps a ground - taken from the live section colour, not a hardcoded black. */
#structures .tblock { background: var(--bg-color); }

/* ---- sentinels ---------------------------------------------------------
   Zero-height markers at the chapter boundaries. They are what the observer
   watches; nothing renders. */
#structures .chapter-sentinel {
  position: absolute; left: 0; width: 1px; height: 1px;
  pointer-events: none; visibility: hidden;
}

/* ---- the accordion, still here ----------------------------------------
   Present in the DOM always. Hidden only once JS has confirmed the panel is
   actually running, so a JS failure degrades to the real list rather than to
   nothing. Not display:none while visible-to-crawlers matters, but it is
   display:none once the panel is up - at that point it is the panel's detail
   layer, opened on demand. */
.structures-fallback .structures-chapter { scroll-margin-top: 6rem; }
html.js-panel #structures .structures-fallback { display: none; }

/* ---- THE DETAIL VIEW ---------------------------------------------------
   ISO 128-3:2022 cl. 4.12, "Enlarged features" - the live clause. ISO 128-34,
   the citation everyone reaches for, was withdrawn when 128-3:2021/2022
   cancelled and replaced 128-30/33/34/40/44/50; the text survives near-identical.
   It requires the region of interest to be "enclosed or encircled by a
   continuous narrow line (type 01.1), with the area thus enclosed identified by
   a capital letter", and the 2020/2022 edition adds that a leader line of the
   same register may join circle to letter for unambiguous relation. That is
   exactly what is drawn here.

   NO SCALE RATIO. The clause asks for "an indication of the scale beside it
   between parentheses", and this panel deliberately does not carry one: it is
   not a geometric enlargement of the feature, it is what the feature stands for.
   The figure is schematic and the title block already reads SCALE NTS, so
   "A (2:1)" would be a claim about a drawing that was never to scale. Better to
   omit a required field than to state it falsely.

   TYPE. Every size here is on the sheet's existing lettering ladder -
   7 / 8.5 / 10 / 12 / 17px, which is ISO 3098-1's heights at this sheet's
   implied 1.3px/mm. The first cut invented 13 / 10.5 / 9 / 7.5, and a second
   lettering ladder on one drawing is the loudest possible signal that something
   is a web card wearing a drawing's clothes.

   It replaces a layer that appended the site's accordion item 3608px below the
   fold, at the bottom of the five-viewport track, where clicking a label
   appeared to do nothing at all. */
/* No transition on the group: the ring and the leader carry the motion
   themselves, by being DRAWN - see drawIn() in integration.js. Fading the group
   in as well would put a fade on top of a draw and blunt both. */
#structures .detail-marks {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  pointer-events: none;
  opacity: 0;
}
#structures .detail-marks.on { opacity: 1; }

#structures .detail-marks.on .detail-letter { opacity: 1; }

/* Continuous narrow, one register above the grid and level with the leaders it
   sits among - the ring is drawing furniture, not emphasis. */
/* --ink-3, the same register as the leaders it sits among. The house split,
   latent in the sheet already: --ink-3 is lines that MEAN something (leader,
   reference line, ring); --ink-4 is lines that merely CONTAIN (frame, keyline). */
#structures .detail-ring {
  fill: none;
  stroke: var(--ink-3);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
#structures .detail-lead {
  stroke: var(--ink-3);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
#structures .detail-letter {
  fill: var(--ink);
  font-family: var(--mono);
  /* A rung above the body text: ISO 3098-1 puts the identifying letter larger
     than dimension figures, because it is what links the two views. */
  font-size: 12px;
  letter-spacing: .12em;
}

/* The other labels stay legible but stand down: the sheet now has one subject
   and it is not them. Hiding them outright would make the figure look like it
   had lost its callouts. */
/* !important, for the same reason as the pointer-events override above and not
   as a specificity patch: drawRest writes `w.style.opacity = '1'` INLINE on every
   label it draws, and an inline declaration beats any selector. Without it this
   rule computed to opacity 1 - the "other labels stand down" effect was dead from
   the day it was written, in every state, not merely after a repaint. It looked
   plausible in screenshots because the labels are drawn in --label rather than
   --ink to begin with. */
#structures .space[data-detail="on"] .word.stood-down { opacity: .28 !important; }
/* Not dimmed - GONE. These are the labels the sidebar's edge would cut through,
   and half a title reads as a rendering fault rather than as recession. */
#structures .space[data-detail="on"] .word.occluded { visibility: hidden; }
/* The picked label is gone while its detail is open - the enlarged view is the
   callout now, and showing both means the same title twice on one sheet. */
#structures .space[data-detail="on"] .word.picked { visibility: hidden; }

/* The detail panel. Placed against the atom it describes, inside the drawing
   space, bounded by the ring on the inside and the figure's extent on the
   outside - see the placement note in integration.js. */
#structures .detail {
  position: absolute;
  z-index: 3;
  box-sizing: border-box;
  /* 13px = 10mm at this sheet's scale, the same margin the sheet's own frame
     keeps on three sides. */
  padding: 16px;
  border: 1px solid var(--ink-4);
  /* Fully opaque. At 92% the dimmed labels underneath showed through the text,
     and a panel you can see the drawing through reads as a bug rather than as a
     material. A drawing's detail view sits ON the sheet. */
  background: var(--bg-color);
  font-family: var(--mono);
  /* The drawing's own hairline, not a UI shadow. A drop shadow would be the one
     thing on this sheet that no drafting instrument can make. */
  box-shadow: none;
}
#structures .detail[hidden] { display: none; }
/* No entrance motion on the detail pane. It is placed and it is there. */

#structures .detail .d-hd {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 8px;
}
#structures .detail .d-id {
  font-size: 10px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--label);
}
/* A close affordance in drawing language: a light multiplication sign on the
   rail register, not a UI chrome button. */
#structures .detail .d-x {
  appearance: none; background: none; border: 0; padding: 0 2px; cursor: pointer;
  font-family: var(--mono); font-size: 12px; line-height: 1;
  /* --ink-2, not --ink-3. Lines may sit at --ink-3; an interactive control may
     not - it measures about 2.95:1 on this ground, under the 3:1 floor for a UI
     component. This is the one place the drawing register and the contrast
     requirement disagree, and the control wins. */
  color: var(--ink-2);
}
#structures .detail .d-x:hover { color: var(--ink); }
#structures .detail .d-x:focus-visible { outline: 1px solid var(--ink); outline-offset: 3px; }

#structures .detail .d-rule {
  height: 0; margin: 6.5px 0 13px;
  border-top: 1px solid var(--rail);
}
#structures .detail .d-title {
  margin: 0; font-size: 17px; line-height: 1.25; font-weight: 400;
  letter-spacing: .04em; text-transform: uppercase; color: var(--ink);
}
#structures .detail .d-tag {
  margin: 7px 0 0; font-size: 10px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--ink-3);
}
#structures .detail .d-body {
  margin: 14px 0 0; font-size: 12px; line-height: 1.6;
  letter-spacing: .01em; color: var(--label);
}

/* Body paragraphs repeat; only the first gets its full top margin. */
#structures .detail .d-body + .d-body { margin-top: 8px; }

/* Blocks are CLONED out of the accordion, so they arrive carrying the site's own
   typography - and the site styles `p` explicitly, which beats anything the
   panel merely inherits. A paragraph nested inside a list item came through at
   the site's body size, several times the panel's, and blew the layout apart.
   Everything cloned is pinned to the sheet's ladder here. */
#structures .detail .d-body,
#structures .detail .d-list,
#structures .detail .d-list li,
#structures .detail .d-list p,
#structures .detail .d-list span,
#structures .detail .d-list em,
#structures .detail .d-list strong {
  font-size: 12px;
  line-height: 1.6;
  letter-spacing: .01em;
  font-weight: 400;
  font-style: normal;
  font-family: var(--mono);
  color: var(--label);
}
#structures .detail .d-list p { margin: 4px 0 0; }

/* Lists stay lists. Flattening every link into one reference block lost the
   sense of the ones whose text matters - Events has list items whose link is
   just an arrow, and on its own that is a row saying nothing. */
#structures .detail .d-list {
  margin: 14px 0 0; padding: 0; list-style: none;
  font-size: 12px; line-height: 1.6; color: var(--label);
}
#structures .detail .d-list li {
  position: relative; padding-left: 13px; margin-top: 5px;
}
/* An item mark on the sheet's own rail register, not a bullet glyph. */
#structures .detail .d-list li::before {
  content: ''; position: absolute; left: 0; top: .62em;
  width: 6px; height: 1px; background: var(--ink-3);
}
#structures .detail .d-inline {
  color: var(--ink); text-decoration: none;
  border-bottom: 1px solid var(--ink-4);
}
#structures .detail .d-inline:hover { border-bottom-color: var(--ink); }
#structures .detail .d-inline:focus-visible { outline: 1px solid var(--ink); outline-offset: 2px; }

/* A drawing inset, not a photo in a card: ruled frame, contained rather than
   cropped, and a numbered caption below in the figure's own numbering. Several
   images become a strip of equal views, which is how a drawing shows
   alternates - and eight of the nineteen items carry more than one. */
#structures .detail .d-fig { margin: 13px 0 0; }
/* Each view keeps its own proportions.

   The strip used to give every image an equal share of the row at a fixed
   height and crop with object-fit: cover, which on this content was severe:
   these are portrait photographs - nicoya1 is 3024x4032 - and a 151x84 landscape
   box showed a horizontal slice through the middle and discarded the rest. That
   is what read as the images being "compressed weirdly": not squashed, cropped.

   Sizing by HEIGHT with width:auto lets each view take exactly the width its
   aspect asks for, so a portrait photo is narrow and a wide one is wide, which
   is how a drawing shows a set of views. The row wraps rather than squeezing.
   object-fit stays `contain` for the case where max-width caps a very wide image
   - that is the only path left that could distort one. */
#structures .detail .d-strip {
  display: flex; flex-wrap: wrap; gap: 5px; align-items: flex-start;
}
#structures .detail .d-strip img {
  display: block;
  /* min-width because width:auto on an image that has not loaded yet resolves to
     its intrinsic width of zero - the whole strip collapsed to 2px slivers, being
     nothing but the two border edges, until the last byte arrived. The HEIGHT is
     explicit, so the row never changes height and the panel's placement, which is
     computed from offsetHeight at open, stays correct either way. */
  height: 150px; width: auto; min-width: 64px; max-width: 100%;
  object-fit: contain; object-position: center;
  border: 1px solid var(--ink-4);
  background: color-mix(in srgb, var(--ink) 4%, transparent);
}
#structures .detail .d-fig.multi .d-strip img { height: 104px; }
/* Carried content the extractor cannot express as prose - the allocation chart.

   RE-REGISTERED. The site draws it in four hues - a gold, two greys and a mint -
   with matching coloured swatches in the legend. On a sheet whose entire language
   is white hairlines on a near-black ground that is a second colour system, and
   the drawing has no vocabulary for it.

   Redrawn in the sheet's own device instead - see hatch() in integration.js.
   Every mark on this drawing is a line, so the wedges are hatched rather than
   toned, and they are told apart by ANGLE the way ISO 128-50 separates adjacent
   sectioned areas. Angle is keyed to series order, so wedge n and legend row n
   always agree however the allocation is reweighted upstream.

   The inline fills are presentation attributes, which CSS outranks; the legend
   swatches are inline STYLE, which needs !important. */
#structures .detail .d-extra { margin: 14px 0 0; }

/* The site absolutely-positions the pie inside a relative container that only
   exists under its accordion scope. That scope does not follow the content into
   the pane, so top:0/left:0 resolved against .detail itself - the chart pinned to
   the pane's top-left corner, straight over the title, and contributed no height,
   collapsing .d-extra to the legend alone. Put it back in flow. */
#structures .detail .d-extra .portfolio-chart-container {
  display: block; padding: 0; background: none; border: 0; position: static;
}
#structures .detail .d-extra svg {
  position: static; inset: auto;
  display: block; width: 100%; max-width: 190px; height: auto;
  margin: 0 0 2px;
}

/* Wedge outline at full ink; the tone inside is hatching, minted per pane in
   integration.js (see hatch()). The pattern lines themselves ride the same 1:2:4
   ladder as everything else on the sheet - thin. */
#structures .detail .d-extra svg path {
  stroke: var(--ink); stroke-width: .8; stroke-linejoin: round;
}
#structures .detail .d-extra svg pattern line {
  stroke: var(--ink); stroke-width: .7;
}

#structures .detail .d-extra .portfolio-legend {
  margin-top: 12px; display: grid; gap: 6px;
}
#structures .detail .d-extra .legend-item {
  display: grid; grid-template-columns: 10px 1fr; align-items: baseline; gap: 8px;
  font-size: 10px; letter-spacing: .02em; color: var(--label);
}
#structures .detail .d-extra .legend-color {
  width: 10px; height: 10px; border-radius: 0; align-self: center;
  border: 1px solid var(--ink-4);
}
/* The swatch repeats its wedge's angle, so it keys the chart rather than
   standing in for a colour. --hatch is written per row by hatch(). */
#structures .detail .d-extra .legend-color {
  background: repeating-linear-gradient(
    var(--hatch, 45deg),
    var(--ink) 0 .7px,
    transparent .7px 4px) !important;
}

/* The number is furniture and is set in caps; the author's caption is a
   sentence and keeps its own case. */
#structures .detail .d-fig figcaption .n { text-transform: uppercase; letter-spacing: .18em; }
#structures .detail .d-fig figcaption .c { text-transform: none; letter-spacing: .02em; }
#structures .detail .d-fig figcaption {
  margin-top: 7px; font-size: 8.5px; line-height: 1.5;
  color: var(--ink-3);
}
/* References. Every link the item carries, each stating where it goes: the host
   for an external document, VIEW for one of the site's own modals. A drawing
   lists its reference documents; it does not hide them behind prose. */
#structures .detail .d-refs {
  margin-top: 13px; padding-top: 10px;
  border-top: 1px solid var(--ink-4);
}
#structures .detail .d-refs-k {
  display: block; margin-bottom: 6px;
  font-size: 8.5px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--ink-3);
}
#structures .detail .d-ref {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  padding: 3px 0; text-decoration: none;
  font-size: 10px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--label);
}
#structures .detail .d-ref:hover { color: var(--ink); }
#structures .detail .d-ref:focus-visible { outline: 1px solid var(--ink); outline-offset: 2px; }
#structures .detail .d-ref .t { flex: 1 1 auto; min-width: 0; }
#structures .detail .d-ref .m {
  flex: 0 0 auto; letter-spacing: .12em; color: var(--ink-3);
}
#structures .detail .d-ref:hover .m { color: var(--ink-2); }

#structures .detail .d-link {
  display: inline-block; margin-top: 13px;
  font-size: 8.5px; letter-spacing: .16em; text-transform: uppercase;
  color: var(--label); text-decoration: none;
  border-bottom: 1px solid var(--ink-4); padding-bottom: 2px;
}
#structures .detail .d-link:hover { color: var(--ink); border-bottom-color: var(--ink); }
#structures .detail .d-link:focus-visible { outline: 1px solid var(--ink); outline-offset: 3px; }

/* ---- labels are navigation, so they must look and behave like it -------- */
#structures .word { pointer-events: auto; }

/* The panel disables labels while the structure is morphing, which is most of
   the track - the rest plateau is 16% of each segment. That left the headings
   dead at nearly every scroll position. They stay live here; integration.js
   reads a click during a morph as "take me to this chapter's lock point"
   instead of as "open this detail". */
#structures .space[data-state="moving"] .word {
  /* !important is doing real work here, not papering over specificity: the panel
     writes pointer-events:none as an INLINE style in drawMorph, and an inline
     declaration beats any selector. This is the one mechanism CSS gives you to
     overrule it, and the panel is a shared standalone artefact that should keep
     its own behaviour when it is not seated in this page. */
  pointer-events: auto !important;
  cursor: pointer;
}
#structures .word:focus-visible { outline: 1px solid var(--ink); outline-offset: 4px; }

@media (prefers-reduced-motion: reduce) {
  /* The spring is already bypassed in the panel; this stops the site's own
     background transition from re-introducing a slow cross-fade on every
     chapter change. */
  #structures { transition: none; }
}

/* The DNA's zoom affordance is fixed over the whole page. Inside the panel the
   scroll drives the structure, not the camera, so the hint would be telling you
   to do something that does not happen. */
/* The hint is created by scene.js with id="zoom-hint" and NO class, so the
   obvious `.zoom-hint` selector matched nothing at all; and it carries
   opacity:1 in its inline cssText, which only !important can beat. Under
   prefers-reduced-motion scene.js's animate() runs exactly one frame, so
   nothing else ever hides it - "SCROLL TO ZOOM" sat under the sheet for the
   whole of #structures telling you to do something that does not happen. */
body.in-structures #zoom-hint { opacity: 0 !important; pointer-events: none; }


/* ======================================================================
   THE DRAWING SET - ONE LATTICE, SCREEN-ANCHORED

   The panel arrived as a full technical sheet between two plainly-typeset
   sections, so it read as an insert rather than a crescendo. Drafting has the
   answer: sheets in a SET share their furniture - the same grid, the same filing
   margin - and only the sheet carrying the subject gets the full apparatus of
   frame, reference rail, title block and figure.

   This was first built as a grid painted per section, and that produced a hard
   seam between About and Work. Three separate reasons, all of them structural:

     1. #structures painted NO ground grid at all (content: none), so 4024px of
        page had nothing but the pinned sheet's own lattice.
     2. background-position-y was 0 relative to EACH SECTION's border box, so the
        horizontal lines restarted their phase at every boundary. #about is 900px
        tall and #structures 4024px; 900 mod 16 = 4 and 4024 mod 16 = 8, so the
        rows could never line up across a boundary even where both drew a grid.
     3. Each section masked its own grid to transparent over its top and bottom
        22%, so every boundary was a double fade to nothing.

   The fix is to stop painting the lattice per section at all. MEASURED: the
   sheet's SVG is 1:1 with CSS pixels, its vertical grid lines start at x=26 -
   which is exactly --set-margin - on the same 16/80 pitch as the page ground,
   and while the sheet is pinned its grid is SCREEN-ANCHORED: the first
   horizontal line sits at viewport y=67 at every scroll offset from 1900 to
   4800. A lattice that scrolls with the page can therefore agree with the
   sheet's at exactly one scroll position and no other.

   So the lattice is screen-anchored too: one fixed layer, the drafting table the
   drawing moves across. Continuity stops being something to maintain and becomes
   structural - a fixed background has no section boundaries in it. Verified: all
   102 vertical and 58 horizontal sheet grid lines land exactly on this lattice,
   at every scroll offset. The sheet then reads as a brighter REGION OF THE SAME
   LATTICE rather than a second grid.
   ---------------------------------------------------------------------- */
:root {
  --set-minor: rgba(255,255,255,.018);
  --set-major: rgba(255,255,255,.038);
  --set-rule:  rgba(255,255,255,.10);
  --set-margin: 26px;
}
html.light-mode, body.light-mode {
  --set-minor: rgba(0,0,0,.030);
  --set-major: rgba(0,0,0,.055);
  --set-rule:  rgba(0,0,0,.13);
}

/* The table. Fixed, so it never moves relative to the pinned sheet.
   --tx / --ty are the lattice phase, written on :root by integration.js from the
   sheet's own grid. The fallbacks here are the with-JS-but-no-sheet phase, used
   in the window before the panel has drawn; what a client with NO JS sees is
   decided by the --sg-grid fallback below, not by these. */
.sheet-table {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background-image:
    linear-gradient(to right,  var(--set-major) 1px, transparent 1px),
    linear-gradient(to bottom, var(--set-major) 1px, transparent 1px),
    linear-gradient(to right,  var(--set-minor) 1px, transparent 1px),
    linear-gradient(to bottom, var(--set-minor) 1px, transparent 1px);
  background-size: 80px 80px, 80px 80px, 16px 16px, 16px 16px;
  background-position:
    var(--tx, var(--set-margin)) var(--ty, 0px), var(--tx, var(--set-margin)) var(--ty, 0px),
    var(--tx, var(--set-margin)) var(--ty, 0px), var(--tx, var(--set-margin)) var(--ty, 0px);
  /* Hidden by default, ON PURPOSE. The previous per-section grid defaulted to
     opacity 1, so a client with no JS got a lattice; this one gets none. That is
     the right call rather than a regression: without JS the panel never runs,
     there is no sheet, and the page is the plain accordion. A drafting table
     with no drawing on it is decoration without its subject - and because this
     layer is fixed and full-viewport, a static default would also wash the grid
     over the hero, which is precisely what the coverage ramp exists to prevent.
     It also means no flash of lattice before the first paint. */
  opacity: var(--sg-grid, 0);
}

/* The filing margin. ISO 5457 puts 20mm on the binding edge. It is the one piece
   of sheet furniture that runs the whole set rather than stopping at a sheet
   edge, and now it genuinely does: one line, the full height of the view, at the
   same x the sheet's own lattice starts from. Arrives a beat behind the grid so
   the two do not land as a block.

   A SIBLING of the table, not a child. Nested inside it, its opacity was
   multiplied by the table's - measured 0.483 x 0.275 = 0.133 mid-ramp - so it
   rendered at about half its intended strength for the whole arrival, and a
   check that read the rule's own opacity property could not see it. */
.sheet-rule {
  position: fixed;
  z-index: 0;
  top: 0; bottom: 0;
  left: var(--tx, var(--set-margin));
  width: 1px;
  background: var(--set-rule);
  opacity: var(--sg-rule, 0);
}

/* Content sits above the table. The sections are already position:relative with
   z-index auto, and the table is z-index 0 earlier in the DOM, so they paint
   over it without needing a z-index of their own.

   The footer is not: it is position:static, and a positioned z-index:0 box paints
   ABOVE non-positioned in-flow content in the same stacking context, so the
   lattice was drawing over the footer's text. It is 201px tall and sits at the
   bottom of the page where coverage still holds the table at full opacity, so
   this was visible rather than theoretical. */
.sheet-ground { position: relative; }
footer { position: relative; }

/* Without JS the panel never initialises, so #structures.app is an empty block
   that still claims its full CSS height - .track is calc(--vh * (1 + 2*--span))
   and owes nothing to script. That left several blank viewports above the
   accordion. .js-panel is added synchronously once the panel is confirmed up, so
   this is the exact mirror of the rule that hides the accordion. */
html:not(.js-panel) #structures .app { display: none; }


/* ======================================================================
   THE MODALS, AS SHEETS
   Portfolio, Writing, Structure, Experiments and Tools are the site's own
   overlays, and they were the last surface still speaking the old dialect:
   12px rounded corners, a transform: scale(.95) entrance, and 0.3s ease. The
   drawing has no radii, nothing on it scales, and nothing eases - so opening one
   from a detail pane was a change of language mid-sentence.

   They are restyled here as further SHEETS laid over the page: square, hairline-
   framed, on the sheet's ink and its lettering ladder, and drawn on rather than
   popped. Nothing about their MARKUP changes, so the site's own handlers, focus
   management and close behaviour are untouched.

   `body ` prefixes throughout, because integration.css is loaded BEFORE style.css
   so that the site can win any argument - which means matching specificity would
   lose. This is the narrowest way to outrank it without !important.
   ---------------------------------------------------------------------- */
body .modal-overlay {
  background: color-mix(in srgb, var(--bg-color) 92%, transparent);
  transition: opacity 150ms linear, visibility 150ms linear;
}

body .modal-overlay .modal-content {
  border-radius: 0;                       /* a drawing has no rounded corners */
  border: 1px solid var(--ink-4, rgba(255,255,255,.26));
  background: var(--bg-color);
  padding: 28px 32px 36px;
  /* Drawn on, not scaled up: the same wipe the detail pane uses, running down
     from the top edge as a sheet is laid on a table. Linear, because the idiom
     is an instrument at constant speed. */
  transform: none;
  clip-path: inset(0 0 100% 0);
  transition: clip-path 200ms linear;
}
body .modal-overlay.active .modal-content {
  transform: none;
  clip-path: inset(0 0 0 0);
}

/* Title and subtitle onto the sheet's ladder, matching the detail pane's head. */
body .modal-overlay .modal-content h2 {
  font-size: 17px; line-height: 1.25; font-weight: 400;
  letter-spacing: .04em; text-transform: uppercase;
  margin: 0 0 7px;
}
body .modal-overlay .modal-subtitle {
  font-size: 10px; letter-spacing: .16em; text-transform: uppercase;
  opacity: 1; color: var(--ink-3, rgba(255,255,255,.42));
  margin: 0 0 22px; padding-bottom: 16px;
  border-bottom: 1px solid var(--ink-4, rgba(255,255,255,.26));
}

/* The close control in the same register as the detail pane's, and at --ink-2
   rather than a half-opacity glyph: --ink-3 measures under the 3:1 an
   interactive control needs. */
body .modal-overlay .modal-close {
  font-size: 20px; line-height: 1; opacity: 1;
  color: var(--ink-2, rgba(255,255,255,.64));
  transition: color 150ms linear;
}
body .modal-overlay .modal-close:hover { color: var(--ink, #fff); }

/* Item labels read as captions, like FIG. numbers on the sheet. */
body .modal-overlay .modal-project-label,
body .modal-overlay .link-preview-domain,
body .modal-overlay .pdf-size,
body .modal-overlay .structure-caption {
  font-size: 8.5px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--ink-3, rgba(255,255,255,.42));
}

/* Every image framed the way the detail pane frames its insets: a hairline
   keyline, square, no radius and no shadow. */
body .modal-overlay .modal-images img,
body .modal-overlay .project-images img,
body .modal-overlay .link-preview-image img,
body .modal-overlay .experiment-video-wrapper {
  border-radius: 0;
  border: 1px solid var(--ink-4, rgba(255,255,255,.26));
  box-shadow: none;
}
/* Same crop, same fix: the site sizes these 180x120 with object-fit: cover, so
   every portrait photograph loses most of its frame. Height-sized with width
   auto, each keeps its own proportions. */
body .modal-overlay .modal-images,
body .modal-overlay .project-images { flex-wrap: wrap; align-items: flex-start; }
body .modal-overlay .modal-images img,
body .modal-overlay .project-images img {
  width: auto; height: 190px; max-width: 100%;
  object-fit: contain;
}
body .modal-overlay .modal-images img:hover,
body .modal-overlay .project-images img:hover {
  transform: none;                      /* nothing on this sheet scales */
  border-color: var(--ink-2, rgba(255,255,255,.64));
}

/* Rules between list rows in the drawing's containing register. */
body .modal-overlay .modal-experiment-list li,
body .modal-overlay .experiment-list li,
body .modal-overlay .compact-list li {
  border-bottom-color: var(--ink-4, rgba(255,255,255,.26));
}
body .modal-overlay .link-preview-card {
  border-radius: 0;
  border: 1px solid var(--ink-4, rgba(255,255,255,.26));
  transition: border-color 150ms linear;
}
body .modal-overlay .link-preview-card:hover { border-color: var(--ink-2, rgba(255,255,255,.64)); }

@media (prefers-reduced-motion: reduce) {
  body .modal-overlay .modal-content,
  body .modal-overlay.active .modal-content {
    transition: none; clip-path: none;
  }
  body .modal-overlay { transition: none; }
}


/* ======================================================================
   THE SPECIMEN SHEET
   The V14 docking structure was the most distinctive artefact on the site and
   the best hidden: two clicks deep behind Science, in a generic centred card,
   with thirteen words of context and NO representation at all without
   JavaScript. It is a sheet now, with its own URL.

   Framed as a specimen under examination rather than a widget in a box: one
   hairline rectangle, no radius, no shadow, no card. The identification table
   beside it carries what the file actually says - which chain is the peptide
   that was designed and which is the receptor it was docked into. Nothing on
   the sheet claims anything the coordinates do not.
   ---------------------------------------------------------------------- */
#specimen {
  position: fixed; inset: 0; z-index: 200;
  display: grid; place-items: center;
  padding: 3vh 3vw;
  background: color-mix(in srgb, var(--bg-color) 94%, transparent);
  font-family: 'Inter', ui-sans-serif, system-ui, sans-serif;
}
#specimen[hidden] { display: none; }

.specimen-sheet {
  width: min(1180px, 100%);
  max-height: 94vh; overflow-y: auto;
  box-sizing: border-box;
  padding: 22px 26px 26px;
  border: 1px solid var(--ink-4, rgba(255,255,255,.26));
  background: var(--bg-color);
  /* Drawn on, like every other surface here. */
  clip-path: inset(0 0 100% 0);
  transition: clip-path 200ms linear;
  scrollbar-width: thin; scrollbar-color: var(--ink-4) transparent;
}
#specimen.in .specimen-sheet { clip-path: inset(0 0 0 0); }

.sp-head { display: flex; align-items: baseline; gap: 14px; }
.sp-fig {
  font-size: 10px; letter-spacing: .2em; color: var(--ink-3, rgba(255,255,255,.42));
}
.specimen-sheet h2 {
  margin: 0; flex: 1 1 auto;
  font-size: 17px; font-weight: 400; letter-spacing: .04em; text-transform: uppercase;
  color: var(--text-color);
}
.sp-close {
  appearance: none; background: none; border: 0; cursor: pointer;
  font-size: 20px; line-height: 1; padding: 0 2px;
  color: var(--ink-2, rgba(255,255,255,.64));
  transition: color 150ms linear;
}
.sp-close:hover { color: var(--text-color); }
.sp-sub {
  margin: 6px 0 18px; padding-bottom: 14px;
  border-bottom: 1px solid var(--ink-4, rgba(255,255,255,.26));
  font-size: 10px; letter-spacing: .16em; text-transform: uppercase;
  color: var(--ink-3, rgba(255,255,255,.42));
}

.sp-body { display: grid; grid-template-columns: minmax(0,1.55fr) minmax(260px,1fr); gap: 26px; }
@media (max-width: 820px) { .sp-body { grid-template-columns: 1fr; } }

/* The stage: one ruled rectangle, and nothing else. */
.sp-view {
  position: relative;
  aspect-ratio: 4 / 3; width: 100%;
  border: 1px solid var(--ink-4, rgba(255,255,255,.26));
  background: color-mix(in srgb, var(--text-color) 3%, transparent);
}
.sp-view canvas { display: block; }

/* Named views. Three small views under one large one announce that the large
   one moves - the affordance is the layout, not a tooltip. They are buttons, so
   the keyboard gets them for free, and 4A is also the reset. */
.sp-views { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-top: 8px; }
.sp-vw {
  appearance: none; background: none; border: 0; padding: 0; cursor: pointer;
  display: block; text-align: left;
}
.sp-vw .thumb {
  display: block; aspect-ratio: 4 / 3; width: 100%;
  border: 1px solid var(--ink-4, rgba(255,255,255,.26));
  background-size: cover; background-position: center;
  transition: border-color 150ms linear;
}
.sp-vw .cap {
  display: block; margin-top: 5px;
  font-size: 7px; letter-spacing: .16em; text-transform: uppercase;
  color: var(--ink-3, rgba(255,255,255,.42));
  transition: color 150ms linear;
}
.sp-vw:hover .thumb, .sp-vw[aria-pressed="true"] .thumb { border-color: var(--ink-2, rgba(255,255,255,.64)); }
.sp-vw:hover .cap,   .sp-vw[aria-pressed="true"] .cap   { color: var(--text-color); }
.sp-vw:focus-visible .thumb { outline: 1px solid var(--text-color); outline-offset: 2px; }

/* The identification table - what the modal never carried. */
.sp-k {
  display: block; margin-bottom: 8px;
  font-size: 8.5px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--ink-3, rgba(255,255,255,.42));
}
.sp-table { width: 100%; border-collapse: collapse; }
.sp-table th, .sp-table td {
  text-align: left; vertical-align: baseline;
  padding: 6px 0; font-weight: 400;
  border-bottom: 1px solid var(--ink-4, rgba(255,255,255,.26));
}
.sp-table th {
  width: 92px; padding-right: 12px;
  font-size: 8.5px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--ink-3, rgba(255,255,255,.42));
}
.sp-table td { font-size: 11px; letter-spacing: .01em; color: var(--ink-2, rgba(255,255,255,.64)); }
.sp-note {
  margin: 14px 0 0; font-size: 11px; line-height: 1.6;
  color: var(--ink-2, rgba(255,255,255,.64));
}
.sp-src {
  display: inline-block; margin-top: 16px; padding-bottom: 2px;
  font-size: 8.5px; letter-spacing: .16em; text-transform: uppercase;
  color: var(--ink-2, rgba(255,255,255,.64)); text-decoration: none;
  border-bottom: 1px solid var(--ink-4, rgba(255,255,255,.26));
  transition: color 150ms linear, border-color 150ms linear;
}
.sp-src:hover { color: var(--text-color); border-bottom-color: var(--text-color); }

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