/* ==========================================================================
   PIPELINE CONTENT LAYER — ncerttextbooks.com (2026-07-10)
   Styles for every HTML element/class the content pipeline emits, audited
   from pipeline/cli.py + wp.py + gates.py + templates/. Scoped to article
   content; token-driven (uses main.css :root vars). Mobile-first (RULES §11):
   nothing here may cause page-level horizontal scroll.
   CONTRACT: any new pipeline-emitted class ships with a rule here in the
   same change — see the repo skill .claude/skills/front-design/SKILL.md.
   ========================================================================== */

/* ---------- Reading rhythm (readability law, RULES §2) ------------------- */
.ink-article-content {
  font-size: 1.02rem;
  line-height: 1.8;
}

.ink-article-content p {
  margin: 0 0 1.05em;
}

.ink-article-content h2 {
  margin: 0em 0 .7em;
  padding-top: .35em;
  line-height: 1.25;
  font-weight: 700;
  scroll-margin-top: 90px;
  /* TOC anchor jumps clear the sticky header */
}

/* 3.1.1 (owner 2026-08-18: "Use var(--v-orange) for stroke") — the rule under
   every article h2 is the same hand-drawn marker stroke the homepage uses.

   PAINTED AS A MASK, NOT AN IMAGE, and that is exactly why the owner's request is
   satisfiable. A data URI is a frozen string: you cannot write var(--v-orange)
   inside it, so an <svg> background would have hard-coded the colour and drifted
   the day the token changed. As a mask the SVG supplies only the SHAPE and the
   colour comes from CSS — so the stroke follows --v-orange for real, everywhere,
   forever.

   `#` is still percent-encoded (%23) or the browser reads it as a URL fragment and
   the mask silently fails — no error, just a heading with nothing under it.

   Sized 118x13 rather than the old 56x3 bar: a drawn stroke needs length to read
   as drawn. preserveAspectRatio='none' lets it stretch without redrawing the paths. */
.ink-article-content h2::after {
  content: "";
  display: block;
  width: 118px;
  height: 13px;
  margin-top: 6px;
  background: var(--v-orange, #f4523b);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 14' preserveAspectRatio='none'%3E%3Cpath d='M3 8C46 2 104 10 197 4' stroke='%23000' stroke-width='8' fill='none' stroke-linecap='round'/%3E%3Cpath d='M9 12C57 8 119 13 191 8' stroke='%23000' stroke-width='4' fill='none' stroke-linecap='round'/%3E%3C/svg%3E") no-repeat left center;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 14' preserveAspectRatio='none'%3E%3Cpath d='M3 8C46 2 104 10 197 4' stroke='%23000' stroke-width='8' fill='none' stroke-linecap='round'/%3E%3Cpath d='M9 12C57 8 119 13 191 8' stroke='%23000' stroke-width='4' fill='none' stroke-linecap='round'/%3E%3C/svg%3E") no-repeat left center;
  -webkit-mask-size: 100% 100%;
  mask-size: 100% 100%;
}

.ink-article-content h3 {
  margin: 1.5em 0 .5em;
  line-height: 1.3;
  font-weight: 700;
  scroll-margin-top: 90px;
}

.ink-article-content ul,
.ink-article-content ol {
  margin: 0 0 1.1em;
  padding-left: 1.35em;
}

.ink-article-content li {
  margin: .35em 0;
}

.ink-article-content li::marker {
  color: var(--primary);
  font-weight: 600;
}

/* ---------- BOLD DISCIPLINE (owner 2026-08-19) ---------------------------
   Bold marks a KEYWORD OR A FORMULA. It must never shout a paragraph.

   MEASURED BEFORE WRITING THIS, on /cbse-notes/class-12/chemistry/electrochemistry/:
   96 of 150 <strong> elements computed to font-weight 900, and 73% of the page's
   text blocks rendered bold. Nothing in this theme asks for 900 anywhere — the
   BROWSER default for <strong> is `bolder`, which is RELATIVE: inside text already
   at 700 it resolves to 900, and it compounds again on every nesting. An absolute
   weight ends that.

   AND EIGHT <strong> TAGS HAD SWALLOWED BLOCK CONTENT — 438 <td>, 181 <p>, 129
   <li>, 39 <h2> and 16 tables between them; the largest held 17,357 characters,
   over half the article. Those are UNCLOSED TAGS IN STORED CONTENT. A site-wide
   scan of all 508 pages found the defect on exactly three: page 2740 (10 unclosed),
   767 and 776 (one each). <strong> may only contain phrasing content, so a
   <strong> that is an ANCESTOR of a block element is broken markup by definition,
   and its block descendants render at normal weight. Note the direction: `td
   strong` (bold inside a cell) is untouched; only `strong … td` is.

   CSS ONLY, by owner's instruction — no page content is edited. That leaves the
   stray "}" characters those same pages show ("Resistivity \( \rho \)}") visible,
   because they are text, not markup. Repairing them is a content job.

   VERIFIED: on the broken page, bold text blocks 73% -> 0% while 141 keywords stay
   bold and none are lost; on four healthy pages nothing changes at all. */
.ink-article-content strong,
.ink-article-content b {
  color: var(--ink);
  font-weight: 600;
}

.ink-article-content strong :is(p, li, ul, ol, table, thead, tbody, tr, td, th,
                                div, section, blockquote),
.ink-article-content b :is(p, li, ul, ol, table, thead, tbody, tr, td, th,
                           div, section, blockquote) {
  font-weight: 400;
}

/* A heading a runaway <strong> reached keeps a heading's weight, not body weight. */
.ink-article-content strong :is(h1, h2, h3, h4, h5, h6),
.ink-article-content b :is(h1, h2, h3, h4, h5, h6) {
  font-weight: 700;
}

.ink-article-content img {
  max-width: 100%;
  height: auto;
  border-radius: var(--radius-sm);
}

/* ---------- Table of contents (<nav class="lcbse-toc ce-toc">) -----------
   OWNER DECISION 2026-07-10 (v2.2.1): the TOC keeps its PREVIOUS rendering —
   the v2.2.0 card restyle was reviewed and reverted. Do not restyle the TOC
   without an explicit owner request. */

/* ---------- Tables: scroll shell + data styling --------------------------
   Every content table sits inside .lcbse-table-scroll (pipeline emits it;
   functions.php normalizes strays) — the §11 no-horizontal-overflow law. */
.lcbse-table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  margin: var(--flow-box, 1.6em) 0;
  border-radius: var(--radius-sm);
}

.lcbse-table-scroll>table {
  margin: 0;
}

/* The blanket `min-width: 480px` that used to live here was removed in 2.9.6.
   MEASURED at phone width: it gave a 2-column table a 480px floor inside a
   457px shell, so a table that would have wrapped perfectly well was pushed
   into a sideways scroll it never needed. A floor that helps a 6-column matrix
   is not a floor that belongs on every table — the scroll tier now states its
   own width with `min-width: max-content`, and the other two tiers state none. */
.ink-article-content td {
  font-variant-numeric: tabular-nums;
}

/* Exam-footprint / weightage tables (PYQ + cluster stats) */
.lcbse-weightage thead th {
  background: var(--primary-l);
  color: var(--primary-d);
}

.lcbse-weightage tbody tr:hover {
  background: var(--surface);
}

/* NCERT-books chapter-PDF table (code-rendered from the verified registry) */
.lcbse-books thead th {
  background: var(--surface-2);
}

.lcbse-books td:first-child {
  font-weight: 600;
  white-space: nowrap;
}

.lcbse-books a {
  font-weight: 600;
}

/* ---------- PYQ year tag chip ("(CBSE 2024, Set 1, 3 marks)") ------------ */
.lcbse-pyq-tag {
  display: inline-block;
  font-family: "Spline Sans Mono", ui-monospace, monospace;
  font-size: .78rem;
  font-weight: 500;
  color: var(--primary-d);
  background: var(--primary-l);
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  padding: 2px 10px;
  margin: 0 0 .4em;
  white-space: nowrap;
}

/* ---------- Solution / answer blocks ------------------------------------- */
.icse-solution-answer,
.lcbse-solution-answer {
  background: var(--paper-card);
  border: 1px solid var(--line);
  border-left: 4px solid var(--accent);
  border-radius: var(--radius-sm);
  padding: 14px 18px;
  margin: .6em 0 1.6em;
}

.icse-solution-answer>p:first-child,
.lcbse-solution-answer>p:first-child {
  margin-top: 0;
}

.icse-solution-answer>p:last-child,
.lcbse-solution-answer>p:last-child {
  margin-bottom: 0;
}

/* ---------- FAQ accordions (<details class="lcbse-faq">) ------------------
   The pipeline emits lcbse-faq; icse-faq-item (older pages) stays aliased. */
details.lcbse-faq {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--paper-card);
  overflow: hidden;
  margin: 0 0 10px;
}

details.lcbse-faq>summary {
  list-style: none;
  cursor: pointer;
  padding: 14px 18px;
  color: var(--ink);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 44px;
  /* tap target */
}

details.lcbse-faq>summary::-webkit-details-marker {
  display: none;
}

details.lcbse-faq>summary::after {
  content: "+";
  font-size: 1.3rem;
  line-height: 1;
  color: var(--primary);
  transition: transform .2s;
  flex: none;
}

details.lcbse-faq[open]>summary {
  color: var(--primary-d);
  border-bottom: 1px solid var(--line);
}

details.lcbse-faq[open]>summary::after {
  transform: rotate(45deg);
}

details.lcbse-faq>*:not(summary) {
  padding: 0 18px;
}

details.lcbse-faq>p:last-child,
details.lcbse-faq>div:last-child {
  padding-bottom: 14px;
}

details.lcbse-faq>summary+* {
  padding-top: 12px;
}

/* ---------- Cluster / silo navigation footer ------------------------------
   <div class="lcbse-silo-nav"> — reverse chain, prev/next, related, cluster. */
/* ============================================================================
   SILO NAV v3 — QUIET ROWS (owner chose this from three samples, 2026-08-19)

   The block sits at the END of a ~3,000-word chapter, where the reader has
   already done a lot of scrolling, so its height is a real cost. Measured at
   360px across the three candidates: bento 992px, colour blocks 935px, these
   rows 794px — 1.1 phone screens against 1.4.

   WHY NOT THE BENTO the owner asked to see. A bento grid earns its unequal tiles
   when the tiles hold different KINDS of content — a number, a chart, an image.
   Every tile here holds two words ("Syllabus", "Formulas"), so varied sizes are
   decoration rather than information, and the tiles came out mostly empty.

   Structure still encodes direction of travel (§58): trail = quiet text, prev /
   next = arrowed rows, destinations = a chevroned list. No markup changes — the
   block is code-owned (§2), so every group is reached with structural selectors.
   ========================================================================== */
