/* ============================================================================
   DFC Factory Hub — INDUSTRIAL MODERNIST SKIN
   ----------------------------------------------------------------------------
   A FINISH, NOT A REDESIGN. Loaded last, after theme.css and tokens.css, and it
   changes nothing but appearance: no markup, no structure, no copy, no layout
   reflow, no JavaScript. Every screen, route, chart, table, filter, form and
   selection state behaves exactly as it did.

   TO SWITCH BACK: delete the one <link> to this file in index.html. Nothing
   else in the app knows it exists.

   Direction: engineering drawing and control-room panel. Whitespace and 1px
   borders do the structuring; shadows and gradients do none of it.

   THE PALETTE IS THE REGISTERED ONE. Maestro Dark Green (#1B4332) is the single
   accent, kept for primary action and "good". Every other colour is a status
   meaning - pass, warning, fail, info - as a light fill with a dark text tone
   and a mid border. The one token moved is --color-bg, from the warm cream
   #f7f5ee to a neutral slate, because "neutral slate canvas" cannot be reached
   from a warm ground. Brand, status and text colours are untouched.
   ========================================================================== */

:root {
  /* Canvas: neutral, light, quiet. */
  --color-bg: #f4f5f7;

  /* Radii, per the spec: cards 12, inputs 8, buttons and nav rows 6, pills full.
     --radius / --radius-sm already drive most of the app, so setting them here
     carries the change to every control without touching a single call site. */
  --radius: 8px;
  --radius-sm: 6px;
  --radius-card: 12px;
  --radius-pill: 999px;

  /* Flat means flat. Anything reading a shadow token gets nothing. */
  --shadow: none;
  --shadow-sm: none;
  --shadow-lg: none;
  --elevation-1: none;
  --elevation-2: none;

  /* Hairlines. The lightest neutral is for gridlines and table rules only. */
  --rule: #e5e7eb;
  --rule-strong: #d1d5db;
  --rule-faint: #eef0f3;

  /* Status borders - the mid tone between the light fill and the dark text.
     Derived from the registered status hues; no new colours are introduced. */
  --status-success-border: #86c9a4;
  --status-warning-border: #e0b876;
  --status-danger-border:  #e6a3a3;
  --status-info-border:    #a8c2ef;

  /* One sans for the interface, one mono for anything you would read digit by
     digit. System mono rather than a web font: no extra request, and a control
     room should not wait on a CDN to render a number. */
  --font-ui: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas,
    'Liberation Mono', 'Courier New', monospace;

  --motion: 160ms;
}

/* ── Canvas and type ──────────────────────────────────────────────────────── */

body, .hub-main { background: var(--color-bg); }

body, button, input, select, textarea, .hub-main {
  font-family: var(--font-ui);
}

/* Body copy: 14/400. Set on the shell rather than with a universal selector so
   nothing that deliberately sizes itself is overridden. */
body, .hub-main { font-size: 14px; font-weight: 400; line-height: 1.5; }

/* Page title 24/600 with a touch of negative tracking; section heading 16/600.
   Sizes only - the heading levels each screen uses are unchanged. */
.hub-main h1, .screen-title, .page-title {
  font-size: 24px; font-weight: 600; letter-spacing: -0.01em; line-height: 1.25;
  color: var(--color-text);
}
.hub-main h2, .ac-head h2 {
  font-size: 16px; font-weight: 600; letter-spacing: -0.005em; color: var(--color-text);
}
.hub-main h3, .hub-main h4, .dash-card h4 {
  font-size: 14px; font-weight: 600; letter-spacing: 0; color: var(--color-text);
}

/* Tiny all-caps tracked labels: eyebrows, table headers, metadata. */
.dash-sub, .ac-band, .dfc-kpi-label, .ac-meta, .dash-bh-axis, .hub-eyebrow,
.dash-lg-pct, .dfc-kpi-sub, .ac-mine-h, .dash-legend .dash-lg-lbl {
  letter-spacing: .04em;
}
.dash-sub, .ac-band, .dfc-kpi-label, .ac-mine-h {
  text-transform: uppercase; font-size: 10.5px; font-weight: 600;
  letter-spacing: .07em; color: var(--color-muted);
}
table thead th, .access-tbl thead th, .dash-mx thead th {
  text-transform: uppercase; font-size: 10.5px; font-weight: 600;
  letter-spacing: .07em; color: var(--color-muted);
}

/* EVERY NUMBER, SCORE, ID AND CODE IN TABULAR MONO. Tabular so columns of
   figures line up digit over digit, which is the entire point of a register. */
.dfc-kpi-value, .ac-n, .dash-lg-val, .dash-lg-pct, .dash-bh-val, .dfc-kpi-delta,
.mono, code, kbd, samp, .hub-code, .ac-row-s, .dash-mx td, .dash-rings-leg em,
.dash-rings-leg b, .dash-rings-cap {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
}
/* Table cells that hold figures are right-aligned by the app already; that is
   the reliable signal that the cell is numeric. */
