/**
 * WHAT:    The visual system for the dwlearn surfaces — the named primitives every
 *          page composes from.
 * WHY:     Kant rule: a design element is a general rule with a global name, or it does
 *          not exist. Nothing here is a one-off; each block below is one primitive, used
 *          wherever that kind of thing appears.
 *
 *            lhd      surface head (crumb · title)
 *            crumb    the way back, plus the other language
 *            lmeta    structural information — counts, ordinals, verdicts
 *            steps    position in the lesson's steps
 *            meter    partial progress, honest about being partial
 *            drill    one exercise, blank INLINE in the sentence
 *            pane     help beside the blank — bank (candidates) / ref (forms)
 *            keys     the drill's buttons
 *            pending  secondary prose — how to work this page, and what is not written yet
 *            forward  the one move on from a page
 *            entry    the one way INTO a course or group
 *
 * NOT:     a palette, and NOT a type scale. Every colour here is a dwtheme token, and so is
 *          every font-size but one — inline code, which is sized as a ratio to the line it
 *          interrupts and says why at its own rule.
 *          All four skins (Hell · Sand · Dunkel · Auto) keep working with
 *          no rule of their own, and the type sits on the site's five-step ladder rather
 *          than on the design mock's — which is where it started, and which is how a
 *          single page came to carry EIGHT sizes and four weights. A literal hex would
 *          break exactly one theme and nobody would notice which; a literal px breaks the
 *          rule that every text element picks a step, and everything drifts from there.
 *          The LEADING is a ramp too, and the same rule binds it: a bare 1.22 next to a bare
 *          1.25 is two people guessing at the same decision.
 *          --fs-display · --fs-heading · --fs-body · --fs-subhead · --fs-small · --fs-micro
 *          --fw-regular · --fw-medium · --fw-semibold · --fw-bold
 *          --lh-solid · --lh-tight · --lh-snug · --lh-normal · --lh-loose
 * INPUT:   the markup in includes/routes.php and assets/js/react-frontend.js.
 * DEPENDS: dwtheme's tokens.css (enqueued globally by the theme).
 * TESTED BY: tests/parity.mjs (which asserts VISIBILITY, not class names — a class that
 *          applies while the rule that does the work is missing is the bug it caught).
 *
 * SCOPING. These are short, generic names — .steps, .keys, .pane, .entry — chosen because
 * they name the rule rather than the plugin. They are safe only because every selector is
 * under .dwlearn-main (the page) or .dwlearn (the drill, which also renders in wp-admin's
 * preview). Never write one of these names unscoped.
 */

/* ---- the token bridge -------------------------------------------------------
   The design system speaks --key / --fg / --line; dwtheme's kernel calls the same
   things --rubric / --ink / --rule. Bridged ONCE, here, rather than translated at
   every callsite — so a theme that re-tints --rubric (dushanwegner.com's red over
   latinprayer.org's oxblood) re-tints dwlearn with it, for free.

   .dwlearn-essay IS ON THIS LIST even though it renders on an essay page, outside every
   learn surface. The colour half of the bridge it does not need — that block names dwtheme's
   own tokens, which reach an essay page by themselves. The SPACING half it does: --l-1..--l-5
   are dwlearn's own scale and exist nowhere else, so while the block sat outside this
   selector every var(--l-N) there fell through to a literal pixel fallback written beside
   it — the three rungs the block uses, restated by hand. A change to the scale would then
   have moved every learn surface and left the essay door where it was. */
.dwlearn-main,
.dwlearn,
.dwlearn-essay {
  --key:    var(--rubric);
  --key-2:  var(--rubric-2);      /* the same accent, deeper — what a key-coloured link does on hover */
  --fg:     var(--ink);
  --fg-2:   var(--ink-soft);
  --fg-3:   var(--ink-mute);
  --line:   var(--rule);
  --line-2: var(--rule-soft);
  --yes:    var(--positive-fg);   /* the colour a word turns when it means "correct" */

  /* the one spacing scale — every margin and gap below is one of these five */
  --l-1: 6px; --l-2: 10px; --l-3: 16px; --l-4: 26px; --l-5: 38px;
  --l-num: 40px;   /* the ordinal gutter — identical in every list on the surface */
}

/* THE MEASURE IS THE SITE'S READING COLUMN, not one of dwlearn's own.
   The markup carries the theme's `container`, so the centring and the responsive
   gutters are the very rules a single essay is set in; all that is left to say is
   how wide the column may grow, and that is already a named token — `--w-read`,
   documented in the theme's kernel as "single-column reading: prayer, chapter,
   LESSON, doc". A lesson is exactly that, so it uses it rather than a number of
   its own, and a reader moving from an essay to a drill sees the text stay where
   it was.
   The selector names all three parts because it has to outrank the theme's own
   `main.container { max-width: 1080px }`, which is the index measure and loads
   after this file: dwlearn's stylesheet is enqueued during template_redirect,
   before the theme's, so on equal specificity the theme would win. */
main.dwlearn-main.container {
  max-width: var(--w-read, 720px);
  /* The reading column's gutter is ONE value at every width (dwtheme's own rule: --w-read is an
     outer cap, so a gutter that steps with the viewport makes the measure wobble). The theme
     applies it by body class — single-post, page, 404 — and a dwlearn surface is not a WP
     template, so it claims the same token here rather than inheriting bootstrap's stepped
     default. Same token, not the same number: when the reading measure moves, this moves with it. */
  padding-left: var(--w-read-gutter, 1rem);
  padding-right: var(--w-read-gutter, 1rem);
  padding-bottom: var(--l-5);
  color: var(--fg);
}

/* ---- lhd · surface head ---------------------------------------------------- */
.dwlearn-main .lhd { margin-bottom: var(--l-4); }
.dwlearn-main .lhd h1 {
  font-size: var(--fs-display); font-weight: var(--fw-bold); letter-spacing: -0.03em; line-height: var(--lh-tight);
  margin: 0; color: var(--fg);
}
/* The eyebrow that says what the page IS, above a title that says what it is about. It carries
   dwtheme's .lp-eyebrow for everything typographic; the only thing said here is that it sits
   tight above the h1, which is a fact about this head and not about eyebrows. */
.dwlearn-main .lhd .lhd-eyebrow { margin: 0 0 var(--l-1); }
.dwlearn-main .lhd .sub { font-size: var(--fs-small); color: var(--fg-2); margin: 8px 0 0; text-wrap: pretty; }
@media (max-width: 520px) { .dwlearn-main .lhd h1 { font-size: var(--fs-heading); } }

/* ---- crumb · the way back ---------------------------------------------------
   Only that. A language switcher used to ride the far end of this row; it is gone
   from every surface — a reader on the German site is reading German, and the
   hreflang alternates in <head> tell a crawler the other edition exists without
   spending a line on it. */
