/* ============================================================
   Pure Math Lab — shared layout fixes for the free library
   Added 2026-08-21 (phone / iPad usability audit).

   Loaded LAST on every /learn page so it can correct the
   per-page inline styles without editing 300 files by hand.
   Nothing depends on it structurally — deleting the file and
   the <link> tags restores the previous behaviour exactly.
   ============================================================ */

/* ---- 1. Long display equations ------------------------------
   A wide \[ ... \] block used to be cut off by any parent with
   overflow:hidden (the "Answer + working" mark-scheme panels)
   or push the whole page sideways on a phone. It now scrolls
   inside its own box and the rest of the page stays put. */
mjx-container[display="true"]{
  max-width:100%;
  overflow-x:auto;
  padding-bottom:2px;
  overscroll-behavior-x:contain;
  scrollbar-width:thin;
  -webkit-overflow-scrolling:touch;
}
mjx-container[display="true"]::-webkit-scrollbar{height:4px;}
mjx-container[display="true"]::-webkit-scrollbar-thumb{
  background:rgba(15,29,58,.22);border-radius:4px;}

/* ---- 2. Wide tables -----------------------------------------
   Data tables inside a question stem were wider than the phone
   and dragged the whole document sideways. They now get their
   own horizontal scroller; narrow tables are unaffected because
   min-width keeps them at full container width. */
@media (max-width:900px){
  table{
    display:block !important;
    width:max-content;
    min-width:100%;
    max-width:100%;
    overflow-x:auto !important;
    -webkit-overflow-scrolling:touch;
  }
}

/* ---- The 4-7px phantom scrollbar on question boxes (2026-09-07)
   The rule above gives .stem / .part overflow-x:auto so a very wide
   maths run scrolls instead of dragging the page. That makes the
   VERTICAL axis auto too, and MathJax's inline SVG hangs a few px
   past the last line box, so every question box grew a scroll thumb
   with 4-7px of travel — measured on every pack and paper. Absorb the
   overhang instead of clipping it: overflow-y must stay auto so tall
   inline maths is never shaved off. */
@media (max-width:900px){
  .part, .step, .stem, .mock-q p, .mock-q>p, .ladwrap p, .example .step, .q p{
    padding-bottom:13px;
  }
}

/* ---- 3. Room under the floating buttons ---------------------
   The fixed Session / Whiteboard / Book-a-call pills sat on top
   of the last answer row and the final CTA at the foot of the
   page. Give the page enough tail that nothing ends underneath. */
@media (max-width:900px){
  .wrap, main{ padding-bottom:120px !important; }
  body:not(:has(.wrap)):not(:has(main)){ padding-bottom:110px; }
}

/* ---- 4. Exam-board strip ------------------------------------
   "· pick yours to see what applies to you" was ellipsed away on
   a phone. Let it wrap to a second line instead.
   (!important because _igcse-board.js injects its own <style>
   after this file.) */
@media (max-width:620px){
  .tbmin{ align-items:flex-start !important; }
  .tbmin-t{
    white-space:normal !important;
    overflow:visible !important;
    text-overflow:clip !important;
    line-height:1.35 !important;
  }
}

/* ---- 5. Thai vowels and descenders --------------------------
   Question boxes on Teach Mode set overflow-y:hidden so they can
   scroll sideways; that shaved the top off Thai vowel marks and
   the tails off g / y / ฏ / ฐ, and cut the top of tall integrals.
   Letting the vertical axis fall back to auto keeps every glyph
   reachable without changing any spacing. */
.qtext, .exq, .fbody, .sbody, .fb, .why, .exone .exq, .mathrow>div{
  overflow-y:auto;
  overscroll-behavior:contain;
}

/* ---- 6. Tap targets on a phone ------------------------------ */
@media (max-width:620px){
  .mpbtn{ min-height:34px; }
  .smbtn{ min-height:34px; }
  .fx-close{ min-width:34px; min-height:34px; }
  .crumb{ display:inline-block; padding:6px 0; }
}

/* ---- 7. Long inline equations -------------------------------
   Some worked-solution lines carry a very long \( ... \) run that
   is wider than a phone, which used to drag the whole document
   sideways. The line itself now scrolls, the page does not.
   Only the horizontal axis is named, so the vertical axis falls
   back to auto and tall inline maths (integrals, stacked
   fractions) is never shaved off. */
@media (max-width:900px){
  .part, .step, .stem, .mock-q p, .mock-q>p, .ladwrap p, .example .step, .q p{
    overflow-x:auto;
    -webkit-overflow-scrolling:touch;
    overscroll-behavior:contain;
  }
}

/* ---- 8. Mark-scheme panels ----------------------------------
   "Answer + working" uses overflow:hidden to animate open, which
   also cut the right-hand end off every wide line of working —
   up to 200px of the solution was unreachable on a phone. Once
   the panel is open, let it scroll sideways instead. */
.ms.open{
  overflow:auto;
  overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch;
}

/* ---- 9. "there is more to the right" hint -------------------
   _pml-fix.js adds .pml-xscroll to any box that really does
   scroll sideways. Without a hint a wide line of working just
   looks cut off and no one thinks to swipe it. The inset shadow
   sits on the border box, so it works over any background. */
.pml-xscroll{
  box-shadow: inset -16px 0 13px -13px rgba(15,29,58,.34);
}
.ms.pml-xscroll, .q p.pml-xscroll, .part.pml-xscroll, .step.pml-xscroll, .stem.pml-xscroll{
  padding-right:10px;
}

/* ---- 10. Toolkit grid ---------------------------------------
   A long unbreakable formula inside one "toolkit" card forced its
   grid track wider than the track it was given, which pushed the
   whole page sideways on an iPad. Let the cards shrink and scroll
   their own content instead. */
.tools{ grid-template-columns:repeat(auto-fill,minmax(min(240px,100%),1fr)) !important; }
.tools > .tool{ min-width:0; overflow-x:auto; }


/* ============================================================
   Round 2 — 2026-08-21. The items peat signed off after the
   first audit pass. Each block says which one it is.
   ============================================================ */

/* ---- (A) Whiteboard toolbar on a phone -----------------------
   The bar wrapped onto six rows and covered 235px — 28% of an
   iPhone screen — right where the lesson text sits. One row that
   swipes sideways instead; the ⤢ button at the end brings the
   old stacked layout back for anyone who wants every tool at
   once. Tablets and desktops are untouched. */