.lcbse-silo-nav {
  margin: 3em 0 0;
  padding: 18px 0 0;
  background: none;
  border: 0;
  border-top: 2px solid var(--ink);
  border-radius: 0;
}

.lcbse-silo-nav h2 {
  margin: 0 0 4px;
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--ink);
}

.lcbse-silo-nav h2::after { display: none; }

.lcbse-silo-nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* `.ink-article-content li+li` (main.css:2155) adds 6.5px above every item after
   the first — right for prose, wrong here: it breaks row rhythm and misaligns
   grid cells. That rule is (0,1,2), so this reset must match it or it silently
   loses (§54, §58). */
.lcbse-silo-nav ul li,
.lcbse-silo-nav ul li + li { margin: 0; }

/* ── 1. TRAIL — where you are. Text, not chips; it must not compete. ─────── */
.lcbse-silo-nav > ul:first-of-type {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 10px;
  margin: 0 0 18px;
}

.lcbse-silo-nav > ul:first-of-type li { display: flex; align-items: center; }

.lcbse-silo-nav > ul:first-of-type li + li::before {
  content: "\00B7";
  margin-right: 10px;
  color: var(--muted);
}

.lcbse-silo-nav > ul:first-of-type a,
.lcbse-silo-nav > ul:first-of-type span[data-lcbse-pending-link] {
  font-size: .78rem;
  color: var(--muted);
  text-decoration: none;
}

.lcbse-silo-nav > ul:first-of-type a:hover {
  color: var(--primary-d);
  text-decoration: underline;
}

/* ── 2. STEPS — previous / next chapter, the likeliest move from a chapter. ─ */
.lcbse-silo-nav > ul:first-of-type + ul {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 24px;
  margin: 0 0 8px;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.lcbse-silo-nav > ul:first-of-type + ul li { display: flex; }

.lcbse-silo-nav > ul:first-of-type + ul a,
.lcbse-silo-nav > ul:first-of-type + ul span[data-lcbse-pending-link] {
  flex: 1;
  display: flex;
  align-items: center;
  min-height: 56px;                     /* thumb target */
  font-size: .92rem;
  font-weight: 600;
  color: var(--primary-d);
  text-decoration: none;
}

/* Direction is real information, so it is drawn. `:not(:only-child)` keeps a
   lone row (chapter 1 has no previous) from claiming to be both. */
.lcbse-silo-nav > ul:first-of-type + ul li:first-child:not(:only-child) a::before { content: "\2190"; }
.lcbse-silo-nav > ul:first-of-type + ul li:last-child a::before,
.lcbse-silo-nav > ul:first-of-type + ul li:only-child a::before { content: "\2192"; }

.lcbse-silo-nav > ul:first-of-type + ul a::before {
  margin-right: 10px;
  color: var(--muted);
  font-weight: 400;
}

.lcbse-silo-nav > ul:first-of-type + ul span[data-lcbse-pending-link] { color: var(--muted); }

/* ── 3. DESTINATIONS — a chevroned list, two columns where there is room. ── */
/* THE LABEL IS TEXT, THE ROW IS A LINK, SO THEY MUST NOT SHARE A COLOUR
   (owner 2026-08-19). Measured live before the change: the label rendered
   #5f42c8 and the row beneath it #7b5cf0 — two shades of the same purple, so the
   only thing separating a heading from a destination was letter-spacing. Labels
   are now --ink; links keep the article's purple below. */
.lcbse-silo-nav p {
  margin: 22px 0 2px;
  font-family: var(--font-display);
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink);
}

.lcbse-silo-nav > p + ul {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 24px;
}

.lcbse-silo-nav > p + ul li {
  display: flex;
  border-bottom: 1px solid var(--line);
}

.lcbse-silo-nav > p + ul a,
.lcbse-silo-nav > p + ul span[data-lcbse-pending-link] {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 52px;                     /* thumb target */
  padding: 8px 2px;
  font-size: .92rem;
  font-weight: 500;
  line-height: 1.4;
  text-decoration: none;
  transition: color .15s ease;
}

/* NO COLOUR DECLARED ON PURPOSE. `.ink-article-content a` (main.css:2140) paints
   every article link --primary, and this block sits inside that container — an
   earlier `color: var(--ink)` here never applied and merely looked like it did.
   Rows stay the article's link colour; the LABEL above them carries --ink. */

.lcbse-silo-nav > p + ul a::after {
  content: "\203A";
  flex: none;
  font-size: 1.3rem;
  line-height: 1;
  color: var(--muted);
}

.lcbse-silo-nav > p + ul a:hover { color: var(--primary-d); }
.lcbse-silo-nav > p + ul a:hover::after { color: var(--primary); }

.lcbse-silo-nav > p + ul span[data-lcbse-pending-link] { color: var(--muted); }

.lcbse-silo-nav a:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

@media (max-width: 640px) {
  .lcbse-silo-nav > p + ul,
  .lcbse-silo-nav > ul:first-of-type + ul { grid-template-columns: 1fr; }

  .lcbse-silo-nav > ul:first-of-type + ul li + li { border-top: 1px solid var(--line); }
}

@media (prefers-reduced-motion: reduce) {
  .lcbse-silo-nav a { transition: none; }
}

/* ---------- Figures + MathJax (overflow-safe, §11) ------------------------ */
.ink-article-content figure {
  margin: var(--flow-box) 0;
  text-align: center;
}

.ink-article-content figcaption {
  font-size: .86rem;
  color: var(--muted);
  margin-top: 8px;
}

mjx-container {
  max-width: 100%;
  overflow-x: auto;
  overflow-y: hidden;
}

mjx-container[display="true"] {
  padding: 4px 0;
}

/* ---------- Generic details inside content (not FAQ, not theme UI) -------- */
.ink-article-content details:not(.lcbse-faq):not([class]) {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 10px 14px;
  margin: 0 0 1em;
  background: var(--paper-card);
}

/* ---------- Mobile refinements (§11: phone first) -------------------------- */
@media (max-width: 640px) {
  .ink-article-content {
    font-size: 1rem;
  }

  .ink-article-content table {
    font-size: .9rem;
  }

  .ink-article-content th,
  .ink-article-content td {
    padding: 9px 10px;
  }

  /* The full-width CENTRED chip belonged to the flat-pill design (pre-3.1.7).
     The block is now a card grid that sets its own phone layout at 480px, and a
     centred label inside a left-aligned card reads as a mistake. Removed rather
     than overridden, so there is one rule for this, not two that fight. */
}

