/* course.css — the learner's stylesheet, and the only place presentation lives.

   Two lineages meet in this file.

   The structure, the accessibility rules and every comment marked WCAG come
   from this project's original baseline: focus outlines that are never
   removed, 44px targets, scroll padding clear of the fixed pager, a skip link
   visible on focus. Those are load-bearing and several were found by a
   browser test rather than by reading. Do not "tidy" them.

   The visual language — the palette, the 10px rem base, Rise's rem values,
   the near-square uppercase buttons — is ported from the `StyleTheme` layer of
   the sibling authoring tool, which mined it from the original Articulate Rise
   stylesheet. Rules carrying it are annotated RISE with the declaration they
   reproduce.

   Every value an author can change is a custom property declared in :root
   below, and every one of them is defined in `exporter/theme.py` with the same
   annotation. A course whose theme differs from the defaults ships a small
   `:root` override in the document head; this file is otherwise identical for
   every course, so it caches across a library.

   The two lineages did not in the end disagree about the palette: every
   default below is Rise's own, and every one of them clears WCAG AA on the
   pairs `theme.check_contrast()` measures. That check runs on every render
   regardless, because the palettes authors type in are the ones that fail.  */

:root{
  /* palette */
  --page-bg:#f5f5f5;      /* RISE: html{background:#f5f5f5} */
  --bg:#ffffff;           /* RISE: blocks-lesson{background:#fff} */
  --nav-bg:#fafafa;       /* RISE: nav-sidebar--light bg */
  --nav-hover:#f3f3f3;    /* RISE: nav-sidebar hover-bg */
  --rule:#e6e6e7;         /* RISE: outline border #e6e6e7 */
  --rule-strong:#cccccc;  /* RISE: #0003 dividers, composited on white */
  --fg:#212121;
  --muted:#6f6f73;        /* RISE: muted UI grey, 5.00:1 on white */
  --accent:#7837a8;       /* RISE: --color-theme */
  --accent-contrast:#ffffff;
  --warn-bg:#fff4e5;
  --warn-br:#8a5300;
  /* typography */
  --font-body:Lato,Roboto,system-ui,-apple-system,"Segoe UI",sans-serif;
  --font-head:Lato,Roboto,system-ui,-apple-system,"Segoe UI",sans-serif;
  --body-size:1.7rem;     /* RISE: block-text{font-size:1.7rem} */
  --head-size:2.8rem;     /* RISE: .fr-view h2{font-size:2.8rem} */
  --block-space:3rem;     /* RISE: block-text{padding-block:3rem} */
  --measure:92rem;    /* RISE: __wrap{max-width:92rem} */
  /* buttons */
  --btn-radius:2px;       /* RISE: --radius-button (near-square) */
  --btn-track:.17rem;     /* RISE: .continue-btn{letter-spacing:.17rem} */
  --btn-transform:uppercase;
  --btn-pad:1.4rem 3rem;
}

*{box-sizing:border-box}

/* FUNCTION: 10px rem base, so every size below can copy Rise's rem values
   verbatim rather than converting them and drifting.
   RISE: html{font-size:62.5%} with antialiased smoothing.
   The scroll padding is unrelated and older: the pager is fixed to the bottom,
   so anything scrolled to the fold lands underneath it. This keeps
   scrollIntoView and browser focus scrolling clear of it — WCAG 2.2 SC 2.4.11
   Focus Not Obscured. Found by a browser test where a checkbox near the fold
   could not be clicked at all. */
html{--rail:28rem;   /* RISE: nav sidebar 280px */
     font-size:62.5%;-webkit-font-smoothing:antialiased;
     -moz-osx-font-smoothing:grayscale;
     scroll-padding-bottom:7rem;scroll-padding-top:1rem}

/* RISE: body{line-height:1.5} is the dominant value in the package. */
body{margin:0;font-family:var(--font-body);font-size:var(--body-size);
     line-height:1.5;color:var(--fg);background:var(--page-bg)}

