/* ═══════════════════════════════════════════════════════════════════
   marketing-paper.css  —  site-wide "paper" aesthetic + brand theme
   -------------------------------------------------------------------
   Applies to every tab (Technicians, Marketing, Location Owners) via
   `body.paper-mode` which is set in index.html and defensively re-
   added on every tab switch in app.js.

   Brand palette (per user spec):
     #F38A3F  Orange   — hero / strong CTAs
     #E88140  Orange-soft (off-color) — buttons, pills, bar fills
     #373B4D  Black/Ink — text, titles, totals
     #BFE0F3  Light Blue — sparse accent
     #F1F3F5  (not used — too cold for paper texture)

   Paper canvas: slightly warmer than #F1F3F5 (which reads as e-paper)
   but noticeably less warm than the original #FAF9F6.

   To roll back completely: (1) delete this file, (2) remove its
   <link> tag from index.html, (3) remove class="paper-mode" from
   <body>, (4) remove the one-line class add in activateTab() (app.js).
   ═══════════════════════════════════════════════════════════════════ */

/* ── Custom properties (tweak here, cascade everywhere) ────────── */
body.paper-mode {
  /* Paper surfaces */
  --paper-bg:           #F4F3EF;   /* page canvas — subtle warmth, not yellow */
  --paper-card:         #F7F6F2;   /* cards sit just one step lighter than canvas, same hue family */
  --paper-card-alt:     #F9F8F4;   /* alt rows, hover states */

  /* Brand */
  --brand-orange:       #F38A3F;   /* full-vibrant hero */
  --brand-orange-soft:  #E88140;   /* off-color: slightly muted/deeper — everyday UI */
  --brand-orange-pale:  rgba(232, 129, 64, 0.12);
  --brand-orange-tint:  rgba(232, 129, 64, 0.08);

  --brand-ink:          #373B4D;   /* titles, body, totals — brand black */
  --brand-ink-soft:     #4A4E5F;   /* slightly lighter variant */
  --brand-ink-muted:    #6B7280;   /* secondary text, labels */

  --brand-blue:         #BFE0F3;   /* soft accent — sparse */
  --brand-blue-deep:    #7FB5D3;   /* deeper blue for text/borders when blue is used */

  /* ── Risograph ink palette ──────────────────────────────────
     Vibrant, saturated pigments designed to be applied ON TOP of the
     paper canvas via `mix-blend-mode: multiply` + low alpha, so the
     color reads like wet ink soaking into the page instead of a
     glowing digital overlay. Use sparingly, for accents only. */
  --riso-cyan:          #00A3E0;
  --riso-magenta:       #E30074;
  --riso-yellow:        #FFD100;
  --riso-tangerine:     #FF671F;
  --riso-oxford:        #002147;   /* fountain-pen deep blue — premium headers */
  --riso-hunter:        #1A3622;   /* fountain-pen deep green — alt headers */

  /* Watercolor wash hovers — extremely faint tints of the ink palette,
     drawn on top of the paper via mix-blend-mode: multiply. */
  --wash-cyan:          rgba(0, 163, 224, 0.06);
  --wash-cyan-firm:     rgba(0, 163, 224, 0.10);
  --wash-yellow:        rgba(255, 209, 0, 0.45);   /* highlighter marker */

  /* Borders & shadows — tuned to brand ink, not pure black */
  --paper-border:       rgba(55, 59, 77, 0.08);
  --paper-border-firm:  rgba(55, 59, 77, 0.14);
  --paper-shadow-sm:    0 1px 2px rgba(55, 59, 77, 0.04);
  --paper-shadow-md:    0 1px 2px rgba(55, 59, 77, 0.04), 0 6px 18px rgba(55, 59, 77, 0.06);
  --paper-shadow-lg:    0 1px 2px rgba(55, 59, 77, 0.04), 0 6px 18px rgba(55, 59, 77, 0.06), 0 16px 40px rgba(55, 59, 77, 0.05);

  /* Apply base canvas + ink */
  background-color: var(--paper-bg);
  color: var(--brand-ink);
  transition: background-color 0.35s ease;
}

/* Base canvas extends into chrome so the page reads as one sheet */
body.paper-mode .header,
body.paper-mode .footer,
body.paper-mode .main-wrapper,
body.paper-mode .content,
body.paper-mode .view-panel {
  background-color: transparent;
  color: var(--brand-ink);
}
body.paper-mode .footer { color: var(--brand-ink-muted); }

/* ── Procedural SVG noise overlay (fine fractal grain) ───────── */
body.paper-mode::before {
  content: "";
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  pointer-events: none;
  z-index: 9999;
  opacity: 0.04;                   /* a touch lighter for cooler paper */
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 220 220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.55 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 220px 220px;
  transition: opacity 0.4s ease;
}

/* ── Card surfaces (all 3 tabs) ────────────────────────────────── */
body.paper-mode .stat-card,
body.paper-mode .table-wrapper,
body.paper-mode .fin-chart-card,
body.paper-mode .fin-month-picker,
body.paper-mode #finCards > .mf-card,
body.paper-mode .mkt-table-card,
body.paper-mode .mkt-proj-card,
body.paper-mode .mkt-chart-card,
body.paper-mode .bar-chart-card,    /* Marketing "Jobs Per Month" card was white */
body.paper-mode .proj-card,
body.paper-mode .progress-wrap,
body.paper-mode .exp-sheet,
body.paper-mode .modal,
body.paper-mode .date-bs-sheet {
  background-color: var(--paper-card);
  box-shadow: var(--paper-shadow-md);
  border: 1px solid var(--paper-border);
}
/* Clip the card corners so inner rectangular elements don't poke
   past the rounded edge */
body.paper-mode .proj-card,
body.paper-mode .progress-wrap { border-radius: 12px; overflow: hidden; }
body.paper-mode .stat-card { border-radius: 12px; }
body.paper-mode .fin-chart-card,
body.paper-mode .modal,
body.paper-mode .exp-sheet,
body.paper-mode .fin-month-picker,
body.paper-mode .date-bs-sheet { border-radius: 14px; }

/* Tables read as paper, not stark white */
body.paper-mode table { background-color: transparent; }
body.paper-mode thead,
body.paper-mode tfoot { background-color: var(--paper-card-alt); }
/* Fountain-pen ink on column headers — rich Oxford Blue reads as
   premium stationery, still small + bold, replaces the muted grey. */
body.paper-mode th {
  color: var(--riso-oxford);
  border-bottom-color: var(--paper-border-firm);
  font-weight: 700;
  letter-spacing: 0.04em;
}
body.paper-mode td { border-bottom-color: var(--paper-border); }
/* NOTE: the earlier tr:hover rule at this selector has been replaced by
   the stable row-level hover defined in the Risograph block below. */

/* Marketing "Monthly History" table — the sticky first column was
   hardcoded to `background: white` and the current-month row to
   cream #fffbf5; neither matches the paper canvas. Re-paint both. */
body.paper-mode .mkt-table thead th:first-child,
body.paper-mode .mkt-table tbody td:first-child,
body.paper-mode .mkt-table tfoot td:first-child {
  background-color: var(--paper-card);
}
/* Current-month row: must be OPAQUE, not translucent. The sticky
   first-column cell paints on top of the TR's own background; if both
   use a translucent --brand-orange-tint, the two 8%-alpha layers stack
   to ~15% alpha inside the sticky cell — visibly darker than the rest
   of the row. #F6EDE4 is the pre-computed opaque equivalent of
   `--paper-card` (#F7F6F2) blended with --brand-orange-tint
   (rgba(232,129,64,0.08)). Same hue, no doubling. */
body.paper-mode .mkt-row-current,
body.paper-mode .mkt-row-current td:first-child {
  background-color: #F6EDE4 !important;
}
/* Section title above the card — remove any implicit background so
   the label reads as a heading, not a floating block. */
body.paper-mode .section-title {
  background: transparent;
  border: none;
  box-shadow: none;
  color: var(--brand-ink-muted);
  padding-left: 2px;
}

/* "# JOBS" cell: stacked layout — number on top, delta + PROJ underneath
   in a smaller meta line. Everything right-aligns to the td's right
   edge (inherited from `.mkt-table td:not(:first-child) { text-align: right }`)
   so numbers form a clean vertical column across every row, including
   the footer's plain-text total — no grid wrappers needed.
   Why not the old 3-column grid? Fixed-ch columns (5.5ch + 4.5ch) would
   consume the whole cell on narrow viewports, compressing the number
   column to zero and visually shifting the number rightward, which is
   what made the projected row's number appear to land where PROJ sits
   underneath. Stacking eliminates the horizontal-fit problem entirely. */
/* Horizontal flex row — number | delta | PROJ, baseline-aligned so
   glyph bottoms sit on the same invisible line regardless of font
   size. The delta wrapper has a fixed min-width so its slot is
   reserved even on rows with no % change (column geometry stays
   identical — numbers align vertically down the column). */
body.paper-mode .mkt-jobs-cell {
  display: flex;
  flex-direction: row;
  align-items: baseline;
  justify-content: flex-end;     /* anchor at the right edge of the td */
  gap: 0;
  line-height: 1.2;
  white-space: nowrap;
}
/* The number itself — always tabular-nums, always right-aligned to
   a fixed min-width slot so every row's number lands at the same x */
body.paper-mode .mkt-jobs-num {
  font-weight: 700;
  font-size: 15px;
  font-variant-numeric: tabular-nums;
  min-width: 3.5ch;
  text-align: right;
  color: #2C2A28;                /* Dark Charcoal — historical fact */
  position: relative;            /* for the PROJ highlighter pseudo */
}
/* Projected row: graphite italic + hand-dragged sunflower highlighter
   behind the digits. Italic + graphite color differentiate the
   estimate from historical fact without requiring a separate slot. */
body.paper-mode .mkt-jobs-num--proj {
  color: #7A7571;                /* Graphite Pencil */
  font-style: italic;
  isolation: isolate;            /* scope the multiply-blend pseudo */
}
body.paper-mode .mkt-jobs-num--proj::before {
  content: '';
  position: absolute;
  inset: 8% -3px 14% -3px;
  background: #FFD700;           /* Sunflower Yellow */
  opacity: 0.4;
  mix-blend-mode: multiply;
  border-radius: 2px 4px 3px 1px;   /* irregular — human-drawn */
  transform: rotate(-2deg);         /* hand-swipe marker angle */
  z-index: -1;
  filter: blur(0.3px);              /* slight pigment bleed */
  pointer-events: none;
}
/* Delta wrapper ALWAYS renders (empty on rows with no % change).
   Reserving the slot keeps every row's number at the same x even
   when the % is absent (see spec: "the empty space is mathematically
   important"). Left margin gives the number breathing room. */
body.paper-mode .mkt-jobs-delta {
  display: inline-block;
  min-width: 5.5ch;
  margin-left: 0.6rem;
  text-align: left;
  font-variant-numeric: tabular-nums;
  font-size: 11.5px;
  font-weight: 600;
  line-height: 1;
}
body.paper-mode .mkt-jobs-delta .delta { margin-left: 0; font-size: inherit; }
/* Ensure tfoot total gets the same tabular digit widths as body rows
   so "2516" right-aligns to exactly the same x as "222", "248", etc. */
body.paper-mode .mkt-table tfoot td {
  font-variant-numeric: tabular-nums;
}
/* ── Delta highlighter pills ─────────────────────────────────────
   The % change cell reads as a HIGHLIGHTED PILL rather than plain
   colored text — a tactile "highlighter swipe" behind the number,
   same visual vocabulary as the sunflower highlighter behind the
   projected month. This makes the Variance/Delta the most visually
   prominent column (per spec: "visually prioritize the Variance
   over raw historical totals") without requiring bold weight or
   size changes that would fight the rest of the table's typography.

   mix-blend-mode: multiply makes the wash look like it's soaking
   into the paper texture behind it, rather than sitting on top as
   a digital overlay. border-radius + inline-block lets the pill
   hug the number with a tiny bit of breathing room on either side. */
body.paper-mode .delta-up,
body.paper-mode .delta-down {
  display: inline-block;
  padding: 2px 7px;
  border-radius: 6px;
  font-weight: 700;
  mix-blend-mode: multiply;
  line-height: 1.25;
}
body.paper-mode .delta-up {
  color: #15803D;                        /* Kelly Green ink */
  background: rgba(34, 197, 94, 0.14);   /* vibrant green wash */
}
body.paper-mode .delta-down {
  color: #B91C1C;                        /* Crimson ink */
  background: rgba(239, 68, 68, 0.14);   /* crimson wash */
}
/* Widen the reserved slot so the padded pill doesn't bump the
   number left — the column geometry was tuned for plain-text
   percentages (5.5ch) and the pill needs ~1ch more breathing room. */
body.paper-mode .mkt-jobs-delta {
  min-width: 6.5ch;
}

/* ── Softened ink typography ──────────────────────────────────── */
body.paper-mode h1,
body.paper-mode h2,
body.paper-mode h3,
body.paper-mode h4,
body.paper-mode .stat-value,
body.paper-mode .fin-month-title,
body.paper-mode .fin-pnl-month,
body.paper-mode .mf-header-title,
body.paper-mode .mf-step-num,
body.paper-mode .modal-title,
body.paper-mode .exp-sheet-title,
body.paper-mode .tech-name-label {
  color: var(--brand-ink);
}
body.paper-mode .stat-label,
body.paper-mode .fin-card-label,
body.paper-mode .mf-step-label,
body.paper-mode .mf-step-desc,
body.paper-mode .header-eyebrow,
body.paper-mode .fin-pnl-overline,
body.paper-mode .fin-month-eyebrow,
body.paper-mode small,
body.paper-mode .footer {
  color: var(--brand-ink-muted);
}

/* ── Orange brand accent applied everywhere orange used to be ── */
/* Active pill in the horizontal date row */
body.paper-mode .date-btn.active {
  background: var(--brand-orange-soft);
  color: #fff;
  box-shadow: 0 2px 6px rgba(232, 129, 64, 0.28);
}
/* Bottom-sheet selected item */
body.paper-mode .date-bs-item.active {
  background: var(--brand-orange-tint);
  color: var(--brand-ink);
}
body.paper-mode .date-bs-item-check { color: var(--brand-orange-soft); }

/* Tab nav + sliding indicator */
body.paper-mode .tab-indicator { background: var(--brand-orange-soft); }
body.paper-mode .tab-btn.active { color: var(--brand-ink); }

/* Sort pills */
body.paper-mode .sort-btn.active {
  background: var(--brand-orange-soft);
  color: #fff;
  border-color: var(--brand-orange-soft);
}

/* Trend-chart toggle buttons (owners) — keep the metric's own color
   as the pill background (var(--c) inline), but flip the text from
   white to brand ink so it's readable on any brand color. */
body.paper-mode .fin-trend-btn.on {
  color: var(--brand-ink) !important;
}

/* $/% toggle inside Full Picture card */
body.paper-mode .fin-toggle button.active {
  background: var(--brand-ink);
  color: #fff;
}

/* Month-picker active row + left accent bar */
body.paper-mode .fin-month-item.active {
  background: var(--brand-orange-tint);
  color: var(--brand-ink);
}
body.paper-mode .fin-month-item.active::before { background: var(--brand-orange-soft); }

/* Month/quarter period tabs underline */
body.paper-mode .fin-period-tab.active {
  color: var(--brand-ink);
  border-bottom-color: var(--brand-orange-soft);
}

/* Compare chip (Full Picture) */
body.paper-mode .pnl-cmp-chip.act {
  background: var(--brand-ink);
  color: #fff;
  border-color: var(--brand-ink);
}

/* Primary month pill in Full Picture header */
body.paper-mode .fin-pnl-head #finPnlSubtitle,
body.paper-mode .fin-pnl-month { color: var(--brand-ink); }

/* Gross Profit progress bar target line / labels that were hard orange */
body.paper-mode .progress-bar-fill { background: linear-gradient(90deg, var(--brand-orange-soft), var(--brand-orange)); }

/* Marketing projection cards — big number + track softened to brand tones */
body.paper-mode .proj-card-value { color: var(--brand-orange-soft); }
/* The uppercase eyebrow labels ("JOBS THIS MONTH", "PROJECTED JOBS",
   etc.) are the page's small-type section anchors — they benefit from
   Oxford Blue fountain-pen ink instead of the default muted gray.
   Blue reads as a deliberate chosen ink color on a real ledger,
   breaks the page out of the "drab grey feel" without competing
   with the orange primary numerals. Sub-text + progress label stay
   muted so only the anchor labels carry the rich ink color. */
body.paper-mode .proj-card-label {
  color: var(--riso-oxford);             /* Oxford Blue fountain pen */
  font-weight: 700;
  letter-spacing: 0.12em;
}
body.paper-mode .proj-card-sub,
body.paper-mode .progress-label-row { color: var(--brand-ink-muted); }
/* Progress track was `#f0f0f0` — looks like a hard gray block against
   paper. Use a soft paper-ink-tinted track instead. */
body.paper-mode .progress-bar-bg {
  background: rgba(55, 59, 77, 0.07);
}

/* Connect-QuickBooks banner CTA */
body.paper-mode .fin-connect-banner a[href*="connect"] { background: var(--brand-orange-soft) !important; }

/* ── Light-blue sparse accents ────────────────────────────────── */
/* Use blue as a quiet complement: chart compare column header + the
   small "compare" tag next to the compared-month label */
