
/* ── the page ─────────────────────────────────────────────────────────── */
body { margin: 0; background: var(--paper); color: var(--ink); }

/* hidden HAS TO OUTRANK THE LAYOUT, AND ON ITS OWN IT DOES NOT. The user
   agent's rule is display:none at the lowest specificity there is, so a class
   that says display:grid beats it and the attribute silently does nothing. That
   is how a page with no script would have drawn an empty workspace frame under
   the lesson, and how the lesson would have gone on taking 6,000 pixels of
   scroll under the workspace. */
.ln-read[hidden], .ln-frame[hidden] { display: none; }

/* ── the reading rendering ───────────────────────────────────────────────
   THE SAME LESSON, SCROLLED. It is what a reader with no script gets, and it
   is what a machine reading this page gets. Everything in it was composed from
   the same compiled seed the workspace is driven by, so the two cannot drift.
   ────────────────────────────────────────────────────────────────────────── */
.ln-read { max-width: 46rem; margin: 0 auto; padding: var(--ln-5) var(--ln-4); display: grid; gap: var(--ln-5); }
.ln-read h1 { font-family: var(--serif); font-size: 1.75rem; line-height: 1.15; margin: 0 0 var(--ln-3); }
.ln-read h2 { font-family: var(--serif); font-size: var(--ln-case); line-height: 1.2; margin: 0 0 var(--ln-2); }
.ln-read h3 { font-family: var(--mono); font-size: var(--ln-eyebrow); line-height: var(--ln-lh-eyebrow);
              letter-spacing: .06em; text-transform: uppercase; color: var(--brass); margin: var(--ln-4) 0 var(--ln-2); }
.ln-read p { font-size: var(--ln-prose); line-height: var(--ln-lh-prose); max-width: var(--ln-measure); margin: 0 0 var(--ln-3); }
.ln-read__step { border-top: 1px solid var(--rule); padding-top: var(--ln-4); }
.ln-read__note { font-size: var(--ln-prose-quiet); line-height: var(--ln-lh-quiet); color: var(--ink-soft); }
.ln-read__fig { margin: 0 0 var(--ln-3); font-size: var(--ln-prose-quiet); line-height: var(--ln-lh-quiet); color: var(--ink-soft); }
.ln-read__fig b { color: var(--ink); font-weight: 600; }
.ln-read details { border-left: 3px solid var(--rule-2); padding-left: var(--ln-3); margin: 0 0 var(--ln-3); }
.ln-read summary { font-size: var(--ln-label); line-height: var(--ln-lh-label); font-weight: 600;
                   min-height: 44px; display: flex; align-items: center; cursor: pointer; }
.ln-read ul, .ln-read ol { font-size: var(--ln-prose); line-height: var(--ln-lh-prose);
                           max-width: var(--ln-measure); margin: 0 0 var(--ln-3); padding-left: var(--ln-4); }
.ln-read a { color: var(--brass); }

/* ── the workspace, once a composer is driving it ────────────────────────
   src/scene/measure.ts writes data-flow and four absolute boxes when the
   arrangement is bounded, and clears them and writes a reading order when it is
   not. Both need the frame to stop being the grid the scriptless stylesheet
   lays out, and neither may change a size.
   ────────────────────────────────────────────────────────────────────────── */
.ln-frame[data-flow='bounded'] { display: block; position: relative; }
.ln-frame[data-flow='page'] { display: flex; flex-direction: column; height: auto; min-height: 100svh; }
.ln-frame[data-flow='page'] > * { min-width: 0; }
/* On one column the page is the scroll container, and a panel keeping its own
   scrollbar inside it is where a reader cannot reach the end of a sentence. */
.ln-frame[data-flow='page'] .ln-ask__result,
.ln-frame[data-flow='page'] .ln-inspect__body { overflow: visible; }

/* ONE SCROLL CONTAINER PER REGION AND NOT TWO NESTED ONES. The scriptless
   stylesheet gives the result band the slack in a question region whose height
   is the viewport's, so the verdict is the part that scrolls. Under a composer
   the region's height is the plan's and there is no slack to give: flex-basis
   zero then computes to zero, the verdict is clipped to nothing, and a learner
   who pressed the button watches nothing happen. The region already scrolls,
   which is what OVERFLOW in the contract gives it, so the band inside it does
   not need to. */
.ln-frame[data-composition] .ln-ask__result { flex: 0 0 auto; min-height: 0; overflow: visible; }

/* THE INSPECTOR HAS THREE CHILDREN AND THE TEMPLATE COUNTS TWO. The scriptless
   stylesheet lays it out as a heading over a body; this screen puts the two
   facet controls between them, so the body lands in an implicit third row that
   the second row has already spent the height on, and the empty-state sentence
   is painted under the buttons. A template that has to agree with how many
   children a region happens to have breaks the next time one is added, which
   is the lesson learning.css records for the question region. */