/* FUNCTION: the content column, on its own surface above the page canvas.
   RISE: blocks-lesson — white column, page grey behind it. */
main{max-width:var(--measure);margin:0 auto;padding:2.4rem 6rem 8rem;
     background:var(--bg);width:100%}
main:focus{outline:none}

/* FUNCTION: Rise's two-width layout. The wrap above is generous (92rem) so a
   large screen is not a narrow ribbon in a field of grey; prose is then inset
   inside it so the line length still reads. Measured before this existed: the
   column was a flat 620px at 768, 1280 and 1920 alike, leaving 650px of dead
   space each side on a desktop.
   RISE: __wrap{max-width:92rem;margin-inline:auto} with block content inset
   8.3333% — one twelfth of the grid, the signature Rise text measure.
   Everything is inset by default and media opts out, which is the order Rise
   uses (.rb{margin-inline:8.3333%} then .rb-image-hero{margin-inline:0}); an
   opt-in list would silently miss every block type added later. */
[data-lesson] > *{margin-inline:8.3333%}
/* Media and data want the full wrap: insetting them crops the thing being
   looked at, and a table inset twice is a table that scrolls for no reason. */
[data-lesson] > .b-image,[data-lesson] > .b-media,[data-lesson] > .b-lg,
[data-lesson] > .b-table,[data-lesson] > .b-cards{margin-inline:0}
/* RISE: container--custom-width-med{max-width:76rem;margin-inline:auto} —
   the quiz card is narrower than the wrap and centred, not inset. */
[data-lesson] > .b-kc{max-width:76rem;margin-inline:auto}

/* Skip link is visible on focus — a hidden-forever skip link helps nobody. */
.skip{position:absolute;left:-9999px}
.skip:focus{left:0;top:0;padding:.75rem 1rem;background:var(--accent);
            color:var(--accent-contrast);z-index:10}

h1,h2,h3{font-family:var(--font-head);line-height:1.25}
h1{font-size:var(--head-size);margin:0 0 var(--block-space)}
/* FUNCTION: the lesson heading takes focus but does not advertise it.
   runtime.js focuses the new <h1> on every lesson change, so a screen reader
   announces the lesson instead of the page silently swapping underneath. That
   focus move is load-bearing and stays. Drawing a ring on it is not: the
   heading carries tabindex="-1", so it is never tabbed to and never operated —
   the ring appeared unprompted around the title the moment a lesson opened.
   This is not the "never remove focus outlines" rule being bent. That rule is
   about controls a keyboard user acts on; `main:focus{outline:none}` above is
   the same call for the same reason, the skip link's own target. Every
   genuinely interactive element still matches :focus-visible below. */
h1[tabindex="-1"]:focus{outline:none}
h2{font-size:2.2rem;margin:var(--block-space) 0 1rem}
h3{font-size:1.9rem;margin:2rem 0 .8rem}
p{margin:0 0 1.6rem}

img{max-width:100%;height:auto}
figure{margin:var(--block-space) 0}
figcaption{color:var(--muted);font-size:1.4rem;margin-top:.8rem}
a{color:var(--accent)}

/* Never remove focus outlines. */
:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

/* FUNCTION: the persistent lesson rail, and the page grid that holds it.
   A Rise course spends its screen on a fixed 280px sidebar *plus* the 92rem
   content wrap — about 1200px in use. This project replaced the sidebar with a
   list at the top of the page, which is why a 1920px monitor showed a 920px
   column adrift in grey: the wrap was right, the layout around it was missing.
   The markup did not have to change for this. The lesson <nav> was already a
   sibling of <main> rather than inside it, so a two-column grid on <body> is
   the whole change; `unrender` reads <main> and the config JSON and never
   looks at the nav, so the round trip is untouched.
   RISE: nav-sidebar--light surface, hairline border on the trailing edge. */