body.paper-mode .pnl2-th-cmp,
body.paper-mode .pnl2-cmp-tag { color: var(--brand-blue-deep) !important; }
body.paper-mode .pnl2-cmp-tag { background: var(--brand-blue) !important; }

/* Cash-in-the-bank chart already uses blues — keep those intact;
   downstream Chart.js color prop overrides aren't reachable from CSS. */

/* ── Borders softened to warm-gray-ink ─────────────────────────── */
body.paper-mode .tab-nav,
body.paper-mode th,
body.paper-mode td,
body.paper-mode .pnl-cmp-chip,
body.paper-mode .fin-month-item,
body.paper-mode .fin-period-tabs,
body.paper-mode .modal-header,
body.paper-mode .modal-footer,
body.paper-mode .exp-sheet-drag,
body.paper-mode .fin-pnl-head,
body.paper-mode .tab-btn {
  border-color: var(--paper-border);
}

/* ── Expense-modal vendor summary in paper mode ─────────────────
   Oxford-blue ink on names + values, softer borders on the track
   and section divider so the summary feels like the same stationery
   as the rest of the sheet. Section labels use Oxford Blue at a
   lower opacity to read as the "small caps" layer. */
body.paper-mode .exp-summary {
  border-bottom-color: var(--paper-border);
}
body.paper-mode .exp-section-label {
  color: var(--riso-oxford);
  opacity: 0.62;
}
body.paper-mode .exp-stacked-bar {
  background: var(--paper-border);
}
body.paper-mode .exp-vlegend-name,
body.paper-mode .exp-vlegend-val {
  color: var(--riso-oxford);
}
body.paper-mode .exp-vlegend-pct {
  color: var(--riso-oxford);
  opacity: 0.55;
}
body.paper-mode .exp-vlegend-caret {
  color: var(--riso-oxford);
  opacity: 0.6;
}
body.paper-mode .exp-vlegend-row--expandable:hover,
body.paper-mode .exp-vlegend-row--expandable:focus-visible {
  background: rgba(0, 33, 71, 0.06);  /* Oxford-blue wash on hover */
}
body.paper-mode .exp-other-sublist {
  border-left-color: var(--paper-border-firm);
}
body.paper-mode .exp-vlegend-row--sub {
  color: var(--riso-oxford);
  opacity: 0.78;
}
body.paper-mode .exp-vlegend-row--sub .exp-vlegend-val {
  color: var(--riso-oxford);
  opacity: 1;
}

/* ── Kill hardcoded white dividers throughout the app ──────────
   Several legacy rules use `#fff` / `white` as the "cut" between
   stacked bar segments, the sticky first column of the Full Picture
   grid, halo rings on gauges, etc. In paper mode all of those would
   show as harsh bright lines over the off-white canvas. Re-paint
   them to the paper-card tone so they read as gentle creases. */
body.paper-mode .mf-split-bar > *:not(:last-child) {
  box-shadow: inset -1px 0 0 var(--paper-card) !important;
}
/* Kill the outer drop shadow on stacked bars. The base rule applies
   `box-shadow: 0 2px 6px rgba(0,0,0,0.04)` to .mf-split-bar, which on
   a uniform paper canvas renders as a faint darker strip directly
   beneath each bar — reads as a "dividing line" or "highlight" that
   doesn't match the background. Paper doesn't cast shadows. */
body.paper-mode .mf-split-bar {
  box-shadow: none !important;
}
/* Unify "Profit formula" section backgrounds. Before: .mf-op used
   #f7f8f9 and .mf-step--gp/noi each had their own tinted fills, so
   the 1px paper-card cuts between stacked-bar segments looked off-
   colored against the surrounding surface. Making every sub-section
   transparent lets them inherit the card's paper tone, and the bar
   cuts now blend perfectly. */
body.paper-mode .mf-op,
body.paper-mode .mf-step--gp,
body.paper-mode .mf-step--noi {
  background: transparent !important;
}
/* Drop the hard 1px/2px section dividers entirely — they rendered as
   off-color pencil marks against the paper canvas (pale blue on gp,
   pale green on noi, pale gray on mf-op). Paper-style layouts rely
   on vertical whitespace + the bar graphics themselves to separate
   sections; explicit rules look mechanical. */
body.paper-mode .mf-op,
body.paper-mode .mf-step--gp,
body.paper-mode .mf-step--noi {
  border-top: none !important;
  border-bottom: none !important;
}

/* Revenue bar at the top — bump to match the 26px split-bar height
   below it so every bar in this card shares the same vertical rhythm. */
body.paper-mode .mf-rev-bar {
  height: 26px;
  border-radius: 7px;
}

/* Modern, earthy heart in the footer credit line — replaces the glossy
   red emoji with a minimal outlined terracotta heart that sits
   comfortably on the paper canvas. */
body.paper-mode .footer-heart {
  color: #C75A3A;
  vertical-align: -2px;
  margin: 0 2px;
}
body.paper-mode .mf-gp-revbar-cogs {
  border-right-color: var(--paper-card) !important;
}
body.paper-mode .mf-noi-gauge-needle {
  border-color: var(--paper-card) !important;
}
body.paper-mode .mf-noi-gauge-now::after {
  border-top-color: var(--paper-card) !important;
}
/* Full Picture grid — sticky first column was `background: #fff` */
body.paper-mode .pnl-grid th:first-child,
body.paper-mode .pnl-grid td:first-child,
body.paper-mode .pnl2-th-lbl,
body.paper-mode .pnl2-td-lbl {
  background-color: var(--paper-card) !important;
}
/* Modal table sticky header — was `background: white` */
body.paper-mode .modal-table thead th {
  background-color: var(--paper-card) !important;
  border-bottom-color: var(--paper-border) !important;
}
/* Both chart edges are bare hard-cuts — no paper-mode override
   needed since there's no edge pseudo to style. */

/* ── Summary Plate (hover/scrub header on Revenue + Cash charts) ──
   Default is flat #f8fafc on neutral gray border with a cool shadow —
   reads as plastic against the warm paper surface. Re-skin as a sticky
   note resting on the page: paper-card fill, faint pencil border,
   warm sepia shadow, fountain-pen ink text. */
body.paper-mode .fin-summary-plate {
  background: var(--paper-card-alt);
  border: 1px solid var(--paper-border-firm);
  box-shadow: 0 2px 8px rgba(70, 65, 60, 0.06);
  border-radius: 10px;
}
body.paper-mode .fin-summary-plate-month {
  color: var(--brand-ink-muted);
}
body.paper-mode .fin-summary-plate-value {
  color: var(--riso-oxford);            /* fountain-pen Oxford Blue */
  letter-spacing: -0.4px;
}
/* Delta pills — soften the bright candy green/red to muted paper tones */
body.paper-mode .fin-summary-plate-delta.up {
  background: rgba(138, 154, 91, 0.18);  /* sage wash */
  color: #4F5E2E;                        /* deep sage ink */
}
body.paper-mode .fin-summary-plate-delta.down {
  background: rgba(181, 102, 121, 0.18); /* dusty rose wash */
  color: #6E3040;                        /* deep rose ink */
}

/* ── Custom floating trend-chart tooltip (owners.js renderTrendTooltip) ──
   Default card was stark white with cool slate border + black-tinted
   shadow. Same sticky-note treatment as the Summary Plate. */
body.paper-mode .fin-trend-tooltip {
  background: var(--paper-card-alt);
  border: 1px solid rgba(70, 65, 60, 0.12);
  box-shadow: 0 4px 12px rgba(70, 65, 60, 0.08);
}
body.paper-mode .fin-trend-tooltip-date {
  color: var(--brand-ink-muted);
}
body.paper-mode .fin-trend-tooltip-label {
  color: var(--brand-ink-soft);
}
/* NOTE: .fin-trend-tooltip-value is color-tinted inline by JS (matches
   the active series color) — we intentionally leave that alone so the
   legend swatch and the tooltip value stay visually linked. */
/* Sort / date pills — unchecked state was pure white */
body.paper-mode .sort-btn:not(.active),
body.paper-mode .date-btn:not(.active) {
  background: var(--paper-card);
  border-color: var(--paper-border-firm);
  color: var(--brand-ink-soft);
}
body.paper-mode .fin-toggle button { background: var(--paper-card); color: var(--brand-ink-muted); }
/* Legacy mkt-table also had white first-column (handled above) */

/* ═════ Full Picture "Ledger" redesign ═════════════════════════
   Replaces the horizontal scrolling chip picker with a dual-anchor
   header ("MAR 2026  vs  MAR 2025 ▾"), ledger-style row dividers,
   highlighter delta pills, and a dedicated compare-month sheet. */

/* Dual-anchor header block */
body.paper-mode .pnl-anchor {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 6px 0 22px;
  flex-wrap: wrap;
}
body.paper-mode .pnl-anchor-pri,
body.paper-mode .pnl-anchor-cmp {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
body.paper-mode .pnl-anchor-kicker {
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--brand-ink-muted);
  line-height: 1;
}
body.paper-mode .pnl-anchor-pri-month {
  font-size: 22px;
  font-weight: 800;
  color: var(--brand-ink);
  letter-spacing: -0.3px;
  line-height: 1.15;
  /* Labels are already abbreviated (e.g. "Feb 2026", "Apr 25 – Mar 26"),
     so one line is always enough. nowrap guarantees they never split. */
  white-space: nowrap;
}
/* Stamped circular "vs" badge — inset shadow makes it look pressed
   into the paper rather than sitting on top of it. */
body.paper-mode .pnl-anchor-vs {
  width: 38px; height: 38px;
  border-radius: 50%;
  background: var(--paper-bg);
  color: var(--brand-ink-muted);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-shadow:
    inset 0 2px 4px rgba(55, 59, 77, 0.12),
    inset 0 -1px 2px rgba(255, 255, 255, 0.65);
  flex-shrink: 0;
}
/* Tappable compare button — dashed outline signals "interactive" */
body.paper-mode .pnl-anchor-cmp {
  background: transparent;
  border: 1px dashed var(--paper-border-firm);
  border-radius: 10px;
  padding: 7px 14px;
  cursor: pointer;
  text-align: left;
  transition: border-color 0.15s, background 0.15s;
  font: inherit;
}
body.paper-mode .pnl-anchor-cmp:hover {
  border-color: var(--brand-ink-muted);
  background: rgba(55, 59, 77, 0.03);
}
/* Range mode: comparison is auto-computed (prior period), not user-
   selectable. Keep the visual frame but drop the dashed "interactive"
   treatment and the hover affordance — it reads as a static label. */
body.paper-mode .pnl-anchor-cmp--auto {
  background: transparent;
  border: 1px solid var(--paper-border);  /* solid, muted — not dashed */
  border-radius: 10px;
  padding: 7px 14px;
  text-align: left;
  cursor: default;
  font: inherit;
}
body.paper-mode .pnl-anchor-cmp-month {
  font-size: 18px;
  font-weight: 700;
  color: var(--brand-ink-soft);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  line-height: 1.15;
  /* Belt-and-suspenders with the abbreviation on the JS side —
     guarantee the month text + chevron never wrap onto 2 lines. */
  white-space: nowrap;
}
body.paper-mode .pnl-anchor-chev {
  color: var(--brand-ink-muted);
  transform: translateY(1px);
}

/* Hide the old chip-picker CSS (row/chip classes) if ever re-rendered */
body.paper-mode .pnl-cmp-row { display: none; }

/* ── Ledger rows — dashed pencil-line dividers + breathing room ── */
body.paper-mode .pnl-grid--2col td,
body.paper-mode .pnl-grid--2col th {
  border-bottom: 1px dashed rgba(55, 59, 77, 0.15) !important;
  padding-top: 14px !important;
  padding-bottom: 14px !important;
}
body.paper-mode .pnl-grid--2col tr.indent td {
  padding-top: 10px !important;
  padding-bottom: 10px !important;
}