@media (prefers-reduced-motion: reduce) {
  details.lcbse-faq>summary::after {
    transition: none;
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   NCERT SOLUTIONS — question / answer presentation      (added 2026-07-29)

   Styles the markup the pipeline ALREADY emits, so every existing solutions
   page is restyled with no regeneration and no content change:

     <h3>Question 1: …</h3>
     <div class="icse-solution">
       <p class="icse-solution-step">   <strong>Concept:</strong> …   <- FIRST
       <p class="icse-solution-step">   <strong>Step 1:</strong>  …
       <p class="icse-solution-answer"> <strong>Final answer:</strong> …
       <p class="icse-solution-step">   <strong>Common error:</strong> … <- LAST
     </div>

   Concept and Common error share one class with the steps, so they are
   selected structurally. VERIFIED on live page 1570 across all 45 blocks:
   Concept is first in 45/45; Common error is last in 44/45 (the 45th has no
   Common error, and there the last child carries .icse-solution-answer, so the
   :last-child rule correctly matches nothing).

   Tokens only — no new palette. Semantic colour is kept OFF the brand accent:
   green --accent for the answer, amber --marker for the error, so neither is
   confused with vermillion. Mobile-first per RULES §11.
   ═══════════════════════════════════════════════════════════════════════ */

/* --- the question ---------------------------------------------------- */
/* THE QUESTION HEADER. `.lcbse-q` is stamped on every "Question N…" heading by
   the pipeline (mark_question_headings), so the style depends on WHAT THE
   HEADING IS rather than on what happens to follow it.

   The `:has(+ .icse-solution)` form is kept for pages published before the class
   existed, but it can never be the primary rule: it matched 0 of 34 questions on
   the 2026-08-04 rebuild, because a multi-part question correctly renders its
   parts — and often a figure — between the heading and the solution, which
   breaks the adjacent-sibling relationship the selector needs. */
.ink-article-content h3.lcbse-q,
.ink-article-content h3:has(+ .icse-solution) {
  margin: 2.2em 0 0;
  padding: 14px 18px 13px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-bottom: 0;
  border-radius: var(--radius) var(--radius) 0 0;
  font-size: 1.06rem;
  line-height: 1.4;
}

/* --- the answer card ------------------------------------------------- */
/* Padding uses the 2.9.11 content scale (fallbacks keep it correct if a
   `.icse-solution` ever renders outside `.ink-article-content`, where the
   tokens are not defined). It was 18px all round — the odd one out against
   every other box on the page. */
.icse-solution {
  background: var(--paper-card);
  border: 1px solid var(--line);
  border-radius: 0 0 var(--radius) var(--radius);
  padding: var(--box-pad-y, 16px) var(--box-pad-x, 20px);
  margin: 0 0 10px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* a solution that somehow has no heading above it still reads as a card */
.icse-solution:first-child {
  border-radius: var(--radius);
}

.icse-solution>p {
  margin: 0;
}

/* label chips: "Concept:", "Step 1:", "Final answer:", "Common error:" */
.icse-solution>p>strong:first-child {
  color: var(--primary-d);
  font-weight: 600;
}

/* --- CONCEPT (always the first child) -------------------------------- */
.icse-solution>p.icse-solution-step:first-child {
  padding: 12px 14px;
  background: var(--bg);
  border-radius: var(--radius-sm);
}

.icse-solution>p.icse-solution-step:first-child>strong:first-child {
  font-size: .72rem;
  letter-spacing: .12em;
  margin-bottom: 4px;
  color: var(--primary-d);
}

/* --- STEPS ----------------------------------------------------------- */
.icse-solution>p.icse-solution-step {
  padding-left: 2px;
  line-height: 1.62;
}

.icse-solution>p.icse-solution-step>strong:first-child {
  display: inline-block;
  min-width: 4.2em;
  color: var(--ink);
}

/* --- FINAL ANSWER ---------------------------------------------------- */
.icse-solution>p.icse-solution-answer {
  padding: 14px 16px;
  /* tint of --accent, not the accent */
  font-weight: 500;
}

.icse-solution>p.icse-solution-answer>strong:first-child {
  display: block;
  font-size: .72rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  margin-bottom: 5px;
  color: #3d6349;
}

/* --- COMMON ERROR (always the last child) ---------------------------- */
.icse-solution>p.icse-solution-step:last-child {
  padding: 13px 16px;
  background: #fdf6e6;
  /* tint of --marker */
  border: 1px solid #efdcb0;
  border-left: 4px solid var(--marker);
  border-radius: var(--radius-sm);
  color: var(--ink);
}

.icse-solution>p.icse-solution-step:last-child>strong:first-child {
  display: block;
  min-width: 0;
  font-size: .72rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  margin-bottom: 4px;
  color: #8a6410;
}

/* --- maths inside a solution ----------------------------------------- */
.icse-solution .icse-solution-math,
.icse-solution p:has(> .MathJax) {
  overflow-x: auto;
  /* RULES §11: never scroll the page */
  -webkit-overflow-scrolling: touch;
}

/* --- phones ----------------------------------------------------------- */
@media (max-width: 600px) {

  .ink-article-content h3.lcbse-q,
  .ink-article-content h3:has(+ .icse-solution) {
    padding: 12px 14px;
    font-size: 1rem;
  }

  .icse-solution {
    padding: 14px;
    gap: 10px;
  }

  .icse-solution>p.icse-solution-step>strong:first-child {
    min-width: 0;
  }
}

/* --- browsers without :has() ------------------------------------------
   The question heading simply keeps its default look; the answer card,
   final-answer and common-error styling above are all plain selectors and
   still apply. Nothing is lost, only the heading's joined-card effect. */

/* --- numbered steps ---------------------------------------------------
   The pipeline now emits a real ordered list for a run of "Step N:"
   paragraphs (gates.group_solution_steps), so the browser owns the
   numbering and each step gets a circular badge.

   The literal "Step 1:" text is kept in .lcbse-step__label and hidden
   visually — the badge already says it. The span exists ONLY on genuine
   steps, so hiding it can never swallow a real label like "(a) Corrosion"
   or "Example:", which stay ordinary paragraphs. Screen readers and search
   engines still receive the words.                       (2026-07-29) */
.icse-solution .lcbse-steps {
  list-style: none;
  counter-reset: lcbse-step;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 11px;
}

.icse-solution .lcbse-steps>li.lcbse-step {
  counter-increment: lcbse-step;
  display: grid;
  grid-template-columns: 28px 1fr;
  gap: 12px;
  align-items: start;
  line-height: 1.62;
  margin: 0;
}

.icse-solution .lcbse-steps>li.lcbse-step::before {
  content: counter(lcbse-step);
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--primary);
  color: #fff;
  font-size: .82rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  display: grid;
  place-items: center;
  flex: none;
  margin-top: 1px;
}

/* the words stay in the HTML, out of sight */
.icse-solution .lcbse-step__label {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* display math inside a step must scroll in its own box (RULES §11) */
.icse-solution .lcbse-steps>li.lcbse-step>.MathJax_Display,
.icse-solution .lcbse-steps>li.lcbse-step mjx-container[display="true"] {
  overflow-x: auto;
  overflow-y: hidden;
  max-width: 100%;
}

@media (max-width: 600px) {
  .icse-solution .lcbse-steps>li.lcbse-step {
    grid-template-columns: 24px 1fr;
    gap: 10px;
  }

  .icse-solution .lcbse-steps>li.lcbse-step::before {
    width: 24px;
    height: 24px;
    font-size: .76rem;
  }
}

/* --- FIX 2026-07-29: step badges must not use grid ---------------------
   The first version put `display:grid; grid-template-columns:28px 1fr` on
   li.lcbse-step. A grid container makes EVERY child element a grid ITEM, so
   inline children were torn out of the text flow and dropped into cells:
     · <strong>magnesium oxide</strong> jumped into the badge column and
       overlapped the following words
     · MathJax <mjx-container> for \(H_2\), \(CuO\), \(BaCl_2\) landed on its
       own row, leaving a stray "." behind and wrapping the sentence one word
       per line
   The badge is decoration, so it is positioned OUT of flow and the content
   keeps ordinary inline layout — strong, math, links and all.
   These rules come after the originals, so they win on equal specificity. */
.icse-solution .lcbse-steps>li.lcbse-step {
  display: block;
  /* undo grid */
  grid-template-columns: none;
  position: relative;
  padding-left: 40px;
  min-height: 28px;
  gap: 0;
}

.icse-solution .lcbse-steps>li.lcbse-step::before {
  position: absolute;
  left: 0;
  top: 0.1em;
  margin-top: 0;
}

/* inline maths sits on the text baseline and never forces a line break */
.icse-solution .lcbse-steps>li.lcbse-step mjx-container[display="false"],
.icse-solution .lcbse-steps>li.lcbse-step mjx-container:not([display="true"]) {
  display: inline-block;
  vertical-align: baseline;
  margin: 0 .12em;
}

/* display maths gets its own scrollable line (RULES §11) */
.icse-solution .lcbse-steps>li.lcbse-step mjx-container[display="true"] {
  display: block;
  margin: .55em 0;
  overflow-x: auto;
  overflow-y: hidden;
  max-width: 100%;
}

/* the same guarantee for maths anywhere else in a solution */
.icse-solution mjx-container[display="true"] {
  overflow-x: auto;
  overflow-y: hidden;
  max-width: 100%;
}

.icse-solution mjx-container:not([display="true"]) {
  display: inline-block;
  vertical-align: baseline;
}

@media (max-width: 600px) {
  .icse-solution .lcbse-steps>li.lcbse-step {
    padding-left: 34px;
    grid-template-columns: none;
  }
}

/* ---------- Table of contents (<nav class="lcbse-toc">) -----------------
   OWNER REQUEST 2026-07-29 — this is the "explicit owner request" the
   2026-07-10 note required before restyling. Deliberately RESTRAINED: the
   v2.2.0 attempt was a heavy card and the owner reverted it, so this keeps
   the list feeling like part of the article — a quiet panel, a small label,
   and links that read as links. No shadow, no big radius, no hero treatment.

   The pipeline emits <nav class="lcbse-toc"><ul><li><a href="#id">…</a>.
   Until now the theme had a comment here but NO rules, so it rendered as a
   bare bulleted list.                                                     */
/* ═══════════════════════════════════════════════════════════════════════
   READING RHYTHM — ONE SPACING SCALE FOR EVERY CONTENT BOX
                                             (2.9.11, owner audit 2026-08-17)

   Owner: "we are working to provide best reading experience to the students,
   teacher and parents … margins, spacing need to be adjusted — we need
   professional audit for all classes we use."

   AUDITED, NOT GUESSED. Computed styles were read off 8 live pages spanning
   classes 9, 10 and 11 across /cbse-notes/, /important-questions/,
   /mcq-questions/ and /ncert-solutions/. The corpus had drifted into:

     FIVE box paddings      16 18 14 18 · 18 20 18 20 · 16 20 16 20
                            14 20 13 20 · 12 14 12 14
     SEVEN vertical gaps    19.6 · 21.2 · 26.1 · 30.7 · 32.6 · 35.9 · 37.3 px

   Nothing was individually wrong; together they read as drift, because a
   student scrolling one page meets four differently-inset boxes and four
   different gaps between them. These two tokens replace the guesswork. They
   are declared on `.ink-article-content` rather than `:root` so this is a
   CONTENT-typography scale and cannot leak into the theme chrome (header,
   rails, cards on the home page).

     --box-pad-y / --box-pad-x   inside any bordered content box
     --flow-box                  above and below any bordered content box

   Values are the ones already dominant in the corpus (16/20 padding, 1.6em
   flow), so the majority of boxes do not move at all — the outliers come to
   them. The QA card keeps a LARGER top gap on purpose: it separates one
   question from the next, which is a stronger boundary than the gap between a
   paragraph and a table.
   ═══════════════════════════════════════════════════════════════════════ */
.ink-article-content {
  --box-pad-y: 16px;
  --box-pad-x: 20px;
  --flow-box: 1.6em;
}

@media (max-width: 640px) {
  .ink-article-content {
    --box-pad-y: 14px;
    --box-pad-x: 15px;
  }
}

.ink-article-content .lcbse-toc {
  margin: var(--flow-box) 0 2em;
  padding: var(--box-pad-y) var(--box-pad-x);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}

/* a small label so the block announces itself without needing a heading */
.ink-article-content .lcbse-toc::before {
  content: "On this page";
  display: block;
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--primary-d);
  margin-bottom: 10px;
}

.ink-article-content .lcbse-toc ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 2px;
}

.ink-article-content .lcbse-toc li {
  margin: 0;
}

.ink-article-content .lcbse-toc a {
  display: block;
  padding: 7px 10px 7px 22px;
  border-radius: var(--radius-sm);
  color: var(--ink);
  text-decoration: none;
  font-size: .95rem;
  line-height: 1.45;
  position: relative;
  transition: background .15s, color .15s;
}

.ink-article-content .lcbse-toc a::before {
  content: "";
  position: absolute;
  left: 8px;
  top: .95em;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--primary);
  opacity: .55;
}

.ink-article-content .lcbse-toc a:hover,
.ink-article-content .lcbse-toc a:focus-visible {
  background: var(--paper-card);
  color: var(--primary-d);
}

.ink-article-content .lcbse-toc a:hover::before {
  opacity: 1;
}

/* two columns once there is room — a 12-item list is a tall wall on desktop */
@media (min-width: 720px) {
  .ink-article-content .lcbse-toc ul {
    grid-template-columns: 1fr 1fr;
    column-gap: 14px;
  }
}

/* the heading you jump to should not hide under a sticky header */
.ink-article-content h2[id] {
  scroll-margin-top: 90px;
}

/* ==========================================================================
   SOLUTIONS RAIL — sticky group on desktop, collapsible panel on mobile
   (owner 2026-07-30). Scoped to `.lcbse-silo-ncert-solutions` on purpose: the
   behaviour is proven on one content type before it is extended to the rest.
   To roll out, add the silo class to each selector list below — the markup and
   the JS are already global, so no PHP changes are needed.

   The CARD styling is deliberately NOT redefined here. main.css already renders
   the "◆ RELATED" eyebrow with its rule, the orange numbered list and the
   bordered arrow rows — i.e. the reference design is already live. Restating
   those rules would fork one design into two places that then drift.
   ========================================================================== */

/* The <summary> is a mobile control. On desktop it must not exist visually —
   `display: none` on it, while <details> stays open, makes the wrapper inert. */
.ink-rail-panel>.ink-rail-panel__toggle {
  display: none;
}

