/* ==========================================================================
   SMB IT Budget Estimator — site theme
   Styles for tools/it-budget.html.

   Loaded AFTER styles.css. Every rule is scoped under `.itb-app` so the tool's
   dense 14px UI cannot leak into the navbar, hero or footer — and so the site's
   editorial h1–h6 / p / a rules cannot blow up the tool's compact typography.

   Same technique as cost-of-living.theme.css: the tool declares its OWN custom
   property names on the wrapper and maps each onto a site design token, so the
   markup and JS never reference a site token directly. Deliberately a SEPARATE
   file from the planner's theme — that one is scoped `.col-app`, and sharing it
   would mean a change for one tool silently altering the other. Some rule
   duplication across the two is accepted; extract a shared base at three tools.
   ========================================================================== */

.itb-app {
    /* ---- tool vars → site design tokens ---- */
    --bg: var(--color-bg-primary);
    --card: var(--color-surface);
    --raised: var(--color-raised);
    --ink: var(--color-text-primary);
    --dim: var(--color-text-secondary);
    --muted: var(--color-text-muted);
    --line: var(--color-border);
    --line-strong: var(--color-border-strong);
    --accent: var(--color-primary);
    --accent-soft: rgba(229, 163, 68, 0.12);
    --pos: var(--color-text-primary);
    --neg: var(--color-error);
    --warn: var(--color-warning);
    --warn-soft: rgba(224, 184, 75, 0.1);

    /* ---- series colours (cost type only) ----
       The single documented exception to the one-hue chart rule — see DESIGN.md
       "Series colour" and the .sharebar block below. These paint three fixed,
       meaningfully-ordered series, never a nominal category, and each has a paper
       counterpart in the print block. Do not reach for them for decoration: the
       one-accent guardrail is untouched everywhere else. */
    --series-recurring: var(--accent);
    --series-labour: #4FB08A;
    --series-capital: #7E8AA2;
    --series-extra: var(--line-strong);

    /* DESIGN.md: flat surfaces, hairline rules, no glow — structure, not effects */
    --shadow: none;

    /* Native widgets (the select popup above all) are drawn by the OS, not by
       these rules. Without this the popup renders light-mode while inheriting the
       near-white `color` off the select — white text on a white menu. Declaring
       the scheme is what actually fixes it; the explicit option colours below are
       the belt-and-braces for engines that ignore it. */
    color-scheme: dark;
    /* Firefox draws the .table-scroll horizontal scrollbar as a solid WHITE bar
       straight across the dark card — verified in a real Firefox render, not
       assumed; `color-scheme: dark` alone did not stop it. Naming both halves
       does. Chromium is unaffected either way. */
    scrollbar-color: var(--line-strong) var(--card);

    font-family: var(--font-primary);
    font-size: 14px;
    /* dense data tool: deliberately below the site's 1.0625rem body */
    line-height: 1.45;
    color: var(--ink);
}

/* Neutralize the site's editorial typography inside the tool */
.itb-app h1,
.itb-app h2,
.itb-app h3,
.itb-app p {
    font-family: inherit;
    font-size: inherit;
    font-weight: inherit;
    line-height: inherit;
    letter-spacing: normal;
    color: inherit;
    margin: 0;
    max-width: none;
}

.itb-app * {
    box-sizing: border-box;
}

.itb-app .wrap {
    /* wider than the planner's 1240px: this tool's line table carries eight
       columns and must fit beside the sticky summary without scrolling */
    max-width: 1400px;
    margin: 0 auto;
    padding: 112px 2rem 96px;
    /* 112px clears the fixed navbar */
}

/* ---------- tool header ---------- */
.itb-app header.app {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 1.5rem;
    flex-wrap: wrap;
    padding-bottom: 1.25rem;
    margin-bottom: 2rem;
    border-bottom: 1px solid var(--line);
}

.itb-app .doc-title {
    font-family: var(--font-display);
    font-size: 2rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--ink);
    background: transparent;
    border: 0;
    border-bottom: 1px dashed transparent;
    padding: 0 0 2px;
    width: min(420px, 100%);
}

.itb-app .doc-title:hover {
    border-bottom-color: var(--line-strong);
}

.itb-app .doc-title:focus {
    outline: none;
    border-bottom-color: var(--accent);
}

