/* Custom rules that do not come from Tailwind. Separate file so a strict
   Content-Security-Policy can forbid inline <style>. */
[x-cloak] { display: none !important; }
.card { transition: transform .15s ease, box-shadow .15s ease; }
.card:hover { transform: translateY(-2px); box-shadow: 0 12px 32px -14px rgba(11,31,58,.28); }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: #cdd9e1; border-radius: 9999px; }
a, button { outline-color: #003399; }

/* Floating election bar: a single row that sticks right below the top bar (h-16 = 64px)
   on scroll. Custom rules because the prebuilt Tailwind CSS lacks the
   top-16/z-20/h-11 classes. z-20 < the topbar's z-30 so the top bar stays on top. */
.election-bar      { position: sticky; top: 4rem; z-index: 20; }
.election-bar__row { height: 2.75rem; }
.election-bar__logo{ width: 1.5rem; height: 1.5rem; }
.election-bar__date-lg { display: none; }
.election-bar__date-sm { display: inline; }
.election-bar__clock   { display: none; }              /* ticking hh:mm:ss · hidden on small screens */
.election-bar__hint    { display: none; }              /* the "till valet" label · hidden below md */
@media (min-width: 640px) {
    .election-bar__date-lg { display: inline; }
    .election-bar__date-sm { display: none; }
    .election-bar__clock   { display: inline-flex; align-items: center; }
}
@media (min-width: 768px) {
    .election-bar__hint { display: inline; }
}

/* Auto-hiding top bar · slides smoothly up when scrolling down (more reading area) and back
   when scrolling up. header.site-header (top:0) and the election bar (top:4rem) move past
   the screen edge when <body> gets the .nav-hidden class · header-scroll.js drives the class
   from scroll direction. calc(-100% - 4rem) also accounts for the election bar's top offset. */
.site-header  { transition: transform .3s cubic-bezier(.4, 0, .2, 1); will-change: transform; }
.election-bar { transition: transform .3s cubic-bezier(.4, 0, .2, 1); }
body.nav-hidden .site-header  { transform: translateY(-100%); }
body.nav-hidden .election-bar { transform: translateY(calc(-100% - 4rem)); }
@media (prefers-reduced-motion: reduce) {
    .site-header, .election-bar { transition: none; }
}

/* The feed sticks FLUSH under the top bar + election bar (64 + 44 = 108px) ·
   no air gap, same alignment as the statistics and map sticky tops. */
@media (min-width: 1024px) {
    .feed-sticky { position: sticky; top: 108px; height: calc(100dvh - 124px); }
}

/* Start-page layout · left (intro + statistics) and right (map + opinion + feed) as
   independent columns on desktop, so a short municipal-data left column leaves no gap
   against the tall map column. On mobile the wrappers dissolve (display:contents) and order
   gives the stacking heading → map → statistics. (The grid variants are missing in prebuilt Tailwind.) */
/* Wider wrap than max-w-7xl · three columns (feed · statistics · map) need the room.
   Shared by topbar/election bar/main/footer so the edges line up. */
.wrap-wide { max-width: 105rem; }

/* The map layer rail outside the map card · needs ~160px OUTSIDE the wide wrap.
   1850–1920px: the WHOLE page (every .wrap-wide · topbar, ribbon, main, footer) hugs the
   LEFT edge so the right margin alone fits the rail (1680 + 12 + ~150 ≈ 1842). From 1920px
   the centered layout has room and the page re-centers. Below 1850px the rail is replaced
   by a small hamburger in the map card's heading (a floating panel · the map never moves). */
.map-rail { display: none; }
@media (min-width: 1850px) {
    .wrap-wide    { margin-left: 0; margin-right: auto; }
    .map-rail     { display: flex; }
    .map-menu-btn { display: none; }
    /* !important beats Alpine's inline display · a panel opened at a narrower width must
       not linger when the window grows past the rail breakpoint. */
    .map-menu-panel { display: none !important; }
}
@media (min-width: 1920px) {
    .wrap-wide { margin-left: auto; }   /* back to centered */
}

/* Mobile: everything stacks. spa-shell = [scroll content, map]; spa-grid = [parties, stats]. */
.spa-shell, .spa-scroll, .spa-grid { display: flex; flex-direction: column; gap: 1rem; }
@media (max-width: 1023.98px) {
    .spa-map { order: -1; }   /* the map first on mobile, so switching kommun is up top */
}
/* News feed as a responsive card grid (defined here so the responsive column counts survive
   the Tailwind purge · same reason as the utilities block below). Ragged bottoms are fine. */
.feed-grid { display: grid; gap: .75rem; align-items: start; grid-template-columns: 1fr; }
@media (min-width: 640px)  { .feed-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .feed-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1280px) { .feed-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (min-width: 1600px) { .feed-grid { grid-template-columns: repeat(5, minmax(0, 1fr)); } }
/* Clear divider line under the pinned top block · makes it visible that the KPI
   cards scroll UNDER it (the line + a soft shadow on desktop). */
.stat-stickytop { border-bottom: 1px solid rgba(148, 163, 184, .28); padding-bottom: .55rem; }
@media (min-width: 1024px) {
    /* Top level: the scrolling content (left) + the sticky map sidebar (right). */
    .spa-shell { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 26rem);
                 column-gap: 1rem; align-items: start; }
    /* The map is a real sticky sidebar · it sits inside spa-shell (which is as tall as ALL the
       scrolling content, feed included), so it stays pinned the entire way down · always one
       click from switching municipality ↔ whole country. */
    .spa-map { position: sticky; top: 108px; align-self: start;
        transition: top .3s cubic-bezier(.4, 0, .2, 1); }
    body.nav-hidden .spa-map { top: 0; }
    /* The two data columns · parties/opinion/budget + statistics. */
    .spa-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.18fr);
                column-gap: 1rem; align-items: start; }
    /* "Sverige i siffror" · the top block (the state-finances chart + heading) sticks while
       you scroll the cards, so the key figures can always be compared against spending/revenue
       at the same point in time. The offset sits FLUSH against the chrome: 108px (top bar 64 +
       election bar 44) when the header is visible, 0 when hidden (.nav-hidden) · no air gap
       where cards slide past. z-6 + the shadow make the cards scroll UNDER the block, clearly bounded. */
    .stat-stickytop { position: sticky; top: 108px; z-index: 6;
        box-shadow: 0 10px 12px -10px rgba(2, 6, 23, .22);
        transition: top .3s cubic-bezier(.4, 0, .2, 1); }
    body.nav-hidden .stat-stickytop { top: 0; }
    /* Keep the block compact · the economy chart fills the width at a lower height. */
    .stat-stickytop .fin-svg { height: 190px; }
}