.ink-rail-panel {
  border: 0;
  margin: 0;
  padding: 0;
}

/* 3.1.5 — THE TAP BAR IS UNSCOPED, BECAUSE THE RULE THAT HIDES IT ALWAYS WAS.
   `.ink-rail-panel > .ink-rail-panel__toggle { display: none }` above applies to
   EVERY page at EVERY width. Until 3.1.4 the panel shipped `open`, so a hidden
   summary was harmless — an inert wrapper. 3.1.4 removed `open`, and on any page
   whose body carried neither `.ink-silo-tpl` nor `.lcbse-silo-ncert-solutions`
   (i.e. every ordinary page and every post, via page.php / single.php) the phone
   layout became a closed <details> with its only control painted out: measured
   0px of sidebar, unreachable. Restoring the control must therefore be as global
   as hiding it. Specificity is the trap here — a bare `.ink-rail-panel__toggle`
   is (0,1,0) and LOSES to the (0,2,0) hide rule, so the child combinator stays.
   The LAYOUT rules further down remain scoped to the solutions silo on purpose:
   panel-above-article ordering is a content-type choice, the control is not. */
@media (max-width: 767px) {

  .ink-rail-panel > .ink-rail-panel__toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    cursor: pointer;
    list-style: none;
    padding: 13px 16px;
    border: 1px solid var(--line);
    border-radius: 12px;
    background: var(--paper-card);
    color: var(--ink);
    font-size: .82rem;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
  }

  /* Safari/iOS draws its own disclosure triangle on the summary marker. */
  .ink-rail-panel .ink-rail-panel__toggle::-webkit-details-marker {
    display: none;
  }

  .ink-rail-panel .ink-rail-panel__label::before {
    content: "◆";
    color: var(--verm);
    margin-right: 8px;
    font-size: .72em;
    vertical-align: 1px;
  }

  /* Chevron rotates to point down when the panel is open — the state has to be
     readable at a glance, not only from whether cards are visible. */
  .ink-rail-panel .ink-rail-panel__chev {
    width: 9px;
    height: 9px;
    flex: none;
    border-right: 2px solid var(--verm);
    border-bottom: 2px solid var(--verm);
    transform: rotate(-45deg);
    transition: transform .2s ease;
  }

  .ink-rail-panel[open] .ink-rail-panel__chev {
    transform: rotate(45deg);
  }

  .ink-rail-panel[open] > .ink-rail-panel__toggle {
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
    border-bottom-color: transparent;
  }

  .ink-rail-panel[open] > .ink-rail-panel__body {
    border: 1px solid var(--line);
    border-top: 0;
    border-radius: 0 0 12px 12px;
    padding: 16px 14px 2px;
  }

  /* PANEL ABOVE THE ARTICLE. main.css puts the content first on small screens
     (`.ink-article-content { order: -1 }`); solutions pages invert that, so the
     specificity here has to beat it — hence the silo class on both selectors. */
  .lcbse-silo-ncert-solutions .ink-article-layout.has-left .ink-article-content,
  .lcbse-silo-ncert-solutions .ink-article-layout.has-right .ink-article-content {
    order: 0;
  }

  .lcbse-silo-ncert-solutions .ink-article-left,
  .lcbse-silo-ncert-solutions .ink-article-aside {
    order: -1;
    margin-top: 0;
    margin-bottom: 22px;
  }

  /* Sticky is wrong for a collapsed bar at the top of a scroll — it would pin a
     control the reader has already passed. */
  .lcbse-silo-ncert-solutions .ink-aside-sticky {
    position: static;
  }

  /* A collapsed panel must not reserve the open panel's card margins. */
  .lcbse-silo-ncert-solutions .ink-rail-panel:not([open]) .ink-rail-card:last-child,
  .lcbse-silo-ncert-solutions .ink-rail-panel .ink-rail-card:last-child {
    margin-bottom: 0;
  }
}

/* NO HORIZONTAL OVERFLOW. A grid/flex child defaults to min-width:auto, so one
   long unbroken string (a URL in a Related title, a wide table) can push the
   whole column past the viewport and scroll the BODY sideways. Every wrapper in
   the rail chain is pinned to min-width:0, and long link text is allowed to
   break rather than force the column wider. */
.ink-article-left,
.ink-article-aside,
.ink-rail-panel,
.ink-rail-panel__body,
.ink-rail-stack,
.ink-rail-card,
.ink-rail-list,
.ink-tool-links {
  min-width: 0;
}

.ink-rail-list li,
.ink-rail-list a,
.ink-tool-links a {
  min-width: 0;
  overflow-wrap: anywhere;
}

.ink-rail-stack {
  display: block;
}

/* ==========================================================================
   LONG-TOKEN OVERFLOW GUARD (measured 2026-07-30, headless Chrome at 320/375/
   414px). A single unbreakable token — a bare URL, a long chemical name, an
   OCR'd filename — sets a MINIMUM width on its container, which stretches the
   article column past the viewport and scrolls the whole BODY sideways. It was
   reproducible at 637px of content inside a 305px viewport, on every content
   type, so this is deliberately GLOBAL and not scoped to one silo: the theme's
   own table shell already states horizontal overflow is forbidden site-wide
   (functions.php, inkline_wrap_content_tables).

   `break-word` for prose so normal words still wrap on word boundaries;
   `anywhere` for links, where a 100-character URL has no boundary to use. */
.ink-article-content {
  overflow-wrap: break-word;
}

.ink-article-content a,
.ink-article-content code,
.ink-article-content li {
  overflow-wrap: anywhere;
}

/* ==========================================================================
   CHAPTER PDF DOWNLOAD BOX — rendered by gates.ensure_pdf_download inside
   lcbse:block markers. Uses the theme's own tokens so it reads as part of the
   page, not a bolted-on advert.
   ========================================================================== */
.ink-article-content .lcbse-pdf-dl {
  margin: 26px 0;
  padding: 20px 22px;
  background: var(--paper-card);
  border: 1px solid var(--line);
  border-left: 3px solid var(--verm);
  border-radius: 14px;
}

.ink-article-content .lcbse-pdf-dl__eyebrow {
  margin: 0 0 6px;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--verm);
}

.ink-article-content .lcbse-pdf-dl__title {
  margin: 0 0 8px;
  font-size: 1.12rem;
  line-height: 1.3;
  border: 0;
  padding: 0;
}

.ink-article-content .lcbse-pdf-dl__body {
  margin: 0 0 14px;
  font-size: .95rem;
  color: var(--muted);
}

.ink-article-content .lcbse-pdf-dl__cta {
  margin: 0;
}

/* SPECIFICITY, not source order, decides this one. main.css:784 carries
   `.ink-editorial .ink-article-content a { color: var(--verm) }` — two classes
   plus an element type, which outranks two classes alone however late this file
   loads. The first version of this rule lost that fight and painted the label
   the same orange as its own background: a solid slab with a correct, unreadable
   caption. Nothing automated could catch it (contrast is not a gate); it showed
   up only in a rendered screenshot. Hence `a.lcbse-pdf-dl__btn` nested under the
   block — three classes plus an element, which wins without depending on the
   `.ink-editorial` body class. */
.ink-article-content .lcbse-pdf-dl a.lcbse-pdf-dl__btn {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 12px 20px;
  border-radius: 10px;
  background: var(--verm);
  color: #fff;
  font-weight: 700;
  font-size: .95rem;
  text-decoration: none;
  overflow-wrap: anywhere;
}

.ink-article-content .lcbse-pdf-dl a.lcbse-pdf-dl__btn::before {
  content: "\2913";
  font-size: 1.05em;
  line-height: 1;
}

.ink-article-content .lcbse-pdf-dl a.lcbse-pdf-dl__btn:hover,
.ink-article-content .lcbse-pdf-dl a.lcbse-pdf-dl__btn:focus-visible {
  background: var(--verm-deep);
  color: #fff;
}

/* ==========================================================================
   THE TABLE SHELL COULD NOT ACTUALLY SCROLL (measured 2026-07-30, Chrome at
   320px). `.lcbse-table-scroll` has had `overflow-x: auto` all along, yet a
   wide table still scrolled the whole PAGE sideways on phones. The shell was
   not the problem — its WIDTH was: at <=999px the article layout is
   `display: flex; flex-direction: column`, so `.ink-article-content` is a flex
   item, and a flex item's default `min-width: auto` forbids shrinking below its
   min-content width. An 8-column table therefore set the column to 617px inside
   a 320px viewport, and `overflow-x: auto` on a box that is already wider than
   the screen has nothing to clip.

   `min-width: 0` on the chain is what lets the shell do the job it was written
   for. This is why the guard has to be MEASURED and not reasoned about — the
   rule that was supposed to prevent this was present, correct, and inert.
   ========================================================================== */
.ink-article-layout>*,
.ink-article-content {
  min-width: 0;
}