.itb-app header.app .sub {
    color: var(--muted);
    font-family: var(--font-mono);
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    margin-top: 0.6rem;
}

.itb-app .actions {
    display: flex;
    gap: 0.5rem;
}

/* ---------- buttons ---------- */
.itb-app button {
    font-family: var(--font-primary);
    font-size: 0.82rem;
    border-radius: var(--radius-md);
    border: 1px solid var(--line);
    background: var(--raised);
    color: var(--ink);
    padding: 0.5rem 0.9rem;
    cursor: pointer;
    transition: border-color 200ms ease, background 200ms ease, color 200ms ease;
}

.itb-app button:hover {
    border-color: var(--accent);
}

.itb-app button.primary {
    background: var(--accent);
    border-color: var(--accent);
    color: #14100a;
    font-weight: 600;
}

.itb-app button.primary:hover {
    background: var(--color-primary-dark, #D18F2E);
    border-color: var(--color-primary-dark, #D18F2E);
}

.itb-app button.ghost {
    background: transparent;
}

.itb-app button.mini {
    font-size: 0.78rem;
    padding: 0.4rem 0.7rem;
}

.itb-app button.danger {
    background: transparent;
    border-color: transparent;
    color: var(--muted);
    padding: 0.2rem 0.4rem;
    line-height: 1;
}

.itb-app button.danger:hover {
    color: var(--neg);
    border-color: var(--neg);
}

/* ---------- layout ---------- */
.itb-app .grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 320px;
    gap: 1.5rem;
    align-items: start;
}

.itb-app .col-main {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
    min-width: 0;
}

.itb-app .summary {
    position: sticky;
    top: 96px;
}

/* ---------- cards ---------- */
.itb-app .itb-card {
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow);
    overflow: hidden;
}

.itb-app .itb-card h2 {
    font-family: var(--font-mono);
    font-size: 0.72rem;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.16em;
    color: var(--accent);
    padding: 0.9rem 1.25rem;
    border-bottom: 1px solid var(--line);
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex-wrap: wrap;
}

.itb-app .badge {
    font-family: var(--font-mono);
    font-size: 0.62rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--muted);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    padding: 0.15rem 0.45rem;
}

.itb-app .itb-card .body {
    padding: 1.25rem;
}

.itb-app .sub-head {
    font-family: var(--font-mono);
    font-size: 0.68rem;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--muted);
    margin: 1.5rem 0 0.75rem;
    padding-bottom: 0.4rem;
    border-bottom: 1px solid var(--line);
}

.itb-app .note {
    color: var(--dim);
    margin-bottom: 1.1rem;
    max-width: 68ch;
}

.itb-app .footnote {
    color: var(--muted);
    font-size: 0.78rem;
    line-height: 1.6;
    margin-top: 1.1rem;
    padding-top: 0.9rem;
    border-top: 1px solid var(--line);
    max-width: 78ch;
}

.itb-app .warn-line {
    margin-top: 1rem;
    padding: 0.6rem 0.8rem;
    border: 1px solid var(--warn);
    background: var(--warn-soft);
    border-radius: var(--radius-sm);
    color: var(--ink);
    font-size: 0.82rem;
}

/* ---------- fields ---------- */
.itb-app .field-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(175px, 1fr));
    gap: 1rem;
}

.itb-app .field {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    min-width: 0;
}

/* Labels differ in height (some carry a `small` hint). Push the control to the
   bottom of the cell so every input in a row lines up regardless. */
.itb-app .field input,
.itb-app .field .money-in {
    margin-top: auto;
}

.itb-app .field label {
    color: var(--dim);
    font-size: 0.82rem;
}

.itb-app .field label small {
    display: block;
    color: var(--muted);
    font-size: 0.72rem;
    margin-top: 0.1rem;
}

.itb-app input,
.itb-app select {
    font-family: var(--font-primary);
    font-size: 0.86rem;
    color: var(--ink);
    background: var(--bg);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    padding: 0.42rem 0.55rem;
    width: 100%;
    min-width: 0;
    transition: border-color 200ms ease;
}

.itb-app input:hover,
.itb-app select:hover {
    border-color: var(--line-strong);
}

.itb-app input:focus,
.itb-app select:focus {
    outline: none;
    border-color: var(--accent);
}