table td[style*="text-align:right"], table td[align="right"],
table th[style*="text-align:right"] {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

/* ── Surfaces: white, hairline, flat ──────────────────────────────────────── */

.dash-card, .card, .ac-tile, .ac-mine, .panel, .hub-panel, .dfc-kpi,
.ac-hidden, .ac-clear, .ac-fail {
  box-shadow: none !important;
  border-radius: var(--radius-card);
}
.dash-card, .card, .panel, .hub-panel {
  background: var(--color-surface);
  border: 1px solid var(--rule);
  padding: 16px;
}
.dash-grid { gap: 12px; }
.dash-grid, .dash-card { margin-bottom: 12px; }

/* The page gutter. 24px, and no more - density is part of the identity. */
.hub-main { padding: 24px; }

/* Anything that painted a resting shadow inline stops. !important is the point
   of this layer: it beats a style attribute without editing the template that
   wrote it, which is what keeps this change reversible. */
[style*="box-shadow"] { box-shadow: none !important; }

/* ── KPI tiles: the biggest single change, and the most careful ───────────── */
/* They were saturated gradient blocks with white text. Now they are cards like
   any other - but the colour they carried MEANT something, so it is kept as a
   3px left rule in the status tone rather than thrown away. The selectors match
   the fixed set of gradient strings _kpiGrad() emits, so no JS is touched. */
.dfc-kpi {
  background: var(--color-surface) !important;
  color: var(--color-text);
  border: 1px solid var(--rule);
  border-radius: var(--radius-card);
  padding: 14px 16px;
}
.dfc-kpi-value { color: var(--color-text); font-weight: 700; }
.dfc-kpi-sub   { color: var(--color-muted); }
/* THE EDGE CARRIES WHAT THE WASH USED TO. Each tile's accent is mapped onto the
   nearest registered status token and drawn as a 3px left rule, so a tile that
   read "bad" still reads bad - just without a saturated block behind it. The
   selectors match the inline background _kpiGrad() writes, which is why no
   JavaScript is touched and why removing this file restores the old look
   exactly. Every other tile gets a neutral rule, so the column still aligns. */
.dfc-kpi { border-left: 3px solid var(--rule-strong); }

/* fail */
.dfc-kpi[style*="#E05252"], .dfc-kpi[style*="#B5352A"], .dfc-kpi[style*="#C0392B"],
.dfc-kpi[style*="#c0392b"], .dfc-kpi[style*="#b91c1c"], .dfc-kpi[style*="#d32f2f"],
.dfc-kpi[style*="#8b2533"], .dfc-kpi[style*="#ef6b6b"], .dfc-kpi[style*="status-danger"] {
  border-left-color: var(--color-danger);
}
/* warning */
.dfc-kpi[style*="#C9821B"], .dfc-kpi[style*="#9A5B0C"], .dfc-kpi[style*="#E8992B"],
.dfc-kpi[style*="#E3A53C"], .dfc-kpi[style*="#b45309"], .dfc-kpi[style*="#d2871a"],
.dfc-kpi[style*="#f0a93c"], .dfc-kpi[style*="#C8871D"], .dfc-kpi[style*="status-warning"] {
  border-left-color: var(--color-warning);
}
/* pass */
.dfc-kpi[style*="#37A56C"], .dfc-kpi[style*="#2A8352"], .dfc-kpi[style*="#059669"],
.dfc-kpi[style*="#2D6A4F"], .dfc-kpi[style*="#2f8f5b"], .dfc-kpi[style*="#3fb878"],
.dfc-kpi[style*="#1a6b3f"], .dfc-kpi[style*="#166534"], .dfc-kpi[style*="status-success"] {
  border-left-color: var(--color-success);
}
/* info */
.dfc-kpi[style*="#2F72D6"], .dfc-kpi[style*="#1E56B4"], .dfc-kpi[style*="#1565C0"],
.dfc-kpi[style*="#3B82E0"], .dfc-kpi[style*="#2264c8"], .dfc-kpi[style*="#1587be"],
.dfc-kpi[style*="#1F4E79"], .dfc-kpi[style*="status-info"] {
  border-left-color: var(--color-info);
}
/* brand - the violets and teals the kit used for "no particular status" */
.dfc-kpi[style*="#8A4FD0"], .dfc-kpi[style*="#6B4AD4"], .dfc-kpi[style*="#6A1B9A"],
.dfc-kpi[style*="#6A4C93"], .dfc-kpi[style*="#9B5DE0"], .dfc-kpi[style*="#0E9A88"],
.dfc-kpi[style*="color-primary"] {
  border-left-color: var(--color-primary);
}

/* A tile that leads somewhere lifts by a border, not by a shadow. */
.dfc-kpi[data-kpigo], .dfc-kpi[data-tpmgo] {
  transition: border-color var(--motion) ease-out, background var(--motion) ease-out;
}
.dfc-kpi[data-kpigo]:hover, .dfc-kpi[data-tpmgo]:hover {
  transform: none !important;
  box-shadow: none !important;
  border-color: var(--color-border-strong);
  background: var(--rule-faint) !important;
}

/* ── Status: light fill, dark text, mid border ────────────────────────────── */

oh-pill, .oh-pill, .pill, .badge {
  border-radius: var(--radius-pill) !important;
  border: 1px solid var(--rule-strong);
  font-weight: 600;
  letter-spacing: .02em;
}
oh-pill[kind="success"], .oh-pill.success, .pill-success {
  background: var(--color-success-bg); color: var(--color-success);
  border-color: var(--status-success-border);
}
oh-pill[kind="warn"], oh-pill[kind="warning"], .oh-pill.warn, .pill-warn {
  background: var(--color-warning-bg); color: var(--color-warning);
  border-color: var(--status-warning-border);
}
oh-pill[kind="danger"], .oh-pill.danger, .pill-danger {
  background: var(--color-danger-bg); color: var(--color-danger);
  border-color: var(--status-danger-border);
}
oh-pill[kind="info"], .oh-pill.info, .pill-info {
  background: var(--color-info-bg); color: var(--color-info);
  border-color: var(--status-info-border);
}
oh-pill[kind="muted"], .oh-pill.muted {
  background: var(--rule-faint); color: var(--color-muted); border-color: var(--rule-strong);
}

/* The Action Centre's two groups keep their meaning; only the finish flattens. */
.ac-tile { background: var(--color-surface); border: 1px solid var(--rule); }
.ac-hidden, .ac-clear, .ac-fail { border: 1px solid var(--rule-strong); border-radius: var(--radius-card); }
.ac-clear { border-color: var(--status-success-border); }
.ac-fail  { border-color: var(--status-danger-border); }

/* ── Controls ─────────────────────────────────────────────────────────────── */

button, .btn, .btn-sm {
  border-radius: var(--radius-sm);
  font-weight: 500;
  transition: background var(--motion) ease-out, border-color var(--motion) ease-out,
              color var(--motion) ease-out;
  box-shadow: none !important;
}
/* Secondary: white, neutral border. The default for almost every button here. */
.btn-sm, button:not(.primary):not(.danger) {
  background: var(--color-surface);
  border: 1px solid var(--rule-strong);
  color: var(--color-text);
}
.btn-sm:hover, button:not(.primary):not(.danger):hover {
  background: var(--rule-faint);
  border-color: var(--color-border-input);
}
/* Primary: dark and semibold. The accent is spent here and on "good", nowhere else. */
button.primary, .btn.primary, .btn-sm.primary, .btn-primary {
  background: var(--color-primary);
  border: 1px solid var(--color-primary);
  color: var(--color-on-primary);
  font-weight: 600;
}
button.primary:hover, .btn.primary:hover, .btn-sm.primary:hover, .btn-primary:hover {
  /* A dark element goes one step LIGHTER on hover, not darker. */
  background: #235a43;
  border-color: #235a43;
}
button.danger, .btn-sm.danger {
  background: var(--color-danger-bg); color: var(--color-danger);
  border: 1px solid var(--status-danger-border); font-weight: 600;
}
button.danger:hover, .btn-sm.danger:hover { background: #fde8e8; }

input:not([type=checkbox]):not([type=radio]), select, textarea {
  border-radius: var(--radius);
  border: 1px solid var(--rule-strong);
  background: var(--color-surface);
  transition: border-color var(--motion) ease-out, background var(--motion) ease-out;
}
input:not([type=checkbox]):not([type=radio]):hover, select:hover, textarea:hover {
  border-color: var(--color-border-input);
}

/* A SHORT DROPDOWN STAYS NATIVE, AND MUST NOT READ AS A DIFFERENT CONTROL.
   hubCombo() only upgrades a select to .hub-combo-btn once it has COMBO_MIN (6) options; under
   that a plain select is quicker to use than a search box. But nothing ever gave the plain one the
   combo's type, so a filter bar holding both showed Substorage type, Empty locations and Rows at
   the browser's ~13.3px default beside Organization and Subinventory at 11px -- one row, two
   control designs, which is what "uneven fonts" looks like from the outside.

   Matched to .hub-combo-btn (--text-xs, 3px/8px) rather than moving the combo: the combo is what
   several hundred dropdowns in this app already are.

   The browser's own arrow is KEPT. html[data-theme="dark"] sets color-scheme:dark, so it is drawn
   in the right colour for the theme; a data-URI caret is a fixed hex and could not follow it.

   Deliberately NOT !important, so the coarse-pointer 16px rule in tokens.css still wins on a
   tablet. Deliberately a bare element selector, so .sst select.f, .acc-userpick select and the
   other module-scoped controls keep the sizing they set for themselves. [multiple] and [size] are
   list boxes rather than dropdowns and are left alone. */
select:not([multiple]):not([size]) {
  font-family: inherit;
  font-size: var(--text-xs);
  line-height: 1.35;
  padding: 3px 8px;
}

/* AND THE SAME FOR A BOX THE USER TYPES INTO. industrial.css gave an input its border and never
   its type, so an unstyled one kept Chrome's 13.33px -- which is how the Stock vs Demand item
   search ended up noticeably larger than every control beside it.
   --text-s, not --text-xs: 11px is right for a dense filter control somebody reads, and too small
   for a field somebody types in. tokens.css names --text-s as the default for exactly this.
   Inline font-size still wins (hundreds of sites set one), as does any module-scoped rule, and the
   coarse-pointer 16px override in tokens.css still beats this on a tablet. */
input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=color]):not([type=file]),
textarea {
  font-family: inherit;
  font-size: var(--text-s);
}

/* Focus: a 2px accent ring, on everything, always visible. */
:where(button, a, input, select, textarea, [tabindex], .hub-combo-btn, .ac-tile, .ac-row):focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
input:focus, select:focus, textarea:focus {
  outline: 2px solid var(--color-primary); outline-offset: -1px;
}

/* Nav rows: 6px, flat, tint on hover. */
.hub-nav a, .hub-nav button, .nav-row, .ac-row, .dash-act {
  border-radius: var(--radius-sm);
  transition: background var(--motion) ease-out;
}
.hub-nav a:hover, .nav-row:hover, .ac-row:hover, .dash-act:hover { background: var(--rule-faint); }

/* The combo panel is a control surface, not a popover with depth. */
.hub-combo-panel { box-shadow: none !important; border: 1px solid var(--rule-strong); border-radius: var(--radius); }
.hub-combo-btn { border-radius: var(--radius-sm); }
.hub-combo-opt { border-radius: 4px; }

/* ── Tables: hairline rules, dense ────────────────────────────────────────── */

table, .access-tbl { border-collapse: collapse; }
.access-tbl th, .access-tbl td, table.oee-tree th, table.oee-tree td {
  border-bottom: 1px solid var(--rule-faint);
}
.access-tbl thead th { border-bottom: 1px solid var(--rule-strong); background: var(--color-surface); }
.tbl-wrap { border-radius: var(--radius); border: 1px solid var(--rule); }

/* ── .tbl: the register table ──────────────────────────────────────────────
   Thirteen tables carry class="tbl" and NOTHING styled it, so their cells fell
   back to the browser's 1px default padding. Wherever two right-aligned numeric
   columns sat next to each other the figures simply touched: the payroll deck
   read 61189,209.663,101.80 where it meant 61 · 189,209.66 · 3,101.80, and the
   Runs table ran deductions into net as 35,222.75320,387.60. Two numbers with no
   gap are not a hard-to-read table, they are a wrong number.

   Padding is the fix. The rest is what makes a column of figures legible. */
table.tbl { width: 100%; border-collapse: collapse; }
table.tbl th, table.tbl td { padding: 8px 14px; vertical-align: middle; }
/* A header that wraps stops being a header — "Overtime %" over two lines reads
   as two columns. And a th defaults to centred, which left SECTION floating in
   the middle of a column of left-aligned section names; the numeric headers
   carry inline text-align:right and outrank this, so they keep their side. */
table.tbl thead th {
  white-space: nowrap; text-align: left;
  border-bottom: 1px solid var(--rule-strong);
}
table.tbl tbody th { text-align: left; }
table.tbl tbody td { border-bottom: 1px solid var(--rule-faint); }
table.tbl tbody tr:last-child td { border-bottom: 0; }
/* Right-aligned cells already get mono + tabular figures from the rule near the
   top of this file. This picks up the rest, so a date or a code in a text column
   also lines up down the rows. */
table.tbl td { font-variant-numeric: tabular-nums; font-feature-settings: 'tnum' 1; }
table.tbl tfoot td { border-top: 1px solid var(--rule-strong); }

/* ── Charts: same data, same axes, same behaviour - flat finish ───────────── */
/* Nothing here changes a value, a scale or a series. Fills lose their depth,
   gridlines drop to the lightest neutral, bar caps square off, and every tick
   label becomes tabular mono so figures read down a column. */

