/* RoomLAB scene-report print stylesheet — Sofia Calderón design system.
 *
 * Two-tone + one accent. System-font only. Plan as hero. WCAG AA on body.
 * Six semantic colour variables; one accent reserved for "the answer"
 * (RT60 cover figure, STI tier-pass on the precision page).
 *
 * 7 pages A4 portrait, with deliberate visual contrast between chapter
 * openers (RT60, Precision results) and appendices (sources, listeners).
 *
 * Pipeline constraints: Chromium browser print, no PDF library, no
 * @page named counters, no webfonts.
 */

/* Default: hide the report on screen. Print mode and the PDF-export
   capture path both override this further down. */
@media screen {
  #print-report { display: none; }
}

/* PDF-export path (html2pdf.js): the design rules below apply universally
   to #print-report so html2canvas can rasterize them. We just need to flip
   visibility for the duration of the export — body class set by
   triggerProposalPDF() in print-report.js. */
body.is-pdf-export > *:not(#print-report) { display: none !important; }
body.is-pdf-export #print-report { display: block !important; }

/* Native browser-print path. */
@media print {
  html { color-scheme: light; }
  /* CRITICAL: main.css sets `html, body { overflow: hidden; height: 100% }`
     to prevent SpeakerLAB / SurfaceLAB scroll. That rule clips
     anything past one viewport-height during print and the print
     engine only produces a single page. Reset both for print so the
     pagination engine can flow the whole report. */
  html, body {
    overflow: visible !important;
    height: auto !important;
  }
  body > *:not(#print-report) { display: none !important; }
  #print-report { display: block !important; }

  @page {
    size: A4 portrait;
    /* A4 margins. User asked (v=562) for 12.5mm left/right/bottom,
       top stays at 10mm. The CSS Paged Media model clips content beyond
       the .pr-page boundary (the @page margin area is reserved for
       @page margin boxes only), so the only way to move content closer
       to the page edge is to shrink the @page margin itself. Body
       content + per-page logo now sit 12.5mm from physical page edges
       left and right.

       12.5mm sits comfortably clear of the typical consumer printer
       hard margin (~4mm) on all sides. */
    margin: 10mm 12.5mm 12.5mm 12.5mm; /* top / right / bottom / left */

    /* Page number rendered INSIDE the printable area (not in the
       browser chrome). Survives the user unchecking "Headers and
       footers" in the print dialog. Chrome / Edge / Firefox / Safari
       all support @page margin boxes + counter(page) / counter(pages).
       Right-aligned in the bottom margin, hairline grey so it reads
       as a chrome detail rather than competing with page content. */
    @bottom-right {
      content: counter(page) " / " counter(pages);
      font-family: 'Inter Tight', system-ui, sans-serif;
      font-size: 8pt;
      color: #8a929c;
      margin-top: 4mm;
    }
  }

  /* Hide live-app chrome that lives outside #print-report. The
     body > *:not(#print-report) rule above catches direct children;
     these explicit selectors are belt-and-braces against deeper
     descendants (e.g. portals, fullscreen overlays). */
  .help-modal, #help-overlay, .probe-tooltip, .vp-tab, .rl-toast,
  .rail, .rail-panel, .walk-touch, .vp-fullscreen-btn,
  .vp-mode-segment, .vp-corner-btn, .vp-more-panel,
  #app-header, .lab-route, .vp-tabs {
    display: none !important;
  }
}

/* Same chrome-hide for PDF export — html2canvas captures only the
   #print-report subtree but a forced layout reflow with these visible
   can still affect coordinate math, so we strip them defensively. */
body.is-pdf-export .help-modal,
body.is-pdf-export #help-overlay,
body.is-pdf-export .probe-tooltip,
body.is-pdf-export .vp-tab,
body.is-pdf-export .rl-toast,
body.is-pdf-export .rail,
body.is-pdf-export .rail-panel,
body.is-pdf-export .walk-touch,
body.is-pdf-export .vp-fullscreen-btn,
body.is-pdf-export .vp-mode-segment,
body.is-pdf-export .vp-corner-btn,
body.is-pdf-export .vp-more-panel,
body.is-pdf-export #app-header,
body.is-pdf-export .lab-route,
body.is-pdf-export .vp-tabs {
  display: none !important;
}

/* ============================================================
   Below: ALL design rules for #print-report. These used to be
   wrapped in @media print, but html2canvas captures with screen
   rendering, so the rules must apply universally. They're inert
   on screen because #print-report is display:none unless the
   PDF-export class is set or @media print is active.
   ============================================================ */

  /* ----------- Design tokens ----------- */
  #print-report {
    --ink:     #1A1F24;
    --paper:   #FFFFFF;
    --paper-2: #F2EFE8;
    --muted:   #6B6F75;
    --rule:    #C9C5BC;
    --accent:  #8C2A2A;
    --font-sans: ui-sans-serif, "Helvetica Neue", Helvetica, Arial, sans-serif;
    --font-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  }

  #print-report {
    color: var(--ink);
    background: var(--paper);
    font-family: var(--font-sans);
    font-size: 9.5pt;
    line-height: 1.45;
    font-variant-numeric: tabular-nums;
    padding: 0;
    margin: 0;
  }

  /* Each .pr-page becomes its own physical page. */
  #print-report .pr-page {
    page-break-after: always;
    break-after: page;
    /* Anchor for the per-page logo ::before pseudo-element below. */
    position: relative;
  }
  #print-report .pr-page:last-of-type {
    page-break-after: auto;
    break-after: auto;
  }

  /* ---------- Running header — non-cover pages (pages 2–N) ----------
     Injected as the FIRST child of each non-cover .pr-page by the regex
     postprocess in print-report.js (replaces the old .pr-page-logo
     top-right overlay, v=562). Mirrors the cover titleblock geometry so
     the rule lands at the IDENTICAL y on every page: a 25mm-min-height
     row with the rule on its bottom edge and the eyebrow pinned to the
     bottom via flex-end + 1mm padding. Differences from the cover:
       - rule runs FULL content width (no 48mm logo gap),
       - logo is HALF the cover size (22mm vs 45mm) and STRADDLES the
         right end of the rule instead of sitting in the top margin. */
  #print-report .pr-running-header {
    position: relative;   /* anchor for the straddling logo */
    display: block;
  }
  #print-report .pr-running-header-rule {
    /* IDENTICAL box model to .pr-cover-titleblock-rule EXCEPT full width
       (margin-right:0, no logo gap). min-height + flex-end +
       padding-bottom + border-bottom reproduce the cover's rule-y. */
    min-height: 25mm;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    padding-bottom: 1mm;
    border-bottom: 1pt solid var(--ink);
    margin-right: 0;
  }
  /* Selector carries the extra .pr-running-header-rule class (specificity
     1,3,0) so it BEATS any page-scoped descendant eyebrow rule like
     `.pr-page-appendix .pr-eyebrow` / `.pr-page-plan .pr-eyebrow` (1,2,0).
     Those were leaking onto the INJECTED running-header eyebrow (the
     header is a descendant of the page div), adding margin-bottom that
     lifted the title OFF the rule on the appendix/plan pages while
     Acoustic results (no such rule) sat correctly flush. This keeps the
     running-header title flush to the rule on EVERY page. (v=572, user.) */
  #print-report .pr-running-header .pr-running-header-rule .pr-eyebrow {
    /* Same position as the cover eyebrow: just above the rule, flush to
       the left content edge. */
    display: block;
    margin: 0;
  }
  /* Logo sits ABOVE the right end of the rule. The .pr-running-header is
     position:relative and its height = the 25mm rule row, so the rule
     (border-bottom) is at the wrapper's bottom edge. Anchoring the logo
     bottom 1mm up from there rests it just above the line, fully clear. */
  #print-report .pr-running-logo {
    position: absolute;
    right: 0;
    bottom: 1mm;
    width: 22mm;
    height: auto;
    display: block;
    pointer-events: none;
    z-index: 5;            /* above the 1pt rule */
    image-rendering: -webkit-optimize-contrast;
    /* Force the raster to print even on the v=561 effects-drop PDF path. */
    print-color-adjust: exact;
    -webkit-print-color-adjust: exact;
  }
  /* Comfort gap below the running-header rule on the appendix page, whose
     title now lives IN the running header (v=571) so it has no chapter-
     opener / eyebrow buffer between the line and the BILL OF MATERIALS
     heading. The running header is injected as the page's first child, so
     `+ *` is its first real content (the first .pr-section). (v=572.)
     NOTE: the methodology page needs the same comfort gap, but its intro
     is .pg-prose whose `margin: 0 0 3pt 0` rule (later, equal specificity)
     resets margin-top here — so methodology's gap is set directly on
     `.pg-methodology .pg-intro` further down, where it wins. */
  #print-report .pr-page-appendix > .pr-running-header + * {
    margin-top: 7mm;
  }

  /* User-flagged: methodology + disclaimers must NEVER continue from a
     previous page. Force a page break before each — page-break-after on
     the previous .pr-page already triggers, but page-break-before is
     belt-and-braces against future re-orderings of the page list. */
  #print-report .pg-methodology,
  #print-report .pr-page-disclaimer,
  #print-report .pr-page-heatmap,
  #print-report .pr-page-operating-range {
    page-break-before: always;
    break-before: page;
  }

  /* Headings should never be the last line on a page. */
  #print-report h1,
  #print-report h2,
  #print-report h3,
  #print-report .pr-eyebrow {
    page-break-after: avoid;
    break-after: avoid;
  }

  /* Body paragraphs should keep at least 3 lines together at a page
     boundary — orphaned 1-line continuations look unfinished. */
  #print-report p,
  #print-report .pr-note,
  #print-report .pr-section p {
    orphans: 3;
    widows: 3;
  }

  /* Table headers repeat across page breaks and rows never split. */
  #print-report .pr-table thead { display: table-header-group; }
  #print-report .pr-table tfoot { display: table-footer-group; }

  /* Chromium strips background-image (linear-gradient) and background-
     colour fills from print by default to "save ink". Sofia v2 audit:
     opt the elements that NEED to print colour into exact-rendering
     mode. Keep this list narrow — applied globally it would also force
     incidental background fills (zebra rows on muted-paper) which the
     proposal aesthetic already strips on purpose. */
  #print-report .pr-heatmap-legend-bar,
  #print-report .pr-strip-legend-bar,
  #print-report .pr-heatmap-legend-tick-line,
  #print-report .pr-strip-legend-tick-line,
  #print-report .pr-strip-cell-stage,
  #print-report .pr-tierstrip-cell.pr-tierstrip-active,
  #print-report .pr-precision-headline,
  #print-report .pr-acoustic-results .pr-sti-cell,
  #print-report .pr-empty-state,
  #print-report .pr-table th,
  #print-report .pr-zebra tbody tr:nth-child(even) td,
  #print-report .pr-bandstrip-label,
  #print-report .pr-tile,
  #print-report .pr-cover-spec-overlay,
  #print-report .pr-cover-hero-nameplate h1,
  #print-report .pr-cover-hero-nameplate .pr-cover-room-name {
    print-color-adjust: exact;
    -webkit-print-color-adjust: exact;
  }

  /* ----------- Type scale ----------- */
  #print-report h1 {
    font-size: 26pt;
    font-weight: 600;
    line-height: 1.15;
    letter-spacing: -0.01em;
    color: var(--ink);
    margin: 0 0 4pt 0;
  }
  #print-report h2 {
    font-size: 14pt;
    font-weight: 600;
    line-height: 1.25;
    color: var(--ink);
    margin: 0 0 5pt 0;
    border-bottom: none;       /* override existing rule on h2 */
    padding-bottom: 0;
  }
  #print-report h3 {
    font-size: 10pt;
    font-weight: 600;
    line-height: 1.3;
    letter-spacing: 0.02em;
    text-transform: none;
    color: var(--ink);
    margin: 8pt 0 3pt 0;
  }
  #print-report .pr-eyebrow {
    font-size: 8pt;
    font-weight: 600;
    line-height: 1.4;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--muted);
    margin: 0 0 4pt 0;
    display: block;
  }
  #print-report .pr-lead {
    font-size: 11pt;
    line-height: 1.45;
    color: var(--ink);
    max-width: 165mm;
    margin: 0;
  }
  #print-report .pr-mute {
    color: var(--muted);
    font-size: 8pt;
  }
  #print-report .pr-mono {
    font-family: var(--font-mono);
    font-size: 8.5pt;
  }

  /* ----------- COVER (page 1) — room-centric (Sofia v3) -------- */
  #print-report .pr-page-cover {
    display: grid;
    grid-template-rows: auto auto auto auto;
    gap: 6mm;
  }
  #print-report .pr-cover-titleblock {
    /* v=548: line moved off the titleblock itself and onto the inner
       title-text container (see selector below). Reason: in v=547 the
       absolute-positioned logo extended past the line, and the line
       visually cut across the logo. By putting the line on the inner
       container with a right margin = logo width + gap, the line now
       ENDS before reaching the logo. Clean separation. */
    position: relative;
    display: block;
  }
  /* Eyebrow row above the rule. The line lives here so it stops before
     the logo (48mm = 45mm logo + 3mm gap). The names that used to sit
     here moved onto the hero (.pr-cover-hero-nameplate) in v=562, but
     the RULE must stay at its original vertical position — so this row
     keeps a min-height ≈ the old h1+h2 block (~21mm) and pins the
     eyebrow to the bottom (right above the line). */
  #print-report .pr-cover-titleblock-rule {
    min-height: 25mm;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    padding-bottom: 1mm;
    border-bottom: 1pt solid var(--ink);
    margin-right: 48mm;
  }
  #print-report .pr-cover-titleblock .pr-eyebrow {
    /* v=562: eyebrow sits right above the rule (bottom of the row). */
    display: block;
    margin-top: 0;
    margin-bottom: 0;
  }
  #print-report .pr-cover-titleblock-right {
    /* Taken OUT of grid flow via position: absolute (v=547) so the
       titleblock row height is determined ONLY by the title text.
       z-index lifts the logo above the .pr-cover-hero-wrap painted
       later in the DOM — v=549 fix for the cropped logo bottom (the
       hero image was painting over the lower edge of the logo when
       it spilled into the hero area). */
    position: absolute;
    top: 0;
    right: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 4mm;
    z-index: 10;
  }
  /* Cover hero logo — significantly larger than the per-page running
     header (22mm). The cover gets a styled brand mark; non-cover pages
     get the running header (.pr-running-logo, see above) that the
     regex postprocess in print-report.js injects. v=541: bumped from
     28mm → 50mm now that the date + engine moved to the left column
     under the room name, freeing the right cell to be a logo-only
     hero. The wider logo reads as a proper cover brand mark. */
  #print-report .pr-cover-logo {
    width: 45mm;
    height: auto;
    display: block;
    image-rendering: -webkit-optimize-contrast;
  }
  /* (.pr-cover-meta rule removed in v=542 — date + engine no longer
     rendered on the cover per user request. The fields are still
     available on model.project.date / model.precision if needed for
     a future re-add or for a non-cover page.) */

  /* Hero band — 3D perspective render dominates the cover. The
     wrapper is positioned so the 2D plan inset can absolute-pin to
     the bottom-right corner. */
  #print-report .pr-cover-hero-wrap {
    position: relative;
    width: 100%;
  }
  #print-report .pr-cover-hero {
    width: 100%;
    background: transparent;
    padding: 0;
    border-radius: 0;
    box-sizing: border-box;
  }
  #print-report .pr-cover-hero-image {
    /* Fixed 4:3 landscape slot, sized to nearly fill the A4 content
       column (185 × 138.75 mm; A4 usable width ≈ 185 mm after the
       v=537 margin set 10mm/15mm). Every room renders into the same
       footprint regardless of its actual dimensions, so report pages
       line up visually across presets. Capture is a 1500×1125 PNG
       (print-report.js passes width:1500, height:1125, fixedAspect:true)
       and the iso fit math frames the room inside it at NDC 0.99
       (~1 % margin per side, scene.js). object-fit:contain is a
       defence-in-depth letterbox: if a future caller passes a
       different aspect, the image fits inside the slot rather than
       stretching or cropping. */
    width: 185mm;
    height: 138.75mm;
    display: block;
    margin: 0 auto;
    object-fit: contain;
  }
  /* Cover nameplate — project + room name overlaid on the top-left of
     the hero (v=562). Black text with a strong white halo: the white
     glow lifts the black words off a dark 3D interior render, and reads
     equally on the light 2D-plan fallback. Top-left is clear of the
     spec overlay and 2D inset (both bottom-right). */
  #print-report .pr-cover-hero-nameplate {
    position: absolute;
    top: -4mm;                 /* pulled up into the grid gap, close under the rule */
    left: 0;                   /* flush-left to the eyebrow / page content edge */
    z-index: 3;
    max-width: 120mm;          /* leaves the right third for the eye to read the render */
    pointer-events: none;
  }
  #print-report .pr-cover-hero-nameplate h1 {
    font-size: 26pt;
    font-weight: 600;
    line-height: 1.1;
    letter-spacing: 0;
    margin: 0;
    color: var(--ink);                       /* black words */
    /* White halo, always present: a crisp text-stroke (rasterized with
       the glyph → survives Print-to-PDF) UNDER the black fill, plus a
       soft white glow for the shadow look. Both white → invisible on
       white paper, but they keep the black words readable the moment a
       dark part of the render falls behind them. */
    -webkit-text-stroke: 0.4mm rgba(255, 255, 255, 0.95);
    paint-order: stroke fill;
    /* Long, gradual fade-off: many closely-spaced stops ramping opacity
       down smoothly out to ~26mm, so the halo dissolves into the render
       instead of ending in a tight ring. */
    text-shadow:
      0 0 1.5mm rgba(255, 255, 255, 0.98),
      0 0 3mm rgba(255, 255, 255, 0.9),
      0 0 5mm rgba(255, 255, 255, 0.74),
      0 0 8mm rgba(255, 255, 255, 0.55),
      0 0 12mm rgba(255, 255, 255, 0.38),
      0 0 18mm rgba(255, 255, 255, 0.22),
      0 0 26mm rgba(255, 255, 255, 0.1);
    print-color-adjust: exact;
    -webkit-print-color-adjust: exact;
  }
  #print-report .pr-cover-hero-nameplate .pr-cover-room-name {
    font-size: 15pt;            /* nudged 16→15 so the pair reads as one block, not two headlines */
    font-weight: 400;
    line-height: 1.2;
    letter-spacing: 0;
    margin: 1.5mm 0 0 0;
    color: var(--ink);
    -webkit-text-stroke: 0.28mm rgba(255, 255, 255, 0.95);
    paint-order: stroke fill;
    text-shadow:
      0 0 1.3mm rgba(255, 255, 255, 0.98),
      0 0 2.6mm rgba(255, 255, 255, 0.88),
      0 0 4.5mm rgba(255, 255, 255, 0.7),
      0 0 7mm rgba(255, 255, 255, 0.5),
      0 0 11mm rgba(255, 255, 255, 0.32),
      0 0 17mm rgba(255, 255, 255, 0.16);
    print-color-adjust: exact;
    -webkit-print-color-adjust: exact;
  }
  /* Guarantee the hero wrap is tall enough to host the top-left
     nameplate even when the body is just the empty-state notice. */
  #print-report .pr-cover-hero-wrap {
    min-height: 40mm;
  }
  #print-report .pr-cover-hero:has(.pr-empty-state) {
    padding-top: 22mm;   /* push the "preview unavailable" line clear of the nameplate */
  }
  #print-report .pr-cover-hero-caption {
    font-size: 7.5pt;
    color: var(--muted);
    text-align: center;
    margin: 2mm 0 4mm;
    line-height: 1.4;
    font-style: italic;
  }
  #print-report .pr-cover-hero-plan {
    width: 100%;
  }
  #print-report .pr-cover-hero-plan svg,
  #print-report .pr-cover-hero-plan .pr-heatmap-svg {
    width: 100%;
    max-height: 90mm;
    height: auto;
    display: block;
  }
  /* 2D plan inset — Sofia v4: frameless. Sits transparently over the
     bottom-right of the hero so the room outline + symbols read as
     a ghost overlay on the 3D render. No background, no border, no
     drop-shadow, no caption — the inset IS the room and its symbols. */
  #print-report .pr-cover-hero-inset {
    position: absolute;
    right: 4mm;
    bottom: 4mm;
    width: 50mm;
    height: 35mm;
    background: transparent;
    border: none;
    box-shadow: none;
    padding: 0;
    box-sizing: border-box;
    overflow: hidden;
    pointer-events: none;
  }
  #print-report .pr-cover-hero-inset svg,
  #print-report .pr-cover-hero-inset .pr-heatmap-svg {
    width: 100%;
    height: 100%;
    display: block;
  }
  #print-report .pr-cover-inset-label {
    position: absolute;
    top: 1pt;
    left: 3pt;
    font-size: 6pt;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--muted);
    background: var(--paper);
    padding: 0 2pt;
    z-index: 1;
  }

  /* Sofia v5 — Room-specifications overlay card.
     Pinned to the top-left of .pr-cover-hero-wrap so it sits over the
     hero image regardless of the hero's variable aspect (square-ish
     classroom heroes vs. wide-and-short pavilion heroes both work).
     Translucent white (92% opacity) keeps it readable against both
     bright daytime skies and dark room interiors. Hairline ink rule;
     no drop-shadow, no backdrop-blur — those date a proposal instantly.
     Fixed width 62mm so the data column lands at the same x on every
     room type, leaving the 2D plan inset (bottom-right, 50mm wide)
     uncrowded. */
  /* Spec overlay v6 — tiny, ghosted (5 % opacity), bottom-right of the
     hero. User wants the room specs as an unobtrusive footnote, not a
     headline panel. No border, no background fill — just type at 5 %
     opacity floating over the hero. */
  #print-report .pr-cover-spec-overlay {
    position: absolute;
    right: 3mm;
    bottom: 3mm;
    width: 54mm;
    opacity: 0.90;
    z-index: 2;
    pointer-events: none;
  }
  #print-report .pr-cover-spec-overlay-title {
    font-size: 6.5pt;
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink);
    margin: 0 0 1mm 0;
    padding-bottom: 0.6mm;
    border-bottom: 0.25pt solid var(--rule);
  }
  #print-report .pr-cover-spec-overlay-table {
    width: 100%;
    border-collapse: collapse;
  }
  #print-report .pr-cover-spec-overlay-table th,
  #print-report .pr-cover-spec-overlay-table td {
    padding: 0.5mm 0;
    text-align: left;
    vertical-align: baseline;
    font-size: 7.5pt;
    line-height: 1.2;
  }
  #print-report .pr-cover-spec-overlay-table th {
    width: 44%;
    font-weight: 500;
    color: var(--muted);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    font-size: 6.5pt;
  }
  #print-report .pr-cover-spec-overlay-table td {
    font-family: var(--font-mono);
    color: var(--ink);
    text-align: right;
    font-variant-numeric: tabular-nums;
  }

  /* Backwards-compat: a couple of other pages still re-use .pr-cover-measurements
     classes for styling. Keep a thin legacy rule so we don't regress them. */
  #print-report .pr-cover-measurements {
    width: 100%;
    border-collapse: collapse;
    font-size: 10pt;
  }

  /* Proposal description v6 — single full-width paragraph, justified
     edges. No scope table, no accent rule, no two-column grid. The
     paragraph IS the proposal cover statement, set to read as
     polished professional consultancy prose. text-align: justify
     evens both edges; hyphens:auto keeps the river-of-whitespace
     problem at bay on narrow word runs. */
  #print-report .pr-cover-proposal {
    padding-top: 3mm;
    border-top: 0.5pt solid var(--rule);
  }
  #print-report .pr-cover-proposal-para {
    font-size: 10.5pt;
    line-height: 1.6;
    color: var(--ink);
    margin: 0;
    text-align: justify;
    hyphens: auto;
    -webkit-hyphens: auto;
    text-wrap: pretty;
  }

  /* Author's note — engineer's per-room commentary, sits directly
     below the proposal paragraph. Body type MATCHES the proposal
     paragraph above it (10.5pt / 1.6 / justified / hyphenated)
     so the two reads as continuous prose; only the small-caps
     eyebrow signals the voice change. No separator rule above
     (v=551 user request: removed the hairline + matched the font).
     Body capped at 240 chars by the panel input so the cover
     stays one page on the densest preset (surau) and the longest
     room name (pavilion). */
  #print-report .pr-cover-author-note {
    margin-top: 4mm;
  }
  #print-report .pr-cover-author-note-eyebrow {
    display: block;
    margin-bottom: 1.5mm;
    color: var(--muted);
  }
  #print-report .pr-cover-author-note-body {
    font-size: 10.5pt;
    line-height: 1.6;
    color: var(--ink);
    margin: 0;
    text-align: justify;
    hyphens: auto;
    -webkit-hyphens: auto;
    text-wrap: pretty;
  }

  /* Cover footer is the meta strip */
  #print-report .pr-cover-foot {
    display: flex;
    justify-content: space-between;
    border-top: 0.5pt solid var(--rule);
    padding-top: 4pt;
    font-size: 7.5pt;
    letter-spacing: 0.04em;
    color: var(--muted);
  }

  /* ----------- PLAN PAGE (page 2) ----------- */
  #print-report .pr-page-plan {
    /* Drawing-sheet feel — small caps eyebrow + plan + tile grid */
  }
  #print-report .pr-page-plan .pr-eyebrow {
    margin-bottom: 6pt;
  }
  #print-report .pr-plan-grid {
    display: grid;
    grid-template-columns: 1fr 110pt;
    gap: 12pt;
    align-items: stretch;
    margin: 4pt 0 8pt 0;
  }
  #print-report .pr-plan-svg-wrap {
    border: 1pt solid var(--rule);
    padding: 4mm;
    background: var(--paper);
    /* Same Chrome paginator workaround as .pr-heatmap-stage — see comment there. */
    position: relative;
    overflow: hidden;
  }
  #print-report .pr-plan-svg {
    width: 100%;
    max-height: 18cm;
    height: auto;
    display: block;
  }
  #print-report .pr-plan-svg svg { width: 100%; height: auto; }

  #print-report .pr-plan-legend {
    border-left: 0.5pt solid var(--rule);
    padding-left: 8pt;
    font-size: 8.5pt;
    color: var(--ink);
    display: flex;
    flex-direction: column;
    gap: 5pt;
  }
  #print-report .pr-plan-legend-row {
    display: flex;
    align-items: center;
    gap: 6pt;
  }
  #print-report .pr-plan-legend-icon {
    width: 12pt;
    height: 12pt;
    flex: 0 0 12pt;
  }
  #print-report .pr-plan-legend-note {
    margin-top: 6pt;
    font-size: 7.5pt;
    color: var(--muted);
    font-style: italic;
    line-height: 1.45;
  }

  /* ----------- HERO HEATMAP PAGE (Sofia v1) -----------
     Drawing 02. Hybrid SVG (vector linework over PNG raster) + a
     vertical legend column with numeric ticks shared with the 2D
     and 3D viewports via computeTicks(). */
  #print-report .pr-heatmap-grid {
    /* 2026-06-04 (Maya) restructure #2: flex ROW — hero map (left, flex:1)
       beside the two operating-range minis (right, narrow fixed column,
       stacked Background-over-Programme). User asked the minis move from
       BELOW the hero to the RIGHT of it, 2026-06-04. The shared legend
       moved OUT of this grid to a full-width wrap below (see
       .pr-strip-legend-wrap-full). The 12 KPI tiles remain a full-width
       6-col band at the page bottom. History: 2026-06-04 #1 was a single
       full-width column (map → minis → legend); 2026-05-22 a two-column
       flex-row (hero + KPI rail); before that a single column. */
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    gap: 6pt;
    margin: 4pt 0 0 0;
    width: 100%;
  }
  /* Left column — the hero map only now (minis + legend left this column
     in restructure #2). flex:1 so the hero takes all width the right-side
     minis column doesn't claim. */
  #print-report .pr-heatmap-main {
    flex: 1 1 auto;
    min-width: 0;          /* let the stage shrink to the column */
    display: flex;
    flex-direction: column;
    gap: 6pt;
  }
  /* Operating-range minis — now a NARROW RIGHT COLUMN beside the hero
     (2026-06-04 restructure #2). Fixed 46mm wide, vertical 1-col stack:
     Background on top, Programme below. flex:0 0 46mm so it never grows
     to rival the hero; the hero (.pr-heatmap-main, flex:1) keeps the rest
     of the page width. align-self:stretch is NOT set — the column is only
     as tall as its two minis, the row is top-aligned (grid align-items:
     flex-start), so a tall portrait hero simply extends below the minis. */
  #print-report .pr-heatmap-grid > .pr-strip {
    flex: 0 0 46mm;
    display: flex;
    flex-direction: column;
    gap: 6pt;
    margin: 0;
    /* override the base .pr-strip 2-col grid template — it's a flex column
       here, the grid-template-columns is inert but cleared for clarity. */
    grid-template-columns: none;
  }
  #print-report .pr-heatmap-grid > .pr-strip .pr-strip-cell-title { font-size: 8pt; }
  #print-report .pr-heatmap-grid > .pr-strip .pr-strip-cell-tag   { font-size: 6.5pt; }
  #print-report .pr-heatmap-grid > .pr-strip .pr-strip-cell-label { padding-bottom: 1.5pt; margin-bottom: 2pt; }
  #print-report .pr-heatmap-grid > .pr-strip .pr-strip-cell-sub   { font-size: 6.5pt; margin-top: 2pt; line-height: 1.25; }
  /* 40mm: each mini is now ~42mm wide (46mm col − 2×2mm padding). Two
     stacked at 40mm tall + labels + subs ≈ 96mm column height — well under
     the 138mm hero cap, so the minis never drive the page past one A4. */
  #print-report .pr-heatmap-grid > .pr-strip .pr-strip-cell-stage svg { max-height: 40mm; }
  /* Suppress the per-mini north arrow — the hero map beside them already
     establishes north for the page; two extra "N" kites read as clutter
     (carried over from the previous layout). (2026-05-22) */
  #print-report .pr-heatmap-grid > .pr-strip .pr-strip-cell-stage::after { content: none !important; }
  /* Shared SPL legend — now a FULL-WIDTH row BELOW the hero+minis row
     (2026-06-04 restructure #2; was nested in .pr-heatmap-main before).
     Stretch it the whole page width so the gradient + ticks span the same
     width as the caption + KPI band below it, reading as one footer block.
     The base .pr-strip-legend-wrap centres at 70%; this override stretches
     the full-page variant. */
  #print-report .pr-page-heatmap > .pr-strip-legend-wrap-full {
    display: flex;
    justify-content: stretch;
    margin: 6pt 0 0 0;
    width: 100%;
  }
  #print-report .pr-page-heatmap > .pr-strip-legend-wrap-full .pr-strip-legend {
    width: 100%;
    max-width: none;
  }
  /* Full-width caption: lives BELOW the hero+minis row + shared legend
     so it spans the whole page. User, 2026-06-04. */
  #print-report .pr-page-heatmap > .pr-caption-full {
    margin-top: 8pt;
    width: 100%;
  }
  #print-report .pr-heatmap-stage {
    border: 1pt solid var(--rule);
    padding: 4mm;
    background: var(--paper);
    /* position: relative so the north-arrow ::after overlay anchors here. */
    position: relative;
    /* aspect-ratio is normally OVERRIDDEN by an inline style the report
       sets per-room (heatStageStyle in print-report.js → the room's
       viewBox aspect, clamped 3/4..16/9) so the coverage map FILLS the
       frame instead of letterboxing in a square (2026-06-04). The 1/1
       here is only the fallback when no heatmap/grid exists. The SVG's
       preserveAspectRatio="xMidYMid meet" still letterboxes any residual
       so nothing clips. max-height caps the height so the page fits one A4
       even for a PORTRAIT room — the worst case for height. With the minis
       now a 46mm column BESIDE the hero (restructure #2, 2026-06-04), the
       top-row height = max(hero, minis-col ~96mm). Worst case PORTRAIT:
       138 hero cap + ~10 legend + ~14 caption + ~26 KPI band + ~12 gaps
       ≈ 200mm — fits A4 ≈247mm content with margin. WIDE room (16/9 hero
       ≈73mm): top row = max(73, 96) = 96mm (minis dominate) → ~158mm. The
       138mm cap is unchanged from restructure #1. (2026-06-04) */
    aspect-ratio: 1 / 1;
    width: 100%;
    max-height: 138mm;
    /* overflow: hidden — clip the north-arrow ::after to the stage's
       printed box. WHY: Chrome's print-paginator can render a
       `position: absolute` ::after on EVERY printable page that the
       relatively-positioned parent intersects (visible at top-right of
       the cover page 1 even though the stage lives on page 2). User-
       reported and confirmed by removing position:absolute in DevTools
       on the actual page-2 arrow — both arrows disappear together. */
    overflow: hidden;
  }
  /* Fixed-pixel north arrow overlay — does NOT scale with the room size
     unlike the SVG-embedded version that was here before. Renders as a
     small dark kite + "N" letter at the top-right of every heatmap +
     plan stage. Same arrow appears via the cover-hero variant below. */
  /* North-arrow + "N" overlay on plan / heatmap stages.
     2026-05-19: SUPPRESSED on the cover page (.pr-page-cover) — the
     cover hero is a 3D iso render, where the north convention reads
     differently than a top-down plan. User-reported the arrow at the
     cover's top-right doesn't belong on a 3D illustration. Targeted
     suppression of the 5 known carriers didn't work (user reported
     the arrow still appeared), so this rule uses a universal-descendant
     ::before/::after kill-switch on .pr-page-cover. The arrow still
     renders on pages 2+ (heatmap, plan, strip-cell) where it's anchored
     to a proper top-down view. The kill-switch only nukes content +
     background-image; layout pseudo-elements that use neither (rare in
     this codebase, but a precaution) keep working. */
  #print-report .pr-page-cover *::before,
  #print-report .pr-page-cover *::after {
    content: none !important;
    background-image: none !important;
  }

  #print-report .pr-heatmap-stage::after,
  #print-report .pr-cover-hero-plan::after,
  #print-report .pr-cover-hero-inset::after,
  #print-report .pr-plan-svg-wrap::after,
  #print-report .pr-strip-cell-stage::after {
    content: "N";
    position: absolute;
    top: 3mm;
    right: 3mm;
    width: 6mm;
    height: 9mm;
    padding-top: 5mm;
    font-size: 7pt;
    font-weight: 700;
    text-align: center;
    color: #000;
    /* Inline SVG kite arrow as background; sized to top half of the box,
       N text sits below in the padding-top region. */
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 18' fill='%23000'><polygon points='6,0 9,5 6,4.6 3,5'/></svg>");
    background-repeat: no-repeat;
    background-position: top center;
    background-size: 4mm auto;
    pointer-events: none;
    print-color-adjust: exact;
    -webkit-print-color-adjust: exact;
    z-index: 5;
  }
  #print-report .pr-heatmap-svg {
    width: 100%;
    height: 100%;
    display: block;
  }
  /* Fill the fixed-square stage; preserveAspectRatio="xMidYMid meet"
     letterboxes wide/tall rooms inside the square. */
  #print-report .pr-heatmap-stage svg { width: 100%; height: 100%; display: block; }
  /* Horizontal legend below the heatmap (2026-05-19 redesign).
     Width: stretches across the heatmap's printed width.
     Height: compact — ~22pt for the bar + ~14pt for the labels. */
  #print-report .pr-heatmap-legend {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 3pt;
    font-size: 8.5pt;
    color: var(--ink);
  }
  #print-report .pr-heatmap-legend-header {
    font-size: 7.5pt;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--muted);
  }
  #print-report .pr-heatmap-legend-stage {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    width: 100%;
  }
  #print-report .pr-heatmap-legend-bar {
    width: 100%;
    height: 9pt;
    border-radius: 1pt;
    border: 0.4pt solid var(--rule);
    position: relative;
  }
  /* Data-extent bracket (Phase 11a, 2026-05-25).
     Faint translucent band INSIDE the bar marking the actual data
     extent (e.g. 72–106 dB). Legend caption ends remain the ramp
     domain (30–110 dB) so the colour-to-value mapping is invariant
     across indoor/outdoor modes. */
  #print-report .pr-heatmap-legend-data-bracket {
    position: absolute;
    top: -1pt;
    bottom: -1pt;
    border: 0.5pt solid rgba(0, 0, 0, 0.55);
    border-radius: 1pt;
    background: rgba(255, 255, 255, 0.0);
    pointer-events: none;
  }
  #print-report .pr-heatmap-legend-data-caption {
    font-size: 6.8pt;
    color: var(--muted);
    text-align: center;
    margin-top: 1.5pt;
    letter-spacing: 0.02em;
    font-variant-numeric: tabular-nums;
  }
  #print-report .pr-heatmap-legend-ticks {
    position: relative;
    width: 100%;
    height: 14pt;
    margin-top: 2pt;
  }
  #print-report .pr-heatmap-legend-tick {
    position: absolute;
    top: 0;
    bottom: 0;
    transform: translateX(-50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2pt;
    white-space: nowrap;
  }
  #print-report .pr-heatmap-legend-tick-line {
    width: 0.4pt;
    height: 4pt;
    background: var(--ink);
  }
  /* End ticks: keep the tick line on the exact bar end but anchor the
     first label left / last label right so they don't clip at the edge
     (same fix as the strip legend). */
  #print-report .pr-heatmap-legend-tick--first {
    transform: translateX(0);
    align-items: flex-start;
  }
  #print-report .pr-heatmap-legend-tick--last {
    transform: translateX(-100%);
    align-items: flex-end;
  }
  /* Minor (unlabeled) graduation — shorter line, fainter ink. */
  #print-report .pr-heatmap-legend-tick.minor .pr-heatmap-legend-tick-line {
    height: 2.5pt;
    opacity: 0.65;
  }
  #print-report .pr-heatmap-legend-tick-label {
    font-size: 7pt;
    color: var(--ink);
    line-height: 1;
    font-variant-numeric: tabular-nums;
  }
  #print-report .pr-caption {
    font-size: 8.5pt;
    line-height: 1.45;
    color: var(--ink);
    margin: 6pt 0 0 0;
    page-break-inside: avoid;
    break-inside: avoid;
    text-align: justify;
    hyphens: auto;
  }

  /* ----------- DRAWING 02 — OPERATING-RANGE STRIP -----------
     Three coverage plots side by side on one page (background /
     programme / max drive). Shared colour scale below. The whole
     page resists internal page-breaks so the strip never gets
     split across sheets. */
  #print-report .pr-page-operating-range {
    page-break-inside: avoid;
    break-inside: avoid;
  }
  #print-report .pr-page-operating-range > .pr-eyebrow {
    margin-bottom: 6pt;
  }
  #print-report .pr-strip {
    /* BASE rule — used by the standalone .pr-page-operating-range page as a
       side-by-side 2-col grid. On the heatmap page (.pr-heatmap-grid >
       .pr-strip) this is OVERRIDDEN to a narrow vertical flex column to the
       RIGHT of the hero (2026-06-04 restructure #2 — see that rule above). */
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 6pt;
    margin: 2pt 0 8pt 0;
    page-break-inside: avoid;
    break-inside: avoid;
  }
  #print-report .pr-strip-cell {
    display: flex;
    flex-direction: column;
    page-break-inside: avoid;
    break-inside: avoid;
  }
  #print-report .pr-strip-cell-label {
    display: flex;
    align-items: baseline;
    gap: 6pt;
    border-bottom: 0.5pt solid var(--rule);
    padding-bottom: 2pt;
    margin-bottom: 4pt;
  }
  #print-report .pr-strip-cell-tag {
    font-size: 7.5pt;
    font-weight: 600;
    letter-spacing: 0.08em;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
  }
  #print-report .pr-strip-cell-title {
    font-size: 10pt;
    font-weight: 600;
    color: var(--ink);
    letter-spacing: -0.005em;
  }
  #print-report .pr-strip-cell-stage {
    border: 0.5pt solid var(--rule);
    padding: 2mm;
    background: var(--paper);
    /* Same Chrome paginator workaround as .pr-heatmap-stage — see comment there. */
    position: relative;
    overflow: hidden;
  }
  #print-report .pr-strip-cell-stage svg {
    width: 100%;
    height: auto;
    max-height: 11cm;
    display: block;
  }
  #print-report .pr-strip-cell-sub {
    margin-top: 4pt;
    font-size: 8pt;
    font-variant-numeric: tabular-nums;
    color: var(--ink);
    letter-spacing: 0;
    line-height: 1.35;
  }

  /* Shared horizontal legend, centred under the three plots. */
  #print-report .pr-strip-legend-wrap {
    display: flex;
    justify-content: center;
    margin: 2pt 0 4pt 0;
  }
  #print-report .pr-strip-legend {
    width: 70%;
    max-width: 130mm;
  }
  #print-report .pr-strip-legend-header {
    font-size: 7.5pt;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--muted);
    text-align: center;
    margin-bottom: 4pt;
  }
  #print-report .pr-strip-legend-stage {
    position: relative;
    width: 100%;
  }
  #print-report .pr-strip-legend-bar {
    width: 100%;
    height: 9pt;
    border: 0.4pt solid var(--rule);
    border-radius: 1pt;
  }
  #print-report .pr-strip-legend-ticks {
    position: relative;
    width: 100%;
    height: 14pt;
    margin-top: 1pt;
  }
  #print-report .pr-strip-legend-tick {
    position: absolute;
    top: 0;
    transform: translateX(-50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1pt;
  }
  #print-report .pr-strip-legend-tick-line {
    width: 0.4pt;
    height: 3pt;
    background: var(--ink);
  }
  /* Minor (unlabeled) graduation — shorter line, fainter ink; renders
     as ruler-style sub-ticks between the labelled majors. Bumped to
     2pt / 0.65 from the original 1.5pt / 0.45 for the same reason as
     the heatmap legend — at print scale the originals were invisible. */
  #print-report .pr-strip-legend-tick.minor .pr-strip-legend-tick-line {
    height: 2pt;
    opacity: 0.65;
  }
  #print-report .pr-strip-legend-tick-label {
    font-size: 7pt;
    color: var(--ink);
    font-variant-numeric: tabular-nums;
    line-height: 1;
    white-space: nowrap;
  }
  /* End ticks: keep the tick LINE on the exact bar end (0% / 100%) but
     left/right-align the LABEL so "60 dB" / "100 dB" don't overflow the
     legend edge and get clipped to "dB" / "100". The div anchors its
     left edge at 0% (first) or right edge at 100% (last); the flex
     column then aligns line + label to that edge. */
  #print-report .pr-strip-legend-tick--first {
    transform: translateX(0);
    align-items: flex-start;
  }
  #print-report .pr-strip-legend-tick--last {
    transform: translateX(-100%);
    align-items: flex-end;
  }

  /* KPI band — 2026-06-04 (Maya): the 12 KPI tiles are a full-width
     horizontal band at the BOTTOM of the heatmap page (was a 46mm
     vertical rail to the RIGHT of the map 2026-05-22; before that a
     4-col band). 6 columns → 2 rows of 6 = ~26mm tall, shorter than
     4-col's 3 rows, so it fits under the enlarged hero. Page-scoped
     (.pr-page-heatmap >) so it beats the legacy 4-col .pr-tilegrid rule
     below in specificity without touching other callers. break-inside
     avoid on the band keeps all 12 tiles on the same page as the map. */
  #print-report .pr-page-heatmap > .pr-tilegrid {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 4pt;
    margin: 8pt 0 0 0;
    width: 100%;
    break-inside: avoid;
  }
  /* Legacy 4-col grid kept for any other caller of .pr-tilegrid. */
  #print-report .pr-tilegrid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 4pt;
    margin: 8pt 0 6pt 0;
  }
  #print-report .pr-tile {
    border: 0.5pt solid var(--rule);
    padding: 5pt 7pt;
    background: var(--paper);
    break-inside: avoid;
  }
  #print-report .pr-tile-label {
    font-size: 7pt;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin-bottom: 3pt;
  }
  #print-report .pr-tile-value {
    font-size: 11pt;
    font-weight: 600;
    color: var(--ink);
  }

  /* ----------- CHAPTER OPENERS (pages 3 + 6) ----------- */
  #print-report .pr-chapter-opener {
    position: relative;
    padding-top: 18mm;
    margin-bottom: 8pt;
  }
  #print-report .pr-chapter-number-ghost {
    position: absolute;
    top: 0;
    right: 0;
    font-size: 60pt;
    font-weight: 200;
    line-height: 1;
    letter-spacing: -0.02em;
    color: var(--paper-2);
    user-select: none;
  }
  #print-report .pr-chapter-opener .pr-eyebrow {
    margin-bottom: 4pt;
  }
  /* Acoustic results (Chapter 02): drop the whole chapter opener — the
     ghost "02", the "Chapter 02" eyebrow, and the "Acoustic results"
     title are all redundant now that the running header labels the page
     (user request v=562). Scoped to this page so the Chapter 03 opener
     is untouched. */
  #print-report .pr-acoustic-results .pr-chapter-opener {
    display: none;
  }
  /* Furnishing schedule (v=671 — user request): drop the ghost "04"
     numeral and the duplicate "Furnishing schedule" eyebrow that
     repeat the running-header label. Only the H2 remains; reclaim the
     18mm of padding the ghost numeral would have occupied. */
  #print-report .pr-chapter-opener-furniture {
    padding-top: 0;
    margin-bottom: 4pt;
  }
  /* Per-band consolidated table hidden (user request v=562) — its two
     load-bearing messages (Sabine/Eyring diffuse-field caveat; ray-traced
     T30 supersedes for sign-off) were folded into the Fig. 02.1 caption.
     Kept in the DOM (not removed) so the data is still recoverable. */
  #print-report .pr-acoustic-results .pr-band-section {
    display: none;
  }
  #print-report .pr-chapter-opener h2 {
    font-size: 22pt;
    font-weight: 300;
    line-height: 1.1;
    letter-spacing: -0.01em;
    margin: 0;
  }

  /* RT60-vs-frequency analytical chart (page 3 hero figure) — Sofia
     spec. 100×70mm vector with axes, target band, dual-series. The
     SVG itself carries inline stroke/fill so it survives any
     rasterisation pipeline; the wrap rules are layout-only. */
  #print-report .pr-rt60-chart {
    display: block;
    width: 132mm;
    height: 70mm;
    margin: 0;
    /* The T30 value labels carry a white halo (stroke) that must PAINT —
       not be dropped as "no ink" — so the digits read over the ochre line
       on the v=561 effects-drop PDF path. (Maya 2026-05-21.) */
    print-color-adjust: exact;
    -webkit-print-color-adjust: exact;
  }
  /* The .pr-rt60-grid 2-col chart+KV layout and .pr-rt60-kv-wrap
     companion rules were retired in v=557. The KV table duplicated
     room geometry already carried on the cover (Shape · W×D×H · Floor
     area · Volume · Surface area) and Drawing 01 tile grid (Volume +
     Floor area + Surface area + Mean α + RT60 1k Sabine/Eyring + r_c +
     f_s + ambient). The chart now sits full-row inside .pr-rt60-hero
     below — see also the Chapter 02 block-budget comment in the
     ACOUSTIC RESULTS section further down. */

  /* ----------- SECTIONS ----------- */
  #print-report .pr-section {
    margin-bottom: 10pt;
    break-inside: auto;
  }
  #print-report .pr-section h2 {
    border-bottom: 0.5pt solid var(--rule);
    padding-bottom: 2pt;
  }
  #print-report .pr-note {
    font-size: 8pt;
    color: var(--muted);
    margin: 4pt 0 0 0;
    font-style: italic;
    line-height: 1.5;
    text-align: justify;
    hyphens: auto;
  }

  /* ----------- TABLES ----------- */
  #print-report .pr-table {
    width: 100%;
    border-collapse: collapse;
    margin-bottom: 4pt;
    font-variant-numeric: tabular-nums;
  }
  #print-report .pr-table thead {
    display: table-header-group;
  }
  #print-report .pr-table tr {
    break-inside: avoid;
    page-break-inside: avoid;
  }
  #print-report .pr-table th,
  #print-report .pr-table td {
    border: 0.4pt solid var(--rule);
    padding: 2pt 5pt;
    text-align: right;
    vertical-align: top;
    font-size: 8.5pt;
    color: var(--ink);
  }
  #print-report .pr-table th {
    background: var(--paper-2);
    font-weight: 600;
    text-align: left;
    color: var(--ink);
  }

  /* Key-value tables: left-rag with dotted leader, no boxed look */
  #print-report .pr-table.pr-kv {
    border: none;
  }
  #print-report .pr-table.pr-kv th,
  #print-report .pr-table.pr-kv td {
    border: none;
    border-bottom: 0.4pt dotted var(--rule);
    background: transparent;
    text-align: left;
    padding: 3pt 0;
  }
  #print-report .pr-table.pr-kv th {
    width: 50%;
    font-weight: 400;
    color: var(--muted);
  }
  #print-report .pr-table.pr-kv td {
    color: var(--ink);
  }

  /* Source / appendix tables: smaller, denser */
  #print-report .pr-source-table th,
  #print-report .pr-source-table td {
    font-size: 8pt;
    padding: 1.6pt 4pt;
  }
  #print-report .pr-zebra tbody tr:nth-child(even) td {
    background: var(--paper-2);
  }
  #print-report .pr-bom-model {
    text-align: left;
  }

  /* ----------- APPENDIX TREATMENT (pages 4 + 5) ----------- */
  #print-report .pr-page-appendix h2 {
    font-size: 10pt;
    font-weight: 600;
    border-bottom: 0.4pt solid var(--rule);
    padding-bottom: 2pt;
    margin-bottom: 4pt;
  }
  #print-report .pr-page-appendix .pr-eyebrow {
    margin-bottom: 6pt;
  }
  #print-report .pr-page-appendix .pr-table {
    font-size: 8pt;
  }

  /* ----- FurnitureLAB schedule (v=670, 2026-05-27) -------------------
     Layout mirrors the appendix BoM (compact 8 pt body) so the page
     reads like a continuation of the equipment schedule. Reliability
     badge + interaction-mode chip carry the colour palette already
     established by reliability-colors.js and the in-app sidebar. */
  #print-report .pr-page-furniture {
    page-break-inside: auto;
  }
  #print-report .pr-page-furniture h2 {
    font-size: 14pt;
    font-weight: 600;
    margin: 0 0 2pt 0;
  }
  #print-report .pr-fbom-table {
    font-size: 8pt;
    margin-top: 4pt;
  }
  #print-report .pr-fbom-table th {
    font-size: 7.5pt;
    text-align: left;
    border-bottom: 0.4pt solid var(--rule);
    padding: 3pt 4pt;
    vertical-align: bottom;
  }
  #print-report .pr-fbom-table td {
    padding: 3pt 4pt;
    vertical-align: middle;
  }
  #print-report .pr-fbom-th-sub {
    display: block;
    font-size: 6.5pt;
    font-weight: 400;
    color: var(--muted);
    letter-spacing: 0.02em;
    text-transform: none;
  }
  #print-report .pr-fbom-name {
    font-weight: 600;
  }
  #print-report .pr-fbom-sub {
    display: block;
    font-size: 6.8pt;
    font-weight: 400;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin-top: 1pt;
  }
  #print-report .pr-fbom-mode {
    display: inline-block;
    padding: 1pt 5pt;
    border-radius: 2pt;
    font-size: 6.5pt;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
  }
  #print-report .pr-fbom-mode-porous {
    color: #4A3A22;
    background: #F3EBDA;
    border: 0.3pt solid #C8B68F;
  }
  #print-report .pr-fbom-mode-reflective {
    color: #2F4757;
    background: #DEE8EF;
    border: 0.3pt solid #94B0C0;
  }
  #print-report .pr-fbom-rel {
    display: inline-block;
    padding: 1pt 5pt;
    border-radius: 2pt;
    font-size: 6.5pt;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
  }
  #print-report .pr-fbom-rel-measured  { color: #1B6E37; background: #E3F1E7; border: 0.3pt solid #A6CDB1; }
  #print-report .pr-fbom-rel-derived   { color: #8A6A1F; background: #F5EEDD; border: 0.3pt solid #C9B786; }
  #print-report .pr-fbom-rel-estimated { color: #7A2018; background: #F2DDDA; border: 0.3pt solid #C99A95; }
  #print-report .pr-fbom-cite {
    margin-left: 3pt;
    font-size: 6pt;
    color: var(--muted);
    font-weight: 400;
  }
  #print-report .pr-fbom-spark {
    display: block;
    width: 60pt;
    height: 14pt;
  }
  #print-report .pr-fbom-totals td {
    border-top: 0.4pt solid var(--ink);
    padding-top: 4pt;
  }
  #print-report .pr-fbom-citations {
    list-style: none;
    padding-left: 0;
    margin: 6pt 0 0 0;
    font-size: 7.5pt;
    color: var(--ink);
  }
  #print-report .pr-fbom-cite-li {
    display: grid;
    grid-template-columns: 20pt 1fr;
    gap: 4pt;
    margin-bottom: 5pt;
    page-break-inside: avoid;
  }
  #print-report .pr-fbom-cite-n {
    font-weight: 700;
    color: var(--muted);
  }
  #print-report .pr-fbom-cite-ref,
  #print-report .pr-fbom-cite-method,
  #print-report .pr-fbom-cite-notes {
    color: var(--muted);
    font-size: 7pt;
    line-height: 1.4;
  }

  /* Ambient noise as a band-strip fingerprint, not a table */
  #print-report .pr-bandstrip {
    display: grid;
    grid-template-columns: 70pt repeat(7, 1fr);
    border: 0.4pt solid var(--rule);
    margin: 4pt 0;
  }
  #print-report .pr-bandstrip-label {
    padding: 4pt 6pt;
    background: var(--paper-2);
    font-size: 7.5pt;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--muted);
    align-self: center;
    border-right: 0.4pt solid var(--rule);
  }
  #print-report .pr-bandstrip-cell {
    padding: 4pt 6pt;
    text-align: center;
    border-right: 0.4pt solid var(--rule);
  }
  #print-report .pr-bandstrip-cell:last-child { border-right: none; }
  #print-report .pr-bandstrip-cell-band {
    font-size: 7pt;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: 0.06em;
  }
  #print-report .pr-bandstrip-cell-value {
    font-size: 14pt;
    font-weight: 300;
    color: var(--ink);
    line-height: 1.1;
  }

  /* ----------- PRECISION PAGE (page 6) ----------- */
  #print-report .pr-precision-headline {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 12pt;
    align-items: center;
    margin: 4pt 0 8pt 0;
    padding: 8pt 10pt;
    border: 0.5pt solid var(--rule);
    background: var(--paper-2);
  }
  #print-report .pr-precision-sti {
    /* Bumped from 28 pt → 40 pt (v=557, Maya). Now unambiguously the
       page-opening statement on Chapter 02 Acoustic results — the user
       kept calling this "the answer" and the visual hierarchy now
       matches that framing. Hairline rules above/below the surrounding
       pr-sti-rt60-row do the framing without a box. */
    font-size: 40pt;
    font-weight: 300;
    color: var(--accent);
    line-height: 1;
    letter-spacing: -0.02em;
  }
  #print-report .pr-precision-sti-label {
    font-size: 7.5pt;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--muted);
    margin-bottom: 4pt;
  }

  /* Pass / marginal / fail tier strip */
  #print-report .pr-tierstrip {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    margin: 6pt 0 8pt 0;
    border: 0.4pt solid var(--rule);
  }
  #print-report .pr-tierstrip-cell {
    padding: 5pt 8pt;
    text-align: center;
    font-size: 8pt;
    border-right: 0.4pt solid var(--rule);
    color: var(--muted);
  }
  #print-report .pr-tierstrip-cell:last-child { border-right: none; }
  #print-report .pr-tierstrip-cell.pr-tierstrip-active {
    background: var(--accent);
    color: var(--paper);
    font-weight: 600;
  }

  /* ===========================================================
     CHAPTER 02 · ACOUSTIC RESULTS (merged page) — v=558 layout
     -----------------------------------------------------------
     Single A4 portrait. Block budget (mm of 277 usable):
       1. Chapter opener .................... 22
       2. STI cell (60 mm) | RT60 chart cell (~134 mm)
          — SIDE-BY-SIDE in one row, framed by hairlines ... 70
                                                  (was two stacked
                                                   sections at 32 + 80 mm,
                                                   compressed per user ask
                                                   "STI we put a 30% is
                                                   more than enough, and
                                                   reverb results on the
                                                   right")
       3. Joined listener × precision table . ~60 (scales w/ listeners)
       4. Consolidated band table (5 cols) .. 32  (Band · Mean α · Sabine
                                                   · Eyring · Ray-traced T30
                                                   mean (min–max))
       5. Footer (zones + ambient strip) .... 28
       Total ............................... ~212  (~38 mm freed vs v=557
                                                   by the side-by-side row)
     Layout history:
       Maya 2026-05-20    — initial merge of 3 pages into 1
       v=557 (2026-05-20-2) — KV-table redundancy with cover + Drawing 01
                              removed; band tables collapsed
       v=558 (2026-05-20-3) — STI + RT60 chart compressed into one row
       v=560 (2026-05-20-4) — STI cell filled with brand accent (white
                              reverse), "STI" metric tag + 54 pt number,
                              "Reverberation · RT60" chart title added
     Physics floor: Dr. Chen.
     ----------------------------------------------------------- */

  /* Page container — no special positioning; the constituent blocks
     do the work. Reserved for future page-level tweaks (page-break-
     inside avoid, etc.) without polluting .pr-page globally. */
  #print-report .pr-acoustic-results {
    /* nothing yet; class is a hook for future targeted rules */
  }

  /* Section h3s INSIDE the merged page use a quieter style than the
     chapter-opener h2. Same visual weight as a Sofia "block heading"
     in the appendix system: 9.5 pt, medium weight, hairline underline,
     no border-rule (the surrounding table borders provide separation). */
  #print-report .pr-acoustic-results .pr-block-h3 {
    font-size: 9.5pt;
    font-weight: 600;
    line-height: 1.2;
    color: var(--ink);
    margin: 4pt 0 4pt 0;
    letter-spacing: 0;
  }

  /* STI + RT60 side-by-side row (v=558, user-flagged compression).
     -----------------------------------------------------------
     Previously two stacked sections: STI bar full-width (32 mm tall)
     above RT60 chart full-width (70 mm tall), with hairlines around the
     STI bar. User: "STI we put a 30% is more than enough, and reverb
     results on the right ... trim it, so we can have better visual and
     space saving."
     New layout: ONE row, 60 mm STI cell on the left, ~134 mm chart cell
     on the right. STI block stacks vertically inside the narrow cell.
     Vertical budget collapses from ~108 mm → ~70 mm; ~38 mm freed.
     Hairlines retained around the row (not just the STI), so the row
     still reads as a distinct page-opening block. */
  #print-report .pr-acoustic-results .pr-sti-rt60-row {
    display: grid;
    grid-template-columns: 60mm 1fr;     /* ~30% / ~70% of 200 mm usable */
    gap: 6mm;
    align-items: stretch;
    border-top: 0.5pt solid var(--rule);
    border-bottom: 0.5pt solid var(--rule);
    padding: 6pt 0;
    margin-bottom: 6mm;
  }

  /* STI cell — v=560: filled with the brand accent (--accent #8C2A2A)
     as the "answer" panel, per user "do the template color background
     for STI to make it more elegant". The cell reads as a solid red
     card; STI metric tag + 54 pt number reverse out to white. The
     .pr-precision-headline switches from its default 2-col grid (number
     left, tier strip right) to a vertical stack so the narrow 60 mm
     column reads top-to-bottom: eyebrow · STI tag · 54 pt number ·
     tier strip · advisory sentence. */
  #print-report .pr-acoustic-results .pr-sti-cell {
    background: var(--accent);
    color: var(--paper);
    padding: 9pt 10pt;
    display: flex;
    flex-direction: column;
    justify-content: center;
  }
  #print-report .pr-acoustic-results .pr-sti-cell .pr-precision-headline {
    display: block;          /* override the default 2-col grid */
    grid-template-columns: none;
    gap: 0;
    border: none;
    background: transparent; /* cell carries the accent bg */
    padding: 0;
    margin: 0;
  }
  /* Vertical rhythm between the two inner blocks of the headline:
     the number-block (eyebrow + STI tag + number) and the tier-block
     (3-cell strip + advisory paragraph). 8 pt gap separates them. */
  #print-report .pr-acoustic-results .pr-sti-cell .pr-precision-headline > div {
    margin-bottom: 8pt;
  }
  #print-report .pr-acoustic-results .pr-sti-cell .pr-precision-headline > div:last-child {
    margin-bottom: 0;
  }
  /* Eyebrow label — reversed to a translucent white so it reads as a
     caption above the metric without competing with the number. */
  #print-report .pr-acoustic-results .pr-sti-cell .pr-precision-sti-label {
    color: rgba(255, 255, 255, 0.78);
    margin-bottom: 5pt;
  }
  /* "STI" metric tag (v=560) — names the number so a reader knows the
     54 pt figure is the Speech Transmission Index, not some other
     dimensionless score. Bold, uppercase, spaced. */
  #print-report .pr-acoustic-results .pr-sti-cell .pr-precision-sti-metric {
    font-size: 11pt;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--paper);
    line-height: 1;
    margin-bottom: 2pt;
  }
  /* The headline number — enlarged 40 pt → 54 pt (user: "enlarge the
     STI number") and reversed to white on the accent card. */
  #print-report .pr-acoustic-results .pr-sti-cell .pr-precision-sti {
    font-size: 54pt;
    color: var(--paper);
    line-height: 0.95;
  }
  /* Tier strip on the accent card — inactive cells are faint white
     outlines; the ACTIVE cell inverts to a white fill with accent text
     so the live tier still reads as the highlighted state against the
     red background. */
  #print-report .pr-acoustic-results .pr-sti-cell .pr-tierstrip {
    margin: 4pt 0 6pt 0;
    border-color: rgba(255, 255, 255, 0.45);
  }
  #print-report .pr-acoustic-results .pr-sti-cell .pr-tierstrip-cell {
    padding: 3pt 2pt;
    font-size: 6.5pt;
    color: rgba(255, 255, 255, 0.7);
    border-right-color: rgba(255, 255, 255, 0.45);
  }
  #print-report .pr-acoustic-results .pr-sti-cell .pr-tierstrip-cell.pr-tierstrip-active {
    background: var(--paper);
    color: var(--accent);
    font-weight: 700;
  }
  /* Advisory note reversed to near-white italic. */
  #print-report .pr-acoustic-results .pr-sti-cell .pr-note {
    color: rgba(255, 255, 255, 0.9);
  }
  /* Empty-precision fallback — pending dash keeps the white-on-accent
     treatment but at reduced opacity so it reads as "awaiting data". */
  #print-report .pr-acoustic-results .pr-sti-cell .pr-sti-pending {
    color: rgba(255, 255, 255, 0.6);
    font-weight: 300;
  }

  /* Ambient NC band-strip pinned to the BOTTOM of the red STI card
     (v=563, user: "move the NC table to the lowest part of the STI red
     bar, fit cleverly, match the color"). margin-top:auto eats the
     card's free vertical space so the strip sits at the floor while the
     STI headline stays centred above — and it NEVER grows the card,
     because flex auto-margins only consume EXISTING slack (the RT60
     chart cell defines the row height). If a future short-chart variant
     ever makes headline+strip exceed the chart cell, add overflow:hidden
     to .pr-sti-cell rather than letting the row grow — do NOT do that
     now (it would clip data silently). */
  #print-report .pr-acoustic-results .pr-sti-cell .pr-sti-ambient {
    margin-top: auto;            /* pin to card floor; never adds height */
    padding-top: 6pt;
    border-top: 0.5pt solid rgba(255, 255, 255, 0.45);
  }
  #print-report .pr-acoustic-results .pr-sti-cell .pr-sti-ambient-eyebrow {
    font-size: 6.5pt;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.78);
    margin-bottom: 4pt;
  }
  /* On-accent band-strip — no label cell (no room in 60 mm); 7 equal
     band cells fill the width. White-on-accent to match the tier strip:
     translucent-white dividers, band freqs faint, values solid white. */
  #print-report .pr-acoustic-results .pr-sti-cell .pr-bandstrip-onaccent {
    grid-template-columns: repeat(7, 1fr);
    border-color: rgba(255, 255, 255, 0.45);
    margin: 0;
  }
  #print-report .pr-acoustic-results .pr-sti-cell .pr-bandstrip-onaccent .pr-bandstrip-cell {
    padding: 3pt 1pt;
    border-right-color: rgba(255, 255, 255, 0.45);
  }
  #print-report .pr-acoustic-results .pr-sti-cell .pr-bandstrip-onaccent .pr-bandstrip-cell-band {
    /* Keep every band label on ONE line ("125 HZ" was wrapping to two
       lines in the narrow 60 mm cell while "1 KHZ" stayed on one, which
       pushed 60/52/45 below 40/36/34/33). nowrap + 5 pt keeps all seven
       labels single-line so the unit row aligns and the values below sit
       on one horizontal baseline. (v=570, user.) */
    font-size: 5pt;
    color: rgba(255, 255, 255, 0.7);
    letter-spacing: 0;
    white-space: nowrap;
  }
  #print-report .pr-acoustic-results .pr-sti-cell .pr-bandstrip-onaccent .pr-bandstrip-cell-value {
    font-size: 10pt;
    font-weight: 400;
    color: var(--paper);
  }

  /* RT60 chart cell — title on top, chart, then caption. Chart keeps
     its v=557 width (110 mm) since that's the size the inline SVG axis
     labels were tuned at; growing it scales the labels proportionally
     and they start to dominate. Cell is ~134 mm wide so a slim 24 mm
     of breathing room sits to the chart's right. */
  #print-report .pr-acoustic-results .pr-rt60-cell {
    display: flex;
    flex-direction: column;
  }
  /* "Reverberation · RT60" title (v=560) — names the chart so a reader
     knows the curves are reverberation time, matching the STI tag on
     the left cell. Same weight as a block h3. */
  #print-report .pr-acoustic-results .pr-rt60-title {
    font-size: 9.5pt;
    font-weight: 600;
    color: var(--ink);
    margin: 0 0 3pt 0;
    letter-spacing: 0;
    text-align: center;          /* v=562 — centered over the figure */
  }
  /* 4-series legend, centered row under the title (moved out of the plot
     interior in v=562 — Eyring/T30/Sabine/Mean α no longer fit inside). */
  #print-report .pr-acoustic-results .pr-rt60-legend {
    display: flex;
    justify-content: center;
    flex-wrap: wrap;
    gap: 3pt 12pt;
    font-size: 7pt;
    color: var(--ink);
    margin: 0 0 3pt 0;
  }
  #print-report .pr-acoustic-results .pr-rt60-legend span {
    display: inline-flex;
    align-items: center;
    gap: 3pt;
    white-space: nowrap;
  }
  #print-report .pr-acoustic-results .pr-rt60-cell .pr-rt60-chart {
    width: 132mm;
    height: 70mm;
  }
  #print-report .pr-acoustic-results .pr-rt60-cell .pr-caption {
    margin-top: 4pt;
    font-size: 7pt;
    line-height: 1.4;
    color: var(--muted);
  }

  /* Joined listener × precision table — the user's key insight: one row
     per listener, position columns left, ray-traced acoustic metrics
     right. Drop ID column (debug handle, not load-bearing); fold posture
     into the label cell as a muted parenthetical; ear-height moves to
     the table footnote (derived from posture + elevation, not measured).
     Em-dash for missing precision cells per Dr. Chen — distinguishes
     "not rendered" from STI = 0 (undefined per IEC 60268-16). */
  #print-report .pr-listener-precision {
    font-size: 7.5pt;
    table-layout: fixed;
  }
  #print-report .pr-listener-precision th,
  #print-report .pr-listener-precision td {
    padding: 2pt 4pt;
    font-size: 7.5pt;
  }
  #print-report .pr-listener-precision th:first-child,
  #print-report .pr-listener-precision td:first-child {
    text-align: left;
    width: 28%;
  }
  /* The remaining 9 columns share the 72% balance evenly. */
  #print-report .pr-listener-precision th:not(:first-child),
  #print-report .pr-listener-precision td:not(:first-child) {
    width: 8%;
  }
  /* Label cell: name in ink, posture parenthetical in muted span. */
  #print-report .pr-listener-label {
    font-weight: 500;
    color: var(--ink);
  }
  #print-report .pr-listener-posture {
    font-weight: 400;
    color: var(--muted);
    font-size: 6.5pt;
  }

  /* Consolidated 5-col band table (v=557) — replaces the old paired
     side-by-side tables (room-avg Sabine/Eyring left, per-listener
     ×per-band T30 matrix right). One row per octave band, columns:
       Band | Mean α | Sabine RT60 | Eyring RT60 | Ray-traced T30 mean (min–max)
     Sabine + Eyring bracket the ray-traced ground truth as theoretical
     bounds; the (min–max) parens surface per-listener spread without
     the 8-col receiver matrix that overwhelmed a proposal reader. */
  #print-report .pr-band-consolidated th,
  #print-report .pr-band-consolidated td {
    font-size: 8pt;
    padding: 2.5pt 5pt;
  }
  #print-report .pr-band-consolidated th:first-child,
  #print-report .pr-band-consolidated td:first-child {
    text-align: left;
    font-weight: 500;
  }
  #print-report .pr-band-cell-band {
    color: var(--ink);
    letter-spacing: 0.02em;
  }
  /* (min–max) range in the ray-traced T30 column — muted secondary
     read, sits visually behind the mean without being illegible. */
  #print-report .pr-band-range {
    color: var(--muted);
    font-size: 7pt;
    margin-left: 2pt;
  }

  /* Footer strip (block 6) — zones table left, ambient noise band-strip
     right. Both demoted from their old Appendix B treatment: inline
     eyebrow instead of h2, dense cells, no breathing room above. */
  #print-report .pr-footer-grid {
    /* Single column (v=563) — ambient strip moved into the STI card, so
       the zones table now spans the full page width. */
    display: grid;
    grid-template-columns: 1fr;
    gap: 6mm;
    align-items: start;
    margin-top: 4pt;
  }
  #print-report .pr-footer-cell { min-width: 0; }
  #print-report .pr-footer-cell > .pr-eyebrow {
    display: block;
    margin-bottom: 3pt;
    font-size: 7pt;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--muted);
  }
  #print-report .pr-zones-footer {
    font-size: 7.5pt;
  }
  #print-report .pr-zones-footer th,
  #print-report .pr-zones-footer td {
    font-size: 7.5pt;
    padding: 2pt 4pt;
  }
  /* Inside the footer, the ambient band-strip shrinks slightly so it
     sits visually balanced beside the zone table (the standalone
     Appendix-B strip was full-page-wide). */
  #print-report .pr-footer-cell .pr-bandstrip {
    grid-template-columns: 50pt repeat(7, 1fr);
    margin: 0;
  }
  #print-report .pr-footer-cell .pr-bandstrip-label {
    padding: 3pt 4pt;
    font-size: 6.5pt;
  }
  #print-report .pr-footer-cell .pr-bandstrip-cell {
    padding: 3pt 2pt;
  }
  #print-report .pr-footer-cell .pr-bandstrip-cell-value {
    font-size: 11pt;
  }
  #print-report .pr-footer-cell .pr-bandstrip-cell-band {
    font-size: 6pt;
  }

  /* ===========================================================
     METHODOLOGY + DISCLAIMERS + SIGNATURE PAGE (last A4 page)
     -----------------------------------------------------------
     CLEAN-SLATE REWRITE Edition 2026-05-14 (9th iteration).
     Five classes total. ONE coherent type system. Every paragraph
     on this page is a <p class="pg-prose"> — identical element +
     identical class = identical baseline by construction.

     Type tiers (DO NOT add a fourth):
       pg-prose          6.5 pt sans, weight 400, line-height 1.35
       pg-section-label  6 pt, weight 700, uppercase, ls 0.12em
       pg-method-cite    5.5 pt italic, weight 400, muted
       (page title h2)   11.5 pt, weight 600

     Spacing scale: every vertical margin is k·3pt (3 / 6 / 9 / 12).
     If you're tempted to add a 1.5pt or 4pt or 5pt margin — STOP.
     Round to the nearest 3pt. That's why this page is stable.
     =========================================================== */

  #print-report .pg-methodology {
    /* Page layout — natural document flow, NO flex column. Earlier
       flex+margin-top:auto pinning was the source of half the drift
       between rounds (margins compounding into the flex gap budget).
       Plain stacking lets the page grow top-down predictably. */
    font-family: var(--font-sans);
    color: var(--ink);
  }

  /* ----- TYPE SYSTEM — single source of truth for all prose ----- */

  /* The page title — only h2 on the page. */
  #print-report .pg-methodology .pg-page-title {
    font-family: var(--font-sans);
    font-size: 11.5pt;
    font-weight: 600;
    line-height: 1.15;
    letter-spacing: 0;
    color: var(--ink);
    margin: 0 0 6pt 0;
    padding: 0 0 3pt 0;
    border-bottom: 0.6pt solid var(--ink);
  }

  /* Section labels — h3 above each block. */
  #print-report .pg-methodology .pg-section-label {
    font-family: var(--font-sans);
    font-size: 7pt;
    font-weight: 700;
    line-height: 1.2;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--muted);
    margin: 9pt 0 3pt 0;
    padding: 0;
    border: none;
    break-after: avoid;
  }
  /* First section label gets less top margin — the intro paragraph
     already supplies vertical breathing room above it. */
  #print-report .pg-methodology .pg-intro + .pg-section-label {
    margin-top: 6pt;
  }

  /* THE prose tier — disclaimers, acceptance, reviewer, intro AND
     methodology entry bodies all use this exact class. Properties
     listed exhaustively so no inherited rule can shift one of them.
     Override #print-report tabular-nums explicitly. */
  #print-report .pg-methodology .pg-prose {
    font-family: var(--font-sans);
    font-size: 7pt;
    line-height: 1.35;
    font-weight: 400;
    font-style: normal;
    letter-spacing: 0;
    word-spacing: normal;
    text-align: justify;       /* Full-width prose (intro, disclaimers,
                                  acceptance, reviewer) justifies cleanly for
                                  a neat block edge (user v=576). The NARROW
                                  4-col method grid is overridden back to
                                  left below — justify there flows ugly
                                  river-gaps (the original reason this was
                                  left); hyphens:auto keeps the wide blocks
                                  river-free. */
    text-indent: 0;
    hyphens: auto;
    color: var(--ink);
    font-variant-numeric: normal;
    font-feature-settings: normal;
    font-kerning: auto;
    margin: 0 0 3pt 0;
    padding: 0;
    break-inside: avoid;
  }
  /* Page intro — same prose tier, just a slightly larger bottom margin
     for visual separation from the first section label. Plus a comfort gap
     ABOVE: the page title now lives in the running header (v=571), so the
     intro is the first content under the rule and must clear it. Set here
     (not in the generic running-header sibling rule) because the .pg-prose
     `margin: 0 0 3pt 0` shorthand above zeroes margin-top at equal
     specificity — this later .pg-intro longhand wins. (v=573, user: "still
     too near to the line".) */
  #print-report .pg-methodology .pg-intro {
    margin-top: 7mm;
    margin-bottom: 3pt;
  }
  /* Strong tag inside prose (reviewer note "Reviewer's note —" lead)
     stays in prose colour, just bolded; no size or spacing change. */
  #print-report .pg-methodology .pg-prose strong {
    font-weight: 700;
    color: var(--ink);
  }

  /* ----- METHODOLOGY GRID — 4 columns, balanced height ----- */
  #print-report .pg-methodology .pg-method-grid {
    column-count: 4;
    column-gap: 9pt;
    column-fill: balance;
    margin: 0 0 3pt 0;
  }
  #print-report .pg-methodology .pg-method-entry {
    margin: 0 0 6pt 0;
    padding: 0 0 0 3pt;
    border-left: 0.3pt solid var(--rule);
    break-inside: avoid;
    -webkit-column-break-inside: avoid;
    page-break-inside: avoid;
  }
  #print-report .pg-methodology .pg-method-heading {
    font-family: var(--font-sans);
    font-size: 7pt;
    font-weight: 700;
    line-height: 1.25;
    letter-spacing: 0;
    color: var(--ink);
    margin: 0;
  }
  #print-report .pg-methodology .pg-method-cite {
    font-family: var(--font-sans);
    font-size: 6pt;
    font-weight: 400;
    font-style: italic;
    line-height: 1.3;
    letter-spacing: 0;
    color: var(--muted);
    margin: 0;
  }
  /* Methodology body paragraph — already gets .pg-prose styling above.
     Add a tiny top margin so it sits clear of the cite line, and
     keep its bottom margin tight inside the entry block. */
  #print-report .pg-methodology .pg-method-entry .pg-prose {
    margin: 0;
    /* User v=656: full-justify across the whole methodology page,
       consistent with the wide prose blocks (intro, disclaimers,
       acceptance, reviewer). The narrow 4-col grid can flow visible
       word-space gaps on short lines; hyphens:auto (inherited from
       .pg-prose) softens that. */
    text-align: justify;
  }

  /* ----- SESSION SIGNATURE ROW — 5 captured fields ----- */
  /* Signature row: 5 KV pairs. Labels reuse the SAME .pg-section-label
     tier as every other label on the page; values reuse the SAME .pg-prose
     tier as every other paragraph. No bespoke typography here. The cream
     background is gone — page is one consistent prose surface. */
  #print-report .pg-methodology .pg-signature-row {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 3pt 9pt;
    margin: 0 0 6pt 0;
    padding: 0;
    background: transparent;
    break-inside: avoid;
  }
  #print-report .pg-methodology .pg-signature-cell {
    display: flex;
    flex-direction: column;
    gap: 1pt;
  }
  /* Key = exact same class spec as .pg-section-label.
     Value = exact same class spec as .pg-prose, just inline (no margin). */
  #print-report .pg-methodology .pg-signature-key {
    font-family: var(--font-sans);
    font-size: 6.5pt;
    font-weight: 700;
    line-height: 1.2;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--muted);
  }
  #print-report .pg-methodology .pg-signature-val {
    font-family: var(--font-sans);
    font-size: 6.5pt;
    font-weight: 400;
    line-height: 1.35;
    letter-spacing: 0;
    color: var(--ink);
    word-break: break-word;
  }

  /* ----- WET-SIGNATURE BLOCK — 3 cells (Author / Company / Date) -----
     Table layout for print-engine reliability (Chrome / Firefox / Safari
     all honour table-cell widths + borders consistently in print). */
  #print-report .pg-methodology .pg-signoff {
    width: 100%;
    margin: 9pt 0 0 0;
    border-collapse: collapse;
    table-layout: fixed;
    break-inside: avoid;
    page-break-inside: avoid;
  }
  #print-report .pg-methodology .pg-signoff-sub-row {
    border: none;
  }
  /* Sub-label sits ABOVE each cell — same .pg-section-label spec
     as every other label on the page, just rendered at 10 % opacity
     so it reads as a faint guide caption without competing with the
     writing target. */
  #print-report .pg-methodology .pg-signoff-sub {
    font-family: var(--font-sans);
    font-size: 6.5pt;
    font-weight: 700;
    line-height: 1.2;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: rgba(26, 31, 36, 0.30);
    text-align: left;
    padding: 0 0 1pt 1pt;
    border: none;
    vertical-align: bottom;
  }
  #print-report .pg-methodology .pg-signoff-cell {
    width: 50mm;
    height: 22mm;
    border: 0.4pt solid rgba(26, 31, 36, 0.10);
    padding: 3pt 6pt;
    vertical-align: bottom;
    text-align: center;
    position: relative;
  }
  #print-report .pg-methodology .pg-signoff-spacer {
    width: 4mm;
    border: none;
    padding: 0;
  }
  #print-report .pg-methodology .pg-signoff-line {
    display: block;
    width: 100%;
    height: 14mm;
    border-bottom: 0.5pt solid var(--ink);
    margin: 0 0 1pt 0;
  }
  #print-report .pg-methodology .pg-signoff-label {
    display: block;
    font-family: var(--font-sans);
    font-size: 6.5pt;
    font-weight: 700;
    line-height: 1.2;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink);
    text-align: left;
  }

  /* Empty state — paper-2 panel, muted accent bar */
  #print-report .pr-empty-state {
    padding: 10pt 12pt;
    background: var(--paper-2);
    border-left: 2pt solid var(--muted);
    font-size: 9pt;
    color: var(--ink);
    margin: 4pt 0;
  }

  #print-report .pr-section p {
    font-size: 9pt;
    line-height: 1.5;
    margin: 3pt 0 6pt 0;
    color: var(--ink);
  }

  /* ----------- FOOTER ----------- */
  #print-report .pr-foot {
    border-top: 0.5pt solid var(--rule);
    padding-top: 4pt;
    font-size: 7.5pt;
    letter-spacing: 0.04em;
    color: var(--muted);
    text-align: center;
    margin-top: 10pt;
  }

  /* ----------- CHAPTER 04: ACOUSTIC TREATMENT ----------- */
  /* Chapter 04 hero page — paired-bar comparison chart sits between the
     chapter opener and the KPI table. Layout mirrors Chapter 02 so a
     reader flipping pages sees the same composition rhythm. */
  #print-report .pr-page-treatment-hero,
  #print-report .pr-page-treatment-plan {
    break-before: page;
  }

  /* Dr. Chen's framing sentence — slightly more prominent than body
     copy so it reads as the chapter's thesis, but not louder than the
     chart that follows. */
  #print-report .pr-lead-chen {
    font-size: 10pt;
    line-height: 1.55;
    color: var(--ink);
    border-left: 2pt solid var(--accent);
    padding-left: 8pt;
    margin: 6pt 0 8pt 0;
    font-style: italic;
  }

  /* Comparison chart wrap — centred, white background, hairline frame
     so the SVG bars read crisp on the page. */
  #print-report .pr-compare-chart-wrap {
    text-align: center;
    margin: 4pt 0 2pt 0;
  }
  #print-report .pr-compare-chart {
    display: block;
    margin: 0 auto;
    max-width: 100%;
  }

  /* KPI table — right-align numerics, tabular-nums for column alignment. */
  #print-report .pr-compare-kpi td.pr-num,
  #print-report .pr-compare-kpi th.pr-num,
  #print-report .pr-treatment-schedule td.pr-num,
  #print-report .pr-treatment-schedule th.pr-num,
  #print-report .pr-alpha-matrix td.pr-num,
  #print-report .pr-alpha-matrix th.pr-num {
    text-align: right;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
  }

  /* Δ-cell colouring — green for improvement, red for regression,
     muted grey when no change or insufficient data. */
  #print-report .pr-delta-improve {
    color: #2C7A4B;
    font-weight: 600;
  }
  #print-report .pr-delta-regress {
    color: #A8332B;
    font-weight: 600;
  }
  #print-report .pr-delta-neutral {
    color: var(--muted);
  }

  /* Drawing 03 — plan + legend in a 2-column grid. Plan takes the
     larger column; the swatch legend on the right keeps the reader's
     eye anchored to the colour code while they scan the schedule. */
  #print-report .pr-treatment-plan-grid {
    display: grid;
    grid-template-columns: 1fr 38mm;
    gap: 6mm;
    align-items: start;
    margin: 4pt 0 4pt 0;
  }
  #print-report .pr-treatment-plan-stage {
    border: 0.4pt solid var(--rule);
    padding: 2mm;
    background: var(--paper);
  }
  #print-report .pr-treatment-plan-svg {
    display: block;
    width: 100%;
    height: auto;
  }
  #print-report .pr-treatment-plan-key {
    font-size: 8pt;
    line-height: 1.5;
    color: var(--ink);
  }
  #print-report .pr-treatment-key-title {
    font-size: 8.5pt;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    margin-bottom: 4pt;
    color: var(--muted);
  }
  #print-report .pr-treatment-key-row {
    display: flex;
    align-items: center;
    gap: 5pt;
    margin-bottom: 3pt;
  }
  #print-report .pr-treatment-key-swatch {
    display: inline-block;
    width: 10pt;
    height: 10pt;
    border-radius: 1pt;
    border: 0.4pt solid #1A1F24;
    flex: 0 0 auto;
  }
  #print-report .pr-treatment-key-ceiling {
    background: transparent;
    border-style: dashed;
    border-width: 0.8pt;
  }

  /* Treatment schedule — denser text + no horizontal overflow even
     with 11 columns. NRC / α columns are 1-2 chars so we can afford
     tight column widths. Manual column-padding override prevents the
     fire-rating + weight columns from being squashed off the page. */
  #print-report .pr-treatment-schedule {
    font-size: 7.5pt;
    line-height: 1.35;
  }
  #print-report .pr-treatment-schedule th,
  #print-report .pr-treatment-schedule td {
    padding: 2.5pt 3pt;
  }

  /* Per-band α matrix — denser still; 8 columns (Tag + 7 bands). */
  #print-report .pr-alpha-matrix {
    font-size: 7.5pt;
    line-height: 1.35;
    margin-top: 4pt;
  }
  #print-report .pr-alpha-matrix th,
  #print-report .pr-alpha-matrix td {
    padding: 2pt 3pt;
  }

  /* Aggregate strip — the "X panels · Y m² · Z kg" one-liner under
     the schedule. Reads as a quiet receipt of the totals. */
  #print-report .pr-aggregate {
    font-size: 8.5pt;
    color: var(--ink);
    background: var(--paper-2);
    padding: 5pt 8pt;
    margin: 4pt 0 0 0;
    border-left: 2pt solid var(--accent);
    font-feature-settings: "tnum" 1;
  }

  /* "clamped" badge inline in the schedule — pings the engineer that
     the panel's catalogue area exceeded the host-wall budget and the
     physics math applied a clamp. */
  #print-report .pr-clamp-badge {
    display: inline-block;
    font-size: 6.5pt;
    background: #F0E4C8;
    color: #6B5610;
    padding: 0.4pt 3pt;
    border-radius: 2pt;
    margin-left: 3pt;
    letter-spacing: 0.04em;
    text-transform: lowercase;
    vertical-align: 1pt;
  }

/* (Chrome-hide rules moved to top of file — applied via @media print
   AND body.is-pdf-export so they cover both paths.) */
