/* The section pages: four sections on one page, each block one flat colour
   at its own natural height.

   Danny's ruling, 2026-08-16 -- "let's make each section page natural
   proportions and get rid of the raster. just use backgrounds... one color
   only per page : b/b is green, c/p is orange" -- SUPERSEDES the strip
   treatment this file used to carry (D6's raster background and D7's band
   mapping, spec 2026-08-15). What went, and deliberately:

   - the WebP is no longer painted. It was stretched to each block's own
     height, which is exactly what "natural proportions" rules out: a block
     is as tall as its content needs, and a fixed-proportion image scaled to
     that is a distortion nobody chose. The asset stays in source/ with its
     verify_artwork pins intact -- nothing re-exported, nothing deleted.
   - the two-colour blocks went with it. Bio/Biochem was green over yellow
     and Chem/Phys orange over blue, at the artboard's own inner seams; his
     ruling names one colour for each, so the seams have nothing left to
     pin.

   The colours below are the strip's own band colours, which is what sat
   beneath the raster as its pre-load fill all along -- so this is the
   image removed and what was under it kept, rather than a new palette. */

.sections-page {
  margin: 0;
  background: var(--page-ground);   /* so overscroll matches the blocks */
}

/* ---- the blocks ----------------------------------------------------------
   Natural height, one flat colour, and nothing above the first one: the
   page-head nav went with Danny's 2026-08-16 ruling and each block carries
   its own back arrow now. That also puts a block's top back at the viewport
   top when it is scrolled to, which is the line section-view.js measures for
   the address and the return flight -- with no sticky chrome to clear, the
   boundary is the block top itself, exactly as the spec defined it before
   the nav existed. */
/* THE BOTTOM PADDING IS WHAT KEEPS THE BLOCKS TOUCHING, and that is its
   whole job -- Danny, 2026-08-16: "remove those random gray bars between
   sections."

   They were margin collapse. The block ended with .section-graph-wrap, whose
   `margin: 2rem auto` is poster.css's; with the block's own bottom padding
   at zero there was nothing to contain that margin, so it collapsed straight
   out through the block's bottom edge and the PAGE's background showed
   through the 32px it left -- a grey bar under every section, measured at
   exactly 32px between all four. Give the block real bottom padding and the
   margin has something to sit inside.

   The wrap's own bottom margin is then zeroed here as well, so the space
   below a graph is this padding and nothing else, rather than a padding plus
   a margin that happen to add up. */
.secblock {
  position: relative;
  padding: 2.5rem 1rem 3rem;
}
.secblock .section-graph-wrap { margin-bottom: 0 }
/* Two colours per block, and they do different jobs.

   The BACKGROUND is the section's own band colour, the value the strip
   carried there and the value that sat beneath the raster as its pre-load
   fill. One flat grey for all four was tried at Danny's word on 2026-08-16
   ("let's try making the backgrounds of all four sections the same as the
   CARS background") and reverted the same day -- "revert to four colors".
   Recorded so the next session knows it was tried and rejected on his eye
   rather than never considered.

   --section-fill is the plate colour his one-colour ruling picks, and BOTH
   panels the block holds are dressed in it -- the writing and the graph
   ("text boxes should take the same background as the graph"). The four
   are named one per section in site.css beside the subject colours they
   alias; this is only where each block picks up its own. --fill is
   deliberately left alone, so the back arrow's plate stays white against
   the dark heading plates. */
/* The ground is EMITTED, not written here -- `--section-ground` on the block
   carries the colour of the one topic cell Danny named to land on top when
   the section blooms open (SECTION_BLOOM_TOP in build.py). "if that doesn't
   match the section page, change the section page background", so the page
   reads the same value the gesture settles on and the two cannot disagree.
   Rename a cell's colour in the artwork and both follow. */
.secblock              { background-color: var(--section-ground) }
.secblock--cars        { --section-fill: var(--cars-fill) }
.secblock--psych-soc   { --section-fill: var(--ps-fill) }
.secblock--bio-biochem { --section-fill: var(--bb-fill) }
.secblock--chem-phys   { --section-fill: var(--cp-fill) }

/* The poster's title page -- the whole of /mcat-title/ since the 2026-08-16
   split, and before that the block that stood on top of the four. It wears
   its own cell colour, the middle cloud's. Its body is the macro in
   partials/basics.html; only the frame around it is here. */
.basicsblock {
  position: relative;
  /* padding: 0 is load-bearing and has to be SAID, because this block also
     carries .secblock and would otherwise inherit that rule's 2.5rem top
     padding. That padding is what put the whole title row 40px below the
     line the map draws it on, uniformly, after every other offset had
     already been made exact. The .sheet inside carries the measure and the
     spacing, and its own 5rem bottom padding closes the page out.

     IT STILL CARRIES .secblock, and that is not vestigial: section-view.js
     finds what to mount by `.secblock[data-section]`, in the panel as well
     as on the page, so dropping the class would take the title page's graph
     with it. (It used to be there for the address spy as well; the spy went
     with the split, this reason did not.)

     Carrying .secblock would also hand it a section's --section-ground; it
     has none, and its ground is its own cell. */
  padding: 0;
  background-color: var(--cell, #d3d3d3);
}
/* Same margin-collapse guard as the blocks below: the last child's bottom
   margin would otherwise escape and show the page's ground as a bar. */
/* THE BASICS SHEET IS DECLARED HERE, NOT INHERITED FROM page.css.
   ---------------------------------------------------------------------------
   `.sheet` and `.sheet-head` live in page.css, and **map.html does not load
   page.css** -- so the block reads correctly on /mcat-basics/ and arrived in
   the panel with no measure and no side padding at all: prose from edge to
   edge at the full 1280 instead of 1240 inset by 20. Danny: "the first text
   block on mcat basics broke on overlay."

   This is the same trap the file header of poster.css already records twice
   (.mline, then .mplate) with the surfaces swapped: a rule only one of the
   two homes loads is a rule the other silently does without. sections.css is
   loaded by BOTH the section pages and map.html, which is why the section
   block's own rules have always worked in the panel -- and why these belong
   here beside them rather than in page.css.

   padding-top is 0 because the title's offset is measured from the block's
   top; anything above it pushes the whole row off the map's line. */
.basicsblock .sheet {
  max-width: var(--wide);
  margin: 0 auto;
  padding: 0 1.25rem 5rem;
}
.basicsblock .sheet-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 1.5rem;
  margin-bottom: 2.25rem;
}
/* THE /mcat-basics/ SHEET IS DECLARED HERE TOO, and for exactly the reason
   the block above it is: page.css is not loaded by map.html, and the
   `poster` / `page-doc` classes that carry the rest of this page's layout
   live on the STANDALONE page's body, which the panel does not receive
   either. Item 56 gave that page a self-dressing block and proved its PAINT
   correct in the panel -- and measured only the paint. Its layout was not
   measured, and it was broken: sheet padding 32px 20px 80px -> 0, measure
   1376px -> none, and the head therefore spanning the full 1280 with the
   back arrow on the viewport edge instead of inset 20. The same trap this
   file already records one rule up, walked into a second time.

   SCOPED TO #section-scroll so it cannot reach the standalone page at all,
   where page.css and poster.css still do the work unbeaten. The values are
   that page's own measured ones, not new choices. */