.dwlearn-main .crumb {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
  font-size: var(--fs-small); color: var(--fg-3);
  padding-bottom: var(--l-3); margin-bottom: var(--l-4);
  border-bottom: 1px solid var(--line);
}
.dwlearn-main .crumb a { color: var(--fg-2); }
.dwlearn-main .crumb a:hover { color: var(--key); }
.dwlearn-main .crumb .sep { color: var(--fg-3); }
/* NO SEGMENT MAY DOMINATE THE ROW. On a wide column the trail has room, so this
   cap cuts almost nothing — every group name in the course and every lesson title
   passes through whole, including the 52-character extremes. It is a safety valve
   against a title nobody has written yet, not a routine trim.
   The full text stays in the DOM: a screen reader and a crawler read the whole
   name, only the eye is spared it, and the h1 below always says it in full. */
.dwlearn-main .crumb a,
.dwlearn-main .crumb > span:not(.sep) {
  display: inline-block;
  max-width: 40ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: bottom;
}

/* ON A PHONE THE TRAIL IS ONE THING: THE WAY UP.
   A third of the width cannot hold a chain. Capping each segment instead produced
   "Spanisch › Pretérito imperfe… › Pretérito imperfe…" — two crumbs truncated to
   the same string, telling the reader nothing and still wrapping to two lines.
   So the chain collapses to its nearest ancestor, marked with a back chevron, and
   the current page is dropped: the h1 directly beneath already names it. What
   remains is one line with one link on it, which is the whole job. */
@media (max-width: 560px) {
  /* These mirror the truncation selectors above SHAPE FOR SHAPE, because they have to beat
     them and specificity is decided before source order: a bare `> span` loses to
     `> span:not(.sep)`, and the chain stayed visible twice while I shortened the wrong thing. */
  .dwlearn-main .crumb > a,
  .dwlearn-main .crumb > span:not(.sep),
  .dwlearn-main .crumb > span.sep { display: none; }
  .dwlearn-main .crumb > a.up { display: inline-block; max-width: 22ch; }
  .dwlearn-main .crumb .up::before { content: "‹\00a0"; color: var(--fg-3); }
}

/* ---- lmeta · structural information -----------------------------------------
   AN EYEBROW THAT CARRIES NUMBERS. dwtheme's `.lp-eyebrow` is a label that NAMES something, and
   that is what the heads and the box titles use. This is the other half: counts, ordinals,
   verdicts and progress — data, not a name, so it is a flex row with tabular figures and the
   number in the accent. It takes the primitive's TYPE exactly (micro, semibold, 0.16em, upper),
   because two uppercase micro labels a hand's width apart at different trackings read as a
   mistake; only the layout and the figures are its own. */
.dwlearn-main .lmeta,
.dwlearn .lmeta {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 3px 10px; margin: 0;
  font-size: var(--fs-micro); font-weight: var(--fw-semibold); letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--fg-3); font-variant-numeric: tabular-nums;
}
.dwlearn-main .lmeta b,
.dwlearn .lmeta b { color: var(--key); font-weight: var(--fw-bold); }
/* the head's two halves: where you are in this round, and how much of the lesson you have
   answered. The second is the one worth watching, so it is the one the meter draws. */
.dwlearn .drill-hd .pct { white-space: nowrap; }
.dwlearn-main .lmeta .sep,
.dwlearn .lmeta .sep { color: var(--line); }
.dwlearn-main .lmeta .prog,
.dwlearn .lmeta .prog { display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; }

/* ---- steps · the lesson is a few steps at one level -------------------------
   Position in a sequence, not a progress bar and not a wizard: equal columns, the
   ordinal above the name, the current one carrying the accent rule on top.
   grid-auto-columns rather than repeat(3,1fr) because a lesson without a
   vocabulary deck has two steps and must not leave a third of the row empty. */
.dwlearn-main .steps {
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  border-top: 1px solid var(--line); margin: 0 0 var(--l-4);
}
.dwlearn-main .steps a {
  display: flex; flex-direction: column; justify-content: center; gap: 2px;
  /* the ordinal used to make this row tall enough by accident; with one line in it the step
     needs a stated height, or it drops under the thumb minimum on a phone */
  min-height: 44px; padding: 10px 12px 8px 0; margin-top: -1px;
  border-top: 2px solid transparent; color: var(--fg-3);
}
.dwlearn-main .steps a:hover { text-decoration: none; }
.dwlearn-main .steps .nm {
  font-size: var(--fs-small); font-weight: var(--fw-semibold); letter-spacing: -0.012em; color: var(--fg-2); line-height: var(--lh-snug);
}
.dwlearn-main .steps a:hover .nm { color: var(--fg); }
.dwlearn-main .steps a[aria-current="page"] { border-top-color: var(--key); color: var(--key); }
.dwlearn-main .steps a[aria-current="page"] .nm { color: var(--fg); font-weight: var(--fw-bold); }

/* ---- meter · partial progress -----------------------------------------------
   40px of hairline. It reads at a glance and it cannot be mistaken for a score,
   which is the point: it says "this far through", not "this well". */
.dwlearn-main .meter,
.dwlearn .meter {
  position: relative; display: block; width: 40px; height: 3px;
  background: var(--line); border: 0; flex: none;
}
.dwlearn-main .meter i,
.dwlearn .meter i { position: absolute; inset: 0 auto 0 0; width: var(--p, 0%); background: var(--key); }
html[data-theme="dark"] .meter,
html[data-theme="night"] .meter { background: var(--bg-3); }

/* ---- drill · one exercise ----------------------------------------------------
   THE BLANK SITS IN THE GAP. It used to float above the sentence, centred, with
   the sentence printed underneath — so the reader read the sentence, looked up,
   typed, and looked down again to check. An inline input is the whole exercise in
   one line of sight. */
.dwlearn.drill {
  border: 1px solid var(--line); background: var(--bg-2);
  padding: var(--l-3) var(--l-4) var(--l-4);
}
.dwlearn .drill-hd {
  display: flex; align-items: center; justify-content: space-between; gap: var(--l-3);
  padding-bottom: var(--l-4); border-bottom: 1px solid var(--line);
}
.dwlearn .sent {
  font-size: var(--fs-body); line-height: var(--lh-loose); letter-spacing: -0.012em; color: var(--fg);
  margin: var(--l-4) 0 0; text-wrap: pretty;
}
/* The cue — "(Can you)" — is the English a Spanish sentence does not have. It is a
   note ABOUT the sentence, so it is set back from it. */
.dwlearn .sent .cue { color: var(--fg-2); }
.dwlearn input.blank {
  font: inherit; font-weight: var(--fw-bold); color: var(--fg);
  background: transparent; border: 0; border-bottom: 2px solid var(--fg-3); border-radius: 0;
  padding: 0 3px; margin: 0 1px; width: var(--w, 7ch); text-align: center;
  outline: none; -webkit-appearance: none;
}
.dwlearn input.blank:focus { border-bottom-color: var(--key); }
/* Correct is the sentence completing itself — the word simply stands there, in the
   ink of the sentence. No tick, no green, no celebration. Wrong takes the accent,
   which is the same colour the rest of the page uses to mean "look here". */