body{display:grid;grid-template-columns:var(--rail) 1fr;align-items:start}
/* FUNCTION: place the rail and the content explicitly, and give anything else
   a full-width row of its own.
   REGRESSION: this first relied on auto-placement, on the reasoning that the
   skip link is `position:absolute` and `<script>` is `display:none`, so the
   rail and `<main>` were the only children taking a cell. That is true of an
   exported package and false of the admin preview, which injects a banner
   `<aside>` straight after `<body>`. One extra in-flow child shifted every
   cell along: the nav moved to column 2 and `<main>` landed in column 1, so
   the lesson rendered inside the sidebar. The export was unaffected, which is
   exactly why no test caught it. Never assume the child list. */
body > *{grid-column:1 / -1}
.lessons{grid-column:1}
main{grid-column:2}
/* `height`, not `max-height`: the grid row is start-aligned so the rail would
   otherwise be only as tall as its list, leaving the surface and its hairline
   stopping partway down the page. A full-viewport rail with its own scroll is
   also what a course with thirty lessons needs. */
.lessons{position:sticky;top:0;height:100vh;overflow-y:auto;
         background:var(--nav-bg);border-right:1px solid var(--rule)}
/* No list marker. Two reasons, and either alone would be enough: the decimal
   sat *above* each title rather than beside it, because the marker box and an
   inline-block link cannot share 28rem of rail; and the titles a real course
   carries already begin "Lesson 1 —", so the marker numbered every entry
   twice. It stays an <ol>, which is where the ordering actually belongs. */
.toc{margin:0;padding:1.6rem 1.2rem;list-style:none}
.toc li+li{margin-top:.2rem}
.toc a{color:var(--fg);text-decoration:none;display:block;
       padding:.8rem 1.2rem;border-radius:var(--btn-radius)}
.toc a:hover{background:var(--nav-hover)}
.toc a[aria-disabled="true"]{color:var(--muted);pointer-events:none}

.b-table{border-collapse:collapse;width:100%;margin:var(--block-space) 0}
.b-table caption{text-align:left;font-weight:700;font-family:var(--font-head);
                 font-size:1.8rem;padding-bottom:1.2rem;line-height:1.4}
/* 0.8rem is 8px, which read as cramped against 17px copy at a 1.5 line
   height — the text touched the cell edge on every side. Rise's block rhythm
   is 1.6rem/2rem; this is the cell-scale step down from it. */
.b-table th,.b-table td{border:1px solid var(--rule);padding:1.2rem 1.6rem;
                        text-align:left;vertical-align:top;line-height:1.5}
.b-table th{background:var(--nav-bg)}

.b-note{border-left:4px solid var(--warn-br);background:var(--warn-bg);
        padding:1.2rem 1.6rem;margin:var(--block-space) 0}
.b-note__label{font-weight:700;margin:0 0 .25rem}

/* FUNCTION: a divided list of disclosures, not boxed cards.
   The element stays a native <details>/<summary> — the accessibility note in
   CLAUDE.md is about semantics, and none of this touches them. What changes is
   the marker: the platform triangle is larger and heavier than Rise's, and it
   sits hard against the text. `list-style:none` suppresses it in modern
   engines and the -webkit rule covers older WebKit; the +/− is drawn in the
   trailing corner instead, muted rather than accent-coloured so it reads as a
   control and not as content.
   RISE: blocks-accordion__item{border-style:none none solid;border-width:.1rem}
   with header text 1.8rem/700/1.4 in the head face and a #00000080 glyph. */
.b-accordion__item{border-bottom:1px solid var(--rule-strong)}
.b-accordion summary{padding:2rem 0;cursor:pointer;
                     font-family:var(--font-head);font-weight:700;
                     font-size:1.8rem;line-height:1.4;
                     display:flex;justify-content:space-between;
                     align-items:center;gap:1.6rem;list-style:none}
