/* The rendered original document — the fragment public/lib/wdf-html.mjs builds from
   GET …/articles/{ref}/source-html — styled once for every surface that mounts it. The
   studio's reading area is the one that does today. A page links this file and puts
   the "document" class on the element that holds the fragment. A second copy of these
   rules is what drifts, and a page's inline <style> is outside the stylelint gate.
   @tt-about reading-surface

   Structure only: heading scale, list and table shape, the page marker, the source
   document's two flags, and the spoken-form markup. Which line the reader is on is each
   surface's own mark, and that mark sets background and radius only — the element moves
   on every arrow key, so a border, padding or an offset outline would reflow the column
   under a narrator who is reading it. Type size and line height are the surface's, so the
   reading settings reach the document through its container; the reading column's width is
   the one exception and is drawn below, because a container capped at the column would
   leave a wide table nothing to break out into. */
.document {
  /* A manuscript is not a card. Every surface mounts this fragment on an `<article>`, and
     ui.css draws a bare `<article>` as one: a filled, bordered and rounded box with padding, a
     bottom margin, a two-column grid and a row gap. The page around it is the reading surface,
     so the container states its own box and takes the grid below for the reading column. */
  margin: 0;
  padding: 0;
  border: none;
  border-radius: 0;
  background: none;
  gap: 0;
  /* The containing block for the one thing drawn against the document rather than its own
     host: a page marker inside a table cell, below. Nothing else in the fragment is
     positioned against an ancestor. */
  position: relative;

  /* The reading column and the escape from it. Every block sits in the `content` track,
     capped at the reader's own column width, and a table too wide for that column is placed
     in the `full` track instead, which is as wide as the surface gives the document. Both
     gutters take the minimum 0, so a block spanning `full` can never widen the tracks.
     A grid container does not collapse its children's block margins, which is what the
     rhythm rules below are shaped around. --_column is named here so the page marker below
     can find the same column's edges from inside a table. */
  --_column: var(--reading-max-width, var(--reading-width));
  display: grid;
  grid-template-columns:
    [full-start] minmax(0, 1fr)
    [content-start] minmax(0, var(--_column))
    [content-end] minmax(0, 1fr) [full-end];

  /* The doubled class is deliberate: the card rule reaches these same elements as
     `article > :not(…)` and would otherwise win, giving every block the full width. */
  & :is(div, figure, section):has(table, pre):not(table *) > * { grid-column: content; }
  &.document > * { grid-column: content; }

  & :is(h1, h2, h3, h4, h5, h6) {
    margin-block: var(--size-7) var(--size-2);
    line-height: var(--font-lineheight-1);
  }
  /* Scale the document's hierarchy with the reading size inherited from its surface. */
  & h1 { font-size: 2em; }
  & h2 { font-size: 1.5em; }
  & :is(h3, h4, h5, h6) { font-size: 1.25em; }

  & p { margin-block: var(--size-3); }
  & .author { color: var(--text-2); font-style: italic; }

  /* Give notes, boxes and quotations the same neutral border at their leading edge. */
  & :is(blockquote, aside) {
    margin-inline: 0;
    padding-inline-start: var(--size-4);
    border-inline-start: var(--border-size-2) solid var(--border-color);
    color: var(--text-2);
  }

  & :is(ul, ol) { padding-inline-start: var(--size-6); }
  & dt { font-weight: var(--font-weight-6); }

  & table {
    display: block;
    inline-size: fit-content;
    max-inline-size: 100%;
    overflow-x: auto;
    margin-inline: auto;
    margin-block: var(--size-5);
    border-collapse: collapse;
    font-size: 0.9em;
  }
  & caption {
    margin-block-end: var(--size-2);
    color: var(--text-2);
    font-size: 0.75em;
    text-align: start;
  }
  & :is(th, td) {
    padding: var(--size-2);
    border: var(--border-size-1) solid var(--border-color);
    text-align: start;
    vertical-align: top;
  }
  & th { background: var(--surface-2); }

  & figure { margin-inline: 0; }
  & figcaption { color: var(--text-2); font-size: 0.75em; }
  & img { max-inline-size: 100%; height: auto; }

  /* The column's rhythm under the grid. Two blocks in a row would otherwise take both
     margins — the one's end and the other's start — where block layout collapsed them to the
     larger of the two, so every gap would grow. Each block in the column therefore ends flush
     and carries the whole gap above it in its start margin, which is the value the collapsing
     pair produced; the space under the last block is the surface's own bottom padding. Keep
     these two rules after the per-element rules above, whose start margins they preserve.
     A block nested inside one of them is not a grid item and collapses as before. */
  & > :is(p, h1, h2, h3, h4, h5, h6, table, ul, ol, dl, blockquote, aside, figure, pre, hr, div) {
    margin-block-end: 0;
  }
  /* The one pair that loses by that: a table's end margin was the larger of the two, so the
     block after a table takes it back — except a heading, which brings more of its own. */
  & > table + :not(h1, h2, h3, h4, h5, h6) { margin-block-start: var(--size-5); }

  /* Nested source containers inherit the reading tracks so only their tables and
     preformatted blocks escape the column. Content inside table cells stays in cells. */
  & :is(div, figure, section):has(table, pre):not(table *) {
    display: grid;
    grid-template-columns: subgrid;
    min-inline-size: 0;
  }
  &.document :is(table, pre, div:has(table, pre), figure:has(table, pre), section:has(table, pre)):not(table *) {
    grid-column: full;
  }
  & pre {
    inline-size: fit-content;
    max-inline-size: 100%;
    overflow-x: auto;
    margin-inline: auto;
  }

  /* The source page marker, drawn as the webarch content editor draws it: a hairline rule
     across the reading column with the page number centred astride it, so the page a narrator
     names means the same page in both places. The marker is a sentence here — its reading is
     generated and the sentence mark rides on this element — so it keeps the status dot the
     surface puts on it, and that dot, rather than the editor's `PB` margin label, is what the
     margin column carries ([[reading-surface]] § Invariants). */
  & .pagebreak {
    display: flex;
    justify-content: center;
    align-items: center;
    padding-block: var(--size-2);
    /* Two hairlines with a gap between them, the shape the editor's repeating image draws.
       The band is exactly as tall as that pair and sits in the middle of the box, so the
       number's chip below breaks the line where it crosses it. */
    --_rule: repeating-linear-gradient(
      to bottom,
      transparent 0 var(--border-size-1),
      var(--border-color) var(--border-size-1) var(--border-size-2));
    background-image: var(--_rule);
    background-repeat: no-repeat;
    background-position: center;
    background-size: 100% var(--border-size-3);
  }
  & .pagebreak::after {
    content: attr(data-page);
    padding-inline: var(--size-1);
    /* The reading surface's own background, so the chip hides the line under it in either
       theme. A literal white would read as a light patch in dark mode. */
    background-color: var(--surface-1);
    color: var(--text-2);
    font-size: 0.75em;
  }
  /* Inside a list item the marker keeps its block box, so the line it interrupts ends
     before it and the text after it starts below it, as in a paragraph. It draws across the
     item from an inset that leaves the status dot its own place: --pagebreak-inset is the
     surface's handle on that place, and the studio puts the dot in it. */
  & li .pagebreak {
    --pagebreak-inset: var(--size-3);
    margin-inline-start: var(--pagebreak-inset);
  }
  /* Inside a table cell the marker's box stays in the cell — that is what ends the line
     before the break and grows the row — and holds only the dot, at the cell's edge. The
     rule and the number are its two pseudo-elements, positioned against the document and
     inset by the column's own gutters, so they cross the whole reading column at the height
     of the break, through the table's borders: a table is a scroll box, and the one box it
     cannot clip is one whose containing block is above it. The marker and a cell that is
     itself a sentence host give up the `position: relative` every sentence carries, or one
     of them would be that containing block instead. */
  & :is(td, th) .pagebreak {
    position: static;
    justify-content: start;
    background-image: none;
  }
  & :is(td, th):has(.pagebreak) { position: static; }
  & :is(td, th) .pagebreak::before,
  & :is(td, th) .pagebreak::after {
    position: absolute;
    inset-inline: max(0px, (100% - var(--_column)) / 2);
  }
  & :is(td, th) .pagebreak::before {
    content: '';
    block-size: var(--border-size-3);
    background-image: var(--_rule);
  }
  & :is(td, th) .pagebreak::after {
    inline-size: fit-content;
    margin-inline: auto;
  }
  /* A break that opens its cell: the row's first line, in the cells before it, is on the
     page before, so the rule goes under that line rather than through it. */
  & :is(td, th) .pagebreak:first-child { margin-block-start: 1lh; }

  /* An announcement the narrator reads — "Table." before a table, "End of quote." after a
     quotation — is an element the studio puts immediately before or after the container it
     brackets: a div beside a block element, a span beside an inline one, so the running text
     is not broken by an inline announcement. One rule per placement and none per container
     kind; the look is provisional ([[reading-surface]] § "The rendered document"). */
  & div[data-announcement] { margin-block-start: var(--size-3); }
  & span[data-announcement] { margin-inline: var(--size-1); }

  /* Theme-aware tints for the source document's two flags, rather than assuming a white
     background. The colour alone, not the `background` shorthand: these selectors reach the
     page marker too, and the shorthand would take the rule it draws itself with. */
  & [data-error] { background-color: color-mix(in oklch, var(--error) 18%, transparent); }
  & [data-warning] { background-color: color-mix(in oklch, var(--warning) 22%, transparent); }

  /* The spoken-form markup arrives with its attributes and draws nothing until a view
     setting says otherwise: the words inside a say read as the running text, and a break
     is an empty inline element that takes no space. Keep all three inline with no box of
     their own; a setting that shows them adds its own rule rather than changing this. */
  /* stylelint-disable-next-line selector-type-no-unknown -- say is the WDF element name the render keeps */
  & :is(say, say-voice, say-break) { display: inline; }
}
