/* prose.css -- Blocks that appear inside the argument: prose tables, step lists, the pipeline ribbon, and the photographs.
 *
 * Part 4 of 9. These files were one style.css and are still one
 * stylesheet: equal-specificity rules resolve by document order, so the
 * <link> tags in every page must stay in this order and nothing may move
 * between files without checking what it lands after.
 *   tokens.css -> layout.css -> type.css -> prose.css -> charts.css -> sources.css -> paper.css -> interactive.css -> home.css
 *
 * See site/README.md for the rules that govern all of them. */

/* --- Prose tables and step lists ----------------------------------------- */

/* The methods page prints a reference table (markers, primers, databases) in
 * the flow of the text rather than behind a dialog like the chart tables: it is
 * the content, not a backing view of a picture. Held to the prose column and
 * scrolls inside itself, because primer sequences do not wrap. */
.table-figure {
  margin: var(--space-5) 0;
  width: 100%;
  max-width: 100%;
  overflow-x: auto;
}
.data-table {
  border-collapse: collapse;
  width: 100%;
  font: 400 var(--size-1)/var(--lh-snug) var(--font-display);
}
.data-table caption {
  caption-side: bottom;
  text-align: left;
  color: var(--text-muted);
  font-size: var(--size-1);
  padding-top: var(--space-3);
}
.data-table th, .data-table td {
  text-align: left;
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--border);
}
/* Only the primer columns refuse to wrap -- a sequence broken across two lines
 * cannot be read off the screen. Everything else wraps so the table fits
 * without a horizontal scroll on a normal window.
 *
 * Scoped to the one table that holds sequences. As a bare nth-child rule this
 * set "the fourth column" in monospace on every table on the page, which put
 * "Well drained" in a code face in the soil-survey table below. */
.data-table--seq td:nth-child(4), .data-table--seq td:nth-child(5) { white-space: nowrap; }
.data-table th {
  font-weight: 600;
  color: var(--text-secondary);
  border-bottom-color: var(--text-muted);
}
.data-table tbody tr:hover { background: var(--surface-raised); }
/* Primer sequences are the one thing here worth reading character by character. */
.data-table--seq td:nth-child(4), .data-table--seq td:nth-child(5) {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--size-1);
}

/* Every other table on the methods page is mostly statistics, and a column of
 * figures is only comparable down the column if the digits line up. */
.data-table td { font-variant-numeric: tabular-nums; }

/* Identifiers and file names read character by character, like the primer
 * sequences in the table above them. */
code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.875em;
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.05em 0.3em;
}

.steps { padding-left: var(--space-4); margin: 0 0 var(--space-4); }
.steps li { margin-bottom: var(--space-3); }
.steps strong { color: var(--accent); }

/* --- The pipeline ribbon --------------------------------------------------- */

/* Methods is the longest page on this site -- fifteen sections, eight tables --
 * and until this it was the only page carrying no figure at all. Not for want
 * of a subject: the page opens by describing a three-stage pipeline in prose and
 * then lists the three stages, which is a diagram written out longhand.
 *
 * So this draws it, and draws it out of the payload. Every quantity in it is a
 * `data-stat` slot like every other number on the site, which is what keeps a
 * figure about the pipeline from being the one place a figure is typed in by
 * hand -- and what makes it fail loudly, in the contract test, if a stage's
 * number ever stops being computed.
 *
 * It is a ribbon rather than a chart because the three numbers are not
 * comparable: reads per core, distinct sequences and genera are three different
 * units, and any shared axis between them would be a lie about scale. What is
 * true and worth showing is the order and the narrowing, and that is all the
 * geometry here claims. */
.ribbon { margin: 0 0 var(--space-4); }

.ribbon__flow {
  position: relative;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  --ribbon-gap: var(--space-3);
  gap: var(--ribbon-gap);
  margin: 0;
  padding: var(--space-4) 0 0;
  list-style: none;
}

/* The line the stages sit on, drawn behind them, running between the first and
 * last stage's centers rather than edge to edge -- a rule that overshoots the
 * outer stages reads as a cut-off axis.
 *
 * Half a column in from each side, and a column is not a third of the row: two
 * gaps come out of the width first. Written as `100% / 6` it lands a few pixels
 * outside each end dot, which at this size is not a subtlety -- the rule visibly
 * fails to reach the first and last nodes it is meant to connect. */
.ribbon__flow::before {
  content: "";
  position: absolute;
  top: 0.32rem;
  left: calc((100% - 2 * var(--ribbon-gap)) / 6);
  right: calc((100% - 2 * var(--ribbon-gap)) / 6);
  height: 2px;
  border-radius: var(--radius);
  background: color-mix(in oklab, var(--accent) 45%, var(--tint-base));
  transform-origin: left center;
}
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .ribbon__flow::before {
      animation: rule-across linear both;
      animation-timeline: view();
      animation-range: entry 25% cover 40%;
    }
  }
}
@keyframes rule-across {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

/* A column rather than a run of blocks, so the tool line sits on one level
 * across all three stages.
 *
 * The unit lines are different lengths and two of them wrap; left to stack
 * naturally, each stage's tool line starts wherever its own unit line happened
 * to end, and three labels at three heights read as a rendering fault rather
 * than as a row -- the same failure the chart legends had, for the same reason.
 * So the unit grows to fill whatever the tallest one needs and the tool line is
 * pushed to the bottom of every column. */
.ribbon__stage {
  position: relative;
  display: flex;
  flex-direction: column;
  padding-top: var(--space-4);
  text-align: center;
}
/* The node on the line. Filled from the surface outward so the rule appears to
 * pass behind it rather than to stop at it. */
.ribbon__stage::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  width: 9px;
  height: 9px;
  margin: -0.02rem 0 0 -4.5px;
  border-radius: var(--radius-round);
  background: var(--accent);
  box-shadow: 0 0 0 3px var(--surface);
}