@media (max-width:700px){
  #wbBar:not(.pml-wb-tall){
    flex-wrap:nowrap !important;
    overflow-x:auto;
    overflow-y:hidden;
    overscroll-behavior-x:contain;
    -webkit-overflow-scrolling:touch;
    scrollbar-width:none;
  }
  #wbBar:not(.pml-wb-tall)::-webkit-scrollbar{display:none;}
  #wbBar:not(.pml-wb-tall) > *{flex:0 0 auto;}
  #pmlWbMore{
    position:sticky; right:0; margin-left:auto;
    background:rgba(15,29,58,.97) !important;
    box-shadow:-10px 0 12px -6px rgba(15,29,58,.97);
  }
}
@media (min-width:701px){ #pmlWbMore{display:none !important;} }

/* ---- (C) Floating book-a-call pill ----------------------------
   Three floating pills at once on a phone was one too many. The
   booking link now lives in the top-nav menu instead; the two
   study tools keep the corner. */
@media (max-width:620px){
  .pml-cta-fab, .pml-cta-pop{ display:none !important; }
}

/* ---- (D) Sticky top bar --------------------------------------
   It was 93% opaque, so text scrolling underneath showed through
   and read like a printing fault. */
.pml-topnav{ background:#fff !important; }

/* ---- (E) Name gate on Teach Mode ------------------------------
   The whiteboard button and the maths keypad were stacked above
   the "what's your name?" card, so they stayed sharp and tappable
   over a dimmed page. */
#pmlNameGate{ z-index:100060 !important; }
body:has(#pmlNameGate) #wbFab,
body:has(#pmlNameGate) #pmlTrackFab,
body:has(#pmlNameGate) #pmlPad,
body:has(#pmlNameGate) #pmlFsBtn,
body:has(#pmlNameGate) #pmlFsWrap,
body:has(#pmlNameGate) .pml-cta-fab{ display:none !important; }

/* ---- (F) Teacher assign form ----------------------------------
   Three fields shared one row on a phone, so the dropdown text
   was elided mid-word. One field per row below 620px. */
@media (max-width:620px){
  .row > div{ flex:1 1 100% !important; min-width:0; }
}

/* ---- (G) Reasoning text under the progress strip -------------
   Teach Mode pins a progress strip to the bottom of the window.
   scrollIntoView() knows nothing about it, so after a correct
   answer the browser stopped scrolling the moment the "Why this
   works" box reached the bottom edge, and the last lines of the
   explanation stayed under the strip. scroll-padding-bottom
   reserves that strip for every programmatic scroll on the page.
   The second rule gives the same clearance at the very end of a
   page that is already scrolling, so nothing sits flush against
   the strip. Both are inert on a page with no bottom bar. */
html{ scroll-padding-bottom:96px; }
body.overflowy .wrap{ padding-bottom:96px; }

/* ---- (H) The card and its ladder stay put between slides ------
   On a desktop-sized window Teach Mode centred the card vertically,
   so a short slide sat lower than a tall one and the ladder chips
   jumped up and down on every page turn (peat, 2026-08-24: "มันเลื่อน
   บันไดตรงโจทย์ ไม่เอาแบบนี้"). The card now hangs from the top of
   the page on every slide, so the ladder is always in the same place.
   Inert on any page whose .wrap is not a flex column. */
@media (min-width:820px) and (min-height:720px){
  .wrap{ justify-content:flex-start !important; }
}
/* A question box that is 2–3px taller than its line (a superscript
   glyph) grew a scrollbar beside the question. A little vertical
   room keeps every glyph reachable with no scrollbar. */
.qtext{ padding-top:4px; padding-bottom:4px; }

/* ---- (I0) The step-figure kit itself, moved out of the lessons (2026-08-27)
   `.stepfig` / `.sfbar` / `.sfdot` / `.sfnext` used to live in a per-lesson
   "PML-EQKIT widgets" block that only FOUR of the 62 teach pages ever got. The
   moment a widget is offered to every lesson (see (I) below) that is a bug:
   the figure works but its dots vanish and its button renders as a raw grey
   <button>. Same values as the per-lesson block, so the four pages that still
   carry it are unaffected — this file loads last, and (I) overrides the
   transitions immediately below. Every other lesson can now use the kit with
   no per-file CSS edit at all. */
.stepfig{ display:grid; grid-template-rows:auto auto; }
.stepfig>.sf{ grid-column:1; grid-row:1; opacity:0; visibility:hidden; }
.stepfig>.sf.on{ opacity:1; visibility:visible; }
.sfcap{ font-size:14.5px; font-weight:800; color:var(--navy); margin:0 0 9px; }
.sfsub{ font-size:13px; font-weight:700; color:var(--muted); margin:9px 0 0; }
.sfsub code,.sf code{ font-family:ui-monospace,Menlo,monospace; font-size:.95em;
  background:#f1f4f9; border-radius:6px; padding:1px 6px; color:var(--navy); }
.stepfig>.sfbar{ grid-column:1; grid-row:2; }
.sfbar{ display:flex; align-items:center; justify-content:center; gap:7px;
  margin-top:11px; flex-wrap:wrap; }
.sfdot{ width:8px; height:8px; border-radius:50%; background:var(--line); }
.sfdot.on{ background:var(--accent); }
.sfnext,.sfreplay{ border:1.5px dashed var(--accent); background:var(--tint); color:#8a4a23;
  border-radius:999px; padding:6px 14px; font-size:12.5px; font-weight:800; cursor:pointer; }
body.tight .sfcap{ font-size:13.5px; }
body.tighter .sfcap{ font-size:12.5px; margin-bottom:7px; }
@media(min-width:700px) and (min-height:900px) and (orientation:portrait){
  body.roomy .sfcap{ font-size:19px; } body.roomy .sfsub{ font-size:16px; } }

/* ---- (I) Step-reveal widgets: slower fades, cumulative reveal, a
       scrolling working-stack, and short callout tags (2026-08-27) ----
   peat, on teach-pure1-quadratics: "ตัวหนังสือมันเยอะไปหน่อย ... เน้น diagram
   หรือไม่ก็เป็นวงๆ แล้วโยงเป็นคำ หรือวลีสั้นๆ", "slow step reveal ทำเป็น
   slow motion ... slowly fade ... ไม่ใช่ hard transition", and "บรรทัดที่
   เพิ่งทำเสร็จให้ทำเหมือนมันโดน scroll up ไป แล้วบรรทัดที่ working อยู่คือ
   บรรทัดล่าสุด ... จะสามารถเลื่อนขึ้นไปดูได้ว่าเกิดอะไรขึ้นบ้าง".

   Four additions, all opt-in from the lesson markup, so every page that
   does not use them is untouched:
     .stepfig        — slower, STAGGERED cross-fade (the outgoing pane is
                       nearly gone before the incoming one starts to rise)
     .stepfig.cum    — panes accumulate instead of replacing each other
     .stepfig.stack  — a working written one line at a time inside a fixed
                       viewport: the newest line is pinned at the bottom,
                       finished lines scroll up and stay reachable
     .calbub         — a short tag hung under ONE term, aligned to it by its
                       own table column and joined to it by a dashed line
   The .stepfig height stays constant in every case, so fitStage() still
   measures a stable card.                                                */

/* 1 · a one-pane-at-a-time .stepfig SLIDES instead of blinking.
      peat, 2026-08-27: "ไม่อยากให้ในทุกครั้งที่กด enter ... ตัวหนังสือทั้งหมด
      มันกระพิบหายอะ อยากได้แบบเลื่อน". Everything travels the same way — UP —
      so the pane on its way out and the pane on its way in read as one
      movement rather than as a flash of nothing. `.out` is put on the leaving
      pane by _pml-fix.js for the length of the move. */
.stepfig>.sf{ transform:translateY(22px);
  transition:opacity .24s cubic-bezier(.3,0,.75,.5), transform .38s cubic-bezier(.4,0,.7,1); }
.stepfig>.sf.out{ transform:translateY(-22px); }
.stepfig>.sf.on{ transform:none;
  transition:opacity .26s cubic-bezier(.1,.7,.4,1),
             transform .44s cubic-bezier(.2,.72,.26,1); }

/* 2 · a working, one line at a time, in a fixed-height scrolling viewport */
.stepfig.stack{ display:block; }
.ssview{ height:250px; overflow-y:auto; overscroll-behavior:contain;
  scroll-behavior:smooth; -webkit-overflow-scrolling:touch;
  border:1.5px solid var(--line); border-radius:16px; background:#fff;
  padding:10px 10px 8px; }
.ssview::-webkit-scrollbar{ width:7px; }
.ssview::-webkit-scrollbar-thumb{ background:#d7dee9; border-radius:99px; }
.ssview .ssl{ display:none; }
.ssview .ssl.on{ display:block; animation:pmlSslIn .58s cubic-bezier(.22,.68,.28,1) both; }
/* when _pml-fix.js can morph (Element.animate), it drives the entrance itself:
   the new line grows OUT OF the line above it instead of just appearing. */
.ssview.morph .ssl.on{ animation:none; }
@keyframes pmlSslIn{ from{ opacity:0; transform:translateY(15px); } to{ opacity:1; transform:none; } }
.ssl+.ssl{ border-top:1.5px dashed var(--line); padding-top:6px; margin-top:4px; }
.ssl .eqt{ margin:0 auto; transition:opacity .45s ease; }
.ssl .sslcap{ font-size:11.5px; font-weight:800; letter-spacing:.45px;
  text-transform:uppercase; color:var(--muted); text-align:center; margin:0 0 3px;
  transition:color .45s ease; }
/* the line being worked on is the loud one; the finished lines step back */
.ssview .ssl.on:not(.last) .eqt{ opacity:.55; }
.ssview .ssl.last .sslcap{ color:var(--accent); }
/* a finished line folds its tag away: the review view is then the working
   itself plus the step names, and two lines fit where one used to. */
.ssview .ssl.on:not(.last) .calbub{ opacity:0 !important; pointer-events:none; }
.ssview .ssl.on:not(.last) tr.calsp td{ height:0; }
.eqt tr.calsp td{ transition:height .45s ease; }
/* the tag sticks out of its table, which makes the table look sideways-scrollable
   to _pml-fix.js. Inside the stack that shadow is always a false alarm. */
.ssview .pml-xscroll{ box-shadow:none !important; }
body.tight .ssview{ height:220px; }
body.tighter .ssview{ height:190px; }
@media(max-width:560px){ .ssview{ height:200px; padding:8px 6px 6px; } }
@media(min-width:700px) and (min-height:900px) and (orientation:portrait){
  body.roomy .ssview{ height:340px; } body.roomy .ssl .sslcap{ font-size:14px; } }

/* 3 · a short tag under one term. The tag lives in a zero-height cell in the
       column of the term it belongs to, so it is aligned by the table itself
       — no measuring, no percentages, and it cannot drift in Thai. */
.eqt tr.cal td{ padding:0; height:0; border:0; }
.eqt tr.cal td.c{ position:relative; }
.eqt tr.calsp td{ padding:0; border:0; height:64px; }
.calbub{ position:absolute; left:50%; top:10px; width:162px; margin-left:-81px;
  font-size:11.8px; font-weight:800; line-height:1.4; white-space:normal;
  color:#8a4a23; background:var(--tint); border:1.6px dashed var(--accent);
  border-radius:13px; padding:5px 7px; text-align:center; z-index:2;
  opacity:0; transform:translateY(9px);
  transition:opacity .5s cubic-bezier(.22,.68,.28,1) .1s,
             transform .5s cubic-bezier(.22,.68,.28,1) .1s; }
.calbub.on{ opacity:1; transform:none; }
.calbub::before{ content:''; position:absolute; width:0;
  left:var(--connx,50%); bottom:100%; height:var(--connl,12px);
  transform-origin:50% 100%; transform:rotate(var(--conna,0deg));
  border-left:2px dashed var(--accent); }
.calbub.blue{ color:#2b4fa0; background:#eef3ff; border-color:#3f6fd8; }
.calbub.blue::before{ border-left-color:#3f6fd8; }
.calbub.grn{ color:#166b45; background:#effaf4; border-color:#1e8e5a; }
.rc.ring.grn::after{ border-color:#1e8e5a; }
.calbub.grn::before{ border-left-color:#1e8e5a; }
.calbub.lo{ top:26px; }
.eqt tr.calsp.tall td{ height:82px; }
@media(max-width:560px){ .calbub{ width:132px; margin-left:-66px; font-size:11px; }
  .eqt tr.calsp td{ height:70px; } .eqt tr.calsp.tall td{ height:90px; } }

/* 4 · rule on the left, the same line of the real example on the right.
       peat: "explanation อยู่ด้านซ้าย แต่ในแต่ละบรรทัด the example steps
       อยู่ด้านขวา". Rows reveal one at a time and the space for every row is
       reserved from the start, so the card never grows as they appear. */
.stepfig.flow{ display:block; }
.rulebox{ border:1.5px solid var(--line); border-radius:16px; padding:0 12px 8px;
  background:#fff; }
.rulebox .nohd{ height:7px; }
/* A small hand-drawn sketch that is meant to STAY small. It cannot say so
   inline: the lesson engine's upFig() rewrites any inline max-width under
   460px up to 460px, and fitStage() clears an inline width outright. A class
   is invisible to both, so the drawing keeps the size it was drawn at. */
.pmlmini{ max-width:236px; margin:0 auto; }
.rulebox .nohd + .rr{ border-top:0; }
.rulehd{ display:grid; grid-template-columns:1fr 1fr; gap:14px;
  font-size:11.5px; font-weight:800; letter-spacing:.5px; text-transform:uppercase;
  color:var(--accent); padding:8px 4px 6px; }
.rulehd>span:first-child{ text-align:right; }
.rr{ display:grid; grid-template-columns:1fr 1fr; gap:14px; align-items:center;
  padding:6px 4px; border-top:1.5px dashed var(--line);
  opacity:0; visibility:hidden; transform:translateY(11px);
  transition:opacity .30s ease, transform .30s ease; }
.rr.on{ opacity:1; visibility:visible; transform:none;
  transition:opacity .52s cubic-bezier(.22,.68,.28,1) .16s,
             transform .52s cubic-bezier(.22,.68,.28,1) .16s; }
.rr .rl{ font-size:13px; font-weight:800; color:var(--muted); text-align:right; }
.rr .rx{ font-size:1.04em; font-weight:800; color:var(--navy); text-align:left; }
.rr.hi .rx{ color:var(--accent); }
body.tight .rr .rl{ font-size:12.2px; } body.tighter .rr .rl{ font-size:11.5px; }
/* the fit tiers have to reach the rulebox too, or a three-row table on an
   already-tall `name` slide tips the card into overflowy by ~10px */
body.tight .rr{ padding:5px 4px; } body.tighter .rr{ padding:3px 4px; }
body.tight .rulehd{ padding:6px 4px 5px; } body.tighter .rulehd{ padding:4px 4px 3px; }
body.tighter .rr .rx{ font-size:0.96em; }
body.tighter .sfbar{ margin-top:7px; }
@media(max-width:560px){ .rulehd,.rr{ gap:8px; } .rulebox{ padding:0 8px 6px; }
  .rr{ padding:4px 3px; } .rulehd{ padding:5px 3px 4px; font-size:10.5px; }
  .rr .rl{ font-size:11.5px; } .rr .rx{ font-size:0.94em; }
  body.tight .rr{ padding:3px 3px; } body.tighter .rr{ padding:2px 3px; } }
@media(min-width:700px) and (min-height:900px) and (orientation:portrait){
  body.roomy .rr .rl{ font-size:16px; } }
@media(prefers-reduced-motion:reduce){
  .ssview .ssl.on{ animation:none; } .calbub,.rr,.stepfig>.sf{ transition:none; } }

/* ---- (I2) the aligned-equation kit itself, moved out of the lessons (2026-08-28)
   Byte-identical to the block 15 lessons already carry inline, so pages that have
   it see no change; the two that never had it (igcse-probability, pure1-trigonometry)
   and every lesson Wave B touches get it for free.  Loaded after the page's own
   <style>, so identical values simply win over identical values.               */
/* ---- PML-EQKIT-2026-08-17 · aligned equation frames -----------------------
   A pair of equations only teaches anything if the x column sits over the x
   column, so these are laid out as a TABLE and let the columns align
   themselves. Sized in em, not px, so the engine's fitter shrinks them like
   any other text. width:max-content is load-bearing: a table squeezed below
   its content width never triggers the fitter, and Chromium crushes the
   MathJax glyphs cell by cell instead.
   .rc.ring    dotted transparent ring round one coefficient
   td.bx/bl/br dotted capsule round a whole equation
   .wl/.wr/.wx worked lines: lhs = rhs, or one centred expression           */
.eqfig{margin:12px 0 10px;}
.eqt{border-collapse:separate;border-spacing:0 5px;margin:0 auto;width:max-content;
  font-size:1.4em;font-weight:700;color:var(--navy);line-height:1.25;}
.eqt td{border:2px solid transparent;padding:3px 4px;vertical-align:middle;white-space:nowrap;}
.eqt td.tg{font-size:.5em;font-weight:800;letter-spacing:.4px;text-transform:uppercase;
  color:var(--muted);text-align:right;padding-right:13px;}
.eqt td.cx,.eqt td.cy{text-align:right;}
.eqt td.ld,.eqt td.op,.eqt td.eqs{text-align:center;padding:3px 6px;}
.eqt td.rhs,.eqt td.wr{text-align:left;}
.eqt td.wl{text-align:right;}
.eqt td.wx{text-align:center;}
.eqt td.hi{background:#f1faf6;}
.eqt td.bx{border-top-style:dashed;border-bottom-style:dashed;
  border-top-color:var(--accent);border-bottom-color:var(--accent);background:var(--tint);}
.eqt td.bl{border-left-style:dashed;border-left-color:var(--accent);border-radius:15px 0 0 15px;}
.eqt td.br{border-right-style:dashed;border-right-color:var(--accent);border-radius:0 15px 15px 0;}
.eqt tr.ann td{padding:0 4px;}
.opnote{display:inline-block;font-size:.58em;font-weight:800;letter-spacing:.3px;
  text-transform:uppercase;color:var(--accent);}
.eqt tr.rl td{padding:0;}
.eqt tr.rl .hr{border-top:2.5px solid var(--navy-2);margin:3px 0;}
.rc{position:relative;display:inline-block;padding:0 1px;}
.rc.ring{margin-right:6px;}
.rc.ring::after{content:'';position:absolute;left:-6px;right:-5px;top:-7px;bottom:-7px;
  border:2px dashed var(--accent);border-radius:50%;pointer-events:none;}
.rc.ring.blue::after{border-color:#3f6fd8;}
.rc.ring.grey::after{border-color:#9aa5bd;}
.eqnote{font-size:13.5px;font-weight:700;color:var(--muted);margin:11px 0 0;text-align:center;}
.eqnote b{color:var(--accent);}
.pairwrap{display:grid;grid-template-columns:1fr 1fr;gap:11px;}
.pairbox{border:1.5px solid var(--line);border-radius:14px;padding:10px 8px 8px;}
.pairbox .plab{display:block;font-size:11.5px;font-weight:800;letter-spacing:.5px;
  text-transform:uppercase;color:var(--accent);text-align:center;margin-bottom:6px;}
.pairbox .eqt{font-size:1.15em;}
.pairbox.wk .eqt{font-size:1.1em;border-spacing:0 2px;}
body.tight .eqt{font-size:1.25em;} body.tighter .eqt{font-size:1.1em;}
body.tight .eqnote,body.tighter .eqnote{font-size:12.5px;}
@media(min-width:700px) and (min-height:900px) and (orientation:portrait){
  body.roomy .eqt{font-size:1.8em;} body.roomy .eqnote{font-size:16px;}}
@media(max-width:560px){.eqt{font-size:1.15em;} .pairwrap{grid-template-columns:1fr;gap:8px;}
  .pairwrap.wk2{gap:7px;} .pairwrap.wk2 .pairbox{padding:8px 4px 6px;}
  .pairbox .eqt{font-size:1.05em;} .eqt td.tg{padding-right:8px;}}
/* ---- /PML-EQKIT ----------------------------------------------------------- */
.rc.ring.wide::after{ border-radius:16px; }

/* ---- PML walk slides (stepped worked example, 2026-08-30) ----
   FormulaAnimation-style worked example: big current line + one-line note,
   earlier lines stay stacked above, dimmed, tappable. Shared here per the
   rule at the top of this file: any widget offered to every lesson lives in
   _pml-fix.css/_pml-fix.js, never in a per-lesson block. */
.wkfig{margin:14px 0 2px;}
/* the topic's opening picture, beside the working (2026-09-05) */
.wkwrap.haspic{display:flex;gap:clamp(10px,2.4vw,22px);align-items:center;margin-top:12px;}
.wkwrap.haspic>.wkfig{flex:1 1 auto;min-width:0;margin-top:0;}
.wkpic{flex:0 0 auto;width:clamp(150px,26vw,240px);background:#FFFDF7;border:1px solid var(--line);
  border-radius:12px;padding:10px;align-self:center;}
.wkpic svg{width:100%;height:auto;display:block;}
.wkpic [data-b]{opacity:0;transition:opacity .35s ease;}
.wkpic [data-b].on{opacity:1;}
@media(max-width:700px){.wkwrap.haspic{flex-direction:column;gap:8px;}
  .wkpic{width:min(74vw,240px);padding:8px;}}
body.tighter .wkpic{width:clamp(130px,22vw,190px);}
/* PML working notation — one guide line, every = on it (2026-09-05) */
.wkstack{position:relative;}
.wkguide{position:absolute;left:50%;top:0;width:0;border-left:1.5px dashed #f0a97f;opacity:.85;pointer-events:none;z-index:0;}
.wkrow{position:relative;display:grid;grid-template-columns:1fr auto 1fr;align-items:center;width:100%;}
.wkrow>.wl{position:relative;justify-self:end;text-align:right;padding-right:.34em;min-width:0;}
.wkrow>.we{text-align:center;}
.wkrow>.wr{position:relative;justify-self:start;text-align:left;padding-left:.34em;min-width:0;}
.wkrow.solo{display:block;text-align:center;}
.wkrow .wcx{position:relative;display:inline-block;}
.wkrow .wcx::after{content:"";position:absolute;left:-2px;right:-2px;top:52%;height:2px;background:var(--bad);
  border-radius:2px;transform:rotate(-8deg);opacity:.9;}
.wkrow.wku{color:var(--bad);font-size:.62em;margin-top:1px;}
.wkrow .wno{position:absolute;left:100%;margin-left:9px;top:50%;transform:translateY(-50%) rotate(-2deg);
  width:1.6em;height:1.6em;border:1.5px solid var(--navy);border-radius:50%;font-size:13px;font-weight:800;
  color:var(--navy);display:inline-flex;align-items:center;justify-content:center;line-height:1;}
.wkrow .wlab{position:absolute;right:100%;margin-right:8px;top:50%;transform:translateY(-50%);font-size:13px;
  font-weight:800;color:var(--accent);white-space:nowrap;}
.wkline .wkrow .wlab{font-size:10.5px;margin-right:6px;}
.wkline .wkrow .wno{font-size:10px;margin-left:6px;border-width:1.2px;}
.wkrow .wcx::after{transform:rotate(-5deg);}
.wkhist{align-items:stretch!important;}
.wkline{width:100%;}
.wkline .wkrow .wno{border-color:var(--muted);color:var(--muted);}
.wkhist{height:112px;overflow-y:auto;display:flex;flex-direction:column;align-items:center;gap:1px;padding:1px 6px;margin-bottom:8px;scrollbar-width:none;-ms-overflow-style:none;}
/* the passed lines fit; the scrollbar they used to show did nothing but sit there (2026-09-04) */
.wkhist::-webkit-scrollbar,.wkline::-webkit-scrollbar{width:0;height:0;display:none;}
.wkhist .wkline:first-child{margin-top:auto;}
.wkline{font-size:15px;color:var(--muted);opacity:.62;padding:1px 10px;border-radius:9px;cursor:pointer;transition:opacity .15s,background .15s;max-width:100%;overflow-x:auto;flex:0 0 auto;scrollbar-width:none;-ms-overflow-style:none;}
.wkline:hover{opacity:1;background:var(--tint);}
.wkcur{background:#f8fafd;border:1px solid var(--line);border-radius:13px;padding:14px 12px 10px;text-align:center;}
.wkcur.pop{animation:wkIn .35s cubic-bezier(.2,.7,.3,1) both;}
@keyframes wkIn{from{opacity:0;transform:translateY(10px);}to{opacity:1;transform:none;}}
.wkeq{font-size:25px;min-height:58px;display:flex;flex-direction:column;align-items:stretch;justify-content:center;
  overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none;}
.wkeq::-webkit-scrollbar{width:0;height:0;display:none;}
.wknote{margin-top:8px;font-size:13.5px;color:var(--muted);min-height:1.3em;}
.wkcur .hl{color:var(--accent);}
.wkcur.settled .hl{color:inherit;transition:color .8s ease;}
.wkbar{display:flex;align-items:center;justify-content:center;gap:10px;margin-top:11px;}
.wkprev,.wknext{width:38px;height:38px;border-radius:50%;border:1.5px solid var(--line);background:#fff;color:var(--navy);font-size:19px;cursor:pointer;line-height:1;}
.wkprev:disabled,.wknext:disabled{opacity:.3;cursor:default;}
.wkdots{display:flex;gap:6px;align-items:center;}
.wkdot{width:8px;height:8px;border-radius:50%;background:var(--line);display:inline-block;cursor:pointer;}
.wkdot.done{background:#f3c9ae;}
.wkdot.on{background:var(--accent);transform:scale(1.35);}
.wkcount{font-size:12px;color:var(--muted);min-width:40px;text-align:center;font-variant-numeric:tabular-nums;}
body.tight .wkhist{height:92px;} body.tight .wkeq{font-size:22px;}
body.tighter .wkhist{height:76px;} body.tighter .wkeq{font-size:20px;min-height:48px;}
@media(max-width:560px){.wkeq{font-size:21px;}.wkhist{height:96px;}}

/* ---- (K) One card, one text size — the lesson-wide fit lock (2026-09-02) ----
   peat: "เอาให้มันจอไม่เด้งอะ และไม่อยากให้ scroll นะ".

   The old per-slide tier fitter is retired here (see the matching block in
   _pml-fix.js). Every slide in a lesson now renders at ONE zoom, inside a card
   of ONE fixed height, so nothing changes size or moves when the page turns,
   and the height was chosen from the tallest slide so nothing has to scroll.
   The tier classes are left defined above: a page that somehow never gets the
   JS still behaves exactly as it did before. */
body.pmlfit .stage{
  zoom:var(--pmlz,1);
  min-height:var(--pmlcard,340px);
}
/* the column is exactly as tall as the viewport now, so centring it can only
   move the card about; top-align and the first line lands on the same y on
   every single slide */
body.pmlfit .wrap{ justify-content:flex-start !important; }
/* the fixed nav bar's real height, measured at runtime — the card stops above
   it and the footer links clear the two floating buttons instead of sitting
   under them */
body.pmlfit .wrap{ padding-bottom:calc(var(--pmlNavH,60px) + 8px) !important; }
/* every pixel between the card and the bar is a pixel the type does not have
   to give up: the footer links and the resume bar are trimmed, not removed */
body.pmlfit .pmlfoot{ margin-top:10px !important; padding-top:10px !important; }
body.pmlfit .resumebar{ padding-top:7px !important; padding-bottom:7px !important;
  margin-bottom:8px !important; font-size:12.5px !important; }
/* the offscreen measuring pass */
#pmlProbe{ position:fixed !important; left:0; top:0; z-index:-1;
  visibility:hidden !important; pointer-events:none; zoom:1 !important;
  min-height:0 !important; box-shadow:none !important; }
#pmlProbe .pmlprobe1{ display:flow-root; }

/* ---- (L) notes-style `name` slides get the rulebox card (2026-09-02) ----
   peat: "หน้าที่อธิบายทีละสเตป ... ไม่ได้ดูสวยงามและมี feature เหมือนที่แก้ใน
   P1 quadratics". 73 `name` slides across the 62 lessons still carried the
   plain blue "What it means" list: no dots, no reserved space, so the card
   grew a line at a time and everything under it jumped. Same chrome as the
   rulebox now — header rule, dashed row separators, every row's space
   reserved from the first paint, step dots and the orange pill. */
.nsfig{ margin-top:14px; }
.rulebox.nsbox{ padding:0 14px 10px; }
.rulehd.nshd{ grid-template-columns:1fr; padding:9px 4px 7px; }
.rulehd.nshd>span:first-child{ text-align:left; }
.rr.nsr{ grid-template-columns:auto 1fr; gap:11px; align-items:flex-start;
  padding:9px 4px; text-align:left; }
.rr.nsr .nsn{ width:21px; height:21px; border-radius:50%; background:var(--navy-2);
  color:#fff; font-size:12px; font-weight:800; display:flex; align-items:center;
  justify-content:center; margin-top:1px; }
.rr.nsr:last-child .nsn{ background:var(--accent); }
.rr.nsr .nsb{ font-size:15.5px; line-height:1.6; color:#20305a; }
.rr.nsr .nsb b{ color:var(--navy); }
body.tight .rr.nsr{ padding:7px 4px; } body.tight .rr.nsr .nsb{ font-size:14.5px; }
body.tighter .rr.nsr{ padding:5px 4px; } body.tighter .rr.nsr .nsb{ font-size:13.5px; }
@media(max-width:560px){ .rulebox.nsbox{ padding:0 10px 8px; }
  .rr.nsr{ padding:7px 3px; gap:9px; } .rr.nsr .nsb{ font-size:14.5px; }
  .rr.nsr .nsn{ width:19px; height:19px; font-size:11px; } }

/* ---- (L2) a step may carry its own demonstration on the right (2026-09-02) --
   peat: "จริงๆคืออยากให้ทำเป็น equation or diagram or figure มากกว่าอยู่ดี ถ้าทำ
   เป็น text ให้สั้นแบบแค่ short statement ... รวมถึงในแต่ละสเตปอาจจะมี
   demonstration อยู่ด้านขวาด้วย".

   A note may now be {en, th, show} (a LaTeX line) or {en, th, fig} (raw SVG/HTML).
   When any note in the slide carries one, the whole rulebox switches to the
   two-column shape the quadratics figures use: the short statement on the left,
   the maths or the picture doing the talking on the right. A slide whose notes
   are plain text is unchanged, so nothing has to be converted before it works. */
.nsfig .rulebox{ --nsc:auto minmax(0,1fr); }
.nsfig.two .rulebox{ --nsc:26px minmax(0,1fr) minmax(0,1fr); }
/* a two-column step reads as one line, so it wants a line length, not the
   whole card. Left unbounded on a 900px card the statement and its equation
   end up an inch apart with a hole down the middle. */
.nsfig.two .rulebox{ max-width:660px; margin-left:auto; margin-right:auto; }
.rulehd.nshd, .rr.nsr{ grid-template-columns:var(--nsc); gap:12px; }
.rulehd.nshd:not(.two)>span{ grid-column:1 / -1; }
.rulehd.nshd.two>span:first-child{ grid-column:2; text-align:left; }
.rulehd.nshd.two>span:last-child{ grid-column:3; text-align:left; color:var(--navy-2); }
.rr.nsr{ padding:7px 4px; }
.rr.nsr .nsb{ line-height:1.5; }
.rr.nsr .nsd{ min-width:0; font-size:1.03em; font-weight:800;
  color:var(--navy); text-align:left; align-self:center;
  /* a long line still swipes sideways, but setting overflow-x alone makes the
     browser compute overflow-y:auto too, and a MathJax svg overhangs its box by
     ~4px — which drew a grey scrollbar stub beside every equation on a phone.
     Pad the overhang away, pin overflow-y, and never paint the bar. */
  overflow-x:auto; overflow-y:hidden; padding:3px 0;
  scrollbar-width:none; -ms-overflow-style:none; }
.rr.nsr .nsd::-webkit-scrollbar{ width:0; height:0; }
.rr.nsr .nsd .hl{ color:var(--accent); }
/* ONLY a hand-drawn figure is centred. MathJax renders every formula as an
   <svg> too, so a blanket rule here centred each equation inside its own
   column — which is why the IN SYMBOLS heading stopped lining up with them. */
.rr.nsr .nsd.pic{ font-weight:400; }
.rr.nsr .nsd.pic svg{ max-width:100%; height:auto; display:block; margin:0 auto; }
.rr.nsr .nsd mjx-container{ margin:0 !important; text-align:left; }
body.tighter .rr.nsr .nsd{ font-size:0.97em; }
/* 700px, not 640: that is where the JS hands the page back to the old tier
   fitter (narrow()), so the two breakpoints have to be the same number or a
   680px window gets the locked layout with the unlocked fitter. */
@media(max-width:700px){
  /* the two floating buttons sit ON the card on a phone — measured on
     teach-pure1-triangle-rules p21 at 375x812, the last step row ran 687-780px
     and the buttons 690-738px, so the fourth line was unreadable. The page
     scrolls here, so the column just needs enough room underneath for the last
     line to be scrolled clear of them. */
  .wrap{ padding-bottom:158px !important; }
  .nsfig.two .rulebox{ --nsc:26px minmax(0,1fr); max-width:none; }
  .rulehd.nshd.two>span:first-child{ grid-column:1 / -1; }
  .rulehd.nshd.two>span:last-child{ display:none; }
  .rr.nsr .nsd{ grid-column:2; margin-top:4px; }
}

/* ============================================================
   PML-EX-2026-09-04 · exercise set is answered and scored
   (peat: "ตรง exercise set ของทุก teach mode มันมีกดตอบและบันทึกคะแนนด้วย")
   ============================================================ */
.sh .exscore{float:right;font-size:13px;font-weight:800;color:var(--muted,#64748b);margin-top:4px;}
.sh .exscore b{color:var(--good,#1f9d6e);font-size:16px;}
.exdot.ok{border-color:var(--good,#1f9d6e);color:var(--good,#1f9d6e);}
.exdot.on.ok{background:var(--good,#1f9d6e);border-color:var(--good,#1f9d6e);color:#fff;}
.exdot.no{border-color:var(--bad,#c0492f);color:var(--bad,#c0492f);}
.exdot.on.no{background:var(--bad,#c0492f);border-color:var(--bad,#c0492f);color:#fff;}
.exin{margin-top:12px;}
.exmine{margin-top:12px;padding:10px 13px;border-radius:11px;font-size:14.5px;font-weight:700;display:flex;gap:8px;align-items:center;flex-wrap:wrap;}
.exmine.good{background:#e8f7ef;color:#136b4b;}
.exmine.bad{background:#fdecea;color:#a13a24;}
.exmine .exlab{font-weight:600;opacity:.75;font-size:12.5px;}
.exmine .exv{font-size:15.5px;}
.exmine .rlink,.exfoot .rlink{background:none;border:0;color:var(--accent,#c2521f);font-weight:800;font-size:13px;cursor:pointer;text-decoration:underline;padding:2px 4px;font-family:inherit;}
.exmark{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-top:12px;font-size:13.5px;font-weight:700;color:var(--muted,#64748b);}
.exmark .btn{padding:8px 13px;font-size:13.5px;}
.exnext{margin-top:14px;padding:14px 15px;border:1px solid #ffd9c2;border-radius:14px;background:linear-gradient(160deg,#fff6f1,#fff);}
.exnext .exnh{font-size:14px;font-weight:800;color:#0f1d3a;margin-bottom:10px;}
.rsub.rex{margin-top:6px;}
.rsub.rex b{color:var(--good,#1f9d6e);font-size:15px;}
.rsub .rexnote{font-weight:600;opacity:.75;}
.exmine.mid{background:#f1f5f9;color:#1e293b;}
.exmine .exnote{font-weight:600;font-size:13px;opacity:.85;}

/* ---- (M) Zooming shows more maths, not more furniture (2026-09-05) --------
   peat: "When zoomed in to fullscreen the screen wont show the problems but
   only gets pushed down and i have to scroll up to see the problems ... also
   other pages with zooming feature."

   Measured on teach-igcse-quadratics at 1470x790, page zoom 140%: the top bar
   grew 50->71, the exam-board strip 43->59, the ladder 45->64 and the bottom
   nav 59->82, so the question card started 79px lower and had 60px less room
   underneath — 139px of reading screen spent on chrome before one word of
   maths got bigger. On a Teach Mode page it was worse than useless: the card
   already carries its own zoom (--pmlz, often 0.70), so 1.4 x 0.70 = 0.98 and
   the type did not change size at all. Everything moved; nothing grew.

   Two modes, and neither changes anything at 100%.

   A. Teach Mode (body.pmlfit) — the pills scale the CARD (--pmlzoomx) and the
      page is never zoomed, so the furniture cannot move and the question stays
      where it was. The card is unpinned so it may run past the fold; it is
      top-aligned already, so the question is the part you see.

   B. Every other /learn page — the page zoom stays, but the chrome cancels it
      (zoom:1/f, the same trick the whiteboard uses for its own toolbar via
      --wbcz) and the column is one PHYSICAL screen tall (--pmlvh) instead of
      100vh of zoomed units.
   ------------------------------------------------------------------------ */
/* A — the card carries the zoom */
body.pmlfit .stage{ zoom:calc(var(--pmlz,1) * var(--pmlzoomx,1)); }
/* a card pinned to the tallest slide's height reserves that height again at
   the new zoom: white space below when zooming out, nothing gained zooming in */
body.pmlzoomx.pmlfit .stage{ min-height:0; }
body.pmlzoomx .wrap{ justify-content:flex-start !important; }

/* B — the chrome keeps its real size while the page is zoomed */
html.pml-zoomed .topbar,
html.pml-zoomed .navbar,
html.pml-zoomed .ladder,
html.pml-zoomed .pmlfoot,
html.pml-zoomed .resumebar,
html.pml-zoomed .freebar,
html.pml-zoomed .pml-topnav,
html.pml-zoomed .tbstrip,
html.pml-zoomed #igcseBoard,
html.pml-zoomed #pmlTrackFab,
html.pml-zoomed #pmlPad,
html.pml-zoomed .padbtn,
html.pml-zoomed .pml-cta-fab{ zoom:var(--pmlcz,1); }
/* `calc(100vh - 108px)` is read in zoomed units, so at 140% the column
   reserved 1.4 screens and centred the card in the middle of them */
html.pml-zoomed .wrap{ min-height:calc(var(--pmlvh,100vh) - 108px); justify-content:flex-start; }

/* ==== (N) PML-SLW-2026-09-05 · straight-line working layout ================
   peat, 5 Sep: "This is how I want the flow of straight line equation to be —
   with the equal sign aligned in the middle, then we name two equations 1 and
   2, then write the coordinate on the right hand side of 2, then we make sense
   whether 1 and 2 are parallel or perpendicular (with parallel sign or
   perpendicular sign), then say m2 = m1 or m2 = -1/m1, substitute to find m2,
   then sub m2 in the next line with arrows like in the pic with c still in
   tact, then another arrow point the usage of the coordinate given to find c,
   then finally last arrow to summarize final equation. It is important to
   write x and y letters above the given coordinate to not make mistakes."

   Every part of that is load-bearing and none of it survives being written as
   prose or as a single $...$ chain:

   .slwt      the working itself, as a TABLE — lhs | = | rhs — so the equals
              signs sit in one column whatever the numbers are. Same reasoning
              as .eqt above: a chain typeset as one line cannot align, and a
              student copying it off the board loses the column.
   td.A       the annotation column: circled equation numbers and the point.
   .slwpt     the given coordinate with a small x and y printed OVER the two
              numbers, which is the one habit that stops a student feeding the
              y into m's x slot.
   .slwrel    the relation between the two named lines, in its own oval:
              (1) || (2)  or  (1) ⟂ (2).
   tr.sub     the "-4      -4" row: the same move done to both sides, under
              the terms it acts on, with the = column left empty.
   .slwarr    the arrows, drawn by _pml-fix.js from the rows' real geometry
              rather than authored — they have to survive MathJax reflow, the
              fitter's font scaling, Thai (labels run ~25% wider) and page
              zoom, and a hand-drawn path survives none of those.

   Sized in em so the fitter shrinks it like any other text; width:max-content
   for the same reason .eqt needs it (a table squeezed below its content width
   never triggers the fitter and Chromium crushes the glyphs cell by cell).
   =========================================================================== */
.slw{position:relative;margin:11px auto 4px;padding:2px 8px 2px 46px;
  width:max-content;max-width:100%;}
.slwt{border-collapse:separate;border-spacing:0 4px;margin:0;
  font-size:1.32em;font-weight:700;color:var(--navy);line-height:1.22;}
.slwt td{padding:1px 3px;white-space:nowrap;vertical-align:middle;}
.slwt td.L{text-align:right;}
.slwt td.E{text-align:center;padding:1px 8px;}
.slwt td.R{text-align:left;}
.slwt td.A{text-align:left;padding-left:18px;}
/* the LEFT margin: the parallel / perpendicular statement sits beside the
   line it justifies, which is where peat writes it on paper -- not in a row
   of its own above, where it read as a floating decoration nobody could
   attach to anything */
.slwt td.P{text-align:right;padding-right:15px;white-space:nowrap;}
/* the same operation done to both sides, printed under the terms it acts on */
.slwt tr.sub td{font-size:.66em;color:var(--accent);padding:0 3px 2px;}
.slwt tr.sub .slwub{display:inline-block;border-bottom:1.6px solid var(--accent);
  padding:0 2px 1px;}
/* the line that answers the question */
.slwt tr.fin td{color:var(--accent);}
.slwt tr.fin td.L,.slwt tr.fin td.R{background:var(--tint);}
.slwt tr.fin td.L{border-radius:12px 0 0 12px;}
.slwt tr.fin td.R{border-radius:0 12px 12px 0;}

/* (1) (2) — the two named equations */
.slwno{display:inline-flex;align-items:center;justify-content:center;
  width:1.5em;height:1.5em;border:2px solid var(--navy);border-radius:50%;
  font-size:.58em;font-weight:800;color:var(--navy);line-height:1;}
/* (1) || (2)   /   (1) ⟂ (2) */
.slwrel{display:inline-block;border:2px solid var(--accent);
  border-radius:50%/58%;padding:.2em .8em;font-size:.6em;font-weight:800;
  color:var(--accent);white-space:nowrap;line-height:1.35;}
.slwrel .slwno{border-color:var(--accent);color:var(--accent);
  font-size:.95em;width:1.5em;height:1.5em;}
.slwrel .sym{padding:0 .3em;font-size:1.05em;}

/* the given point, with x and y printed over the two numbers */
.slwpt{display:inline-block;vertical-align:middle;}
.slwpt table{border-collapse:collapse;margin:0;}
.slwpt td{padding:0 1px;text-align:center;white-space:nowrap;}
.slwpt tr.lbl td{font-size:.46em;font-weight:800;color:var(--accent);
  line-height:1;padding-bottom:2px;letter-spacing:.4px;}

/* arrow layer — !important beats the fitter's inline caps on .figbox svg */
.slwarr{position:absolute;left:0;top:0;overflow:visible;pointer-events:none;
  width:auto!important;height:auto!important;
  max-width:none!important;max-height:none!important;}
.slwarr path{fill:none;stroke:var(--muted);stroke-width:1.7;
  stroke-linecap:round;opacity:.78;}
.slwarr polygon{fill:var(--muted);opacity:.78;}

/* the running note: one line, swapped as the working advances, because the
   reader has no way to know that (1) and (2) are names we chose or that the
   oval says "line 1 is parallel to line 2" unless something says so at the
   moment it appears. Bilingual spans work inside a fig -- the page's own
   `body.lang-th .en{display:none}` reaches them -- and min-height keeps the
   line's space reserved so nothing jumps as the text changes. */
.slwnote{min-height:2.4em;margin:0 auto 10px;max-width:34em;text-align:center;
  font-size:13.5px;font-weight:700;line-height:1.35;color:var(--navy-2);}
.slwnote b{color:var(--accent);}
.slwnote .slwno{width:1.35em;height:1.35em;font-size:.78em;vertical-align:-.15em;}
@media(max-width:560px){.slwnote{font-size:12px;min-height:3.2em;}}

.slwcap{font-size:13px;font-weight:700;color:var(--muted);
  margin:9px 0 0;text-align:center;}
.slwcap b{color:var(--accent);}

body.tight .slwt{font-size:1.18em;} body.tighter .slwt{font-size:1.06em;}
@media(min-width:700px) and (min-height:900px) and (orientation:portrait){
  body.roomy .slwt{font-size:1.66em;}}
@media(max-width:560px){
  .slw{padding-left:34px;padding-right:2px;}
  .slwt{font-size:1.04em;border-spacing:0 3px;}
  .slwt td.A{padding-left:10px;}
  .slwcap{font-size:12px;}}

/* ---- stepped reveal: the working is written one line at a time -----------
   peat, 5 Sep: "reveal one sentence by one". The stepping ENGINE already
   exists (eqStepSet / stepMore, section (F)), so the figure joins it as a
   `.stepfig` rather than growing a second one -- Enter, the Next key, the
   left arrow and the replay button all work for free.
   Two things have to be overridden. `.stepfig{display:grid}` would destroy
   the table, so `.slw.stepfig` goes back to block, exactly as `.stepfig.stack`
   does. And the panes here are table ROWS, so the generic `.stepfig>.sf`
   rules never reach them and these do the hiding instead: on the CELLS, not
   the row, because opacity on a <tr> is unreliable and transform on a
   table-cell is ignored outright. visibility keeps every row's height
   reserved from the first frame, so the card never reflows as the working
   appears and fitStage() measures the finished figure once. */
.slw.stepfig{display:block;}
.slwt tr.sf > td{visibility:hidden;opacity:0;transition:opacity .3s ease;}
.slwt tr.sf.on > td{visibility:visible;opacity:1;}
.slw.stepfig{cursor:pointer;}
/* the running note: every line's note lives in the box at once, one grid cell,
   only the current one visible -- so the box is as tall as its tallest note
   from the first frame and Enter never moves the working. (2026-09-08) */
.slwnote.stack{display:grid;}
.slwnote.stack>.nt{grid-column:1;grid-row:1;visibility:hidden;opacity:0;
  transition:opacity .25s ease;}
.slwnote.stack>.nt.on{visibility:visible;opacity:1;}
@media(prefers-reduced-motion:reduce){.slwnote.stack>.nt{transition:none;}}
/* The cue for "there is another line" sits exactly where that line will
   appear, not in a button bar at the bottom of the figure -- the rows keep
   their height reserved, so a bar ends up stranded in blank space several
   lines below the last thing written, which reads as a broken slide. It is
   placed from JS against the last written row. */
.slwcue{position:absolute;width:26px;height:26px;border-radius:50%;
  border:1.6px dashed var(--accent);color:var(--accent);background:var(--tint);
  display:flex;align-items:center;justify-content:center;font-size:11px;
  line-height:1;pointer-events:none;opacity:.9;
  animation:slwpulse 1.9s ease-in-out infinite;}
@keyframes slwpulse{0%,100%{transform:translateY(0);opacity:.9;}
                    50%{transform:translateY(3px);opacity:.55;}}
@media(prefers-reduced-motion:reduce){.slwcue{animation:none;}}
@media(prefers-reduced-motion:reduce){.slwt tr.sf > td{transition:none;}}
/* ---- /PML-SLW ------------------------------------------------------------ */
/* a right-hand arc (the given point feeding the substitution line) needs its
   own gutter, and an attribute selector buys it with no reflow dance */
.slw[data-arrows*="R"]{padding-right:44px;}
@media(max-width:560px){.slw[data-arrows*="R"]{padding-right:30px;}}
/* ==== exam-question working (ask slide steps, 2026-09-05) ==== */
.why.steps{padding:14px 16px 12px;line-height:1.5;}
.why.steps .wkfig{margin:6px 0 0;}
.why.steps .wkcur{background:#fff;}
.why.steps .wknote{font-size:14px;color:var(--navy);}
/* the question stays on screen while the working is read */
.qtext.pinq{position:sticky;top:0;z-index:5;background:var(--card,#fff);margin-top:0;padding:8px 0 8px;
  border-bottom:1px solid var(--line);box-shadow:0 8px 12px -10px rgba(15,29,58,.25);}

/* ==== the walk renderer as a static block (exam packs, ladders) 2026-09-06 ==
   PML.walkHTML() emits the same rows a Teach Mode walk uses (.wkrow / .wl /
   .we / .wr / .wcx / .wku / .wno / .wlab) but all at once. The rows go
   display:contents inside ONE 1fr auto 1fr grid, so every relation sits in
   one shared column and PML.walkPaint() can put the dashed guide on it.
   No page defines its own working grid. ==================================== */
.wkfig.wkstatic{margin:9px 0 7px;}
.wkfig.wkstatic>.wkstack{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;
  row-gap:1px;position:relative;padding:7px 30px 7px 46px;font-size:15px;line-height:1.5;
  background:#fff;border:1px solid #e4efe8;border-radius:11px;overflow-x:auto;}
.wkfig.wkstatic .wkrow{display:contents;}
.wkfig.wkstatic .wkrow.solo{display:block;grid-column:1/4;justify-self:stretch;text-align:center;}
.wkfig.wkstatic .wl,.wkfig.wkstatic .wr{white-space:nowrap;}
.wkfig.wkstatic>.wkstack>.wkguide{top:5px;bottom:5px;height:auto;}
/* overflow-x:auto above makes the vertical axis auto too, and a tall
   MathJax row (an integral, a stacked fraction) hangs 2-3px past the
   grid, which showed as a stub scrollbar on narrow screens. Absorb it
   rather than clip it — a clipped exponent is worse than a scrollbar. */
@media(max-width:900px){.wkfig.wkstatic>.wkstack{padding-bottom:15px;}}
@media(max-width:640px){.wkfig.wkstatic>.wkstack{font-size:13.5px;padding-left:34px;padding-right:20px;}
  .wkfig.wkstatic .wlab{margin-right:5px;font-size:10px;} .wkfig.wkstatic .wno{margin-left:5px;}}
@media print{.wkfig.wkstatic>.wkstack{background:#fff;break-inside:avoid;}}

/* ---- a mark-scheme row: code · tag · working · staged figure · (why) ---- */
.msbody{flex:1 1 auto;min-width:0;}
.mstag{display:block;font-size:14px;font-weight:700;color:var(--navy,#12294D);}
.mswhy{display:block;margin-top:4px;font-size:13.5px;line-height:1.55;color:var(--muted,#8A8F9B);
  border-left:2px solid var(--line,#e4e9f2);padding-left:9px;}
.msfig{background:#fff;border:1px solid var(--line,#e4e9f2);border-radius:12px;padding:6px 8px;margin:0 0 10px;}
.msfig svg{max-width:100%;height:auto;}
.msfig [data-b]{opacity:.15;transition:opacity .3s ease;}
.msfig [data-b].on{opacity:1;}
/* a row's own layer is the one drawn in accent (class stgo); a revealed
   construction layer keeps its ink, so .now carries no colour of its own */
.stgo{display:none;}
.msfig .stgo.on{display:inline;}
.msrow.hasfig{cursor:pointer;}
.msrow.hasfig.live{background:#fff;border-radius:9px;}
@media print{.msfig [data-b]{opacity:1!important;} .msfig .stgo{display:none!important;}}

/* the "answer form" hint line backfilled by _pml-fix.js section (K).
   Scoped to .pmlfmt — the 13 lessons with their own fmtHTML() carry their
   own .fmtline rule in their own <style>, and _pml-fix.css loads after it,
   so a bare .fmtline rule here would restyle them. Declarations copied
   from the twelve that agree. */
.fmtline.pmlfmt{margin:-2px 0 2px;font-size:12.5px;color:var(--muted,#5b6680);font-weight:600;}
.fmtline.pmlfmt b{color:var(--navy,#0f1d3a);font-weight:800;}

/* ===== Thai word-labels inside maths (additive, new class names only) =====
   MathJax tex-svg renders every character of \text{} as a separate <text>
   element, which detaches Thai vowels and tone marks. Thai labels are
   therefore written as page-font HTML outside the maths, using these two
   classes, so shaping is done by the browser. */
.pml-mw{font-family:inherit;font-style:normal;font-weight:inherit;white-space:nowrap;}
.pml-mfr{display:inline-flex;flex-direction:column;align-items:center;vertical-align:middle;position:relative;top:-.06em;margin:0 .2em;line-height:1.42;text-align:center;font-style:normal;}
.pml-mfr>span{display:block;padding:0 .15em;}
.pml-mfr>span:first-child{border-bottom:1.1px solid currentColor;padding-bottom:.19em;}
.pml-mfr>span:last-child{padding-top:.19em;}
.pml-mdisp{display:block;text-align:center;margin:.75em 0;}
.pml-mx{white-space:nowrap;}

/* ===== Thai word-labels inside scripts and radicals (additive; new class
   names only) ===========================================================
   Companion to the .pml-mw / .pml-mfr block above. Those cover Thai labels
   that sit on the baseline; these cover the ones that sit in a superscript,
   subscript or radicand, where closing the maths around the label would
   flatten the structure. The structure is rebuilt in HTML instead, so the
   Thai is shaped by the browser and its vowels and tone marks stay attached.

   Every number is MathJax's own, read off the transforms in its own SVG
   output: superscript baseline +0.3931em, subscript -0.150em, script scale
   0.707, msubsup superscript +0.3931em / subscript -0.247em, sqrt rule top
   0.7885em and thickness 0.060em, radical advance 0.853em and descent
   0.200em, medium (relation) space 0.278em, thick (binary) space 0.222em.
   They are written in ex because MathJax sizes its output in ex so that its
   x-height matches the page's; its font's x-height is 0.442em, so one
   MathJax em is 1/0.442 = 2.2624 page ex. Expressed this way the components
   track MathJax on whatever font the device actually resolves. */
.pml-msup,.pml-msub{font-size:.707em;font-style:normal;font-weight:inherit;
  white-space:nowrap;display:inline-block;margin-left:.106ex;line-height:1;}
.pml-msup{vertical-align:1.258ex;}
.pml-msub{vertical-align:-.480ex;}

/* base carrying a superscript and a subscript at once: the two scripts are
   a left-aligned column, exactly as MathJax stacks them. */
.pml-mss{display:inline-flex;align-items:baseline;white-space:nowrap;}
.pml-mss>.pml-msc{display:inline-flex;flex-direction:column;align-items:flex-start;
  font-size:.707em;font-style:normal;font-weight:inherit;line-height:2.048ex;
  margin-left:.106ex;position:relative;top:-1.258ex;}
.pml-mss>.pml-msc>span{display:block;white-space:nowrap;}

/* radical: the sign is MathJax's own U+221A outline as a mask so it takes
   currentColor and stretches; the overbar is the radicand's border-top,
   put at MathJax's rule height by a zero-width strut of exactly that height
   (line-height:0 keeps the text from moving it, so the bar does not depend
   on the resolved font's ascent). .pml-msqrtT is the same with a taller
   bar, for a radicand whose Thai carries stacked upper marks. */
.pml-msqrt,.pml-msqrtT{--pml-sqt:1.784ex;white-space:nowrap;}
.pml-msqrtT{--pml-sqt:2.45ex;}
.pml-msqrt>.pml-mrad,.pml-msqrtT>.pml-mrad{display:inline-block;width:1.930ex;
  height:calc(var(--pml-sqt)*1.25);vertical-align:calc(var(--pml-sqt)*-.25);
  background-color:currentColor;
  -webkit-mask:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 853 1000' preserveAspectRatio='none'%3E%3Cpath transform='translate(0,800) scale(1,-1)' d='M95 178Q89 178 81 186T72 200T103 230T169 280T207 309Q209 311 212 311H213Q219 311 227 294T281 177Q300 134 312 108L397 -77Q398 -77 501 136T707 565T814 786Q820 800 834 800Q841 800 846 794T853 782V776L620 293L385 -193Q381 -200 366 -200Q357 -200 354 -197Q352 -195 256 15L160 225L144 214Q129 202 113 190T95 178Z'/%3E%3C/svg%3E") no-repeat 0 0/100% 100%;
  mask:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 853 1000' preserveAspectRatio='none'%3E%3Cpath transform='translate(0,800) scale(1,-1)' d='M95 178Q89 178 81 186T72 200T103 230T169 280T207 309Q209 311 212 311H213Q219 311 227 294T281 177Q300 134 312 108L397 -77Q398 -77 501 136T707 565T814 786Q820 800 834 800Q841 800 846 794T853 782V776L620 293L385 -193Q381 -200 366 -200Q357 -200 354 -197Q352 -195 256 15L160 225L144 214Q129 202 113 190T95 178Z'/%3E%3C/svg%3E") no-repeat 0 0/100% 100%;}
.pml-msqrt>.pml-mrdc,.pml-msqrtT>.pml-mrdc{display:inline-block;line-height:0;
  font-style:normal;border-top:.136ex solid currentColor;}
.pml-mrdc>.pml-mstrut{display:inline-block;width:0;height:var(--pml-sqt);
  vertical-align:baseline;}

/* the spacing MathJax would have given an operator that now sits in its own
   $...$ island, where TeX can no longer see its neighbours. */
.pml-mrel{margin:0 .629ex;}
.pml-mbin{margin:0 .502ex;}

/* structured `why` blocks (2026-09-08) — see PML.whyHTML in _pml-fix.js */
.whytag{font-weight:800;font-size:.97em;letter-spacing:.1px;margin:0 0 .45em;}
.why .wkfig.wkstatic,.fb .wkfig.wkstatic{margin:.35em 0 .1em;}
.whynote{margin:.55em 0 0;font-size:.94em;line-height:1.6;opacity:.92;}
.whytag+.whynote{margin-top:.2em;}

/* ---- (O) the rulebox '=' sits in one fixed column (2026-09-09) ----
   peat, on teach-functions P20 and "อีกหลายๆหน้า": each .rx cell held one
   whole equation, so the '=' landed wherever that row's left side happened
   to end and slid about from line to line. The rows now reuse the walk
   slide's own .wkrow grid (lhs | = | rhs), so every '=' in a box lands on
   the same vertical line. minmax(0,1fr) is load-bearing: a bare 1fr keeps
   an auto minimum, so one long left side would push the column off centre.
   The split itself is done in _pml-fix.js (section O) before MathJax runs.  */
.rr .rx>.wkrow{ display:grid; grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);
  align-items:center; width:100%; }
.rr .rx>.wkrow>.wl{ justify-self:end; text-align:right; padding-right:.34em; min-width:0; }
.rr .rx>.wkrow>.we{ text-align:center; }
.rr .rx>.wkrow>.wr{ justify-self:start; text-align:left; padding-left:.34em; min-width:0; }

/* No vertical guide line here, deliberately. The first build drew one and it
   ran straight through the '=' glyph; with only the first row revealed it
   also read as a stray stub next to a single equation. The walk slides earn
   their guide because they are a tall centred stack - a three-row rulebox
   does not, and the alignment is self-evident once the rows are out.        */

/* PML-WKPIC-LG (11 Sep 2026): a walk picture that IS the point of the slide
   (a derivation drawn step by step) opts in to a bigger panel by carrying
   data-size="lg" on its <svg>. Additive: no older picture has it. */
.wkpic:has(> svg[data-size="lg"]){width:clamp(170px,32vw,300px);}
@media(min-width:701px){body.tighter .wkpic:has(> svg[data-size="lg"]){width:clamp(150px,28vw,250px);}}
@media(max-width:700px){.wkpic:has(> svg[data-size="lg"]){width:min(66vw,260px);}}
/* PML-WHYFIG: the picture inside an answer (why.fig), drawn before the working */
.whyfig{margin:4px 0 8px;}
.whyfig svg{display:block;margin:0 auto;}