svg { filter: none !important; }
svg text { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
/* Chart TITLES and category names stay in the UI sans - only figures are mono. */
svg text.dash-title, svg .dash-cat text { font-family: var(--font-ui); }

/* Hairline gridlines, lightest neutral. */
svg line[stroke-dasharray], .dash-spc line, .dash-pareto line {
  stroke: var(--rule-faint) !important;
}
/* Square caps: a bar is a measurement, not a lozenge. rx/ry are geometry
   properties, so CSS can flatten them without touching the attribute. */
.dash-bv rect, .dash-bh rect, .dash-pareto rect, svg.dash-bars rect { rx: 0; ry: 0; }
.dash-bh-track, .dash-bh-fill, .dash-bh-stack { border-radius: 2px; }

/* Donut and ring arcs keep their colours - a wedge's colour is its identity and
   changing it would change what the chart says. Only the finish is flattened. */
svg.dash-donut circle, svg.dash-rings circle { filter: none; }

/* ── Motion: short, purposeful, and only where it was already ─────────────── */
/* This layer used to force animation-iteration-count:1 on every element, to
   honour "no looping motion". That was too blunt a reading. It did not only
   stop ornament - it stopped the helpbot avatar entirely (ten looping
   animations: sway, float, blink, wave, glow, dots), froze the news ticker
   after a single pass, and stopped the RECORDING pulse, which is the one cue
   telling someone their microphone is still live.

   A loop that carries state is not decoration. Nothing here loops for
   ornament, so the blanket rule is gone; reduced-motion is still honoured
   below, which is the setting that actually belongs to the user. */
.skeleton { animation: none !important; background: var(--rule-faint) !important; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 1ms !important; animation: none !important; }
}

/* ── Legibility: divider glyphs ───────────────────────────────────────────── */
/* A few screens separate inline stamps with a typed bar rather than a border,
   painted in the hairline colour. A hairline is right for a 1px rule and wrong
   for a glyph: at text weight it all but disappears. Lift those to the token
   the app already uses for de-emphasised text, so they stay quiet but legible
   and follow that token if it is ever retuned. */
[style*="color:var(--color-border)"] { color: var(--color-faint) !important; }

/* Nine inline captions across Traceability, Recall and Product Photos are painted
   with a one-off grey (#789) that predates the token system and sits outside the
   registered palette. Bring them onto the same de-emphasis token as every other
   caption: no layout change, and it removes the last off-palette colour in the UI. */
[style*="color:#789"] { color: var(--color-faint) !important; }

/* ── Inline white text on surfaces this layer lightened ───────────────────── */
/* The old design painted KPI tiles, Action Centre tiles, status pills and
   danger buttons as saturated blocks, and wrote the text on them white from
   the template, inline. This layer turns those blocks white - so that inline
   white became white on white. Invisible, and on the figures people open the
   screen to read (P&L month and YTD variance were the reported case).

   A style attribute beats a stylesheet, so the only way to reach it without
   editing the template is !important, scoped to exactly the surfaces that
   were lightened.

   inherit, not a fixed colour: a span inside .dfc-kpi-value picks up the value
   tone and one inside .dfc-kpi-sub picks up the muted tone, so the type tiers
   survive instead of collapsing to one weight.

   :not([style*="background"]) leaves alone any chip that paints its OWN dark
   background and therefore still needs white text. Elements that are still
   dark - primary buttons, the active tab, anything on --color-primary - are
   not matched by these selectors at all, and keep their white text. */
.dfc-kpi *[style*="color:#fff" i]:not([style*="background"]),
.dfc-kpi *[style*="color:white" i]:not([style*="background"]),
.ac-tile *[style*="color:#fff" i]:not([style*="background"]),
.ac-tile *[style*="color:white" i]:not([style*="background"]) {
  color: inherit !important;
}
/* Pills, badges and danger buttons were checked and deliberately left out. Every
   white-text site in those is written on an element that also sets its own
   inline background, so it keeps its dark fill and its white text is still
   right. Matching them here could only produce the opposite bug. */

/* The same, where the template wrote the colour onto the tile itself. */
.dfc-kpi[style*="color:#fff" i], .dfc-kpi[style*="color:white" i] {
  color: var(--color-text) !important;
}

/* theme.css paints three more parts of the KPI tile for a dark background: the
   target line and the link in white, and the sub-label with a dark text-shadow
   that only makes sense under white type. The value and sub-label colours were
   handled further up; these are the rest of the set, found by listing every
   .dfc-kpi rule in theme.css rather than by looking at screens - which is how
   the P&L and Staff Efficiency numbers were missed the first time. */
.dfc-kpi-tgt  { color: var(--color-muted) !important; }
.dfc-kpi-link { color: var(--color-primary) !important; }
/* A shadow tuned to lift white type off a saturated wash is just a smudge
   under dark type on white. */
.dfc-kpi, .dfc-kpi * { text-shadow: none !important; }

/* ── KPI delta chip and target bar ────────────────────────────────────────── */
/* theme.css designs both for a saturated tile, and says so: the chip is a 30%
   BLACK wash carrying white text, chosen because it had to survive nine
   different gradients behind it. On a white tile that wash is mid-grey and its
   white text falls to about 1.9:1.
   The constraint it was solving is gone - there is one background now, and it
   is white - so the chip becomes what everything else here is: a light fill,
   a hairline border and dark text. That also frees the dot to carry the
   judgement in the registered status tones, which is the palette rule for this
   layer anyway: colour only where it means something. */
.dfc-kpi-delta {
  background: var(--rule-faint) !important;
  border: 1px solid var(--rule-strong) !important;
  color: var(--color-text) !important;
}
.dfc-kpi-delta::before        { background: var(--color-success) !important; }
.dfc-kpi-delta.is-worse::before { background: var(--color-danger) !important; }
.dfc-kpi-delta.is-flat::before  { background: var(--color-faint) !important; }

/* Target bar: the track was a 30% black wash and the fill a near-white, both
   sized to a dark tile. Inverted for a light one - quiet track, accent fill,
   success once the value is past target - and the marker loses the white
   shadow it needed to stay visible on a light fill. */
.dfc-kpi-bar            { background: var(--rule) !important; }
.dfc-kpi-bar > b        { background: var(--color-primary) !important; }
.dfc-kpi-bar.is-over > b{ background: var(--color-success) !important; }
.dfc-kpi-bar > u        { background: var(--color-text) !important; box-shadow: none !important; }

/* ═══════════════════════════════════════════════════════════════════════════
   ICONS — thin-stroke line set for the side rail and every module card
   ───────────────────────────────────────────────────────────────────────────
   GROUP_META and MOD_ICON in hub.js emit emoji TEXT NODES. Emoji are
   multi-colour bitmaps: CSS cannot recolour or restyle them, so changing the
   register means replacing the glyph, not styling it.

   The text node is collapsed to font-size 0 and a MASK is painted in its
   place. A mask uses only the SVG's alpha, so the colour comes from
   background-color - keyed to var(--color-primary), which means the set
   follows dark mode on its own (primary flips to #5ec98f there) without a
   second definition.

   Each glyph is defined ONCE below and referenced by name; inlining a data
   URI per module would repeat about a kilobyte eighty times.

   No markup is touched, so deleting this file restores the emoji. */