/* Primary column — deep umber ink */
body.paper-mode .pnl2-cell--pri .pnl2-dollar { color: #2C2A28 !important; }

/* Comparison column — faded, italicized ink */
body.paper-mode .pnl2-cell--cmp .pnl2-dollar,
body.paper-mode .pnl2-cell--cmp .pnl2-pct-sub {
  color: #7A7571 !important;
  font-style: italic;
  font-weight: 500;
}

/* Highlighter delta — flat color wash, no shadow, deep-tone text */
body.paper-mode .pnl2-delta.pnl2-good .pnl2-pill {
  background: rgba(42, 89, 52, 0.1) !important;
  color: #2A5934 !important;
  box-shadow: none !important;
}
body.paper-mode .pnl2-delta.pnl2-bad .pnl2-pill {
  background: rgba(140, 58, 58, 0.1) !important;
  color: #8C3A3A !important;
  box-shadow: none !important;
}
body.paper-mode .pnl2-pill-pct { opacity: 0.7; }

/* Category + subtotal rows — keep hierarchy via font weight, drop the
   solid grey fills so the paper texture shows through. */
body.paper-mode .pnl-grid--2col tr.category td,
body.paper-mode .pnl-grid--2col tr.category .pnl2-td-lbl,
body.paper-mode .pnl-grid--2col tr.subtotal td,
body.paper-mode .pnl-grid--2col tr.subtotal .pnl2-td-lbl {
  background: transparent !important;
}
body.paper-mode .pnl-grid--2col tr.category .pnl2-td-lbl {
  font-weight: 700;
  font-size: 14.5px;
}
body.paper-mode .pnl-grid--2col tr.subtotal .pnl2-td-lbl {
  font-weight: 800;
  color: var(--brand-ink);
}
/* Total row stays the dark ink block — it's the financial bottom line */
body.paper-mode .pnl-grid--2col tr.total td,
body.paper-mode .pnl-grid--2col tr.total .pnl2-td-lbl {
  background: var(--brand-ink) !important;
  color: #fff !important;
}

/* ════════════════════════════════════════════════════════════════
   "Modern Paper P&L" Ledger — strict 3-column tabular layout
   ────────────────────────────────────────────────────────────────
     Col 1: Line Item Name + dotted leader (fills empty space)
     Col 2: Current period $ (hero) + italic "was $X" below
     Col 3: Delta badge with directional arrow, confined strictly
            to this column — the rest of the row reads clean B&W.
   Hierarchy via ALL-CAPS + gray wash (categories), indentation
   (leaves), single-rule top (subtotal), double-rule (grand total).
   Wins / Watchlist grouping is retained as the outer structure.
   ════════════════════════════════════════════════════════════════ */

body.paper-mode .pnl-ledger {
  padding: 4px 0 6px;
  font-variant-numeric: tabular-nums;  /* every digit same width */
}

/* Section grouping (Growth & Improvements / Areas for Attention) */
body.paper-mode .pnl-group { display: block; }
body.paper-mode .pnl-group-title {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--brand-ink-muted);
  padding: 18px 12px 10px;
}
body.paper-mode .pnl-group--wins .pnl-group-title  { color: #15803D; }
body.paper-mode .pnl-group--watch .pnl-group-title { color: #B91C1C; }
body.paper-mode .pnl-divider {
  height: 1px;
  margin: 12px 12px 2px;
  border-bottom: 1px dashed rgba(55, 59, 77, 0.22);
}

/* ── The tabular row ──────────────────────────────────────────── */
/* 3-col grid: name(+leader fills) | values(auto) | delta(auto).
   Column 1 is the only flexible column — it absorbs all available
   width so the leader can stretch between the label and the values. */
body.paper-mode .pnl-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center;
  column-gap: 18px;
  padding: 9px 14px;
  position: relative;
  font-variant-numeric: tabular-nums;
}

/* Column 1 — label + dotted leader */
body.paper-mode .pnl-row-name {
  display: flex;
  align-items: baseline;
  min-width: 0;
  gap: 8px;
}
body.paper-mode .pnl-row-label {
  flex-shrink: 0;
  white-space: nowrap;
  font-size: 14px;
  font-weight: 500;
  color: var(--brand-ink-soft);
  line-height: 1.3;
  letter-spacing: 0.01em;
}
/* Dotted ledger leader — the classic accounting "...." that tracks
   from the label over to the numbers. Flex-grow takes all remaining
   horizontal space; border-bottom draws the dots on the baseline;
   transform nudges it up to sit under the x-height. */
body.paper-mode .pnl-row-leader {
  flex: 1 1 auto;
  min-width: 18px;
  height: 1px;
  border-bottom: 1.5px dotted rgba(55, 59, 77, 0.22);
  transform: translateY(-5px);
}

/* Column 2 — current value (hero) stacked over italic "was $X" */
body.paper-mode .pnl-row-values {
  text-align: right;
  min-width: 96px;
}
body.paper-mode .pnl-row-cur {
  font-size: 16px;
  font-weight: 700;
  color: var(--brand-ink);
  line-height: 1.15;
}
body.paper-mode .pnl-row-prev {
  font-size: 11.5px;
  font-style: italic;
  color: var(--brand-ink-muted);
  opacity: 0.78;
  line-height: 1.15;
  margin-top: 2px;
}

/* Column 3 — delta pill, STRICTLY confined to this column */
body.paper-mode .pnl-row-delta-cell {
  min-width: 158px;
  text-align: right;
}
body.paper-mode .pnl-row-delta {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 4px 10px;
  border-radius: 5px;
  font-size: 12.5px;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: 0.01em;
  font-variant-numeric: tabular-nums;
}
body.paper-mode .pnl-row-delta {
  border-radius: 6px;       /* spec: confined "highlighter pill" in delta col */
  padding: 4px 11px;
}
body.paper-mode .pnl-row-delta--good {
  background: rgba(34, 197, 94, 0.12);
  color: #15803D;
}
body.paper-mode .pnl-row-delta--bad {
  background: rgba(239, 68, 68, 0.12);
  color: #B91C1C;
}
body.paper-mode .pnl-row-delta--flat {
  background: rgba(55, 59, 77, 0.06);
  color: var(--brand-ink-muted);
  font-weight: 600;
}
body.paper-mode .pnl-delta-arrow {
  font-size: 10px;
  line-height: 1;
  font-weight: 900;
  letter-spacing: 0;
}
body.paper-mode .pnl-delta-pct {
  opacity: 0.78;
  font-weight: 600;
}

/* ── Accounting hierarchy tiers ────────────────────────────────── */

/* LEAF — indented sub-items (Tech Labor, Parts, Rent, etc.)
   Warm sepia/umber ink rather than cool grey, so the "ink" reads as
   older + more organic against the paper canvas. */
body.paper-mode .pnl-row--leaf .pnl-row-label {
  padding-left: 26px;     /* leaves 24px for label + 2px flag buffer */
  font-weight: 500;
  color: #4A4238;         /* warm sepia ink */
}
body.paper-mode .pnl-row--leaf .pnl-row-cur {
  font-weight: 600;
  color: #3F382F;         /* slightly richer than the label */
}

/* CATEGORY — Revenue / Cost of Goods Sold / Operating Expenses
   ALL-CAPS, fountain-pen Oxford Blue, and a color-coded row wash
   keyed by [data-cat] so each section is subconsciously grouped.
   mix-blend-mode: multiply lets the wash darken the paper grain
   rather than covering it — stays well under the "drab white" line. */
body.paper-mode .pnl-row--cat {
  margin: 6px 0 2px;
  padding-top: 12px;
  padding-bottom: 12px;
  border-radius: 3px;
  mix-blend-mode: multiply;
}
body.paper-mode .pnl-row--cat[data-cat="rev"]  { background: rgba(34, 197, 94, 0.03); }
body.paper-mode .pnl-row--cat[data-cat="cogs"] { background: rgba(239, 68, 68, 0.02); }
body.paper-mode .pnl-row--cat[data-cat="opex"] { background: rgba(239, 68, 68, 0.02); }
/* Fallback for any category not keyed (shouldn't happen in current data) */
body.paper-mode .pnl-row--cat:not([data-cat])  { background: rgba(55, 50, 45, 0.035); }
body.paper-mode .pnl-row--cat .pnl-row-label {
  font-size: 13px;
  font-weight: 800;
  letter-spacing: 0.1em;
  color: var(--riso-oxford);  /* Oxford Blue #002147 */
}
body.paper-mode .pnl-row--cat .pnl-row-cur {
  font-size: 18px;
  font-weight: 800;
  color: var(--riso-oxford);
}

/* SUBTOTAL — Gross Profit. Single "ledger blue" rule above the
   number (classic accounting-pad guideline, not grey). */
body.paper-mode .pnl-row--sub {
  border-top: 1px solid rgba(74, 107, 140, 0.45);   /* Ledger Blue */
  margin-top: 4px;
  padding-top: 12px;
}
body.paper-mode .pnl-row--sub .pnl-row-label {
  font-weight: 800;
  font-size: 14.5px;
  color: var(--riso-oxford);
}
body.paper-mode .pnl-row--sub .pnl-row-cur {
  font-size: 19px;
  font-weight: 800;
  color: var(--riso-oxford);
}

/* TOTAL — Net Operating Income. Double ledger-blue rule above AND
   below (bottom-line convention, but warmed up to accounting-pad
   colors so the page feels hand-penned rather than grey-on-grey).
   Border width is 6px: per spec `Npx double` renders as three equal
   bands (line / gap / line), so 6px = 2px line + 2px gap + 2px line.
   3px produced 1+1+1 which read as a single thin smudge rather than
   a true double rule. Padding is bumped to 20px so the big NOI $
   value has clear breathing room on both sides of each rule. */
body.paper-mode .pnl-row--total {
  border-top: 6px double rgba(74, 107, 140, 0.6);
  border-bottom: 6px double rgba(74, 107, 140, 0.6);
  margin-top: 10px;
  padding-top: 20px;
  padding-bottom: 20px;
}
body.paper-mode .pnl-row--total .pnl-row-label {
  font-size: 14px;
  font-weight: 800;
  letter-spacing: 0.12em;
  color: var(--riso-oxford);
}
body.paper-mode .pnl-row--total .pnl-row-cur {
  font-size: 22px;
  font-weight: 800;
  color: var(--riso-oxford);
}

/* ── Margin flag: sticky-note for outlier variances (>=50%) ────
   Small angled pennant in the far-left margin of leaf rows whose
   percent change is >= 50. Mustard for wins, terracotta for watches.
   Positioned absolutely against the row so it doesn't shift column 1
   (the row's position:relative is already set in the base .pnl-row
   rule higher up — no re-declaration needed). */
body.paper-mode .pnl-row-flag {
  position: absolute;
  left: 4px;
  top: 50%;
  width: 12px;
  height: 12px;
  transform: translateY(-50%) rotate(-8deg);
  border-radius: 1px 3px 1px 3px;
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.08);
  pointer-events: none;
}
body.paper-mode .pnl-row-flag--good { background: #D4A94A; }   /* muted mustard */
body.paper-mode .pnl-row-flag--bad  { background: #C75A3A; }   /* soft terracotta */

/* ── Drillable rows: cursor + focus ring ─────────────────────────
   Rows with an acctKey get a pointer cursor and a visible keyboard
   focus ring. The hover tint is already provided by the general
   `.pnl-row:hover` rule below, so these rows light up the same way
   non-drillable subtotals do — the cursor is enough to signal intent
   without adding visual noise to every row in the ledger. */
body.paper-mode .pnl-row--drill {
  cursor: pointer;
}
body.paper-mode .pnl-row--drill:focus-visible {
  outline: 2px solid var(--riso-oxford);
  outline-offset: -2px;
  background: rgba(70, 65, 60, 0.04);
}

/* ── Hover state on ledger rows (Location Owners Full Picture) ──
   Warm-gray fill matches the Technicians hover — no blend modes,
   no cyan wash, just a simple solid tint. Fires on all leaf +
   subtotal rows AND on any row marked drillable (categories like
   Revenue / COGS / Operating Expenses now open a drill-down modal,
   so they benefit from a hover affordance). The total row still
   keeps its double-rule borders unaffected. */
body.paper-mode .pnl-row:not(.pnl-row--cat):not(.pnl-row--total):hover,
body.paper-mode .pnl-row--drill:hover {
  background: rgba(70, 65, 60, 0.04);
}
/* Category rows already have a persistent color wash; overlay the
   hover tint on top so the click affordance still reads. */
body.paper-mode .pnl-row--cat.pnl-row--drill:hover {
  filter: brightness(0.97);
}

/* ── Mobile — tighter padding, smaller labels, narrower delta col ── */
@media (max-width: 768px) {
  body.paper-mode .pnl-row {
    grid-template-columns: minmax(0, 1fr) auto auto;
    column-gap: 10px;
    padding: 9px 8px;
  }
  body.paper-mode .pnl-row-label           { font-size: 12.5px; }
  body.paper-mode .pnl-row--leaf .pnl-row-label { padding-left: 14px; }
  body.paper-mode .pnl-row--cat .pnl-row-label  { font-size: 11.5px; letter-spacing: 0.08em; }
  body.paper-mode .pnl-row--sub .pnl-row-label  { font-size: 13px; }
  body.paper-mode .pnl-row--total .pnl-row-label{ font-size: 12.5px; letter-spacing: 0.1em; }
  body.paper-mode .pnl-row-values          { min-width: 72px; flex-shrink: 0; }
  body.paper-mode .pnl-row-cur             { font-size: 14px; }
  body.paper-mode .pnl-row--cat  .pnl-row-cur { font-size: 15.5px; }
  body.paper-mode .pnl-row--sub  .pnl-row-cur { font-size: 16px; }
  body.paper-mode .pnl-row--total .pnl-row-cur{ font-size: 18px; }

  /* ── Total row (Net Operating Income) — spatial separation fix ──
     "NET OPERATING INCOME" + letter-spacing 0.1em doesn't fit in
     column 1 on narrow phones and bleeds into the $41K value. Four
     coordinated changes keep it clean:
       1. Row padding bumped to 22px so the taller (wrapped) label
          has breathing room inside the double-rule borders.
       2. Label loses nowrap/flex-shrink ONLY on the total row so it
          wraps cleanly ("NET OPERATING" / "INCOME" on two lines).
       3. align-items: flex-start on the label row so the number
          stays flush to the first line of the label.
       4. padding-right buffer on the label guarantees a visible gap
          of "paper" between the label and the dollar value no matter
          how tight the viewport.
     The values + delta columns already have `flex-shrink: 0` +
     `min-width`, so they stay pristine. */
  body.paper-mode .pnl-row--total {
    padding-top: 22px;
    padding-bottom: 22px;
    align-items: flex-start;
    column-gap: 12px;
  }
  body.paper-mode .pnl-row--total .pnl-row-name {
    align-items: flex-start;
    min-width: 0;
    padding-right: 10px;          /* guaranteed buffer against the $ value */
  }
  body.paper-mode .pnl-row--total .pnl-row-label {
    white-space: normal;          /* allow wrap on narrow viewports */
    overflow-wrap: break-word;
    word-break: normal;
    flex-shrink: 1;               /* shrinkable so grid column can contain it */
    flex-basis: auto;
    line-height: 1.3;
    max-width: 100%;
  }
  /* Leader dots look odd when the label wraps to two lines (they'd
     stick to the baseline of line 1 while line 2 sits below). Hide
     them on the total row at mobile widths so the wrapped label
     reads cleanly. */
  body.paper-mode .pnl-row--total .pnl-row-leader {
    display: none;
  }
  body.paper-mode .pnl-row-prev            { font-size: 10.5px; }
  body.paper-mode .pnl-row-delta-cell      { min-width: 126px; }
  body.paper-mode .pnl-row-delta           { font-size: 11px; padding: 3px 7px; gap: 5px; }
  body.paper-mode .pnl-delta-arrow         { font-size: 9px; }
  body.paper-mode .pnl-row-leader          { min-width: 10px; border-bottom-width: 1px; }
}

/* ── Compare-month sheet / modal ────────────────────────────── */
/* Scroll lock while the sheet is open — prevents the background
   page from scrolling when the user drags on the sheet's grabber
   or anywhere inside the sheet shell. Without this the native touch
   gesture falls through to window and the whole page slides. */
body.pnl-cmp-lock {
  overflow: hidden;
  overscroll-behavior: contain;
  touch-action: none;
}
.pnl-cmp-backdrop[hidden] { display: none !important; }
.pnl-cmp-backdrop {
  position: fixed; inset: 0;
  background: rgba(55, 59, 77, 0);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  z-index: 1000;
  pointer-events: none;
  transition: background 0.28s ease;
}
.pnl-cmp-backdrop.is-open {
  background: rgba(55, 59, 77, 0.4);
  pointer-events: auto;
}
.pnl-cmp-sheet {
  width: 100%;
  max-width: 520px;
  max-height: 82vh;
  background: var(--paper-card, #F7F6F2);
  border-radius: 18px 18px 0 0;
  padding: 0 0 env(safe-area-inset-bottom);
  transform: translateY(100%);
  transition: transform 0.3s cubic-bezier(0.32, 0.72, 0, 1);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  box-shadow: 0 -8px 30px rgba(55, 59, 77, 0.15);
}
.pnl-cmp-backdrop.is-open .pnl-cmp-sheet { transform: translateY(0); }
/* Active drag: kill the slide transition so the sheet tracks the
   finger 1:1. The transition is restored on release so the snap-back
   or dismiss animation is smooth. */
.pnl-cmp-sheet.is-dragging { transition: none; }
/* Desktop: centered modal with fade+slide-down entrance + X close */
@media (min-width: 769px) {
  .pnl-cmp-backdrop { align-items: center; }
  .pnl-cmp-sheet {
    max-width: 420px;
    max-height: 72vh;
    border-radius: 14px;
    transform: translateY(-10px);
    opacity: 0;
    transition: transform 0.2s ease-out, opacity 0.2s ease-out;
  }
  .pnl-cmp-backdrop.is-open .pnl-cmp-sheet { transform: translateY(0); opacity: 1; }
}
.pnl-cmp-sheet-drag {
  flex-shrink: 0;
  padding: 16px 20px 14px;
  border-bottom: 1px solid rgba(55, 59, 77, 0.08);
  position: relative;
  /* Claim the vertical gesture — the browser must NOT interpret a
     swipe here as a page scroll. Paired with the body scroll-lock
     and our pointer drag handler this makes the drag 100% captured. */
  touch-action: none;
  cursor: grab;
  user-select: none;
}
.pnl-cmp-sheet.is-dragging .pnl-cmp-sheet-drag { cursor: grabbing; }
.pnl-cmp-sheet-grabber {
  width: 38px; height: 4px;
  background: #cbd5e1;
  border-radius: 2px;
  margin: 0 auto 10px;
}
@media (min-width: 769px) { .pnl-cmp-sheet-grabber { display: none; } }
.pnl-cmp-sheet-title {
  font-size: 15px; font-weight: 700;
  color: var(--brand-ink);
  text-align: center;
}
.pnl-cmp-sheet-close {
  position: absolute;
  top: 10px; right: 10px;
  width: 32px; height: 32px;
  border: none;
  background: transparent;
  font-size: 22px;
  color: var(--brand-ink-muted);
  cursor: pointer;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}
.pnl-cmp-sheet-close:hover { background: rgba(55, 59, 77, 0.06); color: var(--brand-ink); }
@media (max-width: 768px) { .pnl-cmp-sheet-close { display: none; } }

.pnl-cmp-sheet-list {
  overflow-y: auto;
  padding: 6px 0;
  -webkit-overflow-scrolling: touch;
}
.pnl-cmp-sheet-item {
  position: relative;
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 20px 14px 22px;
  font-size: 16px;
  font-weight: 500;
  color: var(--brand-ink);
  background: transparent;
  border: none;
  border-bottom: 1px dashed rgba(55, 59, 77, 0.1);
  text-align: left;
  cursor: pointer;
  min-height: 48px;
  transition: background 0.1s;
}
.pnl-cmp-sheet-item:last-child { border-bottom: none; }
.pnl-cmp-sheet-item:hover,
.pnl-cmp-sheet-item:focus-visible { background: rgba(55, 59, 77, 0.04); outline: none; }
.pnl-cmp-sheet-item.is-active {
  background: var(--brand-orange-tint);
  font-weight: 700;
}
.pnl-cmp-sheet-item.is-active::before {
  content: '';
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 4px;
  background: var(--brand-orange-soft);
  border-radius: 0 2px 2px 0;
}
.pnl-cmp-sheet-item-label { flex: 1; display: flex; flex-direction: column; gap: 2px; }
/* "No comparison" sentinel row — subtle visual separation from the
   month list below via a solid bottom border (vs dashed siblings). */
.pnl-cmp-sheet-item--none {
  border-bottom: 1px solid rgba(55, 59, 77, 0.12);
}
.pnl-cmp-sheet-item-desc {
  font-size: 11px;
  font-weight: 500;
  color: var(--brand-ink-muted);
  letter-spacing: 0.01em;
}
.pnl-cmp-sheet-tag {
  font-size: 9px;
  font-weight: 800;
  padding: 2px 6px;
  background: rgba(55, 59, 77, 0.08);
  color: var(--brand-ink-soft);
  border-radius: 4px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
.pnl-cmp-sheet-check {
  color: var(--brand-orange-soft);
  font-size: 18px;
  font-weight: 800;
}

/* ════════════════════════════════════════════════════════════════
   Marketing loader — EVALUATION GALLERY (temporary)
   ────────────────────────────────────────────────────────────────
   A 10-up grid of loader concepts shown on the Marketing tab's
   first-fetch. Each `.lg-cell` is numbered + labeled + contains
   one SVG running its own animation continuously. When the user
   picks a favorite the winning cell's animation will replace this
   gallery entirely.

   All animations are scoped with `lg` / `lgN` prefixes so there's
   no bleed to any other part of the site. The gallery lives inside
   `.ledger-loader.ledger-loader--gallery` which is hidden by CSS
   `.ll-done` (set by JS on dismiss).

   Mount-in animation for the real dashboard is kept unchanged.
   ════════════════════════════════════════════════════════════════ */

body.paper-mode .ledger-loader {
  position: relative;
  min-height: 320px;
  padding: 28px 22px;
  border-radius: 14px;
  background: #FAF9F6;
  font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  color: #2C2A28;
  user-select: none;
  /* Fast fade-out to match the 160ms JS dismiss timeout. This is the
     real production loader now, not an evaluation gallery — we don't
     want a long fade holding the eye after data is ready. */
  transition: opacity 160ms ease;
}
body.paper-mode .ledger-loader.ll-done {
  opacity: 0;
  pointer-events: none;
}

/* ── Solo loader (single Topographical Ripple, no gallery chrome) ─
   Centers the single SVG in the container at a large scale so the
   animation reads as the page's primary loading state. The old
   .lg-intro strip + .lg-grid are unused in this mode — the Continue
   button still lives here for the fast-API-response case. */
body.paper-mode .ledger-loader--solo {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 22px;
  min-height: 580px;
}
body.paper-mode .lg-stage--solo {
  width: 100%;
  max-width: 600px;
  display: flex;
  align-items: center;
  justify-content: center;
}
body.paper-mode .lg-stage--solo .lg-svg {
  width: 100%;
  max-width: 560px;
  height: auto;
  aspect-ratio: 1 / 1;
}
@media (max-width: 768px) {
  body.paper-mode .ledger-loader--solo { min-height: 380px; gap: 16px; }
  body.paper-mode .lg-stage--solo      { max-width: 360px; }
  body.paper-mode .lg-stage--solo .lg-svg { max-width: 320px; }
}

/* ── Gallery intro strip ─────────────────────────────────────── */
body.paper-mode .lg-intro {
  text-align: center;
  margin-bottom: 18px;
}
body.paper-mode .lg-intro-title {
  font-size: 18px;
  font-weight: 700;
  color: #2C2A28;
  margin-bottom: 4px;
}
body.paper-mode .lg-intro-sub {
  font-size: 12px;
  color: #7A7571;
  max-width: 560px;
  margin: 0 auto 10px;
  line-height: 1.4;
}
/* "Continue" button stays hidden until finalize() swaps in .is-ready
   (i.e. once the API response is back and the cb is queued). */
body.paper-mode .lg-continue {
  margin-top: 6px;
  padding: 7px 14px;
  font-size: 12px;
  font-weight: 600;
  color: #FAF9F6;
  background: #5C5448;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  opacity: 0;
  transform: translateY(-4px);
  pointer-events: none;
  transition: opacity 260ms ease, transform 260ms ease;
  font-family: inherit;
  letter-spacing: 0.02em;
}
body.paper-mode .lg-continue.is-ready {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
body.paper-mode .lg-continue:hover { background: #453f36; }

/* ── Grid layout ──────────────────────────────────────────────── */
body.paper-mode .lg-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 14px;
}
body.paper-mode .lg-cell {
  background: #FAF9F6;
  border: 1px solid rgba(92, 84, 72, 0.14);
  border-radius: 10px;
  padding: 12px 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 220px;
}
body.paper-mode .lg-head {
  display: flex;
  align-items: center;
  gap: 10px;
}
body.paper-mode .lg-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px; height: 26px;
  border-radius: 50%;
  background: #5C5448;
  color: #FAF9F6;
  font-size: 13px;
  font-weight: 700;
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
}
body.paper-mode .lg-name {
  font-size: 12px;
  font-weight: 600;
  color: #5C5448;
  letter-spacing: 0.01em;
  line-height: 1.25;
}
body.paper-mode .lg-stage {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 150px;
  overflow: hidden;
  position: relative;
}
body.paper-mode .lg-svg {
  width: 150px;
  height: 150px;
  display: block;
  overflow: visible;
}

/* ════════════════════════════════════════════════════════════════
   Topographical Ripple loader — sole animation.
   Four contours draw outward from OUTER → INNER in sequence
   (delay inversion is done in JS: outermost gets 0s, innermost
   gets (n-1)*stagger). Cycle 12s, slow + meditative. Central
   "Transforming Plumbing" label ONLY appears AFTER all four rings
   have drawn. Peak pulses through the whole cycle.
   Timing map (12s = 100%):
     0%   — all rings hidden (dashoffset 100)
     0–54%  — rings draw one-by-one (outer first, inner last)
              Each ring uses 36% of cycle to draw; with 0.9s
              staggers between four rings, the innermost ring
              finishes drawing at ~56% of the cycle.
     58–90% — label + peak fully visible (hold state)
     90–100% — rings + label fade together for a clean loop
   ════════════════════════════════════════════════════════════════ */
/* Cycle 20s. Each ring draws in its OWN non-overlapping 20% slot so
   the ripple reads as a slow meditative outward→inward pulse while
   /api/marketing is in flight. When the response lands, JS adds
   .ll-finishing on the loader root which snaps everything to the
   completed end state (all rings drawn, label + accent visible)
   with a short ease — so the user always sees a punctuated "done"
   tableau before the wrapper fades out. Outer first (--3), inner last (--0). */
body.paper-mode .lg4-ring--3 {
  animation: lg4Ring3 20s cubic-bezier(0.45, 0, 0.55, 1) infinite;
}
@keyframes lg4Ring3 {
  0%, 2%    { stroke-dashoffset: 100; opacity: 1; }
  20%       { stroke-dashoffset: 0;   opacity: 1; }
  95%       { stroke-dashoffset: 0;   opacity: 1; }
  100%      { stroke-dashoffset: 0;   opacity: 0; }
}
body.paper-mode .lg4-ring--2 {
  animation: lg4Ring2 20s cubic-bezier(0.45, 0, 0.55, 1) infinite;
}
@keyframes lg4Ring2 {
  0%, 20%   { stroke-dashoffset: 100; opacity: 1; }
  40%       { stroke-dashoffset: 0;   opacity: 1; }
  95%       { stroke-dashoffset: 0;   opacity: 1; }
  100%      { stroke-dashoffset: 0;   opacity: 0; }
}
body.paper-mode .lg4-ring--1 {
  animation: lg4Ring1 20s cubic-bezier(0.45, 0, 0.55, 1) infinite;
}
@keyframes lg4Ring1 {
  0%, 40%   { stroke-dashoffset: 100; opacity: 1; }
  60%       { stroke-dashoffset: 0;   opacity: 1; }
  95%       { stroke-dashoffset: 0;   opacity: 1; }
  100%      { stroke-dashoffset: 0;   opacity: 0; }
}
body.paper-mode .lg4-ring--0 {
  animation: lg4Ring0 20s cubic-bezier(0.45, 0, 0.55, 1) infinite;
}
@keyframes lg4Ring0 {
  0%, 60%   { stroke-dashoffset: 100; opacity: 1; }
  80%       { stroke-dashoffset: 0;   opacity: 1; }
  95%       { stroke-dashoffset: 0;   opacity: 1; }
  100%      { stroke-dashoffset: 0;   opacity: 0; }
}
/* Center label: reveals only AFTER all 4 rings are drawn (≥80%) */
body.paper-mode .lg4-label {
  opacity: 0;
  transform: translateY(3px);
  animation: lg4Label 20s cubic-bezier(0.34, 1.3, 0.64, 1) infinite;
}
@keyframes lg4Label {
  0%, 80%   { opacity: 0; transform: translateY(3px); }
  86%, 94%  { opacity: 1; transform: translateY(0); }
  100%      { opacity: 0; transform: translateY(0); }
}
/* Orange drafting rule beneath the label — draws in last, after the
   label has settled, as a finishing flourish that carries the warm
   accent color without colliding with the text. */
body.paper-mode .lg4-accent {
  animation: lg4Accent 20s cubic-bezier(0.4, 0, 0.2, 1) infinite;
}
@keyframes lg4Accent {
  0%, 86%   { stroke-dashoffset: 100; opacity: 0; }
  89%       { opacity: 1; }
  92%, 94%  { stroke-dashoffset: 0;   opacity: 1; }
  100%      { stroke-dashoffset: 0;   opacity: 0; }
}

/* ── .ll-finishing — snap to completed tableau on data-ready ───
   When /api/marketing resolves, JS adds .ll-finishing on the root.
   This kills the infinite cycle and transitions every ring + the
   label + the orange accent to their fully-drawn end state in ~380ms.
   The user always sees the "done" pose before the loader fades out,
   no matter where in the 20s cycle the data happened to arrive. */
body.paper-mode .ledger-loader.ll-finishing .lg4-ring--0,
body.paper-mode .ledger-loader.ll-finishing .lg4-ring--1,
body.paper-mode .ledger-loader.ll-finishing .lg4-ring--2,
body.paper-mode .ledger-loader.ll-finishing .lg4-ring--3,
body.paper-mode .ledger-loader.ll-finishing .lg4-label,
body.paper-mode .ledger-loader.ll-finishing .lg4-accent {
  animation: none !important;
  transition: stroke-dashoffset 380ms cubic-bezier(0.4, 0, 0.2, 1),
              opacity           220ms ease-out,
              transform         300ms cubic-bezier(0.34, 1.3, 0.64, 1);
}
body.paper-mode .ledger-loader.ll-finishing .lg4-ring--0,
body.paper-mode .ledger-loader.ll-finishing .lg4-ring--1,
body.paper-mode .ledger-loader.ll-finishing .lg4-ring--2,
body.paper-mode .ledger-loader.ll-finishing .lg4-ring--3,
body.paper-mode .ledger-loader.ll-finishing .lg4-accent {
  stroke-dashoffset: 0 !important;
  opacity: 1 !important;
}
body.paper-mode .ledger-loader.ll-finishing .lg4-label {
  opacity: 1 !important;
  transform: translateY(0) !important;
}

/* ── Reduced motion — freeze at a readable end-state ──────────── */
@media (prefers-reduced-motion: reduce) {
  body.paper-mode .lg4-ring--0,
  body.paper-mode .lg4-ring--1,
  body.paper-mode .lg4-ring--2,
  body.paper-mode .lg4-ring--3,
  body.paper-mode .lg4-label,
  body.paper-mode .lg4-accent { animation: none !important; }
  body.paper-mode .lg4-ring--0,
  body.paper-mode .lg4-ring--1,
  body.paper-mode .lg4-ring--2,
  body.paper-mode .lg4-ring--3,
  body.paper-mode .lg4-accent { stroke-dashoffset: 0 !important; opacity: 1 !important; }
  body.paper-mode .lg4-label  { opacity: 1 !important; transform: none !important; }
}

/* ── "Unfolding Ledger" staggered mount-in ─────────────────────
   Top-down cascade: stat cards land first, then progress bar, then
   each section title immediately followed by its card. Each step
   uses the same "Cardstock Placement" easing (0.2, 0.8, 0.2, 1 —
   decelerating like a matte card settling onto a desk) so the
   whole page reads as one physical unfolding motion.

   Using nth-child rather than explicit class names so the cascade
   stays robust when an optional QBO-banner row is prepended (every
   position just shifts one slot, delays still sequence correctly).
   The ~720ms last-sibling delay + 420ms duration = page fully
   settled by ~1140ms, comfortably inside the 1500–2000ms budget. */
body.paper-mode #marketingContent.mkt-mount-in > * {
  animation: mktMountIn 420ms cubic-bezier(0.2, 0.8, 0.2, 1) both;
}
body.paper-mode #marketingContent.mkt-mount-in > *:nth-child(1) { animation-delay: 0ms;   }
body.paper-mode #marketingContent.mkt-mount-in > *:nth-child(2) { animation-delay: 120ms; }
body.paper-mode #marketingContent.mkt-mount-in > *:nth-child(3) { animation-delay: 240ms; }
body.paper-mode #marketingContent.mkt-mount-in > *:nth-child(4) { animation-delay: 360ms; }
body.paper-mode #marketingContent.mkt-mount-in > *:nth-child(5) { animation-delay: 480ms; }
body.paper-mode #marketingContent.mkt-mount-in > *:nth-child(6) { animation-delay: 600ms; }
body.paper-mode #marketingContent.mkt-mount-in > *:nth-child(7) { animation-delay: 720ms; }

/* Phase 1 sub-cascade — the four stat cards lift in one at a time
   inside the .proj-cards container. Short 60ms delta between each
   so the row reads as a quick left-to-right unfurl, not four
   simultaneous pops. The container itself fades in at delay 0ms
   (from the > * rule above); the cards layer their own animation
   on top with micro-staggered delays. */
body.paper-mode #marketingContent.mkt-mount-in .proj-card {
  animation: mktMountIn 360ms cubic-bezier(0.2, 0.8, 0.2, 1) both;
}
body.paper-mode #marketingContent.mkt-mount-in .proj-card:nth-child(1) { animation-delay: 40ms;  }
body.paper-mode #marketingContent.mkt-mount-in .proj-card:nth-child(2) { animation-delay: 100ms; }
body.paper-mode #marketingContent.mkt-mount-in .proj-card:nth-child(3) { animation-delay: 160ms; }
body.paper-mode #marketingContent.mkt-mount-in .proj-card:nth-child(4) { animation-delay: 220ms; }

/* Phase 3 sub-cascade — Monthly History table rows flow in after the
   table container lands (~720ms via the > * rule). Each row stags
   36ms after the previous so a 12-row history takes ~432ms to
   complete, landing the last row around 1150ms. The footer total
   arrives right after the last body row. */
body.paper-mode #marketingContent.mkt-mount-in .mkt-table tbody tr {
  animation: mktMountIn 300ms cubic-bezier(0.2, 0.8, 0.2, 1) both;
}
body.paper-mode #marketingContent.mkt-mount-in .mkt-table tbody tr:nth-child(1)  { animation-delay: 720ms; }
body.paper-mode #marketingContent.mkt-mount-in .mkt-table tbody tr:nth-child(2)  { animation-delay: 756ms; }
body.paper-mode #marketingContent.mkt-mount-in .mkt-table tbody tr:nth-child(3)  { animation-delay: 792ms; }
body.paper-mode #marketingContent.mkt-mount-in .mkt-table tbody tr:nth-child(4)  { animation-delay: 828ms; }
body.paper-mode #marketingContent.mkt-mount-in .mkt-table tbody tr:nth-child(5)  { animation-delay: 864ms; }
body.paper-mode #marketingContent.mkt-mount-in .mkt-table tbody tr:nth-child(6)  { animation-delay: 900ms; }
body.paper-mode #marketingContent.mkt-mount-in .mkt-table tbody tr:nth-child(7)  { animation-delay: 936ms; }
body.paper-mode #marketingContent.mkt-mount-in .mkt-table tbody tr:nth-child(8)  { animation-delay: 972ms; }
body.paper-mode #marketingContent.mkt-mount-in .mkt-table tbody tr:nth-child(9)  { animation-delay: 1008ms; }
body.paper-mode #marketingContent.mkt-mount-in .mkt-table tbody tr:nth-child(10) { animation-delay: 1044ms; }
body.paper-mode #marketingContent.mkt-mount-in .mkt-table tbody tr:nth-child(11) { animation-delay: 1080ms; }
body.paper-mode #marketingContent.mkt-mount-in .mkt-table tbody tr:nth-child(12) { animation-delay: 1116ms; }
body.paper-mode #marketingContent.mkt-mount-in .mkt-table tbody tr:nth-child(n+13) { animation-delay: 1152ms; }
body.paper-mode #marketingContent.mkt-mount-in .mkt-table tfoot tr { animation-delay: 1200ms; }
body.paper-mode #marketingContent.mkt-mount-in .mkt-table tfoot tr {
  animation: mktMountIn 300ms cubic-bezier(0.2, 0.8, 0.2, 1) both;
}