.dwlearn input.blank.is-ok { color: var(--fg); border-bottom-color: var(--fg); }
.dwlearn input.blank.is-off { color: var(--key); border-bottom-color: var(--key); }
/* A DASHED RULE MEANS THE SHAPE IS RIGHT AND SOMETHING IS MISSING. The letters are right and a
   mark is not, so the blank keeps the sentence's ink and only its rule marks the miss — dashed,
   because a broken line reads as incomplete where a solid one reads as rejected. */
.dwlearn input.blank.is-near {
  color: var(--fg); border-bottom-style: dashed; border-bottom-color: var(--key);
}
/* ---- slot · the reserved answer area ----------------------------------------
   A CONTROL MUST NEVER MOVE OUT FROM UNDER THE POINTER ABOUT TO PRESS IT.
   Everything an item can say about itself — hint, translation, literal, verdict — lives in ONE
   slot under the sentence, and drill.js holds that slot at the height of its tallest possible
   state. So a verdict arriving moves nothing, and neither does a translation: not the reference
   panel, not the buttons.

   On a phone the same reservation would cost a third of the screen, so there the slot collapses
   to its content and the keys leave the flow to dock at the bottom edge instead — a docked
   control cannot be pushed out from under a thumb. Which mechanism applies is decided by whether
   reserving is affordable, not by taste; neither is a fallback for the other. */
.dwlearn .slot { min-height: var(--slot, 0px); margin-top: var(--l-2); }
.dwlearn .hint { font-size: var(--fs-small); color: var(--fg-3); margin: 0; }
.dwlearn .trans { font-size: var(--fs-small); color: var(--fg-2); margin: var(--l-1) 0 0; }
.dwlearn .trans[hidden] { display: none; }
/* The literal sits UNDER the translation, quieter: it is a note about what the Spanish actually
   says, for the reader who wants to see the construction rather than the German equivalent. */
.dwlearn .lit { font-size: var(--fs-small); color: var(--fg-3); margin: 2px 0 0; font-style: italic; }
.dwlearn .lit[hidden] { display: none; }
/* THE VERDICT'S LINE IS ALWAYS THERE, empty or not. It is the one thing on the card that appears
   without being asked for, so if it takes its space only when it arrives, answering nudges the
   whole panel — and the button the reader just pressed moves under their cursor.
   One line of its OWN type, stated once as a line-height and once as the height that reserves:
   14px was a guess, and the filled line was 19. The two are the SAME decision, so the reserve is
   computed from the leading token rather than restating its number — move the rung and the empty
   line moves with the filled one. */
.dwlearn .verdict {
  margin-top: var(--l-3);
  line-height: var(--lh-loose);
  min-height: calc(var(--lh-loose) * 1em);
}
/* THE WORD CARRIES THE STATE, THE ASIDE IS ALWAYS QUIET. One rule for all four states rather
   than a colour per line: the reader learns to read the word's colour, and an instruction that
   took the colour too would stop reading as an instruction. */
.dwlearn .verdict .v { font-weight: var(--fw-bold); }
.dwlearn .verdict.ok .v,
.dwlearn .verdict.ok .tick { color: var(--yes); }
.dwlearn .verdict.near .v,
.dwlearn .verdict.off .v { color: var(--key); }
.dwlearn .verdict.shown .v { color: var(--fg-2); }
.dwlearn .verdict .tick { display: inline-flex; align-self: center; }
.dwlearn .verdict .tick svg { width: 1.2em; height: 1.2em; }
.dwlearn .verdict .tick[hidden] { display: none; }
/* aside · a full sentence carried by a meta line. Meta lines uppercase LABELS — a sentence set in
   caps at 0.09em tracking is a line a reader skips — so an aside keeps its own case, its own
   tracking and the line's normal ink, and stays at the line's one size. */
.dwlearn .lmeta .aside {
  text-transform: none; letter-spacing: normal; font-weight: var(--fw-regular);
  color: var(--fg-2);
}
.dwlearn .lmeta .aside[hidden] { display: none; }

/* ---- pane · help beside the blank -------------------------------------------
   Two shapes, deliberately different, because they answer different questions.
   The BANK offers candidates — so its pairs are controls: they hover, they focus,
   you can click one into the blank. The REFERENCE offers forms — data you read,
   so it is hairlines and no affordance at all. Making them look alike would
   promise that a table of forms is clickable. */
.dwlearn .pane { margin-top: var(--l-4); border-top: 1px solid var(--line); padding-top: var(--l-3); }
.dwlearn .pane > .lmeta,
.dwlearn .pane > .bank-ttl { margin-bottom: var(--l-2); }
/* the bank's title is dwtheme's eyebrow; only its colour is the pane's own, which is quieter than
   the primitive's default so the WORDS below it stay the loudest thing in the card */
.dwlearn .pane > .bank-ttl { color: var(--fg-3); }
.dwlearn .pair {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: baseline; gap: var(--l-3);
}
.dwlearn .pane .k { font-size: var(--fs-small); font-weight: var(--fw-semibold); color: var(--fg); }
.dwlearn .pane .v { font-size: var(--fs-small); color: var(--fg-2); }
.dwlearn .bank .cells { display: flex; flex-direction: column; gap: 1px; }
.dwlearn .bank .cell {
  width: 100%; text-align: left; font: inherit; background: transparent;
  border: 1px solid transparent; border-radius: var(--r-control); padding: 8px 10px; cursor: pointer;
}
.dwlearn .bank .cell:hover { background: var(--bg-3); border-color: var(--line); }
.dwlearn .bank .cell:focus-visible { outline: none; border-color: var(--key); }
.dwlearn .bank .cell { font-weight: var(--fw-semibold); color: var(--fg); }
/* a word already tried this round is spent, not gone — removing it would tell the reader
   something about the answers they have not earned */
.dwlearn .bank .cell.is-used { color: var(--fg-3); font-weight: var(--fw-regular); }

/* ref: hairlines and no affordance at all. Nothing here hovers, nothing here can
   be clicked into the blank — because it is a paradigm to read off, not a list of
   answers to pick from. Making it look like the bank would promise otherwise. */