#section-scroll .basicspage .sheet {
  max-width: var(--wide);
  margin: 0 auto;
  padding: 2rem 1.25rem 5rem;
}
/* ...and the navy has to reach the foot of the panel. The block is only as
   tall as its writing, which on this page is deliberately almost none --
   measured 302px inside a 900px scroller, leaving 598px of the scroller's
   own black ground showing under it. */
#section-scroll .basicspage {
  min-height: 100%;
}

.basicsblock .full-graph-wrap { margin-bottom: 0 }
.basicsblock .basics-row { margin-top: 2.5rem }

/* ---- the title row -------------------------------------------------------
   The way back beside the section's own title, one per block. This is the
   topic pages' title row: arrow, centred title, and a spacer of the arrow's
   own width opposite it -- without the spacer the row centres on what the
   arrow left over and the title sits visibly right of the writing below. */
.secblock-head {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  padding-bottom: 1.5rem;
}
/* Option B, below the division floor -- the note is at poster.css's squeeze.
   --hk is declared INLINE (sections.html), so the fallback needs
   `!important` to outrank it; nothing else in this project sets --hk, so the
   important reaches exactly one declaration. The two operands are registered
   `<length>` in poster.css -- which is always loaded before this file, on
   every page that has a section block -- and the block's floor and scale
   ride along from the same inline style rather than being written a second
   time here, so build.py stays the only place those two numbers live. */
@supports not (width: calc(150px / 300px * 1px)) {
  .secblock-head {
    --hk: max(var(--sq-hk-min),
              calc(var(--sq-hk-scale)
                   * tan(atan2(calc(var(--sq-hk-num) + var(--sq-guard)),
                               var(--sq-hk-den)))))
          !important;
  }
}
/* The arrow's plate takes the section's fill too -- Danny, 2026-08-16: "the
   back arrow backgrounds should take the section fill." It was white until
   he said so, on the reasoning that white read clearly against the dark
   heading plates beside it; his eye overrules that, and the arrow now
   matches the writing and the graph so a block wears one colour throughout.
   The glyph and its ring are black either way, which is what keeps it
   legible on all four fills. */