:root {
  --ic-bin: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTQuNSA3aDE1Jy8+PHBhdGggZD0nTTkuNSA3VjUuMkExLjcgMS43IDAgMCAxIDExLjIgMy41aDEuNkExLjcgMS43IDAgMCAxIDE0LjUgNS4yVjcnLz48cGF0aCBkPSdNNi41IDdsLjkgMTIuMkExLjggMS44IDAgMCAwIDkuMiAyMWg1LjZhMS44IDEuOCAwIDAgMCAxLjgtMS44TDE3LjUgNycvPjwvc3ZnPg==");
  --ic-book: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTEyIDYuNEMxMC40IDUgOC4yIDQuMyA1LjYgNC4zSDN2MTMuNGgyLjZjMi42IDAgNC44LjcgNi40IDIuMScvPjxwYXRoIGQ9J00xMiA2LjRjMS42LTEuNCAzLjgtMi4xIDYuNC0yLjFIMjF2MTMuNGgtMi42Yy0yLjYgMC00LjguNy02LjQgMi4xJy8+PHBhdGggZD0nTTEyIDYuNHYxMy40Jy8+PC9zdmc+");
  --ic-box: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTEyIDIuOGw4LjQgNC4ydjkuOUwxMiAyMS4yIDMuNiAxNi45Vjd6Jy8+PHBhdGggZD0nTTMuNiA3TDEyIDExLjQgMjAuNCA3Jy8+PHBhdGggZD0nTTEyIDExLjR2OS44Jy8+PC9zdmc+");
  --ic-briefcase: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHJlY3QgeD0nMycgeT0nNy41JyB3aWR0aD0nMTgnIGhlaWdodD0nMTInIHJ4PScyJy8+PHBhdGggZD0nTTguNSA3LjVWNS42YTIgMiAwIDAgMSAyLTJoM2EyIDIgMCAwIDEgMiAydjEuOScvPjxwYXRoIGQ9J00zIDEyLjZoMTgnLz48L3N2Zz4=");
  --ic-calculator: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHJlY3QgeD0nNScgeT0nMi42JyB3aWR0aD0nMTQnIGhlaWdodD0nMTguOCcgcng9JzInLz48cGF0aCBkPSdNOCA3aDgnLz48cGF0aCBkPSdNOC42IDExLjZoLjFNMTIgMTEuNmguMU0xNS40IDExLjZoLjFNOC42IDE1LjZoLjFNMTIgMTUuNmguMU0xNS40IDE1LjZoLjEnLz48L3N2Zz4=");
  --ic-camera: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTQgOC42aDIuNkw4IDYuNGg4bDEuNCAyLjJIMjBhMS44IDEuOCAwIDAgMSAxLjggMS44djdBMS44IDEuOCAwIDAgMSAyMCAxOS4ySDRhMS44IDEuOCAwIDAgMS0xLjgtMS44di03QTEuOCAxLjggMCAwIDEgNCA4LjZ6Jy8+PGNpcmNsZSBjeD0nMTInIGN5PScxMy4yJyByPSczLjMnLz48L3N2Zz4=");
  --ic-cap: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTEyIDQuMkwyLjggOC42IDEyIDEzbDkuMi00LjR6Jy8+PHBhdGggZD0nTTYuNiAxMC41djQuMmMwIDEuNSAyLjYgMi44IDUuNCAyLjhzNS40LTEuMyA1LjQtMi44di00LjInLz48cGF0aCBkPSdNMjAuNCA5djQuNicvPjwvc3ZnPg==");
  --ic-chartbar: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTQgM3YxN2gxNicvPjxwYXRoIGQ9J004IDE3di02TTEyIDE3VjcuNk0xNiAxN3YtNCcvPjwvc3ZnPg==");
  --ic-chartline: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTQgM3YxN2gxNicvPjxwYXRoIGQ9J003LjUgMTUuNWwzLjUtNC41IDMgMi41IDQuNS02Jy8+PC9zdmc+");
  --ic-chat: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTIxIDEyLjZhNy42IDcuNiAwIDAgMS04LjIgNy42TDUgMjEuNGwxLjUtNC42QTcuNiA3LjYgMCAxIDEgMjEgMTIuNnonLz48L3N2Zz4=");
  --ic-check: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHJlY3QgeD0nMy41JyB5PSczLjUnIHdpZHRoPScxNycgaGVpZ2h0PScxNycgcng9JzMnLz48cGF0aCBkPSdNOCAxMi4ybDIuOCAyLjggNS4yLTUuNicvPjwvc3ZnPg==");
  --ic-clipboard: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHJlY3QgeD0nNScgeT0nNC41JyB3aWR0aD0nMTQnIGhlaWdodD0nMTYuNScgcng9JzInLz48cGF0aCBkPSdNOSA2LjVoNlY0LjZBMS42IDEuNiAwIDAgMCAxMy40IDNoLTIuOEExLjYgMS42IDAgMCAwIDkgNC42eicvPjxwYXRoIGQ9J004LjUgMTFoN004LjUgMTQuNmg3TTguNSAxOGg0Jy8+PC9zdmc+");
  --ic-clock: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PGNpcmNsZSBjeD0nMTInIGN5PScxMicgcj0nOC42Jy8+PHBhdGggZD0nTTEyIDcuMlYxMmwzLjIgMicvPjwvc3ZnPg==");
  --ic-cog: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PGNpcmNsZSBjeD0nMTInIGN5PScxMicgcj0nMy4xJy8+PHBhdGggZD0nTTEyIDEuOWwxLjUgMi42YTguMiA4LjIgMCAwIDEgMS45LjhsMi45LS42IDEuNiAyLjgtMiAyLjJhOC4yIDguMiAwIDAgMSAwIDJsMiAyLjItMS42IDIuOC0yLjktLjZhOC4yIDguMiAwIDAgMS0xLjkuOEwxMiAyMi4xbC0xLjUtMi42YTguMiA4LjIgMCAwIDEtMS45LS44bC0yLjkuNi0xLjYtMi44IDItMi4yYTguMiA4LjIgMCAwIDEgMC0ybC0yLTIuMiAxLjYtMi44IDIuOS42YTguMiA4LjIgMCAwIDEgMS45LS44eicvPjwvc3ZnPg==");
  --ic-cycle: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTIwIDExYTggOCAwIDAgMC0xMy42LTUuMkw0IDgnLz48cGF0aCBkPSdNNCAzLjhWOGg0LjInLz48cGF0aCBkPSdNNCAxM2E4IDggMCAwIDAgMTMuNiA1LjJMMjAgMTYnLz48cGF0aCBkPSdNMjAgMjAuMlYxNmgtNC4yJy8+PC9zdmc+");
  --ic-database: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PGVsbGlwc2UgY3g9JzEyJyBjeT0nNicgcng9JzcuNScgcnk9JzIuOCcvPjxwYXRoIGQ9J000LjUgNnY1LjljMCAxLjYgMy40IDIuOSA3LjUgMi45czcuNS0xLjMgNy41LTIuOVY2Jy8+PHBhdGggZD0nTTQuNSAxMS45VjE4YzAgMS42IDMuNCAyLjkgNy41IDIuOXM3LjUtMS4zIDcuNS0yLjl2LTYuMScvPjwvc3ZnPg==");
  --ic-doc: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTEzLjggM0g3YTIgMiAwIDAgMC0yIDJ2MTRhMiAyIDAgMCAwIDIgMmgxMGEyIDIgMCAwIDAgMi0yVjguMnonLz48cGF0aCBkPSdNMTMuOCAzdjUuMkgxOScvPjxwYXRoIGQ9J004LjggMTNoNi40TTguOCAxNi42aDYuNCcvPjwvc3ZnPg==");
  --ic-dots: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PGNpcmNsZSBjeD0nNi41JyBjeT0nMTInIHI9JzEuMycvPjxjaXJjbGUgY3g9JzEyJyBjeT0nMTInIHI9JzEuMycvPjxjaXJjbGUgY3g9JzE3LjUnIGN5PScxMicgcj0nMS4zJy8+PC9zdmc+");
  --ic-drop: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTEyIDMuMnM2IDYuMyA2IDEwLjJhNiA2IDAgMCAxLTEyIDBjMC0zLjkgNi0xMC4yIDYtMTAuMnonLz48L3N2Zz4=");
  --ic-factory: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTIuNSAyMWgxOScvPjxwYXRoIGQ9J001IDIxdi04LjZsNC40IDIuN3YtMi43bDQuNCAyLjd2LTIuN2w0LjQgMi43VjUuNWgyLjNWMjEnLz48cGF0aCBkPSdNOC41IDIxdi0zTTEzLjUgMjF2LTMnLz48L3N2Zz4=");
  --ic-flask: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTkuMyAzaDUuNCcvPjxwYXRoIGQ9J00xMC4yIDN2Ni4zTDUgMTguNkExLjYgMS42IDAgMCAwIDYuNCAyMWgxMS4yYTEuNiAxLjYgMCAwIDAgMS40LTIuNGwtNS4yLTkuM1YzJy8+PHBhdGggZD0nTTcuOCAxNWg4LjQnLz48L3N2Zz4=");
  --ic-folder: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTMgNy40YTEuOCAxLjggMCAwIDEgMS44LTEuOGg0LjZsMS44IDIuNGg4QTEuOCAxLjggMCAwIDEgMjEgOS44djguNGExLjggMS44IDAgMCAxLTEuOCAxLjhINC44QTEuOCAxLjggMCAwIDEgMyAxOC4yeicvPjxwYXRoIGQ9J003IDUuNlY0LjRhMSAxIDAgMCAxIDEtMWgzLjYnLz48L3N2Zz4=");
  --ic-hash: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTguNiAzLjRMNi44IDIwLjZNMTcuMiAzLjRsLTEuOCAxNy4yJy8+PHBhdGggZD0nTTMuNiA4LjZoMTdNMyAxNS40aDE3Jy8+PC9zdmc+");
  --ic-idcard: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHJlY3QgeD0nMi42JyB5PSc1JyB3aWR0aD0nMTguOCcgaGVpZ2h0PScxNCcgcng9JzIuNCcvPjxjaXJjbGUgY3g9JzguNCcgY3k9JzEwLjgnIHI9JzIuMicvPjxwYXRoIGQ9J000LjkgMTYuOGMwLTEuOSAxLjYtMy4xIDMuNS0zLjFzMy41IDEuMiAzLjUgMy4xJy8+PHBhdGggZD0nTTE1IDEwaDRNMTUgMTMuNmg0Jy8+PC9zdmc+");
  --ic-link: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTkuNiAxNC40YTQuMiA0LjIgMCAwIDAgNiAwbDMtM2E0LjI0IDQuMjQgMCAwIDAtNi02bC0xLjcgMS43Jy8+PHBhdGggZD0nTTE0LjQgOS42YTQuMiA0LjIgMCAwIDAtNiAwbC0zIDNhNC4yNCA0LjI0IDAgMCAwIDYgNmwxLjctMS43Jy8+PC9zdmc+");
  --ic-list: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTguNCA2LjRoMTJNOC40IDEyaDEyTTguNCAxNy42aDEyJy8+PHBhdGggZD0nTTQgNi40aC4xTTQgMTJoLjFNNCAxNy42aC4xJy8+PC9zdmc+");
  --ic-lock: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHJlY3QgeD0nNC41JyB5PScxMC4yJyB3aWR0aD0nMTUnIGhlaWdodD0nMTAuNicgcng9JzInLz48cGF0aCBkPSdNOC4yIDEwLjJWNy40YTMuOCAzLjggMCAwIDEgNy42IDB2Mi44Jy8+PHBhdGggZD0nTTEyIDE0LjR2Mi4yJy8+PC9zdmc+");
  --ic-map: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTIuOCA2LjZMOSA0bDYgMi42IDYuMi0yLjZ2MTNMMTUgMTkuNiA5IDE3IDIuOCAxOS42eicvPjxwYXRoIGQ9J005IDR2MTNNMTUgNi42djEzJy8+PC9zdmc+");
  --ic-megaphone: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTQgMTB2NGExLjYgMS42IDAgMCAwIDEuNiAxLjZIOGw2IDQuMlY0LjJMOCA4LjRINS42QTEuNiAxLjYgMCAwIDAgNCAxMHonLz48cGF0aCBkPSdNMTcuNSA4LjZhNSA1IDAgMCAxIDAgNi44Jy8+PC9zdmc+");
  --ic-microscope: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTUuNSAyMWgxMycvPjxwYXRoIGQ9J004LjUgMjF2LTIuNmg3VjIxJy8+PHBhdGggZD0nTTcuNSAxNi40aDknLz48cGF0aCBkPSdNMTIgMTYuNHYtMicvPjxwYXRoIGQ9J00xNS42IDMuMmwyLjYgMS41LTUuMiA5LTIuNi0xLjV6Jy8+PHBhdGggZD0nTTExLjQgMTAuNGwtMS4zIDIuMiAyLjYgMS41IDEuMy0yLjInLz48L3N2Zz4=");
  --ic-news: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTQgNS40aDEzdjE0LjJhMS44IDEuOCAwIDAgMCAxLjggMS44SDUuOEExLjggMS44IDAgMCAxIDQgMTkuNnonLz48cGF0aCBkPSdNMTcgOC42aDIuMkExLjggMS44IDAgMCAxIDIxIDEwLjR2OS4yJy8+PHBhdGggZD0nTTcgOWg3TTcgMTIuNGg3TTcgMTUuOGg0Jy8+PC9zdmc+");
  --ic-note: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHJlY3QgeD0nMi41JyB5PSc2JyB3aWR0aD0nMTknIGhlaWdodD0nMTInIHJ4PScyJy8+PGNpcmNsZSBjeD0nMTInIGN5PScxMicgcj0nMi42Jy8+PHBhdGggZD0nTTYgMTB2NE0xOCAxMHY0Jy8+PC9zdmc+");
  --ic-nut: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTEyIDIuOGw3LjYgNC40djguOEwxMiAyMC40bC03LjYtNC40VjcuMnonLz48Y2lyY2xlIGN4PScxMicgY3k9JzEyJyByPSczLjInLz48L3N2Zz4=");
  --ic-orgchart: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHJlY3QgeD0nOScgeT0nMi44JyB3aWR0aD0nNicgaGVpZ2h0PSc0LjQnIHJ4PScxJy8+PHJlY3QgeD0nMi44JyB5PScxNi44JyB3aWR0aD0nNicgaGVpZ2h0PSc0LjQnIHJ4PScxJy8+PHJlY3QgeD0nMTUuMicgeT0nMTYuOCcgd2lkdGg9JzYnIGhlaWdodD0nNC40JyByeD0nMScvPjxwYXRoIGQ9J00xMiA3LjJ2NC40Jy8+PHBhdGggZD0nTTUuOCAxNi44di0yLjZoMTIuNHYyLjYnLz48L3N2Zz4=");
  --ic-pin: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTEyIDIxLjJzNi40LTUuNyA2LjQtMTAuMmE2LjQgNi40IDAgMSAwLTEyLjggMGMwIDQuNSA2LjQgMTAuMiA2LjQgMTAuMnonLz48Y2lyY2xlIGN4PScxMicgY3k9JzEwLjgnIHI9JzIuNCcvPjwvc3ZnPg==");
  --ic-receipt: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTYgMi42aDEydjE4LjhsLTIuNC0xLjYtMi40IDEuNi0yLjQtMS42LTIuNCAxLjZMNiAyMS40eicvPjxwYXRoIGQ9J005IDhoNk05IDEyaDYnLz48L3N2Zz4=");
  --ic-search: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PGNpcmNsZSBjeD0nMTAuNicgY3k9JzEwLjYnIHI9JzYuNicvPjxwYXRoIGQ9J00xNS40IDE1LjRMMjEgMjEnLz48L3N2Zz4=");
  --ic-shield: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTEyIDNsNy41IDIuOHY1LjdjMCA0LjctMy4yIDcuNi03LjUgOC41LTQuMy0uOS03LjUtMy44LTcuNS04LjVWNS44eicvPjxwYXRoIGQ9J005LjIgMTIuMWwyIDIgMy42LTMuOCcvPjwvc3ZnPg==");
  --ic-snow: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTEyIDIuNnYxOC44Jy8+PHBhdGggZD0nTTQuMyA3LjJsMTUuNCA4LjlNMTkuNyA3LjJMNC4zIDE2LjEnLz48cGF0aCBkPSdNMTIgNi40TDkuOCA0LjJNMTIgNi40bDIuMi0yLjJNMTIgMTcuNmwtMi4yIDIuMk0xMiAxNy42bDIuMiAyLjInLz48L3N2Zz4=");
  --ic-store: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTQgMTB2MTBoMTZWMTAnLz48cGF0aCBkPSdNMi44IDEwbDEuOC01LjZoMTQuOEwyMS4yIDEweicvPjxwYXRoIGQ9J005IDIwdi02aDZ2NicvPjwvc3ZnPg==");
  --ic-tag: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTIwLjYgMTIuNmwtOCA4YTIgMiAwIDAgMS0yLjggMGwtNi40LTYuNGEyIDIgMCAwIDEtLjYtMS40VjQuNmExLjggMS44IDAgMCAxIDEuOC0xLjhoOC4yYTIgMiAwIDAgMSAxLjQuNmw2LjQgNi40YTIgMiAwIDAgMSAwIDIuOHonLz48Y2lyY2xlIGN4PSc3LjgnIGN5PSc3LjgnIHI9JzEuNCcvPjwvc3ZnPg==");
  --ic-thermo: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTE0IDE0LjhWNS40YTIgMiAwIDEgMC00IDB2OS40YTQgNCAwIDEgMCA0IDB6Jy8+PHBhdGggZD0nTTEyIDguNnY2LjInLz48L3N2Zz4=");
  --ic-truck: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTIuNiA3aDEwLjl2OS42SDIuNnonLz48cGF0aCBkPSdNMTMuNSAxMC42aDMuN2wzLjIgMy4ydjIuOGgtNi45eicvPjxjaXJjbGUgY3g9JzYuNicgY3k9JzE4LjMnIHI9JzEuNycvPjxjaXJjbGUgY3g9JzE3JyBjeT0nMTguMycgcj0nMS43Jy8+PC9zdmc+");
  --ic-users: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PGNpcmNsZSBjeD0nOScgY3k9JzgnIHI9JzMuNCcvPjxwYXRoIGQ9J00zIDIwYzAtMy4zIDIuNy01LjQgNi01LjRzNiAyLjEgNiA1LjQnLz48cGF0aCBkPSdNMTYuNSA2LjRhMy40IDMuNCAwIDAgMSAwIDYuNicvPjxwYXRoIGQ9J00xNy42IDE0LjljMi4xLjYgMy40IDIuMyAzLjQgNS4xJy8+PC9zdmc+");
  --ic-warning: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTEyIDQuMkwyLjYgMjBoMTguOHonLz48cGF0aCBkPSdNMTIgMTB2NC40TTEyIDE3LjN2LjEnLz48L3N2Zz4=");
  --ic-wheat: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTEyIDIxVjknLz48cGF0aCBkPSdNMTIgOWMwLTIuNCAxLjYtNC4yIDMuNi00LjguNCAyLjYtMSA0LjYtMy42IDQuOHonLz48cGF0aCBkPSdNMTIgOWMwLTIuNC0xLjYtNC4yLTMuNi00LjgtLjQgMi42IDEgNC42IDMuNiA0Ljh6Jy8+PHBhdGggZD0nTTEyIDE0LjVjMC0yLjQgMS42LTQuMiAzLjYtNC44LjQgMi42LTEgNC42LTMuNiA0Ljh6Jy8+PHBhdGggZD0nTTEyIDE0LjVjMC0yLjQtMS42LTQuMi0zLjYtNC44LS40IDIuNiAxIDQuNiAzLjYgNC44eicvPjwvc3ZnPg==");
  --ic-wrench: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTIwLjUgNS4zYTQuNiA0LjYgMCAwIDEtNiA2TDYgMTkuOGEyIDIgMCAwIDEtMi44LTIuOGw4LjUtOC41YTQuNiA0LjYgMCAwIDEgNi02bC0zIDMgMi44IDIuOHonLz48L3N2Zz4=");
}