@keyframes mktMountIn {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ── Graph animations — the "actual dashboard waking up" beat ───
   Three CSS-driven keyframes layered on top of the section cascade
   so the GRAPHS themselves animate in, not just the containers:

   1. Progress bar fills 0 → target width (target carried by the
      --fill-target custom property, set inline in renderMarketing).
   2. Bar chart bars grow 0 → full height via scaleY, GPU-accelerated,
      staggered per column via --bar-delay (also inline).
   3. Each bar's value label fades in after its bar reaches full
      height, using the same --bar-delay + a small offset.

   Count-up animations on the stat card numbers + progress %% are
   JS-driven (runMarketingCountUps in marketing.js) so their timing
   syncs with these CSS beats. */

/* 1. Progress bar fill */
body.paper-mode #marketingContent.mkt-mount-in .progress-bar-fill {
  animation: mktProgressFill 900ms cubic-bezier(0.2, 0.8, 0.2, 1) 360ms both;
}
@keyframes mktProgressFill {
  from { width: 0%; }
  to   { width: var(--fill-target, 100%); }
}

/* 2. Bar chart bars grow from the baseline upward. transform-origin
   bottom + scaleY keeps the animation off the paint/layout path. */
body.paper-mode #marketingContent.mkt-mount-in .bar {
  transform-origin: bottom;
  animation: mktBarGrow 560ms cubic-bezier(0.2, 0.8, 0.2, 1) both;
  animation-delay: var(--bar-delay, 480ms);
}
@keyframes mktBarGrow {
  from { transform: scaleY(0); }
  to   { transform: scaleY(1); }
}

/* 3. The number above each bar fades in 280ms AFTER its bar starts
   growing — so the value appears just as the bar nears full height. */
body.paper-mode #marketingContent.mkt-mount-in .bar-val {
  animation: mktMountIn 320ms cubic-bezier(0.2, 0.8, 0.2, 1) both;
  animation-delay: calc(var(--bar-delay, 480ms) + 280ms);
}

/* Respect reduced-motion — skip the entire cascade, show the page instantly. */
@media (prefers-reduced-motion: reduce) {
  body.paper-mode #marketingContent.mkt-mount-in > *,
  body.paper-mode #marketingContent.mkt-mount-in .proj-card,
  body.paper-mode #marketingContent.mkt-mount-in .mkt-table tbody tr,
  body.paper-mode #marketingContent.mkt-mount-in .mkt-table tfoot tr,
  body.paper-mode #marketingContent.mkt-mount-in .progress-bar-fill,
  body.paper-mode #marketingContent.mkt-mount-in .bar,
  body.paper-mode #marketingContent.mkt-mount-in .bar-val {
    animation: none !important;
  }
}