.ribbon__value {
  display: block;
  font-size: var(--size-3);
  font-weight: 600;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
}
/* The wash belongs to running prose; inside a figure the numbers are already
 * the subject and marking them twice reads as a highlighter on a label. */
.ribbon__value b[data-stat] { background-image: none; }

.ribbon__unit {
  display: block;
  flex: 1;
  margin-top: var(--space-1);
  font: 400 var(--size-1)/var(--lh-snug) var(--font-display);
  color: var(--text-secondary);
}
.ribbon__tool {
  display: block;
  margin-top: var(--space-2);
  font: 500 var(--size-1)/var(--lh-snug) var(--font-display);
  color: var(--text-secondary);
}
.ribbon__tool b[data-stat] { background-image: none; font-weight: 500; }

.ribbon figcaption {
  margin-top: var(--space-4);
  font: 400 var(--size-1)/var(--lh-body) var(--font-display);
  color: var(--text-secondary);
}

/* Below about a phone's width three columns of this leave two words a line. The
 * stages stack, and the connecting rule -- which was a picture of left-to-right
 * order -- is dropped rather than rotated: a vertical rule behind a stacked list
 * is the border of a blockquote, which says something else entirely. */
@media (max-width: 560px) {
  .ribbon__flow {
    grid-template-columns: 1fr;
    gap: var(--space-4);
    padding-top: 0;
  }
  .ribbon__flow::before { display: none; }
  .ribbon__stage {
    padding: 0 0 0 var(--space-4);
    text-align: left;
    border-left: 2px solid color-mix(in oklab, var(--accent) 45%, var(--tint-base));
  }
  .ribbon__stage::before { display: none; }
}

/* --- Photographs ----------------------------------------------------------- */

/* Photographs share the prose column like every other figure -- see the note
 * beside --measure about why there is no wider figure track. */
.photo {
  margin: var(--space-5) 0;
}

/* The shadow is the only thing on this site that lifts a block off the page,
 * and photographs are the only blocks that should be lifted: everything else
 * here is text, tables and drawings, which are of the page rather than objects
 * resting on it. It also does a plain job on the light palette, where a
 * photograph with a pale sky along its top edge otherwise dissolves into the
 * paper and the hairline border is left holding the whole boundary. */
.photo__frame {
  overflow: hidden;
  border-radius: var(--radius);
  /* No border. The picture is its own edge, and a photograph is the one block
   * here big enough not to need a line drawn round it -- the shadow is what
   * separates it from the page. Where that leaves a pale overcast sky running
   * into a light background along the top, the picture is allowed to do it. */
  box-shadow: var(--shadow-soft);
  /* The frame is the element with a height; the image fills it. */
  min-height: 0;
}

/* Photographs run at their true proportions here, and any cropping happens in
 * soil-media rather than in the browser. A crop expressed as object-fit is
 * invisible in the file, so the pixels a reader never sees are still downloaded
 * and the alt text still describes them; done at build time it is recorded in
 * one place and the file on disk is what the page shows. */
.photo__frame picture,
.photo__frame img {
  display: block;
  width: 100%;
  height: auto;
}

/* Every photograph on the site is 4:3 and spans the prose column, so the caption
 * spans it too. There was a `.photo--portrait` variant here that held the phone
 * portraits to a third of the column and moved the caption alongside; it is gone
 * because it was the wrong answer twice over. A 9:16 frame at full width stands
 * 1470px tall, and held narrow enough not to, it left most of the line as blank
 * paper -- which a caption beside it does not fill, since two lines of text
 * against a 600px image leaves the hole roughly where it was. Those photographs
 * are cropped to 4:3 by soil-media instead, which is a question about pictures
 * answered where the pictures are made rather than worked around in CSS. */
.photo figcaption {
  font: 400 var(--size-2)/var(--lh-body) var(--font-display);
  color: var(--text-secondary);
  margin: var(--space-3) 0 0;
}

/* Every photograph here was taken on a phone, most of them in flat overcast
 * light, and they arrive slightly hazy: greens that read gray, and skies that
 * wash out the top third of the frame. A small correction is worth making, and
 * the ceiling on it is that these are records of a real field -- so the aim is
 * the scene as it looked standing there, not a scene that looks better than it
 * was. Contrast and saturation just past 1 do that; anything further starts
 * inventing a farm. */
.photo__frame img {
  filter: contrast(1.06) saturate(1.08);
}

/* On the dark palette an unmodified photograph glares -- it becomes the
 * brightest thing on the page by a wide margin, which is emphasis nobody asked
 * for. Knocking the brightness back sits it at about the weight of the
 * surrounding text. The tone correction above still applies, since the flat
 * light it answers is in the file rather than in the theme. */
:root[data-theme="dark"] .photo__frame img {
  filter: brightness(0.86) saturate(1.02) contrast(1.06);
}

@media print {
  /* The dark-mode correction is undone with the rest of the palette; a printer
   * given a deliberately dimmed photograph returns a muddy one. */
  .photo__frame img { filter: none; }
}