.ink-article-content .lcbse-table-scroll {
  min-width: 0;
  max-width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* Inside a SCROLLING shell the table keeps its natural width — that is the
   point. It must not be squeezed into an unreadable column.
   Scoped to [data-mode="scroll"] in 2.9.6: applied to every table it forced a
   2-column table that would have wrapped happily into a needless sideways
   scroll. Only the tables the classifier sends to the scroll tier want it. */
.ink-article-content .lcbse-table-scroll[data-mode="scroll"]>table {
  min-width: max-content;
}

/* MathJax display blocks are the other known wide element (RULES §11). */
.ink-article-content mjx-container[display="true"] {
  max-width: 100%;
  overflow-x: auto;
  overflow-y: hidden;
}

/* THE FIX THAT ACTUALLY WORKED (measured, after two that did not).
   `min-width: 0` governs MAIN-axis shrinking. Below 1000px the article layout is
   `flex-direction: column`, so width is the CROSS axis — a different sizing path
   that min-width does not control. With the table shell asking for `max-width:
   100%` of a parent whose own width was still being derived from its content,
   the browser resolved the circularity using max-content and gave the column
   820px inside a 305px parent.
   Binding the column to its parent with an explicit `width: 100%` removes the
   circularity: the parent is already correctly constrained to the viewport, so
   every descendant now has a definite width to resolve percentages against. */
@media (max-width: 999px) {

  .ink-article-layout.has-left>.ink-article-content,
  .ink-article-layout.has-right>.ink-article-content {
    width: 100%;
  }

  .ink-article-layout.has-left>.ink-article-left,
  .ink-article-layout.has-left>.ink-article-aside,
  .ink-article-layout.has-right>.ink-article-left,
  .ink-article-layout.has-right>.ink-article-aside {
    width: 100%;
  }
}

/* ==========================================================================
   ARTICLE HEADER IS NOW A LAYOUT ITEM (owner-reported 2026-07-30).
   page.php / single.php moved <header class="ink-article-head"> out of
   .ink-article-content so the mobile order can be TITLE -> panel -> body. That
   makes three grid items where there were two, and auto-placement would put the
   content in column 1 underneath the rail. Every position is therefore explicit.

   GLOBAL, not silo-scoped: the markup change affects every page and post, so the
   placement rules must too. Only the mobile ORDER stays scoped to solutions.
   ========================================================================== */
@media (min-width: 1000px) {

  .ink-article-layout.has-left,
  .ink-article-layout.has-right,
  .ink-article-layout.has-left.has-right {
    row-gap: 0;
  }

  .ink-article-layout.has-left>.ink-article-head,
  .ink-article-layout.has-left>.ink-article-content {
    grid-column: 2;
  }

  .ink-article-layout.has-left>.ink-article-left {
    grid-column: 1;
    grid-row: 1 / span 2;
  }

  .ink-article-layout.has-right>.ink-article-head,
  .ink-article-layout.has-right>.ink-article-content {
    grid-column: 1;
  }

  .ink-article-layout.has-right>.ink-article-aside {
    grid-column: 2;
    grid-row: 1 / span 2;
  }

  .ink-article-layout.has-left.has-right>.ink-article-head,
  .ink-article-layout.has-left.has-right>.ink-article-content {
    grid-column: 2;
  }

  .ink-article-layout.has-left.has-right>.ink-article-left {
    grid-column: 1;
    grid-row: 1 / span 2;
  }

  .ink-article-layout.has-left.has-right>.ink-article-aside {
    grid-column: 3;
    grid-row: 1 / span 2;
  }

  /* The header used to inherit the content column's width rules by being inside
     it; as a sibling it needs them itself, or the title would center to 820px
     while the prose below it starts at the column edge. */
  .ink-article-layout.has-left>.ink-article-head,
  .ink-article-layout.has-right>.ink-article-head {
    margin-inline: 0;
    max-width: none;
  }
}

/* No-sidebar pages: the header must stay aligned with the 820px prose column. */
.ink-article-layout>.ink-article-head {
  max-width: 820px;
  margin-inline: auto;
}

@media (max-width: 767px) {

  /* TITLE FIRST, EVERYWHERE — and this rule must NOT be silo-scoped.
     main.css carries `.ink-article-content { order: -1 }` for small screens,
     which was correct while the <h1> lived INSIDE that container. Now that the
     header is a sibling, that same rule renders the article BODY above the
     TITLE on every page type that has no order of its own. Measured on a
     control page (lcbse-silo-cbse-notes) at 320/375/768 before it shipped:
     the markup change is global, so its ordering fix has to be global too. */
  .ink-article-layout>.ink-article-head {
    order: -2;
    width: 100%;
  }

  /* Superseded for silo pages by the SILO PAGES map below (which covers all
     three silos); kept for any non-silo page that still uses the old rail. */
  .lcbse-silo-ncert-solutions .ink-article-layout>.ink-article-left,
  .lcbse-silo-ncert-solutions .ink-article-layout>.ink-article-aside {
    order: -1;
  }
}


/* (The per-silo 768-999 rail block that lived here is superseded by the
   SILO PAGES map further down, which covers all three silos in one place.) */

/* ==========================================================================
   HEADER OVERFLOW — the real cause of horizontal scroll on tablets and small
   laptops, and nothing to do with the sidebar (measured 2026-07-30).
   main.css swaps the inline nav for the burger only below 920px, but the header
   needs brand 182 + nav 802 + actions 42 + 40 padding = ~1066px to fit. So every
   viewport from 921px to ~1080px — including iPad landscape at 1024 — scrolled
   sideways. Overridden here rather than in main.css so the change is additive
   and trivially revertible.

   RE-MEASURED 2026-08-18, AND THE OLD NUMBER HAD GONE STALE. The header now needs
   ~1191px, not ~1066px: it gained menu items and Poppins sets wider than the face
   it replaced. So 1100px-1191px had started scrolling sideways again — a band that
   includes very common laptop widths. Measured, not guessed: at 1099px the burger
   shows and the page is clean; at 1100px the inline nav appears and the document
   is 1191px wide inside 1085px. Raised again the same session: 1199px was still a
   step short — at a 1200px viewport the scrollbar leaves 1185px of client width
   and the nav wants 1203px, so the true cutover is ~1218px. Set to 1229px, which
   keeps a small margin and still gives every 1280px laptop the inline nav.

   A BREAKPOINT DERIVED FROM A MEASUREMENT IS ONLY TRUE ON THE DAY IT IS TAKEN.
   Anything that changes the header's contents or its typeface moves this number,
   and nothing warns you — re-measure whenever either changes.
   ========================================================================== */
@media (max-width: 1259px) {
  .ink-nav {
    display: none;
  }

  .ink-burger {
    display: inline-flex;
  }
}

/* At the very narrowest widths the action buttons' own gap pushed 5px past the
   edge (310 vs 305 measured at 320px). */
@media (max-width: 360px) {
  .ink-header-actions {
    gap: 2px;
  }

  .ink-wrap {
    padding-inline: 14px;
  }
}


/* ==========================================================================
   SILO PAGES — level-aware left rail + article, on every device
   (owner 2026-07-30). Applies to /ncert-solutions/, /ncert-books/ and
   /cbse-notes/ alike: the body class `ink-silo-tpl` is added by inc/silo.php
   from ANCESTRY, so it covers pages the pipeline creates later with no template
   assignment and no CSS change.

   NO RIGHT RAIL. An earlier three-column version was measured and abandoned:
   inside the 1160px wrap it left the article 544px wide at every viewport from
   1280 to 1920 — down from 810px — which is too tight for multi-step worked
   answers. Two columns keep the reading width.

   COLUMN MAP, measured at real device widths:
     <= 767   stacked: title, then the rail as a COLLAPSIBLE panel, then article
     768-999  side rail 210px + 26px gutter   (every iPad portrait width)
     >= 1000  side rail 262px + 40px gutter
   The rail is sticky in both side-rail bands; its <summary> toggle exists only
   below 768. The JS breakpoint in inc/theme-options.php is 767 and MUST match:
   if they drift, one band gets a hidden toggle over collapsed content, i.e. a
   sidebar the reader cannot open.
   ========================================================================== */

/* ---- ONE ROW COMPONENT FOR ALL FOUR RAILS (owner 2026-07-30) ------------
   The content-type rail already used bordered boxes with an arrow, and the class,
   subject and chapter rails were plain text — the same navigation rendered two
   different ways depending on which level you happened to be on. They now share a
   single component with three states, so moving root -> class -> subject ->
   chapter feels like one system instead of four screens.

   THE BOX IS THE LINK. A 40px row is 40px of hit area; the previous text-only
   target was a ~16px line, which is under the 44px touch guidance on a phone.
   Rows that cannot be opened render the same box as a <span>, so the list keeps
   one rhythm whether a chapter is published or still to come.

   THREE STATES, and the difference is legible without colour alone:
     live     solid border, white ground, arrow          -> "this opens"
     current  vermilion border + tinted ground, no arrow -> "you are here"
     planned  dashed border, muted text, no arrow        -> "not yet"
   The dashed border is doing real work: it separates "coming soon" from "broken"
   at a glance, which flat grey text alone never manages.
   ------------------------------------------------------------------------- */
.ink-silo-rail {
  padding: 18px;
}

.ink-silo-rail .ink-rail-title {
  margin-bottom: 10px;
  padding-bottom: 10px;
}

/* Published count + progress rule. The one flourish, and it is real data. */
.ink-silo-rail .ink-silo-count {
  display: grid;
  gap: 7px;
  margin: 0 0 14px;
}

.ink-silo-rail .ink-silo-count__text {
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.ink-silo-rail .ink-silo-progress {
  display: block;
  height: 2px;
  border-radius: 2px;
  background: var(--line);
  position: relative;
  overflow: hidden;
}

.ink-silo-rail .ink-silo-progress::before {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--p, 0%);
  background: var(--verm);
  border-radius: 2px;
}

.ink-silo-rail .ink-silo-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 8px;
}

/* The row box — matched to .ink-tool-links so every rail reads the same. */
.ink-silo-rail .ink-silo-link {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 13px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: #fff;
  color: var(--ink);
  text-decoration: none;
  font-size: .875rem;
  font-weight: 600;
  line-height: 1.4;
  transition: border-color .15s ease, color .15s ease;
}

.ink-silo-rail a.ink-silo-link:hover {
  border-color: var(--verm);
  color: var(--verm-deep);
}

.ink-silo-rail a.ink-silo-link:focus-visible {
  outline: 2px solid var(--verm);
  outline-offset: 2px;
}

.ink-silo-rail .ink-silo-link .ink-arr {
  width: 16px;
  height: 16px;
  color: var(--verm);
  flex: none;
  margin-left: auto;
}

.ink-silo-rail .ink-silo-num {
  flex: none;
  min-width: 16px;
  text-align: right;
  font-size: .74rem;
  font-weight: 700;
  color: var(--verm);
  font-variant-numeric: tabular-nums;
}

.ink-silo-rail .ink-silo-body {
  display: grid;
  gap: 1px;
  min-width: 0;
  margin-right: auto;
}

.ink-silo-rail .ink-silo-name {
  overflow-wrap: anywhere;
}