/* ── Mobile ───────────────────────────────────────────────────── */
@media (max-width: 768px) {
  body.paper-mode .ledger-loader { padding: 20px 14px; }
  body.paper-mode .lg-intro-title { font-size: 16px; }
  body.paper-mode .lg-intro-sub   { font-size: 11.5px; }
  body.paper-mode .lg-grid        { grid-template-columns: 1fr 1fr; gap: 10px; }
  body.paper-mode .lg-cell        { min-height: 190px; padding: 10px; gap: 8px; }
  body.paper-mode .lg-name        { font-size: 11px; }
  body.paper-mode .lg-num         { width: 22px; height: 22px; font-size: 12px; }
  body.paper-mode .lg-svg         { width: 120px; height: 120px; }
  body.paper-mode .lg-stage       { min-height: 120px; }
}


/* ════════════════════════════════════════════════════════════════
   Risograph ink accents (see palette vars at top of this file)
   ────────────────────────────────────────────────────────────────
   Five targeted injections of color over the charcoal-on-paper base:
     1. Fountain-pen Oxford Blue on the primary page title
     2. Highlighter marker on the #1 revenue leader
     3. Watercolor cyan wash on row hover / active states
     4. Multiply blend mode on chart canvases (richer ink tones)
     5. Fountain-pen Hunter Green on major section titles
   "Platform rubber-stamp icons" (spec #2) is omitted — no platform
   data (Google LSA / Yelp / Angi) exists in the dataset to apply to.
   ════════════════════════════════════════════════════════════════ */

/* ── 1. Fountain-pen header ink ───────────────────────────────── */
/* Main page title "Sunwave Plumbing" — swap charcoal for deep Oxford
   Blue. Reads as premium stationery ink, not digital grey. */
body.paper-mode h1 {
  color: var(--riso-oxford);
}
/* Section titles across tabs ("Jobs Per Month", "Monthly History",
   "Cash in the Bank Over Time", etc.) — Hunter Green feels like a
   ledger heading penned in rich ink. */
body.paper-mode .section-title,
body.paper-mode .fin-chart-title {
  color: var(--riso-hunter);
  font-weight: 700;
}

/* ── 2. Leaderboard #1 winner highlighter ────────────────────────
   Marker-stroke behind the top-ranked technician's Revenue number.
   Simple + stable: solid-ish sunflower yellow background, small
   radius, subtle horizontal padding. No mix-blend-mode (caused
   paint glitches on hover) and no pseudo-elements — the span's own
   background handles it cleanly. */
body.paper-mode .row-count.is-winner {
  display: inline-block;
  background-color: rgba(255, 209, 0, 0.25);
  padding: 2px 6px;
  border-radius: 4px;
  font-weight: 700;
  color: var(--brand-ink);
}

/* ── Stamped-ink avatar circles (paper-mode override) ────────────
   Base .avatar rule in styles.css sets a 36×36 rounded-square tile
   with white text on a solid color; paper-mode flips that to a
   circular chip whose background comes from JS (faint tinted hue)
   and whose text is the matching dark ink — both set inline via
   the new AVATAR_PALETTES in app.js. CSS here just handles shape +
   sizing so the ink letter has enough breathing room. */
body.paper-mode .avatar {
  border-radius: 50%;
  width: 32px;
  height: 32px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.04em;
  border: 1px solid rgba(55, 59, 77, 0.06);
}

/* ── "Pencil Sketch" projection bar (Jobs Per Month → current month) ─
   Replaces the harsh diagonal peach stripes on the forthcoming-month
   bar with a tactile pencil-sketched look: a dashed charcoal outline,
   a nearly-invisible 45° hatch fill, and italic graphite typography
   for the projected number + PROJ badge. Reads as "penciled in,
   not yet permanent" — the way an accountant marks a projection
   in a physical ledger before inking it in. */
body.paper-mode .bar.is-current {
  background: repeating-linear-gradient(
    45deg,
    transparent 0,
    transparent 4px,
    rgba(44, 42, 40, 0.04) 4px,
    rgba(44, 42, 40, 0.04) 5px
  ) !important;   /* beats any lingering inline background */
  border: 2px dashed rgba(243, 138, 63, 0.5);   /* brand orange @ 50% */
  opacity: 1 !important;                        /* reset the old 0.6 */
  box-sizing: border-box;
  border-radius: 4px 4px 0 0;
}

/* Projected value + PROJ tag — italic, graphite pencil color */
body.paper-mode .bar-val--proj {
  font-style: italic;
  color: #6B6761;   /* warm graphite gray */
  font-weight: 600;
}
body.paper-mode .bar-proj-tag {
  font-size: 8px;
  font-weight: 700;
  font-style: italic;
  letter-spacing: 0.08em;
  color: #6B6761;
  line-height: 1;
  margin-top: 2px;
}

/* X-axis baseline tinted warm instead of cool grey #f0f0f0, so the
   tiny hairline under the bars reads as part of the paper palette. */
body.paper-mode .bar-chart::after {
  background: var(--paper-border-firm) !important;
}

/* ── 3. Row hover: simple, stable, no blending ─────────────────
   Previously applied a cyan-wash + multiply blend to every cell
   individually, which caused paint flicker on rapid mouse moves
   (multiple compositing layers re-running per td). Replaced with
   a single solid warm-gray fill applied across all cells of the
   hovered row. No mix-blend-mode, no per-cell !important battles;
   150ms background transition keeps it tactile without re-renders. */
body.paper-mode tbody tr {
  transition: background-color 150ms ease;
}
body.paper-mode tbody tr:hover td {
  background-color: rgba(70, 65, 60, 0.04);
}
/* Marketing "Monthly History" hover — intentionally the simplest
   possible interaction: an ultra-faint single-tone darkening of the
   row background, with a fast 0.1s transition and NO text-color
   shifts. Multi-tone hover chains are what caused the rendering
   glitches the spec §3 called out. Also scope transitions explicitly
   to background-color so nothing else animates on hover. */
body.paper-mode .mkt-table tbody td {
  transition: background-color 0.1s ease;
  /* Accounting-pad ledger lines — replaces the default light-grey
     underlines with pale "Accounting Red" dashed rows. Physical
     accounting paper uses these muted red lines to guide the eye
     across wide columnar rows; the dashed style reinforces the
     "soft pencil guide" feel rather than a hard digital border. */
  border-bottom: 1px dashed rgba(139, 58, 58, 0.32) !important;
}
/* Thead underline + tfoot overline get a deeper accounting-red
   solid line — the "subtotal rule" you draw in ledger books above
   and below a totals row. Still muted enough to read as pencil, not
   as a harsh digital divider. */
body.paper-mode .mkt-table thead th {
  border-bottom: 1.5px solid rgba(139, 58, 58, 0.45);
}
body.paper-mode .mkt-table tfoot td {
  border-top: 2px double rgba(139, 58, 58, 0.50);   /* double rule — the classic "grand total" accounting mark */
}
/* Drop the last-row underline so the body ends cleanly before the
   tfoot's double rule takes over. */
body.paper-mode .mkt-table tbody tr:last-child td {
  border-bottom-color: transparent !important;
}
body.paper-mode .mkt-table tbody tr:hover td,
body.paper-mode .mkt-table tbody tr:hover td:first-child {
  background-color: rgba(0, 0, 0, 0.02);
}
/* Hold the number / delta ink colors steady on hover — no fades,
   no shifts. The row just darkens its paper, nothing else. */