/* Shared paint for both surfaces. */
oh-side-rail .rail-group-head .ico,
.mod-card .mc-icon { font-size: 0 !important; line-height: 0; }
oh-side-rail .rail-group-head .ico::after,
.mod-card .mc-icon::after {
  content: '';
  display: block;
  background-color: var(--color-primary);
  -webkit-mask: var(--ic) center / contain no-repeat;
          mask: var(--ic) center / contain no-repeat;
}
oh-side-rail .rail-group-head .ico::after { width: 17px; height: 17px; }
.mod-card .mc-icon::after { width: 21px; height: 21px; }
/* A code with no mapping would otherwise paint an empty block. */
oh-side-rail .rail-group-head, .mod-card { --ic: var(--ic-dots); }

/* Rail categories. */
oh-side-rail .rail-group-head[data-code="operations"] { --ic: var(--ic-factory); }
oh-side-rail .rail-group-head[data-code="supply_chain"] { --ic: var(--ic-truck); }
oh-side-rail .rail-group-head[data-code="quality"] { --ic: var(--ic-flask); }
oh-side-rail .rail-group-head[data-code="projects"] { --ic: var(--ic-chartline); }
oh-side-rail .rail-group-head[data-code="compliance"] { --ic: var(--ic-shield); }
oh-side-rail .rail-group-head[data-code="academy"] { --ic: var(--ic-cap); }
oh-side-rail .rail-group-head[data-code="forms"] { --ic: var(--ic-doc); }
oh-side-rail .rail-group-head[data-code="admin"] { --ic: var(--ic-lock); }
oh-side-rail .rail-group-head[data-code="data"] { --ic: var(--ic-database); }
oh-side-rail .rail-group-head[data-code="settings"] { --ic: var(--ic-cog); }
oh-side-rail .rail-group-head[data-code="other"] { --ic: var(--ic-dots); }