.ink-silo-rail .ink-silo-meta {
  font-size: .7rem;
  font-weight: 500;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* "You are here" — same box, vermilion border, tinted ground, no arrow. */
.ink-silo-rail .ink-silo-item.is-current>.ink-silo-link {
  border-color: var(--verm);
  background: var(--paper);
  color: var(--verm-deep);
  font-weight: 700;
}

.ink-silo-rail .ink-silo-item.is-current .ink-silo-num {
  color: var(--verm-deep);
}

/* Not yet published — dashed border says "coming", not "broken". */
.ink-silo-rail .ink-silo-item.is-planned>.ink-silo-link,
.ink-silo-rail .ink-silo-item.is-draft>.ink-silo-link {
  border-style: dashed;
  border-color: #d7d7e0;
  background: transparent;
  color: var(--muted);
  font-weight: 500;
  cursor: default;
}

.ink-silo-rail .ink-silo-item.is-planned .ink-silo-num,
.ink-silo-rail .ink-silo-item.is-draft .ink-silo-num {
  color: #6f6f82;
  font-weight: 600;
}

/* Book heading, when a subject spans several (First Flight / Footprints). */
.ink-silo-rail .ink-silo-book {
  list-style: none;
  margin: 14px 0 2px;
  padding: 0 2px;
  font-size: .64rem;
  font-weight: 700;
  letter-spacing: .11em;
  text-transform: uppercase;
  color: var(--verm);
}

.ink-silo-rail .ink-silo-book:first-child {
  margin-top: 0;
}

.ink-silo-rail .ink-silo-up {
  margin: 14px 0 0;
  padding-top: 12px;
  border-top: 1px solid var(--line);
  font-size: .8rem;
}

.ink-silo-rail .ink-silo-up a {
  color: var(--verm);
  font-weight: 600;
  text-decoration: none;
}

.ink-silo-rail .ink-silo-up a:hover {
  text-decoration: underline;
}

/* Content-type rail: identical box, and its current row matches too. */
.ink-silo-rail .ink-tool-links {
  display: grid;
  gap: 8px;
}

.ink-silo-rail .ink-tool-links a,
.ink-silo-rail .ink-tool-links .is-current {
  padding: 10px 13px;
  font-size: .875rem;
  border-radius: 10px;
}

.ink-silo-rail .ink-tool-links .is-current {
  display: flex;
  align-items: center;
  border: 1px solid var(--verm);
  background: var(--paper);
  color: var(--verm-deep);
  font-weight: 700;
}

/* A 31-row chapter rail is a long list — tighten it a step so it stays scannable. */
.ink-silo-rail .ink-silo-list:not(.is-plain) {
  gap: 6px;
}

.ink-silo-rail .ink-silo-list:not(.is-plain) .ink-silo-link {
  padding: 9px 12px;
}

@media (prefers-reduced-motion: reduce) {
  .ink-silo-rail .ink-silo-link {
    transition: none;
  }
}

/* ---- >=1000: full-width side rail ---- */
@media (min-width: 1000px) {
  .ink-silo-tpl .ink-article-layout.ink-silo-layout {
    display: grid;
    grid-template-columns: 262px minmax(0, 1fr);
    column-gap: 40px;
    row-gap: 0;
    align-items: start;
    max-width: var(--wrap);
  }
}

/* ---- 768-999: narrower side rail (iPad portrait) ---- */
@media (min-width: 768px) and (max-width: 999px) {
  .ink-silo-tpl .ink-article-layout.ink-silo-layout {
    display: grid;
    grid-template-columns: 210px minmax(0, 1fr);
    column-gap: 26px;
    row-gap: 0;
    align-items: start;
  }

  .ink-silo-tpl .ink-silo-rail .ink-rail-card {
    padding: 14px;
  }

  .ink-silo-tpl .ink-silo-rail .ink-silo-item {
    font-size: .84rem;
  }

  .ink-silo-tpl .ink-tool-links a,
  .ink-silo-tpl .ink-tool-links .is-current {
    padding: 9px 11px;
    font-size: .85rem;
  }
}

/* ---- both side-rail bands: explicit placement + sticky, no toggle ---- */
@media (min-width: 768px) {

  /* `order` must be reset FIRST. main.css's <=999px block sets
     `.ink-article-layout.has-left .ink-article-content { order: -1 }` for the old
     stacked flex layout, and `order` also drives GRID auto-placement — it put the
     article before the header and pushed the <h1> to a row BELOW the whole
     article (measured at top: 30657px on a 768px tablet). */
  .ink-silo-tpl .ink-silo-layout>* {
    order: 0;
  }

  .ink-silo-tpl .ink-silo-layout>.ink-article-head {
    grid-column: 2;
    grid-row: 1;
  }

  .ink-silo-tpl .ink-silo-layout>.ink-article-content {
    grid-column: 2;
    grid-row: 2;
  }

  .ink-silo-tpl .ink-silo-layout>.ink-article-left {
    grid-column: 1;
    grid-row: 1 / span 2;
  }

  .ink-silo-tpl .ink-aside-sticky {
    position: sticky;
    top: 84px;
  }

  .ink-silo-tpl .ink-rail-panel__toggle {
    display: none;
  }

  .ink-silo-tpl .ink-article-left {
    margin-block: 0;
  }

  .ink-silo-tpl .ink-silo-layout>.ink-article-head,
  .ink-silo-tpl .ink-silo-layout>.ink-article-content {
    margin-inline: 0;
    max-width: none;
    width: auto;
  }

  /* A long rail must not outgrow the viewport: it scrolls inside itself while
     the page keeps scrolling normally. 12 classes or 25 chapters exceed one
     screen, and a sticky element taller than the viewport can never reach its
     own end. */
  .ink-silo-tpl .ink-aside-sticky {
    max-height: calc(100vh - 104px);
    overflow-y: auto;
  }
}

/* ---- <=767: collapsible panel ABOVE the article ---- */
@media (max-width: 767px) {
  .ink-silo-tpl .ink-article-layout.ink-silo-layout {
    display: flex;
    flex-direction: column;
  }

  .ink-silo-tpl .ink-silo-layout>.ink-article-head {
    order: -2;
    width: 100%;
  }

  .ink-silo-tpl .ink-silo-layout>.ink-article-left {
    order: -1;
    margin: 0 0 20px;
    width: 100%;
  }

  .ink-silo-tpl .ink-silo-layout>.ink-article-content {
    order: 0;
    width: 100%;
  }

  .ink-silo-tpl .ink-aside-sticky {
    position: static;
    max-height: none;
  }
}

/* Long-token / table overflow guards apply to the silo columns too. */
.ink-silo-layout>*,
.ink-silo-layout .ink-article-content {
  min-width: 0;
}

/* ---- three-state rows in the silo rail (owner 2026-07-30) ----------------
   The rail lists EVERY chapter the corpus knows, so most rows are pages that do
   not exist yet. They must read as "coming", never as broken links: a planned row
   is plain text, dimmed, with no hover affordance at all. */
.ink-silo-rail .ink-silo-count {
  margin: -6px 0 12px;
  font-size: .74rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
}

.ink-silo-rail .ink-silo-item.is-planned .ink-silo-name,
.ink-silo-rail .ink-silo-item.is-draft .ink-silo-name {
  color: var(--muted);
}

.ink-silo-rail .ink-silo-item.is-planned .ink-silo-num,
.ink-silo-rail .ink-silo-item.is-draft .ink-silo-num {
  color: #6f6f82;
}

.ink-silo-rail .ink-silo-item.is-planned {
  opacity: .78;
}

/* A book heading groups the rows when a subject spans several books — without it
   two rows would both be "1" (First Flight 1 and Footprints 1). */
.ink-silo-rail .ink-silo-book {
  list-style: none;
  margin: 12px 0 4px;
  padding: 0 8px;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--verm);
}

.ink-silo-rail .ink-silo-book:first-child {
  margin-top: 0;
}

/* ==========================================================================
   STICKY ACTUALLY STICKS (owner-reported 2026-07-30, measured)
   `position: sticky` was applied and computed correctly, and still scrolled away
   with the page. A sticky box can only travel INSIDE its containing block, and
   the rail's containing block is the <aside> — which, because the grid sets
   `align-items: start`, was exactly as tall as its own content: aside 702px,
   sticky child 702px, inside a 24,840px article. Zero spare height means zero
   travel, so it behaves like `static`.

   `align-self: stretch` gives the aside the full height of the rows it spans, so
   the rail now has ~24,000px to travel through. Nothing visual changes: the
   aside has no background of its own, the visible box is `.ink-rail-card` inside.

   THIS WAS NEVER WORKING SITE-WIDE. main.css sets `align-items: start` on
   `.ink-article-layout.has-left/.has-right` too, so the older rails had the same
   zero-travel containing block. Fixed for both here rather than in main.css.

   LESSON (RULES §31): asserting `getComputedStyle(el).position === 'sticky'`
   proves the declaration landed, NOT that the element sticks. The only honest
   check scrolls the page and measures whether the box stayed put — which is what
   caught this after the property-level check passed.
   ========================================================================== */
@media (min-width: 768px) {

  .ink-silo-tpl .ink-silo-layout>.ink-article-left,
  .ink-article-layout.has-left>.ink-article-left,
  .ink-article-layout.has-right>.ink-article-aside {
    align-self: stretch;
  }

  /* The sticky box must not be taller than the viewport either, or its bottom
     edge can never come into view — it would scroll once and then stop. */
  .ink-silo-tpl .ink-aside-sticky,
  .ink-article-layout.has-left .ink-aside-sticky,
  .ink-article-layout.has-right .ink-aside-sticky {
    position: sticky;
    top: 84px;
    max-height: calc(100vh - 104px);
    overflow-y: auto;
    overscroll-behavior: contain;
  }

  /* A thin scrollbar inside a 262px rail, only when the list overflows. */
  .ink-silo-tpl .ink-aside-sticky {
    scrollbar-width: thin;
  }
}

/* ---------- Textbook shape for maths solutions (owner 2026-08-04) ----------
   From the NCERT page itself: the question and its parts sit ABOVE the worked
   solution, every move of the working is its own line, and each display
   equation is centred on its own. The pipeline emits `.lcbse-q-parts` and one
   `.icse-solution-step` per step (normalise_question_block +
   textbook_working_lines); these rules give them the page furniture. */
.ink-article-content ol.lcbse-q-parts {
  list-style: none;
  margin: .2em 0 1.1em;
  padding: 12px 18px;
  background: var(--paper-card);
  border: 1px solid var(--line);
  border-top: 0;
  border-radius: 0 0 var(--radius) var(--radius);
  display: grid;
  gap: 6px;
}

.ink-article-content ol.lcbse-q-parts>li {
  margin: 0;
  font-weight: 500;
  overflow-wrap: anywhere;
}

/* PROSE READS LEFT, MATHS SITS CENTRE. Only the equation paragraph is centred;
   a step's words are never centred, because centred prose is where the first
   version of this went wrong — Parts (ii)-(v) rendered as a poster because the
   equation and the next step shared one `.icse-solution-math` paragraph. The
   pipeline now splits them (split_equation_from_next_step); this keeps the two
   visually distinct so the mistake is obvious if it ever returns. */
.icse-solution p.icse-solution-step {
  text-align: left;
}

.icse-solution p.icse-solution-math {
  /* text-align: center;
  margin: 1em 0 1.1em;*/
}

.icse-solution mjx-container[display="true"] {
  display: block;
  text-align: center;
  margin: 0 auto;
  overflow-x: auto;
  overflow-y: hidden;
}

/* THE STEP LABEL IS A SIGNPOST, not decoration. "Part (i):" / "Step 2:" carry
   the vermillion accent and sit on the same line as their first words, so a
   student scanning for one part finds it without reading the sentence. */