/* The popup is a separate surface from the closed control: give it the raised
   tone so it reads as sitting above the card, and an opaque background — a
   translucent one composites against the OS menu, not against the page. */
.itb-app select option,
.itb-app select optgroup {
    background-color: var(--raised);
    color: var(--ink);
}

.itb-app select optgroup {
    color: var(--dim);
    font-style: normal;
    font-weight: 600;
}

/* The highlighted row in an open popup is painted with the DESKTOP's selection
   colour, not ours — captured at #99C8FF on a bare X server, but it is whatever
   the user's GTK theme says. Pair that with the author `color` above and the two
   halves are chosen by different parties, which is how you get near-white text
   on a near-white bar. Pin BOTH halves to the site's amber so the combination
   can never depend on the desktop. `background-color` alone is ignored on
   `option:checked` inside the Chromium popup — the gradient is the documented
   way through. */
.itb-app select option:checked,
.itb-app select option:hover {
    background: linear-gradient(0deg, var(--accent) 0%, var(--accent) 100%);
    background-color: var(--accent);
    color: #14100A;
}

.itb-app input[type="number"] {
    font-family: var(--font-mono);
    text-align: right;
}

.itb-app .money-in {
    position: relative;
}

.itb-app .money-in::before {
    content: "$";
    position: absolute;
    left: 0.55rem;
    top: 50%;
    transform: translateY(-50%);
    color: var(--muted);
    font-family: var(--font-mono);
    font-size: 0.8rem;
    pointer-events: none;
}

.itb-app .money-in input {
    padding-left: 1.5rem;
}

/* ---------- tables ---------- */
.itb-app .table-scroll {
    overflow-x: auto;
}

/* The line table carries selects and money inputs that become unreadable when
   squeezed. Hold its natural width and let .table-scroll scroll instead of
   letting `width:100%` crush the columns.

   This has to clear the SUM of the thead widths or it does nothing: below that,
   auto table layout shrinks every column proportionally and the declared widths
   are only suggestions. At 900px the Mode select rendered 92px against the 102px
   "Amortized" needs, and Per rendered 90px against 108px for "per quarter" —
   both clipped mid-word, which is the whole failure this rule exists to prevent.
   Re-measure and raise this if a column is added or an option label grows. */
.itb-app #lineTable {
    min-width: 1008px;
}

.itb-app table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.84rem;
}

.itb-app thead th {
    font-family: var(--font-mono);
    font-size: 0.66rem;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--muted);
    text-align: left;
    padding: 0.5rem 0.5rem;
    border-bottom: 1px solid var(--line);
    white-space: nowrap;
}

.itb-app td {
    padding: 0.4rem 0.5rem;
    border-bottom: 1px solid var(--line);
    vertical-align: middle;
}

.itb-app .num {
    text-align: right;
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
}

.itb-app th.num {
    text-align: right;
}

.itb-app .dash {
    color: var(--muted);
    text-align: center;
}

.itb-app .empty td {
    color: var(--muted);
    padding: 1.25rem 0.5rem;
    text-align: center;
}

.itb-app .label-cell {
    display: table-cell;
}

/* Print-only mirror of the line-name input — see the print block. */
.itb-app .label-cell .print-name {
    display: none;
}

/* Print-only mirror of every other control, written by syncPrintMirrors(). Same
   idea as .print-name, generalised: on paper nothing is rendered by a widget. */
.itb-app .print-mirror {
    display: none;
}

.itb-app .label-cell .cat-pick {
    margin-top: 0.3rem;
    font-size: 0.72rem;
    color: var(--muted);
    padding: 0.2rem 0.35rem;
}

.itb-app .count-cell {
    white-space: nowrap;
}

.itb-app .count-cell .ref {
    width: auto;
    /* fits "power seats", the longest UNIT_REFS label */
    max-width: 118px;
    display: inline-block;
}

/* Resolved unit count, written by recompute(). Muted while it is doing its job;
   amber the moment it is 0, because that is the one value that silently zeroes
   the whole line. Not red — a count of 0 is an unfinished profile, not an error. */
.itb-app .count-cell .ref-n {
    color: var(--muted);
    font-family: var(--font-mono);
    font-size: 0.72rem;
    margin-left: 0.25rem;
}