.dwlearn .pane > summary {
  display: flex; align-items: center; gap: 8px; cursor: pointer; list-style: none;
  margin-bottom: var(--l-2);
  font-size: var(--fs-micro); font-weight: var(--fw-semibold); letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--fg-3);
}
.dwlearn .pane > summary::-webkit-details-marker { display: none; }
.dwlearn .pane > summary:hover { color: var(--fg-2); }
/* THE DISCLOSURE CHEVRON IS THE THEME'S, `.lp-chev` — dwlearn drew its own 13px box with 5px arms
   at 1.6px, which is the same idea as the primitive at a different weight, and the primitive
   already carries the two angles, the 0.16s and the reduced-motion guard. Only the OPEN angle is
   stated here: `.lp-chev` documents -45° closed and 45° open, and the rule that flips it belongs to
   whoever owns the <details> — the primitive cannot know what opened. */
.dwlearn-main [open] > summary .lp-chev,
.dwlearn [open] > summary .lp-chev { transform: rotate(45deg); }
/* auto-fit, so a panel with one group fills the width and a later one with two
   splits — without either needing a rule of its own. */
.dwlearn .ref .cols {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
  gap: var(--l-4);
}
.dwlearn .ref .col > .lmeta { padding-bottom: 6px; border-bottom: 1px solid var(--line); }
/* --line, not the softer --line-2: the pane sits on the card's sunken ground, and
   --line-2 is a hairline tuned against the PAGE. On the Sand card it disappeared
   entirely and the forms ran together as one block of text. */
.dwlearn .ref .pair { padding: 7px 0; border-bottom: 1px solid var(--line); }
.dwlearn .ref .pair:last-child { border-bottom: 0; }
/* A CONJUGATION IS A TABLE, not a sentence. Six forms in one wrapped line is the hardest thing to
   read in a panel whose whole job is scan → find → type; two columns, singular beside plural, is
   how every grammar book sets one and how a reader hunting "the vosotros form" expects to find
   it. The person words carry which column is which, so it needs no headings. */
/* FOUR COLUMNS, not two columns of rows. Each `.f` is a person and a form, and while the pair
   was its own flex box the forms started wherever the person happened to end — "yo soy" and
   "nosotros somos" set their verbs at different x, so a reader scanning for a form had a ragged
   edge to follow. `display: contents` hands the person and the form straight to the grid, which
   then sizes the two person columns to their own widest word and lines every form up. */
.dwlearn .ref .forms {
  display: grid; grid-template-columns: repeat(2, auto 1fr);
  gap: 2px 8px; align-items: baseline;
}
.dwlearn .ref .forms .f { display: contents; }
.dwlearn .ref .forms .p { color: var(--fg-3); font-size: var(--fs-small); }
/* the second pair keeps its distance from the first — one gap between a person and its form,
   a wider one between the singular column and the plural */
.dwlearn .ref .forms > .f:nth-of-type(2n) .p { padding-left: var(--l-3); }
.dwlearn .ref .forms .e { color: var(--fg); font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; }
/* A GLOSSARY IS A TABLE TOO — the paradigm's rule above, for the other shape a reference takes: a
   term and what it means. Two columns, the term sized to its own widest entry so every gloss
   starts at the same x and the eye runs down one edge instead of hunting along a wrapped line. */
.dwlearn .ref .pairs {
  display: grid; grid-template-columns: auto 1fr;
  gap: 4px var(--l-2); align-items: baseline;
}
.dwlearn .ref .pairs .pr { display: contents; }
.dwlearn .ref .pairs .t { color: var(--fg); font-weight: var(--fw-semibold); }
.dwlearn .ref .pairs .g { color: var(--fg-2); text-wrap: pretty; }
/* Narrow: the label stops taking half the row, so the paradigm keeps its two columns instead of
   being squeezed into a quarter of the screen each. */
@media (max-width: 600px) {
  .dwlearn .ref .pair { grid-template-columns: 1fr; gap: 4px; }
  .dwlearn .ref .forms { gap: 2px var(--l-2); }
}
@media (max-width: 600px) { .dwlearn .ref .cols { gap: var(--l-3); } }

/* ---- keys · the drill's buttons ---------------------------------------------
   The site's own button primitive, not the browser's. One of the three is primary
   because one of them is what you do next. */
.dwlearn .keys { display: flex; flex-wrap: wrap; gap: 8px; margin-top: var(--l-4); }
.dwlearn .keys .btn { flex: 1 1 auto; min-width: 112px; }

/* THE PHONE DOCKS WHAT THE DESKTOP RESERVES. Below this width the slot collapses — reserving
   here would spend a third of the screen on emptiness — and the keys leave the flow for the
   bottom edge, where nothing appearing above them can push them away from a thumb. The negative
   margin lets the docked bar span the card's full width while its padding keeps the buttons on
   the card's own gutter. */
@media (max-width: 560px) {
  .dwlearn .slot { min-height: 0; }
  .dwlearn .keys {
    position: sticky; bottom: 0; z-index: 2;
    margin: var(--l-3) calc(-1 * var(--l-3)) 0;
    padding: var(--l-2) var(--l-3);
    background: var(--bg-2); border-top: 1px solid var(--line);
    gap: 6px;
    /* the rule the comment below states, actually written: the desk bar wraps, and a docked bar
       must not — wrapping is decided BEFORE shrinking, so without this a button whose label is
       wider than its share drops to a second row instead of the row giving way */
    flex-wrap: nowrap;
  }
  /* ONE ROW, because a docked bar is paid for in screen height: three buttons wrapping to two
     rows spend a second band of the page on controls the reader is not looking at. They shrink
     to fit rather than wrap, and stay at the thumb minimum.
     THE BASIS IS THE LABEL, NOT AN EQUAL THIRD. `flex-basis: 0` divides the bar into three equal
     boxes, which on a 320px phone gives each 79px of content — and "Übersetzung" is 87px of ink,
     so the longest German label spilled out over its own border and into the button beside it.
     Equal thirds is not what "shrink to fit" means: shrinking the box without shrinking what is
     in it fits nothing. Basis `auto` sizes each button to its own label and shares the leftover,
     so the three still fill one row and every label stays inside its button — at 320px too, where
     the labels need 245px of the 264 available. `auto` is also the basis one breakpoint up, so the
     phone no longer sizes its buttons by a different principle than the desk — only smaller. */
  .dwlearn .keys .btn {
    flex: 1 1 auto; min-width: 0; padding: 12px 8px; font-size: var(--fs-small);
  }
  /* A DOCKED BAR OWNS THE FOOT OF THE SCREEN, SO NOTHING THE READER MUST READ MAY BE LAID OUT
     INTO IT. This rule is the docking rule's other half and lives beside it deliberately: the bank
     is two columns HERE, at exactly the widths where the bar leaves the flow, and nowhere else.
     One column of five 49px cells is 247px and the bar leaves 201px of room above itself, so the
     list ran under an opaque bar that then said nothing about it — and because the bank is
     alphabetical, "late in the alphabet" silently meant "not on the screen". On this lesson that
     hid the item's OWN ANSWER on 2 of 7 bank items at 390px and 4 of 7 at 320px, under a title
     that reads "Eines dieser Wörter". Two columns is three rows, 147px, and every candidate clears
     the bar at both widths.
     NOT a shorter bar and NOT fewer candidates: to clear the fifth cell by shrinking the bar it
     would have to be 25px at 390 and 1px at 320, and four candidates still overrun the bar at 320.
     The cell is untouched — same height, same left-aligned text, same hover and focus — because
     what was wrong was the column count, not the control. */
  .dwlearn .bank .cells { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; }
}
.dwlearn .btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  border: 1px solid var(--line); border-radius: var(--r-control); background: var(--bg);
  padding: 9px 15px; font: inherit; font-size: var(--fs-small); font-weight: var(--fw-semibold); color: var(--fg);
  cursor: pointer;
}
.dwlearn .btn:hover { background: var(--bg-3); text-decoration: none; }
.dwlearn .btn:disabled { opacity: .45; cursor: default; }
.dwlearn .btn:disabled:hover { background: var(--bg); }
.dwlearn .btn.primary { background: var(--key); border-color: var(--key); color: var(--on-key); }
.dwlearn .btn.primary:hover { filter: brightness(1.08); background: var(--key); }
@media (max-width: 520px) {
  .dwlearn.drill { padding: var(--l-3); }
  .dwlearn .sent { font-size: var(--fs-subhead); }
}