.b-accordion summary::-webkit-details-marker{display:none}
.b-accordion summary::after{content:"+";color:var(--muted);font-size:2.4rem;
                            font-weight:400;line-height:1;flex:0 0 auto}
.b-accordion__item[open] > summary::after{content:"\2212"}
/* Rise has no hover state on an accordion header at all. A full-width grey
   wash behind the whole row — which is what was here — is the thing that made
   it read as a plain list of buttons rather than a Rise accordion. The
   affordance is kept, moved onto the glyph, which is the part that acts. */
.b-accordion summary:hover::after{color:var(--accent)}
/* RISE: blocks-accordion body sits under the header with its own bottom gap. */
.b-accordion__item > div{padding-bottom:2rem}

[role=tablist]{display:flex;flex-wrap:wrap;gap:.25rem;
               border-bottom:2px solid var(--rule)}
[role=tab]{padding:.8rem 1.6rem;border:0;background:none;font:inherit;
           cursor:pointer;border-bottom:3px solid transparent}
[role=tab][aria-selected=true]{border-bottom-color:var(--accent);font-weight:600}
[role=tabpanel]{padding:1.6rem 0}

/* FUNCTION: Rise's flashcard — a 3D flip, front white, back in the theme
   colour. Both faces are in the DOM and absolutely positioned on top of one
   another inside a rotating wrapper; `backface-visibility` keeps the far side
   from painting through.
   That alone would be an accessibility regression. The previous disclosure put
   `hidden` on the back face, which took it out of the accessibility tree for
   free; here both faces live inside one button and a screen reader would read
   them as a single run-on label. `visibility` is the property that hides a
   face from assistive technology *and* the eye, so it carries the exposure —
   delayed to the half-way point of the rotation so the outgoing face does not
   vanish before the card has turned. Under prefers-reduced-motion the global
   rule below drops the transition and the swap is simply instant.
   RISE: .rb-flashcard{perspective:1000px;height:20rem};
   .rb-fc-back{background:var(--color-theme);transform:rotateY(180deg)}. */
.b-cards{display:grid;gap:1.6rem;
         grid-template-columns:repeat(auto-fill,minmax(22rem,1fr))}
.b-card{perspective:1000px}
/* Square, not a fixed height. The grid tracks are flexible (1fr above a
   22rem floor), so a fixed height made every card a different shape depending
   on how many fitted the row. aspect-ratio ties the height to whatever width
   the track resolves to; min-height is the fallback for engines without it,
   which would otherwise collapse the card to nothing — the faces inside are
   absolutely positioned and contribute no height. */
.b-card__btn{display:block;width:100%;aspect-ratio:1;min-height:20rem;padding:0;
             font:inherit;color:inherit;background:none;border:0;cursor:pointer}
.b-card__inner{position:relative;display:block;width:100%;height:100%;
               transform-style:preserve-3d;transition:transform .5s}
.b-card__btn[aria-expanded="true"] .b-card__inner{transform:rotateY(180deg)}
.b-card__face{position:absolute;inset:0;overflow:auto;
              display:flex;align-items:center;justify-content:center;
              text-align:center;padding:1.6rem;
              backface-visibility:hidden;-webkit-backface-visibility:hidden;
              border-radius:var(--btn-radius);
              /* RISE: a 0.3rem accent rule on the leading edge. */
              border:1px solid var(--rule);
              border-block-start:.3rem solid var(--accent);
              visibility:hidden;transition:visibility 0s linear .25s}
/* The front is a single term or prompt on a large surface, so it carries the
   head face at heading weight rather than body copy. The back is an
   explanation and stays at body size. */
.b-card__front{background:var(--bg);font-family:var(--font-head);
               font-weight:700;font-size:2.2rem;line-height:1.3}
.b-card__back{background:var(--accent);color:var(--accent-contrast);
              border-color:var(--accent);transform:rotateY(180deg)}