body.paper-mode .mkt-table tbody tr:hover .mkt-jobs-num        { color: #2C2A28; }
body.paper-mode .mkt-table tbody tr:hover .mkt-jobs-num--proj  { color: #7A7571; }
body.paper-mode .mkt-table tbody tr:hover .delta-up            { color: #4CBB17; }
body.paper-mode .mkt-table tbody tr:hover .delta-down          { color: #E34234; }
/* Full Picture 2-col legacy table — same warm gray, beats the base
   styles.css `#eef2f7` hover on specificity via paper-mode prefix. */
body.paper-mode .pnl-grid--2col tbody tr:hover:not(.total) td,
body.paper-mode .pnl-grid--2col tbody tr:hover:not(.total) .pnl2-td-lbl {
  background-color: rgba(70, 65, 60, 0.04);
}
/* Full Picture ledger rows (Location Owners) — press state only. */
body.paper-mode .pnl-row:not(.pnl-row--cat):not(.pnl-row--total):active {
  background: rgba(70, 65, 60, 0.08);
  transform: scale(0.99);
}

/* ── 4. Chart canvas: multiply blend mode ──────────────────────
   Chart.js paints colors at full opacity; layering the canvas with
   mix-blend-mode: multiply lets the paper texture beneath show
   through, turning flat digital colors into richer "ink on paper"
   tones. Applied to every canvas in the Location Owners tab. */
body.paper-mode #trendChart,
body.paper-mode #revBarChart,
body.paper-mode #cfBarChart {
  mix-blend-mode: multiply;
}
/* #donutChart is intentionally EXCLUDED from multiply. The 3px slice
   borders are set to paper-card (#F7F6F2); multiply would darken them
   against the same paper tone beneath, producing visible cream lines
   between slices. Leaving it as normal blend lets the borders blend
   seamlessly into the card background. */

/* ── Donut center total (animated count-up) ─────────────────────
   Overlays the donut hole with a small label + animated total. The
   value is populated in JS; this just handles the visual. */
body.paper-mode .fin-donut-wrap {
  position: relative;
}
/* ── Paper texture overlay on donut segments ──────────────────────
   Chart.js draws the donut as flat colored fills on a canvas. To give
   the slices the same paper-fiber grain as the rest of the page, we
   overlay the SAME fractalNoise SVG that body.paper-mode::before uses
   for the page background — and clip it to a ring shape matching the
   donut's geometry so the texture paints ONLY over the colored slices,
   not the empty rectangle around them.

   Two safeguards keep the bg clean:
     1) `mask-image: radial-gradient(...)` — a ring-shaped alpha mask
        centered on the donut. Transparent outside the outer edge and
        inside the inner hole; opaque through the ring band.
     2) `mix-blend-mode: soft-light` — preserves base luminance so
        the paper pixels outside the mask stay paper-toned even if the
        mask edge bleeds slightly. Multiply would darken the bg into
        a grey rectangle (which is what the previous pass did).

   Opacity matches the subtlety of the body::before texture (0.04) but
   is bumped to ~0.55 so the grain actually reads on the saturated
   donut colors — soft-light is much gentler than multiply and needs
   more alpha to show. pointer-events:none so slice clicks still land. */
body.paper-mode .fin-donut-wrap::after {
  content: '';
  position: absolute;
  inset: 0;
  background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 220 220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.55 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 220px 220px;          /* match the body bg texture exactly */
  /* Ring mask: chart.js donut fills a centered square of min(width,height)
     and uses cutout:'60%' for the inner hole. So the ring lives roughly
     between 30% and 50% of the container's smaller axis. We size the mask
     to a square tied to the wrap's HEIGHT (340px), centered horizontally,
     and cut a ring via a radial-gradient alpha mask. */
  /* Ring mask sized to the donut. CRITICAL: use `circle closest-side`
     so 100% of the gradient = half the mask's shorter axis (170px on a
     340x340 mask = the donut's actual outer radius). Without
     closest-side, radial-gradient defaults to farthest-corner sizing
     (100% ≈ 240px), and percentage stops land WAY inside the donut's
     geometry — producing the "darker inner half / brighter outer half"
     artifact where the opaque mask band only covers the inner half of
     the ring and the outer half receives no texture.

     With closest-side:
       100% = 170px = donut outer edge (cutout:58% ⇒ outer ≈ height/2)
       58%  ≈ 98.6px = donut inner edge
     The gradient is fully opaque across the ENTIRE donut ring width
     (58–100%), with gentle feathers that land in the hole (50→57%)
     and at the outer anti-aliasing edge (99→100%). Corners of the
     340x340 mask square stay transparent (beyond 100% extrapolates
     the last `transparent` stop). */
  -webkit-mask-image: radial-gradient(circle closest-side at center,
      transparent 50%,
      #000 57%,
      #000 99%,
      transparent 100%);
          mask-image: radial-gradient(circle closest-side at center,
      transparent 50%,
      #000 57%,
      #000 99%,
      transparent 100%);
  -webkit-mask-size: 340px 340px;
          mask-size: 340px 340px;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  -webkit-mask-position: center center;
          mask-position: center center;
  mix-blend-mode: soft-light;
  opacity: 0.55;
  pointer-events: none;
  z-index: 1;
}
/* Responsive: the donut height shrinks at narrower breakpoints
   (styles.css: 320px at one bp, 290px at the next). Shrink the
   mask square in lockstep so the ring keeps hugging the donut. */
@media (max-width: 900px) {
  body.paper-mode .fin-donut-wrap::after {
    -webkit-mask-size: 320px 320px;
            mask-size: 320px 320px;
  }
}
@media (max-width: 600px) {
  body.paper-mode .fin-donut-wrap::after {
    -webkit-mask-size: 290px 290px;
            mask-size: 290px 290px;
  }
}
body.paper-mode .fin-donut-center {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  text-align: center;
  pointer-events: none;   /* never blocks slice clicks */
  font-variant-numeric: tabular-nums;
  width: 46%;             /* constrain so long values don't overflow the hole */
  max-width: 170px;
  /* Stay above the paper-texture overlay so the center total reads
     without being darkened by the multiply blend. */
  z-index: 2;
}
body.paper-mode .fin-donut-center-label {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--brand-ink-muted);
  margin-bottom: 4px;
}
body.paper-mode .fin-donut-center-value {
  font-size: 24px;
  font-weight: 800;
  color: var(--brand-ink);
  line-height: 1.1;
}
@media (max-width: 768px) {
  body.paper-mode .fin-donut-center-value { font-size: 20px; }
  body.paper-mode .fin-donut-center-label { font-size: 9.5px; }
}

/* ── Hidden-slice pill state ──────────────────────────────────
   When a user taps a pill to hide its slice, the pill fades, the
   colored dot drops to a hollow ring, and a strike-through runs
   across the label so the "off" state is unmistakable at a glance. */
body.paper-mode .fin-donut-chip--hidden {
  opacity: 0.45;
  background: transparent !important;
}
body.paper-mode .fin-donut-chip--hidden .fin-donut-chip-label {
  text-decoration: line-through;
  text-decoration-color: rgba(55, 59, 77, 0.4);
  text-decoration-thickness: 1.5px;
}
body.paper-mode .fin-donut-chip--hidden .fin-donut-chip-dot {
  background: transparent !important;
  box-shadow: inset 0 0 0 2px var(--chip-c);
}

/* ── 5. Reinforce premium ink feel on subtotal / total labels ───
   The P&L ledger's category and subtotal rows ("Revenue", "Gross
   Profit", "Net Operating Income") pick up the fountain-pen blue so
   they read as anchor lines of a hand-kept ledger. Leaves + the big
   grand-total row stay in the brand ink for contrast. */
/* Gross Profit (subtotal) label picks up the fountain-pen Oxford Blue
   to feel like a hand-penned anchor line. Categories stay charcoal
   (#2C2A28) per the "Modern Paper P&L" spec — the warm gray wash is
   enough hierarchy, adding color would muddy the ALL-CAPS treatment. */
body.paper-mode .pnl-row--sub .pnl-row-label { color: var(--riso-oxford); }

/* ════════════════════════════════════════════════════════════════
   "Paper Watermark" skeleton loader
   ────────────────────────────────────────────────────────────────
   Replaces the default cool-grey blocks (#eef1f5 → #f8fafc shimmer)
   with a transparent warm-charcoal wash that multiplies into the
   paper grain beneath. The shimmer wave darkens rather than
   brightens, so it reads like a shadow rolling across damp paper
   instead of a glossy sheen. Every block also gets a tiny inner
   shadow so it looks stamped / debossed into the page.
   ════════════════════════════════════════════════════════════════ */

body.paper-mode .skel {
  /* Base "wet paper" wash — transparent warm charcoal, so the paper
     grain and canvas tone show through instead of being blocked. */
  background-color: rgba(44, 42, 40, 0.04);
  /* Rolling wave: fully transparent → faint warm ink peak → transparent.
     Animation remains the same @keyframes skel-shimmer from styles.css
     (swept via background-position), only the colors change here. */
  background-image: linear-gradient(
    90deg,
    rgba(70, 65, 60, 0.00) 0%,
    rgba(70, 65, 60, 0.08) 50%,
    rgba(70, 65, 60, 0.00) 100%
  );
  background-size: 200% 100%;
  /* Makes the block interact with the global SVG noise texture —
     the grain darkens THROUGH the skeleton shape instead of the block
     sitting on top like a plastic overlay. */
  mix-blend-mode: multiply;
  /* Micro inner shadow — the block looks pressed into the paper fibers
     while it waits for the real ink (data) to fill it in. */
  box-shadow: inset 0 1px 3px rgba(70, 65, 60, 0.04);
}

/* Row divider in the loading-state table was a cool pale grey — swap
   to the shared paper-border so rows separate on warm paper. */
body.paper-mode .skel-row td {
  border-bottom-color: var(--paper-border);
}

/* Cipher text / status line were cool slate — warm them to muted
   pencil ink so they read like faintly penciled placeholders, not
   LCD subpixels. */
body.paper-mode .skel-cipher {
  color: rgba(44, 42, 40, 0.28);
  opacity: 0.7;
}
body.paper-mode .skel-status {
  color: rgba(44, 42, 40, 0.5);
}
/* Name scramble tone during reveal — keep the FULL brand-ink color
   (same as the settled state) so there's no lighter→darker shift when
   the caret finishes. The typewriter dash cursor (defined in styles.css
   via ::after) signals the "still typing" state instead of a color fade.
   We do slightly soften the caret itself so it reads as fountain-pen
   rather than a hard digital cursor. */
body.paper-mode .tech-name-label.is-revealing {
  color: var(--brand-ink);
}
body.paper-mode .tech-name-label.is-revealing::after {
  background: var(--riso-oxford);  /* Oxford-blue nib for the cursor */
  opacity: 0.55;
  height: 2px;
  border-radius: 1px;
}

/* ── Respect reduced-motion preferences ──────────────────────── */
@media (prefers-reduced-motion: reduce) {
  body.paper-mode,
  body.paper-mode::before { transition: none; }
  .pnl-cmp-sheet { transition: none; }
  .pnl-cmp-backdrop { transition: none; }
  /* Marketing loader: the stream + ink-soak + dot + label reduced-motion
     overrides are already scoped inside the ledger-loader block above;
     this rule just ensures the mount-in slide-up is skipped too. */
  body.paper-mode #marketingContent.mkt-mount-in > * { animation: none; }
  /* Skeleton shimmer also stops — block stays at base tone. */
  body.paper-mode .skel { animation: none; background-image: none; }
}

/* ════════════════════════════════════════════════════════════════
   Unified Financial Summary card (.ufs-card)
   ────────────────────────────────────────────────────────────────
   A new sibling card that lives directly below the existing
   "<Month> Financial Summary" (.mf-card). Same warm paper aesthetic
   + deep charcoal ink, with three vibrant category colors driving a
   single tactile interactive bar. Accordion expansion uses the
   grid-template-rows 0fr → 1fr trick for a real-height transition
   (no max-height approximation) so the panel slides like paper.
   ════════════════════════════════════════════════════════════════ */

body.paper-mode .ufs-card {
  background: var(--paper-bg, #F4F1EA);
  border: 1px solid rgba(92, 84, 72, 0.14);
  border-radius: 16px;
  /* Generous inner padding + bottom margin per spec so the card
     breathes and doesn't crowd what sits below it. */
  padding: 36px 40px 32px;
  /* V6: Generous bottom margin per spec so the glow/ink-wash on an
     open dropdown can breathe without crowding the next card. */
  margin-top: 1.2rem;
  margin-bottom: 48px;
  font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  color: #373B4D;
  position: relative;
  box-shadow:
    0 1px 1px rgba(44, 42, 40, 0.04),
    0 2px 10px rgba(44, 42, 40, 0.04);
  /* "Cardstock Placement" entrance — the card descends gently onto
     the paper with a strong ease-out, mimicking the physical action
     of setting a heavy piece of matte cardstock down on a desk. The
     0.2, 0.8, 0.2, 1 bezier gives the settle the friction feel of
     something heavy coming to rest. Everything inside the card
     (ink-fill segments, count-up, amount labels) starts AFTER this
     400ms window closes, so the card is fully landed before any ink
     appears on it. */
  animation: ufsCardPlace 400ms cubic-bezier(0.2, 0.8, 0.2, 1) both;
}
@keyframes ufsCardPlace {
  0%   { opacity: 0; transform: translateY(12px); }
  100% { opacity: 1; transform: translateY(0); }
}

/* ── 0. Card title header ──────────────────────────────────────── */
body.paper-mode .ufs-header {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding-bottom: 14px;
  margin-bottom: 16px;
  border-bottom: 1px solid rgba(92, 84, 72, 0.14);
  flex-wrap: wrap;
}
body.paper-mode .ufs-header-title {
  font-size: 17px;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: #373B4D;
  line-height: 1.2;
}
body.paper-mode .ufs-header-period {
  font-size: 14px;
  font-weight: 600;
  color: #7A7571;
  letter-spacing: 0.01em;
  font-variant-numeric: tabular-nums;
}

/* ── 1. Main revenue header (stacked typographic hierarchy) ──────
   Eyebrow label "TOTAL REVENUE" in small highly-tracked charcoal
   above a massive $ figure. Creates a dominant anchor so the eye
   lands on the revenue total the moment the card renders. */
body.paper-mode .ufs-main-header {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 6px 4px 26px;
  margin-bottom: 24px;
  border-bottom: 1px dashed rgba(92, 84, 72, 0.28);
  font-variant-numeric: tabular-nums;
}
body.paper-mode .ufs-main-eyebrow {
  font-size: 11px;
  font-weight: 800;
  color: #2C2A28;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  line-height: 1;
}
body.paper-mode .ufs-main-value {
  font-size: 52px;
  font-weight: 800;
  color: #373B4D;
  letter-spacing: -0.025em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

/* ── 1b. Per-segment $ amount labels (above the bar) ───────────── */
/* Flex row with the SAME flex weights as the bar, so each amount
   sits centered above its segment. Tying the $ directly to the
   colored block below creates a stronger visual link than the
   old formula line did. */
body.paper-mode .ufs-amounts {
  display: flex;
  width: 100%;
  gap: 2px;                 /* matches the bar's inter-segment gap */
  padding: 0;
  margin-bottom: 8px;
  font-variant-numeric: tabular-nums;
}
body.paper-mode .ufs-amount {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
  font-size: 17px;
  font-weight: 800;
  letter-spacing: -0.01em;
  line-height: 1;
  padding: 0 6px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
body.paper-mode .ufs-amount--cogs   { color: #B83E3E; }
body.paper-mode .ufs-amount--ovhd   { color: #C76810; }
body.paper-mode .ufs-amount--profit { color: #1E8749; }

/* ── 2. Unified interactive bar ────────────────────────────────── */
/* The wrap reserves room above + below the bar so the target markers
   (TARGET 50% coral tick / PROFIT GOAL 15% green tick) can extrude
   slightly above the bar and hang their uppercase labels below. */
body.paper-mode .ufs-bar-wrap {
  position: relative;
  padding: 8px 0 38px;
  margin-bottom: 4px;
}
/* The old ufsOutlineFade dashed-charcoal rectangle that outlined the
   bar during the entrance has been removed. It was flashing a dotted
   line across the bar during the animation and reading as a rendering
   artifact (a rogue outline during CSS repaints) rather than an
   intentional ink mark on paper. Nothing replaces it — the empty bar
   track now shows through as paper-color gaps between segments,
   which is visible during the left-to-right ink fill below and fades
   in cleanly with the card placement. */

/* ── "Ink Fill Sequence" entrance for the bar segments ──────────
   Each segment reveals left → right via clip-path, like a fountain
   pen drawing a thick line of ink across the paper. clip-path lets
   us preserve the flex layout (each seg reserves its target flex
   width from the start) while progressively revealing the colored
   fill horizontally — no layout thrash, no mid-flight re-measurement.

   Durations are proportional to segment width so the "pen speed"
   feels constant as it travels across the bar: COGS is the widest so
   takes the longest, PROFIT is the narrowest so finishes fastest.
   Delays overlap slightly so the pen appears to flow continuously
   through the inter-segment gaps rather than lifting + restarting.

   Delay 420ms = card placement animation (400ms) + 20ms settle.
   Full bar is inked by ~1020ms, matching the count-up duration
   in ufsAnimateTally (700ms starting at 420ms ⇒ finishes at 1120ms). */
body.paper-mode .ufs-seg {
  animation: ufsInkFill 420ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
}
body.paper-mode .ufs-seg--cogs   { animation-delay: 420ms; animation-duration: 420ms; }
body.paper-mode .ufs-seg--ovhd   { animation-delay: 720ms; animation-duration: 260ms; }
body.paper-mode .ufs-seg--profit { animation-delay: 860ms; animation-duration: 160ms; }
@keyframes ufsInkFill {
  0%   { clip-path: inset(0 100% 0 0); -webkit-clip-path: inset(0 100% 0 0); }
  100% { clip-path: inset(0 0 0 0);    -webkit-clip-path: inset(0 0 0 0); }
}

/* Per-segment $ amount labels fade in as the pen reaches the end
   of their segment — a "finish line" marker for each column. Each
   amount arrives just after its colored seg below is fully inked. */
body.paper-mode .ufs-amount {
  animation: ufsAmountRise 280ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
}
body.paper-mode .ufs-amount--cogs   { animation-delay: 820ms; }
body.paper-mode .ufs-amount--ovhd   { animation-delay: 960ms; }
body.paper-mode .ufs-amount--profit { animation-delay: 1000ms; }
@keyframes ufsAmountRise {
  0%    { opacity: 0; transform: translateY(-4px); }
  100%  { opacity: 1; transform: translateY(0); }
}

/* V5: Target ticks on the main bar were removed — they caused
   horizontal layout glitches at 85% on narrow viewports. The
   goal-vs-actual readout now lives inside the dropdown panels
   (see .ufs-target-readout). No tick-slice animation needed. */

/* V6: The funnel has been replaced by the CSS ink-wash treatment on
   .ufs-zoom (caret + sheer bg tint + category glow). That treatment
   is USER-triggered (click), not part of initial load, so no
   keyframe here. */
body.paper-mode .ufs-bar {
  display: flex;
  width: 100%;
  /* Min-height 72px: large enough for a thumb tap on mobile while
     the narrow Profit segment (~15% width) still has plenty of
     vertical surface area. */
  min-height: 72px;
  height: 72px;
  border-radius: 10px;
  /* Background transparent so the CARD's paper color shows through
     the inter-segment gap — reads as physical separation between
     the colored blocks, not a drawn line. */
  background: transparent;
  /* Drop the inset shadow — the bar should look like segments
     resting on paper, not a recessed well. */
  box-shadow: none;
  overflow: visible;    /* allow the drop-slam animation to peek */
  gap: 4px;             /* 4px of paper showing between blocks */
  padding: 0;
  position: relative;
  z-index: 1;
}
body.paper-mode .ufs-seg {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
  padding: 0 14px;
  border: none;
  color: #373B4D;
  font-family: inherit;
  cursor: pointer;
  outline: none;
  /* Opacity joins the transition so the dim-siblings effect fades
     in/out smoothly rather than snapping when you switch segments. */
  transition: filter 180ms cubic-bezier(0.2, 0, 0.1, 1),
              opacity 240ms cubic-bezier(0.4, 0, 0.2, 1),
              transform 180ms cubic-bezier(0.2, 0, 0.1, 1);
  user-select: none;
}
body.paper-mode .ufs-seg--cogs   { background: #FF5B5B; }
body.paper-mode .ufs-seg--ovhd   { background: #FF8A1F; }
body.paper-mode .ufs-seg--profit { background: #2ECC71; }
/* With overflow:visible on the bar (so segments can drop-slam on
   load), each segment needs to carry its own corner radius. First
   + last get the outer bar rounding; middle stays square so the
   gap reads cleanly. */
body.paper-mode .ufs-seg--cogs   { border-radius: 10px 2px 2px 10px; }
body.paper-mode .ufs-seg--ovhd   { border-radius: 2px; }
body.paper-mode .ufs-seg--profit { border-radius: 2px 10px 10px 2px; }

body.paper-mode .ufs-seg-ink {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  line-height: 1.1;
  text-align: center;
  pointer-events: none;
  min-width: 0;
  max-width: 100%;
}
body.paper-mode .ufs-seg-label {
  /* Category name is the PRIMARY inside the block: larger + heavier
     than the percentage below it. Deep charcoal ink for legibility
     on every vibrant color. */
  font-size: 15px;
  font-weight: 800;
  letter-spacing: 0.01em;
  color: #373B4D;                /* dark ink — NO white text anywhere */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
body.paper-mode .ufs-seg-pct {
  /* Percentage is the SECONDARY inside the block — slightly smaller
     so the category name reads as the lead. */
  font-size: 13px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
  color: #373B4D;
}

/* Hover: ONE clean effect — subtle brightness lift. No multi-tone. */
body.paper-mode .ufs-seg:hover {
  filter: brightness(1.08) saturate(1.04);
}
body.paper-mode .ufs-seg:active {
  transform: translateY(1px);
}
body.paper-mode .ufs-seg:focus-visible {
  outline: 2px solid #FFD700;
  outline-offset: 2px;
  z-index: 2;
}
/* ── Active segment: downward caret extruding into the dropdown ────
   A pure-CSS triangle (border trick) grows from scaleY(0) to scaleY(1)
   with a gentle back-ease when a segment is opened, creating the
   visual bridge between the bar and the dropdown container. The
   per-category ::after color matches the segment's background hex so
   the caret reads as a continuation of the segment itself. */
body.paper-mode .ufs-seg.is-active::after {
  content: '';
  position: absolute;
  bottom: -10px;
  left: 50%;
  width: 0; height: 0;
  border-left: 10px solid transparent;
  border-right: 10px solid transparent;
  border-top: 11px solid #2C2A28;   /* overridden per-category below */
  pointer-events: none;
  z-index: 2;
  transform-origin: top center;
  transform: translateX(-50%) scaleY(0);
  opacity: 0;
  animation: ufsCaretGrow 260ms cubic-bezier(0.34, 1.45, 0.64, 1) 40ms forwards;
  /* Subtle drop shadow to separate from the panel below */
  filter: drop-shadow(0 1px 0.5px rgba(44, 42, 40, 0.18));
}
body.paper-mode .ufs-seg--cogs.is-active::after   { border-top-color: #FF5B5B; }
body.paper-mode .ufs-seg--ovhd.is-active::after   { border-top-color: #FF8A1F; }
body.paper-mode .ufs-seg--profit.is-active::after { border-top-color: #2ECC71; }
@keyframes ufsCaretGrow {
  from { transform: translateX(-50%) scaleY(0); opacity: 0; }
  to   { transform: translateX(-50%) scaleY(1); opacity: 1; }
}
body.paper-mode .ufs-seg.is-active {
  filter: brightness(1.06) saturate(1.05);
  z-index: 1;
}

/* ── Dim siblings when one segment is active ───────────────────────
   When the card has an active category, all OTHER segments fade hard
   so the user's eye is magnetized to the chosen one. We stack THREE
   effects (opacity + desaturation + brightness cut) so the dim reads
   unmistakably — a single opacity change alone can get lost on
   vibrant fills. !important because .ufs-seg:hover above and the
   .ufs-seg.is-active filter rule both target the same property and
   can override in certain orderings. */
body.paper-mode .ufs-card.is-active--cogs   .ufs-seg:not(.ufs-seg--cogs),
body.paper-mode .ufs-card.is-active--ovhd   .ufs-seg:not(.ufs-seg--ovhd),
body.paper-mode .ufs-card.is-active--profit .ufs-seg:not(.ufs-seg--profit) {
  opacity: 0.22 !important;
  filter: saturate(0.35) brightness(0.95) !important;
}
body.paper-mode .ufs-card.is-active--cogs   .ufs-seg:not(.ufs-seg--cogs):hover,
body.paper-mode .ufs-card.is-active--ovhd   .ufs-seg:not(.ufs-seg--ovhd):hover,
body.paper-mode .ufs-card.is-active--profit .ufs-seg:not(.ufs-seg--profit):hover {
  /* Raise dimmed siblings on hover so they remain discoverable */
  opacity: 0.60 !important;
  filter: saturate(0.75) brightness(1.0) !important;
}

/* ── V5: Target Goal vs Actual readout ───────────────────────────
   Lives at the very top of the COGS and Profit dropdown panels
   (just below the funnel, above the rainbow sub-bar). Injected
   by ufsCloneZoomPanels() for any panel that carries a
   data-target-goal attribute. Overhead has no published goal so
   no readout is injected there. Typography is technical/mono to
   match the rest of the card's structured feel. */
body.paper-mode .ufs-target-readout {
  display: flex;
  align-items: baseline;
  justify-content: center;
  flex-wrap: wrap;
  gap: 10px 14px;
  padding: 14px 18px;
  margin: 0 0 16px;
  border-radius: 10px;
  background: rgba(44, 42, 40, 0.035);
  border: 1px solid rgba(44, 42, 40, 0.08);
  font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, monospace;
  font-variant-numeric: tabular-nums;
  color: #373B4D;
}
body.paper-mode .ufs-target-readout-lbl {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #6B655C;
}
body.paper-mode .ufs-target-readout-val {
  font-size: 16px;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: #373B4D;
}
body.paper-mode .ufs-target-readout-sep {
  font-size: 14px;
  font-weight: 400;
  color: rgba(44, 42, 40, 0.22);
  padding: 0 2px;
}
/* Per-category accent — tints the Actual number so the active
   category color is echoed in the readout. */
body.paper-mode .ufs-zoom--cogs   .ufs-target-readout-val:last-of-type { color: #B83E3E; }
body.paper-mode .ufs-zoom--profit .ufs-target-readout-val:last-of-type { color: #1E8749; }
/* V6 bug fix: the readout's left border is driven by the PARENT
   panel's category class, NOT by whether we hit the goal. So COGS
   always reads as coral, Profit always reads as green — matching
   the tint of the segment the user clicked on the main bar. */
body.paper-mode .ufs-zoom--cogs   .ufs-target-readout { border-left: 3px solid #FF5B5B; }
body.paper-mode .ufs-zoom--profit .ufs-target-readout { border-left: 3px solid #2ECC71; }

/* ── 3. Accordion panels ───────────────────────────────────────── */
/* ── Cloned zoom-panel dropdowns ──────────────────────────────────
   Each .ufs-zoom panel is a clone of the corresponding mf-card zoom
   panel (mfZoomDetail output for COGS/Overhead; noiDetailHtml "What
   is Profit?" explainer for Profit). All inner styling (bars,
   legends, gauge, etc.) is inherited from the existing .mf-zoom-detail
   / .mf-noi-detail rules — we only need to handle positioning +
   spacing inside the UFS card shell. */
/* ── V6: Ink-Wash Connection ──────────────────────────────────────
   Replaces the SVG trapezoid funnel with a pure-CSS treatment that
   reads like a highlighter wash bleeding down from the active
   segment. Three layers combine to prove the connection without any
   geometry computation:
     1) Caret ::before — an upward-pointing triangle on the dropdown
        that points at whichever segment the user clicked. Colored
        per active category so it visually "extrudes" from that
        segment's color.
     2) Sheer bg wash — 5–7% of the active color tints the entire
        panel surface, so the dropdown reads as a faint colored paper
        rather than a neutral grey box.
     3) Category-colored glow — box-shadow with the active color at
        low alpha, giving the panel a soft "printed ink" halo that
        bleeds outward and connects visually to the segment above. */
body.paper-mode .ufs-zoom {
  position: relative;
  margin-top: 22px;            /* room for the caret to live above */
  padding: 22px 22px 10px;
  border-radius: 14px;
  background: transparent;
  transition: background-color 280ms cubic-bezier(0.4, 0, 0.2, 1),
              box-shadow       360ms cubic-bezier(0.4, 0, 0.2, 1),
              border-color     280ms cubic-bezier(0.4, 0, 0.2, 1);
  border: 1px solid transparent;
}

/* Caret triangle — sits above the panel, flush with its top edge,
   pointing up at the main bar. `clip-path` instead of the border hack
   so the triangle scales cleanly with its container and we can drive
   its color via background-color on the same element. Bigger than V6
   v1 (28×14 vs 22×11) so the pointer reads unambiguously as a
   connector, not decoration. Drop-shadow makes it pop off the paper. */
body.paper-mode .ufs-zoom::before {
  content: '';
  position: absolute;
  left: 0; right: 0;
  top: -13px;
  margin: 0 auto;
  width: 28px;
  height: 14px;
  clip-path: polygon(50% 0, 100% 100%, 0 100%);
  background: transparent;
  transition: background-color 260ms cubic-bezier(0.4, 0, 0.2, 1),
              filter            260ms cubic-bezier(0.4, 0, 0.2, 1);
  pointer-events: none;
  z-index: 3;
}

/* Active-state glow / border / caret per category. The panel
   background stays neutral paper — NO color wash over the top — so
   the Tech Labor / Parts / Subcontractors rows read cleanly. The
   visual connection is carried entirely by three EXTERIOR cues:
     1) Outer glow (box-shadow) in the category hue, bleeding outward
     2) A 1px border in the category hue so the panel edge reads tinted
     3) The upward caret pointing at the active segment
   No inset shadows, no background-color fill. The cloned panel
   internals (rainbow sub-bar, pastel row tints) come through unmuddied. */
/* Thinner rim-glow. Previous values (44px spread at 0.32 alpha)
   bled ~50px outside the panel and read as an overwhelming flood.
   Halved the spread (44→14px) AND the alpha (0.32→0.15) so the
   halo now hugs the panel's edge as a restrained rim light —
   still enough to signal "this panel belongs to the active
   category" without swallowing the screen real estate around it. */
body.paper-mode .ufs-card.is-active--cogs   .ufs-zoom--cogs {
  border-color: rgba(255, 91, 91, 0.42);
  box-shadow: 0 4px 14px rgba(255, 91, 91, 0.15),
              0 1px 3px  rgba(255, 91, 91, 0.10);
}
body.paper-mode .ufs-card.is-active--cogs   .ufs-zoom--cogs::before {
  background-color: #FF5B5B;
  filter: drop-shadow(0 1px 2px rgba(255, 91, 91, 0.35));
}
body.paper-mode .ufs-card.is-active--ovhd   .ufs-zoom--ovhd {
  border-color: rgba(255, 138, 31, 0.45);
  box-shadow: 0 4px 14px rgba(255, 138, 31, 0.16),
              0 1px 3px  rgba(255, 138, 31, 0.11);
}
body.paper-mode .ufs-card.is-active--ovhd   .ufs-zoom--ovhd::before {
  background-color: #FF8A1F;
  filter: drop-shadow(0 1px 2px rgba(255, 138, 31, 0.38));
}
body.paper-mode .ufs-card.is-active--profit .ufs-zoom--profit {
  border-color: rgba(46, 204, 113, 0.45);
  box-shadow: 0 4px 14px rgba(46, 204, 113, 0.16),
              0 1px 3px  rgba(46, 204, 113, 0.11);
}
body.paper-mode .ufs-card.is-active--profit .ufs-zoom--profit::before {
  background-color: #2ECC71;
  filter: drop-shadow(0 1px 2px rgba(46, 204, 113, 0.38));
}

/* Keep closed-panel collapse behavior identical to V5 — the ink-wash
   only engages on the currently-open panel, everything else is
   neutral + height-collapsed. */
body.paper-mode .ufs-zoom[hidden] { display: none; }
body.paper-mode .ufs-zoom:not(.is-open):not([hidden]) {
  max-height: 0;
  overflow: hidden;
  padding-top: 0;
  margin-top: 0;
  background: transparent;
  box-shadow: none;
}

/* ── Cloned-panel styling inside .ufs-zoom ─────────────────────────
   Per spec: the dropdown keeps the "fun, multi-colored, segmented
   horizontal breakdown bar" AND the "distinct colored backgrounds
   for each individual list row" from the original mf-card design.
   Row left-edge stripes match the SPECIFIC rainbow color of their
   corresponding bar segment (NOT the parent category) — done at
   clone time by ufsCloneZoomPanels() which only bumps the border
   width from 3px → 4px, preserving the original color. */

/* (a) Section label tinted to the active category */
body.paper-mode .ufs-zoom--cogs   .mf-zoom-conn-label { color: #B83E3E; }
body.paper-mode .ufs-zoom--ovhd   .mf-zoom-conn-label { color: #C76810; }
body.paper-mode .ufs-zoom--profit .mf-zoom-conn-label { color: #1E8749; }

/* (b) Row breathing room under the thicker 4px stripe */
body.paper-mode .ufs-zoom .mf-zoom-leg-row {
  padding-left: 12px;
}

/* (c) Sub-bar pct labels — off-white paper color (NOT pure white)
   so the labels stay legible on every rainbow color in the bar
   without violating the "no pure white text" rule. A faint dark
   text-shadow gives extra contrast on lighter yellows + pinks. */
body.paper-mode .ufs-zoom .mf-zoom-seg-pct {
  color: #FAF0D5;
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.18);
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: 0.2px;
  padding: 0 3px;
}

/* ── Mobile ────────────────────────────────────────────────────── */
@media (max-width: 768px) {
  body.paper-mode .ufs-card {
    padding: 16px 14px 14px;
    margin-top: 14px;
  }
  body.paper-mode .ufs-card {
    padding: 22px 18px 18px;
    margin-bottom: 28px;
  }
  body.paper-mode .ufs-main-header {
    gap: 6px;
    padding-bottom: 18px;
    margin-bottom: 16px;
  }
  body.paper-mode .ufs-main-eyebrow { font-size: 9.5px; letter-spacing: 0.22em; }
  body.paper-mode .ufs-main-value   { font-size: 34px; }
  body.paper-mode .ufs-amounts    { margin-bottom: 6px; }
  body.paper-mode .ufs-amount     { font-size: 13px; padding: 0 4px; }
  body.paper-mode .ufs-bar     { height: 64px; min-height: 64px; }
  body.paper-mode .ufs-bar-wrap { padding: 6px 0 30px; }
  body.paper-mode .ufs-bar-wrap::before { height: 64px; }
  body.paper-mode .ufs-seg     { padding: 0 8px; }
  body.paper-mode .ufs-seg-label { font-size: 12.5px; }
  body.paper-mode .ufs-seg-pct   { font-size: 11px; }
  /* V5: .ufs-target / .ufs-target-lbl no longer exist on the main bar. */
  body.paper-mode .ufs-target-readout { padding: 10px 12px; gap: 6px 10px; }
  body.paper-mode .ufs-target-readout-lbl { font-size: 9.5px; letter-spacing: 0.14em; }
  body.paper-mode .ufs-target-readout-val { font-size: 14px; }
  body.paper-mode .ufs-header-title  { font-size: 15px; }
  body.paper-mode .ufs-header-period { font-size: 12.5px; }
  body.paper-mode .ufs-zoom      { margin-top: 14px; padding: 14px 14px 4px; }
  body.paper-mode .ufs-zoom::before { top: -8px; width: 18px; height: 9px; }
}

/* Reduced motion — instant expand/collapse + skip entrance animations.
   Cardstock placement, ink fill, and amount rise all freeze at their
   100% keyframe so the final layout is reached instantly without any
   motion. */
@media (prefers-reduced-motion: reduce) {
  body.paper-mode .ufs-seg    { transition: none !important; }
  body.paper-mode .ufs-card,
  body.paper-mode .ufs-seg,
  body.paper-mode .ufs-amount { animation: none !important; }
}

/* ════════════════════════════════════════════════════════════════
   Education card — 4-tab interactive profit-lever simulator
   Sits beneath the UFS card, hidden by default behind a "Learn
   More" toggle button. Visual language mirrors the UFS card so the
   two read as a matched pair: same coral/orange/green palette for
   COGS/Overhead/Profit, same paper-card shell, same Inter body
   type, same Oxford/Hunter ink accents, same ink-wash callouts.
   ════════════════════════════════════════════════════════════════ */

/* ── Toggle button ───────────────────────────────────────────── */
body.paper-mode .edu-toggle-row {
  margin: -32px 0 20px;          /* pull up against the UFS card's bottom margin */
  display: flex;
  justify-content: center;
}
body.paper-mode .edu-toggle-btn {
  display: inline-flex;
  align-items: baseline;
  gap: 10px;
  padding: 12px 22px;
  background: var(--paper-card, #F7F6F2);
  border: 1px dashed rgba(92, 84, 72, 0.32);
  border-radius: 999px;
  font-family: inherit;
  font-size: 14px;
  color: #373B4D;
  cursor: pointer;
  transition: background-color 160ms ease, border-color 160ms ease, transform 120ms ease;
  box-shadow: 0 1px 2px rgba(44, 42, 40, 0.04);
}
body.paper-mode .edu-toggle-btn:hover {
  background: #FAF8F3;
  border-color: rgba(92, 84, 72, 0.50);
}
body.paper-mode .edu-toggle-btn:active {
  transform: translateY(1px);
}
body.paper-mode .edu-toggle-btn.is-open {
  border-style: solid;
  border-color: rgba(243, 138, 63, 0.50);
  background: rgba(243, 138, 63, 0.06);
}
body.paper-mode .edu-toggle-icon {
  font-size: 14px;
  font-weight: 800;
  color: var(--brand-orange-soft, #E88140);
  line-height: 1;
  position: relative;
  top: 1px;
}
body.paper-mode .edu-toggle-lbl {
  font-weight: 700;
  letter-spacing: 0.01em;
}
body.paper-mode .edu-toggle-sub {
  color: var(--brand-ink-muted, #6B7280);
  font-size: 12.5px;
  font-weight: 500;
}

/* ── Card shell ──────────────────────────────────────────────── */
body.paper-mode .edu-card {
  background: var(--paper-card, #F7F6F2);
  border: 1px solid rgba(92, 84, 72, 0.14);
  border-radius: 16px;
  padding: 28px 32px;
  margin-bottom: 48px;
  font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  color: #373B4D;
  box-shadow:
    0 1px 1px rgba(44, 42, 40, 0.04),
    0 2px 10px rgba(44, 42, 40, 0.04);
  /* Expand/collapse: start height:0 + opacity:0, animate to full
     when .edu-open is applied (JS handles the class flip). Using
     max-height rather than height:auto so the transition works;
     ceiling is generous enough for all 4 tabs' content. */
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  padding-top: 0;
  padding-bottom: 0;
  transition: max-height 360ms cubic-bezier(0.2, 0.8, 0.2, 1),
              opacity    280ms ease-out,
              padding    320ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
body.paper-mode .edu-card.edu-open {
  max-height: 4000px;
  opacity: 1;
  padding-top: 28px;
  padding-bottom: 28px;
}

/* ── Header + title ──────────────────────────────────────────── */
body.paper-mode .edu-hdr {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding-bottom: 14px;
  margin-bottom: 18px;
  border-bottom: 1px solid rgba(92, 84, 72, 0.14);
  flex-wrap: wrap;
}
body.paper-mode .edu-title {
  font-size: 18px;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: #373B4D;
}
body.paper-mode .edu-subtitle {
  font-size: 13px;
  font-weight: 500;
  color: var(--brand-ink-muted, #6B7280);
}

/* ── Tab bar ─────────────────────────────────────────────────── */
/* Folder-style tabs — each tab is a top-rounded chip with its own
   subtle fill; the active tab uses the paper card's own background,
   erases its bottom border, and appears to "attach" to the panel
   below. The row's bottom border acts as the spine that inactive
   tabs sit above and the active tab breaks through. */
body.paper-mode .edu-tabs {
  display: flex;
  gap: 3px;
  margin-bottom: 20px;
  border-bottom: 1.5px solid rgba(92, 84, 72, 0.22);
  flex-wrap: wrap;
  padding-left: 2px;
}
body.paper-mode .edu-tab {
  font-family: inherit;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--brand-ink-muted, #6B7280);
  background: rgba(92, 84, 72, 0.06);
  border: 1.5px solid rgba(92, 84, 72, 0.18);
  border-bottom: none;
  border-radius: 8px 8px 0 0;
  padding: 10px 18px;
  margin-bottom: -1.5px;
  cursor: pointer;
  transition: color 160ms ease, background 160ms ease, border-color 160ms ease;
  letter-spacing: 0.01em;
  position: relative;
  top: 2px;               /* inactive tabs sit slightly lower, like folder tabs */
}
body.paper-mode .edu-tab:hover {
  color: #373B4D;
  background: rgba(92, 84, 72, 0.10);
}
body.paper-mode .edu-tab.is-active {
  color: #373B4D;
  font-weight: 700;
  background: var(--paper-card, #FBFAF6);
  border-color: rgba(92, 84, 72, 0.22);
  /* Paint the active tab's bottom-edge in the card color so it erases
     the row's bottom border where the tab meets the panel — classic
     "tab attached to content" folder trick. */
  box-shadow: 0 1.5px 0 0 var(--paper-card, #FBFAF6);
  top: 0;                  /* active tab rises flush with the spine */
  z-index: 1;
}
/* Accent strip on the active tab — a slim orange underline under the
   label, inside the tab, that reinforces which one is picked without
   clashing with the folder silhouette. */
body.paper-mode .edu-tab.is-active::after {
  content: '';
  position: absolute;
  left: 12px;
  right: 12px;
  bottom: 6px;
  height: 2px;
  background: var(--brand-orange-soft, #E88140);
  border-radius: 1px;
}

/* ── Panels ──────────────────────────────────────────────────── */
body.paper-mode .edu-panel[hidden] { display: none; }
body.paper-mode .edu-panel.is-open { display: block; }

/* ── Lead paragraphs ─────────────────────────────────────────── */
body.paper-mode .edu-lead {
  font-size: 14.5px;
  line-height: 1.65;
  color: #4A4E5F;
  margin: 0 0 18px;
}
body.paper-mode .edu-lead b {
  color: #373B4D;
  font-weight: 700;
}

/* ── Formula row (Tab 1) ─────────────────────────────────────── */
body.paper-mode .edu-formula {
  display: flex;
  align-items: stretch;
  gap: 10px;
  margin: 0 0 22px;
  flex-wrap: wrap;
}
body.paper-mode .edu-fp {
  flex: 1;
  min-width: 120px;
  background: var(--paper-bg, #F4F3EF);
  border: 1px solid rgba(92, 84, 72, 0.12);
  border-radius: 10px;
  padding: 14px 18px;
  text-align: center;
}
body.paper-mode .edu-fp-l {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--brand-ink-muted, #6B7280);
  margin-bottom: 5px;
}
body.paper-mode .edu-fp-v {
  font-size: 22px;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: #373B4D;
  font-variant-numeric: tabular-nums;
}
body.paper-mode .edu-fp--cogs .edu-fp-l { color: #B83E3E; }
body.paper-mode .edu-fp--gp {
  background: rgba(46, 204, 113, 0.08);
  border-color: rgba(46, 204, 113, 0.28);
}
body.paper-mode .edu-fp--gp .edu-fp-l { color: #1E8749; }
body.paper-mode .edu-fp--gp .edu-fp-v { color: #13532E; }
body.paper-mode .edu-fop {
  display: flex;
  align-items: center;
  font-size: 22px;
  font-weight: 600;
  color: var(--brand-ink-muted, #6B7280);
  padding: 0 4px;
}

/* ── Slider + readout ────────────────────────────────────────── */
body.paper-mode .edu-ctrl {
  margin: 0 0 18px;
}
body.paper-mode .edu-ctrl-row {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 10px;
  flex-wrap: wrap;
}
body.paper-mode .edu-ctrl-lbl {
  flex: 0 0 160px;
  font-size: 13.5px;
  font-weight: 600;
  color: #4A4E5F;
}
body.paper-mode .edu-slider {
  flex: 1;
  min-width: 140px;
  -webkit-appearance: none;
  appearance: none;
  height: 4px;
  background: rgba(55, 59, 77, 0.14);
  border-radius: 2px;
  outline: none;
  cursor: pointer;
}
body.paper-mode .edu-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--brand-orange-soft, #E88140);
  border: 2px solid #FFFFFF;
  box-shadow: 0 1px 3px rgba(44, 42, 40, 0.22);
  cursor: grab;
  transition: transform 120ms ease;
}
body.paper-mode .edu-slider::-moz-range-thumb {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--brand-orange-soft, #E88140);
  border: 2px solid #FFFFFF;
  box-shadow: 0 1px 3px rgba(44, 42, 40, 0.22);
  cursor: grab;
}
body.paper-mode .edu-slider:active::-webkit-slider-thumb { transform: scale(1.12); cursor: grabbing; }
body.paper-mode .edu-ctrl-val {
  min-width: 68px;
  text-align: right;
  font-size: 15px;
  font-weight: 800;
  color: #373B4D;
  font-variant-numeric: tabular-nums;
}

/* Preset chips */
body.paper-mode .edu-presets {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin-left: 174px;   /* aligns with slider start on wide layout */
}
body.paper-mode .edu-preset {
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  padding: 5px 11px;
  border-radius: 999px;
  border: 1px solid rgba(92, 84, 72, 0.20);
  background: transparent;
  color: var(--brand-ink-muted, #6B7280);
  cursor: pointer;
  transition: background-color 140ms ease, color 140ms ease, border-color 140ms ease;
  font-variant-numeric: tabular-nums;
}
body.paper-mode .edu-preset:hover {
  background: rgba(243, 138, 63, 0.08);
  border-color: rgba(243, 138, 63, 0.40);
  color: #373B4D;
}
body.paper-mode .edu-preset:active { transform: translateY(1px); }

/* ── Bar row (before/after stacked-segment bars) ─────────────── */
body.paper-mode .edu-bar-row {
  margin-bottom: 14px;
}
body.paper-mode .edu-bar-lbl {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--brand-ink-muted, #6B7280);
  margin-bottom: 7px;
  font-variant-numeric: tabular-nums;
}
body.paper-mode .edu-bar-outer {
  width: 100%;
}
body.paper-mode .edu-bar-outer--dynamic {
  /* Tab 4 only — the After bar's outer width grows with revenue. */
  transition: width 0.28s cubic-bezier(0.2, 0.8, 0.2, 1);
}

/* ── Gross-profit bracket (Tab 1 only) ──────────────────────────
   A blue horizontal bar sitting ABOVE the main stacked bar. Its
   `left` edge tracks the COGS segment's right edge, so its width
   always equals the combined Overhead + Profit portion — which is
   exactly what Gross Profit represents ("what's left of every
   revenue dollar after COGS"). Two small down-legs at the corners
   give it a literal bracket look that visually "grabs" the two
   segments below it. */
body.paper-mode .edu-bar-bracket-wrap {
  position: relative;
}
/* The bracket row is a flex container that MIRRORS the bar below
   it: same gap, per-item min-widths matching the segments they span,
   and flex values driven by the same math. That guarantees pixel-
   perfect alignment of the bracket's edges with the Overhead and
   Profit segments — no percentage math, no JS measurement. */
body.paper-mode .edu-bracket-row {
  display: flex;
  gap: 3px;               /* matches .edu-bar gap exactly */
  margin-bottom: 6px;     /* room for the bracket's down-legs */
  position: relative;
}
body.paper-mode .edu-bracket-spacer {
  min-width: 52px;        /* matches .edu-seg min-width */
  visibility: hidden;
  pointer-events: none;
}
body.paper-mode .edu-bracket {
  /* min-width covers ovhd's 52 + gap 3 + profit's 52, so even when
     profit goes negative (clamped flex 0.1) the bracket can't shrink
     below the actual rendered Overhead + Profit span below it. */
  min-width: 107px;
  height: 30px;
  background: rgba(0, 33, 71, 0.18);         /* stronger Oxford-blue wash — reads as blue */
  border: 1.5px solid #002147;                /* solid Oxford Blue border */
  border-bottom: none;                        /* legs continue downward via ::before/::after */
  border-radius: 6px 6px 0 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 12px;
  box-sizing: border-box;
  pointer-events: none;
  position: relative;                          /* anchor for down-legs */
  transition: flex 0.28s cubic-bezier(0.2, 0.8, 0.2, 1);   /* match bar seg transition */
}
/* Down-legs — the vertical ticks that hang toward the bar, making
   the element read as a bracket rather than a floating plaque. */
body.paper-mode .edu-bracket::before,
body.paper-mode .edu-bracket::after {
  content: '';
  position: absolute;
  top: 100%;
  width: 1.5px;
  height: 6px;
  background: #002147;
}
body.paper-mode .edu-bracket::before { left:  -1.5px; }
body.paper-mode .edu-bracket::after  { right: -1.5px; }
body.paper-mode .edu-bracket-lbl {
  font-size: 12px;
  font-weight: 700;
  color: #002147;                             /* Oxford Blue ink */
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
body.paper-mode .edu-bracket-lbl span {
  font-weight: 800;
}
body.paper-mode .edu-bar {
  display: flex;
  height: 52px;
  border-radius: 10px;
  overflow: hidden;
  gap: 3px;
  background: transparent;
}
body.paper-mode .edu-seg {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 0 8px;
  font-size: 13px;
  font-weight: 700;
  color: #373B4D;
  transition: flex 0.28s cubic-bezier(0.2, 0.8, 0.2, 1);
  min-width: 52px;
  white-space: nowrap;
}
body.paper-mode .edu-seg-sub {
  font-size: 11.5px;
  font-weight: 600;
  margin-top: 2px;
  font-variant-numeric: tabular-nums;
  opacity: 0.85;
}
body.paper-mode .edu-seg--cogs   { background: #FF5B5B; }
body.paper-mode .edu-seg--ovhd   { background: #FF8A1F; }
body.paper-mode .edu-seg--profit { background: #2ECC71; }
/* Negative profit — paint red so the visual matches the math.
   Green + minus-sign reads as contradictory; red + minus reads as
   "you're underwater." Slightly deeper than cogs red to distinguish. */
body.paper-mode .edu-seg--profit.is-negative { background: #C0392B; }

/* Segment shape — first + last get outer rounding so 3-segment bars
   read as one unit with paper gaps between pieces. */
body.paper-mode .edu-bar > .edu-seg:first-child { border-radius: 10px 2px 2px 10px; }
body.paper-mode .edu-bar > .edu-seg:last-child  { border-radius: 2px 10px 10px 2px; }
body.paper-mode .edu-bar > .edu-seg:only-child  { border-radius: 10px; }

/* ── Metric tiles ────────────────────────────────────────────── */
body.paper-mode .edu-metrics {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 10px;
  margin: 18px 0;
}
body.paper-mode .edu-m {
  background: var(--paper-bg, #F4F3EF);
  border: 1px solid rgba(92, 84, 72, 0.10);
  border-radius: 10px;
  padding: 14px 16px;
}
body.paper-mode .edu-m-lbl {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--brand-ink-muted, #6B7280);
  margin-bottom: 6px;
}
body.paper-mode .edu-m-val {
  font-size: 22px;
  font-weight: 800;
  color: #373B4D;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
  line-height: 1.15;
}
body.paper-mode .edu-m-sub {
  font-size: 12px;
  font-weight: 600;
  color: #1E8749;              /* positive green by default */
  margin-top: 4px;
  font-variant-numeric: tabular-nums;
}
body.paper-mode .edu-m-sub--muted { color: var(--brand-ink-muted, #6B7280); }
body.paper-mode .edu-m-sub.is-negative { color: #B83E3E; }

/* ── Insight callout (bottom of each panel) ──────────────────── */
body.paper-mode .edu-insight {
  background: rgba(0, 33, 71, 0.05);
  border-left: 3px solid rgba(0, 33, 71, 0.45);
  border-radius: 8px;
  padding: 14px 18px;
  font-size: 13.5px;
  line-height: 1.65;
  color: #1D2B52;
  margin-top: 18px;
}
body.paper-mode .edu-insight b {
  font-weight: 700;
  color: #002147;
}

/* ═══════════════════════════════════════════════════════════════
   Education card — mobile optimization (≤768px)
   Rewritten from the previous bare-minimum mobile block. Five
   structural problems get addressed here:
     1) Tab bar wraps to 2 rows on phones (4 long labels won't fit)
        → horizontal scroll with scroll-snap + hidden scrollbar.
     2) Formula row (Revenue − COGS = Gross Profit) wraps its 3
        pills + 2 operators awkwardly → stack vertically with
        operators centered between rows. Each pill flips label/value
        to a left/right row inside so height stays tight.
     3) Metric tiles use `auto-fit, minmax(160px, 1fr)` which yields
        2-col on phones → 3 tiles render as 2+1 (awkward).
        → force 1-col on narrow phones, keep 2-col on medium phones
          via a nested (min-width: 481px) media query.
     4) Gross-profit bracket label "Gross profit: $129K" overflows
        when the bracket is narrow (low gross margin). Shrink font +
        let ellipsis clip rather than wrap.
     5) Sliders: label shown ABOVE track on its own row (full-width)
        so the slider + readout get full-width real estate below.
   ═══════════════════════════════════════════════════════════════ */
@media (max-width: 768px) {
  /* Toggle button + card shell */
  body.paper-mode .edu-toggle-row  { margin: -22px 0 16px; }
  body.paper-mode .edu-toggle-btn  { padding: 10px 18px; font-size: 13.5px; gap: 8px; }
  body.paper-mode .edu-toggle-sub  { display: none; }          /* tagline too chatty on phones */
  body.paper-mode .edu-card        { padding: 0 16px; margin-bottom: 28px; }
  body.paper-mode .edu-card.edu-open {
    padding-top: 18px;
    padding-bottom: 18px;
  }

  /* Header — tighter */
  body.paper-mode .edu-hdr         { padding-bottom: 10px; margin-bottom: 14px; gap: 8px; }
  body.paper-mode .edu-title       { font-size: 16px; }
  body.paper-mode .edu-subtitle    { font-size: 11.5px; }

  /* Tab bar — horizontal scroll rather than wrap. scroll-snap so
     the tabs land cleanly when the user swipes between them. */
  body.paper-mode .edu-tabs {
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    -ms-overflow-style: none;
    overscroll-behavior-x: contain;
    scroll-snap-type: x proximity;
    margin-bottom: 14px;
  }
  body.paper-mode .edu-tabs::-webkit-scrollbar { display: none; }
  body.paper-mode .edu-tab {
    flex: 0 0 auto;
    font-size: 13px;
    padding: 10px 14px;
    white-space: nowrap;
    scroll-snap-align: start;
  }

  /* Lead paragraphs */
  body.paper-mode .edu-lead { font-size: 13.5px; line-height: 1.55; margin: 0 0 14px; }

  /* Formula row — stack vertically. Each pill becomes a compact
     row with label on the left, value on the right, so the vertical
     stack doesn't blow up the panel height. Operators (−, =) center
     between pill rows as their own centered line. */
  body.paper-mode .edu-formula {
    flex-direction: column;
    gap: 6px;
    margin: 0 0 18px;
  }
  body.paper-mode .edu-fp {
    min-width: 0;
    width: 100%;
    padding: 10px 14px;
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    text-align: left;
  }
  body.paper-mode .edu-fp-l { margin-bottom: 0; font-size: 10px; }
  body.paper-mode .edu-fp-v { font-size: 17px; }
  body.paper-mode .edu-fop {
    width: 100%;
    justify-content: center;
    padding: 0;
    font-size: 18px;
    line-height: 1;
    color: var(--brand-ink-muted, #6B7280);
  }

  /* Slider row — label takes its own full-width line above, slider
     + readout share the next line. Cleaner than cramming all three
     inline on a ~320px screen. */
  body.paper-mode .edu-ctrl        { margin: 0 0 16px; }
  body.paper-mode .edu-ctrl-row    { gap: 10px; margin-bottom: 10px; row-gap: 6px; }
  body.paper-mode .edu-ctrl-lbl    { flex: 1 1 100%; font-size: 12.5px; }
  /* Taller track + fatter thumb + a vertical tap buffer so the slider
     is an easy thumb target on mobile. Previous 18px thumb + 4px track
     was basically a sniper rifle — bump the thumb to 28px and add 10px
     of vertical padding via the wrapping row so the hit area clears the
     iOS 44pt guideline without changing the track's visual size much. */
  body.paper-mode .edu-slider      {
    flex: 1 1 auto;
    min-width: 0;
    height: 6px;                    /* was 4px */
    padding: 12px 0;                /* vertical tap buffer around the thin track */
    background-clip: content-box;   /* keeps the track's painted color in its 6px band */
    box-sizing: content-box;
    touch-action: pan-x;            /* grab dragging without page-scroll fights */
  }
  body.paper-mode .edu-slider::-webkit-slider-thumb {
    width: 28px;                    /* was 18px — easy thumb hit */
    height: 28px;
    border-width: 3px;              /* thicker white halo so it reads big */
    box-shadow: 0 1.5px 4px rgba(44, 42, 40, 0.28);
  }
  body.paper-mode .edu-slider::-moz-range-thumb {
    width: 28px;
    height: 28px;
    border-width: 3px;
    box-shadow: 0 1.5px 4px rgba(44, 42, 40, 0.28);
  }
  body.paper-mode .edu-ctrl-val    { font-size: 14.5px; min-width: 58px; }

  /* Preset chips — un-indent (desktop aligned them with slider start) */
  body.paper-mode .edu-presets     { margin-left: 0; gap: 6px; }
  body.paper-mode .edu-preset      { padding: 5px 11px; font-size: 11.5px; }

  /* Bars — slightly shorter + tighter. Reduced seg min-width so 3
     segments always fit the viewport; very-narrow profit slices
     still get their label visible. */
  body.paper-mode .edu-bar-row     { margin-bottom: 12px; }
  body.paper-mode .edu-bar-lbl     { font-size: 10.5px; letter-spacing: 0.12em; margin-bottom: 6px; }
  body.paper-mode .edu-bar         { height: 48px; gap: 2px; }
  body.paper-mode .edu-seg         { font-size: 11.5px; padding: 0 4px; min-width: 38px; }
  body.paper-mode .edu-seg-sub     { font-size: 10.5px; margin-top: 1px; }

  /* Gross-profit bracket (Tab 1) — shrink + clip. Mobile bar has
     2px gap and 38px seg min-width, so the bracket row must match:
     spacer min 38, bracket min 78 (= 38 + 2 + 38). */
  body.paper-mode .edu-bracket-row    { gap: 2px; margin-bottom: 5px; }
  body.paper-mode .edu-bracket-spacer { min-width: 38px; }
  body.paper-mode .edu-bracket        { min-width: 78px; height: 26px; padding: 0 8px; border-radius: 5px 5px 0 0; }
  body.paper-mode .edu-bracket-lbl    { font-size: 10.5px; }

  /* Tab 4 dynamic-width "After" bar — slight override so the
     growing bar transitions remain smooth even on mobile. */
  body.paper-mode .edu-bar-outer--dynamic { transition: width 0.3s cubic-bezier(0.2, 0.8, 0.2, 1); }

  /* Metric tiles — default to 1 column on phones so the 3rd tile
     never becomes an orphan row below a 2-wide first row. */
  body.paper-mode .edu-metrics     { grid-template-columns: 1fr; gap: 8px; margin: 16px 0; }
  body.paper-mode .edu-m           { padding: 11px 14px; }
  body.paper-mode .edu-m-lbl       { font-size: 10.5px; margin-bottom: 5px; }
  body.paper-mode .edu-m-val       { font-size: 19px; }
  body.paper-mode .edu-m-sub       { font-size: 11.5px; }

  /* Insight callout */
  body.paper-mode .edu-insight     { padding: 12px 14px; font-size: 12.5px; line-height: 1.55; margin-top: 16px; }
}

/* Medium-width phones / small tablets — upgrade metric grid to
   2 columns so the 3 tiles split 2+1 gracefully (same behavior
   auto-fit had, but here it's intentional rather than emergent). */
@media (min-width: 481px) and (max-width: 768px) {
  body.paper-mode .edu-metrics { grid-template-columns: repeat(2, 1fr); }
}

/* Reduced-motion: skip the expand/collapse transition. */
@media (prefers-reduced-motion: reduce) {
  body.paper-mode .edu-card,
  body.paper-mode .edu-bar-outer--dynamic,
  body.paper-mode .edu-seg { transition: none !important; }
}
