/* Printed and exported dashboards are documents, not screenshots of the app:
   force the light palette regardless of the on-screen theme, hide in-app
   chrome (rail, composer, per-panel action controls), and stop a panel
   splitting across a page boundary.

   ApexCharts draws inline SVG, which — unlike a Chart.js <canvas> — a
   stylesheet COULD in principle recolour after the fact. This app does not
   rely on that: real printing (theme.js's beforeprint/afterprint handlers)
   and the html2pdf export path (dashboard.js's withExportLayout) both flip
   data-bs-theme to "light" for their duration instead, which is what
   chart-theme.js already listens for ("themechange") to re-theme every
   registered chart light-on-white through its own updateOptions/updateSeries
   calls — the same values pushed into the chart's own config, not a
   stylesheet override sitting on top of it. That means this stylesheet only
   has to carry the surrounding page — the light values below are a
   defensive fallback for the DOM in case JS did not run in time, not the
   mechanism charts rely on. */
@media print {
    :root, [data-bs-theme="dark"] {
        --surface: #ffffff; --surface-raised: #ffffff; --surface-sunken: #f4f7fc;
        --text: #0f172a; --text-muted: #475569; --text-subtle: #5f6d85;
        --border: #d9e2ef; --accent: #0a68bd;
        --shadow-sm: none; --shadow-md: none; --shadow-lg: none;
    }

    .app-rail, .app-composer, .panel-action, .panel-menu,
    .panel-feedback, .no-print { display: none !important; }

    /* A clipped scroller prints clipped, and paper has no scrollbar to drag — same
       reason as the body.is-exporting rule further down. */
    .table-responsive { overflow: visible !important; }

    /* "Show as" and Legend/Values are presentation controls, not content —
       same reasoning as the chrome above. */
    .feedback-chart, .chart-controls,
    /* ApexCharts' toolbar is the same kind of thing — a presentation control — but it
       lives INSIDE the chart container, so the two selectors beside it never reached it
       and it rasterised into the corner of every chart on paper. */
    .apexcharts-toolbar { display: none !important; }

    .app-shell   { display: block; }
    .app-results { padding: 0; overflow: visible; }

    .panel {
        border: 1px solid var(--border);
        box-shadow: none;
        break-inside: avoid; page-break-inside: avoid;
    }
    .dashboard-grid > [class*="col-"] { break-inside: avoid; page-break-inside: avoid; }

    a[href]::after { content: ""; }   /* Bootstrap prints URLs otherwise */
}

/* ── html2pdf export path ──────────────────────────────────────────────────
   dashboard.js's withExportLayout toggles body.is-exporting for the duration
   of exportDashboardPdf / exportPanelPdf. html2canvas renders the live DOM
   under screen media — the @media print rule above never matches there — so
   the chrome-hiding and shadow/border flattening has to be repeated as a
   plain rule. Colour needs no override here: the same helper also flips
   data-bs-theme to "light" for the export, so every token already resolves
   to tokens.css's light values by the time html2canvas measures the DOM. */
body.is-exporting .app-rail,
body.is-exporting .app-composer,
body.is-exporting .panel-action,
body.is-exporting .panel-menu,
body.is-exporting .panel-feedback { visibility: hidden; }

/* Unlike the chrome above, these two must leave the render tree entirely
   (display: none, not visibility: hidden) rather than just go invisible.
   Bootstrap draws their control (the "Show as" <select> and the Legend/
   Values <input type=checkbox> switches) with a two-layer background-image
   — one url() layer plus a bare `none` layer — and the bundled html2canvas
   throws "Unsupported image type" walking that value on an element it still
   has to lay out. A hidden-but-present element still gets that walk;
   display: none removes it from the tree so html2canvas never reaches it.
   Confirmed by reproducing the crash and clearing it with this rule alone,
   nothing else changed (see task-13-report.md). */
body.is-exporting .feedback-chart,
body.is-exporting .chart-controls,
/* Same reason as the print rule: inside the chart, so hiding the surrounding controls
   does not hide it, and html2canvas rasterises whatever is laid out — a dashboard PDF
   would carry a zoom/pan/download widget on every panel. */
body.is-exporting .apexcharts-toolbar { display: none !important; }

/* A .table-responsive is overflow-x:auto on screen — right for reading, wrong for
   rasterising: html2canvas renders what the box SHOWS, so every column past the
   scroller's edge was simply absent from the PDF. Unclipped here so the whole table is
   laid out where savePdfOf (dashboard.js) can measure it and widen html2pdf's container
   to match, letting html2pdf scale it down to the page instead of cutting it off.

   Deliberately its OWN rule, after the display:none list above and not inside it — the
   first version of this change spliced the selector into the middle of that list, which
   quietly dropped .feedback-chart from it. That is the element whose two-layer
   background-image html2canvas cannot parse, so every export died on "Unsupported image
   type" until the rule was moved back out. */
body.is-exporting .table-responsive { overflow: visible !important; }

body.is-exporting .panel {
    box-shadow: none; border: 1px solid var(--border);
    break-inside: avoid; page-break-inside: avoid;
}

/* html2canvas/html2pdf renders under screen media too, so the @media print
   break-avoidance rules above never reach this path either — duplicated here
   for the same reason the chrome-hiding and border/shadow rules were.
   html2pdf's own pagebreak heuristic ('avoid-all') targets <tr>/<img>, not
   arbitrary .panel divs, so without this a panel can still be cut across a
   PDF page boundary. */
body.is-exporting .dashboard-grid > [class*="col-"] { break-inside: avoid; page-break-inside: avoid; }

/* ── Organize mode and the page-break spacers ──────────────────────────────
   components.css plans an organized grid with `order` and moves nothing in the DOM, which is
   right for the screen: streaming, Refresh and corrections all stay simple. html2pdf's
   pagebreak plugin, though, inserts each spacer into the DOM in front of the panel it is
   pushing onto the next page — and a spacer is a flex item with no order of its own, so every
   one of them sorted to the front of the row instead. Measured on an organized 24-panel
   dashboard: 16 spacers, none landing on a page boundary, and nine panels still sliced across
   one; unplanned, the same dashboard gave 3 spacers on exact boundaries and nothing sliced.

   dashboard.js's orderPanelsForExport has already re-appended the panels in the planned order
   by the time this applies, so dropping `order` changes nothing about what the reader gets —
   it only makes document order and visual order the same thing, which is what the spacers
   assume. Deliberately just `order`: the planned widths in the same rule (--org-basis) are
   what give the rows their shape and must survive. */
body.is-exporting .dashboard-grid.is-organized > .dashboard-panel { order: 0; }

/* ── The score bars in a table ─────────────────────────────────────────────
   A .score-bar is an inline-block strip with a percentage-width child painting the fill
   (components.css). html2canvas draws the strip and drops the child: measured on a four-row
   table, every bar came out an empty grey pill — the 100% ones included — leaving the number
   beside it as the only thing saying what the score was, which is the column's whole point.

   Taking the fill out of the inline-block's flow and placing it against the strip is what
   makes it paint. Measured, the same four bars then came out at exactly 100%, 100%, 20% and
   20%. The percentage the renderer writes inline is untouched: against a positioned strip it
   still resolves to the same share of the same 40px. Every other way of keeping the layout
   was measured and did nothing — inline-flex, inline-grid, an explicit height on the fill,
   dropping the border-radius, dropping the strip's overflow. Only `display: block` on the
   strip also worked, and that would drop the number onto its own line. */
body.is-exporting .score-bar       { position: relative; }
body.is-exporting .score-bar > span { position: absolute; top: 0; left: 0; bottom: 0; }