.b-card__btn[aria-expanded="false"] .b-card__front,
.b-card__btn[aria-expanded="true"] .b-card__back{visibility:visible}

.b-timeline{padding-left:2.4rem}

/* FUNCTION: Rise's numbered step — a filled accent disc beside the step body.
   A list marker cannot be a disc: ::marker takes font and colour but no
   background or border-radius. So the marker is removed and the number drawn
   as a counter in ::before, which costs the list role in Safari with
   VoiceOver — hence the explicit role="list" that render.py now writes. That
   attribute and this rule are a pair; removing either alone breaks the block
   for exactly one audience and nobody else notices.
   Two columns rather than flex because the step body is not wrapped: the
   <h3>, the paragraphs and any image are siblings, so they are placed into
   column 2 individually and stack as rows.
   RISE: .rb-step-num{flex:0 0 3.2rem;height:3.2rem;border-radius:50%;
   background:var(--color-theme);font-weight:700;font-size:1.5rem}. */
.b-process{list-style:none;padding-left:0;counter-reset:b-step}
.b-step{counter-increment:b-step;
        display:grid;grid-template-columns:3.2rem 1fr;column-gap:1.6rem}
.b-step > *{grid-column:2;min-width:0}
.b-step::before{content:counter(b-step);grid-column:1;grid-row:1;
                width:3.2rem;height:3.2rem;border-radius:50%;
                background:var(--accent);color:var(--accent-contrast);
                display:flex;align-items:center;justify-content:center;
                font-family:var(--font-head);font-weight:700;font-size:1.5rem;
                line-height:1}
/* The heading sits beside the disc, so it must not carry its usual top gap. */
.b-step > h3:first-of-type{margin-top:0}
.b-step,.b-event{margin-bottom:var(--block-space)}
.b-event__marker{font-weight:700;color:var(--accent);margin:0}

/* RISE: block-divider{--divider-color:#0003} — a hairline, not a heavy rule. */
hr,.b-divider{border:0;border-top:1px solid var(--rule-strong);
              margin:var(--block-space) 0}

.b-lg__stage{position:relative;display:inline-block;max-width:100%}
.b-lg__marker{position:absolute;transform:translate(-50%,-50%);
              width:3.2rem;height:3.2rem;border-radius:50%;
              border:2px solid var(--accent-contrast);background:var(--accent);
              color:var(--accent-contrast);font-weight:700;cursor:pointer}
.b-lg__list{margin-top:1.6rem}

.b-kc{border:1px solid var(--rule);border-radius:var(--btn-radius);
      padding:1.6rem;margin:var(--block-space) 0}
.q{border:0;padding:0;margin:0 0 var(--block-space)}
.q legend{font-weight:600;padding:0}
/* The label sat flush against its input with no gap at every width. */
.q-label{display:block;margin-bottom:.5rem}
/* FUNCTION: the fill-in field, styled and on its own line.
   Same platform-default problem as the matching <select> below, plus a layout
   bug it was hiding: the input and the Check answer button are both inline, so
   they shared a line and the button sat over the end of the field. Making the
   field a block puts the button beneath it, which is also where every other
   question kind has it.
   RISE: quiz text inputs are bordered, full width, body-size. */
.q input[type=text]{display:block;width:100%;font:inherit;font-size:1.5rem;
                    padding:1rem;min-height:44px;
                    color:var(--fg);background:var(--bg);
                    border:1px solid var(--rule);border-radius:var(--btn-radius)}
.q input[type=text]:hover{border-color:var(--accent)}
/* RISE: .rb-submit{margin-top:1.6rem} — the button is never beside a field. */
.q-submit{display:block;margin-top:1.6rem}
.q-opt{margin:.8rem 0;display:flex;gap:.75rem;align-items:flex-start;
       padding:.4rem;border-radius:var(--btn-radius)}