/* ---- pending · secondary prose ----------------------------------------------
   How to work this page, and what is not written yet. Both are the same kind of
   thing: a quiet sentence beside the content that does not compete with it. The
   partial state is the NORMAL state here for as long as the German is unwritten,
   so it gets a rule rather than an apology. */
.dwlearn-main .pending {
  font-size: var(--fs-small); line-height: var(--lh-normal); color: var(--fg-3);
  margin: 0 0 var(--l-3); max-width: 62ch;
}

/* A translation that has fallen back to English SAYS SO, keyed on its own lang
   attribute — never on the language of the page, because a German page carries
   honest lang="en" on exactly the strings that fell back.
   Only on a GERMAN surface: on the English course the same lang="en" is not a
   fallback, it is the language, and marking it would be nonsense. */
.dwlearn-main[data-interface="de"] .hint:lang(en)::after,
.dwlearn-main[data-interface="de"] .trans:lang(en)::after,
.dwlearn-main[data-interface="de"] .pane .v:lang(en)::after,
.dwlearn-main[data-interface="de"] .exs .eg:lang(en)::after,
.dwlearn-main[data-interface="de"] .gloss:lang(en)::after {
  content: "EN"; margin-left: 7px; font-size: var(--fs-micro); font-weight: var(--fw-bold);
  letter-spacing: 0.16em; color: var(--fg-3); vertical-align: 1px;
}

/* ---- prose · the one surface here that is READ, not worked ---------------------
   The explanation. Continuous text needs a rhythm the rest of this design does not:
   a measure, space between paragraphs, headings that separate rather than label.
   Nothing here is dwlearn-specific — it is the general rule for a passage of prose,
   and the lesson tables are the house form for a two-column mapping (138 of 148
   lessons use one), so they get a rule rather than a workaround. */
.dwlearn-main .prose { font-size: var(--fs-subhead); line-height: var(--lh-loose); color: var(--fg); max-width: 68ch; }
.dwlearn-main .prose p { margin: 0 0 20px; text-wrap: pretty; }
.dwlearn-main .prose h2 { font-size: var(--fs-heading); font-weight: var(--fw-bold); letter-spacing: -0.02em; margin: 40px 0 14px; }
.dwlearn-main .prose h3 { font-size: var(--fs-subhead); font-weight: var(--fw-bold); letter-spacing: -0.015em; margin: 30px 0 10px; }
.dwlearn-main .prose h4,
.dwlearn-main .prose h5 { font-size: var(--fs-subhead); font-weight: var(--fw-bold); margin: 24px 0 8px; }
.dwlearn-main .prose a { color: var(--key); font-weight: var(--fw-medium); }
.dwlearn-main .prose strong { font-weight: var(--fw-bold); }
.dwlearn-main .prose em { font-style: italic; }
/* THE ONE FONT-SIZE HERE THAT IS NOT A RUNG, and deliberately: code interrupts a line of
   prose, so its size is a RATIO to that line, not a step on the ladder. The ladder could not
   express it anyway — --fs-prose is viewport-conditional (21.6px on a desk, 16.2px on a
   phone), so any absolute rung would sit right at one width and wrong at the other. */
.dwlearn-main .prose code {
  font-family: var(--font-mono); font-size: .92em; background: var(--bg-2);
  padding: 1px 5px; border: 1px solid var(--line);
}
.dwlearn-main .prose ul { margin: 0 0 20px; padding-left: 22px; }
.dwlearn-main .prose li { margin-bottom: 9px; }
/* The table is HAIRLINES, not a box: it is a mapping to scan, and a grid of borders
   makes the eye stop at every cell. Same reasoning as the reference panel. */
/* A PROSE TABLE IS AS WIDE AS IT NEEDS TO BE, NOT AS WIDE AS THE COLUMN. Stretched to full
   width it put half a row between "I" and "am", and the eye then has to travel a hand's width to
   pair two things that belong together — which is the one job a mapping table has. Sized to its
   content instead, the pairs sit next to each other; the rules still run the full measure, so the
   block keeps the page's left and right edges. */
.dwlearn-main .prose table {
  /* min-width keeps a two-word mapping from collapsing to a thin ribbon in the middle of a
     720px column; max-width keeps a wide one inside it. */
  width: auto;
  min-width: min(100%, 34ch);
  max-width: 100%; border-collapse: collapse; margin: 0 0 24px;
  font-size: var(--fs-small); text-wrap: pretty;
}
.dwlearn-main .prose thead th {
  text-align: left; font-size: var(--fs-micro); font-weight: var(--fw-semibold); letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--fg-3); padding: 0 var(--l-3) 6px 0;
  border-bottom: 1px solid var(--line);
}
.dwlearn-main .prose tbody td {
  padding: 8px var(--l-3) 8px 0; border-bottom: 1px solid var(--line); vertical-align: top;
}
.dwlearn-main .prose tbody tr:last-child td { border-bottom: 0; }
.dwlearn-main .prose tbody td:first-child { color: var(--fg); font-weight: var(--fw-semibold); }
.dwlearn-main .prose tbody td:last-child { color: var(--fg-2); padding-right: 0; }
/* a wide table scrolls inside itself rather than pushing the page sideways */
@media (max-width: 560px) {
  .dwlearn-main .prose table { display: block; overflow-x: auto; }
}

/* ---- lsec · a section of a surface --------------------------------------------
   A heading and, beside it, how much is under it. Used wherever a page does more
   than one job and the second is not a footnote to the first. */