.icse-solution p.icse-solution-step>strong:first-child {
  color: var(--verm-deep);
  margin-right: .25em;
}

/* One move per line, with enough air between them to read as a sequence of
   steps rather than a block of prose — the NCERT page's own rhythm. */
.icse-solution>p.icse-solution-step {
  margin: 0 0 .7em;
  line-height: 1.75;
}

.icse-solution>p.icse-solution-step+p.icse-solution-step {
  margin-top: 0;
}

/* THE SECOND `.icse-solution { padding }` LIVED HERE AND WAS THE REAL ONE
   (found by the 2026-08-17 audit). It is deleted, not edited: it had the same
   specificity as the declaration beside the rest of the solution styling ~1400
   lines above, so it won purely by being later in the file, and a reader
   editing the obvious rule saw nothing change. Padding now comes from the
   content spacing scale in ONE place (`.icse-solution`, with the --box-pad-*
   tokens), which is also where the mobile step is handled — so the media
   override that used to sit below is gone too, as the tokens already drop to
   14/15 at this breakpoint. One mechanism per behaviour (RULES §18). */

@media (max-width: 640px) {

  .icse-solution p.icse-solution-math {
    margin: .8em 0;
  }

  /* A wide equation scrolls inside its own box; the PAGE never scrolls (§11). */
  .icse-solution mjx-container[display="true"] {
    max-width: 100%;
  }
}

/* ---------- Exercise page structure (owner 2026-08-04) --------------------
   The contract: overview → important concepts → per question (heading, parts,
   solution, student tip). `.solution` is the new container name; `.icse-solution`
   remains an alias so every page already published keeps its styling. */
.ink-article-content .exercise-overview,
.ink-article-content .important-concepts {
  /*background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--box-pad-y) var(--box-pad-x);
  margin: var(--flow-box) 0;*/
}


.ink-article-content .important-concepts {
  /* border-left: 4px solid var(--marker); */
}


.ink-article-content .exercise-overview>*:first-child,
.ink-article-content .important-concepts>*:first-child {
  margin-top: 0;
}

.ink-article-content .exercise-overview>*:last-child,
.ink-article-content .important-concepts>*:last-child {
  margin-bottom: 0;
}

/* The grounded sub-parts, directly under their parent question. */
.ink-article-content .question-parts {
  background: var(--paper-card);
  border: 1px solid var(--line);
  border-top: 0;
  border-radius: 0 0 var(--radius) var(--radius);
  padding: 12px 18px;
  margin: 0 0 1.1em;
}

.ink-article-content .question-parts>ol,
.ink-article-content .question-parts>ul {
  margin: 0;
  padding-left: 1.2em;
}

.ink-article-content .question-parts li {
  margin: .3em 0;
}

/* `.solution` is the new name for the worked answer; the older `.icse-solution`
   keeps every already-published page rendering identically. */