/* Module cards - every active module, so no emoji survives anywhere. */
.mod-card[data-modcard="academy"] { --ic: var(--ic-cap); }
.mod-card[data-modcard="pdp"] { --ic: var(--ic-cap); }
.mod-card[data-modcard="skillgap"] { --ic: var(--ic-chartbar); }
.mod-card[data-modcard="branches"] { --ic: var(--ic-store); }
.mod-card[data-modcard="brands"] { --ic: var(--ic-tag); }
.mod-card[data-modcard="fleet"] { --ic: var(--ic-truck); }
.mod-card[data-modcard="helpbot"] { --ic: var(--ic-chat); }
.mod-card[data-modcard="item_master"] { --ic: var(--ic-list); }
.mod-card[data-modcard="orgchart"] { --ic: var(--ic-orgchart); }
.mod-card[data-modcard="recipe_master"] { --ic: var(--ic-list); }
.mod-card[data-modcard="sections"] { --ic: var(--ic-list); }
.mod-card[data-modcard="sfg_master"] { --ic: var(--ic-list); }
.mod-card[data-modcard="user_master"] { --ic: var(--ic-users); }
.mod-card[data-modcard="allergens"] { --ic: var(--ic-wheat); }
.mod-card[data-modcard="audits"] { --ic: var(--ic-clipboard); }
.mod-card[data-modcard="extlab"] { --ic: var(--ic-flask); }
.mod-card[data-modcard="fooddefence"] { --ic: var(--ic-shield); }
.mod-card[data-modcard="foreign_body"] { --ic: var(--ic-search); }
.mod-card[data-modcard="fso"] { --ic: var(--ic-shield); }
.mod-card[data-modcard="haccp"] { --ic: var(--ic-shield); }
.mod-card[data-modcard="health_cards"] { --ic: var(--ic-idcard); }
.mod-card[data-modcard="knowledge"] { --ic: var(--ic-book); }
.mod-card[data-modcard="nutrition"] { --ic: var(--ic-wheat); }
.mod-card[data-modcard="recall_withdrawal"] { --ic: var(--ic-warning); }
.mod-card[data-modcard="sensory"] { --ic: var(--ic-flask); }
.mod-card[data-modcard="stickers"] { --ic: var(--ic-tag); }
.mod-card[data-modcard="traceability"] { --ic: var(--ic-link); }
.mod-card[data-modcard="walkthrough"] { --ic: var(--ic-pin); }
.mod-card[data-modcard="audit"] { --ic: var(--ic-clipboard); }
.mod-card[data-modcard="replication"] { --ic: var(--ic-cycle); }
.mod-card[data-modcard="validation"] { --ic: var(--ic-check); }
.mod-card[data-modcard="forms"] { --ic: var(--ic-doc); }
.mod-card[data-modcard="attendance"] { --ic: var(--ic-clock); }
.mod-card[data-modcard="budget"] { --ic: var(--ic-note); }
.mod-card[data-modcard="chiller"] { --ic: var(--ic-snow); }
.mod-card[data-modcard="downtime"] { --ic: var(--ic-clock); }
.mod-card[data-modcard="hygiene"] { --ic: var(--ic-drop); }
.mod-card[data-modcard="incidents"] { --ic: var(--ic-warning); }
.mod-card[data-modcard="inventory"] { --ic: var(--ic-box); }
.mod-card[data-modcard="kpi"] { --ic: var(--ic-chartbar); }
.mod-card[data-modcard="opm"] { --ic: var(--ic-factory); }
.mod-card[data-modcard="pm"] { --ic: var(--ic-wrench); }
.mod-card[data-modcard="production"] { --ic: var(--ic-factory); }
.mod-card[data-modcard="qc"] { --ic: var(--ic-microscope); }
.mod-card[data-modcard="rounds"] { --ic: var(--ic-pin); }
.mod-card[data-modcard="sfg_transfers"] { --ic: var(--ic-cycle); }
.mod-card[data-modcard="timesheet"] { --ic: var(--ic-clock); }
.mod-card[data-modcard="tpm"] { --ic: var(--ic-cog); }
.mod-card[data-modcard="training"] { --ic: var(--ic-cap); }
.mod-card[data-modcard="projects"] { --ic: var(--ic-chartline); }
.mod-card[data-modcard="alc"] { --ic: var(--ic-check); }
.mod-card[data-modcard="calibration"] { --ic: var(--ic-thermo); }
.mod-card[data-modcard="capa"] { --ic: var(--ic-wrench); }
.mod-card[data-modcard="changecontrol"] { --ic: var(--ic-cycle); }
.mod-card[data-modcard="complaints"] { --ic: var(--ic-megaphone); }
.mod-card[data-modcard="document_control"] { --ic: var(--ic-folder); }
.mod-card[data-modcard="inprocess"] { --ic: var(--ic-clipboard); }
.mod-card[data-modcard="jobdesc"] { --ic: var(--ic-doc); }
.mod-card[data-modcard="layouts"] { --ic: var(--ic-map); }
.mod-card[data-modcard="manual"] { --ic: var(--ic-book); }
.mod-card[data-modcard="memoranda"] { --ic: var(--ic-doc); }
.mod-card[data-modcard="mrm"] { --ic: var(--ic-users); }
.mod-card[data-modcard="mwi"] { --ic: var(--ic-clipboard); }
.mod-card[data-modcard="news"] { --ic: var(--ic-news); }
.mod-card[data-modcard="product"] { --ic: var(--ic-box); }
.mod-card[data-modcard="sops"] { --ic: var(--ic-clipboard); }
.mod-card[data-modcard="strategy"] { --ic: var(--ic-chartline); }
.mod-card[data-modcard="settings"] { --ic: var(--ic-cog); }
.mod-card[data-modcard="approved_suppliers"] { --ic: var(--ic-briefcase); }
.mod-card[data-modcard="branch_orders"] { --ic: var(--ic-receipt); }
.mod-card[data-modcard="costs"] { --ic: var(--ic-note); }
.mod-card[data-modcard="dispatch_runs"] { --ic: var(--ic-truck); }
.mod-card[data-modcard="erp_txns"] { --ic: var(--ic-cycle); }
.mod-card[data-modcard="inventory_counts"] { --ic: var(--ic-hash); }
.mod-card[data-modcard="mrp"] { --ic: var(--ic-calculator); }
.mod-card[data-modcard="mrtr"] { --ic: var(--ic-box); }
.mod-card[data-modcard="ops_tasks"] { --ic: var(--ic-check); }
.mod-card[data-modcard="spares"] { --ic: var(--ic-nut); }
.mod-card[data-modcard="stock_demand"] { --ic: var(--ic-chartbar); }
.mod-card[data-modcard="suppliers"] { --ic: var(--ic-briefcase); }
.mod-card[data-modcard="wastage"] { --ic: var(--ic-bin); }
.mod-card[data-modcard="access"] { --ic: var(--ic-lock); }
.mod-card[data-modcard="capas"] { --ic: var(--ic-check); }
.mod-card[data-modcard="observability"] { --ic: var(--ic-chartline); }
.mod-card[data-modcard="product_photos"] { --ic: var(--ic-camera); }
.mod-card[data-modcard="regions_routes"] { --ic: var(--ic-map); }
.mod-card[data-modcard="specifications"] { --ic: var(--ic-doc); }
.mod-card[data-modcard="users"] { --ic: var(--ic-users); }

/* ═══════════════════════════════════════════════════════════════════════════
   INLINE ICONS — for controls whose whole label was one emoji
   ───────────────────────────────────────────────────────────────────────────
   Most emoji in the UI decorate a label and can simply go. About fifty do not:
   they ARE the label - the delete button, the camera button, the dictate
   button. Removing those would leave an empty, unclickable-looking control, so
   hub.js puts a <span class="hic" data-ic="name"> in their place and this
   paints it. Same mask technique as the rail: alpha from the SVG, colour from
   background-color, so it follows the theme. */