.ln-frame[data-composition] .ln-inspect { display: flex; flex-direction: column; gap: var(--ln-2); }
.ln-frame[data-composition] .ln-inspect > * { flex: 0 0 auto; }
.ln-frame[data-composition] .ln-inspect__body { flex: 1 1 auto; min-height: 0; }

.ln-orient__row { row-gap: var(--ln-2); }
.ln-orient__where { font-family: var(--mono); font-size: var(--ln-eyebrow); line-height: var(--ln-lh-eyebrow);
                    letter-spacing: .06em; text-transform: uppercase; color: var(--ink-soft); }
.ln-scene__pair { display: grid; gap: var(--ln-3); grid-template-columns: minmax(0, 1fr); min-height: 0; }
/* TWO PANES AS SOON AS THERE IS ROOM FOR TWO READABLE ONES, because one column
   of two drawings is twice as tall as the body of a desk arrangement ever is,
   and the composer answers that by falling to a scrolling page. 40rem is the
   narrowest the pair can be and leave each pane above the width the drawing
   needs before it starts panning. */
/* THE CHART GETS THE LARGER SHARE. Its minimum width is five periods times
   four lanes at a target each, so it is the pane that starts panning first,
   and the drawing beside it is laid out to whatever width it is given. */
@media (min-width: 40rem) { .ln-scene__pair { grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr); } }
/* FLEX AND NOT A GRID TEMPLATE, on the lesson learning.css records in full: a
   template that has to agree with how many children a region happens to have
   breaks the next time one is added, and it breaks by giving a row no height. */
.ln-pane { min-width: 0; min-height: 0; display: flex; flex-direction: column; gap: var(--ln-2); }
.ln-pane > * { flex: 0 0 auto; }
.ln-pane .ln-art { flex: 0 1 auto; min-height: 0; }
/* THE SCENE IS AS TALL AS ITS TWO DRAWINGS AND NOT AS TALL AS ITS BOX. The
   scriptless stylesheet gives the drawing row all the slack, which is right
   when the region's height is the viewport's; under a composer it makes the
   region's measured content exactly its box, and seed.ts explains at length
   what that costs. */
.ln-frame[data-composition] .ln-scene { grid-template-rows: auto auto; align-content: start; }
/* THE PANEL PANS AND NOTHING INSIDE IT IS SCALED. A percentage width on a
   drawing lets the browser fit it, fitting is scaling, and scaling takes a
   13px label under the floor with no rule anywhere saying it may. */
.ln-art { overflow: auto; overscroll-behavior: contain; border: 1px solid var(--rule); background: var(--card); padding: var(--ln-3); }
.ln-art > div { position: relative; }
.ln-axis { font-size: var(--ln-prose-quiet); line-height: var(--ln-lh-quiet); color: var(--ink-soft); margin: 0; }
.ln-readout { font-family: var(--mono); font-size: var(--ln-eyebrow); line-height: var(--ln-lh-eyebrow); color: var(--ink-soft); margin: 0; }

/* ── the diagram ─────────────────────────────────────────────────────────── */
.dg { display: block; }
.dg-conn { stroke: var(--rule-2); stroke-width: 1.25; fill: none; }
.dg-conn--back { stroke-dasharray: 4 3; }
#dg-arrow path { fill: var(--rule-2); }
.dg-node__b { fill: var(--paper); stroke: var(--rule-2); stroke-width: 1; }
.dg-node { cursor: pointer; }
.dg-node:focus-visible { outline: none; }
.dg-node:focus-visible .dg-node__b { stroke: var(--brass); stroke-width: 2; stroke-dasharray: 4 3; }
.dg-node__l, .dg-label { font-family: var(--sans); font-size: 0.8125rem;
                         line-height: 1.2; fill: var(--ink); }
.dg-label__bg { fill: var(--paper); }
.dg-mark rect { fill: var(--paper); stroke: var(--rule-2); stroke-width: 1; }
.dg-mark text { fill: var(--ink); font-size: 0.8125rem; }
.dg-key { margin: 0; padding: 0; display: grid; gap: var(--ln-1); list-style: none; }
.dg-key__i { font-size: 0.9375rem; line-height: 1.5; color: var(--ink-soft); }
.dg-fallback { display: grid; gap: var(--ln-2); }
.dg-steps { margin: 0; padding-left: var(--ln-4); display: grid; gap: var(--ln-1); }
.dg-step { font-size: 1rem; line-height: 1.55; }

/* ── the chart ───────────────────────────────────────────────────────────
   FOUR LANES TOLD APART BY WEIGHT AND BY POSITION, which is what STATES in
   the contract asks for: a channel that is not color. Lane order is fixed left
   to right, so a reader who cannot see the weights can still count across.
   ────────────────────────────────────────────────────────────────────────── */