.dwlearn-main .lsec { margin-top: var(--l-5); }
.dwlearn-main .lsec-hd { display: flex; align-items: baseline; gap: var(--l-2); margin-bottom: var(--l-2); }
.dwlearn-main .lsec-hd h2 { font-size: var(--fs-subhead); font-weight: var(--fw-bold); letter-spacing: -0.02em; margin: 0; }

/* ---- exs · one word in real sentences -----------------------------------------
   The sentence and its translation are two LINES. A dash between two languages
   asks the reader to find where one ends; a line break tells them. `.idx.flush`
   drops the ordinal gutter, because a numbered example says nothing — these are
   instances, not a sequence. */
.dwlearn-main .exs { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--line); }
.dwlearn-main .exs li { padding: 12px 0; border-bottom: 1px solid var(--line); }
.dwlearn-main .exs .es { font-size: var(--fs-subhead); color: var(--fg); margin: 0; text-wrap: pretty; }
.dwlearn-main .exs .eg { font-size: var(--fs-small); color: var(--fg-3); margin: 3px 0 0; text-wrap: pretty; }

/* ---- forward · the one move on from a page ---------------------------------- */
/* .crumb-ext — the one thing the far end of the trail may carry. Pushed right, quiet, and
   carrying the site's own ↗ so it reads as "this opens the other thing" before it is read at all.
   On a phone the trail collapses to one link and this goes with it: two links on a 390px row,
   one of them leaving the section, is a row nobody aims at. */
.dwlearn-main .crumb .crumb-ext {
  margin-left: auto; display: inline-flex; align-items: center; gap: 5px;
  font-size: var(--fs-small); font-weight: var(--fw-semibold); color: var(--key);
}
.dwlearn-main .crumb .crumb-ext svg { width: 11px; height: 11px; }
.dwlearn-main .crumb .crumb-ext:hover { color: var(--key-2); text-decoration: none; }
@media (max-width: 560px) { .dwlearn-main .crumb .crumb-ext { display: none; } }

/* ---- foot · who made this and where a mistake goes --------------------------
   A course that ends mid-air reads as unfinished. It says three things and stops: what these
   lessons are, that they are checked but not perfect, and the address a correction goes to. The
   address is the point — a reader who finds a wrong translation and has nowhere to put it simply
   stops trusting the rest. */
.dwlearn-main .lfoot {
  margin-top: var(--l-5); padding-top: var(--l-3);
  border-top: 1px solid var(--line);
  font-size: var(--fs-small); line-height: var(--lh-normal); color: var(--fg-3);
  text-wrap: pretty;
}
.dwlearn-main .lfoot a { color: var(--fg-2); }
.dwlearn-main .lfoot a:hover { color: var(--key); }

/* .to-text — the essay this lesson belongs to. An `entry` because that is what it is: the one
   way into something, which is the same job the card on a course index does. Its own modifier
   only to sit tight under the step nav, where the decision it supports is made. */
.dwlearn-main .entry.to-text { display: block; margin: 0 0 var(--l-4); }
.dwlearn-main .entry.to-text .ttl {
  /* THREE LINES OF GERMAN ARE READ, NOT SCANNED, so they take --lh-loose — the ramp's reading
     step. `.ttl` is a title elsewhere and arrives tracked tight and set solid; both are undone
     here, because this one is a paragraph wearing the class of the thing it sits under. */
  font-size: var(--fs-small); font-weight: var(--fw-regular);
  line-height: var(--lh-loose); letter-spacing: 0;
  color: var(--fg-2); text-wrap: pretty; margin: 4px 0 0;
}
/* the way to the text sits on its own line under the summary, as a link — see the renderer */
.dwlearn-main .entry.to-text .forward { margin: var(--l-2) 0 0; font-weight: var(--fw-bold); }
.dwlearn-main .forward {
  display: inline-flex; align-items: center; gap: 6px; margin-top: var(--l-4);
  font-size: var(--fs-small); font-weight: var(--fw-semibold); color: var(--key);
}

/* ---- seg · one exclusive choice ----------------------------------------------
   The lens. Filled, not underlined: an underline says "link", a fill says "this
   is the one you are in". Keyed on aria-current, so the markup states the fact
   once and the styling reads it. */
.dwlearn-main .seg {
  display: inline-flex; border: 1px solid var(--line); border-radius: var(--r-control);
  overflow: hidden; background: var(--bg);
}
.dwlearn-main .seg a {
  display: inline-flex; align-items: center;
  font-size: var(--fs-micro); font-weight: var(--fw-medium); color: var(--fg-2);
  padding: 0 14px; border-left: 1px solid var(--line);
}
.dwlearn-main .ltools .seg { height: var(--l-ctl); }
.dwlearn-main .seg a:first-child { border-left: none; }
.dwlearn-main .seg a:hover { background: var(--bg-2); color: var(--fg); text-decoration: none; }
.dwlearn-main .seg a[aria-current="page"] { background: var(--key); color: var(--on-key); }

/* ---- ltools · the row of things you do TO the list below -----------------------
   ONE HEIGHT for everything in it. A segmented control and an icon button sitting
   side by side at 36 and 42 pixels read as two unrelated objects that happen to be
   near each other; the same height makes them one row. */
.dwlearn-main .ltools {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--l-2) var(--l-3); margin: 0 0 var(--l-4);
  --l-ctl: 42px;
}
/* the search sits at the FAR END — it acts on the list, the lens chooses which list */
.dwlearn-main .lsearch-toggle { margin-left: auto; }
/* …and the field it opens takes the row below, whole */
.dwlearn-main .lsearch { flex: 0 0 100%; min-width: 0; }
.dwlearn-main .lsearch form { display: flex; gap: 8px; min-width: 0; }
.dwlearn-main .lsearch .field {
  flex: 1; min-width: 0; height: var(--l-ctl);
  border: 1px solid var(--line); border-radius: 0;
  background: var(--bg); padding: 8px 12px; font: inherit; font-size: var(--fs-small); color: var(--fg);
}
.dwlearn-main .lsearch .field::placeholder { color: var(--fg-3); }
.dwlearn-main .lsearch .field:focus { outline: none; border-color: var(--key); }
.dwlearn-main .lsearch .btn { flex: none; height: var(--l-ctl); }
/* It SLIDES: the row grows from nothing rather than appearing, so the list below is
   pushed down by something the eye has followed. grid-template-rows because it needs
   no guessed height — 0fr to 1fr is the element's own. */
.dwlearn-main .lsearch:not([hidden]) { display: grid; grid-template-rows: 0fr; }
.dwlearn-main .lsearch > form { overflow: hidden; min-height: 0; }
.dwlearn-main .lsearch.is-open { grid-template-rows: 1fr; }
@media (prefers-reduced-motion: no-preference) {
  .dwlearn-main .lsearch:not([hidden]) { transition: grid-template-rows .18s ease; }
}

/* icon-btn · a control that is only its icon. The cost of pressing the wrong one here is
   nothing — you land on a page and come back — so it carries no label, only an aria-label for
   the readers who need one. Square, and never below the thumb minimum. */