:root {
  --ic-eye: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTEuOCAxMlM1LjYgNS4yIDEyIDUuMiAyMi4yIDEyIDIyLjIgMTIgMTguNCAxOC44IDEyIDE4LjggMS44IDEyIDEuOCAxMnonLz48Y2lyY2xlIGN4PScxMicgY3k9JzEyJyByPSczLjInLz48L3N2Zz4=");
  --ic-inbox: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTIxIDEyLjZoLTVsLTEuNiAyLjZIOS42TDggMTIuNkgzJy8+PHBhdGggZD0nTTYuMiA1aDExLjZsMy4yIDcuNlYxOGExLjggMS44IDAgMCAxLTEuOCAxLjhINC44QTEuOCAxLjggMCAwIDEgMyAxOHYtNS40eicvPjwvc3ZnPg==");
  --ic-key: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PGNpcmNsZSBjeD0nNy42JyBjeT0nMTUuNCcgcj0nMy44Jy8+PHBhdGggZD0nTTEwLjQgMTIuNkwyMCAzaDEuNHYyLjZoLTIuNnYyLjZoLTIuNnYyLjZoLTIuNicvPjwvc3ZnPg==");
  --ic-mic: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHJlY3QgeD0nOScgeT0nMi42JyB3aWR0aD0nNicgaGVpZ2h0PScxMS40JyByeD0nMycvPjxwYXRoIGQ9J001LjQgMTEuNmE2LjYgNi42IDAgMCAwIDEzLjIgMCcvPjxwYXRoIGQ9J00xMiAxOC4ydjMuMk04LjYgMjEuNGg2LjgnLz48L3N2Zz4=");
  --ic-printer: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTYuNSA5LjRWMy42aDExdjUuOCcvPjxyZWN0IHg9JzMnIHk9JzkuNCcgd2lkdGg9JzE4JyBoZWlnaHQ9JzcuNCcgcng9JzEuOCcvPjxwYXRoIGQ9J002LjUgMTQuMmgxMXY2LjJoLTExeicvPjxwYXRoIGQ9J00xNy42IDEyLjRoLjEnLz48L3N2Zz4=");
  --ic-star: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTEyIDMuMmwyLjcgNS42IDYuMS45LTQuNCA0LjMgMSA2LjEtNS40LTIuOS01LjQgMi45IDEtNi4xTDMuMiA5LjdsNi4xLS45eicvPjwvc3ZnPg==");
}

.hic {
  display: inline-block;
  width: 1.05em; height: 1.05em;
  vertical-align: -.16em;
  background-color: currentColor;      /* inherits the control's own colour */
  -webkit-mask: var(--hic) center / contain no-repeat;
          mask: var(--hic) center / contain no-repeat;
}
.hic[data-ic="bin"] { --hic: var(--ic-bin); }
.hic[data-ic="box"] { --hic: var(--ic-box); }
.hic[data-ic="camera"] { --hic: var(--ic-camera); }
.hic[data-ic="chat"] { --hic: var(--ic-chat); }
.hic[data-ic="clipboard"] { --hic: var(--ic-clipboard); }
.hic[data-ic="clock"] { --hic: var(--ic-clock); }
.hic[data-ic="cog"] { --hic: var(--ic-cog); }
.hic[data-ic="doc"] { --hic: var(--ic-doc); }
.hic[data-ic="eye"] { --hic: var(--ic-eye); }
.hic[data-ic="inbox"] { --hic: var(--ic-inbox); }
.hic[data-ic="key"] { --hic: var(--ic-key); }
.hic[data-ic="lock"] { --hic: var(--ic-lock); }
.hic[data-ic="mic"] { --hic: var(--ic-mic); }
.hic[data-ic="printer"] { --hic: var(--ic-printer); }
.hic[data-ic="search"] { --hic: var(--ic-search); }
.hic[data-ic="shield"] { --hic: var(--ic-shield); }
.hic[data-ic="star"] { --hic: var(--ic-star); }
.hic[data-ic="thermo"] { --hic: var(--ic-thermo); }
.hic[data-ic="users"] { --hic: var(--ic-users); }
.hic[data-ic="warning"] { --hic: var(--ic-warning); }
.hic:not([data-ic]) { --hic: var(--ic-dots); }

/* Empty states. The component writes the emoji into a 38px div, so the glyph is
   collapsed and a mask painted over it - keyed on the ATTRIBUTE VALUE, which
   means neither the component nor hub.js is touched. */
oh-empty-state div[style*="font-size:38px"] { font-size: 0 !important; position: relative; }
oh-empty-state div[style*="font-size:38px"]::after {
  content: ''; display: block; width: 38px; height: 38px; margin: 0 auto;
  background-color: var(--color-faint);
  -webkit-mask: var(--es, var(--ic-inbox)) center / contain no-repeat;
          mask: var(--es, var(--ic-inbox)) center / contain no-repeat;
}
oh-empty-state[icon="🔒"] { --es: var(--ic-lock); }
oh-empty-state[icon="⚠"] { --es: var(--ic-warning); }
oh-empty-state[icon="📭"] { --es: var(--ic-inbox); }
oh-empty-state[icon="📂"] { --es: var(--ic-folder); }
oh-empty-state[icon="🔍"] { --es: var(--ic-search); }
oh-empty-state[icon="📋"] { --es: var(--ic-clipboard); }
oh-empty-state[icon="📦"] { --es: var(--ic-box); }
oh-empty-state[icon="✅"] { --es: var(--ic-check); }

/* Three more: the theme toggle's sun and moon, and an image button. */
:root {
  --ic-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHJlY3QgeD0nMycgeT0nNC42JyB3aWR0aD0nMTgnIGhlaWdodD0nMTQuOCcgcng9JzInLz48Y2lyY2xlIGN4PSc4LjYnIGN5PSc5LjgnIHI9JzEuOCcvPjxwYXRoIGQ9J00zLjQgMTYuOGw0LjgtNC42IDMuNCAzLjIgMy4yLTMgNS44IDUuNCcvPjwvc3ZnPg==");
  --ic-moon: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTIwLjQgMTQuNkE4LjYgOC42IDAgMCAxIDkuNCAzLjZhOC42IDguNiAwIDEgMCAxMSAxMXonLz48L3N2Zz4=");
  --ic-sun: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PGNpcmNsZSBjeD0nMTInIGN5PScxMicgcj0nNC40Jy8+PHBhdGggZD0nTTEyIDIuNHYyLjZNMTIgMTl2Mi42TTQuMiA0LjJsMS45IDEuOU0xNy45IDE3LjlsMS45IDEuOU0yLjQgMTJINU0xOSAxMmgyLjZNNC4yIDE5LjhsMS45LTEuOU0xNy45IDYuMWwxLjktMS45Jy8+PC9zdmc+");
}
.hic[data-ic="image"] { --hic: var(--ic-image); }
.hic[data-ic="moon"] { --hic: var(--ic-moon); }
.hic[data-ic="sun"] { --hic: var(--ic-sun); }