.itb-app .count-cell .ref-n.zero {
    color: var(--warn);
}

.itb-app .count-cell .qty,
.itb-app td .qty {
    width: 52px;
    display: inline-block;
}

.itb-app .times {
    color: var(--muted);
    margin: 0 0.3rem;
}

.itb-app .unit-note {
    color: var(--muted);
    font-size: 0.72rem;
    margin-left: 0.3rem;
}

.itb-app tr.cat-head td {
    font-family: var(--font-mono);
    font-size: 0.66rem;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--accent);
    background: var(--raised);
    padding: 0.5rem;
    border-bottom: 1px solid var(--line);
}

.itb-app tr.cat-sub td {
    color: var(--dim);
    background: rgba(255, 255, 255, 0.015);
    font-size: 0.8rem;
}

.itb-app tfoot .calc td {
    color: var(--dim);
}

.itb-app tfoot .grand td {
    font-weight: 600;
    color: var(--ink);
    border-top: 1px solid var(--line-strong);
    border-bottom: none;
    padding-top: 0.6rem;
    font-size: 0.95rem;
}

.itb-app .add-row {
    margin-top: 1rem;
    display: flex;
    gap: 0.6rem;
    align-items: center;
    flex-wrap: wrap;
}

.itb-app .add-row select {
    width: auto;
    min-width: 210px;
}

/* ---------- rate sources disclosure ---------- */
.itb-app .rate-sources {
    margin-top: 1rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
}

.itb-app .rate-sources>summary {
    cursor: pointer;
    padding: 0.6rem 0.8rem;
    font-family: var(--font-mono);
    font-size: 0.68rem;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--accent);
}

.itb-app .rate-sources>div {
    padding: 0 0.8rem 0.8rem;
}

.itb-app .rate-sources .note {
    margin-bottom: 0.75rem;
}

.itb-app .rate-sources .footnote {
    word-break: break-word;
}

.itb-app .src-table {
    font-size: 0.8rem;
}

.itb-app .src-table td {
    vertical-align: top;
    padding: 0.5rem 0.5rem 0.5rem 0;
}

.itb-app .src-amt {
    display: block;
    font-family: var(--font-mono);
    color: var(--ink);
}

.itb-app .src-label {
    display: block;
    color: var(--dim);
    margin-top: 0.15rem;
}

.itb-app .src-note {
    display: block;
    color: var(--muted);
    font-size: 0.75rem;
    margin-top: 0.2rem;
    max-width: 62ch;
}

.itb-app .src-link {
    text-align: right;
    white-space: nowrap;
    width: 1%;
}

.itb-app .src-link a {
    color: var(--accent);
    font-size: 0.78rem;
}

.itb-app .src-date {
    display: block;
    color: var(--muted);
    font-family: var(--font-mono);
    font-size: 0.68rem;
    margin-top: 0.15rem;
}

/* ---------- summary ---------- */
.itb-app .seg {
    display: inline-flex;
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    overflow: hidden;
    margin-bottom: 1.25rem;
}

.itb-app .seg button {
    border: 0;
    border-radius: 0;
    background: transparent;
    color: var(--muted);
    padding: 0.35rem 0.8rem;
    font-size: 0.76rem;
}

.itb-app .seg button.on {
    background: var(--accent);
    color: #14100a;
    font-weight: 600;
}

.itb-app .stat {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.55rem 0;
    border-bottom: 1px solid var(--line);
}

.itb-app .stat .k {
    color: var(--dim);
    font-size: 0.82rem;
}

.itb-app .stat .v {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    color: var(--ink);
}

.itb-app .stat.big {
    display: block;
    border-bottom: 1px solid var(--line-strong);
    padding-bottom: 1rem;
    margin-bottom: 0.5rem;
}

.itb-app .stat.big .k {
    display: block;
    font-family: var(--font-mono);
    font-size: 0.66rem;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--muted);
}

.itb-app .stat.big .v {
    display: block;
    font-size: 2rem;
    line-height: 1.15;
    margin-top: 0.35rem;
    color: var(--accent);
}

.itb-app .stat.big .u {
    display: block;
    color: var(--muted);
    font-size: 0.75rem;
    margin-top: 0.15rem;
}