.q-opt:hover{background:var(--nav-hover)}
/* Targets meet the 24x24 minimum for pointer inputs (WCAG 2.5.8). */
.q-opt input{min-width:24px;min-height:24px;margin-top:.15rem}
/* Belt and braces: individual interactive targets keep their own clearance
   even inside nested scroll containers. */
.q-opt,.q-match,.q-submit,.b-card__btn,[role=tab],
.q input[type=text]{scroll-margin-bottom:7rem}
.q-match{display:flex;gap:.75rem;align-items:center;margin:.8rem 0;
         flex-wrap:wrap}
.q-match label{flex:1 1 12rem;min-width:0}
/* FUNCTION: bring the matching control into the document.
   Left alone, a <select> renders in the platform default — measured at 13.3px
   Arial in a 19px-tall box, inside a page set in 17px Lato, which is what made
   matching questions look unfinished next to every other block. The height is
   not only cosmetic: 19px fails the 24x24 pointer target minimum the radio
   inputs below were given explicitly (WCAG 2.5.8), so the control the learner
   has to hit was the smallest thing on the page.
   RISE: matching pairs a left prompt with a bordered control at UI size. */
.q-match select{flex:1 1 16rem;min-width:0;max-width:100%;
                font:inherit;font-size:1.5rem;
                padding:1rem;min-height:44px;
                color:var(--fg);background:var(--bg);
                border:1px solid var(--rule);border-radius:var(--btn-radius)}
.q-match select:hover{border-color:var(--accent)}

/* FUNCTION: the Rise button signature — near-square, tracked, uppercase —
   carried onto the two buttons this runtime actually has. The 44px minimum
   height and the never-removed focus ring are ours and outrank it.
   The label is 1.5rem/700 as Rise's is, not the 17px body size at weight 400
   it inherited before — that was the whole of "the font looks weak". --btn-pad
   stays below Rise's 2rem block padding: at the smaller label size the button
   already clears 44px, and the shorter bar reads better against a block.
   RISE: .continue-btn{letter-spacing:.17rem;text-transform:uppercase}. */
.q-submit,.pager button{font:inherit;font-family:var(--font-head);
                        font-size:1.5rem;font-weight:700;line-height:1.5;
                        padding:var(--btn-pad);min-height:44px;
                        letter-spacing:var(--btn-track);
                        text-transform:var(--btn-transform);
                        text-align:center;
                        border:1px solid var(--accent);background:var(--accent);
                        color:var(--accent-contrast);
                        border-radius:var(--btn-radius);cursor:pointer}
.q-submit:hover,.pager button:not([disabled]):hover{filter:brightness(1.08)}
/* RISE: .continue-btn{width:100%} — the in-lesson button is a full-width bar,
   which is why a shrink-to-fit one sat oddly left-aligned against the block
   above it. The pager's Previous/Next are the documented exception: Rise pairs
   those at their natural width (.sc-navbtns .rb-btn{width:auto}). */
.q-submit{width:100%}
.q-submit[disabled],.pager button[disabled]{opacity:.5;cursor:not-allowed}
.q-feedback{margin-top:.75rem}
.q-feedback:empty{display:none}

/* FUNCTION: the persistent lesson pager.
   `sticky` was tried here and reverted. A bar that stays visible necessarily
   overlays the fold while you scroll — measured, sticky covered exactly as
   many controls mid-scroll as fixed did — and it additionally un-pins itself
   on a document shorter than the viewport, which is worse. What makes the bar
   safe is not its positioning but the two rules that surround it: `main`
   reserves 8rem of bottom padding so the last control can always be scrolled
   clear of it, and `scroll-padding-bottom` on `html` keeps programmatic and
   focus scrolling above it (WCAG 2.2 SC 2.4.11). Both are tested. */
.pager{position:fixed;bottom:0;left:var(--rail);right:0;display:flex;gap:1rem;
       align-items:center;justify-content:space-between;padding:.75rem 1rem;
       background:var(--nav-bg);border-top:1px solid var(--rule)}