.ink-article-content .solution {
  background: var(--paper-card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 18px 20px;
  margin: 0 0 1em;
}

.ink-article-content .solution>*:first-child {
  margin-top: 0;
}

.ink-article-content .solution>*:last-child {
  margin-bottom: 0;
}

/* One checking method or common-error warning — amber, so it reads as a margin
   note rather than part of the working. */
.ink-article-content .student-tip {
  background: var(--primary-l);
  border-left: 4px solid var(--marker);
  border-radius: var(--radius-sm);
  padding: 12px 16px;
  margin: 0 0 2em;
  font-size: .95rem;
}

.ink-article-content .student-tip>*:first-child {
  margin-top: 0;
}

.ink-article-content .student-tip>*:last-child {
  margin-bottom: 0;
}

@media (max-width: 640px) {

  .ink-article-content .exercise-overview,
  .ink-article-content .important-concepts,
  .ink-article-content .solution {
    padding: 14px 15px;
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   ONE CARD PER QUESTION                        (2.9.10, owner 2026-08-17)

   `.lcbse-qa` is supplied at render time by `inkline_wrap_qa_blocks()` in
   functions.php — it wraps a question heading together with its parts, its
   solution and its student tip. Before it, those four were flat siblings and
   each had to fake its attachment to the one above (`.question-parts` still
   carries `border-top: 0` for exactly that reason, and that rule stays, because
   pages that predate this wrapper must keep rendering as they do today).

   EVERY RULE HERE IS SCOPED UNDER `.lcbse-qa`. `.solution` and `.student-tip`
   are shared with other content types and with pages this filter does not
   touch; nothing outside a wrapped question may change appearance.

   NO `overflow: hidden` ON THE CARD, deliberately. Clipping is the obvious way
   to keep children inside a rounded corner, but it would make the card a new
   scroll container around every wide table and MathJax block inside it — the
   §11 overflow guards added in 2.9.6/2.9.8/2.9.9 own that behaviour and must
   keep owning it. The corners are rounded on the first and last child instead.
   ═══════════════════════════════════════════════════════════════════════ */
/* A question is separated from the one before it by a LARGER gap than the one
   between ordinary blocks — the boundary between two questions is the strongest
   one on the page, and an even rhythm here made the cards read as a single
   undivided run. Bottom margin stays on the shared scale; adjacent margins
   collapse, so the gap BETWEEN two cards is the 2.2em top. */
.ink-article-content .lcbse-qa {
  background: var(--paper-card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  margin: 2.2em 0 var(--flow-box);
}

/* THE CARD'S HEADER IS SELECTED BY POSITION, NOT BY CLASS (fixed 2026-08-17,
   owner-reported: a blank strip above the header with a second border inside
   the card).
   The first cut keyed on `h3.lcbse-q`, which is wrong on every page published
   before that class existed. Audited across 8 live pages, the SAME component
   was rendering three different ways:

     modern page   m 0/0        p 14 20 13 20   b 0/0   <- intended
     legacy page   m 37.3/0     p 14 18 13 18   b 1/1   <- the reported gap,
                                                           plus its own border
                                                           drawn inside the card
     legacy, multi-part question
                   m 30.7/10.2  p 0             b 0/0   <- no header at all

   The third exists because the legacy selector is `h3:has(+ .icse-solution)`,
   an ADJACENT-sibling rule that cannot match when `.question-parts` sits
   between the heading and the solution — the same defect RULES §40 records as
   "matched 0 of 34 questions". Page ch6 shipped two of the three renderings.

   The card's first child IS the question heading, by construction: the filter
   opens the card AT that heading. So `:first-child` identifies the header on
   every page of every vintage, and its (0,3,1) specificity beats both legacy
   rules (0,2,1). Padding is symmetric 14/14 — the old 14/13 was a rounding
   artifact, visible as an off-centre label at large text sizes. */
.ink-article-content .lcbse-qa>h3:first-child {
  margin: 0;
  padding: 14px 20px;
  background: var(--surface);
  border: 0;
  border-radius: var(--radius) var(--radius) 0 0;
  font-size: 1.06rem;
  line-height: 1.4;
}

/* The members stop being boxes and become sections of one box, divided by a
   single hairline.
   THE DIVIDER IS DECLARED HERE, NOT IN A `>*+*` RULE, and that is not a style
   preference — it is specificity. `.ink-article-content .lcbse-qa>*+*` scores
   (0,2,0) while this selector scores (0,3,0), so a `border: 0` here silently
   BEAT the sibling rule and every internal divider vanished. Measured, not
   guessed: the computed `border-top-width` on `.solution` read 0px while the
   card still looked plausible, because the header tint and the tip's amber
   background fake the divisions the borders were supposed to draw. Same trap
   RULES §31 records for the download button — specificity beats source order.
   Every member follows the header, so every member draws its top hairline. */
.ink-article-content .lcbse-qa>.question-parts,
.ink-article-content .lcbse-qa>.solution,
.ink-article-content .lcbse-qa>.icse-solution,
.ink-article-content .lcbse-qa>.student-tip {
  background: transparent;
  border: 0;
  border-top: 1px solid var(--line);
  border-radius: 0;
  margin: 0;
  padding: var(--box-pad-y) var(--box-pad-x);
}

/* NOT TOUCHED ON PURPOSE: `.icse-solution` is `display: flex` with `gap: 12px`,
   and `.icse-solution>p` sets `margin: 0` — so that gap is the ONLY thing
   separating its paragraphs. Switching it to `block` to match `.solution`
   would collapse every legacy answer into one unbroken slab. The residual
   difference (legacy answers space their steps ~23px, modern ~17px) is real
   but second-order, and fixing it means re-homing the paragraph rhythm of
   every pre-2026-08 page — measured and reported, deliberately not bundled
   into a spacing pass. */

/* Anything else the model placed between members — a table shell, a figure, a
   stray paragraph — is a section too and divides the same way. */
.ink-article-content .lcbse-qa>*+* {
  border-top: 1px solid var(--line);
}

.ink-article-content .lcbse-qa>*:last-child {
  border-radius: 0 0 var(--radius) var(--radius);
}

/* The tip keeps its amber accent — inside the card it is the one distinction
   still worth drawing, because it is guidance rather than working. */
.ink-article-content .lcbse-qa>.student-tip {
  background: var(--primary-l);
  border-left: 4px solid var(--marker);
  padding-left: 16px;
}

.ink-article-content .lcbse-qa>.question-parts>ol,
.ink-article-content .lcbse-qa>.question-parts>ul {
  margin: 0;
  padding-left: 1.2em;
}

/* A table or figure the model placed BETWEEN members is a section too, so it
   gets the same gutter rather than sitting flush against the card edge. */
.ink-article-content .lcbse-qa>.lcbse-table-scroll,
.ink-article-content .lcbse-qa>figure,
.ink-article-content .lcbse-qa>p {
  margin: 0;
  padding: 16px 20px;
}

@media (max-width: 640px) {

  .ink-article-content .lcbse-qa {
    margin: 1.6em 0 1.2em;
  }

  .ink-article-content .lcbse-qa>h3:first-child {
    padding: 13px 15px;
  }

  .ink-article-content .lcbse-qa>.question-parts,
  .ink-article-content .lcbse-qa>.solution,
  .ink-article-content .lcbse-qa>.icse-solution,
  .ink-article-content .lcbse-qa>.student-tip,
  .ink-article-content .lcbse-qa>.lcbse-table-scroll,
  .ink-article-content .lcbse-qa>figure,
  .ink-article-content .lcbse-qa>p {
    padding: 14px 15px;
  }

  .ink-article-content .lcbse-qa>.student-tip {
    padding-left: 12px;
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   RESPONSIVE TABLES — THREE TIERS            (2.9.6, owner-reported 2026-08-07)

   Reported with screenshots at 386px AND at desktop width. The cause was not
   this stylesheet: Customizer -> Additional CSS carried a hand-written block
   that printed inline in <head> AFTER every enqueued sheet and overrode the
   shell with `!important`:

     body .lcbse-table-scroll        { overflow-x: visible !important; }
     body .lcbse-table-scroll > table{ width:100% !important; min-width:0 !important; }
     body .lcbse-table-scroll th, td { overflow-wrap: anywhere !important; }
     body .lcbse-table-scroll th:first-child { width: 18%; }
     body .lcbse-table-scroll th:last-child  { width: 22%; }

   Two separate defects lived in it, and both are worth writing down because
   they are easy to re-introduce:

   1. `overflow-wrap: anywhere` PARTICIPATES in intrinsic sizing — it declares
      the column's min-content width to be one character. `break-word` renders
      identically but is excluded from min-content sizing, so a column still
      asks for its longest word. `anywhere` is what produced "Introdu/ction"
      broken mid-word in the class-10 English chapter directory.
   2. `width: 18%` / `width: 22%` on first/last column applied to EVERY table
      on the site at EVERY width, which is why desktop showed a starved first
      column beside a bloated middle one on the formula pages.

   The replacement does not try to find one rule for every table, because a
   census of 1512 tables in 447 drafts says there is no such rule:

     2 cols 319 | 3 cols 896 | 4 cols 243 | 5 cols 30 | 6 cols 19 | 7+ cols 5

   functions.php (inkline_table_shell) measures each table once and publishes
   the verdict as `data-mode`; this sheet only styles it. Column count and cell
   length are not things CSS can ask about, so the split has to happen in PHP.

     fluid   wraps naturally at every width. Every 2-column table, and any
             short 3-4 column table. Nothing clever, nothing to break.
     cards   below 720px each row becomes a labelled card. For 3-4 column
             tables whose cells hold real prose — the chapter directory, the
             "When to Use Each Formula" and "Common Mistake" tables.
     scroll  keeps natural width and scrolls inside its own box. 5+ columns
             (a trig-ratio matrix means nothing stacked) and any table holding
             a display equation, which has a hard minimum width.

   §11 still holds throughout: the PAGE never scrolls sideways. Only a shell
   does, and only in the scroll tier.
   ═══════════════════════════════════════════════════════════════════════ */

/* ---------- shared by all three tiers ---------------------------------- */
.ink-article-content .lcbse-table-scroll>table {
  width: 100%;
  max-width: 100%;
}

/* break-word, never `anywhere` — see note 1 above. A word too long for its
   column is allowed to break; a word that merely COULD break is not. */
.ink-article-content .lcbse-table-scroll th,
.ink-article-content .lcbse-table-scroll td {
  overflow-wrap: break-word;
  word-break: normal;
  hyphens: auto;
  min-width: 0;
}

/* The one genuine exception: a bare URL or slug is a single token with no
   break opportunity, so it gets `anywhere` rather than overflowing the cell. */
.ink-article-content .lcbse-table-scroll td>a[href]:only-child {
  overflow-wrap: anywhere;
}

/* ---------- tier: fluid ------------------------------------------------ */
.ink-article-content .lcbse-table-scroll[data-mode="fluid"]>table {
  table-layout: auto;
}

/* ---------- tier: scroll ----------------------------------------------- */
/* Pure-CSS scroll affordance: the inner shadows sit on `background-attachment:
   local` so they are painted against the scrolled content and fade out at each
   end, while the cover gradients ride `scroll`. A student sees the shadow only
   while there is more table in that direction — no JS, no scroll listener. */
.ink-article-content .lcbse-table-scroll[data-mode="scroll"] {
  background-image:
    linear-gradient(to right, var(--paper, var(--bg, #ffffff)) 30%, rgba(255, 255, 255, 0)),
    linear-gradient(to left, var(--paper, var(--bg, #ffffff)) 30%, rgba(255, 255, 255, 0)),
    radial-gradient(farthest-side at 0 50%, rgba(33, 30, 24, .16), rgba(33, 30, 24, 0)),
    radial-gradient(farthest-side at 100% 50%, rgba(33, 30, 24, .16), rgba(33, 30, 24, 0));
  background-position: left center, right center, left center, right center;
  background-repeat: no-repeat;
  background-size: 40px 100%, 40px 100%, 14px 100%, 14px 100%;
  background-attachment: local, local, scroll, scroll;
}

/* ---------- tier: cards (phones) --------------------------------------- */
/* ACCESSIBILITY NOTE: `display: block` on table parts drops the implicit table
   semantics, so the column heading is restored INLINE from data-label via
   ::before. That is the trade this pattern makes — a value with a visible
   label beats a correctly-marked-up value nobody can read. The <thead> is
   visually hidden rather than removed so it is still reachable. */
/* ==========================================================================
   TABLES STAY TABLES ON SMALL SCREENS (owner 2026-08-18, after comparing the same
   page at 684px and 728px: "for above 721*756 the table are correctly appearing -
   for below can we implement the table same so the table are well displayed").

   Below 719px a `data-mode="cards"` table used to be re-flowed into stacked
   field/value cards — one row became four labelled blocks. It read as a long
   list of repeated labels rather than a table, and a student comparing chapter
   numbers or PDF codes down a column could no longer do so, because there was no
   longer a column. That ~4KB block is REMOVED, not disabled, so there is one
   behaviour instead of two (RULES §18).

   What replaces it is the behaviour the wrapper already had: the table keeps its
   columns and scrolls sideways INSIDE `.lcbse-table-scroll`, never the page —
   which is what RULES §11 requires of anything wide.
   ========================================================================== */


/* (The old 419px rule that re-stacked the label:value grid is gone — the cell
   is block at every width now, so there is no second layout to fall back to.) */

/* ---------- maths inside a table cell ----------------------------------- */
/* MathJax output is an inline-block with a hard intrinsic width: it will not
   wrap, so a cell holding a long formula is the one place that can still
   overflow. The formula scrolls inside ITSELF rather than widening the cell.
   (The companion `:has(mjx-container)` rule that used to live here is gone —
   it existed only to undo the label:value grid, and there is no grid now.) */
/* `display: inline-block` IS THE LOAD-BEARING DECLARATION HERE, not the two
   below it. MEASURED on /cgpa-calculator/ at 386px: a formula container was
   389px wide inside a 329px cell while reporting `max-width: 100%` and
   `overflow-x: auto` as its COMPUTED style — because MathJax renders inline
   maths as `display: inline`, and per CSS neither `max-width` nor `overflow`
   applies to a non-replaced inline element. Both rules were correct, present,
   and inert; `scrollWidth: 0` on the container was the tell.
   Promoting it to inline-block makes the box model apply, so the formula is
   capped at the cell and scrolls inside itself instead of pushing the cell
   wider than the card. */
.ink-article-content .lcbse-table-scroll td mjx-container,
.ink-article-content .lcbse-table-scroll th mjx-container {
  display: inline-block;
  vertical-align: middle;
  max-width: 100%;
  overflow-x: auto;
  overflow-y: hidden;
}

/* A DISPLAY equation is a block of its own — give it the full card width and
   its own breathing room instead of letting it sit mid-sentence. */
.ink-article-content .lcbse-table-scroll[data-mode="cards"] mjx-container[display="true"] {
  margin: .5em 0;
  text-align: left;
}

/* ...AND THE SAME GUARD FOR INLINE MATHS IN ORDINARY PROSE, which is where the
   sitewide sweep found the last two §11 violations. The rule above was scoped
   to table cells because that is where the reported bug was; measured at 320px
   on /mcq-questions/class-10/science/acids-bases-and-salts/ and
   /important-questions/…/, a long inline formula in a QUESTION paragraph pushed
   the document to 390px inside a 305px viewport — the page scrolling sideways,
   with no table involved at all.
   `mjx-container[display="true"]` already had a guard higher up in this file;
   inline maths never did, because as `display: inline` it silently ignored any
   width or overflow it was given. */
.ink-article-content mjx-container:not([display="true"]) {
  display: inline-block;
  vertical-align: middle;
  max-width: 100%;
  overflow-x: auto;
  overflow-y: hidden;
}

/* =========================================================================
   3.0.9 — FIRST-LINE INDENT (owner 2026-08-18: "We need to implement 1 tab space
   for every paragraph must start", then narrowed the same session: "Note first
   paragraph only after each heading").

   READ AS: the paragraph that OPENS each section is indented; the ones that
   follow it are not. If the intent was the opposite — the printing convention,
   where the opening paragraph is flush and every following one is indented —
   it is one selector to swap, and this comment is where to swap it.

   Scoped to `.ink-article-content`, so the homepage, the silo rail, the footer
   directory and every widget are untouched: those are lists and cards, not prose.

   2em is the conventional first-line indent and reads as one tab at body size.
   It steps down to 1.5em on phones — at 360px a 2em indent costs ~10% of the
   measure, and line length is the scarce resource there (RULES §11).

   THREE EXCLUSIONS, each because the indent would visibly break something:
   · `.icse-solution-math` is a display equation set as a block — indenting one
     that happens to follow a heading knocks it out of line with the equations
     above and below it;
   · a heading followed by a table wrapper or figure is not prose;
   · the opening paragraph of an article carries a FLOATED 3.2em drop cap. It is
     not matched by these selectors anyway (the H1 sits outside the content
     wrapper since 2.5.1), and it is named here so nobody re-adds it by hand.
   ====================================================================== */
.ink-article-content h2+p,
.ink-article-content h3+p,
.ink-article-content h4+p {
  text-indent: 2em;
}

.ink-article-content h2+p.icse-solution-math,
.ink-article-content h3+p.icse-solution-math,
.ink-article-content h4+p.icse-solution-math,
.ink-editorial .ink-article-content>p:first-of-type {
  text-indent: 0;
}

@media (max-width: 640px) {

  .ink-article-content h2+p,
  .ink-article-content h3+p,
  .ink-article-content h4+p {
    text-indent: 1.5em;
  }
}

/* ==========================================================================
   3.1.4 — the rail panel ships CLOSED (owner 2026-08-18), so above the phone
   breakpoint the body must be revealed by CSS as well as by the script. The
   <summary> is hidden from 768px up, so if the script ever failed to run the
   sidebar would be unreachable — a collapsed <details> with no visible control.
   Both selectors are needed: older engines hide the children of a closed
   <details>, current Chrome hides `::details-content` instead, and neither
   mechanism overrides the other.
   ========================================================================== */
@media (min-width: 768px) {
  .ink-rail-panel:not([open])>.ink-rail-panel__body {
    display: block;
  }

  .ink-rail-panel::details-content {
    content-visibility: visible;
  }
}