/* ---------- breakdown charts ------------------------------------------------
   A bar list. Every bar is the one accent: these categories are nominal, so
   colour would be re-encoding what bar length already shows (and eight hues
   would break the site's one-accent rule for nothing). The label carries
   identity, which is also why there is no legend.

   Marks per the chart spec: 8px track, square at the baseline, rounded at the
   data end, hairline-recessive track, no border around the fill.
   -------------------------------------------------------------------------- */
.itb-app .chart {
    margin: 0.15rem 0 1.1rem;
}

.itb-app .chart-note {
    color: var(--muted);
    font-size: 0.75rem;
    margin: 0 0 0.6rem;
}

.itb-app .chart-row {
    padding: 0.38rem 0;
    /* a row's label, bar and value are one unit — never split across a page */
    break-inside: avoid;
}

.itb-app .chart-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.6rem;
}

.itb-app .chart-label {
    color: var(--dim);
    font-size: 0.8rem;
    /* wraps rather than truncating — a clipped category name is worse than
       two lines, and this column is only ~200px wide in the sidebar */
    min-width: 0;
}

.itb-app .chart-val {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    font-size: 0.8rem;
    color: var(--ink);
    white-space: nowrap;
    flex: none;
}

.itb-app .chart-line {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.32rem;
}

.itb-app .chart-track {
    flex: 1;
    min-width: 0;
    height: 8px;
    background: var(--raised);
    border-radius: 2px;
}

.itb-app .chart-fill {
    display: block;
    height: 100%;
    background: var(--accent);
    border-radius: 0 3px 3px 0;
}

/* Contingency rides in both charts so the shares still sum to 100%, but it is
   not a category and not a cost type — grey says "different kind of row"
   without spending a second hue on it. */
.itb-app .chart-row.is-extra .chart-fill {
    background: var(--line-strong);
}

.itb-app .chart-share {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    font-size: 0.7rem;
    color: var(--muted);
    width: 2.4rem;
    text-align: right;
    flex: none;
}

.itb-app .chart-empty {
    color: var(--muted);
    font-size: 0.8rem;
    margin: 0.2rem 0 0;
}

/* ---------- share bar (cost type) ------------------------------------------
   The only multi-hue chart in either tool. DESIGN.md "Series colour" carries the
   reasoning: cost type is a fixed set of three ordered by how much of it you can
   still change, so hue is encoding something bar length cannot. Every category
   chart stays single-hue.

   The `data-k` attribute — not a pair of class names — is what binds a segment to
   its swatch. The planner's older .exp/.sav bar needs a comment telling you to
   keep two selectors in sync; here one rule paints both, so they cannot drift. */
.itb-app .sharebar {
    display: flex;
    height: 12px;
    margin: 0.5rem 0 0.6rem;
    border-radius: 2px;
    overflow: hidden;
    background: var(--raised);
}

.itb-app .sharebar .share-seg {
    display: block;
    height: 100%;
}

.itb-app .share-seg[data-k="recurring"],
.itb-app .sw[data-k="recurring"] {
    background: var(--series-recurring);
}

.itb-app .share-seg[data-k="labour"],
.itb-app .sw[data-k="labour"] {
    background: var(--series-labour);
}

.itb-app .share-seg[data-k="capital"],
.itb-app .sw[data-k="capital"] {
    background: var(--series-capital);
}

.itb-app .share-seg[data-k="extra"],
.itb-app .sw[data-k="extra"] {
    background: var(--series-extra);
}

.itb-app .share-row {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    padding: 0.22rem 0;
    border-bottom: 1px solid var(--line);
}

.itb-app .share-row:last-child {
    border-bottom: 0;
}

.itb-app .sw {
    flex: none;
    width: 9px;
    height: 9px;
    border-radius: 2px;
    /* baseline-aligned text next to a square looks 1px low without this */
    transform: translateY(1px);
}

.itb-app .share-label {
    flex: 1;
    min-width: 0;
    font-size: 0.82rem;
}

.itb-app .share-val {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    font-size: 0.82rem;
}

.itb-app .share-pct {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    font-size: 0.7rem;
    color: var(--muted);
    width: 2.4rem;
    text-align: right;
    flex: none;
}

/* sign colours — nothing in this tool should go negative, but keep the
   contract identical to the sibling planner's setMoney() */