@media print { .no-print, .election-bar { display: none } body { background: #fff } }

/* ============================================================================
   Utilities missing from the purged app.css. They are used in dynamic
   :class bindings (which the purge scanner misses) and in the admin views, so
   they silently did nothing. Defined here with Tailwind's default values.
   ============================================================================ */
.space-y-6 > :not([hidden]) ~ :not([hidden]) { margin-top: 1.5rem; }
.opacity-50 { opacity: .5; }
.border-b-2 { border-bottom-width: 2px; }
.pb-1 { padding-bottom: .25rem; }
.pt-4 { padding-top: 1rem; }
.ml-2 { margin-left: .5rem; }
.py-24 { padding-top: 6rem; padding-bottom: 6rem; }
.max-w-md { max-width: 28rem; }
.max-h-64 { max-height: 16rem; }
.overflow-y-auto { overflow-y: auto; }
.w-5 { width: 1.25rem; }
.w-6 { width: 1.5rem; }
.h-6 { height: 1.5rem; }
.align-top { vertical-align: top; }
.justify-end { justify-content: flex-end; }
.text-rose-500 { color: #f43f5e; }
.bg-emerald-50 { background-color: #ecfdf5; }
.bg-emerald-600 { background-color: #059669; }
.bg-emerald-700 { background-color: #047857; }
.bg-rose-50 { background-color: #fff1f2; }
.border-emerald-200 { border-color: #a7f3d0; }
.border-rose-200 { border-color: #fecdd3; }
.border-rose-300 { border-color: #fda4af; }
.hover\:bg-emerald-50:hover { background-color: #ecfdf5; }
.hover\:bg-emerald-700:hover { background-color: #047857; }
.hover\:bg-rose-50:hover { background-color: #fff1f2; }

/* ============================================================================
   Mörkt tema. Tailwind är förbyggd utan dark:-varianter, så vi lägger ett eget
   override-lager scopet till :root[data-theme="dark"]. Attributet sätts av
   /js/theme.js innan sidan målas. Selektorerna [data-theme=dark] .klass har högre
   specificitet än .klass (0,2,0 > 0,1,0) och vinner utan !important eftersom
   site.css laddas efter app.css.
   ============================================================================ */
:root[data-theme="dark"] {
    color-scheme: dark;
}
/* Default border colour (bare border-b/border-t without a colour class inherits preflight grey).
   Set first so the specific border-* overrides below (same specificity) win. */
:root[data-theme="dark"] *,
:root[data-theme="dark"] ::before,
:root[data-theme="dark"] ::after { border-color: #273449; }

/* Ytor */
:root[data-theme="dark"] .bg-sand      { background-color: #0b1120; }
:root[data-theme="dark"] .bg-white     { background-color: #111b30; }
:root[data-theme="dark"] .bg-white\/95 { background-color: rgba(17,27,48,.92); }
:root[data-theme="dark"] .bg-slate-50  { background-color: #16223a; }
:root[data-theme="dark"] .bg-slate-100 { background-color: #1b2740; }
:root[data-theme="dark"] .bg-slate-200 { background-color: #243149; }
:root[data-theme="dark"] .bg-eublue\/5  { background-color: rgba(96,140,220,.10); }
:root[data-theme="dark"] .bg-eublue\/10 { background-color: rgba(96,140,220,.16); }
:root[data-theme="dark"] .bg-emerald-50 { background-color: rgba(16,185,129,.12); }
:root[data-theme="dark"] .bg-rose-50    { background-color: rgba(244,63,94,.12); }
:root[data-theme="dark"] .bg-amber-100  { background-color: rgba(245,158,11,.16); }
:root[data-theme="dark"] .bg-teal-100   { background-color: rgba(20,184,166,.16); }

/* Text */
:root[data-theme="dark"] body,
:root[data-theme="dark"] .text-ink      { color: #e6e9ef; }
:root[data-theme="dark"] .text-slate-700 { color: #cbd5e1; }
:root[data-theme="dark"] .text-slate-600 { color: #b4c1d2; }
:root[data-theme="dark"] .text-slate-500 { color: #9fb0c3; }
:root[data-theme="dark"] .text-slate-400 { color: #8493a6; }
:root[data-theme="dark"] .text-slate-300 { color: #6f7f94; }
:root[data-theme="dark"] .text-eublue    { color: #7ea6ff; }
:root[data-theme="dark"] .text-rose-800,
:root[data-theme="dark"] .text-rose-700,
:root[data-theme="dark"] .text-rose-600,
:root[data-theme="dark"] .text-rose-500  { color: #fb7185; }
:root[data-theme="dark"] .text-emerald-700,
:root[data-theme="dark"] .text-emerald-600 { color: #34d399; }
:root[data-theme="dark"] .text-amber-900,
:root[data-theme="dark"] .text-amber-800,
:root[data-theme="dark"] .text-amber-300 { color: #fbbf24; }
:root[data-theme="dark"] .text-teal-700   { color: #5eead4; }
:root[data-theme="dark"] .text-purple-700 { color: #c4b5fd; }
:root[data-theme="dark"] .text-indigo-700 { color: #a5b4fc; }
:root[data-theme="dark"] .text-blue-800   { color: #93c5fd; }

/* Borders (after the * rule so these win) */
:root[data-theme="dark"] .border-slate-100 { border-color: #1e2a41; }
:root[data-theme="dark"] .border-slate-200 { border-color: #273449; }
:root[data-theme="dark"] .border-slate-300 { border-color: #33425c; }
:root[data-theme="dark"] .border-slate-400 { border-color: #47576f; }
/* Ring colours · otherwise a light slate-200 ring (e.g. the pie in the municipal-politics card) glows on a dark surface */
:root[data-theme="dark"] .ring-slate-200 { --tw-ring-color: #273449; }
:root[data-theme="dark"] .ring-slate-100 { --tw-ring-color: #1e2a41; }
:root[data-theme="dark"] .border-rose-200,
:root[data-theme="dark"] .border-rose-300  { border-color: rgba(244,63,94,.35); }
:root[data-theme="dark"] .border-emerald-200 { border-color: rgba(16,185,129,.35); }
:root[data-theme="dark"] .border-amber-200   { border-color: rgba(245,158,11,.35); }

/* Form fields */
:root[data-theme="dark"] input,
:root[data-theme="dark"] select,
:root[data-theme="dark"] textarea { color: #e6e9ef; }
:root[data-theme="dark"] input::placeholder,
:root[data-theme="dark"] textarea::placeholder { color: #64748b; }

/* Scrollbar + focus in dark mode */
:root[data-theme="dark"] ::-webkit-scrollbar-thumb { background: #33425c; }

/* Hover backgrounds in dark mode · otherwise the light Tailwind values flash on hover. */
:root[data-theme="dark"] .hover\:bg-slate-100:hover { background-color: #1b2740; }
:root[data-theme="dark"] .hover\:bg-slate-50:hover  { background-color: #16223a; }
:root[data-theme="dark"] .hover\:bg-sand:hover      { background-color: #16223a; }
:root[data-theme="dark"] .hover\:bg-emerald-50:hover { background-color: rgba(16,185,129,.14); }
:root[data-theme="dark"] .hover\:bg-rose-50:hover    { background-color: rgba(244,63,94,.14); }


/* Utilities purged from app.css but needed by the composition/context panels
   ("Sverige i siffror" · expanded indicator card) and the admin form. */
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.break-all { word-break: break-all; }
.space-y-3 > * + * { margin-top: .75rem; }
.space-y-0\.5 > * + * { margin-top: .125rem; }
.mb-0\.5 { margin-bottom: .125rem; }
.pr-2 { padding-right: .5rem; }
.whitespace-nowrap { white-space: nowrap; }

/* Chart colours that follow the theme · inline SVGs (the "Sverige i siffror" chart,
   the Platform flow) reference these via stroke/fill="var(--chart-…)". The brand's
   EU blue/gold is still set literally · only structure/text/surface flips. */
:root {
    --chart-line:    #1e4b8f;
    --chart-cursor:  #0b1f3a;
    --chart-grid:    #cbd5e1;
    --chart-surface: #f4f6fa;
    --chart-dot:     #0b1f3a;
    --chart-ink:     #0f172a;
    --chart-muted:   #64748b;
    --chart-panel:   #ffffff;
    --chart-panel-border: #dbe4f5;
    --chart-panel-fill:   #eef3fb;
}
:root[data-theme="dark"] {
    --chart-line:    #6ea0f0;
    --chart-cursor:  #cbd5e1;
    --chart-grid:    #334155;
    --chart-surface: #111b30;
    --chart-dot:     #cbd5e1;
    --chart-ink:     #e2e8f0;
    --chart-muted:   #94a3b8;
    --chart-panel:   #16223a;
    --chart-panel-border: #243149;
    --chart-panel-fill:   #16223a;
}

/* The playhead (reading line + dot) follows the pointer DIRECTLY · no position easing;
   easing made it feel laggy. It snaps to the nearest data point every frame.
   Only the read-off value fades softly to blue (does not affect the feeling of immediacy). */
.chart-scrub-val { transition: color .12s ease; }
@media (prefers-reduced-motion: reduce) { .chart-scrub-val { transition: none; } }

/* The statistics cards · 2 per row on small screens, 3 per row from lg (wider body). An
   expanded card spans the whole row (grid-column 1/-1) regardless of column count. */
.stat-grid { display: grid; gap: .5rem; align-items: start; grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 1024px) { .stat-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.stat-full { grid-column: 1 / -1; }
/* Phone: one KPI card per row · 2-up is ~160px wide and truncates every title. */
@media (max-width: 519.98px) { .stat-grid { grid-template-columns: 1fr; } }

/* ============================================================
   Mobile (phone) polish · phone-specific overrides, grouped so
   they are easy to find. See the plan "mobil-vy".
   ============================================================ */
/* Supplier table · the column grid lives here (not an inline :style) so the phone can
   restack it. Desktop: name | amount | share [ | agreement ]. Phone (≤640px): two rows —
   name + amount, then share + agreement — no horizontal overflow, no data hidden. */
.supplier-grid { display: grid; grid-template-columns: minmax(0, 1fr) 8rem 6rem; }
.supplier-grid.has-refs { grid-template-columns: minmax(0, 1fr) 8rem 6rem 11rem; }
@media (max-width: 639.98px) {
    .supplier-grid, .supplier-grid.has-refs { grid-template-columns: minmax(0, 1fr) auto; row-gap: .15rem; }
    .supplier-grid > :nth-child(3) { justify-self: start; }   /* share under the name, not pushed far right */
}

/* Weather forecast slider · a grabbable hit area on touch (the h-1.5 track is 6px). */
@media (max-width: 639.98px) { .touch-range { height: 1.5rem; } }


/* The stream charts (Opinionsstöd över tid, Valresultat över tid) scrub on hover · the crosshair
   cursor matches every other scrubbable chart (the _chart-svg cards set it inline). */
.pp-chartwrap { cursor: crosshair; }

/* "Partierna" on a phone: the per-party standings list is tall · collapse it behind a toggle
   (the stream chart stays visible). From sm the list always shows and the toggle disappears. */
.pp-figures-toggle { display: none; }
@media (max-width: 639.98px) {
    .pp-figures-toggle { display: inline-flex; }
    .pp-standings      { display: none; }
    .pp-standings.open { display: grid; }
}

/* Wider page width · room for three statistics blocks per row. .max-w-7xl is the shared
   page width for topbar, hero, main and footer, so all edges line up. */
.max-w-7xl { max-width: 90rem; }

/* ============================================================
   Evidensmotorn · interaktiv kunskapsgraf (admin/Plattformen)
   ============================================================ */
.eg-wrap { position: relative; border-radius: 1rem; border: 1px solid #e2e8f0; background: var(--chart-panel); overflow: hidden; }
:root[data-theme="dark"] .eg-wrap { border-color: #243149; }
.eg-svg { display: block; width: 100%; height: auto; touch-action: none; cursor: grab; }
.eg-svg.eg-dragging { cursor: grabbing; }

.eg-edge { stroke: var(--chart-grid); opacity: .55; transition: opacity .15s, stroke .15s; }
/* Directional flow: dashes travel from the edge's start (source) toward its end (target).
   Two-way edges are drawn as twin parallel lines, the second animating in reverse. */
.eg-flow { stroke-dasharray: 7 5; animation: eg-dashflow 1.1s linear infinite; }
.eg-flow-rev { animation-name: eg-dashflow-rev; }
@keyframes eg-dashflow     { to { stroke-dashoffset: -12; } }
@keyframes eg-dashflow-rev { to { stroke-dashoffset: 12; } }
@media (prefers-reduced-motion: reduce) { .eg-flow, .eg-flow-rev { animation: none; } }
.eg-node { cursor: pointer; }
.eg-node .eg-dot { stroke: var(--chart-panel); stroke-width: 2; transition: opacity .15s; }
.eg-label { fill: var(--chart-ink); font: 600 12px ui-sans-serif, system-ui, sans-serif; pointer-events: none; }
.eg-hublabel { fill: #422006; font: 800 14px ui-sans-serif, system-ui, sans-serif; pointer-events: none; }

.eg-kalla .eg-dot        { fill: #003399; }
.eg-motor .eg-dot        { fill: #475569; }
.eg-evidens .eg-dot      { fill: #e0a411; }
.eg-presentation .eg-dot { fill: #10b981; }
.eg-medborgare .eg-dot   { fill: #7c3aed; }

.eg-focus .eg-cold                 { opacity: .12; }
.eg-focus .eg-node.eg-cold .eg-label { opacity: .2; }
.eg-edge.eg-hot                    { stroke: var(--chart-line); opacity: .95; stroke-width: 2.2; }
.eg-node.eg-hot .eg-dot            { stroke: var(--chart-line); }
.eg-node:focus                     { outline: none; }
.eg-node:focus .eg-dot             { stroke: var(--chart-line); stroke-width: 3; }

.eg-chip { border-radius: 9999px; padding: .15rem .6rem; border: 0; font-weight: 600; color: #fff; cursor: default; }
.eg-chip-kalla        { background: #003399; }
.eg-chip-motor        { background: #475569; }
.eg-chip-evidens      { background: #b8860b; }
.eg-chip-presentation { background: #10b981; }
.eg-chip-medborgare   { background: #7c3aed; }

.eg-panel { position: absolute; top: .75rem; right: .75rem; width: min(20rem, 82%); max-height: calc(100% - 1.5rem); overflow-y: auto; background: var(--chart-panel); border: 1px solid #e2e8f0; border-radius: .9rem; padding: .9rem 1rem; box-shadow: 0 12px 34px rgba(2,6,23,.16); opacity: 0; transform: translateY(-4px); pointer-events: none; transition: opacity .15s, transform .15s; }
:root[data-theme="dark"] .eg-panel { border-color: #243149; }
.eg-panel.eg-open { opacity: 1; transform: none; pointer-events: auto; }
.eg-p-empty { color: var(--chart-muted); font-size: .8rem; }
.eg-p-kicker { font-size: .65rem; font-weight: 700; text-transform: uppercase; letter-spacing: .08em; }
.eg-kick-kalla { color: #003399; } .eg-kick-motor { color: #64748b; } .eg-kick-evidens { color: #b8860b; } .eg-kick-presentation { color: #059669; } .eg-kick-medborgare { color: #7c3aed; }
:root[data-theme="dark"] .eg-kick-kalla { color: #6ea0f0; }
.eg-p-vision { color: #b8860b; font-weight: 700; }
.eg-p-title { font: 700 1.05rem/1.2 ui-serif, Georgia, serif; color: var(--chart-ink); margin: .1rem 0 .4rem; }
.eg-p-desc { font-size: .82rem; line-height: 1.5; color: var(--chart-muted); }
.eg-p-connlabel { font-size: .65rem; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--chart-muted); margin: .7rem 0 .35rem; }
.eg-p-conns { display: flex; flex-wrap: wrap; gap: .3rem; }
.eg-link { border: 1px solid #e2e8f0; border-radius: 9999px; padding: .1rem .5rem; font-size: .72rem; background: transparent; color: var(--chart-ink); cursor: pointer; }
.eg-link:hover { border-color: var(--chart-line); }
:root[data-theme="dark"] .eg-link { border-color: #243149; }

/* ============================================================
   Live data flow · admin/Platform (instrumented pipeline)
   ============================================================ */
.df-flow { display: flex; align-items: stretch; gap: 0; min-width: 860px; padding: .25rem 0 .5rem; }
.df-stage { flex: 1 1 0; min-width: 118px; display: flex; flex-direction: column; align-items: center; gap: .1rem;
    background: var(--chart-panel); border: 1px solid #e2e8f0; border-top: 3px solid transparent; border-radius: .85rem;
    padding: .7rem .5rem .8rem; cursor: pointer; text-align: center; transition: box-shadow .15s, transform .1s, border-color .15s; }
:root[data-theme="dark"] .df-stage { border-color: #243149; }
.df-stage:hover { box-shadow: 0 8px 22px rgba(2,6,23,.1); transform: translateY(-1px); }
.df-stage.df-active { border-color: var(--chart-line); box-shadow: 0 8px 24px rgba(2,6,23,.14); }
.df-stage:focus-visible { outline: 2px solid var(--chart-line); outline-offset: 2px; }
.df-st-label { font-size: .7rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--chart-muted); }
.df-st-num { font: 800 1.7rem/1 ui-serif, Georgia, serif; font-variant-numeric: tabular-nums; color: var(--chart-ink); margin-top: .15rem; }
.df-st-glyph { font-family: ui-sans-serif, system-ui, sans-serif; }
.df-st-unit { font-size: .68rem; color: var(--chart-muted); }
.df-st-sub { font-size: .7rem; color: var(--chart-muted); margin-top: .15rem; line-height: 1.2; }
.df-g-kalla  { border-top-color: #003399; } .df-g-kalla  .df-st-num { color: #003399; }
:root[data-theme="dark"] .df-g-kalla .df-st-num { color: #6ea0f0; }
.df-g-motor  { border-top-color: #64748b; }
.df-g-out    { border-top-color: #10b981; } .df-g-out    .df-st-num { color: #059669; }
.df-g-people { border-top-color: #e0a411; } .df-g-people .df-st-num { color: #b8860b; }
.df-g-evidens { border-top-color: #7c3aed; } .df-g-evidens .df-st-num { color: #7c3aed; }
:root[data-theme="dark"] .df-g-evidens .df-st-num { color: #a78bfa; }
/* The evidence branch is drawn solid like everything else · the ✦ glyph (no live number) and the purple
   "Evidens · AI" tag suffice as an honest marker that it is still a vision. */
.df-stage.df-vision .df-st-glyph { color: #7c3aed; }
:root[data-theme="dark"] .df-stage.df-vision .df-st-glyph { color: #a78bfa; }

/* Branch after detection: two tracks (Evidens · AI / Participation) that flow into the presentation.
   Vertical spines at the branch edges + short stubs to each track give the fork/merge feel. */
.df-branch { display: flex; flex-direction: column; justify-content: center; gap: .7rem; flex: 2.4 1 0; position: relative; padding: 12px 12px 0; min-width: 340px; }
.df-branch::before, .df-branch::after { content: ""; position: absolute; top: 30%; bottom: 22%; width: 2px; background: var(--chart-grid); }
.df-branch::before { left: 0; }
.df-branch::after  { right: 0; }
.df-lane { display: flex; align-items: center; gap: 0; flex: 1; position: relative; }
.df-lane .df-stage { flex: 1 1 0; }
.df-lane::before, .df-lane::after { content: ""; position: absolute; top: 50%; width: 12px; height: 2px; background: var(--chart-grid); }
.df-lane::before { left: -12px; }
.df-lane::after  { right: -12px; }
.df-lane-tag { position: absolute; top: -11px; left: 2px; font-size: 9px; font-weight: 700; text-transform: uppercase; letter-spacing: .07em; color: var(--chart-muted); }
.df-lane-tag-evidens { color: #7c3aed; }
:root[data-theme="dark"] .df-lane-tag-evidens { color: #a78bfa; }

/* pipes + particles between the steps */
.df-conn { position: relative; flex: 0 0 42px; align-self: center; height: 14px; }
.df-conn::before { content: ""; position: absolute; left: 0; right: 4px; top: 50%; height: 2px; background: var(--chart-grid); }
.df-conn::after { content: ""; position: absolute; right: 0; top: 50%; margin-top: -4px; border-left: 6px solid var(--chart-grid); border-top: 4px solid transparent; border-bottom: 4px solid transparent; }
.df-particle { position: absolute; top: 50%; left: 0; width: 6px; height: 6px; margin-top: -3px; border-radius: 50%; background: var(--chart-line); animation: df-move 1.7s linear infinite; }
@keyframes df-move { 0% { transform: translateX(0); opacity: 0; } 12% { opacity: 1; } 88% { opacity: 1; } 100% { transform: translateX(38px); opacity: 0; } }

/* transparency ledger + feedback */
.df-ledger { margin-top: .8rem; display: flex; align-items: center; flex-wrap: wrap; gap: .45rem; font-size: .8rem; color: var(--chart-muted);
    border: 1px dashed var(--chart-panel-border); border-radius: .7rem; padding: .5rem .8rem; }
.df-ledger b { color: var(--chart-ink); }
.df-ledger-dot { width: 8px; height: 8px; border-radius: 50%; background: #10b981; animation: df-pulse 2.2s ease-in-out infinite; }
@keyframes df-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .3; } }

/* source-health dots */
.df-health { display: flex; flex-wrap: wrap; justify-content: center; gap: 2px; margin-top: .4rem; max-width: 118px; }
.df-dot { width: 7px; height: 7px; border-radius: 50%; display: inline-block; }
.df-dot-ok { background: #10b981; } .df-dot-error { background: #ef4444; } .df-dot-paused { background: #f59e0b; } .df-dot-idle { background: #94a3b8; }

/* klick-panel (under strippen, full bredd) */
.df-panel { display: none; margin-top: .8rem; border-top: 1px solid #e2e8f0; padding-top: .8rem; }
:root[data-theme="dark"] .df-panel { border-color: #243149; }
.df-panel.df-open { display: block; }
.df-p-empty { color: var(--chart-muted); font-size: .8rem; }
.df-p-title { font: 700 1.05rem/1.2 ui-serif, Georgia, serif; color: var(--chart-ink); margin-bottom: .3rem; }
.df-p-desc { font-size: .85rem; line-height: 1.55; color: var(--chart-muted); max-width: 52rem; }
.df-p-connlabel { font-size: .65rem; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--chart-muted); margin: .7rem 0 .4rem; }
.df-src-list { list-style: none; margin: 0; padding: 0; columns: 240px 3; column-gap: 1.2rem; }
.df-src { display: flex; align-items: center; gap: .45rem; padding: .12rem 0; break-inside: avoid; font-size: .8rem; }
.df-src-name { color: var(--chart-ink); flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.df-src-when { color: var(--chart-muted); font-size: .72rem; white-space: nowrap; }
.df-p-link { display: inline-block; margin-top: .7rem; font-size: .8rem; font-weight: 600; color: var(--chart-line); text-decoration: none; }
.df-p-link:hover { text-decoration: underline; }

@media (prefers-reduced-motion: reduce) {
    .df-particle { animation: none; opacity: .55; }
    .df-ledger-dot { animation: none; }
}

/* ============================================================
   Statens ekonomi · finansgraf (underlag) · utgifter mot inkomster
   ============================================================ */
.fin-wrap { position: relative; }
.fin-readout { position: sticky; top: 0; z-index: 6; display: flex; flex-wrap: wrap; align-items: baseline; gap: .3rem .9rem;
    background: var(--chart-panel); border: 1px solid #e2e8f0; border-radius: .6rem; padding: .5rem .8rem; margin-bottom: .5rem;
    font-size: .82rem; box-shadow: 0 6px 16px rgba(2,6,23,.08); }
:root[data-theme="dark"] .fin-readout { border-color: #243149; }
.fin-r-period { font: 800 1rem/1 ui-serif, Georgia, serif; color: var(--chart-ink); }
.fin-r-item { color: var(--chart-muted); } .fin-r-item b { color: var(--chart-ink); }
.fin-r-exp b { color: #003399; } .fin-r-inc b { color: #059669; }
:root[data-theme="dark"] .fin-r-exp b { color: #6ea0f0; }
.fin-r-regime { margin-left: auto; color: var(--chart-muted); font-size: .75rem; }
/* Government support in the polls · its own row in the readout (shown only for the current term). */
.fin-r-poll { flex-basis: 100%; color: var(--chart-muted); font-size: .72rem; }
.fin-r-poll::before { content: "· "; color: var(--chart-line); }
.fin-compact .fin-r-poll { font-size: .66rem; }
/* The balance: plus in black (neutral statement), minus in red (the warning) · themed via var. */
.fin-pos { color: var(--chart-ink); } .fin-neg { color: #e11d48; }

.fin-chart { width: 100%; }
.fin-svg { display: block; width: 100%; height: auto; cursor: crosshair; }

.fin-band-left  { fill: rgba(225,29,72,.06); }
.fin-band-right { fill: rgba(0,51,153,.06); }
.fin-band-label { fill: var(--chart-muted); font: 600 12px ui-sans-serif, system-ui, sans-serif; }
.fin-grid { stroke: var(--chart-grid); stroke-width: 1; opacity: .5; }
.fin-axis { fill: var(--chart-muted); font: 500 11px ui-sans-serif, system-ui, sans-serif; }
.fin-election { stroke: #94a3b8; stroke-width: 1.2; stroke-dasharray: 3 3; }
.fin-zero { stroke: var(--chart-grid); stroke-width: 1; }
.fin-line-exp { stroke: #003399; stroke-width: 2.2; }
.fin-line-inc { stroke: #10b981; stroke-width: 2.2; }
:root[data-theme="dark"] .fin-line-exp { stroke: #6ea0f0; }
/* Deficit periods (balance < 0): the revenue line red (it does not cover), green in surplus ·
   spending is always blue as the reference. The line is clipped per interval in statefinance.js ·
   the fin-deficit class is set on the wrapper while the readout sits on a deficit period,
   so the revenue figure + revenue dot follow along. */
.fin-line-inc-def { stroke: #e11d48; stroke-width: 2.2; }
:root[data-theme="dark"] .fin-line-inc-def { stroke: #fb7185; }
.fin-deficit .fin-r-inc b { color: #e11d48; }
:root[data-theme="dark"] .fin-deficit .fin-r-inc b { color: #fb7185; }
.fin-deficit .fin-dot-inc { fill: #e11d48; }
/* The balance strip: plus black/neutral, minus red (matches the readout's fin-pos/fin-neg). */
.fin-saldo-pos { fill: rgba(15,23,42,.30); }
:root[data-theme="dark"] .fin-saldo-pos { fill: rgba(226,232,240,.30); }
.fin-saldo-neg { fill: rgba(225,29,72,.34); }
.fin-cross { stroke: var(--chart-cursor); stroke-width: 1; }
.fin-dot { stroke: var(--chart-panel); stroke-width: 1.5; }
.fin-dot-exp { fill: #003399; } .fin-dot-inc { fill: #10b981; } .fin-dot-saldo { fill: var(--chart-cursor); }

.fin-legend { display: flex; flex-wrap: wrap; gap: .3rem 1rem; margin-top: .5rem; font-size: .72rem; }
.fin-key { display: inline-flex; align-items: center; gap: .35rem; color: var(--chart-muted); }
.fin-key::before { content: ""; width: 13px; height: 3px; border-radius: 2px; background: #94a3b8; }
.fin-key-exp::before { background: #003399; }
/* The revenue legend key two-toned: green in surplus, red in deficit. */
.fin-key-inc::before { background: linear-gradient(90deg, #10b981 50%, #e11d48 50%); }
.fin-key-saldo::before { height: 10px; width: 11px; background: linear-gradient(rgba(15,23,42,.55), #e11d48); }
.fin-key-left::before  { height: 11px; width: 11px; background: rgba(225,29,72,.45); }
.fin-key-right::before { height: 11px; width: 11px; background: rgba(0,51,153,.45); }
.fin-key-election::before { height: 11px; width: 0; border-left: 2px dashed #94a3b8; background: none; }

/* Compact finance module in the SPA hero · the in-chart text gets too small when scaled down, so hide
   axis/band labels and lean on the HTML-rendered readout instead. */
.fin-compact .fin-readout { position: static; box-shadow: none; padding: .35rem .5rem; font-size: .72rem; gap: .15rem .55rem; margin-bottom: .35rem; }
.fin-compact .fin-r-period { font-size: .85rem; }
.fin-compact .fin-r-regime { font-size: .66rem; margin-left: auto; }
.fin-compact .fin-axis, .fin-compact .fin-band-label { display: none; }

/* Kommun-tidsslider (kartans kommunvy) */
.muni-slider { accent-color: #003399; height: 4px; cursor: pointer; }
:root[data-theme="dark"] .muni-slider { accent-color: #6ea0f0; }

/* Bare finance module (moved to the top of "Sverige i siffror") · no card, just the chart.
   The readout is a plain row ABOVE the chart (fin-compact's static layout applies) · an
   absolute overlay used to cover the curves while scrubbing. */
.fin-bare { position: relative; }

/* text-[11px] is used in 19 views but was missing from the prebuilt Tailwind · defined here. */
.text-\[11px\] { font-size: 11px; line-height: 1.35; }

/* ---------------------------------------------------------------------------
   Platform page on small screens · the pipeline turns vertical (no sideways
   scrolling), the knowledge graph gets readable labels (it also renders a
   portrait viewBox with larger tap targets · see evidence-graph.js). */
@media (max-width: 767px) {
    .df-flow { flex-direction: column; min-width: 0; align-items: stretch; }
    .df-stage { min-width: 0; }
    .df-conn { flex: 0 0 34px; align-self: center; width: 14px; height: 34px; }
    .df-conn::before { left: 50%; right: auto; top: 0; bottom: 6px; width: 2px; height: auto; margin-left: -1px; }
    .df-conn::after { left: 50%; right: auto; top: auto; bottom: 0; margin-top: 0; margin-left: -4px;
        border-top: 6px solid var(--chart-grid); border-left: 4px solid transparent; border-right: 4px solid transparent; border-bottom: 0; }
    .df-particle { left: 50%; top: 0; margin-left: -3px; margin-top: 0; animation-name: df-move-v; }
    .df-branch { flex-direction: column; min-width: 0; padding: 0; gap: 1.1rem; }
    .df-branch::before, .df-branch::after { display: none; }
    .df-lane { flex-direction: column; margin-top: 14px; }
    .df-lane::before, .df-lane::after { display: none; }
    .df-lane-tag { left: 50%; transform: translateX(-50%); top: -14px; }
    .eg-label { font-size: 15px; }
    .eg-hublabel { font-size: 19px; }
}
@keyframes df-move-v { 0% { transform: translateY(0); opacity: 0; } 12% { opacity: 1; } 88% { opacity: 1; } 100% { transform: translateY(30px); opacity: 0; } }

/* ---------------------------------------------------------------------------
   Municipality view · the political-situation card follows the scroll through
   the municipal data (sticky under the chrome) and DISSOLVES after a linger
   distance so it never nags all the way down. Fade driven by header-scroll.js
   ([data-muni-sticky] · desktop only, stacked columns on mobile skip it). */
@media (min-width: 768px) {
    .spa-hero.muni-sticky { position: sticky; top: 116px; z-index: 30; transition: opacity .35s ease; }
    body.nav-hidden .spa-hero.muni-sticky { top: 12px; }
    .spa-hero.muni-sticky.muni-faded { opacity: 0; pointer-events: none; }
}

/* ---------------------------------------------------------------------------
   Hash chain vs blockchain · the interactive quick education on /plattform. */
.cd-tab.cd-active { border-color: var(--chart-line); color: var(--chart-line); background: rgba(0,51,153,.06); }
.cd-chain { display: flex; align-items: stretch; gap: .4rem; flex-wrap: wrap; margin: .75rem 0; }
.cd-block { position: relative; flex: 1 1 9rem; min-width: 8.5rem; background: var(--chart-panel, #fff); border: 1.5px solid #cbd5e1;
    border-radius: .7rem; padding: .6rem .7rem 2.1rem; transition: border-color .25s, background .25s; }
.cd-block.cd-tampered { border-color: #f59e0b; background: rgba(245,158,11,.07); }
.cd-block.cd-badself { border-color: #dc2626; }
.cd-content { font-size: 12px; font-weight: 600; line-height: 1.35; }
.cd-hash { font-family: ui-monospace, monospace; font-size: 10.5px; color: var(--chart-muted, #64748b); margin-top: .3rem; }
.cd-tamper { position: absolute; left: .7rem; bottom: .5rem; font-size: 10.5px; font-weight: 700; color: #b45309;
    border: 1px solid #f59e0b66; border-radius: .4rem; padding: .12rem .5rem; background: transparent; cursor: pointer; }
.cd-tamper:hover { background: rgba(245,158,11,.12); }
.cd-link { align-self: center; font-size: 15px; color: #10b981; }
.cd-link.cd-broken { color: #dc2626; font-size: 17px; animation: cd-shake .4s ease 1; }
@keyframes cd-shake { 25% { transform: translateX(-2px); } 75% { transform: translateX(2px); } }
.cd-intro { font-size: 13px; color: var(--chart-muted, #475569); max-width: 46rem; }
.cd-alert { font-size: 13px; font-weight: 600; color: #b91c1c; margin-top: .5rem; max-width: 46rem; }
.cd-alert.cd-warn { color: #92400e; }
.cd-action { margin-top: .6rem; font-size: 12.5px; font-weight: 700; border-radius: .5rem; padding: .45rem .9rem;
    border: 1px solid #cbd5e1; background: var(--chart-panel, #fff); cursor: pointer; }
.cd-action:hover { border-color: var(--chart-line); }
.cd-action.cd-danger { border-color: #fca5a5; color: #b91c1c; }
.cd-action.cd-danger:hover { background: rgba(220,38,38,.06); }
.cd-replicas { display: grid; gap: .5rem; margin: .75rem 0; }
.cd-replica { border: 1.5px solid #cbd5e1; border-radius: .7rem; padding: .5rem .7rem; background: var(--chart-panel, #fff); }
.cd-replica.cd-deviant { border-color: #dc2626; background: rgba(220,38,38,.05); }
.cd-rep-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--chart-muted, #64748b); margin-bottom: .3rem; }
.cd-replica.cd-deviant .cd-rep-label { color: #b91c1c; }
.cd-rep-chain { display: flex; flex-wrap: wrap; gap: .25rem; align-items: center; }
.cd-mini { font-family: ui-monospace, monospace; font-size: 10.5px; background: rgba(100,116,139,.08); border-radius: .3rem; padding: .1rem .35rem; }
.cd-mini-arrow { font-size: 10px; color: var(--chart-muted, #94a3b8); }
.cd-lesson { font-size: 13.5px; line-height: 1.6; max-width: 46rem; }
.cd-lesson ul { list-style: disc; padding-left: 1.2rem; margin: .6rem 0; display: grid; gap: .35rem; }
.cd-punch { font-weight: 600; margin-top: .6rem; }
.cd-loading { color: var(--chart-muted, #94a3b8); }
:root[data-theme="dark"] .cd-block, :root[data-theme="dark"] .cd-replica, :root[data-theme="dark"] .cd-action { border-color: #334155; }
:root[data-theme="dark"] .cd-tab { border-color: #334155; background: transparent; }
@media (max-width: 640px) {
    .cd-chain { flex-direction: column; }
    .cd-block { min-width: 0; }
    .cd-link { align-self: flex-start; margin-left: 1rem; transform: rotate(90deg); }
}

/* ---------------------------------------------------------------------------
   Dataflow detail panel on small screens: a bottom sheet INSIDE the viewport.
   On the vertical mobile pipeline the inline panel lands far below the fold ·
   tapping "Källor" looked like nothing happened. Desktop stays inline. */
.df-close { display: none; }
@media (max-width: 767px) {
    .df-panel.df-open { position: fixed; left: 0; right: 0; bottom: 0; z-index: 60; margin: 0;
        max-height: 55vh; overflow-y: auto; background: var(--chart-panel, #fff);
        border-top: 1px solid #e2e8f0; border-radius: 1rem 1rem 0 0; padding: .9rem 1rem 1.2rem;
        box-shadow: 0 -12px 40px rgba(2, 6, 23, .25); }
    :root[data-theme="dark"] .df-panel.df-open { border-color: #243149; }
    .df-panel.df-open .df-close { display: flex; position: sticky; top: 0; margin-left: auto;
        width: 1.9rem; height: 1.9rem; align-items: center; justify-content: center;
        border-radius: 9999px; border: 1px solid #e2e8f0; background: var(--chart-panel, #fff);
        font-size: .95rem; cursor: pointer; }
}

/* Chain demo · step 4 (planned mirror model) + step 5 (the choice) */
.cd-planned { display: inline-flex; align-items: center; font-size: 9.5px; font-weight: 800; text-transform: uppercase;
    letter-spacing: .08em; color: #7c3aed; background: rgba(124,58,237,.1); border-radius: 9999px; padding: .15rem .55rem; margin-right: .4rem; }
:root[data-theme="dark"] .cd-planned { color: #a78bfa; }
.cd-h3 { font-weight: 700; font-size: 14px; margin: .9rem 0 .3rem; }
.cd-layers { display: grid; gap: .6rem; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); margin: .5rem 0 .3rem; }
.cd-layer { border: 1.5px solid #cbd5e1; border-radius: .7rem; padding: .7rem .85rem; background: var(--chart-panel, #fff); font-size: 12.5px; line-height: 1.5; }
.cd-layer-h { font-weight: 800; font-size: 12px; text-transform: uppercase; letter-spacing: .05em; color: var(--chart-line, #003399); margin-bottom: .25rem; }
:root[data-theme="dark"] .cd-layer { border-color: #334155; }

/* Party page · the state-finance chart reuses the start-page component, but its own
   readout is hidden here (the values are shown in the right-column readout bar). */
.pp-fin .fin-readout { display: none; }