.ck { display: block; }
.ck-tick { stroke: var(--rule); stroke-width: .5; }
.ck-zero { stroke: var(--rule-2); stroke-width: 1.25; }
.ck-tick__l, .ck-cat { fill: var(--ink-soft); font-family: var(--mono); font-size: 0.8125rem; }
.ck-bar { fill: var(--brass); fill-opacity: .55; }
.ck-series[data-lane='0'] .ck-bar { fill-opacity: .85; }
.ck-series[data-lane='1'] .ck-bar { fill-opacity: .62; }
.ck-series[data-lane='2'] .ck-bar { fill-opacity: .4; }
.ck-series[data-lane='3'] .ck-bar { fill-opacity: .24; }
.ck-bar--zero { stroke: var(--ink-soft); stroke-width: 2.5; }
.ck-line { stroke: var(--brass); stroke-width: 1.5; fill: none; }
.ck-base__l { stroke: var(--ink-soft); stroke-width: 2; stroke-dasharray: 3 2; }
.ck-hit { fill: transparent; }
.ck-dot { fill: var(--brick); opacity: 0; }
.ck-datum { cursor: pointer; }
.ck-datum:focus-visible { outline: none; }
.ck-datum:focus-visible .ck-hit { outline: 2px solid var(--brass); outline-offset: -2px; }
.ck-key { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--ln-1) var(--ln-3);
          font-size: 0.875rem; line-height: 1.3; }
.ck-key__i { display: inline-flex; align-items: center; gap: var(--ln-1); min-height: 24px; }
.ck-key__s { width: .85em; height: .85em; border: 1px solid var(--rule-2); background: var(--brass); display: inline-block; }
.ck-key__i[data-lane='0'] .ck-key__s { opacity: .85; }
.ck-key__i[data-lane='1'] .ck-key__s { opacity: .62; }
.ck-key__i[data-lane='2'] .ck-key__s { opacity: .4; }
.ck-key__i[data-lane='3'] .ck-key__s { opacity: .24; }
.ck-key__i--base .ck-key__s { background: none; border-style: dashed; border-width: 2px 0 0; height: 0; width: 1.2em; }
.ck-key__i[data-selected='yes'] { font-weight: 700; text-decoration: underline; text-underline-offset: 2px; }

/* The four states, each with a channel that is not color. */
.ck-series[data-selected='yes'] .ck-bar { fill-opacity: 1; stroke: var(--brass); stroke-width: 1.5; }
.ck-series[data-selected='yes'] .ck-bar--zero { stroke-width: 4; }
.ck-series[data-hovered='yes'] .ck-bar { stroke: var(--brass); stroke-width: .75; }
.dg-node[data-selected='yes'] .dg-node__b { stroke: var(--brass); stroke-width: 3; }
.dg-node[data-hovered='yes'] .dg-node__b { stroke: var(--brass); stroke-width: 2; }
.ck-datum[data-focused='yes'] .ck-dot { opacity: 1; }
[data-emphasis] { outline: 2px dotted var(--brass); outline-offset: 1px; }

/* ── the summary, the inspector and the result ───────────────────────────── */
.ln-tw { overflow-x: auto; max-width: 100%; }
.ck-t { border-collapse: collapse; font-size: 0.875rem; line-height: 1.3; }
.ck-t caption { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
.ck-t th, .ck-t td { border: 1px solid var(--rule); padding: var(--ln-1) var(--ln-2); text-align: right; white-space: nowrap; }
.ck-t th[scope='row'] { text-align: left; }
.ck-t__r--baseline td, .ck-t__r--baseline th { color: var(--ink-soft); font-style: italic; }
.ck-t__v--none { font-style: italic; color: var(--ink-soft); }
.ck-t__r[data-selected='yes'] th[scope='row'] { font-weight: 700; }
.ck-handle { cursor: pointer; text-decoration: underline; text-underline-offset: 2px;
             display: inline-block; min-height: 24px; }

.ln-ins { display: grid; gap: var(--ln-2); }
.ln-ins dl { display: grid; grid-template-columns: auto 1fr; gap: var(--ln-1) var(--ln-3); margin: 0;
             font-size: var(--ln-label); line-height: var(--ln-lh-label); }
.ln-ins dt { font-weight: 600; }
.ln-ins dd { margin: 0; font-family: var(--mono); font-variant-numeric: tabular-nums; }
.ln-facets { display: flex; flex-wrap: wrap; gap: var(--ln-2); margin: 0 0 var(--ln-2); }

.ln-teach { display: grid; gap: var(--ln-3); }
.ln-teach__beat { display: grid; gap: var(--ln-1); }
.ln-teach__h { font-family: var(--mono); font-size: var(--ln-eyebrow); line-height: var(--ln-lh-eyebrow);
               letter-spacing: .06em; text-transform: uppercase; color: var(--brass); margin: 0; }
.ln-next { display: grid; gap: var(--ln-2); margin: 0; padding: 0; list-style: none; }
.ln-next__why { font-size: var(--ln-prose-quiet); line-height: var(--ln-lh-quiet); color: var(--ink-soft); margin: 0; }
.ln-mark { display: flex; flex-wrap: wrap; gap: var(--ln-2); align-items: center; }
.ln-mark__d { font-size: var(--ln-label); line-height: var(--ln-lh-label); font-weight: 600; }
.ln-held { border-left: 3px solid var(--brick); padding-left: var(--ln-3); }