.secblock .backbtn { background: var(--section-fill, var(--fill, #fff)) }
.section-heads {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: flex-start;
  gap: var(--vgap) var(--hgap);
}

/* ITEM 63, 2026-08-18 -- THE TITLE PAGE'S WRITING GOES UP BY HALF.
   ---------------------------------------------------------------------------
   Danny: "let's try widening the text blocks by 50% by default on the title
   page. this will affect the graph size." The second sentence is not an
   aside, it is the specification: the writing and the global graph share
   grid-column 2 (see `.topic-cols > .full-graph-wrap` in poster.css), so a
   wider measure carries the graph with it and that coupling is wanted.

   TITLE PAGE ONLY. `.basicsblock` exists on /mcat-title/ and nowhere else in
   the built site, which is what makes this scopable at all -- topic pages,
   section pages and the navy page keep the measure item 34 gave them, and
   the suite's "same measure" pin is deliberately broken here rather than
   silently (see its re-point).

   WRITTEN AS THE RELATION, NOT AS 864. The measure this replaces is whatever
   the two rails and the two gaps leave -- `100% - 2*--rail - 4rem` -- so the
   only new number here is Danny's own 1.5, and the page keeps agreeing with
   itself if he ever moves --rail or --wide. At 1280 that is 576 -> 864
   exactly; at 1336 (the block's cap) 672 -> 1008. A literal 864 would have
   been right at one window and quietly wrong at every other.

   THE RAILS ABSORB IT, AND ON THIS PAGE THAT IS FREE: measured, both flanks
   are EMPTY here (scrollWidth 300 against a 300px track, no text) -- they
   are the rails-on-both-sides convention holding the writing's line, not
   content. They become `1fr` and take what is left, 156px a side at 1280.
   On a topic page the same move would crush real rail content, which is
   why this is scoped to the one page whose rails carry nothing.

   `min(100%, ...)` is the narrow-window guard: the multiply is unbounded and
   the grid container is not, so without it a small enough window computes a
   middle track wider than the page it is in. The rails clamp at 0 through
   `minmax(0, 1fr)` and the writing simply stops growing.

   Inside the same `min-width: 66.0625rem` query the flanked grid itself
   lives in -- below that, the small-poster arrangement owns the layout and
   there are no rails to take width from. */
@media (min-width: 66.0625rem) {
  .basicsblock .topic-cols--split:not(.topic-cols--poster) {
    grid-template-columns:
      minmax(0, 1fr)
      min(100%, calc(1.5 * (100% - 2 * var(--rail) - 4rem)))
      minmax(0, 1fr);
  }
  /* The signup invitation is an editable intro box, but on the title page it
     follows the writing rather than the section page's topics.  It shares the
     widened middle-track formula above instead of copying its resolved width:
     the words and the form keep agreeing with the title writing whenever the
     rail or the title's 1.5x measure moves. */
  .basicsblock .topic-cols--split > .prose--intro {
    width: 100%;
    max-width: min(100%, calc(1.5 * (100% - 2 * var(--rail) - 4rem)));
    margin-inline: auto;
  }
}

/* ---- the body ------------------------------------------------------------
   Title, writing, topics, graph -- one column, in that order (Danny,
   2026-08-16), replacing the three-column grid whose rails flanked the
   writing.

   Two measures, the way a topic page has two: the block runs to --wide, and
   the writing is BOUNDED inside it at --sheet, centred. That is what "textbox
   bounded like the topic pages" is -- a topic page's sheet is --wide and its
   writing sits in the middle column, narrower than the page it is on.

   It also fixes what the old grid did here, which is worth recording because
   it looked deliberate: .section-cols capped itself at --sheet (46rem = 736px)
   and then laid out `--rail 1fr --rail` inside it -- 300 + 300 of rails and
   64 of gaps -- leaving the writing about 72px wide. Every check passed,
   because they asked whether the rails FLANKED the writing and they did. */
.secbody {
  max-width: var(--wide, 86rem);
  margin: 0 auto;
}
/* THE WRITING'S MEASURE -- and it is TWO of the three pages, not three.
   ---------------------------------------------------------------------------
   THE ARC, because it turned over inside one day and the dates are what
   settle it. Both rulings are Danny's; the later one wins on the half it
   names, and the earlier one stands everywhere else:

     2026-08-17 morning    "fix formatting in title page and basics page to
                           match the section pages (the text block margins)"
                           -- measured at 1280, a section's prose was 736 and
                           centred while the title page's and the navy page's
                           ran 1240 from the left edge, so all three were
                           capped at --sheet by this one declaration
     2026-08-17 afternoon  "let's revert the size of the text box on the
                           title page to the larger version too"
     2026-08-17 later      "let's try making the title page and section pages
                           use the rails on both sides convention (same as
                           topic pages)", and on the measure that follows from
                           it: "rails like the topic pages but the global
                           graph is the same width as the text box"  <- this
                           one

   AND THEN THE SECTION PAGES LEFT TOO, and the title page's wide block with
   them. Item 34 gives both the topic pages' two-rail grid, so their writing
   is no longer capped by a max-width at all -- it is the grid's middle track,
   four tenths of the sheet under Danny's own 30/40/30. `.secprose` is gone
   from the markup entirely (the element gave way to `.topic-main`), so its
   name is gone from here rather than left behind matching nothing.

   THE MEASURE WENT DOWN, NOT UP, AND HE WAS TOLD SO FIRST: 1240 -> 736 ->
   1240 -> 576, which is narrower than the 736 he had rejected that morning
   and less than half the 1240 he had restored at midday. That was measured
   and put to him before a line of this was built, precisely because it
   inverts his own previous instruction; he ruled it anyway in the words
   above. The latest dated ruling wins, and the arc stays written so nobody
   "fixes" it back.

   576 IS NOWHERE IN THIS FILE, deliberately. It is what 30/40/30 of --wide
   comes to at 1280 and it moves when he moves --rail or --wide. The suite
   asserts the RELATION -- the title and section writing measure exactly what
   a topic page's writing measures -- so the pages stay agreed without a
   number to maintain in four places.

   /mcat-basics/ KEEPS THE SECTION MATCH. Neither his morning sentence nor
   this one names the navy page, so it is still capped here, alone now. Its
   own eyeball veto stands.

   Everything ELSE about all three is still shared -- poster.css dresses them
   from one declaration (`.panel, .poster .topic-main > .prose,
   .poster .secprose > .prose`), so fill, border and padding cannot drift
   apart, and none of that moved with the measure.

   It caps the PROSE on the navy page rather than a wrapper, because there is
   no wrapper to cap: `.topic-main` is `display: contents` on the small poster
   (poster.css), so it has no box of its own and its children are grid items of
   the sheet, spanning 1 / -1. The section pages keep capping `.secprose`,
   which is a real box.

   STILL SCOPED, and now it matters twice over: `.topic-main > .prose` also
   matches every topic and subtopic page, where the writing is meant to fill
   its column and the flanked three-column arrangement depends on it -- and it
   matches the title page, which must NOT be capped. Widening this selector is
   how both of those break at once. */
/* ITEM 41: the Additional Resources dropdown. Dressed like the writing it
   follows and NOT like Example Passage -- his three exclusions are "without
   the animation or spreading page wide - maintains its width when opening",
   so the rule that would be easiest to write (reuse .passage) is the one rule
   that cannot be written. No transition, no grid-column, no width of its own:
   it is a block in the writing's column, so it is already the writing's
   measure and already flanked by nothing. */
/* ITEM 52, 2026-08-18. Danny, after a test pass: "section pages additional
   resources bit needs a box, text font and color off too - look at example
   passage box (topic page) as reference. but do not include the animation or
   widening of the example passage box."

   So item 41's reading is half reversed: the LOOK comes from Example Passage
   after all, and only the BEHAVIOUR stays excluded. What is deliberately NOT
   taken from `.passage`, each one a thing he has now asked twice not to have:
   the widening (--pass-edge and the [open] margin-left/right that spread it
   to the viewport), the animation (--pass-fall/-spread/-collapse/-rise and
   the margin transitions that run them), the height animation
   (::details-content block-size with interpolate-size, and the
   prefers-reduced-motion rule that exists only to cancel those three),
   scroll-margin-top (the air for the scroll the open does), the 11.8rem of
   standing room a real AAMC passage will want, and every flank rule -- item
   41 bought "does not interact with side rails" by putting this block inside
   .topic-main, and that is not being spent. `transition: none` stays, and
   now it is load-bearing rather than decorative.

   THE FILL IS THE HOUSE'S CHAIN, NOT THE REFERENCE'S DECLARATION, and that is
   the one place this departs from "copy the passage". `.passage` says
   `var(--fill, #fff)`, which on a topic page is that topic's colour -- but
   every section page reads --fill: #ffffff, so copying the declaration gives
   a WHITE box under a CREAM one. The shared dress in poster.css already
   solves it with `var(--section-fill, var(--fill, #fff))`, which is Danny's
   2026-08-16 "text boxes should take the same background as the graph", and
   --section-fill is the one of the three that survives into the map panel.
   Measured: chem-phys #ffdbb7, bio-biochem #b3feac, psych-soc #d9b4ff, cars
   #ffffff -- so cars stays white because cars IS white, by construction
   rather than by exception.

   AND THE COLOUR IS STATED RATHER THAN INHERITED, because inherited is what
   was broken. Measured before this rule: rgb(17,17,17) on the standalone page
   but rgb(233,236,241) -- near-white -- in the map panel, where --fill and
   --stroke resolve empty at this scope. One block, two homes, two different
   wrongs; #12140f is the ink the writing beside it already uses. */
.resblock {
  margin: 2rem 0 0;
  background: var(--section-fill, var(--fill, #fff));
  border: var(--stroke, 8px) solid #000;
  color: #12140f;
  transition: none;
}
.resblock > summary {
  display: flex;
  align-items: center;
  gap: .7rem;
  padding: 1rem 1.35rem;
  font-family: Danny, ui-sans-serif, sans-serif;
  font-size: 2rem;
  line-height: 1.1;
  cursor: pointer;
  /* The caret is drawn below, so the native marker goes -- and Safari needs
     to be told twice. */
  list-style: none;
}
.resblock > summary::-webkit-details-marker { display: none; }
.resblock > summary::before {
  content: "";
  flex: none;
  width: 0;
  height: 0;
  border-left: .52em solid currentColor;
  border-top: .34em solid transparent;
  border-bottom: .34em solid transparent;
}

/* The section signup is the main column's middle block: prose, signup,
   resources. It reuses the title form's chrome but takes the section's one
   fill, the same token already shared by prose and graph. */
.secblock .topic-main > .signup-block {
  max-width: none;
  margin: 2rem 0 0;
  background: var(--section-fill, var(--fill, #fff));
}
/* It turns, but it does not travel there: the reference animates this over
   .16s and "do not include the animation" is read as covering it. One line
   to give it back if he wants the motion. */
.resblock[open] > summary::before { transform: rotate(90deg); }
.resblock > summary:focus-visible {
  outline: 3px solid currentColor;
  outline-offset: -3px;
}
.resblock-body {
  padding: 0 1.25rem 1.25rem;
  opacity: .55;
  font-style: italic;
}
.resblock-body p { margin: 0; }

/* ITEM 39, 2026-08-17. Danny: "section page: right rail moves with page,
   left rail doesn't. let's make both static (different from topic page)."

   THE ASYMMETRY WAS A MISSING HEIGHT, not a left/right rule. poster.css pins
   a rail with
       top: min(1.5rem, calc(100vh - var(--rh-max, var(--rh, 0px)) - 1.5rem))
   and its own comment explains why two rails normally agree: "a split topic's
   pair rides on the taller one's height (--rh-max, on the columns), so if the
   tall rail foot-pins, its partner pins at the same moment and the two move as
   one." A topic page emits --rh-max and a per-rail --rh; item 34's section
   pages emitted NEITHER, because section_rail() returns items and no height.
   So the two rails were independent sticky boxes of different content heights
   -- one moving while the other did not, exactly as he saw.

   HIS RULING SUPERSEDES THE HOLE RATHER THAN FILLING IT. Plumbing the height
   would have given these rails the topic pages' full synchronised travel --
   MORE movement, and the opposite of what he asked for. Static needs no
   arithmetic at all, so the height stays unwired deliberately and the
   mechanism is recorded in HANDOFF instead: dead code that looks live is how
   the next person spends an hour proving a variable does nothing.

   SCOPED TO SECTION PAGES, which is the whole of "different from topic page"
   -- and it is the .mline lesson's inverse. That rule broke pages by living
   only in map.css; this one would break the TOPIC pages by not living in
   sections.css. `.secblock` is the section page's own wrapper and it is
   present in the map's panel too, so the panel's copy stands still with it. */
.secblock .topic-cols .strail {
  position: static;
}

/* ITEM 34: the section grid stands where a topic page's grid stands.
   "Same as topic pages" is a measure as well as an arrangement, and the two
   pages hang their grid in containers that pad differently: a topic page's
   `.sheet` pads 1.25rem a side, `.secblock` pads 1rem, so the section grid
   was 8px wider and its writing came out 584 against the topic page's 576.
   Small, and exactly the kind of small that makes two pages look subtly
   unlike each other for no reason anyone can name.

   The arithmetic is written out rather than left as `.25rem`: it is the
   DIFFERENCE between the two paddings, so if either moves this line is
   visibly the thing to reconcile instead of a mystery quarter-rem. */
.secblock > .topic-cols {
  padding-inline: calc(1.25rem - 1rem);
}

/* ITEM 69, 2026-08-19 -- THE ALL-LEFT SECTION CENTRES ON WHAT IS LEFT.
   ---------------------------------------------------------------------------
   Danny: "let's rearrange the layout of the cars section such that all three
   topics are on the left, the right rail is gone, and the remaining layout
   centers." The first two clauses are build.py's and the template's; this is
   the third, and it is the one that needs saying out loud, because dropping
   the right flank on its own does NOT centre anything -- it leaves the rail
   and the writing occupying the first two tracks of a three-track grid with
   300px of nothing to their right, which reads as the page having slipped
   left. That lopsidedness is what the third clause rules out.

   THE MEASURE DOES NOT MOVE, AND THAT IS DELIBERATE. Danny asked for the
   layout to centre, not for the writing to grow -- when he wanted a wider
   measure he said so in those words and item 63 above is what that looks
   like. So the writing stays exactly what a topic page's writing measures
   and only the empty track is dealt with. Half of it goes to each side:

     padding-inline += (--rail + the grid's column-gap) / 2

   and the arithmetic proves itself. The block is border-box, so its outer
   width is untouched; the content box loses exactly one rail and one gap,
   which is exactly what the vanished column and its gap used to take. The
   writing is what remains after the one surviving rail and its gap, which is
   the same subtraction as before. Measured at 1280: 576 before, 576 after,
   with the pair sitting 170px from each edge instead of 4 and 336.

   WRITTEN AS THE RELATION for the reason this file already gives one line
   above: --rail is site.css's and the 2rem is the `gap` poster.css sets on
   `.topic-cols:not(.topic-cols--poster)`. Move either and this line is
   visibly the thing to reconcile. Adding to `calc(1.25rem - 1rem)` rather
   than replacing it keeps the topic-page alignment that difference buys.

   THE SELECTOR IS BUILT TO WIN, not to read prettily. poster.css sets the
   three tracks at `.topic-cols--split:not(.topic-cols--poster)` -- three
   classes -- and specificity beats file order, so a plainer selector here
   would lose to it and the grid would keep a third column that has nothing
   to put in it. `:not(.topic-cols--poster)` also keeps the small-poster
   arrangement's hands free, which is the same guard poster.css uses.

   THE WIDE TIER IS THE ONLY TIER THIS TOUCHES, and the narrow one is left
   alone deliberately -- it was written with a two-band rule first and that
   was an overreach, caught by measuring it. Below 66.0625rem there are no
   rails to remove: `.flank` and `.strail` are both `display: contents`
   there, so the flank this section no longer emits was contributing nothing
   to the layout anyway, and its absence changes nothing that needs a rule.
   The labels simply band out into the same `3fr 4fr 3fr` every section
   uses, which for CARS' three is one clean row of three ahead of the
   writing. A two-band rule instead gave 2-then-1 -- a worse arrangement, on
   a tier Danny's words do not reach, bought for nothing.

   WHAT DOES CHANGE DOWN THERE is the reading order, and it comes from the
   ruling rather than from here: with all three topics in one rail the third
   label now precedes the writing instead of trailing it. That is the same
   DOM move that produces the wide tier's result. */
@media (min-width: 66.0625rem) {
  .secblock > .topic-cols--oneside:not(.topic-cols--poster) {
    grid-template-columns: var(--rail) minmax(0, 1fr);
    padding-inline: calc(1.25rem - 1rem + (var(--rail) + 2rem) / 2);
  }
}

/* ITEM 70, 2026-08-19 -- A SECTION THAT STACKS INSTEAD OF FLANKING.
   ---------------------------------------------------------------------------
   Danny: "try a different cars layout. the three topics up top, under the
   title, similar to its positioning on main map (FOC middle, RWT left, RBT
   right), text box below. all centered." This supersedes item 69's all-left
   rail for CARS; that rule stays above, unused and one word from live again,
   because "try" is a sentence that can be answered no.

   ONE COLUMN, and the children fall in source order -- the topics' row, then
   the writing with its dropdown and graph beneath it. No flanks are emitted
   at all, so there is nothing to flank with and nothing to centre against;
   "all centered" here is the row centring its own items and the writing
   centring inside the block.

   THE MEASURE IS UNCHANGED AND IS STILL WRITTEN AS THE RELATION. The writing
   keeps exactly what a topic page's writing measures -- what two rails and
   two gaps would have left -- so this page still agrees with the other three
   sections, the topic pages and the title page's own pin. Danny asked for the
   text box to sit below and be centred, not to grow; item 63 is what asking
   for a wider measure looks like and this is not that.

   THE RELATION IS WIDE-TIER ONLY, and this one bites if it is not. Below the
   breakpoint the block is barely wider than the two rails it is subtracting:
   at a 900px window `100% - 2*--rail - 4rem` comes out near 196px, a column
   of single words. There are no rails down there to give the space back, so
   the writing simply runs the block's width as it already does on every other
   section.

   THE ROW IS `.strail` STILL. Every contract on this page reads that selector
   -- flight source, hover pop, the suite's counts -- so the container is
   unchanged and only its layout moves. That is why this rule has to out-
   specify poster.css's `.topic-cols:not(.topic-cols--poster) .strail`, which
   makes rails vertical: three classes there, three here, and sections.css
   loads later.

   FEET, NOT TOPS. The items are aligned flex-end so the LABELS line up, since
   the drawings above them differ in height -- the same reasoning, and the same
   gap pair, the `.sectopics` row below this file used when Danny's 2026-08-16
   arrangement put topics in rows. Its values are reused deliberately: that was
   his last row of section topics and it should look like it. */
/* ITEM 70c, 2026-08-19. Danny: "let's also reduce the space between the
   bottom of the labels and the top of the text box by 50%."

   MEASURED FIRST, AND IT WAS NOT WHAT THE DECLARATION SAID. The row carried
   `margin-bottom: 2.5rem`, but the gap a reader sees was **72px**: the grid
   contributes its own 2rem row-gap between the row and the writing, on top of
   the margin. Halving the margin alone would have given 66px -- a 8% trim
   sold as 50%, and nobody would have noticed until they measured.

   So the two sources become ONE. The grid's row-gap goes to zero for this
   arrangement and the row's own margin carries the whole distance, which
   makes the visible gap equal to a single number at every width -- halving it
   again later is then one edit with no arithmetic. 72 -> 36 = 2.25rem. */
.secblock > .topic-cols--toprow:not(.topic-cols--poster) {
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: none;
  row-gap: 0;
  /* ITEM 70b, CODEX P1: the row's budget is measured from THIS box, not from
     the viewport. See the note on --row-k below -- `100vw` counts a classic
     scrollbar that the containing block does not have, and no fixed safety
     margin can be right for both scrollbar styles at once. `cqw` is 1% of
     this container's own content box, so it excludes the scrollbar by
     construction and needs no guess. */
  container-type: inline-size;
}
.secblock > .topic-cols--toprow > .topic-main {
  display: block;
}
.secblock > .topic-cols--toprow .strail--row {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: center;
  /* ITEM 70b -- SHRINK TO FIT, Danny's words, so the row keeps its single
     line instead of wrapping at laptop widths.
     -------------------------------------------------------------------------
     ONE FACTOR FOR THE WHOLE ROW, not one per item. A rail's labels each
     squeeze against their own budget (poster.css, `.strail .stlabel-box`),
     which is right for a column where nothing lines up across. Here it would
     be wrong twice over: the three would shrink by different amounts, and the
     middle's deliberate 10% would dissolve at the first narrow window. So the
     ratio is computed ONCE here and every piece multiplies by it.

     `calc(a / b)` is this project's way of dividing one length by another --
     poster.css's `--k-mini` and `--squeeze` both already do exactly this.
     Nothing new is being invented. (It was written `tan(atan2(a, b))` until
     2026-08-22, when WebKit 18.0 was measured evaluating `atan2()` in degrees
     and `tan()` in radians whenever an operand carries a relative unit -- see
     the long note at poster.css's squeeze. Never restore the trig form on
     this declaration; the ONE place it is allowed to reappear is the
     `@supports not (...)` twin below, where poster.css's registered
     `<length>` operands have already made it px arithmetic.)

     WHAT IT HAS: `100cqw` -- the containing block's OWN content width.
     -------------------------------------------------------------------------
     CODEX P1, and it was right against a fault my own testing could not see.
     This first read `min(86rem, 100vw - 2rem) - .75rem`, reconstructing the
     block's width from the viewport. **`100vw` includes a classic scrollbar
     that the containing block excludes**, so on any browser configured to
     show scrollbars -- Windows and Linux by default, macOS whenever "show
     scroll bars: always" is set -- the budget over-read by roughly 11-13px
     and the row went on WRAPPING through exactly the laptop widths this item
     exists to stop it wrapping at.

     **My twelve-width sweep could not have caught it**: headless Chromium
     reports a scrollbar width of 0, so every green was true and none of them
     was evidence about a scrollbar browser. Reconstructing a box's width from
     the viewport means re-deriving something the layout already knows, and
     the re-derivation is wrong in exactly the configuration the test
     environment does not have.

     `100cqw` is 1% of this row's query container's content box, which IS the
     available width -- scrollbar excluded by construction, padding already
     taken off, and the 86rem cap already applied by the block itself. No
     viewport arithmetic, no scrollbar guess, and it stays correct if the
     block's padding or cap ever change. The quarter rem that remains is for
     sub-pixel rounding only, and still errs early, which is the harmless
     direction.

     WHAT IT WANTS: the label boxes' natural total, from the build, plus the
     gaps below -- which are counted in `rem` here rather than baked in, so
     changing the gap needs no rebuild. The gaps scale by the same factor, so
     the fit stays exact: k*(widths + gaps) = available, by construction.

     THE FLOOR IS LEGIBILITY, AND BELOW IT WRAPPING IS THE BETTER ANSWER.
     Unbounded shrinking reaches ~0.285 on a phone, which is nine-pixel
     lettering -- unreadable, and worse than the wrap Danny asked to remove.
     At 0.6 the smallest lettering on the row is ~18px, and a window too
     narrow to hold even that falls back to `flex-wrap`, which is why the wrap
     is still allowed below. Shrink first, wrap only when shrinking would
     stop being readable. */
  --row-k: max(.6, min(1, calc(
             (100cqw - .25rem)
             / (var(--row-w, 1) * 1px + var(--row-gaps, 0) * 1.8rem))));
  gap: calc(1.6rem * var(--row-k)) calc(1.8rem * var(--row-k));
  position: static;
  /* ITEM 70c: the WHOLE distance from the labels' feet to the text box, now
     that the grid's row-gap above is zero. Half of the 72px it measured. */
  margin-bottom: 2.25rem;
}
/* Option B, below the division floor -- poster.css's squeeze carries the
   whole note. Both operands are relative here (100cqw, rem), which is
   exactly the shape the defect fires on, so both go through registered
   <length> copies. The .6 floor and the 1 ceiling are unchanged, so a
   window too narrow to shrink into still wraps rather than shrinking below
   legibility. */
@supports not (width: calc(150px / 300px * 1px)) {
  .secblock > .topic-cols--toprow .strail--row {
    --sq-row-num: calc(100cqw - .25rem + var(--sq-guard));
    --sq-row-den: calc(var(--row-w, 1) * 1px + var(--row-gaps, 0) * 1.8rem);
    --row-k: max(.6, min(1, tan(atan2(var(--sq-row-num), var(--sq-row-den)))));
  }
}
/* The label boxes: `.mlabel-box` in poster.css already sizes itself as
   `--tw * --squeeze`, so the row does not size them -- it only tells them
   what budget to squeeze against, and it says "your own natural width times
   the row's factor". That makes every item's squeeze resolve to the SAME
   number, which is the whole point, while reusing the existing rule rather
   than fighting it with a more specific one. */
.secblock > .topic-cols--toprow .strail--row .mlabel-box {
  --avail: calc(var(--tw) * var(--row-k));
}
/* The drawings have no such rule of their own, so they get one here. */
.secblock > .topic-cols--toprow .strail--row .sgimg {
  width: calc(var(--iw) * var(--row-k));
  height: calc(var(--ih) * var(--row-k));
}
@media (min-width: 66.0625rem) {
  .secblock > .topic-cols--toprow > .topic-main,
  /* DANNY, 2026-08-21 -- THE BOX ABOVE THE TOPICS TAKES THE WRITING'S MEASURE
     BY SHARING ITS DECLARATION, which is the strongest form of "the normal
     width" available: there is no second number to keep in step, because
     there is no second number. Both are centred by the same
     `margin-inline: auto`, so "centered" is one word in one place too.

     It is a grid child here, unlike the topic page's (see sections.html), so
     `100%` is the same containing block for both selectors on this line --
     which is exactly what makes sharing the declaration correct rather than
     merely tidy. */
  .secblock > .topic-cols--toprow > .prose--intro {
    max-width: calc(100% - 2 * var(--rail) - 4rem);
    margin-inline: auto;
  }
  /* AN EMPTY BOX MUST STILL BE THE FULL MEASURE, and this line is the whole
     difference between the two selectors above.

     `margin-inline: auto` turns OFF a grid item's stretch -- an item with an
     auto inline margin is sized shrink-to-fit and the slack goes to the
     margins. `.topic-main` never notices, because it is full of writing and
     its max-content is wider than the cap. The intro box SHIPS EMPTY, by
     Danny's own ruling that an unwritten box waits for him, so shrink-to-fit
     is its padding plus its border and nothing else: MEASURED AT 72px inside
     a 1240px block, which is precisely the degenerate column MISTAKES.md
     records from 2026-08-16 and which the width pin caught here before any of
     it reached him. `width: 100%` under the cap gives the stretch back.

     Written on the box alone rather than folded into the shared declaration
     because the reason is a fact about the box's CONTENTS, not about the
     measure -- and the measure is the thing worth sharing. */
  .secblock > .topic-cols--toprow > .prose--intro { width: 100%; }
}
/* The air under it. 2.25rem is item 70c's number -- the gap Danny halved
   between the labels' feet and the text box -- reused so the block keeps one
   rhythm rather than gaining a second spacing to tune. The grid's own row-gap
   is 0 for this arrangement (item 70c), so, exactly as with the row's own
   margin, this margin IS the whole visible distance: halve it later and there
   is no second term to find. Move one of the two and move the other. */
.secblock > .topic-cols--toprow > .prose--intro { margin-bottom: 2.25rem; }

/* Wave 11: section pages have one serialized topic sequence below 66rem.
   ---------------------------------------------------------------------
   A topic page's small-poster grid knows about its own stamped `.stitem`
   children. Section topic units are different: each is an indivisible label
   plus drawing. They occupy two equal columns here, scoped to section blocks
   so ordinary topic geometry cannot leak back in, and their image/plate sizes
   are capped by their real cell. The prose keeps its pager; resources stay
   immediately after it; the graph is the final block in source and visual
   reading order. */
.secblock .section-topic-units > .section-rail-flow { display: contents; }
@media (max-width: 66rem) {
  .secblock > .topic-cols {
    display: flex;
    flex-direction: column;
    min-width: 0;
  }
  .secblock-head { overflow-x: clip; }
  .secblock > .topic-cols > .topic-main { display: contents; }
  .secblock > .topic-cols > .topic-main > .prose,
  .secblock > .topic-cols > .topic-main > .signup-block,
  .secblock > .topic-cols > .topic-main > .resblock,
  .secblock > .topic-cols > .section-topic-units,
  .secblock > .topic-cols > .section-graph-wrap {
    box-sizing: border-box;
    min-width: 0;
    max-width: 100%;
  }
  .secblock > .topic-cols > .topic-main > .prose { order: 1; }
  .secblock > .topic-cols > .topic-main > .signup-block { order: 2; }
  .secblock > .topic-cols > .topic-main > .resblock { order: 3; }
  .secblock > .topic-cols > .section-topic-units {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: end;
    gap: 1.6rem 1rem;
    margin: 2rem 0 0;
    width: 100%;
    order: 4;
  }
  .secblock .section-topic-units > .section-rail-flow { display: contents; }
  .secblock .section-topic-units .sgitem {
    width: 100%;
    min-width: 0;
    max-width: 100%;
  }
  .secblock .section-topic-units .mlabel-box,
  .secblock .section-topic-units .mlabel,
  .secblock .section-topic-units .sgimg {
    min-width: 0;
    max-width: 100%;
  }
  /* The section-label plates use a fixed SVG viewBox that can paint outside
     their measured text box. A half-scale remains the ceiling, and narrower
     cells reduce it further so the painted plate stays inside its unit. */
  .secblock .section-topic-units .mlabel-box {
    /* One cell is half the topic sequence after its 1rem column gap. The
       sequence is the viewport less the section grid's two 1.25rem insets,
       so this is the cell's real width, not a second visual guess. */
    --section-topic-cell: calc((100vw - 3.5rem) / 2);
    /* The house division idiom -- never tan(atan2()) here; see poster.css,
       and the below-the-floor twin immediately after this rule. */
    --squeeze: min(.5, calc(var(--section-topic-cell) / var(--tw))) !important;
  }
  /* Option B, below the division floor. The !important is carried over from
     the rule above rather than invented: this squeeze has to beat
     poster.css's own, and its below-the-floor twin has to beat poster.css's
     below-the-floor twin by exactly the same margin.

     AND THE `0 * var(--tw)` IS THE ONE THING HERE THAT IS NOT DECORATION.
     `var(--tw)` in the rule above carries NO fallback, unlike every other
     operand in this fix, and that is deliberate: a topic unit whose label
     was emitted at a literal width has no --tw at all, the declaration goes
     invalid at computed-value time, and `var(--squeeze, .5)` downstream is
     what dresses it. A REGISTERED operand cannot be invalid -- an invalid
     declaration makes it take its 1px initial instead -- so copying --tw
     into --sq-den silently converts "no squeeze" into "a squeeze of .5".
     MEASURED, which is how this was found and not reasoned: ten section-page
     boxes at 390 read .5 through the copy where Chromium reads nothing at
     all. Referencing the raw name once more at a zero coefficient carries
     that invalidity across the copy; it adds 0px when --tw exists, and takes
     the whole declaration down with it when --tw does not. */
  @supports not (width: calc(150px / 300px * 1px)) {
    .secblock .section-topic-units .mlabel-box {
      --sq-num: calc(var(--section-topic-cell) + var(--sq-guard));
      --sq-den: var(--tw);
      --squeeze: min(.5, tan(atan2(var(--sq-num),
                                   calc(var(--sq-den) + 0 * var(--tw)))))
                 !important;
    }
  }
  .secblock .section-topic-units .mlabel--row {
    transform: scale(calc(var(--k, 1) * var(--squeeze, .5)));
  }
  .secblock .section-topic-units .mlabel--row:hover,
  .secblock .section-topic-units .mlabel--row:focus-visible {
    transform: translate(calc(var(--k, 1) * var(--squeeze, .5) * -6%),
                         calc(var(--k, 1) * var(--squeeze, .5) * -6%))
               scale(calc(var(--k, 1) * var(--squeeze, .5) * 1.12));
  }
  .secblock .section-topic-units .sgimg {
    height: auto !important;
  }
  .secblock > .topic-cols > .section-graph-wrap {
    width: 100%;
    margin-top: 2rem;
    order: 5;
  }
}

/* Above the small-poster breakpoint the same source order is restored to the
   existing desktop arrangements entirely by grid placement. A railed section
   overlays its one sequence across the three parent tracks; item classes put
   the old left and right runs back into their respective columns. CARS keeps
   SECTION_TOP_ROW's row above its writing. */
@media (min-width: 66.0625rem) {
  /* Keep the serialized graph last for a phone, but promote the central
     prose/resources/graph pieces into their old desktop rows. The unified
     topic grid spans those rows without deciding when the graph starts. */
  .secblock > .topic-cols--split > .topic-main {
    display: contents;
  }
  .secblock > .topic-cols--split > .topic-main > .prose {
    grid-column: 2;
    grid-row: 1;
  }
  .secblock > .topic-cols--split > .topic-main > .signup-block {
    grid-column: 2;
    grid-row: 2;
    margin-top: 0;
  }
  .secblock > .topic-cols--split > .topic-main > .resblock {
    grid-column: 2;
    grid-row: 3;
    /* The parent grid already supplies this stack's 2rem rhythm. Keeping
       resblock's ordinary margin would charge it twice on desktop. */
    margin-top: 0;
  }
  .secblock > .topic-cols--split > .section-topic-units {
    display: grid;
    grid-column: 1 / -1;
    grid-row: 1 / 5;
    grid-template-columns: var(--rail) minmax(0, 1fr) var(--rail);
    /* The rails are an overlay on the central prose/resources/graph stack.
       Their visual height must not inflate those three rows, or a graph that
       is source-last waits for the tallest rail before it can follow the
       resources. The visible items still lay out in their own grid. */
    height: 0;
    min-height: 0;
    overflow: visible;
    min-width: 0;
    margin-top: 0;
  }
  /* A grid row is shared by both columns: a tall left item was stretching a
     right-side gap (and vice versa). Each serial run is a real independent
     flex column at desktop; below the breakpoint the same spans are contents,
     so the one mobile sequence remains unwrapped. */
  .secblock > .topic-cols--split > .section-topic-units
    > .section-rail-flow {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1.6rem;
    min-width: 0;
  }
  .secblock > .topic-cols--split > .section-topic-units
    > .section-rail-flow--left {
    grid-column: 1;
  }
  .secblock > .topic-cols--split > .section-topic-units
    > .section-rail-flow--right {
    grid-column: 3;
  }
  .secblock > .topic-cols--split > .section-graph-wrap {
    grid-column: 2;
    grid-row: 4;
    margin-top: 0;
  }
  /* A SECTION WITHOUT THE SIGNUP CLOSES THE STACK UP -- Danny, 2026-08-22:
     "let's remove the sign up box from chemphys and biobiochem".
     ------------------------------------------------------------------------
     The four blocks above are placed by EXPLICIT grid-row, and the grid's own
     row-gap is what supplies their 2rem rhythm. So a page that emits no
     `.signup-block` does not simply lose the box: row 2 stays in the grid
     with nothing in it, and prose-to-resources measured 64px -- two row gaps
     around a zero-height row, a visible hole exactly where the box used to
     be. Removing something Danny asked to have removed must not leave its
     outline behind, so the rows below it each move up one.

     ASKED OF THE PAGE, not of a second build-emitted class: `:has()` reads
     whether the block was emitted, which is the very thing
     build.SIGNUP_SECTIONS decides, so this cannot disagree with what the
     build actually shipped -- the same reasoning poster.css:1703 gives for
     `:has(+ ...)`, and the same selector admin.css already relies on. The
     rail overlay's span shortens with them, or an empty row 4 would leave the
     hole under the graph instead of above the resources. Higher specificity
     than the four rules above by the `:not()`, so source order is not what
     makes these win. */
  .secblock > .topic-cols--split:not(:has(.signup-block))
    > .topic-main > .resblock { grid-row: 2; }
  .secblock > .topic-cols--split:not(:has(.signup-block))
    > .section-graph-wrap { grid-row: 3; }
  .secblock > .topic-cols--split:not(:has(.signup-block))
    > .section-topic-units { grid-row: 1 / 4; }
  .secblock > .topic-cols--toprow > .section-topic-units { grid-row: 2; }
  .secblock > .topic-cols--toprow > .topic-main { grid-row: 3; }
  .secblock > .topic-cols--toprow > .section-graph-wrap { grid-row: 4; }
}
.basicspage .topic-main > .prose {
  max-width: var(--sheet, 46rem);
  margin: 0 auto;
}
.secblock .prose { color: var(--ink, #111) }

/* The topics, in rows: one flow in the poster's own reading order, wrapping
   as the width allows. It was two vertical rails; the items are unchanged
   and only the shape they are poured into moved. Aligned on their labels'
   feet rather than their tops, because a row's drawings differ in height and
   it is the labels that should line up. */
.sectopics {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: center;
  gap: 1.6rem 1.8rem;
  margin: 2.5rem 0 0;
}

.section-graph-wrap { padding-bottom: 3rem }
/* max-width alone leaves an empty deferred graph shrink-wrapped until its
   canvas arrives. Give every desktop section graph its settled box up front;
   the narrow-tier rule above still makes it full-width on a phone. */
@media (min-width: 66.0625rem) {
  .section-graph-wrap {
    width: min(100%, calc(var(--section-graph-of-sheet) * var(--sheet)));
  }
}

@media (prefers-reduced-motion: reduce) {
  .sections-page { scroll-behavior: auto }
}