.dwlearn-main .icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--l-ctl, 42px); height: var(--l-ctl, 42px); flex: none;
  border: 1px solid var(--line); border-radius: var(--r-control);
  background: var(--bg); color: var(--fg-2); cursor: pointer;
}
.dwlearn-main .icon-btn[aria-expanded="true"] { background: var(--bg-3); color: var(--fg); }
.dwlearn-main .icon-btn:hover { background: var(--bg-3); color: var(--fg); text-decoration: none; }
.dwlearn-main .icon-btn svg { width: 17px; height: 17px; }
/* The search shows as a FIELD where the row can hold one and as its ICON where it cannot —
   below that width the field wrapped onto a line of its own, which is a whole row spent on a
   control most readers do not use. Both are in the markup and both work without JavaScript. */
/* The course's own line stands down on a phone: "auf Deutsch erklärt · 90 Lektionen"
   answers a question a reader who is already inside the course has stopped asking. */
@media (max-width: 620px) {
  .dwlearn-main .lhd .sub { display: none; }
}
/* the site button primitive, shared with the drill's keys */
.dwlearn-main .btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  border: 1px solid var(--line); border-radius: var(--r-control); background: var(--bg);
  padding: 9px 15px; font: inherit; font-size: var(--fs-small); font-weight: var(--fw-semibold); color: var(--fg);
  cursor: pointer; white-space: nowrap;
}
.dwlearn-main .btn:hover { background: var(--bg-3); text-decoration: none; }
.dwlearn-main .btn.primary { background: var(--key); border-color: var(--key); color: var(--on-key); }
.dwlearn-main .btn.primary:hover { filter: brightness(1.08); background: var(--key); }

/* ---- idx · a list of things you can open --------------------------------------
   ONE ordinal gutter, identical in every list on the surface, so twenty collapsed
   groups read as a table of contents rather than twenty headings. The same
   primitive holds groups (an index) and lessons (a group page): the rows differ
   in what they open, not in what they are. */
.dwlearn-main .idx { border-top: 1px solid var(--line); list-style: none; margin: 0; padding: 0; }
.dwlearn-main .lrow {
  display: grid; grid-template-columns: var(--l-num) 1fr; gap: 2px var(--l-2);
  padding: 14px 0; border-bottom: 1px solid var(--line);
}
/* The row ordinal is dwtheme's .lp-ord primitive — and the primitive IS this
   treatment: oxblood, bold, sans, tabular. dwlearn had it right first, and the
   rest of the sites came to it, so there is nothing left to state here but the
   GUTTER (dwlearn's is 40px, not the 22px default) and the optical nudge that
   sits the numeral on the title's first line. */
.dwlearn-main .lrow { --lp-ord-slot: var(--l-num); }
.dwlearn-main .lrow .ord { padding-top: 4px; }
.dwlearn-main .lrow .ttl {
  font-size: var(--fs-body); font-weight: var(--fw-bold); letter-spacing: -0.022em; line-height: var(--lh-snug);
  color: var(--fg); margin: 0 0 3px; text-wrap: pretty;
}
.dwlearn-main .lrow .ttl a { color: inherit; }
/* The row is the target, not just the words in it: a 40px-tall row whose only hit area is a
   title is a row you miss on a phone. The link stretches over the whole thing. */
/* A ROW THAT LEADS SOMEWHERE IS CLICKABLE ACROSS ITS WHOLE AREA — the row is one destination, so
   the whole row is the target rather than the four words of its title. The stretched
   pseudo-element keeps ONE link with the title as its accessible name; anything in the row that
   must stay separately clickable takes .above. (wgnrstyle: core.css → rowlink.) */
.dwlearn-main .lrow.rowlink { position: relative; cursor: pointer; }
.dwlearn-main .lrow.rowlink .lead::after { content: ""; position: absolute; inset: 0; }
.dwlearn-main .lrow.rowlink .above { position: relative; }
/* DECORATION NEVER INTERCEPTS. The chevron is positioned so it can draw its arrow, which puts it
   ABOVE the stretched link and leaves a dead spot at the one end of the row a reader is most
   likely to aim for. It is aria-hidden — it says nothing and does nothing — so it takes no
   pointer events either. */
.dwlearn-main .lrow.rowlink .dw-chev { pointer-events: none; }
.dwlearn-main .lrow:hover .ttl a { color: var(--key); text-decoration: none; }
/* .in — the secondary half of a title: a word's meaning, a lesson's group. Set at
   reading weight beside a heading, so the row says two things without becoming two
   rows. */
.dwlearn-main .lrow .ttl .in {
  font-size: var(--fs-small); font-weight: var(--fw-medium); letter-spacing: 0; color: var(--fg-2);
}
/* .note — why this row is here at all. On a search result it carries the sentence
   that made the lesson a hit, which is the difference between a list you trust and
   one you have to take on faith. */
.dwlearn-main .lrow .note {
  grid-column: 2; font-size: var(--fs-small); color: var(--fg-3); margin: 4px 0 0; text-wrap: pretty;
}
/* the ordinal gutter is dropped where ordinals mean nothing — search hits and
   examples are instances, not a sequence */
.dwlearn-main .idx.flush .lrow { grid-template-columns: 1fr; }
.dwlearn-main .idx.flush .lrow .note { grid-column: 1; }
/* A group row is a LINK, not a disclosure. Opening one in place cost a click to open plus a
   click to pick — exactly what going straight to the group's page costs — and bought a second
   concept for it. The chevron points the way rather than turning. */
.dwlearn-main .lrow.rowlink { grid-template-columns: var(--l-num) 1fr auto; cursor: pointer; }
.dwlearn-main .lrow.rowlink .dw-chev {
  grid-column: 3; grid-row: 1 / span 2; align-self: center; margin-left: var(--l-2);
}
@media (max-width: 520px) {
  .dwlearn-main { --l-num: 28px; }
  .dwlearn-main .grp .ttl,
  .dwlearn-main .lrow .ttl { font-size: var(--fs-subhead); }
}

/* ---- deck · term ↔ meaning ----------------------------------------------------
   Two columns, because a term and its meaning are two comparable things and the
   eye pairs them by position. That is also what makes the flip work: hiding one
   column leaves the row's shape intact, so the list becomes flashcards rather
   than collapsing.
   visibility, not display — the gloss keeps its space, so nothing moves when a
   row is revealed and the reader's place on the page is never lost. */
.dwlearn-main .deck { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--line); }
.dwlearn-main .deck li {
  display: grid; grid-template-columns: var(--l-num) minmax(0, 1fr) minmax(0, 1fr);
  align-items: baseline; gap: 2px var(--l-3);
  padding: 11px 0; border-bottom: 1px solid var(--line);
}
/* Same primitive, same gutter. The deck's copy had drifted from .lrow's in two
   of five declarations before either pointed at a primitive — one definition
   ends that. */