.itb-app .pos {
    color: inherit;
}

.itb-app .neg {
    color: var(--neg);
}

/* ---------- closing CTA ---------- */
.itb-app .tool-cta {
    margin-top: 2.5rem;
    padding-top: 1.75rem;
    border-top: 1px solid var(--line);
    text-align: center;
}

.itb-app .tool-cta p {
    color: var(--dim);
    max-width: 62ch;
    margin: 0 auto 1.25rem;
}

.itb-app .tool-cta .btn {
    font-size: 0.95rem;
}

/* ---------- responsive ---------- */
/* Stack below 1320px. The sidebar squeezes the eight-column line table into a
   horizontal scroll before that; giving the table full width reads better than
   keeping the summary alongside. */
@media (max-width: 1320px) {
    .itb-app .grid {
        grid-template-columns: 1fr;
    }

    .itb-app .summary {
        position: static;
    }
}

@media (max-width: 768px) {
    .itb-app .wrap {
        padding: 96px 1.25rem 64px;
    }

    .itb-app header.app {
        align-items: flex-start;
    }

    .itb-app .doc-title {
        font-size: 1.5rem;
    }
}

/* ---------- print ----------------------------------------------------------
   The screen theme is dark. Per the site guardrail, anything added here needs a
   print override or it prints as a black page. The printed sheet is the artifact
   the reader keeps, so force the light palette back and drop the site chrome.
   -------------------------------------------------------------------------- */
.itb-app .print-only {
    display: none;
}