.pager__status{color:var(--muted);font-size:1.4rem}

/* FUNCTION: below the phone breakpoint the inset is the whole screen, so it
   collapses and the wrap padding drops with it.
   RISE: the 8.333% text inset collapses on small screens; wrap padding-inline
   falls to 2rem. */
/* FUNCTION: the rail collapses back to a list at the top of the page.
   This happens earlier than the text breakpoint below, and deliberately: the
   rail is a fixed 28rem, so at 768px it takes more than a third of the screen
   and leaves prose at 307px — narrower than the same course on a phone. It is
   only worth its width once there is enough left over for the full wrap. */
@media (max-width:1024px){
  body{grid-template-columns:1fr}
  /* Collapsing the track list is not enough on its own: the explicit
     `main{grid-column:2}` above would otherwise create an *implicit* second
     column and keep the lesson beside the rail on a phone. */
  .lessons,main{grid-column:1 / -1}
  .lessons{position:static;height:auto;overflow:visible;
           border-right:0;border-bottom:1px solid var(--rule)}
  .pager{left:0}
}

@media (max-width:760px){
  main{padding:2.4rem 2rem 8rem}
  [data-lesson] > *{margin-inline:0}
  [data-lesson] > .b-kc{margin-inline:0}
  /* Prompt above control rather than beside it: side by side, the pair needs
     28rem and a 320px phone has 28rem of content box minus the gap. */
  .q-match{flex-direction:column;align-items:stretch;gap:.4rem}
  /* flex-basis is the main axis, so the 16rem that sets the control's width in
     a row becomes a 160px-tall select once the row turns into a column. */
  .q-match label,.q-match select{flex:0 0 auto}
}

/* FUNCTION: print a flip card flat — front, then back beneath it, joined like
   a domino. On screen a card shows one face and the learner turns it; on paper
   there is nothing to turn, and a printed set of prompts with the answers
   omitted is not a study aid. Both faces are already in the DOM, so this is
   only a matter of undoing the 3D: no perspective, no rotation, static
   positioning so the faces stack in flow, and visibility restored on both.
   The back drops its filled accent panel — a page of solid theme colour is
   not a kindness to a printer — and keeps a dashed rule as the domino line.
   The transform override is specificity, not !important: it has to outrank
   .b-card__btn[aria-expanded="true"] .b-card__inner, which is still matching
   on whichever cards the learner happened to leave flipped. */
@media print{
  .b-card{perspective:none;break-inside:avoid;page-break-inside:avoid}
  .b-card__btn{height:auto;min-height:0;aspect-ratio:auto;cursor:default}
  .b-card__btn[aria-expanded] .b-card__inner{transform:none;height:auto;
                                             transition:none}
  /* transition:none is load-bearing, not tidiness. The face carries
     `transition:visibility 0s linear .25s` so the outgoing side does not
     vanish mid-rotation on screen; that delay does not stop applying in print,
     so a face whose state changes as the print stylesheet takes effect is
     still reporting its old visibility when the page is captured. */
  .b-card__face{position:static;visibility:visible;transform:none;
                transition:none;
                backface-visibility:visible;-webkit-backface-visibility:visible;
                display:block;text-align:left;overflow:visible;
                border-radius:0}
  .b-card__front{border-bottom:0}
  .b-card__back{background:none;color:var(--fg);
                border:1px solid var(--rule-strong);
                border-block-start:1px dashed var(--rule-strong)}
  /* The fixed pager prints on top of the first page and says nothing useful
     on paper; the rail is navigation for a document you cannot navigate. */
  .pager,.lessons{display:none}
  body{display:block}
  main{max-width:none;padding:0}
  [data-lesson] > *{margin-inline:0}
}

@media (prefers-reduced-motion:reduce){*{scroll-behavior:auto!important;
       animation:none!important;transition:none!important}}