/* Glyphs the shim needs beyond the icon set already defined above. */
:root {
  --ic-bell: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTE4IDguNmE2IDYgMCAxIDAtMTIgMGMwIDYuNC0yLjYgOC4yLTIuNiA4LjJoMTcuMlMxOCAxNSAxOCA4LjZ6Jy8+PHBhdGggZD0nTTEzLjggMjAuNGEyIDIgMCAwIDEtMy42IDAnLz48L3N2Zz4=");
  --ic-bulb: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTkuMiAxNy40YTYuNCA2LjQgMCAxIDEgNS42IDB2Mi4ySDkuMnonLz48cGF0aCBkPSdNMTAgMjEuNmg0Jy8+PC9zdmc+");
  --ic-calendar: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHJlY3QgeD0nMy40JyB5PSc1JyB3aWR0aD0nMTcuMicgaGVpZ2h0PScxNicgcng9JzInLz48cGF0aCBkPSdNMy40IDkuOGgxNy4yTTggM3Y0TTE2IDN2NCcvPjwvc3ZnPg==");
  --ic-flask2: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTEyIDN2Ni42bC01IDguMkExLjYgMS42IDAgMCAwIDguNCAyMGg3LjJhMS42IDEuNiAwIDAgMCAxLjQtMi4ybC01LTguMlYzJy8+PHBhdGggZD0nTTkuNiAzaDQuOCcvPjwvc3ZnPg==");
  --ic-food: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTQgNC40djZhMyAzIDAgMCAwIDYgMHYtNicvPjxwYXRoIGQ9J003IDEwLjRWMjEnLz48cGF0aCBkPSdNMTcuNiAzLjRjLTEuOCAxLjItMi42IDMuMi0yLjYgNS42IDAgMS44LjggMyAyLjYgMy40VjIxJy8+PC9zdmc+");
  --ic-globe: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PGNpcmNsZSBjeD0nMTInIGN5PScxMicgcj0nOScvPjxwYXRoIGQ9J00zLjIgOS42aDE3LjZNMy4yIDE0LjRoMTcuNicvPjxwYXRoIGQ9J00xMiAzYTE0IDE0IDAgMCAxIDAgMThBMTQgMTQgMCAwIDEgMTIgM3onLz48L3N2Zz4=");
  --ic-mail: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHJlY3QgeD0nMi42JyB5PSc1JyB3aWR0aD0nMTguOCcgaGVpZ2h0PScxNCcgcng9JzInLz48cGF0aCBkPSdNMi42IDYuNEwxMiAxM2w5LjQtNi42Jy8+PC9zdmc+");
  --ic-money: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHJlY3QgeD0nMi42JyB5PSc2JyB3aWR0aD0nMTguOCcgaGVpZ2h0PScxMicgcng9JzInLz48Y2lyY2xlIGN4PScxMicgY3k9JzEyJyByPScyLjgnLz48cGF0aCBkPSdNNiAxMHY0TTE4IDEwdjQnLz48L3N2Zz4=");
  --ic-palette: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTEyIDNhOSA5IDAgMSAwIDAgMThjMS4yIDAgMS44LS45IDEuOC0xLjggMC0xLjYgMS4yLTIuMiAyLjQtMi4ySDE4YTMuNiAzLjYgMCAwIDAgMy42LTMuNkMyMS42IDcuNiAxNy4zIDMgMTIgM3onLz48Y2lyY2xlIGN4PSc3LjQnIGN5PScxMS42JyByPScxLjEnLz48Y2lyY2xlIGN4PScxMC40JyBjeT0nNy42JyByPScxLjEnLz48Y2lyY2xlIGN4PScxNS4yJyBjeT0nOC40JyByPScxLjEnLz48L3N2Zz4=");
  --ic-pencil: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTE2LjQgMy42bDQgNEw4IDIwSDR2LTR6Jy8+PHBhdGggZD0nTTE0LjQgNS42bDQgNCcvPjwvc3ZnPg==");
  --ic-plug: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTkgM3Y1LjRNMTUgM3Y1LjQnLz48cGF0aCBkPSdNNi40IDguNGgxMS4ydjMuMmE1LjYgNS42IDAgMCAxLTExLjIgMHonLz48cGF0aCBkPSdNMTIgMTcuMlYyMScvPjwvc3ZnPg==");
  --ic-ruler: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTE1LjQgMi42bDYgNkw4LjYgMjEuNGwtNi02eicvPjxwYXRoIGQ9J003IDExbDIgMk0xMCA4bDIgMk0xMyA1bDIgMicvPjwvc3ZnPg==");
  --ic-scissors: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PGNpcmNsZSBjeD0nNi40JyBjeT0nNi40JyByPScyLjYnLz48Y2lyY2xlIGN4PSc2LjQnIGN5PScxNy42JyByPScyLjYnLz48cGF0aCBkPSdNOC42IDguMkwyMCAxOS40TTIwIDQuNkw4LjYgMTUuOCcvPjwvc3ZnPg==");
  --ic-stairs: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTMgMjBoNC42di00LjZoNC42di00LjZoNC42VjYuMkgyMScvPjwvc3ZnPg==");
  --ic-stamp: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PHBhdGggZD0nTTggMTAuNFY3YTQgNCAwIDAgMSA4IDB2My40Jy8+PHBhdGggZD0nTTQuNiAxNC42aDE0Ljh2Mi44SDQuNnonLz48cGF0aCBkPSdNNi40IDIwLjRoMTEuMicvPjxwYXRoIGQ9J004IDEwLjRoOHY0LjJIOHonLz48L3N2Zz4=");
  --ic-target: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSdibGFjaycgc3Ryb2tlLXdpZHRoPScxLjYnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcgc3Ryb2tlLWxpbmVqb2luPSdyb3VuZCc+PGNpcmNsZSBjeD0nMTInIGN5PScxMicgcj0nOC42Jy8+PGNpcmNsZSBjeD0nMTInIGN5PScxMicgcj0nNC42Jy8+PGNpcmNsZSBjeD0nMTInIGN5PScxMicgcj0nMScvPjwvc3ZnPg==");
}
.hic[data-ic="bell"] { --hic: var(--ic-bell); }
.hic[data-ic="bulb"] { --hic: var(--ic-bulb); }
.hic[data-ic="calendar"] { --hic: var(--ic-calendar); }
.hic[data-ic="flask2"] { --hic: var(--ic-flask2); }
.hic[data-ic="food"] { --hic: var(--ic-food); }
.hic[data-ic="globe"] { --hic: var(--ic-globe); }
.hic[data-ic="mail"] { --hic: var(--ic-mail); }
.hic[data-ic="money"] { --hic: var(--ic-money); }
.hic[data-ic="palette"] { --hic: var(--ic-palette); }
.hic[data-ic="pencil"] { --hic: var(--ic-pencil); }
.hic[data-ic="plug"] { --hic: var(--ic-plug); }
.hic[data-ic="ruler"] { --hic: var(--ic-ruler); }
.hic[data-ic="scissors"] { --hic: var(--ic-scissors); }
.hic[data-ic="stairs"] { --hic: var(--ic-stairs); }
.hic[data-ic="stamp"] { --hic: var(--ic-stamp); }
.hic[data-ic="target"] { --hic: var(--ic-target); }

/* One .hic rule per glyph. Without these a mapped icon resolves to no mask and
   paints nothing - which is how a hundred icons came out blank. */
.hic[data-ic="book"] { --hic: var(--ic-book); }
.hic[data-ic="briefcase"] { --hic: var(--ic-briefcase); }
.hic[data-ic="calculator"] { --hic: var(--ic-calculator); }
.hic[data-ic="cap"] { --hic: var(--ic-cap); }
.hic[data-ic="chartbar"] { --hic: var(--ic-chartbar); }
.hic[data-ic="chartline"] { --hic: var(--ic-chartline); }
.hic[data-ic="check"] { --hic: var(--ic-check); }
.hic[data-ic="cycle"] { --hic: var(--ic-cycle); }
.hic[data-ic="database"] { --hic: var(--ic-database); }
.hic[data-ic="dots"] { --hic: var(--ic-dots); }
.hic[data-ic="drop"] { --hic: var(--ic-drop); }
.hic[data-ic="factory"] { --hic: var(--ic-factory); }
.hic[data-ic="flask"] { --hic: var(--ic-flask); }
.hic[data-ic="folder"] { --hic: var(--ic-folder); }
.hic[data-ic="hash"] { --hic: var(--ic-hash); }
.hic[data-ic="idcard"] { --hic: var(--ic-idcard); }
.hic[data-ic="link"] { --hic: var(--ic-link); }
.hic[data-ic="list"] { --hic: var(--ic-list); }
.hic[data-ic="map"] { --hic: var(--ic-map); }
.hic[data-ic="megaphone"] { --hic: var(--ic-megaphone); }
.hic[data-ic="microscope"] { --hic: var(--ic-microscope); }
.hic[data-ic="news"] { --hic: var(--ic-news); }
.hic[data-ic="note"] { --hic: var(--ic-note); }
.hic[data-ic="nut"] { --hic: var(--ic-nut); }
.hic[data-ic="orgchart"] { --hic: var(--ic-orgchart); }
.hic[data-ic="pin"] { --hic: var(--ic-pin); }
.hic[data-ic="receipt"] { --hic: var(--ic-receipt); }
.hic[data-ic="snow"] { --hic: var(--ic-snow); }
.hic[data-ic="store"] { --hic: var(--ic-store); }
.hic[data-ic="tag"] { --hic: var(--ic-tag); }
.hic[data-ic="truck"] { --hic: var(--ic-truck); }
.hic[data-ic="wheat"] { --hic: var(--ic-wheat); }
.hic[data-ic="wrench"] { --hic: var(--ic-wrench); }

/* ── News ticker ──────────────────────────────────────────────────────────── */
/* Half speed. tokens.css runs the marquee at 60s for a full -50% translate;
   doubling the duration halves the rate without touching the keyframes, so the
   loop still joins seamlessly. */
.news-ticker-track { animation-duration: 120s !important; }

/* Hovering a headline turned the text dark green ON the dark green bar, which
   made it unreadable. The cause is not this layer: theme.css carries a global
   a:hover { color: var(--color-primary-2) }, and `a:hover` (0,1,1) outranks the
   plain `.news-item` (0,1,0) rule that sets the white, so the moment the
   pointer lands the colour flips. Restated here at (0,2,0), which wins, and
   applied to the whole strip so the tag and the "all news" link cannot pick up
   the same global on a dark background. */
.news-ticker a:hover, .news-ticker a:focus,
.news-item:hover, .news-item:focus,
.news-ticker-all:hover, .news-ticker-all:focus { color: #fff !important; }
.news-item:hover .news-t, .news-item:hover .news-d,
.news-item:hover .news-src { color: #fff !important; }

/* ── White-on-dark links and the global a:hover ───────────────────────────── */
/* theme.css carries an unqualified  a:hover { color: var(--color-primary-2) }
   (#2D6A4F). At specificity (0,1,1) it outranks the plain class rules that set
   a link white, so every white-on-dark link turns mid-green on its own dark
   ground the moment the pointer lands.

   Found by measurement, not by reading: 7,590 rendered links were walked across
   all 88 screens and the hover colour computed against each link's actual
   painted background. Two surfaces fail, and the news ticker handled above is
   the third. Everything else sits on a light background where #2D6A4F is a
   perfectly good hover.

     .brand in the topbar          2.05:1
     a.btn-sm.primary (filled)     1.73:1
     .news-item (ticker)           1.73:1   - fixed above

   !important rather than a specificity duel: an important declaration beats any
   non-important one outright, so this cannot be undone by a future rule that
   happens to be more specific. */
.topbar a:hover, .topbar a:focus,
.brand:hover, .brand:focus,
a.primary:hover, a.primary:focus,
a.btn.primary:hover, a.btn.primary:focus,
a.btn-sm.primary:hover, a.btn-sm.primary:focus,
a.btn-primary:hover, a.btn-primary:focus { color: #fff !important; }

/* For any dark band added later: put .on-dark on the container and its links
   keep their colour through hover, without needing another rule here. */
.on-dark a:hover, .on-dark a:focus { color: inherit !important; }