@media print {

    /* The body reset, the ten shared light variables, `.wrap`, the `.print-only`
       masthead with its h1 and `.meta`, and the `.grid` flex fix for Gecko's
       non-fragmenting grid containers all live in tool-base.css now — this tool
       used every one of them at exactly the base's values, including the grid's
       12px gap. Only the series palette below is this tool's own.

       `.navbar`, `.footer` and `.no-print` are hidden by the base. The rules
       below are the ones the base cannot know about: three of them are genuine
       (`.add-row`, `.rate-sources`, `button.danger` are actions, not values),
       and `.seg` is the segmented control — note that a new tool must NOT name
       its own segmented control `.seg`, because this rule hides it outright. */
    .itb-app .add-row,
    .itb-app .seg,
    .itb-app .rate-sources,
    .itb-app button.danger {
        display: none !important;
    }

    .itb-app {
        /* Paper counterparts of the series colours. Darker than the screen set —
           these are inks on white, not light on a dark card. Checked to stay
           tellable apart in greyscale as well, though the legend carries every
           label, amount and share as text, so nothing depends on that. */
        --series-recurring: #8a6420;
        --series-labour: #1f7a4d;
        --series-capital: #4a5568;
        --series-extra: #9a9aa2;
    }

    .itb-app .summary {
        position: static;
    }

    /* The 900px screen minimum exists so selects and money inputs stay readable.
       On paper those render as plain text, and keeping the minimum would push the
       amount column off the right edge of the sheet. */
    .itb-app #lineTable {
        min-width: 0;
        /* Eight columns of widget text do not fit a Letter sheet at the screen's
           size. Shrink the whole table one step. */
        font-size: 8.4pt;
    }

    /* Controls used to need their font-size re-anchored here: they size text in
       `rem`, which resolves against the root, so they ignored the table's
       font-size and stayed screen-sized while everything around them shrank.
       Mirrors are plain spans and inherit from the cell, so that whole class of
       correction is gone with them. */

    .itb-app .table-scroll {
        overflow-x: visible;
    }

    .itb-app .itb-card {
        border: 1px solid var(--line);
        /* NOT `break-inside: avoid`. That was here first and it cost a page and a
           half: any card too tall for the remaining space jumped to a fresh sheet,
           leaving pages 1 and 3 roughly half empty. Cards may now split; the
           rules below keep the pieces that must stay together — table rows, chart
           rows, stat lines — from ever being cut. */
        break-inside: auto;
        /* Screen sets overflow:hidden to keep the h2 band inside the rounded
           corners. On paper that silently amputates anything wider than the card
           — no scrollbar, no ellipsis, just a missing amount column. Let it show;
           the sizing below is what keeps the table inside the sheet. */
        overflow: visible;
    }

    /* The atoms that must never be split across a page break. */
    /* `tr`, `.chart-row`, `.stat` and `.field` are in the shared atom list in
       tool-base.css. This is the one atom only this tool has. */
    .itb-app .warn-line {
        break-inside: avoid;
    }

    /* A heading stranded at the foot of a sheet reads as a mistake. */
    .itb-app .itb-card h2,
    .itb-app .sub-head {
        break-after: avoid;
    }

    /* A split table repeats its column headers on the next sheet. */
    .itb-app thead {
        display: table-header-group;
    }

    /* But NOT its footer. A tfoot defaults to table-footer-group, which repeats
       on every fragment — so once the table split, "Subtotal / Contingency /
       Total IT budget $63,577" printed at the foot of the first fragment after
       only two line items, as though that were the whole budget. As a row group
       it renders once, in source order, after the last line. */
    .itb-app tfoot {
        display: table-row-group;
    }

    /* The summary — total, per-seat, and both breakdown charts — is the report.
       On screen it is a sidebar because the table is what you are editing; on
       paper the reader is not editing anything, so it leads. */
    .itb-app .col-side {
        order: -1;
    }

    .itb-app .itb-card h2 {
        color: #111;
        background: #f4f4f5;
    }

    .itb-app .stat.big .v {
        color: #111;
    }

    .itb-app tr.cat-head td {
        color: #111;
        background: #f4f4f5;
    }

    /* ---- every value prints as text, never as a control --------------------
       A control cannot wrap and cannot size to its content, so printing one
       means committing to a width in advance — and the moment a value is wider
       than that width it is cut, with no ellipsis and no cue. Every earlier fix
       in this block picked a different width, which only chose which value got
       clipped next: at 3.4ch an FTE of 0.5 printed as "0" on a line still
       charging $37,500, and a 25% burden printed as "2" plus half a digit.

       syncPrintMirrors() writes a `.print-mirror` span beside every control in
       the printed area, which is what makes hiding them outright safe — nothing
       can vanish without a replacement. There is deliberately not one control
       width left in this stylesheet. If you find yourself adding one back, the
       mirror for that field is missing; add the mirror instead. */
    .itb-app input[type="number"],
    .itb-app input[type="text"],
    .itb-app select {
        display: none !important;
    }

    /* nowrap because a mirror holds one value or one option label, and breaking
       "per month" across two lines reads as a layout fault rather than a unit.
       The line name is exempt — it is `.print-name`, which must wrap. */
    .itb-app .print-mirror {
        display: inline;
        color: #111;
        font-family: var(--font-mono);
        white-space: nowrap;
    }

    /* The "$" was an absolutely-positioned pseudo-element floating over a padded
       input — the pairing that printed "$60000" flush here and, in the sibling
       planner, printed the digits directly underneath their own "$". The mirror
       carries a real "$" as text, so the pseudo-element has no job left on paper
       and the whole overlap class goes with it. */
    .itb-app .money-in::before {
        display: none;
    }

    .itb-app .money-in {
        display: inline;
    }

    /* `!important` is load-bearing: the column widths are inline `style=` attrs
       on the <th>s, and an inline declaration outranks any selector without it.
       Without this the screen's ~1020px of column hints survive onto a ~700px
       sheet and the amount column — every figure in the document, including the
       total — falls off the right edge. */
    .itb-app thead th {
        width: auto !important;
        min-width: 0 !important;
    }

    /* The line name is the one mirror built by hand rather than by
       syncPrintMirrors(), because it wraps as a block instead of sitting inline
       with a unit beside it. */
    .itb-app .label-cell .print-name {
        display: block;
        white-space: normal;
        overflow-wrap: anywhere;
    }

    /* "4" and "yr" were wrapping onto two lines inside an 82px cell, which read
       as a layout break rather than a value with a unit. Scoped to the two cells
       that pair a number with a unit — a blanket rule on every `td` would also
       catch the empty-state row, whose sentence would then run off the sheet. */
    .itb-app .count-cell,
    .itb-app .life-cell {
        white-space: nowrap;
    }

    /* --warn is a screen colour; that amber vanishes on white. The resolved count
       still earns its place on paper — it shows what each rate was multiplied by. */
    .itb-app .count-cell .ref-n,
    .itb-app .count-cell .ref-n.zero {
        color: #444;
    }

    /* ---- business profile: label → value, one line each --------------------
       On screen a field is a stacked label-over-input in a 3-up grid, which is
       right for typing into. Printed, that grid put each label at the left of
       its column and its value hard against the right, with nothing joining
       them: "Total employees" and "18" ended up ~200px apart and the eye had to
       guess the pairing. Two columns of label→value rows read as a spec sheet,
       which is what this section is once it is no longer editable. */
    .itb-app .field-grid {
        grid-template-columns: 1fr 1fr;
        gap: 0 28px;
    }

    .itb-app .field {
        flex-direction: row;
        align-items: baseline;
        justify-content: space-between;
        gap: 12px;
        border-bottom: 1px solid var(--line);
        padding: 3px 0;
    }

    .itb-app .field label {
        min-width: 0;
    }

    /* The `small` hint stays a block under its label (as on screen). Inlining it
       was tried and reverted: it turned "Full seats" into a three-line run of
       label-then-hint with the value stranded at the top, which was harder to
       read than the stacked version it replaced. */
    .itb-app .field .money-in,
    .itb-app .field .print-mirror {
        margin-top: 0;
        width: auto;
        flex: none;
        text-align: right;
        white-space: nowrap;
    }

    /* Revenue used to print as the raw `2400000` the input holds. The mirror
       runs it through money(), so the spec sheet reads $2,400,000 — and it
       sizes to the figure instead of needing a width wide enough for one. */
    .itb-app .field .print-mirror {
        font-weight: 600;
    }

    /* ---- breakdown charts ---------------------------------------------------
       print-color-adjust is load-bearing, not decoration: with "Background
       graphics" unticked in the print dialog — the default in some browsers —
       every bar would otherwise render as an empty track. The amounts and shares
       are printed as text beside each bar, so the chart still reads if a browser
       ignores this, but it should not have to.

       `.chart-track` and `.chart-fill` are covered by tool-base.css. These four
       are this tool's own filled surfaces — the share bar, its legend swatches
       and the big stat — and each needs the declaration in its own right. */
    .itb-app .sharebar,
    .itb-app .sharebar .share-seg,
    .itb-app .sw,
    .itb-app .stat.big {
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }

    /* --raised is #f4f4f5 on paper, which is invisible against a white sheet;
       the track has to be a shade the eye can find the end of. */
    .itb-app .chart-track {
        background: #e4e4e7;
        height: 6px;
    }

    /* The screen rhythm is tuned for a 320px sidebar, where the rows need air to
       stay legible. On paper the same chart runs the full width of the sheet, so
       that air is just three charts' worth of wasted page. */
    .itb-app .chart {
        margin: 0.1rem 0 0.7rem;
    }

    .itb-app .chart-row {
        padding: 0.16rem 0;
    }

    .itb-app .chart-line {
        margin-top: 0.16rem;
    }

    .itb-app .chart-row.is-extra .chart-fill {
        background: #9a9aa2;
    }

    .itb-app .chart-note {
        color: #555;
    }

    /* A hairline round the whole bar: the lightest segment against white paper
       would otherwise have no edge on the side it ends. */
    .itb-app .sharebar {
        border: 1px solid var(--line);
        background: #e4e4e7;
    }

    .itb-app .share-row {
        border-bottom-color: var(--line);
    }

    .itb-app .share-pct {
        color: #444;
    }

    /* ---- structural colour ---------------------------------------------------
       The sheet was black text, grey bands and a single brown rule. These give it
       a spine without spending another hue: the accent already earned its place
       in the masthead, so repeat it where the eye needs to find structure. */
    .itb-app .sub-head {
        border-bottom: 1px solid var(--accent);
        padding-bottom: 2px;
        color: var(--accent);
    }

    /* The one figure the whole report exists to deliver. */
    .itb-app .stat.big {
        background: var(--accent-soft);
        border: 1px solid #e8d9b8;
        border-radius: 3px;
        padding: 8px 10px;
        margin-bottom: 10px;
    }

    .itb-app tr.cat-head td {
        border-left: 3px solid var(--accent);
        padding-left: 6px;
    }

    .itb-app tfoot tr:last-child td {
        border-top: 2px solid var(--accent);
    }
}