.dwlearn-main .deck { --lp-ord-slot: var(--l-num); }
.dwlearn-main .deck .term {
  font-size: var(--fs-subhead); font-weight: var(--fw-semibold); letter-spacing: -0.012em; color: var(--fg);
}
.dwlearn-main .deck .gloss { font-size: var(--fs-small); color: var(--fg-2); }
/* a grammatical label, set back from the word it describes — the same uppercase micro type as
   every other label on these pages, at the primitive's tracking */
.dwlearn-main .pos {
  font-size: var(--fs-micro); font-weight: var(--fw-semibold); letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--fg-3);
}
.dwlearn-main .deck.is-hidden li { cursor: pointer; }
.dwlearn-main .deck.is-hidden .gloss { visibility: hidden; }
.dwlearn-main .deck.is-hidden li.is-shown .gloss { visibility: visible; }
@media (max-width: 620px) {
  .dwlearn-main .deck li { grid-template-columns: var(--l-num) minmax(0, 1fr); }
  .dwlearn-main .deck .gloss { grid-column: 2; }
}

/* ---- entry · the one way INTO a course or group ------------------------------ */
.dwlearn-main .entry {
  display: flex; align-items: center; gap: var(--l-3);
  border: 1px solid var(--line); background: var(--bg-2);
  padding: 14px 16px; margin: 0 0 var(--l-4);
}
.dwlearn-main .entry .body { min-width: 0; }
.dwlearn-main .entry .eyebrow { color: var(--key); font: inherit; }
.dwlearn-main .entry .ttl {
  display: block; font-size: var(--fs-subhead); font-weight: var(--fw-bold); letter-spacing: -0.02em;
  line-height: var(--lh-snug); margin-top: 4px; color: var(--fg);
}
.dwlearn-main .entry .btn { margin-left: auto; flex: none; }
.dwlearn-main .entry .btn .arw { display: none; }
.dwlearn-main .entry.after { margin: var(--l-4) 0 0; }

/* On a phone the entry card stays a ROW and the button shrinks to its arrow. Stacking it made a
   full-width red block out of a word the eyebrow two lines above had already said, which is a
   great deal of screen for no new information. The label is still there for a screen reader. */
@media (max-width: 560px) {
  .dwlearn-main .entry { gap: var(--l-2); }
  .dwlearn-main .entry .btn { width: 44px; height: 44px; padding: 0; font-size: var(--fs-subhead); }
  .dwlearn-main .entry .btn .lbl { display: none; }
  .dwlearn-main .entry .btn .arw { display: inline; }
}

/* ---- dwlearn-essay · the offer above an English essay ----------------------
   THE ONE BLOCK THAT RENDERS OUTSIDE A LEARN SURFACE, and therefore the one whose selectors are
   not scoped under .dwlearn-main. It is the mirror of `.entry.to-text` on the lesson — the same
   one-column box, pointing the other way — and it is written out longhand here because the
   primitive it copies lives behind that scope and cannot reach an essay page.

   It sits ABOVE the text: a reader who cannot read the piece finds that out in the first
   sentence, not the last, and an offer at the bottom is one they reach by giving up. */
.dwlearn-essay {
  /* the site's sans, not the essay's serif: this is an offer ABOUT the text, not more of it */
  font-family: var(--font-sans, system-ui, sans-serif);
  display: block;
  margin: 0 0 var(--l-4);
  padding: 14px 16px;
  border: 1px solid var(--rule);
  background: var(--bg-2, transparent);
}
/* THE BOX SHIPS `hidden` AND A SCRIPT REVEALS IT FOR A GERMAN BROWSER, so `display` above is an
   author declaration that the UA's own `[hidden]` rule has to beat — and it only beats it on an
   engine that writes that rule `!important`. Chromium does; the HTML standard prints it without,
   precisely so an author can override it, which is exactly what the line above would otherwise be
   doing. Left to the UA, whether an English reader meets a German offer is a question about their
   browser. Re-asserted here the way `.trans`, `.lit`, `.tick` and `.aside` already do it on this
   surface — the same rule, and the reason it is the rule. */
.dwlearn-essay[hidden] { display: none; }
/* The essay's prose margins reach in here — `.entry-content p:not(.lp-eyebrow)` puts 20px under
   every paragraph, which inside a box is three gaps where the box wanted one.
   `:not()` LENDS ITS ARGUMENT'S SPECIFICITY, so that rule counts two classes and an element, and
   `.entry-content .dwlearn-essay p` merely TIED with it — a tie decided by which file loads last.
   The element selector on the aside breaks it honestly, without !important. */
/* HIDDEN MEANS HIDDEN. The offer renders with the `hidden` attribute and is revealed by script
   only for a German browser, which relies on the user-agent's `[hidden] { display: none }` — and
   any rule here that gives `.dwlearn-essay` a display would silently outrank it and show the box
   to every reader on earth. Stating it in our own sheet costs one line and removes the trap. */
.dwlearn-essay[hidden] { display: none !important; }
.entry-content aside.dwlearn-essay p,
.dwlearn-essay p { margin: 0; }
/* THE THEME'S EYEBROW carries size, weight, tracking, case and colour. All this says is that it
   sits flush at the top of the box — a fact about this box, not about eyebrows. */
.entry-content aside.dwlearn-essay .lp-eyebrow,
.dwlearn-essay .lp-eyebrow { display: block; margin: 0; }
/* THE THREE UNITS SIT CLOSE. They are one thought — what this is, what it gives you, where to
   go — and a paragraph's worth of air between them makes the box read as three announcements. */
.entry-content aside.dwlearn-essay .ttl,
.dwlearn-essay .ttl {
  margin: var(--l-1) 0 0; font-size: var(--fs-small); font-weight: var(--fw-regular);
  line-height: var(--lh-loose); color: var(--ink-soft); text-wrap: pretty;
}
.entry-content aside.dwlearn-essay .forward,
.dwlearn-essay .forward {
  display: inline-flex; margin: var(--l-2) 0 0;
  font-size: var(--fs-small); font-weight: var(--fw-bold); color: var(--rubric);
}
/* A KEY-COLOURED LINK DOES NOT GO BLACK ON HOVER. Ink is the colour of ordinary text, so turning
   the accent into it on hover reads as the link switching off under the cursor — the one moment it
   should feel more live, not less. It deepens instead, to --rubric-2, which is what the theme
   already sets as --bs-link-hover-color for every other link on the site. Written once per rest
   state (the aside's element selector included) so the deepening outranks each of them and lands
   on both sides of the door. */
.entry-content aside.dwlearn-essay .forward:hover,
.dwlearn-essay .forward:hover,
.dwlearn-main .forward:hover { color: var(--rubric-2); text-decoration: none; }
