/* style.css - Supporte Rio Negro Dashboard Redesigned Styling */

/* Imports */
/* @import do Google Fonts removido na publicação: as fontes vêm de
   vendor/fonts.css, servido da nossa própria origem. */

/* Brand Variables - Official Supporte Brand System */
:root {
    --supporte-laranja: #F37021;
    --supporte-chumbo: #58595B;
    --supporte-branco: #FFFFFF;
    --supporte-orange: #F37021;
    --supporte-orange-glow: rgba(243, 112, 33, 0.12);
    /* Distinct "operational alert" accent used only by the boletim draft-alert
       card — named so its 3 prior hardcoded #F97316 literals share one source
       of truth instead of independently drifting. */
    --supporte-alert-orange: #F97316;

    --font-heading: 'Titillium Web', sans-serif;
    --font-body: 'Fira Sans', sans-serif;
    --font-mono: 'Fira Code', monospace;

    --supporte-dark-grey: #1E222A;
    --supporte-bg: #121418;
    --card-bg: #1A1D24;
    --text-primary: #FFFFFF;
    --text-secondary: #94A3B8;
    --border-color: rgba(255, 255, 255, 0.08);
    --overlay-rgb: 255, 255, 255;

    /* Threshold Colors */
    --status-normal: #10B981;
    --status-restricted: #F59E0B;
    --status-critical: #EF4444;

    /* Layout */
    --sidebar-width: 260px;

    /* Boletim "Painel de Escala Portuária" (port berth-status board) — scoped
       to the boletim card only, does not touch the rest of the dashboard's
       token system above. Two lit states only (amber/red); normal is a dim,
       quiet, deliberately UN-lit gray-green, not the bright --status-normal
       green used elsewhere — the board should look boring when nothing is
       wrong and alarming when something is. */
    --board-bg-top: #1b1d19;
    --board-bg-bottom: #131511;
    --board-steel: #4a4d45;
    --board-rivet: #5c5f56;
    --board-rule: rgba(255, 255, 255, 0.07);
    /* Lightened from an initial #4b5d53 — that read as appropriately "quiet"
       but only hit 2.55:1 contrast against the card's dark ground, well under
       WCAG AA (4.5:1) for the normal-state text that's the MOST common state
       (the river usually isn't in crisis). Read mode's own tiebreak rule is
       comprehension over aesthetic purity — this still reads as dim/muted
       next to the saturated amber/red, just legible. */
    --board-unlit: #7d9186;
    --board-unlit-dim: #38443d;
    --board-lit-amber: #f5a623;
    --board-lit-red: #e0392b;
    --board-hazard-yellow: #f5c518;
}

/* Light Theme Overrides */
:root[data-theme="light"] {
    --supporte-dark-grey: #FFFFFF;
    --supporte-bg: #F3F4F6;
    --card-bg: #FFFFFF;
    --text-primary: #1A1D23;
    --text-secondary: #58595B;
    --border-color: #E2E8F0;
    --overlay-rgb: 15, 18, 24;
    --supporte-bg-glow: #FFFFFF;
}

/* Typography Hierarchy - Supporte Brand Guidelines */
h1, h2, h3, h4, h5, h6,
.boletim-brand-name,
.boletim-card-header,
.situacao-cota-val,
.situacao-label,
.evolucao-time,
.footer-card-title,
.kpi-title,
.kpi-value {
    font-family: var(--font-heading);
}

body, p, span, td, th {
    font-family: var(--font-body);
}

code, pre, .situacao-footer, .footer-card-sub, .boletim-edition-tag, .sub-tag {
    font-family: var(--font-mono);
}

/* Base Styles */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

html, body {
    height: 100%;
    max-height: 100vh;
    overflow: hidden;
}

body {
    font-family: 'Fira Sans', sans-serif;
    /* Volumetric radial dark gradient for subtle depth */
    background: radial-gradient(circle at 60% 40%, var(--supporte-bg-glow, #202329) 0%, var(--supporte-bg) 100%);
    color: var(--text-primary);
    height: 100vh;
    display: flex;
    overflow: hidden;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* Sidebar Layout */
aside.sidebar {
    width: var(--sidebar-width);
    background-color: var(--supporte-dark-grey);
    border-right: 1px solid rgba(var(--overlay-rgb), 0.02);
    display: flex;
    flex-direction: column;
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    z-index: 100;
    box-shadow: 10px 0 30px rgba(0, 0, 0, 0.2);
}

aside.sidebar .logo-container {
    padding: 35px 24px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-bottom: 1px solid rgba(var(--overlay-rgb), 0.02);
}

/* Styled specifically for square LogoPP2.png aspect ratio */
aside.sidebar .logo-container img {
    max-height: 70px;
    max-width: 70px;
    height: auto;
    object-fit: contain;
    border-radius: 12px;
    transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}

aside.sidebar .logo-container img:hover {
    transform: scale(1.08) rotate(3deg);
}

aside.sidebar nav {
    flex: 1;
    padding: 30px 16px;
}

aside.sidebar nav ul {
    list-style: none;
}

aside.sidebar nav ul li {
    margin-bottom: 6px;
}

aside.sidebar nav ul li a {
    display: flex;
    align-items: center;
    padding: 12px 16px;
    color: var(--text-secondary);
    text-decoration: none;
    font-weight: 500;
    font-size: 0.9rem;
    border-radius: 8px;
    border: 1px solid transparent;
    transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

aside.sidebar nav ul li a svg {
    margin-right: 12px;
    width: 20px;
    height: 20px;
    stroke: currentColor;
    fill: none;
    stroke-width: 2;
    transition: transform 0.2s ease;
}

aside.sidebar nav ul li a:hover {
    color: var(--text-primary);
    background-color: rgba(var(--overlay-rgb), 0.015);
    border-color: rgba(var(--overlay-rgb), 0.03);
}

aside.sidebar nav ul li a.active {
    color: var(--text-primary);
    background: rgba(244, 121, 32, 0.06);
    border: 1px solid rgba(244, 121, 32, 0.18);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

aside.sidebar nav ul li a.active svg {
    transform: scale(1.05);
    stroke: var(--supporte-orange);
}

/* Micro-interaction on pressed click */
aside.sidebar nav ul li a:active {
    transform: scale(0.97);
}

aside.sidebar .sidebar-footer {
    padding: 24px;
    border-top: 1px solid rgba(var(--overlay-rgb), 0.02);
    font-size: 0.78rem;
    color: var(--text-secondary);
    text-align: center;
    background: rgba(0, 0, 0, 0.05);
}

/* Theme Toggle Button */
.theme-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    width: 100%;
    padding: 10px 12px;
    margin-bottom: 16px;
    background: rgba(var(--overlay-rgb), 0.03);
    border: 1px solid var(--border-color);
    border-radius: 8px;
    color: var(--text-secondary);
    font-family: inherit;
    font-size: 0.8rem;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.2s ease;
}

.theme-toggle:hover {
    color: var(--text-primary);
    background: rgba(var(--overlay-rgb), 0.06);
    border-color: rgba(244, 121, 32, 0.18);
}

.theme-toggle svg {
    width: 15px;
    height: 15px;
    stroke: currentColor;
}

.theme-toggle .icon-sun { display: none; }
.theme-toggle .icon-moon { display: block; }

:root[data-theme="light"] .theme-toggle .icon-sun { display: block; }
:root[data-theme="light"] .theme-toggle .icon-moon { display: none; }

/* Main Content Layout */
main.content {
    margin-left: var(--sidebar-width);
    flex: 1;
    height: 100vh;
    max-height: 100vh;
    padding: 20px 32px;
    background: transparent;
    max-width: 1800px;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    box-sizing: border-box;
    /* Flex items default to min-width:auto, which lets wide content (charts,
       tables) blow the track out past the viewport. Force shrink-to-fit. */
    min-width: 0;
}

/* Dashboard View container */
.dashboard-view {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 0;
    overflow: hidden;
}

/* This view's content is taller than a short viewport can show, and it has no
   charts to shrink. Scroll it rather than clipping the last card. */
#view-prognosticos {
    overflow-y: auto;
}

/* Header */
header.dashboard-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 12px;
    padding-bottom: 8px;
    border-bottom: 1px solid rgba(var(--overlay-rgb), 0.02);
}

header.dashboard-header h1 {
    font-size: 1.8rem;
    font-weight: 700;
    letter-spacing: -0.025em;
    text-wrap: balance;
    background: linear-gradient(135deg, #FFFFFF 0%, #B9BDC7 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
}

header.dashboard-header .meta {
    display: flex;
    align-items: center;
    gap: 16px;
}

header.dashboard-header .last-updated {
    font-size: 0.82rem;
    color: var(--text-secondary);
    background: rgba(var(--overlay-rgb), 0.01);
    padding: 8px 14px;
    border-radius: 8px;
    border: 1px solid var(--border-color);
    letter-spacing: 0.2px;
}

.btn-refresh {
    background: rgba(var(--overlay-rgb), 0.03);
    color: var(--text-primary);
    border: 1px solid rgba(var(--overlay-rgb), 0.08);
    padding: 8px 16px;
    border-radius: 8px;
    font-weight: 500;
    font-size: 0.82rem;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 8px;
    transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

.btn-refresh:hover {
    background: rgba(var(--overlay-rgb), 0.06);
    border-color: rgba(244, 121, 32, 0.4);
    transform: translateY(-1px);
}

.btn-refresh:active {
    transform: translateY(0) scale(0.97);
}

.btn-refresh svg {
    stroke: var(--text-secondary);
    transition: transform 0.3s ease, stroke 0.2s ease;
}

.btn-refresh:hover svg {
    stroke: var(--supporte-orange);
    transform: rotate(30deg);
}

/* Volumetric Alert Banner (Glassmorphism Warnings) */
.alert-banner {
    display: flex;
    align-items: center;
    padding: 18px 24px;
    border-radius: 10px;
    margin-bottom: 35px;
    font-weight: 500;
    gap: 16px;
    display: none;
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    animation: reveal 0.5s ease-out both;
}

.alert-banner.warning {
    background: rgba(245, 158, 11, 0.05);
    border: 1px solid rgba(245, 158, 11, 0.2);
    color: var(--status-restricted);
    box-shadow: 0 8px 24px rgba(245, 158, 11, 0.03);
}

.alert-banner.critical {
    background: rgba(239, 68, 68, 0.05);
    border: 1px solid rgba(239, 68, 68, 0.2);
    color: var(--status-critical);
    box-shadow: 0 8px 24px rgba(239, 68, 68, 0.03);
}

/* KPI Cards Grid */
.kpi-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 12px;
    margin-bottom: 12px;
}

/* .boletim is a flex column with its own gap already — the base .kpi-grid's
   own margin-bottom would double up spacing between it and the next card. */
/* display:grid here (even with a fixed repeat(4,1fr) and an explicit
   width:100%) rendered unreliably in html2canvas's offscreen clone — cards
   3/4 silently vanished, then the whole section collapsed to zero height
   once width:100% was added, while every other section on this same card
   (all flexbox) exported fine. Every export-facing layout in this project
   uses flexbox for exactly this reason; overriding display to match instead
   of fighting CSS Grid's html2canvas support further. */
.boletim-kpi-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    margin-bottom: 0;
    width: 100%;
}

.boletim-kpi-grid .kpi-card {
    flex: 1 1 170px;
    min-width: 0;
    /* .kpi-card has a staggered entrance "reveal" animation (fade/slide-in,
       up to 0.05-0.2s delay + 0.5s duration) meant for the dashboard's first
       page load. The sidebar-hide reflow done right before html2canvas
       capture appears to restart it, so cards with a longer delay were still
       mid-fade (or not yet started) at capture time — ghosted or entirely
       invisible in the real exported file, worse for later cards, matching
       exactly what was observed. A report snapshot doesn't need a load
       animation anyway; disabling it removes the whole timing dependency. */
    animation: none !important;
}

/* Glassmorphism Volumetric Cards */
.kpi-card, .chart-card, .stats-card {
    background-color: var(--card-bg);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    border: 1px solid var(--border-color);
    border-radius: 12px;
    padding: 12px 16px;
    position: relative;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.25), 
                inset 0 1px 1px rgba(var(--overlay-rgb), 0.04); /* Edge refraction shadow */
    transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
}

.chart-card {
    padding: 16px 12px 10px 12px !important;
}

/* Cards are flex columns so their chart/table body can absorb the leftover
   height instead of the chart sitting at a fixed size inside a stretched card. */
.chart-card, .stats-card {
    display: flex;
    flex-direction: column;
    min-height: 0;
    min-width: 0;
}

.kpi-card {
    min-width: 0;
}

/* Grid/flex children default to min-*:auto and refuse to shrink below their
   content, which is what pushes charts past the card and off screen. */
.dashboard-grid > *,
.stacked-charts > * {
    min-width: 0;
    min-height: 0;
}

/* Grid children already stretch to the row height. Flex-column children do not:
   they size to content, so a stacked chart card would collapse to its header
   and leave the rest of the view empty. Split the height evenly instead. */
.stacked-charts > * {
    flex: 1 1 0;
}

/* Chart container and its skeleton loader both fill the card body. Heights
   come from the flex chain, never from hardcoded pixels. */
.chart-body,
.chart-loader {
    flex: 1 1 0;
    min-height: 0;
    width: 100%;
}

/* ApexCharts writes an inline min-height on its container matching whatever it
   last rendered at. That ratchets upward: the chart grows with the viewport
   (or on entering fullscreen) but can never shrink back, because the inline
   floor outranks our stylesheet. !important is the only way to beat it. */
.chart-body {
    min-height: 0 !important;
}

/* Tables can outgrow the card on data-heavy years; scroll them instead of
   stretching the row and starving the paired chart. */
.stats-card {
    overflow-y: auto;
}



/* Spotlight Glowing Border and Tinted Shadows on Hover */
.kpi-card:hover, .chart-card:hover, .stats-card:hover {
    transform: translateY(-2px);
    border-color: rgba(244, 121, 32, 0.25);
    box-shadow: 0 12px 30px rgba(0, 0, 0, 0.35), 
                inset 0 1px 1px rgba(var(--overlay-rgb), 0.04);
}

.kpi-card .card-title {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.8px;
    margin-bottom: 14px;
}

.kpi-card .card-value {
    font-size: 2.3rem;
    font-weight: 700;
    color: var(--text-primary);
    line-height: 1.1;
    display: flex;
    align-items: baseline;
    gap: 6px;
    font-variant-numeric: tabular-nums; /* Tabular numbers for clean numeric layout */
    letter-spacing: -0.5px;
    white-space: nowrap;
}

.kpi-card .card-value span.unit {
    font-size: 1.15rem;
    color: var(--text-secondary);
    font-weight: 500;
}

.kpi-card .card-meta {
    margin-top: 14px;
    font-size: 0.82rem;
    color: var(--text-secondary);
    display: flex;
    align-items: center;
    gap: 6px;
}

/* Small caption under a Status badge naming the real number it was compared
   against (e.g. "Média 2022-2025: -8,4 cm/dia") — the badge word alone
   ("ACIMA DA MÉDIA") asserts a comparison without showing it; this makes
   the comparison itself checkable at a glance. */
.kpi-card .card-ref-note {
    margin-top: 5px;
    font-size: 0.68rem;
    color: var(--text-secondary);
    opacity: 0.75;
}

/* Badges */
.badge {
    display: inline-block;
    padding: 4px 8px;
    border-radius: 5px;
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.3px;
    white-space: nowrap;
}

.badge.normal {
    background: rgba(16, 185, 129, 0.08);
    color: var(--status-normal);
    border: 1px solid rgba(16, 185, 129, 0.15);
}

.badge.restricted {
    background: rgba(245, 158, 11, 0.08);
    color: var(--status-restricted);
    border: 1px solid rgba(245, 158, 11, 0.15);
}

.badge.critical {
    background: rgba(239, 68, 68, 0.08);
    color: var(--status-critical);
    border: 1px solid rgba(239, 68, 68, 0.15);
}

.trend-arrow {
    display: inline-flex;
    align-items: center;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.trend-arrow.up { color: var(--status-normal); }
.trend-arrow.down { color: var(--status-critical); }
.trend-arrow.stable { color: var(--text-secondary); }

.dashboard-grid {
    display: grid;
    grid-template-columns: 2.3fr 1fr;
    gap: 16px;
    margin-bottom: 0;
    align-items: stretch;
    flex: 1;
    min-height: 0;
}

.dashboard-grid.equal-cols {
    grid-template-columns: 1fr 1fr;
}

.stacked-charts {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin-bottom: 0;
    flex: 1;
    min-height: 0;
}

@media (max-width: 1200px) {
    .dashboard-grid, .dashboard-grid.equal-cols {
        grid-template-columns: 1fr;
    }

    /* Once the grid collapses to a single column, chart and table stack
       vertically and cannot both fit one screen height. Splitting the leftover
       space evenly crushes the charts to ~100px, so scroll the view instead and
       give every chart a usable floor. */
    .dashboard-view {
        overflow-y: auto;
    }

    .dashboard-grid,
    .stacked-charts {
        flex: 0 0 auto;
    }

    .dashboard-grid > .chart-card,
    .stacked-charts > .chart-card {
        min-height: 340px;
    }

    /* Cards grow with the scrolling page here; no inner scrollbar needed. */
    .stats-card {
        overflow-y: visible;
    }
}

.chart-card .card-header, .stats-card h2 {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 12px;
    flex-shrink: 0;
    gap: 12px;
}

.card-header-badges {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-shrink: 0;
}

/* Boletim-only: at narrower card widths (the boletim view is responsive,
   unlike the fixed-width html2canvas export), two badges sharing the header
   row with a long title left too little room for the title, wrapping it
   mid-word ("...Cota por Dia do / Ano"). flex-wrap here lets the badge group
   drop to its own line below the title instead of squeezing it — scoped to
   #view-boletim so it doesn't change header wrapping on the main dashboard's
   own chart-cards, which share this same .card-header class. */
#view-boletim .chart-card .card-header {
    flex-wrap: wrap;
    row-gap: 6px;
}

.chart-card .card-header h2, .stats-card h2 {
    font-size: 1.15rem;
    font-weight: 600;
    letter-spacing: -0.2px;
    color: var(--text-primary);
}

/* Table styling with tabular numbers */
table.stats-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.85rem;
    text-align: left;
}

table.stats-table th {
    color: var(--text-secondary);
    font-weight: 600;
    padding: 12px 8px;
    border-bottom: 1px solid rgba(var(--overlay-rgb), 0.03);
    text-transform: uppercase;
    font-size: 0.72rem;
    letter-spacing: 0.8px;
}

table.stats-table td {
    padding: 14px 8px;
    border-bottom: 1px solid rgba(var(--overlay-rgb), 0.015);
    color: var(--text-primary);
    font-variant-numeric: tabular-nums; /* Align data columns vertically */
}

table.stats-table tr:last-child td {
    border-bottom: none;
}

table.stats-table tr:hover td {
    background-color: rgba(var(--overlay-rgb), 0.005);
}

table.stats-table td .date-subtext {
    display: block;
    font-size: 0.75rem;
    color: var(--text-secondary);
    margin-top: 3px;
    font-weight: 400;
}

/* Full Width Section */
.full-width-section {
    margin-bottom: 35px;
}

/* Spinner */
.flex-center {
    display: flex;
    justify-content: center;
    align-items: center;
}

.spinner {
    width: 38px;
    height: 38px;
    border: 3px solid rgba(244, 121, 32, 0.06);
    border-radius: 50%;
    border-top-color: var(--supporte-orange);
    animation: spin 0.8s cubic-bezier(0.5, 0, 0.5, 1) infinite;
}

@keyframes spin {
    to { transform: rotate(360deg); }
}

.no-data {
    color: var(--text-secondary);
    font-size: 0.9rem;
    padding: 50px 0;
    text-align: center;
    font-style: italic;
}

/* News card loading skeleton (Destaques) — mirrors .news-card sizing so the
   real cards don't pop/reflow the layout when data arrives. */
.news-card-skeleton {
    background-color: var(--card-bg);
    border: 1px solid var(--border-color);
    border-radius: 12px;
    padding: 16px;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.news-card-skeleton .skeleton-bar {
    border-radius: 8px;
}

.news-card-skeleton .skeleton-bar.image {
    height: 120px;
}

.news-card-skeleton .skeleton-bar.line {
    height: 12px;
}

.news-card-skeleton .skeleton-bar.line.short {
    width: 55%;
}

.skeleton-lines {
    display: flex;
    flex-direction: column;
    gap: 10px;
    flex: 1;
}

/* Mirror the real lead card's layout so the skeleton doesn't reflow the
   moment real data replaces it — see .destaques-lead in the news-card
   section below. */
.destaques-lead-skeleton .skeleton-bar.image {
    height: 220px;
}

@container (min-width: 560px) {
    .destaques-lead-skeleton {
        flex-direction: row;
        align-items: center;
        gap: 24px;
    }

    .destaques-lead-skeleton .skeleton-bar.image {
        width: 320px;
        height: 220px;
        flex-shrink: 0;
    }
}

.clipping-empty-state {
    grid-column: 1 / -1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    padding: 50px 20px;
    text-align: center;
    color: var(--text-secondary);
}

.clipping-empty-state svg {
    color: var(--supporte-orange);
    opacity: 0.5;
}

.clipping-empty-state p {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--text-primary);
    margin: 0;
}

.clipping-empty-state span {
    font-size: 0.8rem;
}

/* Cinematic Entry Reveal Animations (Strategic Omission Upgrades) */
.kpi-card {
    animation: reveal 0.5s cubic-bezier(0.16, 1, 0.3, 1) both;
}
.kpi-grid div:nth-child(1) { animation-delay: 0.05s; }
.kpi-grid div:nth-child(2) { animation-delay: 0.1s; }
.kpi-grid div:nth-child(3) { animation-delay: 0.15s; }
.kpi-grid div:nth-child(4) { animation-delay: 0.2s; }

.dashboard-grid section:nth-child(1) {
    animation: reveal 0.6s cubic-bezier(0.16, 1, 0.3, 1) both;
    animation-delay: 0.25s;
}
.dashboard-grid section:nth-child(2) {
    animation: reveal 0.6s cubic-bezier(0.16, 1, 0.3, 1) both;
    animation-delay: 0.3s;
}

.full-width-section {
    animation: reveal 0.7s cubic-bezier(0.16, 1, 0.3, 1) both;
    animation-delay: 0.35s;
}

@keyframes reveal {
    from {
        opacity: 0;
        transform: translateY(15px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

/* Skeleton Loader Component */
.skeleton-loader {
    position: relative;
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    padding: 10px 5px;
    overflow: hidden;
}

.skeleton-bar {
    background: rgba(var(--overlay-rgb), 0.04);
    border-radius: 4px;
    position: relative;
    overflow: hidden;
}

.skeleton-bar::after {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: linear-gradient(90deg, transparent, rgba(var(--overlay-rgb), 0.05), transparent);
    transform: translateX(-100%);
    animation: shimmer 1.5s infinite;
}

.skeleton-grid {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    flex: 1;
    width: 100%;
    padding-top: 15px;
    gap: 12px;
}

.skeleton-col {
    flex: 1;
    background: linear-gradient(180deg, rgba(var(--overlay-rgb), 0.03) 0%, rgba(var(--overlay-rgb), 0.005) 100%);
    border-radius: 4px 4px 0 0;
    position: relative;
    overflow: hidden;
}

.skeleton-col::after {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: linear-gradient(90deg, transparent, rgba(var(--overlay-rgb), 0.03), transparent);
    transform: translateX(-100%);
    animation: shimmer 1.5s infinite;
}

@keyframes shimmer {
    100% {
        transform: translateX(100%);
    }
}

/* ApexCharts Premium Tooltip Glassmorphism Customization */
.apexcharts-canvas .apexcharts-tooltip {
    background: var(--card-bg) !important;
    backdrop-filter: blur(12px) !important;
    -webkit-backdrop-filter: blur(12px) !important;
    border: 1px solid rgba(var(--overlay-rgb), 0.08) !important;
    border-radius: 8px !important;
    box-shadow: 0 10px 25px rgba(0, 0, 0, 0.45) !important;
    font-family: 'Fira Sans', sans-serif !important;
    padding: 0 !important;
    color: var(--text-primary) !important;
}

.apexcharts-canvas .apexcharts-tooltip .apexcharts-tooltip-title {
    background: rgba(0, 0, 0, 0.15) !important;
    border-bottom: 1px solid rgba(var(--overlay-rgb), 0.05) !important;
    font-weight: 600 !important;
    font-size: 0.75rem !important;
    letter-spacing: 0.5px !important;
    text-transform: uppercase !important;
    color: var(--text-secondary) !important;
    padding: 8px 12px !important;
    margin-bottom: 0 !important;
}

.apexcharts-canvas .apexcharts-tooltip .apexcharts-tooltip-series-group {
    padding: 8px 12px !important;
    display: flex !important;
    align-items: center !important;
}

.apexcharts-canvas .apexcharts-tooltip .apexcharts-tooltip-text {
    font-size: 0.8rem !important;
    font-weight: 500 !important;
    color: var(--text-primary) !important;
}

/* Leaner ApexCharts Toolbar & Reset Button Customization */
.apexcharts-canvas .apexcharts-toolbar {
    top: 5px !important;
    right: 10px !important;
    opacity: 0.25 !important;
    transition: opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1) !important;
    display: flex !important;
    align-items: center !important;
    gap: 2px !important;
}

.apexcharts-canvas:hover .apexcharts-toolbar {
    opacity: 0.75 !important;
}

.apexcharts-canvas .apexcharts-toolbar:hover {
    opacity: 1 !important;
}

/* Individual Toolbar Icon Containers */
.apexcharts-canvas .apexcharts-toolbar div {
    width: 20px !important;
    height: 20px !important;
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
    border-radius: 4px !important;
    background: transparent !important;
    border: 1px solid transparent !important;
    transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1) !important;
    cursor: pointer !important;
}

/* Hover effect for the icon container */
.apexcharts-canvas .apexcharts-toolbar div:hover {
    background: rgba(244, 121, 32, 0.08) !important;
    border-color: rgba(244, 121, 32, 0.25) !important;
}

/* Make the SVG icon smaller and cleaner */
.apexcharts-canvas .apexcharts-toolbar svg,
.apexcharts-canvas .apexcharts-toolbar .apexcharts-icon {
    width: 13px !important;
    height: 13px !important;
    fill: var(--text-secondary) !important;
    stroke: var(--text-secondary) !important;
    stroke-width: 0 !important;
    transition: fill 0.2s ease, stroke 0.2s ease, transform 0.2s ease !important;
}

/* Hover style for the icon itself */
.apexcharts-canvas .apexcharts-toolbar div:hover svg,
.apexcharts-canvas .apexcharts-toolbar div:hover .apexcharts-icon {
    fill: var(--supporte-orange) !important;
    stroke: var(--supporte-orange) !important;
    transform: scale(1.08);
}

/* Prevent annotation label cut-off and clipping at boundaries */
.apexcharts-canvas svg {
    overflow: visible !important;
}

/* ==================================================== */
/* NEWS CLIPPING TAB STYLING */
/* ==================================================== */

.clipping-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 24px;
    gap: 20px;
    flex-wrap: wrap;
    animation: reveal 0.5s cubic-bezier(0.16, 1, 0.3, 1) both;
}

.clipping-title-container h2 {
    font-size: 1.8rem;
    font-weight: 700;
    letter-spacing: -0.025em;
    background: linear-gradient(135deg, #FFFFFF 0%, #B9BDC7 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
}

/* Light theme: swap the white title gradient for a dark one (text-fill is transparent) */
:root[data-theme="light"] header.dashboard-header h1,
:root[data-theme="light"] .clipping-title-container h2 {
    background: linear-gradient(135deg, #1A1D23 0%, #58595B 100%);
    -webkit-background-clip: text;
}

.clipping-filters {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.clipping-mode-toggle,
.clipping-category-filters {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}

.clipping-filter-divider {
    width: 1px;
    height: 22px;
    background: var(--border-color);
    flex-shrink: 0;
}

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.filter-btn {
    background: rgba(var(--overlay-rgb), 0.03);
    color: var(--text-secondary);
    border: 1px solid rgba(var(--overlay-rgb), 0.05);
    padding: 8px 16px;
    border-radius: 8px;
    font-weight: 500;
    font-size: 0.8rem;
    cursor: pointer;
    transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

.filter-btn:hover {
    color: var(--text-primary);
    background: rgba(var(--overlay-rgb), 0.06);
    border-color: rgba(244, 121, 32, 0.25);
}

.filter-btn.active {
    color: var(--text-primary);
    background: rgba(244, 121, 32, 0.12);
    border: 1px solid rgba(244, 121, 32, 0.35);
    box-shadow: 0 4px 12px rgba(244, 121, 32, 0.08);
}

.filter-btn:active {
    transform: scale(0.96);
}

/* Keyboard focus: visible ring on every interactive element */
.filter-btn:focus-visible,
.news-card:focus-visible,
.nav-link:focus-visible,
button:focus-visible,
a:focus-visible {
    outline: 2px solid var(--supporte-orange);
    outline-offset: 2px;
}

.acervo-scroll-container {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding-right: 6px;
    height: 100%;
}

.acervo-scroll-container::-webkit-scrollbar {
    width: 6px;
}

.acervo-scroll-container::-webkit-scrollbar-track {
    background: rgba(var(--overlay-rgb), 0.02);
    border-radius: 4px;
}

.acervo-scroll-container::-webkit-scrollbar-thumb {
    background: rgba(244, 121, 32, 0.3);
    border-radius: 4px;
}

.acervo-scroll-container::-webkit-scrollbar-thumb:hover {
    background: var(--supporte-orange);
}

/* Clipping Hero Session (One-Pager Top View) */
.clipping-hero-session {
    margin-bottom: 40px;
    padding-bottom: 24px;
    border-bottom: 1px solid rgba(var(--overlay-rgb), 0.05);
}

.clipping-session-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    margin-bottom: 16px;
}

.session-badge {
    display: inline-block;
    padding: 4px 10px;
    border-radius: 6px;
    background: rgba(244, 121, 32, 0.1);
    border: 1px solid rgba(244, 121, 32, 0.25);
    color: var(--supporte-orange);
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.6px;
    margin-bottom: 6px;
}

.clipping-session-header h2 {
    font-size: 1.4rem;
    font-weight: 700;
    color: var(--text-primary);
    letter-spacing: -0.3px;
}

.clipping-count-badge {
    font-size: 0.8rem;
    color: var(--text-secondary);
    background: rgba(var(--overlay-rgb), 0.02);
    padding: 6px 14px;
    border-radius: 20px;
    border: 1px solid var(--border-color);
}

/* 3-Card Hero Grid */
.clipping-hero-grid {
    display: grid;
    grid-template-columns: 1.6fr 1fr 1fr;
    gap: 18px;
    margin-bottom: 18px;
}

.clipping-hero-grid .hero-main-card .news-card-image {
    height: 220px;
}

.clipping-hero-grid .hero-secondary-card .news-card-image {
    height: 140px;
}

@media (max-width: 1200px) {
    .clipping-hero-grid {
        grid-template-columns: 1fr;
    }
}

.scroll-indicator-bar {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    padding: 10px 18px;
    background: rgba(var(--overlay-rgb), 0.015);
    border: 1px solid var(--border-color);
    border-radius: 30px;
    font-size: 0.8rem;
    color: var(--text-secondary);
    font-weight: 500;
    margin-top: 10px;
}

.scroll-indicator-bar svg {
    color: var(--supporte-orange);
    animation: bounce 2s infinite;
}

@keyframes bounce {
    0%, 20%, 50%, 80%, 100% { transform: translateY(0); }
    40% { transform: translateY(4px); }
    60% { transform: translateY(2px); }
}

.news-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 16px;
    margin-top: 10px;
    margin-bottom: 24px;
    /* Don't stretch every card to match the tallest one in its row — most
       articles have no real summary text, so a stretched card just becomes
       a box with a hollow gap in the middle. Let each card be as tall as
       its own content actually needs. */
    align-items: start;
}

/* Supporting-row cards: fluid below 1200px, 4 fixed columns only when they
   fit — the lead card lives outside this grid entirely (#destaques-lead-slot
   above), so this only ever holds uniform, non-spanning cards. No item here
   spans multiple columns, so there's no gap-filling to worry about. */
#container-destaques-news {
    flex: 1;
    min-height: 0;
    margin-top: 0;
    margin-bottom: 0;
    overflow-y: auto;
}

@media (min-width: 1200px) {
    #container-destaques-news {
        grid-template-columns: repeat(4, 1fr);
    }
}

/* Below 1200px the bento wraps to 3+ rows; a fixed-height grid would crush
   them evenly and clip titles. Give rows their natural height and scroll. */
@media (max-width: 1199px) {
    #container-destaques-news {
        flex: 0 0 auto;
        overflow-y: visible;
    }

    #sub-view-highlights {
        overflow-y: auto;
    }
}

.news-card {
    background-color: var(--card-bg);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    border: 1px solid var(--border-color);
    border-radius: 12px;
    padding: 16px;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    gap: 10px;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.25), 
                inset 0 1px 1px rgba(var(--overlay-rgb), 0.04);
    transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
    position: relative;
    overflow: hidden;
    text-decoration: none;
    animation: reveal 0.6s cubic-bezier(0.16, 1, 0.3, 1) both;
}

.news-card:hover {
    transform: translateY(-3px);
    border-color: rgba(244, 121, 32, 0.3);
    box-shadow: 0 14px 35px rgba(0, 0, 0, 0.35),
                inset 0 1px 1px rgba(var(--overlay-rgb), 0.04);
}

#destaques-lead-slot {
    margin-bottom: 20px;
    /* A viewport-width media query doesn't know the sidebar exists — at a
       viewport width where it "should" fit, the actual space left over
       after the 260px sidebar can be much narrower. Query the real
       available width instead. */
    container-type: inline-size;
}

.news-category-badge {
    padding: 3px 6px;
    border-radius: 5px;
    font-weight: 700;
    text-transform: uppercase;
    font-size: 0.7rem;
    letter-spacing: 0.5px;
}

.category-clima {
    background: rgba(59, 130, 246, 0.08);
    color: #60A5FA;
    border: 1px solid rgba(59, 130, 246, 0.15);
}

.category-regula {
    background: rgba(139, 92, 246, 0.08);
    color: #C084FC;
    border: 1px solid rgba(139, 92, 246, 0.15);
}

.category-industria {
    background: rgba(236, 72, 153, 0.08);
    color: #F472B6;
    border: 1px solid rgba(236, 72, 153, 0.15);
}

.category-logistica {
    background: rgba(244, 121, 32, 0.08);
    color: #FB923C;
    border: 1px solid rgba(244, 121, 32, 0.15);
}

.news-source {
    color: var(--text-secondary);
    font-weight: 500;
}

.news-title {
    font-size: 0.95rem;
    font-weight: 600;
    line-height: 1.35;
    color: var(--text-primary);
    text-wrap: balance;
    margin: 0;
    transition: color 0.2s ease;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.news-card:hover .news-title {
    color: var(--supporte-orange);
}

.news-summary {
    font-size: 0.78rem;
    line-height: 1.5;
    color: var(--text-secondary);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    margin: 0;
}

.news-bottom-row {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    flex-wrap: wrap;
    gap: 8px;
    font-size: 0.75rem;
    color: var(--text-secondary);
    border-top: 1px solid rgba(var(--overlay-rgb), 0.02);
    padding-top: 8px;
    margin-top: auto;
}

.news-meta-group {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    font-variant-numeric: tabular-nums;
}

.news-read-more {
    display: flex;
    align-items: center;
    gap: 4px;
    font-weight: 600;
    color: var(--supporte-orange);
    transition: transform 0.2s ease;
}

.news-card:hover .news-read-more {
    transform: translateX(3px);
}

/* Destaques lead card: standalone, full-width, its own row — the layout
   itself says "read this one first" instead of a badge saying it. Never
   shares a row with another card, so it can never leave a gap next to or
   below itself (the bug the last two rounds kept re-introducing). */
.destaques-lead {
    flex-direction: column;
    padding: 20px;
}

.destaques-lead .news-card-image,
.destaques-lead .news-card-fallback-image {
    height: 220px;
    margin-bottom: 0;
}

.destaques-lead-content {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.destaques-lead-title {
    font-size: 1.3rem;
    -webkit-line-clamp: 2;
}

.destaques-lead-summary {
    font-size: 0.9rem;
    line-height: 1.5;
    color: var(--text-secondary);
    margin: 0;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.destaques-lead-byline {
    font-size: 0.8rem;
    color: var(--text-secondary);
    margin: 0;
}

.destaques-lead-reason {
    color: var(--supporte-orange);
    font-weight: 600;
}

@container (min-width: 560px) {
    .destaques-lead {
        flex-direction: row;
        align-items: center;
        gap: 24px;
    }

    .destaques-lead .news-card-image,
    .destaques-lead .news-card-fallback-image {
        width: 320px;
        height: 220px;
        flex-shrink: 0;
    }

    .destaques-lead-content {
        flex: 1;
    }

    .destaques-lead-title {
        font-size: 1.5rem;
    }
}

/* Thumbnail and Fallback Image Styles */
.news-card-image, .news-card-fallback-image {
    width: 100%;
    height: 120px;
    object-fit: cover;
    border-radius: 8px;
    margin-bottom: 4px;
    border: 1px solid rgba(var(--overlay-rgb), 0.03);
    background: rgba(var(--overlay-rgb), 0.01);
}

.news-card-fallback-image {
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;
    overflow: hidden;
}

.news-card-fallback-image.category-clima {
    background: rgba(59, 130, 246, 0.04);
    border: 1px solid rgba(59, 130, 246, 0.1);
}

.news-card-fallback-image.category-regula {
    background: rgba(139, 92, 246, 0.04);
    border: 1px solid rgba(139, 92, 246, 0.1);
}

.news-card-fallback-image.category-industria {
    background: rgba(236, 72, 153, 0.04);
    border: 1px solid rgba(236, 72, 153, 0.1);
}

.news-card-fallback-image.category-logistica {
    background: rgba(244, 121, 32, 0.04);
    border: 1px solid rgba(244, 121, 32, 0.1);
}

.news-card-fallback-image svg {
    width: 36px;
    height: 36px;
    opacity: 0.25;
    color: var(--supporte-orange);
    transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

.news-card:hover .news-card-fallback-image svg {
    opacity: 0.4;
    transform: scale(1.1) rotate(5deg);
}


/* Prognósticos & Estudos View Styles */
/* Prognósticos & Estudos View Styles */
.risk-matrix-top {
    background-color: var(--card-bg);
    backdrop-filter: blur(16px);
    border: 1px solid var(--border-color);
    border-radius: 12px;
    padding: 16px 20px;
    margin-top: 12px;
    margin-bottom: 16px;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.risk-matrix-header h3 {
    font-size: 1rem;
    font-weight: 700;
    color: var(--text-primary);
    margin: 0;
    letter-spacing: 0.5px;
}

.risk-matrix-grid-top {
    display: grid;
    grid-template-columns: 1fr;
    gap: 20px;
}

@media (min-width: 768px) {
    .risk-matrix-grid-top {
        grid-template-columns: repeat(3, 1fr);
        gap: 32px;
    }
}

.risk-item-top {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.risk-meta-top {
    display: flex;
    justify-content: space-between;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--text-secondary);
}

.risk-val-label {
    font-size: 0.78rem;
    font-weight: 700;
}

.risk-val-label.warning {
    color: var(--supporte-orange);
}

.risk-val-label.critical {
    color: #ef4444;
}

.risk-bar-container {
    height: 8px;
    background: rgba(var(--overlay-rgb), 0.05);
    border-radius: 4px;
    overflow: hidden;
}

.risk-bar {
    height: 100%;
    border-radius: 4px;
}

.risk-bar.critical {
    width: 90%;
    background: linear-gradient(90deg, #f97316 0%, #ef4444 100%);
}

.risk-bar.high {
    width: 75%;
    background: linear-gradient(90deg, #eab308 0%, #f97316 100%);
}

.risk-bar.medium-high {
    width: 60%;
    background: linear-gradient(90deg, #3b82f6 0%, #eab308 100%);
}

.risk-action-bar-top {
    background: rgba(244, 121, 32, 0.04);
    border-left: 3px solid var(--supporte-orange);
    padding: 10px 14px;
    font-size: 0.78rem;
    color: var(--text-primary);
    line-height: 1.4;
    border-radius: 0 4px 4px 0;
    margin-top: 6px;
}

.prognosticos-grid-bottom {
    display: grid;
    grid-template-columns: 1fr;
    gap: 20px;
}

@media (min-width: 768px) {
    .prognosticos-grid-bottom {
        grid-template-columns: repeat(2, 1fr);
        gap: 16px;
        flex: 1;
        min-height: 0;
    }
}

.prog-card {
    background-color: var(--card-bg);
    backdrop-filter: blur(16px);
    border: 1px solid var(--border-color);
    border-radius: 12px;
    padding: 16px;
    transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    gap: 12px;
    min-height: 0;
    flex: 1;
}

.prog-card:hover {
    transform: translateY(-2px);
    border-color: rgba(244, 121, 32, 0.4);
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.2);
}

.prog-card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    border-bottom: 1px solid rgba(var(--overlay-rgb), 0.04);
    padding-bottom: 8px;
}

.prog-lab-info {
    display: flex;
    align-items: center;
    gap: 10px;
}

.prog-lab-icon {
    width: 28px;
    height: 28px;
    background: rgba(244, 121, 32, 0.08);
    border-radius: 6px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--supporte-orange);
    flex-shrink: 0;
}

.prog-lab-icon svg {
    width: 16px;
    height: 16px;
}

.prog-lab-name {
    font-size: 0.88rem;
    font-weight: 700;
    color: var(--text-primary);
}

.prog-badge {
    padding: 2px 6px;
    border-radius: 10px;
    font-size: 0.65rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.3px;
    flex-shrink: 0;
}

.prog-badge.status-critical {
    background-color: rgba(239, 68, 68, 0.12);
    color: #ef4444;
    border: 1px solid rgba(239, 68, 68, 0.2);
}

.prog-badge.status-warning {
    background-color: rgba(245, 158, 11, 0.12);
    color: #f59e0b;
    border: 1px solid rgba(245, 158, 11, 0.2);
}

.prog-badge.status-info {
    background-color: rgba(59, 130, 246, 0.12);
    color: #3b82f6;
    border: 1px solid rgba(59, 130, 246, 0.2);
}

.prog-link {
    font-size: 0.75rem;
    color: var(--text-secondary);
    transition: color 0.2s ease;
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

.prog-link:hover {
    color: var(--supporte-orange);
}

.prog-desc {
    color: var(--text-secondary);
    font-size: 0.75rem;
    line-height: 1.4;
    margin: 0;
}

.prog-forecast-box {
    background: rgba(var(--overlay-rgb), 0.015);
    border-left: 2px solid var(--border-color);
    border-radius: 0 4px 4px 0;
    padding: 8px 12px;
    font-size: 0.75rem;
    color: var(--text-secondary);
    line-height: 1.45;
}

.ai-card-insight {
    font-size: 0.72rem;
    line-height: 1.45;
    padding: 8px 12px;
    border-radius: 6px;
    border-left: 2px solid var(--supporte-orange);
    background: rgba(244, 121, 32, 0.03);
    color: var(--text-primary);
    margin-top: 2px;
    font-style: italic;
}

/* ============================================== */
/* Boletim Semanal (Weekly Report)                 */
/* ============================================== */

.boletim-toolbar {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    margin-bottom: 12px;
}

.boletim {
    width: 820px;
    max-width: 100%;
    margin: 0 auto 30px auto;
    /* Was a fixed-dark gradient (var(--board-bg-top/bottom)) left over from
       the port-board round this card was restarted away from — every child
       (kpi-card, chart-card, badges) already correctly follows the site's
       light/dark theme via var(--card-bg) etc., but this outer wrapper
       didn't, so in light mode its children's theme-correct text rendered
       against a wrapper that never actually switched. Reverted to the same
       theme-aware tokens the dashboard's own cards use. */
    background: var(--card-bg);
    border: 1px solid var(--border-color);
    border-radius: 6px;
    /* O padding do card vive em VARIÁVEIS porque duas peças sangram para fora
       dele com margem negativa (a cabeça e o rodapé). Enquanto eram três
       números soltos, mudar o padding deixava a cabeça desalinhada em silêncio.
       Reduzido de 28px 26px: a faixa "Situação Atual" tem cinco células, e a
       nota da quinta ("projetada: início de out") precisava de 9px a mais de
       largura por célula para caber numa linha em vez de duas. */
    --boletim-pad-y: 20px;
    --boletim-pad-x: 14px;
    padding: var(--boletim-pad-y) var(--boletim-pad-x);
    display: flex;
    flex-direction: column;
    gap: 16px;
    box-shadow: 0 14px 34px rgba(0, 0, 0, 0.3);
}


/* HERO HEADER - v8 PATTERN: dark wordmark strip + flat headline banner w/
   dynamic headline. Bleeds to the .boletim card's own edges (card padding
   is 28px 26px) so it reads as full-width instead of inset; radius matches
   the card's 6px minus its 1px border. Height budget: ~50px topbar + 2px
   rule + 138px banner ≈ 190px total (variant E — grown from the original
   166px so the banner text carries more weight; ~10% of the card's height,
   KPI row still dominates).
   Photo removed per user decision (kept variant E's typography/spacing
   gains). The banner's own gradient fill (see .boletim-hero-photo below)
   is what keeps it reading as a distinct masthead zone instead of
   flattening into the KPI row. */
.boletim-hero-header {
    position: relative;
    margin: calc(-1 * var(--boletim-pad-y)) calc(-1 * var(--boletim-pad-x)) 0;
    border-radius: 5px 5px 0 0;
    overflow: hidden;
    color: #FFFFFF;
}

.boletim-hero-topbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 12px;
    background: linear-gradient(135deg, #1a1c19 0%, #101210 100%);
    padding: 12px 24px;
    border-bottom: 2px solid var(--supporte-orange);
}

/* Inline SVG wordmark (real letterforms as paths, see index.html comment).
   Fixed height + width:auto is safe here (unlike an <img>) since html2canvas
   renders inline <svg> paths directly, not as a raster needing intrinsic size. */
.boletim-wordmark {
    height: 34px;
    width: auto;
    display: block;
}

.boletim-hero-tagline {
    font-size: 0.74rem;
    color: #94A3B8;
    font-weight: 600;
    letter-spacing: 0.6px;
}

/* Photo removed per user decision (kept variant E's typography/spacing
   gains, dropped the photo itself). A flat dark fill made the header
   flatten into an undifferentiated stack with the KPI row below (the
   exact risk the design review flagged), so this keeps a subtle vertical
   gradient — a shade darker than the topbar's diagonal one above it — so
   the band still reads as its own masthead zone via a faint seam, without
   needing a photo to do it. min-height (not fixed) + flex column anchored
   to the bottom: at the card's normal 820px width the headline/lede fit on
   one/two lines and the band sits at ~138px, but if the dashboard's own
   (pre-existing, out of scope) narrow-viewport squeeze forces more text
   wrapping, the band grows to contain it instead of overflowing into the
   KPI cards below. */
.boletim-hero-photo {
    position: relative;
    min-height: 138px;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    background:
        linear-gradient(90deg, #0a0b0c 0%, rgba(10,11,12,0.94) 30%, rgba(10,11,12,0.55) 60%, rgba(10,11,12,0.05) 100%),
        url('../img/river_banner_header_crop.jpg') center 8% / cover no-repeat;
}

.boletim-hero-photo-content {
    position: relative;
    z-index: 2;
    padding: 12px 20px 13px;
}

/* Right-aligned opposite the wordmark in the dark topbar strip — margin-left:
   auto absorbs the row's remaining space so it sits at the far edge instead
   of immediately after the tagline, without needing its own wrapper row. */
.boletim-hero-edition {
    margin: 0 0 0 auto;
    text-align: right;
    font-size: 0.66rem;
    font-weight: 500;
    letter-spacing: 0.2px;
    color: #94A3B8;
    white-space: nowrap;
    opacity: 0.9;
}

.boletim-hero-kicker {
    font-size: 0.76rem;
    font-weight: 700;
    letter-spacing: 0.8px;
    color: var(--supporte-orange);
    text-transform: uppercase;
}

.boletim-hero-headline {
    font-size: 1.4rem;
    font-weight: 800;
    color: #FFFFFF;
    line-height: 1.15;
    margin-top: 3px;
}

.boletim-hero-lede {
    font-size: 0.8rem;
    color: #E2E8F0;
    line-height: 1.35;
    margin: 5px 0 0;
    max-width: 620px;
}







/* CHART LEGEND ROW */
.chart-legend-row {
    display: flex;
    gap: 14px;
    justify-content: center;
    font-family: var(--font-mono);
    font-size: 0.65rem;
    color: var(--text-secondary);
    margin-top: 6px;
}

.leg-item.orange b { color: var(--supporte-orange); }
.leg-item.blue b { color: #3B82F6; }
.leg-item.red b { color: #EF4444; }

.op-bullets-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 7px;
}

.op-bullets-list li {
    font-family: var(--font-body);
    font-size: 0.78rem;
    color: var(--text-secondary);
    line-height: 1.35;
    position: relative;
    padding-left: 14px;
}

.op-bullets-list li::before {
    content: "•";
    color: var(--supporte-alert-orange);
    font-size: 1.2rem;
    position: absolute;
    left: 0;
    top: -2px;
}

.op-bullets-list li strong {
    color: var(--text-primary);
    font-weight: 700;
}

.op-bullets-list li span {
    color: var(--supporte-orange);
    font-family: var(--font-body);
    font-weight: 700;
}

.exec-txt-paragraph {
    font-family: var(--font-body);
    font-size: 0.88rem;
    line-height: 1.45;
    color: var(--text-secondary);
    margin: 0 0 10px 0;
}

.exec-context-list {
    list-style: none;
    margin: 0;
    padding-top: 8px;
    border-top: 1px solid var(--border-color);
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.exec-context-list .exec-txt-paragraph--muted {
    padding-top: 0;
    border-top: none;
    position: relative;
    padding-left: 12px;
}

.exec-context-list .exec-txt-paragraph--muted::before {
    content: "•";
    position: absolute;
    left: 0;
    top: 0;
}

.exec-txt-paragraph--muted {
    font-size: 0.82rem;
    /* Was a fixed rgba(148,163,184,0.75) — only 4.3:1 in dark mode (already
       marginal) and 1.96:1 in light mode (clear AA fail) since it didn't
       adapt to the theme. Theme-aware color + opacity dims proportionally
       in both, same pattern used for the map's dim country labels. Raised
       from 0.85 now that each line is a single short fact rather than a
       multi-line quote — it should read as confidently as the rest of the
       card, not as a footnote. */
    color: var(--text-secondary);
    opacity: 0.95;
    margin: 0;
    padding-top: 8px;
    border-top: 1px solid var(--border-color);
}

/* Clipping Seca window — holds a captured screenshot (img, set at export
   time by captureClippingWindow() in app.js) of the live Destaques tab's
   lead card. The border/radius here is the "window frame"; the image fills
   it edge to edge. */
.boletim-clipping-window {
    border-radius: 8px;
    overflow: hidden;
    border: 1px solid var(--border-color);
}

.boletim-clipping-window img {
    display: block;
    width: 100%;
    height: auto;
}

.badge-sub-alert {
    font-size: 0.65rem;
    font-weight: 700;
    color: var(--status-critical);
    text-transform: none;
}

/* .chart-body's flex:1 1 0 (from the base dashboard styles) needs a
   viewport-stretched ancestor to grow into — the main dashboard has one
   (.dashboard-grid chains flex:1 up to the viewport), but the boletim card's
   own vertical stack sizes to content instead (it needs to grow freely for
   the image export), so flex-grow had nothing to distribute and resolved to
   0. flex:0 0 fixed-basis sidesteps that. Height grew from 230 to 280 to
   reclaim the vertical budget the removed 30-day oscillation strip used to
   occupy, now that the projection lives on this chart directly. */
#chart-boletim-trend {
    flex: 0 0 280px;
    height: 280px;
    width: 100%;
}

/* Three-horizon projection summary strip below the chart — flex row, wraps
   to 3 stacked lines if the card is squeezed narrow rather than truncating. */
.proj-row {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 6px;
    padding-top: 8px;
    border-top: 1px solid var(--border-color);
}

/* Each cell is now its own compact tile — same background/border/radius
   tokens as .kpi-card for visual consistency, just tighter padding since
   three of these sit side by side instead of one per card. */
.proj-cell {
    flex: 1 1 200px;
    min-width: 0;
    background-color: var(--card-bg);
    border: 1px solid var(--border-color);
    border-radius: 10px;
    padding: 8px 10px;
}

/* Mini stat-cell language matching the KPI cards above (label / big value /
   muted source line) instead of a single wrapping prose sentence — same
   information, laid out for scanning instead of reading. Sizes are a notch
   below the KPI cards' since three of these live in one tight row. */
.proj-cell-label {
    font-size: 0.55rem;
    font-weight: 700;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.6px;
}

.proj-cell-value {
    font-family: var(--font-mono);
    font-size: 0.92rem;
    font-weight: 800;
    color: var(--text-primary);
    margin: 2px 0;
    white-space: nowrap;
}

.proj-cell-source {
    font-size: 0.56rem;
    font-family: var(--font-mono);
    color: var(--text-secondary);
    opacity: 0.85;
}

/* Labs demoted from a card block to one compact line — reuses .badge-sub-alert-
   style small text, no border/background box of its own. */
/* Illustrated basin+route map — real geometry (Natural Earth country
   boundaries + actual river/route courses to Belém), uniform-scale
   projection. aspect-ratio MUST match the SVG's own viewBox exactly — a
   mismatch here (this was previously left at the old 400x150 ratio after
   the viewBox grew to 560x258.3) forces the browser's default
   preserveAspectRatio="meet" to letterbox the content inside the box
   instead of filling it, which is what read as "not full-frame". */
.basin-illustrated-map {
    width: 100%;
    height: auto;
    aspect-ratio: 560 / 215;
    display: block;
    border-radius: 4px;
    border: 1px solid var(--border-color);
}

.basin-map-bg {
    fill: var(--card-bg);
}

.basin-country {
    fill: rgba(var(--overlay-rgb), 0.02);
    stroke: rgba(var(--overlay-rgb), 0.15);
    stroke-width: 0.75;
    stroke-linejoin: round;
}

.basin-country-label {
    font-family: var(--font-heading);
    font-size: 7px;
    font-weight: 700;
    letter-spacing: 0.4px;
    fill: var(--text-secondary);
}

.basin-country-label--dim {
    /* Was a fixed rgba(148,163,184,*) — dims correctly in dark mode but is
       too faint (near-invisible) once the map background actually switches
       to white in light mode. opacity on the theme-aware base color dims
       proportionally in either theme instead of baking in one fixed tone. */
    opacity: 0.6;
}


.basin-river-path {
    fill: none;
    stroke: #3ba7c4;
    stroke-width: 2.5;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* Bumped from 1px/0.55 opacity now that the basin-influence band (removed)
   no longer gives these a contrasting backdrop against the raster. */
.basin-tributary {
    fill: none;
    stroke: rgba(59, 167, 196, 0.75);
    stroke-width: 1.3;
    stroke-linecap: round;
}

.basin-compass-ring {
    fill: none;
    stroke: var(--text-secondary);
    stroke-width: 1;
}

.basin-compass-needle {
    fill: var(--supporte-orange);
}

.basin-compass-label {
    font-family: var(--font-heading);
    font-size: 7px;
    font-weight: 800;
    fill: var(--text-secondary);
    text-anchor: middle;
}

.basin-station-dot {
    stroke: var(--card-bg);
    stroke-width: 1.2;
}

/* Gradient fill is set inline (style.fill) in app.js — it's a continuous
   interpolation, not a fixed set of classes, since it encodes a ratio
   against each station's own historical norm rather than a binary
   direction. See hydroGradientColor() there. */

/* Route-destination waypoint (Belém) — neutral, distinct from both the
   trend-colored gauges and the dashed "sem dados" marker (this was never a
   monitoring point to begin with). */
.basin-station-dot--waypoint {
    fill: var(--text-secondary);
    opacity: 0.85;
}

/* No live ANA telemetric gauge for this waypoint — hollow marker, never an
   invented value (this exact fabrication was a P0 in an earlier round). */
.basin-station-dot--no-data {
    fill: none;
    stroke: var(--text-secondary);
    stroke-width: 1.3;
    stroke-dasharray: 1.5 1.5;
    opacity: 0.7;
}

.basin-station-label--nodata {
    opacity: 0.6;
    font-weight: 400;
}

/* Logistics route overlays — brand orange, the one place it earns meaning
   on this map ("our flow"). Distinct dash rhythm per route so the balsas/
   Belém fork and the cabotagem/Atlantic fork stay visually separable where
   they run close together right after the split point. */
.basin-route {
    fill: none;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.basin-route--balsas {
    stroke: var(--supporte-orange);
    stroke-width: 1.8;
    stroke-dasharray: 5 3;
}

/* Distinct hue (not just a dimmer orange) from the balsas route — the two
   forks run close together right after the split point near Gurupá, and a
   near-identical orange made them hard to tell apart at export size. */
.basin-route--cabotagem {
    stroke: #64748B;
    stroke-width: 1.6;
    stroke-dasharray: 1.5 2.5;
}

.basin-station-label {
    font-family: var(--font-body);
    /* Bumped from 6.5px (user: too small to read in the WhatsApp export) —
       this is SVG text sized against the map's own 560×215 viewBox, so it
       scales with the export same as everything else on the card. */
    font-size: 8.5px;
    font-weight: 600;
    fill: var(--text-secondary);
}

.basin-station-label--primary {
    /* Manaus/Belém — the only two stations that get this class — read as
       the map's most important labels, so they carry the biggest bump. */
    font-size: 10.5px;
    font-weight: 800;
    fill: var(--text-primary);
}

/* Per-station live value (set dynamically in app.js from data.stations[] /
   latest_reading — never baked in statically here). */
.basin-station-value {
    font-family: var(--font-mono);
    font-size: 8px;
    font-weight: 700;
    fill: var(--supporte-orange);
    /* Halo branco por baixo do texto (paint-order desenha o traço ANTES do
       preenchimento, logo o traço fica atrás e não engorda a letra).
       Motivo: o basemap ESRI Physical é verde-sálvia claro e o laranja da marca
       sobre ele dá contraste ~2,3:1 — o utilizador disse que já não se lia.
       O halo separa a letra do terreno sem mudar a cor da marca. */
    paint-order: stroke fill;
    stroke: #FFFFFF;
    stroke-width: 2.2;
    stroke-linejoin: round;
    stroke-linecap: round;
}

/* Manaus's own cota — the one figure on this map an exec actually acts on
   (draft/transbordo decisions) — reads bigger than the other stations' the
   same way its name label already does via .basin-station-label--primary. */
#st-val-manaus-map {
    font-size: 10px;
}

/* Baked-once basemap raster (CARTO tiles, stitched offline for this exact
   bbox — see index.html comment). Both variants are always in the markup;
   only the one matching the active theme is shown, same show/hide pattern
   as the sidebar's sun/moon theme-toggle icons. */
.basin-map-raster {
    /* Era 0,4. O raster tem luminância média 12/255, logo mais opacidade deixa a
       área do mapa MAIS escura, não mais clara: medido no DOM ao vivo, a
       luminância média do bloco do mapa passa de 33,8 (a 0,4) para 27,9 (a 0,85).
       A 0,85 o litoral, a ilha de Marajó e a rede de afluentes lêem-se melhor
       contra o fundo do card, que é o que faltava ao mapa: saber onde está a água.
       HONESTIDADE SOBRE A MEDIÇÃO: não consegui demonstrar diferença entre 0,4 e
       0,85 no PNG do html2canvas — dois exports com opacidades diferentes saíram
       com estatísticas idênticas. Ou o html2canvas não honra esta propriedade num
       <image> de SVG, ou o clone dele não recebe a alteração. O valor fica a 0,85
       porque melhora a vista no ecrã e não piora nada no PNG; não confiar neste
       número para explicar o aspecto do PNG.
       O que MUDOU de facto no PNG foi o FICHEIRO — ver "MAPA SEMPRE ESCURO". */
    opacity: 0.85;
}

/* As classes --dark e --light saíram do markup: o mapa tem UMA imagem de fundo
   e é sempre a mesma (ver "MAPA SEMPRE CLARO"). O SVG do mapa só existe num
   sítio — dentro do boletim —, logo estas três regras não tinham mais nada
   para governar. */

.basin-map-attribution {
    font-family: var(--font-body);
    font-size: 5px;
    fill: var(--text-secondary);
    opacity: 0.7;
}

/* Linear legend row — swatch + label pairs on one line. */
/* Two deliberate rows (symbology, then station-status) instead of one flat
   wrapping list — 8 entries in one row wrapped unpredictably (an orphaned
   entry bottom-left, ragged gaps) depending on export width. */
.basin-legend-group {
    margin-top: 8px;
    display: flex;
    flex-direction: column;
    gap: 5px;
}

.basin-legend-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 16px;
    font-size: 0.68rem;
    color: var(--text-secondary);
}

/* All 7 entries on one line (basin band removed, so this fits at 820px) —
   smaller type + tighter gaps than the two-row layout it replaced. */
.basin-legend-row--single {
    flex-wrap: nowrap;
    gap: 0 10px;
    font-size: 0.66rem;
    white-space: nowrap;
}

.basin-legend-item {
    display: flex;
    align-items: center;
    gap: 5px;
    white-space: nowrap;
}

.basin-legend-item--value {
    margin-left: auto;
    color: var(--text-secondary);
}

.basin-legend-item--value strong {
    color: var(--text-primary);
    font-weight: 700;
}

.basin-legend-swatch {
    display: inline-block;
    width: 14px;
    height: 3px;
    border-radius: 1px;
}

.basin-legend-swatch--river {
    background: #3ba7c4;
    height: 3px;
}

.basin-legend-swatch--tributary {
    background: rgba(59, 167, 196, 0.55);
    height: 1.5px;
}


/* Gradient scale swatch — matches hydroGradientColor()'s 3 stops exactly
   (green 0.5x -> gray 1.0x -> red 1.5x). A bar, not a dot, since this legend
   entry represents a continuous scale, not one fixed color. */
.basin-legend-swatch--gradient {
    width: 28px;
    height: 8px;
    border-radius: 4px;
    background: linear-gradient(to right, rgb(16, 185, 129), rgb(156, 163, 175), rgb(239, 68, 68));
}

.basin-legend-swatch--nodata {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: none;
    border: 1.3px dashed var(--text-secondary);
    opacity: 0.7;
}

/* Dashed-line legend swatches as tiny inline SVG (not a CSS gradient — that
   didn't survive html2canvas at this size; a real stroke-dasharray line is
   the same mechanism the map's own route paths use, already proven to
   export correctly). */
.basin-legend-line-swatch {
    width: 16px;
    height: 6px;
    display: inline-block;
    vertical-align: middle;
}

.basin-legend-line-swatch--balsas {
    stroke: var(--supporte-orange);
    stroke-width: 1.8;
    stroke-dasharray: 3 2;
}

.basin-legend-line-swatch--cabotagem {
    stroke: #64748B;
    stroke-width: 1.6;
    stroke-dasharray: 1 2;
}

/* FOOTER - v8 PATTERN: full-width near-black bar w/ a strong orange top
   rule, bleeding to the card's own edges same as the hero header. */
.boletim-footer {
    margin: 0 calc(-1 * var(--boletim-pad-x)) calc(-1 * var(--boletim-pad-y));
    padding: 12px 24px 14px;
    border-radius: 0 0 5px 5px;
    border-top: 3px solid var(--supporte-orange);
    background: linear-gradient(135deg, #1a1c19 0%, #101210 100%);
    display: flex;
    align-items: center;
    gap: 14px;
}

/* Uma barra de três colunas: fontes | MARCA | quando foi gerado.
   As duas pontas levam `flex: 1 1 0` com a MESMA base, logo repartem o espaço
   sobrante em partes iguais e a coluna do meio fica no centro geométrico da
   barra. Com `space-between` puro, o centro da barra dependia do comprimento
   dos dois textos das pontas — e eles mudam todos os dias (a data de geração,
   a lista de fontes), logo a marca andava para a esquerda e para a direita de
   edição para edição. */
.boletim-footer-side,
.boletim-footer-center {
    font-size: 0.63rem;
    line-height: 1.4;
    /* Era #64748B: 3,61:1 sobre o fundo do rodapé, abaixo do mínimo de 4,5:1 do
       WCAG AA para texto pequeno. Num PNG lido num telefone à luz do dia isso
       lê-se como cinzento sobre cinzento. #94A3B8 dá 6,3:1 e não muda mais nada. */
    color: #94A3B8;
    white-space: nowrap;
}

/* `flex: 1 1 0` sozinho NÃO garante o centro: com white-space: nowrap, o
   tamanho mínimo automático de um item flex é a largura do seu conteúdo, logo
   uma ponta com texto comprido recusa-se a encolher, fica maior do que a outra
   e empurra a marca para o lado. `overflow: hidden` põe esse mínimo automático
   a zero — só então as duas pontas ficam de facto com a MESMA largura e a
   coluna do meio no centro geométrico da barra, seja qual for o comprimento da
   data ou da lista de fontes.
   Testado a injectar 200 caracteres numa das pontas: o desvio do centro
   mantém-se em 0,0px (sem `overflow: hidden` era de 80px). */
.boletim-footer-side {
    flex: 1 1 0;
    min-width: 0;
    overflow: hidden;
}

.boletim-footer-side--end {
    text-align: right;
}

/* A marca é a única das três que se lê como nome próprio, logo é a única com
   peso e com a cor de texto do card. O monograma e a palavra são uma unidade:
   centrada na vertical e na horizontal, como no rodapé do docs.supplog.com. */
.boletim-footer-center {
    flex: 0 0 auto;
    /* Coluna, não linha: o monograma em cima e o nome debaixo dele, como no
       rodapé do docs.supplog.com. Lado a lado, o bloco tinha 275px de largura e
       era a coisa mais larga da barra; empilhado tem 150px e a barra respira. */
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    font-weight: 700;
    letter-spacing: 0.3px;
    color: #CBD5E1;
}

/* O monograma PP em altura fixa e largura automática — o viewBox é 389x290,
   logo a proporção mantém-se sozinha e não há um segundo número para manter
   de acordo com este. É ELE que manda na altura da barra (ver o padding do
   rodapé), e é por isso que voltou a ter a espessura que tinha com duas
   linhas de texto. */
.boletim-footer-mark {
    height: 20px;
    width: auto;
    flex: 0 0 auto;
    display: block;
}

/* O nome não leva cor própria: o laranja fica só no monograma acima dele, que
   é onde a marca vive. Com "SUPPORTE" em laranja e "Logística Integrada" em
   cinza-claro, a linha lia-se como duas coisas — e por baixo de um monograma
   laranja era laranja duas vezes na mesma coluna. */
.boletim-footer-brand {
    color: inherit;
}

@media (max-width: 800px) {
    .boletim { width: 100%; padding: 16px; }

    .boletim-hero-header { margin: -16px -16px 0; }
    .boletim-footer { margin: 0 -16px -16px; }

    .boletim-executive-grid {
        grid-template-columns: 1fr;
    }

    .kpi-hero-number-row {
        flex-wrap: wrap;
    }

    .kpi-hero-pills {
        align-items: flex-start;
    }

    .kpi-stats-strip {
        grid-template-columns: repeat(2, 1fr);
    }
}




/* =====================================================================
   BOLETIM — SELETOR DE VERSÃO (V1 / V2)
   Controle segmentado mínimo, na mesma linguagem dos botões da barra de
   ferramentas do boletim. A aba inativa NÃO usa display:none: o ApexCharts
   grava as dimensões do SVG no momento do render e o html2canvas apenas
   copia o SVG existente — um gráfico montado dentro de um container com
   largura 0 seria exportado vazio. A aba inativa fica portanto fora do
   fluxo (position:absolute) mas com largura real, apenas invisível.
   ===================================================================== */
#view-boletim {
    position: relative;
}

.boletim-version-tabs {
    display: flex;
    gap: 4px;
    align-self: center;
    margin: 0 auto 10px auto;
    padding: 3px;
    background-color: var(--card-bg);
    border: 1px solid var(--border-color);
    border-radius: 8px;
}

.boletim-version-tab {
    font-family: var(--font-body);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.4px;
    padding: 6px 18px;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
}

.boletim-version-tab:hover {
    color: var(--text-primary);
}

.boletim-version-tab.is-active {
    background-color: var(--supporte-orange);
    color: #FFFFFF;
}

.boletim-pane:not(.is-active) {
    position: absolute;
    top: 0;
    left: 0;
    visibility: hidden;
    pointer-events: none;
    z-index: -1;
}

/* =====================================================================
   BOLETIM V2 — PAINÉIS DE VEREDITO
   Tudo em flexbox (CSS Grid quebra no clone offscreen do html2canvas) e
   sem animação de entrada (a captura pegava o meio do fade). Todas as
   cores saem de tokens de tema — nada fixo em escuro.
   ===================================================================== */
/* flex: 0 0 auto é OBRIGATÓRIO em todo filho direto de .boletim: o card é um
   flex column, e um item que possa encolher (flex-shrink padrão 1) é comprimido
   quando outro item pede mais espaço — foi exatamente o que aconteceu no
   primeiro export (o cabeçalho colapsou para ~10px e o SVG do gráfico
   transbordou por cima do painel seguinte). */
.b2-row {
    display: flex;
    flex: 0 0 auto;
    flex-wrap: wrap;
    gap: 12px;
    animation: none;
}

.b2-panel {
    display: flex;
    flex-direction: column;
    min-width: 0;
    background-color: var(--card-bg);
    border: 1px solid var(--border-color);
    border-radius: 8px;
    overflow: hidden;
    animation: none;
}

.b2-panel--wide { flex: 1 1 340px; }
.b2-panel--third { flex: 1 1 220px; }
.b2-panel--full { flex: 0 0 auto; width: 100%; }

.b2-panel-head {
    font-family: var(--font-heading);
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.9px;
    color: var(--text-primary);
    padding: 7px 12px;
    background-color: rgba(var(--overlay-rgb), 0.05);
    border-bottom: 1px solid var(--border-color);
}

.b2-panel-head--alert {
    color: #FFFFFF;
    background-color: var(--supporte-alert-orange);
    border-bottom-color: var(--supporte-alert-orange);
}

.b2-panel-body {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    padding: 10px 12px;
    gap: 6px;
}

.b2-panel-foot {
    font-family: var(--font-mono);
    font-size: 0.55rem;
    line-height: 1.45;
    color: var(--text-secondary);
    padding: 6px 12px 8px;
    border-top: 1px solid var(--border-color);
}


/* --- Destaque do dia --- */
.b2-verdict {
    font-family: var(--font-heading);
    font-size: 1.02rem;
    font-weight: 700;
    line-height: 1.25;
    color: var(--text-primary);
    margin: 0;
}

.b2-verdict-text {
    font-size: 0.78rem;
    line-height: 1.55;
    color: var(--text-secondary);
    margin: 0;
}

.b2-verdict-text b {
    color: var(--text-primary);
    font-family: var(--font-mono);
    font-weight: 700;
}

/* --- Situação atual --- */
.b2-cells {
    display: flex;
    flex: 1 1 auto;
    align-items: center;
}

.b2-cell {
    flex: 1 1 0;
    min-width: 0;
    text-align: center;
    padding: 2px 6px;
}

.b2-cell--divided {
    border-left: 1px solid var(--border-color);
}

.b2-cell-label {
    font-size: 0.55rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.7px;
    color: var(--text-secondary);
    line-height: 1.3;
}

.b2-cell-verdict {
    font-family: var(--font-heading);
    font-size: 0.94rem;
    font-weight: 800;
    line-height: 1.15;
    margin-top: 4px;
    text-transform: uppercase;
}

.b2-cell-big {
    font-family: var(--font-mono);
    font-size: 1.7rem;
    font-weight: 800;
    line-height: 1.1;
    margin-top: 2px;
    color: var(--text-primary);
    white-space: nowrap;
}

.b2-cell-big .b2-unit {
    font-size: 0.8rem;
    font-weight: 700;
    margin-left: 3px;
    color: var(--text-secondary);
}

.b2-cell-arrow {
    font-size: 1.35rem;
    font-weight: 700;
    line-height: 1.1;
    margin-top: 2px;
}

.b2-tone-critical { color: var(--status-critical); }
.b2-tone-warning { color: var(--status-restricted); }
.b2-tone-normal { color: var(--status-normal); }
.b2-tone-neutral { color: var(--text-secondary); }

/* --- Faixa de veredito (linha executiva: Evolução / Previsão / Semáforo) ---
   Os três painéis abrem com o MESMO bloco: uma palavra de veredito e uma linha
   de apoio. min-height fixo (não conteúdo) porque o veredito de cada painel tem
   comprimento diferente e, sem ela, as três barras de título internas ficavam
   em alturas diferentes lado a lado. 46px = uma linha de veredito + duas de
   nota, o pior caso real dos três painéis. Sem gap: os dois filhos têm
   line-height própria e o gap somava sobra visível dentro da faixa. */
.b2-verdict-strip {
    display: flex;
    flex-direction: column;
    justify-content: center;
    flex: 0 0 auto;
    min-height: 46px;
    padding: 6px 12px;
    border-bottom: 1px solid var(--border-color);
    background-color: rgba(var(--overlay-rgb), 0.02);
}

.b2-verdict-word {
    font-family: var(--font-heading);
    font-size: 0.95rem;
    font-weight: 800;
    line-height: 1.15;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.b2-verdict-note {
    font-size: 0.55rem;
    font-weight: 600;
    line-height: 1.35;
    text-transform: uppercase;
    letter-spacing: 0.4px;
    color: var(--text-secondary);
}

.b2-verdict-num {
    font-family: var(--font-mono);
    font-weight: 800;
    color: var(--text-primary);
}

/* --- Evolução do nível --- */
/* flex:1 1 auto na lista + nos itens: os três painéis da linha executiva têm
   a mesma altura (a do mais alto), e sem isto a Evolução deixava ~150px de
   vazio entre a última linha e o par de estatísticas. Agora as três linhas
   dividem a sobra entre si e o painel fecha cheio. */
.b2-evo-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
}

.b2-evo-item {
    display: flex;
    flex: 1 1 auto;
    align-items: center;
    gap: 6px;
    padding: 7px 0;
    border-bottom: 1px solid var(--border-color);
}

.b2-evo-item:last-child { border-bottom: none; }

.b2-evo-label {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 0.62rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.4px;
    color: var(--text-secondary);
    line-height: 1.25;
}

/* Larguras FIXAS nas duas colunas de número: com flex:0 0 auto cada valor
   tinha a largura do próprio texto ("-8 cm" contra "-235 cm") e a coluna saía
   desalinhada linha a linha. A unidade vai no cabeçalho da coluna, não em cada
   célula, o que encurta as células e mantém tudo em uma linha. */
.b2-evo-value {
    flex: 0 0 46px;
    text-align: right;
    font-family: var(--font-mono);
    font-size: 0.82rem;
    font-weight: 800;
    white-space: nowrap;
}

.b2-evo-rate {
    flex: 0 0 46px;
    text-align: right;
    font-family: var(--font-mono);
    font-size: 0.72rem;
    font-weight: 700;
    white-space: nowrap;
}

.b2-evo-arrow {
    flex: 0 0 12px;
    text-align: center;
    font-size: 0.9rem;
    font-weight: 700;
}

/* Cabeçalho da tabela: mesmo desenho do cabeçalho da tabela de limiares do
   Semáforo, para as duas tabelas da linha executiva se lerem como uma só. */
.b2-evo-item--head {
    flex: 0 0 auto;
    padding: 0 0 4px;
}

.b2-evo-item--head span {
    font-family: var(--font-heading);
    font-size: 0.5rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--text-secondary);
}

/* Par de estatísticas no pé do corpo: velocidade média e perda acumulada
   desde o pico da cheia. margin-top:auto cola no rodapé do painel, para os
   três painéis da linha fecharem na mesma altura. */
.b2-stat-pair {
    display: flex;
    flex: 0 0 auto;
    margin-top: auto;
    padding-top: 8px;
    border-top: 1px solid var(--border-color);
}

.b2-stat {
    flex: 1 1 0;
    min-width: 0;
}

.b2-stat--divided {
    margin-left: 10px;
    padding-left: 10px;
    border-left: 1px solid var(--border-color);
}

/* min-height de duas linhas: "PERDA DESDE O PICO (27/06)" quebra em duas e
   "VELOCIDADE MÉDIA (7 D)" cabe em uma, então sem isto os dois valores ficavam
   em alturas diferentes lado a lado. */
.b2-stat-label {
    min-height: 2.6em;
    font-size: 0.52rem;
    font-weight: 600;
    line-height: 1.3;
    text-transform: uppercase;
    letter-spacing: 0.4px;
    color: var(--text-secondary);
}

.b2-stat-value {
    font-family: var(--font-mono);
    font-size: 0.88rem;
    font-weight: 800;
    line-height: 1.25;
    white-space: nowrap;
}

/* --- Previsão --- */
/* Os dois horizontes ocupam metades iguais do corpo, cada um centrado na sua
   metade. A versão anterior empilhava os dois no topo (vazio de ~90px embaixo)
   e depois colava o segundo no rodapé (vazio no meio); as metades iguais são o
   único arranjo que fica simétrico em qualquer altura de painel. */
.b2-prev-block {
    display: flex;
    flex: 1 1 0;
    flex-direction: column;
    justify-content: center;
    padding: 2px 0;
}

.b2-prev-block--divided {
    padding-top: 8px;
    border-top: 1px solid var(--border-color);
}

.b2-prev-horizon {
    font-size: 0.58rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.6px;
    color: var(--text-secondary);
}

.b2-prev-value {
    font-family: var(--font-mono);
    font-size: 1.15rem;
    font-weight: 800;
    line-height: 1.2;
    color: var(--text-primary);
    white-space: nowrap;
}

/* Valor e variação na MESMA linha, alinhados pela baseline: "22,59 m" sozinho
   não responde "quanto isso custa"; "−2,96 m contra hoje" responde. */
.b2-prev-line {
    display: flex;
    align-items: baseline;
    gap: 7px;
}

.b2-prev-delta {
    font-family: var(--font-mono);
    font-size: 0.72rem;
    font-weight: 800;
    white-space: nowrap;
}

.b2-prev-method {
    font-family: var(--font-mono);
    font-size: 0.55rem;
    line-height: 1.4;
    color: var(--text-secondary);
}

/* --- Semáforo hidrológico ---
   Só as faixas REAIS do projeto (THRESHOLDS): Crítico < 16,00 /
   Atenção 16,00-20,00 / Normal >= 20,00, com marca da taxa de seca em
   17,70 m. As extremidades da escala são valores medidos (recorde
   histórico e pico de cheia do ano), nunca limites inventados. */
.b2-gauge {
    display: flex;
    flex-direction: column;
    gap: 5px;
    flex: 0 0 auto;
}

.b2-gauge-bar {
    position: relative;
    display: flex;
    height: 16px;
    border-radius: 3px;
    overflow: visible;
}

.b2-gauge-seg { height: 16px; }
.b2-gauge-seg--crit { background-color: var(--status-critical); border-radius: 3px 0 0 3px; }
.b2-gauge-seg--aten { background-color: var(--status-restricted); }
.b2-gauge-seg--norm { background-color: var(--status-normal); border-radius: 0 3px 3px 0; }

.b2-gauge-tick {
    position: absolute;
    top: -1px;
    width: 2px;
    height: 18px;
    background-color: var(--text-secondary);
}

.b2-gauge-needle {
    position: absolute;
    top: -7px;
    width: 5px;
    height: 30px;
    background-color: var(--text-primary);
    border: 1px solid var(--card-bg);
    border-radius: 2px;
}

.b2-gauge-ticklabels {
    position: relative;
    height: 12px;
}

.b2-gauge-ticklabel {
    position: absolute;
    top: 0;
    font-family: var(--font-mono);
    font-size: 0.5rem;
    font-weight: 700;
    color: var(--text-secondary);
    white-space: nowrap;
}

/* Rótulo do ponteiro (cota de hoje): o marcador da taxa de seca é uma marca
   de referência secundária, este é a leitura — por isso texto primário e mais
   pesado, para os dois traços na barra não se confundirem. */
.b2-gauge-ticklabel--now {
    color: var(--text-primary);
    font-weight: 800;
}

/* --- Tabela única de limiares operacionais ---
   A leitura "faixa NORMAL" isolada tranquiliza quem lê rápido, mas a pergunta
   de diretoria é "quando aperta". Cada linha traz um limiar real do projeto:
   a cor da faixa (bolinha, igual à barra acima — por isso a tabela dispensa a
   legenda que ficava aqui), o nível de entrada, quanto falta em metros
   (diferença medida contra a cota de hoje) e a data de cruzamento da MESMA
   trajetória projetada do gráfico. Tabela em flexbox, nunca CSS Grid nem
   <table> (o clone offscreen do html2canvas quebra as duas). */
/* flex:1 1 auto (e sem margin-top:auto): sem a legenda acima dela a tabela
   ganhou ~40px, e deixá-la colada no rodapé abria um vazio entre a barra e a
   primeira linha. Agora a tabela ocupa a sobra e as linhas se distribuem. */
.b2-thr {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    padding-top: 10px;
}

.b2-thr-row {
    display: flex;
    flex: 1 1 auto;
    align-items: center;
    gap: 7px;
    padding: 5px 0;
    border-bottom: 1px solid var(--border-color);
}

.b2-thr-row:last-child { border-bottom: none; }

.b2-thr-row--head {
    flex: 0 0 auto;
    padding-bottom: 4px;
    font-size: 0.5rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--text-secondary);
}

/* Larguras dimensionadas para o pior caso MEDIDO, não estimado: no painel
   real a linha tem 221px de largura útil e "TAXA DE SECA 17,70" é a célula
   mais longa (92px). Daí c1 ≈ 99px, c2 40px, c3 66px, gaps 2x8px. A cota do
   limiar sai sem a unidade (o cabeçalho da coluna diz "Limiar (m)"), porque o
   " m" custava os 13px que faltavam e a linha era cortada no export. */
.b2-thr-c1 {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 0.52rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.2px;
    line-height: 1.25;
    white-space: nowrap;
    overflow: hidden;
}

.b2-thr-lvl {
    margin-left: 4px;
    font-family: var(--font-mono);
    font-size: 0.53rem;
    font-weight: 700;
    letter-spacing: 0;
    text-transform: none;
    color: var(--text-secondary);
}

.b2-thr-c2 {
    flex: 0 0 38px;
    text-align: right;
    font-family: var(--font-mono);
    font-size: 0.64rem;
    font-weight: 800;
    white-space: nowrap;
}

.b2-thr-c3 {
    flex: 0 0 84px;
    text-align: right;
    font-family: var(--font-mono);
    font-size: 0.52rem;
    font-weight: 700;
    line-height: 1.3;
    white-space: nowrap;
    color: var(--text-secondary);
}

.b2-thr-row--head .b2-thr-c2,
.b2-thr-row--head .b2-thr-c3 {
    font-family: var(--font-heading);
    font-size: 0.5rem;
    font-weight: 700;
}

/* Bolinha de faixa na coluna do limiar: liga cada linha à cor da barra acima,
   sem repetir a legenda. */
.b2-thr-dot {
    display: inline-block;
    width: 6px;
    height: 6px;
    margin-right: 5px;
    border-radius: 50%;
    vertical-align: middle;
}

/* Asterisco da taxa de seca: marca de nota, não dado. Fica em texto secundário
   para não competir com o nome do limiar nem com a cota ao lado. */
.b2-thr-mark {
    margin-left: 1px;
    font-weight: 700;
    color: var(--text-secondary);
}

/* nowrap + overflow:hidden: esta nota tem de caber em UMA linha. Se um dia o
   texto crescer, ela é cortada em vez de empurrar a altura dos três painéis. */
.b2-thr-note {
    flex: 0 0 auto;
    margin: 6px 0 0;
    font-family: var(--font-mono);
    font-size: 0.5rem;
    line-height: 1.45;
    white-space: nowrap;
    overflow: hidden;
    color: var(--text-secondary);
}

.b2-thr-dot--aten { background-color: var(--status-restricted); }
.b2-thr-dot--lws { background-color: var(--text-secondary); }
.b2-thr-dot--crit { background-color: var(--status-critical); }

/* Limiar já ultrapassado: a linha não desaparece (o fato importa), mas perde
   destaque para não competir com os limiares que ainda estão à frente. */
.b2-thr-row--past .b2-thr-c1,
.b2-thr-row--past .b2-thr-c2 { color: var(--text-secondary); }

/* --- Comparativo histórico (tabela em flexbox, não table/grid) --- */
.b2-tbl {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
}

.b2-tbl-row {
    display: flex;
    flex: 1 1 auto;
    align-items: center;
    gap: 6px;
    padding: 5px 0;
    border-bottom: 1px solid var(--border-color);
}

.b2-tbl-row--head { flex: 0 0 auto; padding-top: 0; }

.b2-tbl-row:last-child { border-bottom: none; }

.b2-tbl-row--head span {
    font-size: 0.53rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.7px;
    color: var(--text-secondary);
}

.b2-tbl-row--self { background-color: rgba(var(--overlay-rgb), 0.04); }

/* A tabela mudou de um painel de largura dupla para um de 1/3 (~221px úteis).
   Com c2 em 82px e c3 em 116px a coluna do ano sobrava com 7px. Recalculado
   para a largura real, com a nota do ano ("(seca histórica)") em linha própria
   em vez de disputar a mesma linha do ano. */
.b2-tbl-c1 { flex: 1 1 0; min-width: 0; font-size: 0.7rem; font-weight: 700; line-height: 1.2; color: var(--text-primary); }
.b2-tbl-c1 i { display: block; font-style: normal; font-weight: 400; font-size: 0.52rem; line-height: 1.2; color: var(--text-secondary); }
.b2-tbl-c2 { flex: 0 0 56px; text-align: right; font-family: var(--font-mono); font-size: 0.78rem; font-weight: 800; color: var(--text-primary); }
.b2-tbl-c3 { flex: 0 0 62px; text-align: right; font-family: var(--font-mono); font-size: 0.7rem; font-weight: 700; }

/* --- Velocidade da vazante (barras horizontais em CSS) --- */
.b2-bars {
    display: flex;
    flex-direction: column;
    gap: 6px;
    flex: 1 1 auto;
}

.b2-bar-row {
    display: flex;
    align-items: center;
    gap: 8px;
}

.b2-bar-label {
    flex: 0 0 112px;
    font-size: 0.62rem;
    font-weight: 700;
    color: var(--text-primary);
    line-height: 1.2;
}

.b2-bar-label i {
    display: block;
    font-style: normal;
    font-weight: 400;
    font-size: 0.52rem;
    color: var(--text-secondary);
}

.b2-bar-track {
    flex: 1 1 auto;
    min-width: 0;
    height: 13px;
    background-color: rgba(var(--overlay-rgb), 0.06);
    border-radius: 2px;
    display: flex;
    justify-content: flex-end;
}

.b2-bar-fill {
    height: 13px;
    border-radius: 2px 0 0 2px;
}

.b2-bar-value {
    flex: 0 0 52px;
    text-align: right;
    font-family: var(--font-mono);
    font-size: 0.74rem;
    font-weight: 800;
    color: var(--text-primary);
}

/* --- Gráfico de profundidade ---
   Altura FIXA obrigatória: um corpo de gráfico em flex:1 1 0 colapsa
   para 0 no clone do html2canvas. */
.b2-chart-card { flex: 0 0 auto; animation: none; }

.b2-chart-body {
    flex: 0 0 320px;
    height: 320px;
    width: 100%;
}

.b2-chart-caption {
    font-size: 0.68rem;
    line-height: 1.5;
    color: var(--text-primary);
    margin: 6px 0 0;
    padding-top: 6px;
    border-top: 1px solid var(--border-color);
}

.b2-chart-caption--muted {
    font-family: var(--font-mono);
    font-size: 0.55rem;
    color: var(--text-secondary);
    border-top: none;
    padding-top: 0;
    margin-top: 3px;
}

/* --- Resumo executivo / metodologia --- */
.b2-resumo {
    font-size: 0.78rem;
    line-height: 1.6;
    color: var(--text-primary);
    margin: 0;
}

.b2-context-list {
    list-style: none;
    margin: 6px 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.b2-context-list li {
    font-size: 0.68rem;
    line-height: 1.5;
    color: var(--text-secondary);
}

.b2-context-list li strong { color: var(--text-primary); }

.b2-next-date {
    font-family: var(--font-mono);
    font-size: 1rem;
    font-weight: 800;
    color: var(--text-primary);
}

.b2-next-note,
.b2-method-text {
    font-size: 0.65rem;
    line-height: 1.5;
    color: var(--text-secondary);
    margin: 0;
}

/* ==========================================================================
   BOLETIM — UMA ÚNICA LINGUAGEM DE MOLDURA E DE TÍTULO
   Os três blocos de mídia do boletim (gráfico de profundidade, mapa da bacia e
   janela do Clipping) são .chart-card, herdados do dashboard: canto de 12px,
   sombra projetada, backdrop-filter e título de 1,15rem solto no topo. Os onze
   painéis de dados ao lado deles são .b2-panel: canto de 8px, sem sombra e com
   o título numa BARRA de 0,7rem em versalete. Duas molduras e dois tamanhos de
   título na mesma página fazem o olho ler dois documentos costurados, e a
   sombra some no PNG exportado de qualquer jeito — ela só existia para o
   estado :hover do dashboard, que uma imagem não tem.
   Escopo em #boletim-card: os cards do dashboard continuam como estão.
   ========================================================================== */
#boletim-card .chart-card {
    border-radius: 8px;
    box-shadow: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
}

/* O cabeçalho vira barra: sai para as bordas do card por margem negativa (o
   corpo mantém o padding que já tinha, então nada mais na página se move). */
#boletim-card .chart-card > .card-header {
    margin: -10px -9px 0 -9px;
    padding: 6px 9px;
    background-color: rgba(var(--overlay-rgb), 0.05);
    border-bottom: 1px solid var(--border-color);
}

#boletim-card .chart-card > .card-header h2 {
    font-family: var(--font-heading);
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.9px;
    color: var(--text-primary);
}

/* Mapa e clipping já trazem a sua própria borda; dentro de um card que agora
   tem o cabeçalho encostado na moldura, a borda dupla fica visível. */
#boletim-card .basin-illustrated-map,
#boletim-card .boletim-clipping-window {
    border-color: transparent;
}

/* Última linha do boletim: "Próxima Atualização" é uma data e "Metodologia" é
   um parágrafo. Esticados à mesma altura, o primeiro painel fica com dois
   terços de vazio. Nesta linha cada painel tem a altura do seu conteúdo. */
.b2-row--top { align-items: flex-start; }

/* O herói tinha min-height de 138px porque o conteúdo (kicker + manchete +
   lede) chegava perto disso. Sem a lede — que repetia a data do kicker e a
   cota e a variação de 24h do painel logo abaixo — sobrava uma faixa vazia de
   quase 80px, com o texto encostado no fim do bloco. Agora o bloco tem a
   altura do que ele carrega. */
#boletim-card .boletim-hero-photo { min-height: 0; }
#boletim-card .boletim-hero-photo-content { padding: 16px 20px 17px; }

/* ==========================================================================
   BOLETIM — UM ÚNICO SISTEMA TIPOGRÁFICO
   O boletim é entregue como PNG no WhatsApp e lido no telefone. Antes deste
   bloco ele usava as TRÊS famílias da folha de estilo de forma trocada — o
   cabeçalho de coluna da Evolução era Titillium e o da mesma linha nos
   Limiares era Fira Sans; um rótulo de campo aparecia com 10,88px num painel e
   12,8px no painel ao lado — e doze corpos de letra quase iguais
   (9,6 / 9,92 / 10,24 / 10,4 / 10,56 / 10,88 / 11,2 / 11,52 / 11,84 / 12,8 /
   13,12 / 13,76px). Sem uma escala, o olho não sabe o que é mais importante e
   a leitura de 15 segundos falha.

   DUAS REGRAS, sem exceção dentro de #boletim-card:

   1) FAMÍLIA POR PAPEL
        título de painel e palavra de veredito -> var(--font-heading)
        rótulo, nota e prosa                   -> var(--font-body)
        QUALQUER número                        -> var(--font-mono)
      Um número nunca sai em Fira Sans e um rótulo nunca sai em Fira Code:
      é isso que faz colunas de números alinharem (a mono tem largura fixa).

   2) UMA ESCALA DE SETE PASSOS
        t1  0,62rem   9,9px  cabeçalho de coluna
        t2  0,64rem  10,2px  nota de pé, método, fonte
        t3  0,72rem  11,5px  rótulo de campo, nota de veredito
        t4  0,86rem  13,8px  título de painel, número secundário
        t5  0,98rem  15,7px  número de tabela
        t6  1,10rem  17,6px  palavra de veredito
        t7  1,20rem  19,2px  número destacado
        t8  1,85rem  29,6px  número herói (Cota Atual)

   ALINHAMENTO: Situação Atual é centrada (cinco células iguais, sem coluna de
   rótulo); todo o resto começa à esquerda; só coluna de número é à direita.
   CAIXA ALTA: apenas rótulo, título e veredito — nunca uma frase. Uma frase em
   caixa alta com três linhas (era o caso da nota da Previsão) perde o desenho
   da palavra e lê-se letra por letra.
   ========================================================================== */

/* --- t4: título de painel ------------------------------------------------ */
#boletim-card .b2-panel-head,
#boletim-card .chart-card > .card-header h2 {
    font-family: var(--font-heading);
    font-size: 0.86rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.3px;
}

/* --- t6: palavra de veredito --------------------------------------------- */
#boletim-card .b2-cell-verdict,
#boletim-card .b2-verdict-word {
    font-family: var(--font-heading);
    font-size: 1.1rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.1px;
}

/* --- t3: nota de veredito. É uma FRASE, então sai da caixa alta. --------- */
#boletim-card .b2-verdict-note {
    font-family: var(--font-body);
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: none;
    letter-spacing: 0;
    line-height: 1.4;
}

/* --- t3: rótulo de campo -------------------------------------------------
   Cinco classes diferentes que fazem exatamente o mesmo trabalho: dizer o que
   é o número ao lado. Antes iam de 10,88px a 12,8px em duas famílias. */
#boletim-card .b2-cell-label,
#boletim-card .b2-stat-label,
#boletim-card .b2-evo-label,
#boletim-card .b2-thr-c1,
#boletim-card .b2-prev-horizon {
    font-family: var(--font-body);
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.2px;
}
/* min-height de 2,6em era a altura de DUAS linhas no corpo antigo; com o corpo
   novo, duas linhas cabem em menos em, e 2,6em passaria a abrir um vão. */
#boletim-card .b2-stat-label { min-height: 2.3em; }

/* --- t1: cabeçalho de coluna --------------------------------------------- */
#boletim-card .b2-evo-item--head span,
#boletim-card .b2-thr-row--head,
#boletim-card .b2-thr-row--head .b2-thr-c1,
#boletim-card .b2-thr-row--head .b2-thr-c2,
#boletim-card .b2-thr-row--head .b2-thr-c3 {
    font-family: var(--font-body);
    font-size: 0.62rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.3px;
}

/* --- Números: uma família só, quatro pesos de tamanho -------------------- */
/* t8 herói */
#boletim-card .b2-cell-big {
    font-size: 1.85rem;
    font-weight: 800;
}
#boletim-card .b2-cell-big .b2-unit {
    font-family: var(--font-body);
    font-size: 0.9rem;
}
/* t7 destacado */
#boletim-card .b2-prev-value {
    font-size: 1.2rem;
    font-weight: 800;
}
/* t5 número de tabela. As larguras FIXAS sobem com o corpo: "5,55 m" a 15,7px
   mede ~60px e era cortado pelos 48px antigos. */
#boletim-card .b2-evo-value,
#boletim-card .b2-stat-value,
#boletim-card .b2-thr-c2 {
    font-size: 0.98rem;
    font-weight: 800;
}
#boletim-card .b2-evo-value { flex: 0 0 56px; }
#boletim-card .b2-thr-c2 { flex: 0 0 62px; }
/* t4 número secundário (variação, prazo, escala do medidor) */
#boletim-card .b2-evo-rate,
#boletim-card .b2-prev-delta,
#boletim-card .b2-thr-c3,
#boletim-card .b2-thr-lvl,
#boletim-card .b2-gauge-ticklabel {
    font-size: 0.8rem;
    font-weight: 700;
}
#boletim-card .b2-evo-rate { flex: 0 0 56px; }
/* 140px e nao 92px: a coluna passou de "~17 d · set" para "~17 d · meados de
   set.". MEDIDO na propria linha de dados (nao na do cabecalho, que tem outro
   corpo — o primeiro numero que tirei estava errado por isso): 129px de
   largura natural em Fira Sans com tabular-nums. Os 11px a mais sao folga para
   o html2canvas, que mede texto mais largo que o DOM.
   A BASE TEM DE SER >= AO CONTEUDO MAIS LARGO. Um flex item tem min-width:auto
   e a largura de conteudo levanta a celula acima da base, roubando o espaco a
   .b2-thr-c1 numa quantidade DIFERENTE por linha — e ai a coluna "Falta", que
   e fixa, deixa de comecar no mesmo x em todas as linhas. Aconteceu com a base
   a 116px.
   Orcamento da linha: 371px = c1 + 62 (c2) + 140 (c3) + 2x7 (gaps) -> c1 fica
   com 155px e precisa de 128 ("TAXA DE SECA*17,70", o pior caso medido). c1 e
   nowrap + overflow:hidden, logo apertar-lhe a largura CORTA o texto sem aviso
   nenhum; foi por isso que a cota do limiar ja saiu sem a unidade. */
#boletim-card .b2-thr-c3 { flex: 0 0 140px; }

/* --- MONO SÓ ONDE HÁ COLUNA PARA ALINHAR --------------------------------
   A regra "qualquer número em mono" deixava o boletim com um ar espaçado: a
   Fira Code dá a mesma caixa larga a cada carácter e não tem kerning, então
   "25,55" saía com buracos entre os dígitos e uma frase inteira em mono
   ("projetada: início de out") lia-se como código, não como boletim. No
   WhatsApp, onde a imagem é encolhida, esse ar custa legibilidade.
   Mono fica onde faz o trabalho para que foi escolhida — as DUAS colunas de
   números que têm de alinhar linha a linha (Evolução e Limiares). Todo o resto
   passa a Fira Sans com `tabular-nums`: a Fira Sans tem algarismos de largura
   fixa (feature OpenType `tnum`), logo um par de valores empilhados continua a
   alinhar, mas ~15% mais estreito e sem os buracos. */
/* .b2-thr-c3 SAIU do mono, pela regra que este proprio comentario ja defendia:
   a celula deixou de ser um numero e passou a ser uma FRASE ("~17 d · meados de
   set."). Em Fira Code media 176px e nao havia largura para ela; em Fira Sans
   com tabular-nums mede 129px — os digitos continuam a alinhar linha a linha,
   que e o unico trabalho que o mono aqui fazia. */
#boletim-card .b2-evo-value,
#boletim-card .b2-evo-rate,
#boletim-card .b2-thr-c2 {
    font-family: var(--font-mono);
}
#boletim-card .b2-cell-big,
#boletim-card .b2-prev-value,
#boletim-card .b2-stat-value,
#boletim-card .b2-thr-lvl,
#boletim-card .b2-thr-c3,
#boletim-card .b2-gauge-ticklabel,
#boletim-card .b2-prev-delta {
    font-family: var(--font-body);
}
/* `tabular-nums` SÓ onde há coluna para alinhar. A feature `tnum` da Fira Sans
   troca também o espaço normal por um espaço com a largura de um algarismo, e
   numa FRASE isso abre um buraco visível ("19  dias", "15,30  m)"). Nestes
   quatro valores há empilhamento (dois a dois, ou três limiares em linha), e é
   o alinhamento que importa; a frase ao lado deles não a leva. */
#boletim-card .b2-cell-big,
#boletim-card .b2-prev-value,
#boletim-card .b2-stat-value,
#boletim-card .b2-thr-lvl,
#boletim-card .b2-thr-c3,
#boletim-card .b2-gauge-ticklabel {
    font-variant-numeric: tabular-nums;
}

/* --- t2: nota de pé. Tudo o que explica codificação ou cita fonte, no mesmo
   corpo e na mesma família, para o olho passar por cima delas de uma vez. --- */
#boletim-card .b2-cell-note,
#boletim-card .b2-thr-note,
#boletim-card .b2-chart-caption--muted,
#boletim-card .b2-prev-method,
#boletim-card .b2-panel-foot {
    font-family: var(--font-body);
    font-size: 0.64rem;
    font-weight: 400;
    text-transform: none;
    letter-spacing: 0;
    line-height: 1.35;
    color: var(--text-secondary);
}

/* --- Glifos de seta: dimensionados pela caixa que ocupam, não pela escala. */
#boletim-card .b2-cell-arrow { font-size: 1.45rem; }
#boletim-card .b2-evo-arrow { font-size: 1rem; flex: 0 0 14px; }

/* --- Cabeça e rodapé do card -------------------------------------------- */
#boletim-card .boletim-hero-kicker { font-size: 0.86rem; }
#boletim-card .boletim-hero-headline { font-size: 1.62rem; }
#boletim-card .boletim-hero-tagline { font-size: 0.8rem; }
#boletim-card .boletim-hero-edition { font-size: 0.72rem; }
/* As três colunas do rodapé num corpo só. A marca era 0,86rem contra 0,64rem
   das outras duas; numa barra horizontal essa diferença fazia a linha parecer
   desalinhada, porque cada coluna tinha a sua própria caixa de linha. */
#boletim-card .boletim-footer-side,
#boletim-card .boletim-footer-center {
    font-family: var(--font-body);
    font-size: 0.64rem;
}

/* O gráfico é o bloco mais alto do card (22%). Com os rótulos maiores ele
   continua legível em menos altura, e cada pixel devolvido aqui é altura que a
   imagem não gasta no telefone. */
/* Este 260 tem de ser IGUAL ao chart.height do mountChart('#chart-boletim-depth')
   em app.js — ver o comentário lá. */
/* Sobram ~25px de branco no TOPO do SVG que o ApexCharts reserva para título e
   legenda e não deixa configurar (não existe nem título nem legenda aqui). Como
   são pixels transparentes, o SVG sobe 18px para debaixo do cabeçalho do card:
   o que passa por cima do cabeçalho é branco, logo não se vê nada, e o card
   deixa de gastar 18px de altura. A altura do SVG continua 244 — só a caixa
   ocupa 226 no layout. */
#boletim-card .b2-chart-body { flex: 0 0 244px; height: 244px; margin-top: -18px; }

/* ==========================================================================
   MAPA SEMPRE CLARO (e só o mapa)
   Era "sempre escuro". O fundo escuro era CARTO dark_matter, e o problema real
   não era o tema: era que aquele ficheiro traz os RÓTULOS dele (Manaus,
   Itacoatiara, Belém, Santarém, Macapá, Itaituba, Tucuruí, AMAPÁ, AMAZONAS) e
   imprimia-os por baixo dos rótulos que o SVG já desenha.
   Agora o fundo é ESRI World Physical Map — claro, com relevo e o Atlântico em
   azul, e sem rótulos nenhuns. Foi a única das seis opções claras testadas que
   traz DETALHE sem trazer clutter (ver o comentário no <image> em index.html).
   O card e os painéis continuam a trocar de tema com o dashboard — o que fica
   fixo é o DESENHO do mapa.
   Feito redefinindo os tokens de cor DENTRO do SVG: cada cor do mapa já é
   var(--card-bg) / var(--text-primary) / var(--text-secondary) /
   var(--overlay-rgb), então nada mais precisa de mudar. Os valores são os do
   :root[data-theme="light"]; se um deles mudar lá, muda aqui.
   Cores herdadas não são problema: todo o fill/stroke do mapa é declarado.
   ========================================================================== */
#boletim-card .basin-illustrated-map {
    --card-bg: #FFFFFF;
    --text-primary: #0F172A;
    --text-secondary: #475569;
    --overlay-rgb: 0, 0, 0;
}

/* Já não há duas imagens para o tema escolher: o markup tem UMA, e é sempre
   esta. As regras que escondiam/mostravam a variante escura e a clara foram
   removidas junto com as classes --dark/--light. */

/* --- Faixa MAPA (2/3) + PREVISÃO (1/3) ---
   flex-basis em porcentagem, não em px: os dois têm de manter a proporção que
   o corpo do mapa foi calibrado para (ver o bloco do mapa mais abaixo). */
#boletim-card .b2-chart-card--map { flex: 1 1 66%; min-width: 0; }
#boletim-card .b2-panel--side { flex: 1 1 30%; min-width: 0; }

/* --- Corpo e traço do mapa a 2/3 de largura ---
   O SVG tem viewBox 560x215 e width:100%, então TODO o desenho (texto, traço,
   raio dos pontos) é dimensionado em unidades do viewBox e encolhe junto com a
   largura do card. A dois terços da largura, os corpos originais (7px a 10,5px
   de unidade) cairiam para ~8px na tela — ilegíveis no telefone. Cada um sobe
   ~1,4x (1 / 0,66 + folga), de forma que o desenho sai do MESMO tamanho
   aparente que tinha em largura cheia.
   Se a proporção da faixa mudar, este bloco tem de ser recalibrado. */
#boletim-card .basin-country-label { font-size: 10.5px; }
#boletim-card .basin-compass-label { font-size: 10.5px; }
#boletim-card .basin-station-label { font-size: 13px; }
#boletim-card .basin-station-label--primary { font-size: 16px; }
#boletim-card .basin-station-value { font-size: 12px; stroke-width: 3.2; }
#boletim-card #st-val-manaus-map { font-size: 15px; stroke-width: 3.8; }
#boletim-card .basin-map-attribution { font-size: 7.5px; }
#boletim-card .basin-country { stroke-width: 1.05; }
#boletim-card .basin-river-path { stroke-width: 3.4; }
#boletim-card .basin-tributary { stroke-width: 1.8; }
#boletim-card .basin-route--balsas { stroke-width: 2.5; }
#boletim-card .basin-route--cabotagem { stroke-width: 2.2; }
#boletim-card .basin-station-dot { stroke-width: 1.7; r: 6.2; }
#boletim-card .basin-station-dot--no-data { stroke-width: 1.8; }
#boletim-card #basin-dot-manaus { r: 7.6; }
#boletim-card .basin-compass-ring { stroke-width: 1.4; }

/* Legenda do mapa: uma linha de seis itens num card de dois terços. Menor que
   os rótulos do desenho — ela decodifica o mapa, não carrega dado. */
#boletim-card .basin-legend-row--single { font-size: 0.62rem; gap: 9px; }

/* --- Célula "Taxa de Seca": o estado grande, o prazo pequeno embaixo.
   Corpo e família vêm do papel "nota de pé" no bloco do sistema tipográfico
   mais acima — aqui só o espaçamento. --- */
.b2-cell-note { margin-top: 2px; }

/* --- Previsão estreita: o conteúdo vai para o TOPO e a linha do valor pode
   quebrar. Num painel de um terço de largura, "24,46 m -1,09 m contra hoje"
   não cabe numa linha só, e o flex sem wrap cortava o final do texto contra a
   borda do card. O painel é mais baixo que o mapa ao lado, então o vão que
   sobra embaixo recebe a nota de método (b2-panel-foot): ela não custa altura
   nenhuma ao card e tira uma linha da nota do veredito. --- */
#boletim-card .b2-panel--side .b2-panel-body { justify-content: flex-start; }
#boletim-card .b2-panel--side .b2-prev-block { flex: 0 0 auto; }
#boletim-card .b2-panel--side .b2-prev-line { flex-wrap: wrap; row-gap: 2px; align-items: baseline; }
#boletim-card .b2-panel--side .b2-panel-foot { margin-top: auto; }
/* Sem método publicado o pé fica vazio — e um pé vazio ainda desenharia a
   linha de topo e o padding dele. */
#boletim-card .b2-panel-foot:empty { display: none; }

/* --- SITUAÇÃO ATUAL: rótulos numa linha, valores noutra ---
   Cada célula centrava o SEU próprio conteúdo verticalmente. Como as cinco têm
   conteúdos de alturas diferentes (um número de 29,6px, um veredito de 17,6px,
   uma seta mais uma palavra, um veredito mais uma nota), os cinco rótulos
   acabavam em cinco alturas diferentes e a faixa lia-se como cinco caixas
   soltas em vez de uma linha. Ancorar tudo no TOPO põe os cinco rótulos na
   mesma linha; os valores crescem para baixo. */
#boletim-card .b2-cells { align-items: flex-start; }
#boletim-card .b2-cell {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
}

/* A seta da tendência era um <div> IRMÃO do veredito, o que obrigava esta
   célula a ser flex-row com flex-wrap e um rótulo a 100% de largura — uma
   mecânica de layout só para ela, e era a razão pela qual a palavra
   "DESCENDO" assentava 2,9px mais abaixo do que a seta ao lado dela.
   A seta passou para DENTRO do veredito, no markup, como o ícone SVG das
   outras duas células. Estas cinco regras deixaram de ter razão de existir.
   A seta é agora dimensionada como um irmão inline do texto, mais abaixo. */
#boletim-card #b2-trend-arrow {
    flex: 0 0 auto;
    margin-right: 5px;
    line-height: 1;
}

/* --- Menos padding interno para a nota da quinta célula caber numa linha ---
   Faltavam 9px de largura de texto por célula (medido: a nota pede 144px e
   tinha 135,2px). Os 9px vêm de três sítios, nenhum deles suficiente por si:
     padding do card    26px -> 14px  (+24px partilhados pelas cinco células)
     corpo do painel    12px ->  9px  (+6px partilhados)
     padding da célula   6px ->  4px  (+4px em cada célula)
   Total: ~10px por célula. Vale para TODOS os painéis, não só este — o gráfico
   e o mapa também ganham largura, e o card perde 16px de altura. */
#boletim-card .b2-panel-body { padding: 10px 9px; }
#boletim-card .b2-cell { padding: 2px 4px; }

/* A nota cabe agora com 0px de folga (mede 144px em 144px disponíveis). Zero de
   folga não é caber: qualquer arredondamento de fonte noutra máquina põe-na de
   volta em duas linhas. Ela come 3px do padding da própria célula em cada lado
   — a nota não tem fundo nem borda, então nada se vê. */
/* align-self: stretch é indispensável — a célula é `align-items: center`, logo
   os filhos são do tamanho do seu conteúdo e a margem negativa não lhes dava
   largura nenhuma. */
#boletim-card .b2-cell-note { align-self: stretch; margin-inline: -3px; }

/* A etiqueta de edição do cabeçalho ("EDIÇÃO #031 · FONTE: PORTO DE MANAUS /
   SGB / ANA") herdava a mono de um ancestral. É uma frase, não uma coluna. */
#boletim-card .boletim-hero-edition {
    font-family: var(--font-body);
    letter-spacing: 0.1px;
}

/* ==========================================================================
   BOLETIM — MENOS RESPIRO, MAIS INFORMAÇÃO
   O card é lido como imagem encolhida no WhatsApp. Aí o padding não se lê como
   elegância: lê-se como altura gasta a não dizer nada. Cada valor abaixo é o
   anterior a menos ~30%, e nenhum desce abaixo de 5px (a partir daí o texto
   encosta na borda do painel).
   ATENÇÃO: o padding do .chart-card e a margem NEGATIVA do cabeçalho dele têm
   de ser iguais em módulo — o cabeçalho sangra até à moldura. Ver
   "#boletim-card .chart-card > .card-header" mais acima.
   ========================================================================== */
#boletim-card { gap: 10px; }
#boletim-card .b2-row { gap: 8px; }
#boletim-card .b2-panel-head { padding: 6px 9px; }
#boletim-card .b2-verdict-strip { min-height: 0; padding: 5px 9px; }
#boletim-card .b2-panel-body { padding: 8px 9px; }
#boletim-card .b2-panel-foot { padding: 5px 9px 6px; }
#boletim-card .b2-evo-item { padding: 5px 0; }
#boletim-card .chart-card { padding: 10px 9px 6px 9px !important; }
/* A barra tinha ~54px de altura enquanto o rodapé eram duas linhas de texto e
   caiu para ~33px ao passar a uma. Com o monograma de 24px e este padding
   volta aos ~53px — a mesma presença de assinatura no fim do card, sem as duas
   linhas empilhadas que a davam antes. */
#boletim-card .boletim-footer { padding: 10px 18px 11px; }
#boletim-card .boletim-hero-photo-content { padding: 12px 14px 13px; }

/* Colunas da Previsão: o painel tem ~225px de largura útil. Sem o " m" em cada
   célula (subiu para o cabeçalho) os números cabem em 50px, e sobram ~113px
   para o rótulo do horizonte ("19 d · 09/09" mede ~66px). */
#boletim-card .b2-panel--side .b2-evo-value,
#boletim-card .b2-panel--side .b2-evo-rate { flex: 0 0 50px; }

/* --- FAIXA DE INDICADORES encostada à cabeça (padrão v8) ---
   A cabeça e o rodapé do boletim sangram até às bordas do card com margem
   negativa; a faixa dos cinco indicadores passa a fazer o mesmo e a encostar na
   tarja do título. Deixa de ser um painel solto (que precisava de um título
   próprio) e passa a ser a segunda barra da cabeça.
   O -10px de cima é exactamente o `gap` de #boletim-card: qualquer outro valor
   deixa uma fenda ou sobrepõe. Se o gap mudar, este muda. */
#boletim-card .b2-panel--full {
    margin: -10px calc(-1 * var(--boletim-pad-x)) 0;
    border-top: 0;
    border-left: 0;
    border-right: 0;
    border-radius: 0;
    /* Tinta de fundo para a faixa se ler como barra e não como texto a flutuar
       sobre o card. Mesmo token das tarjas de título dos painéis, mais fraco
       porque aqui cobre a largura toda. */
    background-color: rgba(var(--overlay-rgb), 0.03);
}

/* --- A FAIXA NÃO ENCHIA A LARGURA ---
   `.b2-panel--full` traz `width: 100%`. Com a margem negativa que a faz sangrar,
   esses 100% continuam a ser 100% da caixa de conteúdo do card (792px): a caixa
   começava 14px à esquerda da borda e acabava 14px ANTES da borda direita.
   `width: auto` deixa o flex esticar a faixa até às duas margens. */
#boletim-card .b2-panel--full { width: auto; }

/* O título é agora o sumário executivo e carrega três factos em vez de um, logo
   é mais comprido. Um passo abaixo na escala mantém-no em duas linhas em vez de
   três, e continua a ser o maior corpo do card. */
#boletim-card .boletim-hero-headline { font-size: 1.42rem; }

/* ==========================================================================
   BOLETIM — VEREDITO COMO SELO NA TARJA DO TÍTULO
   Cada painel gastava uma linha inteira (.b2-verdict-strip) só para a palavra
   do veredito. O gráfico já resolvia o mesmo problema com um selo no canto da
   tarja ("ATENÇÃO EM ~32D"), e a tarja tem espaço vazio à direita em todos os
   painéis. Três linhas poupadas, e um padrão só em vez de dois.
   O tom vem das classes b2-tone-* que setTone() já escreve — as mesmas quatro
   que colorem os números do card. As regras .prog-badge.status-* continuam a
   existir para o dashboard, que não usa b2-tone-*.
   ========================================================================== */
#boletim-card .b2-panel-head,
#boletim-card .chart-card > .card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

#boletim-card .prog-badge {
    font-family: var(--font-body);
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: 0.3px;
    /* inline-flex + altura fixa em vez de padding vertical: com padding, a
       caixa era a soma da caixa-de-linha da fonte (que tem mais folga acima
       das maiúsculas do que abaixo) e o texto assentava alto dentro do selo.
       Com altura própria e align-items:center, o texto fica a meio do selo,
       e o line-height deixa de decidir a altura. */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 19px;
    /* padding-top de 2px, não 0: a caixa de linha da Fira Sans tem mais folga
       ACIMA das maiúsculas do que abaixo (medido na página viva: 2,5px em cima
       contra 4,5px em baixo), logo centrar a caixa deixa a PALAVRA alta. Os
       2px de padding empurram-na para o meio óptico do selo. Medido, não
       adivinhado — ver o comentário da medição abaixo. */
    padding: 2px 8px 0;
    border-radius: 9px;
    line-height: 1;
    white-space: nowrap;
}

/* `color` vem de .b2-tone-*; aqui entram o fundo e a borda que fazem o selo.
   currentColor: uma cor só por tom, não três valores a ter de concordar. */
/* O fundo era rgba(--overlay-rgb, 0.06): cinzento igual nos quatro tons, logo
   só a borda e o texto diziam a severidade. Agora cada selo tem o fundo do seu
   PRÓPRIO tom, muito diluído — o selo lê-se como um bloco de cor à distância
   do telefone, antes de a palavra ser legível.
   Os rgba são escritos à mão em vez de color-mix(currentColor...) porque o
   html2canvas não resolve color-mix e o fundo sairia transparente no PNG. */
#boletim-card .prog-badge.b2-tone-critical {
    background-color: rgba(239, 68, 68, 0.14);   /* --status-critical */
    border: 1px solid currentColor;
}

#boletim-card .prog-badge.b2-tone-warning {
    background-color: rgba(245, 158, 11, 0.16);  /* --status-restricted */
    border: 1px solid currentColor;
}

#boletim-card .prog-badge.b2-tone-normal {
    background-color: rgba(16, 185, 129, 0.14);  /* --status-normal */
    border: 1px solid currentColor;
}

#boletim-card .prog-badge.b2-tone-neutral {
    background-color: rgba(var(--overlay-rgb), 0.07);
    border: 1px solid currentColor;
}

/* ==========================================================================
   BOLETIM — CABEÇA E RODAPÉ NUM FUNDO SÓ
   Havia três fundos diferentes em três barras: a tarja de topo com um gradiente
   diagonal, a faixa do título com um gradiente vertical mais escuro, e o rodapé
   com um terceiro gradiente. O objectivo dos gradientes era criar uma "costura"
   entre as barras; com o card já muito mais compacto, o que eles fazem é
   parecerem três tons por acidente. Um fundo só, e a costura passa a ser a
   régua laranja (que já existia) e a faixa de indicadores clara no meio.
   ========================================================================== */
#boletim-card .boletim-hero-topbar,
#boletim-card .boletim-footer {
    background: rgb(42, 45, 51);
}

#boletim-card .boletim-hero-photo {
    background:
        linear-gradient(90deg, #0a0b0c 0%, rgba(10,11,12,0.94) 30%, rgba(10,11,12,0.55) 60%, rgba(10,11,12,0.05) 100%),
        url('../img/river_banner_header_crop.jpg') center 8% / cover no-repeat;
}

/* A tarja de topo tem agora dois itens (logótipo e edição) em vez de três, e a
   edição já se empurra para a direita com margin-left: auto. Altura mínima
   restaurada (era 0) para o banner de fundo mostrar mais do rio/horizonte
   em vez de ficar cortado pela altura do texto. */
#boletim-card .boletim-hero-photo { min-height: 190px; }

/* A regra do corpo do .boletim-hero-headline saiu daqui: ele deixou de ser o
   título e passou a ser a segunda linha. Ver "O TIPO DE DOCUMENTO É O TÍTULO"
   mais abaixo, que é agora o único sítio que o dimensiona. */

#boletim-card .boletim-hero-lede {
    font-family: var(--font-body);
    font-size: 0.78rem;
    font-weight: 400;
    line-height: 1.45;
    color: #CBD5E1;
    margin-top: 5px;
    /* Sem max-width: com 66ch as duas frases caíam em TRÊS linhas e a cabeça
       crescia 30px. À largura toda cabem em duas, e duas linhas não precisam de
       medida curta para o olho encontrar o início da seguinte. */
}

/* A faixa de indicadores respira como as células do v8. Referência medida no
   ficheiro real (comunicado-seca-2026-v8.html, dentro de "Alerta Seca
   Supporte.zip"): `.data-cell { padding: 18px 16px; text-align: center; }`.
   Os 18px verticais entram tal e qual. Os 16px laterais NÃO: no v8 são três
   células num card de 780px (260px cada), aqui são cinco em 792px (154px cada),
   e 16px de cada lado tirariam à nota da quinta célula a largura que ela precisa
   para caber numa linha (ver a medição de 144px numa entrada anterior). */
#boletim-card .b2-panel--full .b2-panel-body { padding: 18px 9px; }

/* ==========================================================================
   BOLETIM — O TIPO DE DOCUMENTO É O TÍTULO
   Auditoria do cabeçalho, medida na página viva: a linha que diz o que este
   documento É ("RELATÓRIO DE ESTIAGEM") tinha 10,88px — o CORPO MAIS PEQUENO
   de todo o cabeçalho. Menor do que a data (11,52px) e do que os rótulos das
   células (12,16px). E o corpo maior do cabeçalho (24,8px) era o estado do rio,
   que a célula vermelha "ACELERANDO" repete 40px abaixo.
   Resultado: o olho aterra no estado do rio e a intenção do relatório, que é a
   coisa que se procura primeiro num telefone, perdia por ser a menor de todas.
   A hierarquia inverte-se: o tipo de documento passa a ser o corpo maior do
   card inteiro, e o estado do rio desce a segunda linha, em laranja.
   O título é uma CONSTANTE — o alerta vive nas células e no texto, nunca aqui.
   A altura do cabeçalho não muda (250px medidos antes e depois).
   ========================================================================== */
#boletim-card .boletim-hero-kicker {
    font-family: var(--font-heading);
    font-size: 2.35rem;
    font-weight: 800;
    /* O espaçamento de 2,2px servia uma etiqueta de 11px; a 37,6px ele abriria
       a palavra até ela não caber. A negativo, aperta o que a caixa alta a este
       corpo tem de folga a mais. */
    letter-spacing: -0.4px;
    line-height: 1.02;
    /* Branco, não laranja: a este corpo o laranja da marca sobre a foto escura
       vibra, e o laranja passa a marcar a linha do estado abaixo — uma cor de
       acento por cabeçalho, não duas. */
    color: #FFFFFF;
    margin-bottom: 1px;
}

/* O estado do rio: segunda linha, laranja, o acento que a etiqueta tinha. */
#boletim-card .boletim-hero-headline {
    font-size: 1.12rem;
    font-weight: 700;
    letter-spacing: 0.1px;
    line-height: 1.3;
    color: var(--supporte-orange);
}

/* ==========================================================================
   BOLETIM — FAIXA DE INDICADORES COM MAIS PESO E COM SÍMBOLOS
   A faixa é o bloco que responde "onde está o rio agora" e era o que menos
   pesava do card: rótulos de 11,5px e vereditos de 17,6px, mais pequenos que os
   números das tabelas abaixo. Sobe um passo em tudo.
   ========================================================================== */
#boletim-card .b2-panel--full .b2-cell-label {
    font-size: 0.76rem;
    letter-spacing: 0.3px;
}
#boletim-card .b2-panel--full .b2-cell-verdict {
    font-size: 1.28rem;
    font-weight: 800;
}
/* A excepção de corpo desta célula (1,02rem contra 1,28rem das outras) saiu:
   o valor voltou a ser UMA palavra ("ACELERANDO") e a palavra "Vazante" mudou
   para o rótulo. Quatro células, um corpo. */

#boletim-card .b2-panel--full .b2-cell-big { font-size: 2.1rem; }
#boletim-card .b2-panel--full .b2-cell-big .b2-unit { font-size: 0.95rem; }
/* A seta desce de 1,6rem para 1,15em DO TEXTO ao lado dela: em `em` ela cresce
   com a palavra e nunca volta a ser reajustada à mão, e a 1,6rem absolutos era
   maior do que a própria palavra que qualifica. */
#boletim-card .b2-panel--full .b2-cell-arrow { font-size: 1.15em; }

/* --- UMA LINHA DE VALOR PARA AS QUATRO CÉLULAS ---
   Auditoria da faixa na página viva: os quatro valores começavam a 21,8 / 19,8 /
   19,8 (seta) e 22,7 (palavra) / 21,8 px do topo da célula, com margens de topo
   de 4px em duas células e 2px nas outras. Quatro alturas de linha diferentes
   (18,8 / 37 / 29,4 / 23,5 px) davam quatro linhas de base diferentes — era isto
   que fazia a faixa ler-se como quatro caixas soltas.
   A caixa do valor passa a ter a MESMA altura em todas (a da cota, que é a mais
   alta e manda), e o conteúdo centra-se nela. Assim as palavras pequenas ficam
   alinhadas com o número grande em vez de penduradas no topo, e a nota da quarta
   célula começa sempre à mesma altura. */
#boletim-card .b2-panel--full .b2-cell-verdict,
#boletim-card .b2-panel--full .b2-cell-big {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 37px;
    margin-top: 4px;
}

/* Símbolo monocromático ao lado do veredito. Dimensionado em `em`, logo cresce
   com o texto que acompanha e nunca precisa de ser reajustado à mão.
   `currentColor` em vez de uma cor própria: é o que faz o símbolo tomar o tom do
   estado (verde em NORMAL, vermelho em EM VIGOR) sem uma linha de JS. */
#boletim-card .b2-cell-icon {
    width: 1.05em;
    height: 1.05em;
    flex: 0 0 auto;
    vertical-align: -0.1em;
    margin-right: 5px;
    /* O traço do SVG é declarado em unidades do viewBox 24x24; a 0,95em de
       ~20px, 2.2 dá uma linha de ~1,8px — o mesmo peso visual do texto a 800. */
}

/* O veredito com ícone deixa de ser um bloco de texto e passa a ser uma linha
   de dois itens, para o glifo e a palavra ficarem centrados JUNTOS na célula. */
#boletim-card .b2-cell-verdict:has(> .b2-cell-icon) {
    display: flex;
    align-items: center;
    justify-content: center;
}

/* --- Legenda visual do gráfico do boletim. Flex, nunca grid: dentro do
   #boletim-card o html2canvas não resolve CSS Grid (ver nota no topo do
   bloco do boletim). As amostras são bordas e blocos sólidos, sem gradiente
   nem color-mix, pelas mesmas razões de captura. As cores vêm inline do JS,
   da paleta do gráfico, para legenda e curvas nunca divergirem. --- */
.b2-chart-legend {
    /* UMA linha, centrada (pedido 2026-08-24). nowrap é deliberado: a legenda
       tem de caber, e o que garante isso são os rótulos curtos — deixar quebrar
       esconderia um rótulo comprido de mais em vez de o expor. Medido a 770px
       de largura útil: os seis itens somam ~676px + 70px de vãos. */
    display: flex;
    flex-wrap: nowrap;
    justify-content: center;
    align-items: center;
    gap: 0 14px;
    margin: 5px 0 0;
    padding-top: 6px;
    border-top: 1px solid var(--border-color);
    font-family: var(--font-body);
    font-size: 0.64rem;
    line-height: 1.35;
    color: var(--text-secondary);
}

.b2-legend-item {
    display: flex;
    align-items: center;
    white-space: nowrap;
}

.b2-legend-swatch {
    display: flex;
    align-items: center;
    flex: 0 0 auto;
    width: 18px;
    margin-right: 5px;
}

/* Amostra de linha = só a borda de cima de um span sem altura. Um par de
   segmentos lado a lado mostra que a categoria tem dois tons (o ano mais
   recente é o mais forte), o que a nota de texto não conseguia dizer. */
.b2-legend-seg {
    display: block;
    flex: 1 1 0;
    height: 0;
}

.b2-legend-block {
    display: block;
    width: 18px;
    height: 9px;
    border-radius: 2px;
}

.b2-legend-item--note {
    color: var(--text-secondary);
    opacity: 0.85;
}

#boletim-card .b2-chart-legend {
    font-size: 0.64rem;
    gap: 0 14px;
}

/* ============================================================
   RODAPÉ DE PRAZOS DO GRÁFICO DA VAZANTE (página Secas)
   ============================================================
   A primeira versão disto era um cartão grande, igual nas duas páginas, posto
   entre os indicadores e os gráficos: repetia os mesmos números e lia-se como
   algo enfiado à força na página. Agora é o rodapé do gráfico que já desenha as
   três linhas — altura de uma linha de texto, tipografia de legenda, sem caixa
   nem borda própria, porque não é um painel: é a legenda do que está acima. */
.chart-deadlines {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 18px;
    padding: 8px 4px 0 4px;
    margin-top: 2px;
    border-top: 1px solid var(--border-color);
    font-size: 0.72rem;
    color: var(--text-secondary);
    /* Não encolhe nem cresce: o gráfico acima é que absorve a altura sobrante
       do cartão (ver .chart-card, flex column). */
    flex: 0 0 auto;
}

.chart-deadlines:empty {
    display: none;
}

.cd-item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
}

/* Limiar já cruzado é facto, não prazo — perde ênfase para os que faltam. */
.cd-item--past { opacity: 0.5; }

.cd-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex: 0 0 auto;
}

.cd-dot--aten { background: var(--status-restricted); }
.cd-dot--crit { background: var(--status-critical); }
/* A taxa de seca não é faixa de profundidade, é a regra de cobrança: marca
   neutra, igual à linha mais grossa do gráfico. */
.cd-dot--lws  { background: var(--text-primary); }

.cd-name { color: var(--text-secondary); }

.cd-eta {
    font-family: var(--font-mono, 'Fira Code', monospace);
    font-weight: 600;
    color: var(--text-primary);
}

/* Empurrada para a direita: é a fonte, não um dos prazos. */
.cd-note {
    margin-left: auto;
    font-size: 0.66rem;
    opacity: 0.7;
    font-style: italic;
}

/* A nota de fonte só cabe na MESMA linha dos três prazos em ecrãs largos; o
   cartão do gráfico tem cerca de metade da largura da janela. Abaixo de 1400px
   ela cairia sozinha numa segunda linha, o que a faz parecer um dado solto. É
   atribuição, não dado: sai. A mesma atribuição continua no boletim e no
   rodapé do card. */
@media (max-width: 1400px) {
    .cd-note { display: none; }
}


/* ======================================================================
   COMUNICADO SECA — documento institucional para clientes (view-comunicado)
   ======================================================================
   PALETA FIXA, NÃO TOKENS DE TEMA. Todas as outras views usam
   var(--card-bg)/var(--text-primary) e mudam com o botão de tema. Esta não:
   o comunicado sai como PNG e como PDF para a base de clientes, e o
   documento tem de ser idêntico venha de que máquina vier. Se herdasse os
   tokens, o operador que estivesse em modo escuro exportaria uma carta
   preta para os clientes. Os hexadecimais abaixo são os mesmos valores da
   marca (#F37021 laranja, #58595B chumbo) e do comunicado v8 (#2A2D33
   tarja escura), escritos à mão de propósito.

   LAYOUT 100% FLEXBOX, sem CSS Grid: o html2canvas quebra grid, e este card
   é alvo de captura (mesma restrição do .boletim).
   ====================================================================== */

.comunicado {
    /* Mais largo que o .boletim (820px) porque é um documento de texto
       corrido com tabelas de cinco colunas, não um painel de indicadores.
       860px é a largura em que a tabela de lead time cabe sem apertar a
       coluna de rota. */
    width: 860px;
    max-width: 100%;
    margin: 0 auto 30px auto;
    background: #FFFFFF;
    color: #2A2D33;
    border-radius: 6px;
    /* overflow:hidden é o que faz a tarja escura e a capa respeitarem o
       border-radius do card. Combinado com flex-shrink por omissão (1), porém,
       era também o que CORTAVA o documento: .dashboard-view é um contentor
       flex-column, o card é um item, e o item encolhia para a altura da
       viewport levando o overflow:hidden a esconder tudo abaixo dela (medido:
       3759px de conteúdo dentro de 899px de card). O .boletim não sofre disto
       só porque não tem overflow:hidden — o conteúdo transborda visível.
       flex:0 0 auto impede o encolhimento e mantém os cantos arredondados. */
    overflow: hidden;
    flex: 0 0 auto;
    box-shadow: 0 14px 34px rgba(0, 0, 0, 0.28);
    font-family: var(--font-body);
    display: flex;
    flex-direction: column;
}

/* ---- 1. TARJA DE MARCA ---- */
.cm-topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    background: #2A2D33;
    padding: 16px 34px;
    border-bottom: 3px solid #F37021;
}

.cm-topbar-brand {
    display: flex;
    align-items: center;
    gap: 12px;
}

/* Altura fixa + width:auto é seguro num <svg> inline (paths desenhados
   directamente pelo html2canvas), ao contrário de um <img> que precisa de
   tamanho intrínseco. Mesma regra da .boletim-wordmark. */
.cm-wordmark {
    height: 30px;
    width: auto;
    display: block;
}

.cm-topbar-divider {
    width: 1px;
    height: 24px;
    background: rgba(255, 255, 255, 0.22);
}

.cm-topbar-serie {
    font-family: var(--font-heading);
    font-size: 1.12rem;
    font-weight: 300;
    color: #FFFFFF;
    letter-spacing: 0.2px;
}

.cm-topbar-meta {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 2px;
    text-align: right;
}

.cm-topbar-meta-k {
    font-size: 0.62rem;
    font-weight: 600;
    letter-spacing: 1.3px;
    text-transform: uppercase;
    color: #8B8F98;
}

.cm-topbar-meta-v {
    font-size: 0.78rem;
    font-weight: 600;
    color: #FFFFFF;
}

/* ---- 2. CAPA ---- */
.cm-cover {
    position: relative;
    min-height: 264px;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    /* Gradiente POR CIMA da foto na mesma declaração, não num pseudo-elemento:
       o html2canvas não compõe ::before com mistura fiável. */
    background:
        /* Escurecimento forte até 62%: a etiqueta laranja e o título ficam
           nessa faixa, e sobre a zona clara do porto (céu ao amanhecer) o
           laranja da marca perdia contraste. O topo continua quase limpo,
           para a foto ainda se ver. */
        linear-gradient(to top, rgba(14, 16, 18, 0.96) 0%, rgba(14, 16, 18, 0.93) 46%, rgba(14, 16, 18, 0.78) 66%, rgba(14, 16, 18, 0.34) 86%, rgba(14, 16, 18, 0.08) 100%),
        url('../img/supporte_mana_port.png') center 46% / cover no-repeat;
}

.cm-cover-body {
    padding: 30px 34px 26px;
}

.cm-cover-label {
    font-size: 0.66rem;
    font-weight: 700;
    letter-spacing: 2.2px;
    text-transform: uppercase;
    color: #F37021;
    margin-bottom: 9px;
    /* Sombra, e não uma faixa de fundo: a etiqueta assenta sobre a zona clara
       da foto (água ao amanhecer) e o laranja da marca perdia contraste ali.
       O gradiente da capa já foi escurecido o máximo que dá sem apagar a
       foto; a sombra resolve o resto sem acrescentar uma caixa ao desenho.
       O html2canvas desenha text-shadow, ao contrário de backdrop-filter. */
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.85);
}

.cm-cover-title {
    font-family: var(--font-heading);
    font-size: 1.92rem;
    font-weight: 700;
    line-height: 1.14;
    letter-spacing: -0.3px;
    color: #FFFFFF;
    margin: 0;
    max-width: 700px;
}

.cm-cover-sub {
    margin: 11px 0 0;
    font-size: 0.86rem;
    line-height: 1.48;
    color: rgba(255, 255, 255, 0.82);
    max-width: 690px;
}

/* ---- 3. FAIXA DE LEITURA RÁPIDA ---- */
.cm-tldr {
    display: flex;
    background: #2A2D33;
}

.cm-tldr-item {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 3px;
    padding: 15px 20px 16px;
    border-right: 1px solid rgba(255, 255, 255, 0.09);
}

.cm-tldr-item:last-child { border-right: none; }

.cm-tldr-k {
    font-size: 0.6rem;
    font-weight: 600;
    letter-spacing: 1.1px;
    text-transform: uppercase;
    color: #8B8F98;
    /* Explícito, e não "normal": as quatro células são itens flex de altura
       igual, então uma quebra num rótulo estica as outras três. Com
       line-height numérico a altura da célula é previsível e a quebra é
       detetável por medição em vez de a olho. Os rótulos foram encurtados
       para caberem numa linha nos ~193px de cada célula. */
    line-height: 1.3;
}

.cm-tldr-v {
    font-family: var(--font-heading);
    font-size: 1.24rem;
    font-weight: 700;
    line-height: 1.12;
    color: #F37021;
    margin-top: 2px;
}

/* O estado do plano é a única célula que não é uma medição do rio, logo não
   leva o laranja de alerta que as outras três levam. Verde de "em ordem",
   o mesmo --status-normal do painel, escrito à mão por causa da regra de
   paleta fixa desta view. */
.cm-tldr-v--ok { color: #34D399; }

.cm-tldr-s {
    font-size: 0.66rem;
    line-height: 1.35;
    color: #A8ACB4;
}

/* ---- 4-11. CORPO ---- */
.cm-body {
    padding: 30px 34px 26px;
}

.cm-salut {
    font-size: 0.92rem;
    font-weight: 600;
    margin: 0 0 14px;
    color: #2A2D33;
}

.cm-p {
    font-size: 0.87rem;
    line-height: 1.62;
    color: #3C4048;
    margin: 0 0 13px;
    text-align: justify;
    /* Hifenização OBRIGATÓRIA aqui. Justificar português numa coluna de
       ~790px sem hífen abre rios de espaço em branco no meio das linhas
       (visível no parágrafo de abertura antes desta regra). O dicionário
       vem do lang="pt-BR" do <html>. */
    hyphens: auto;
    -webkit-hyphens: auto;
}

.cm-p--claim {
    font-weight: 600;
    color: #2A2D33;
    text-align: left;
}

.cm-h2 {
    display: flex;
    align-items: center;
    gap: 11px;
    font-family: var(--font-heading);
    font-size: 1.06rem;
    font-weight: 700;
    color: #2A2D33;
    margin: 27px 0 12px;
    padding-bottom: 8px;
    border-bottom: 1px solid #E4E7EC;
}

/* Numeração como selo, não como "1." dentro do texto: o comunicado tem seis
   secções e o leitor de e-mail precisa de saber onde está sem contar. */
.cm-h2-num {
    flex: 0 0 auto;
    width: 22px;
    height: 22px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #F37021;
    color: #FFFFFF;
    border-radius: 3px;
    font-size: 0.7rem;
    font-weight: 700;
}

.cm-note {
    font-size: 0.7rem;
    line-height: 1.5;
    color: #7A7F88;
    margin: 8px 0 13px;
}

/* ---- TABELAS (flex, não <table> nem grid) ---- */
.cm-table {
    display: flex;
    flex-direction: column;
    border: 1px solid #E4E7EC;
    border-radius: 4px;
    overflow: hidden;
    margin: 4px 0 12px;
}

.cm-table-cap {
    font-size: 0.66rem;
    font-weight: 600;
    letter-spacing: 0.8px;
    text-transform: uppercase;
    color: #7A7F88;
    background: #F7F8FA;
    padding: 8px 14px;
    border-bottom: 1px solid #E4E7EC;
}

.cm-tr {
    display: flex;
    align-items: center;
    border-bottom: 1px solid #EEF0F4;
}

.cm-tr:last-child { border-bottom: none; }

.cm-tr--head {
    background: #F7F8FA;
    border-bottom: 1px solid #E4E7EC;
}

.cm-tr--head .cm-td {
    font-size: 0.64rem;
    font-weight: 700;
    letter-spacing: 0.7px;
    text-transform: uppercase;
    color: #7A7F88;
}

/* Linha de limiar já ultrapassado: cinza e sem ênfase — um prazo que já
   passou não é um alerta, é histórico. */
.cm-tr--past { background: #FAFBFC; }
.cm-tr--past .cm-td { color: #9AA0A8; }

.cm-td {
    flex: 1 1 0;
    min-width: 0;
    padding: 9px 14px;
    font-size: 0.8rem;
    color: #3C4048;
    font-variant-numeric: tabular-nums;
}

/* Primeira coluna: o nome da linha, mais forte e um pouco mais larga. */
/* 150px, e não 118px: com 118 os nomes dos limiares ("Atenção operacional",
   "Taxa de seca (ANTAQ)", "Restrição crítica") quebravam em duas linhas e
   duplicavam a altura de todas as linhas da tabela. */
.cm-td--k {
    flex: 0 0 150px;
    font-weight: 600;
    color: #2A2D33;
}

.cm-td--wide { flex: 1.3 1 0; }
.cm-td--rota { flex: 0 0 218px; font-weight: 600; color: #2A2D33; }
.cm-td--acc { color: #B04E14; font-weight: 600; }

/* Ano em destaque na tabela comparativa (a linha de 2026). */
.cm-tr--now { background: #FEF3E7; }
.cm-tr--now .cm-td--k { color: #B04E14; }

.cm-table--lt .cm-td { font-size: 0.76rem; }

/* ---- QUADRO DUPLO (comparativo | limiares), lado a lado ----
   flex-wrap: em viewport estreita as duas caem uma sob a outra em vez de
   transbordar. align-items: flex-start para a mais curta (limiares, 3 linhas)
   nao esticar ate a altura da mais longa (comparativo, 5 linhas) — esticar
   deixaria uma faixa vazia dentro da moldura. */
.cm-duo {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 12px;
    margin: 4px 0 12px;
}

.cm-duo > .cm-table {
    flex: 1 1 calc(50% - 6px);
    min-width: 296px;
    margin: 0;
}

/* Tudo um ponto menor: metade da largura, o mesmo numero de colunas. */
.cm-duo .cm-table-cap { font-size: 0.62rem; padding: 7px 12px; }
.cm-duo .cm-tr--head .cm-td { font-size: 0.6rem; }
.cm-duo .cm-td {
    padding: 7px 10px;
    font-size: 0.76rem;
}

/* Larguras da PRIMEIRA coluna, medidas pelo conteudo real de cada quadro:
   "2026" de um lado, "20,00 m" do outro. O resto reparte-se. */
.cm-table--comp .cm-td--k { flex: 0 0 52px; }
/* 96px e nao 74px: esta coluna passou a levar o ponto de estado antes da
   cota. Com 74px "20,00 m" partia em duas linhas e o quadro dos limiares ficava
   56px mais alto do que o dos anos, ao lado. */
.cm-table--marcos .cm-td--k { flex: 0 0 96px; }
/* A ultima coluna leva o texto mais longo dos dois quadros
   ("13,19–16,01 (est.)" e "~25 dias · Setembro"), logo e a que precisa de
   mais espaco. */
.cm-table--comp .cm-td--wide { flex: 1.5 1 0; }

/* ---- ÍCONE DE ESTADO DOS DOIS QUADROS DA SECÇÃO 1 ----
   ÍCONE e não célula pintada: pintar o fundo das células transformava o par num
   painel de semáforos e o documento deixava de se ler como uma carta.
   A cor pinta o ícone E o valor ao lado dele, para que o número e o seu estado
   se leiam como uma coisa só.
   Quadro dos ANOS, na coluna da mínima — cor e forma dizem o mesmo, de
   propósito, para o quadro ler-se sem consultar a legenda:
     ▲ verde     a mínima do ano ficou acima da que projetamos para 2026
     ▼ vermelho  ficou abaixo
     ● preto     a própria linha de 2026, a referência da comparação
   Quadro dos LIMIARES, na coluna da cota — gravidade do degrau:
     ● verde     leitura de hoje, sem restrição
     ● amarelo   20,00 m, atenção operacional
     ● preto     17,70 m, o limiar da taxa de seca — o que muda a conta
     ● vermelho  16,00 m, restrição crítica
   As mesmas cores estão em CM_IC_EMAIL, em app.js, para o Outlook. */
.cm-ico {
    /* inline-block com largura fixa: as setas e o ponto têm larguras
       diferentes, e sem isto o texto de cada linha começava num sítio
       ligeiramente diferente. */
    display: inline-block;
    width: 13px;
    margin-right: 5px;
    font-size: 0.84rem;
    line-height: 1;
    text-align: center;
    /* Fallback explícito: se a fonte do documento não tiver ▲ ▼ ●, o browser
       vai buscá-los a uma fonte de símbolos em vez de desenhar um retângulo. */
    font-family: var(--font-body), 'DejaVu Sans', 'Segoe UI Symbol', sans-serif;
}

/* O AMARELO é um ouro escuro (#9A6E00), não um amarelo puro. Amarelo puro sobre
   branco dá ~2:1 de contraste e é ilegível como texto — e aqui a cor pinta
   também o valor, não só o ponto. #9A6E00 dá ~4,9:1 (acima do mínimo AA de
   4,5:1) e continua a ler-se como amarelo ao lado do preto e do vermelho. */
.cm-ic--verde    { color: #1D6B3C; }
.cm-ic--amarelo  { color: #9A6E00; }
.cm-ic--preto    { color: #111418; font-weight: 700; }
.cm-ic--vermelho { color: #A32017; }

/* A linha de 2026 / de hoje tem .cm-tr--now, e .cm-tr--now .cm-td--k (duas
   classes) ganhava por especificidade à cor do degrau (uma classe). Estas
   quatro regras devolvem-lhe a cor. */
.cm-tr--now .cm-ic--verde    { color: #1D6B3C; }
.cm-tr--now .cm-ic--amarelo  { color: #9A6E00; }
.cm-tr--now .cm-ic--preto    { color: #111418; }
.cm-tr--now .cm-ic--vermelho { color: #A32017; }
/* 1.05 e nao 1.35: o html2canvas mede o texto um pouco mais largo do que o
   ecra, e com 1.35 "Atenção operacional" partia em duas linhas SO no PNG
   exportado — que e o ficheiro que o cliente recebe. Medido no PNG real, nao
   no DOM. */
.cm-table--marcos .cm-td--wide { flex: 1.05 1 0; }

/* ---- IMPACTOS (lista numerada) ---- */
.cm-impactos {
    margin: 4px 0 14px;
    padding-left: 22px;
}

.cm-impactos li {
    font-size: 0.79rem;
    line-height: 1.52;
    color: #3C4048;
    margin-bottom: 10px;
    text-align: justify;
    hyphens: auto;
    -webkit-hyphens: auto;
}

.cm-impactos li::marker {
    color: #F37021;
    font-weight: 700;
}

.cm-impactos b { color: #2A2D33; }

/* ---- FRENTES DO PLANO (2x2) ---- */
.cm-frentes {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin: 4px 0 14px;
}

.cm-frente {
    /* calc com o gap: dois por linha em 860px, e ainda assim encolhe em
       viewport estreita em vez de transbordar. */
    flex: 1 1 calc(50% - 5px);
    min-width: 240px;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    column-gap: 7px;
    row-gap: 3px;
    background: #F7F8FA;
    border-left: 3px solid #F37021;
    border-radius: 0 4px 4px 0;
    padding: 11px 15px 12px;
}

.cm-frente-n {
    font-family: var(--font-heading);
    font-size: 0.72rem;
    font-weight: 700;
    color: #F37021;
    letter-spacing: 0.5px;
    flex: 0 0 auto;
}

.cm-frente-t {
    font-family: var(--font-heading);
    font-size: 0.9rem;
    font-weight: 700;
    color: #2A2D33;
    flex: 1 1 auto;
    min-width: 0;
}

/* flex-basis 100%: a descricao ocupa a segunda linha inteira, sem precisar de
   um elemento a embrulhar o numero e o titulo. O HTML fica igual e o
   construtor do e-mail continua a achar as tres classes com querySelector. */
.cm-frente-d {
    font-size: 0.76rem;
    line-height: 1.48;
    color: #5A5F68;
    flex: 0 0 100%;
}

/* ---- FECHAMENTO ---- */
.cm-fecho {
    margin-top: 24px;
    padding-top: 18px;
    border-top: 2px solid #F37021;
}

.cm-sign {
    font-size: 0.87rem;
    line-height: 1.6;
    color: #3C4048;
    margin: 16px 0 0;
}

/* ---- RODAPÉ ----
   Cópia da geometria de .boletim-footer, com os hexadecimais escritos à mão
   por causa da regra de paleta fixa desta view (ver o topo do bloco).
   Fundo escuro com filete laranja: fecha o documento com a mesma tarja que o
   abre, e emoldura a carta em vez de a deixar esvair-se no branco. */
.cm-footer {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 13px 30px 15px;
    border-top: 3px solid #F37021;
    background: linear-gradient(135deg, #1a1c19 0%, #101210 100%);
}

/* UMA coluna so, centrada: as pontas (fontes dos dados e data de geracao)
   foram retiradas. Com um unico filho, justify-content: center no .cm-footer
   basta — todo o arranjo de flex:1 1 0 + min-width:0 + overflow:hidden que
   era preciso para centrar a marca entre duas pontas de comprimentos
   diferentes saiu daqui.
   Coluna e nao linha dentro do centro: monograma em cima, nome debaixo. */
.cm-footer-center {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
}

.cm-footer-mark {
    height: 22px;
    width: auto;
    flex: 0 0 auto;
    display: block;
}

.cm-footer-brandline {
    font-size: 0.66rem;
    font-weight: 700;
    letter-spacing: 0.3px;
    color: #CBD5E1;
    white-space: nowrap;
}

/* O nome não leva cor própria: o laranja fica só no monograma acima dele, que
   é onde a marca vive. */
.cm-footer-brand {
    font-family: var(--font-heading);
    color: inherit;
}

/* ======================================================================
   IMPRESSÃO / PDF
   ======================================================================
   O botão "Imprimir / PDF" chama window.print(). Sem estas regras o browser
   imprimiria a barra lateral, a barra de ferramentas e as outras views
   (que estão só com display:none inline, e a impressão respeita isso — mas
   a sidebar e a toolbar não estavam escondidas).
   Só a .comunicado é impressa, em largura total da folha e sem sombra.
   ====================================================================== */
@media print {
    body { background: #FFFFFF; }
    aside.sidebar,
    .dashboard-header,
    .boletim-toolbar { display: none !important; }
    /* ---- A CADEIA DE SCROLL TEM DE SER DESFEITA ----
       Sem isto o PDF sai com UMA página só (verificado: 1 página, cortada a
       meio da tabela comparativa). O painel é uma aplicação de altura fixa:
       body tem height:100vh e overflow:hidden, main.content tem
       height/max-height:100vh e overflow:hidden, e .dashboard-view tem
       overflow:hidden com overflow-y:auto inline. Na impressão, cada um
       desses contentores recorta o conteúdo à altura da viewport em vez de
       o deixar fluir para as folhas seguintes. Todos precisam de height:auto
       E overflow:visible — mudar só um não basta, porque o de fora continua
       a recortar. O !important é necessário no overflow-y de
       .dashboard-view, que é um estilo inline no markup. */
    html, body {
        height: auto !important;
        max-height: none !important;
        overflow: visible !important;
        display: block !important;
    }
    main.content {
        margin-left: 0 !important;
        padding: 0 !important;
        height: auto !important;
        max-height: none !important;
        max-width: none !important;
        overflow: visible !important;
        display: block !important;
    }
    .dashboard-view {
        height: auto !important;
        overflow: visible !important;
        overflow-y: visible !important;
        display: block !important;
    }
    /* As outras views ficam com display:none inline quando não estão ativas,
       e a impressão respeita isso — mas a view ativa NÃO é necessariamente o
       comunicado. Esconder todas e reexibir só a do comunicado garante que
       Ctrl+P a partir de qualquer página imprime o documento certo. */
    .dashboard-view:not(#view-comunicado) { display: none !important; }
    #view-comunicado { display: block !important; }
    .comunicado {
        width: 100%;
        margin: 0;
        box-shadow: none;
        border-radius: 0;
    }
    /* Quebras de página nos lugares certos: nenhuma secção fica cortada ao
       meio, e nenhum título fica sozinho no fim da folha. */
    .cm-h2 { break-after: avoid; page-break-after: avoid; }
    /* Um paragrafo de introducao nao fica orfao no fim de uma folha com a
       tabela que ele apresenta na folha seguinte. Junto com a regra do .cm-h2
       acima, isto arrasta titulo + introducao + tabela para a mesma folha.
       :has() e suportado no Chrome/Edge, que e por onde este PDF e gerado; em
       browsers sem :has() a regra e simplesmente ignorada e o resultado e o
       anterior, que ja era aceitavel — degrada, nao quebra. */
    .cm-p:has(+ .cm-table),
    .cm-p:has(+ .cm-duo) {
        break-after: avoid; page-break-after: avoid;
    }
    /* NAO JUNTAR ESTAS DUAS REGRAS. Ja aconteceu: ao passar o .cm-fecho para
       `auto`, o comentario ficou DENTRO da lista de seletores e os quatro
       passaram a `auto` de uma vez. Resultado no PDF: a tabela de lead time
       partida entre a folha 2 e a 3, com o cabecalho e uma linha so no fim da
       folha 2. Nada avisou — CSS invalido nao dá erro, e a lista continuou a
       parecer certa a olho. */
    .cm-table,
    .cm-frentes,
    .cm-impactos li,
    .cm-duo {
        break-inside: avoid; page-break-inside: avoid;
    }
    /* O FECHO PODE PARTIR. Com break-inside:avoid ele nao cabia no resto da
       ultima folha e saltava inteiro para uma folha extra, deixando um quarto
       de pagina em branco. Partir e melhor: o que NAO pode partir e a
       assinatura e a frase de fecho, e essas ficam protegidas abaixo. */
    .cm-fecho { break-inside: auto; page-break-inside: auto; }
    .cm-fecho .cm-p, .cm-sign {
        break-inside: avoid; page-break-inside: avoid;
    }
    /* A assinatura nunca se separa da frase que a antecede. */
    .cm-sign { break-before: avoid; page-break-before: avoid; }
    /* O browser não imprime cores de fundo por omissão; sem isto a tarja
       escura e a faixa de indicadores saíam brancas com texto branco. */
    .cm-topbar, .cm-tldr, .cm-cover, .cm-tr--head, .cm-table-cap,
    .cm-frente, .cm-footer, .cm-h2-num, .cm-tr--now {
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }
}

/* Parágrafo de citação de fonte oficial: recuado e com barra, para se
   distinguir da prosa da Supporte. O leitor tem de saber quando está a ler
   o SGB/UEA e quando está a ler-nos. */
.cm-p--src {
    border-left: 3px solid #D5DAE2;
    background: #F7F8FA;
    padding: 11px 15px;
    margin: 4px 0 14px;
    font-size: 0.8rem;
    color: #4A4F58;
    text-align: left;
}

/* Estado de captura do comunicado, posto e retirado por
   generateComunicadoCanvas(). Ver o comentário lá para o defeito que isto
   corrige: o html2canvas parte a palavra no ponto de hifenização e não
   desenha o hífen. Só o PNG usa esta variante; o ecrã e o PDF ficam
   justificados e hifenizados. */
.comunicado.cm-capturing .cm-p,
.comunicado.cm-capturing .cm-impactos li {
    text-align: left;
    hyphens: none;
    -webkit-hyphens: none;
}

/* ---- CAIXA DE ALERTA DO COMUNICADO ----
   O bloco mais importante do documento, e por isso o único com fundo colorido
   no corpo da carta. Barra laranja à esquerda no padrão do e-mail do boletim
   (.corAlerta em buildBoletimClientEmailHtml), para os dois canais se
   parecerem. UMA cor de fundo em qualquer nível de alerta: o que muda é a
   ETIQUETA, não o tom da caixa — uma caixa que muda de cor a cada semana
   deixa de ser reconhecível, e uma caixa azul de "vigilância" lê-se como
   informativa num documento que é de alerta. */
.cm-alerta {
    background: #FEF3E7;
    border-left: 4px solid #F37021;
    border-radius: 0 4px 4px 0;
    padding: 14px 18px 15px;
    margin: 4px 0 20px;
}

/* A etiqueta é a única peça que muda com a faixa em que o rio está. Só o
   TEXTO muda de tom; o fundo da caixa fica igual (ver acima). */
.cm-alerta-tag {
    font-size: 0.64rem;
    font-weight: 700;
    letter-spacing: 1.4px;
    text-transform: uppercase;
    color: #B04E14;
    margin-bottom: 6px;
}

.cm-alerta-tag--normal { color: #8A3D0B; }
.cm-alerta-tag--restricted { color: #A8500B; }
.cm-alerta-tag--critical { color: #B91C1C; }

.cm-alerta-txt {
    font-size: 0.92rem;
    line-height: 1.58;
    color: #3C4048;
    margin: 0;
}

/* Negrito dentro do alerta e da prosa: os números são o que o olho tem de
   encontrar primeiro. O tom é o da tinta do documento, não o laranja — com o
   laranja, sete negritos num parágrafo transformavam a caixa numa mancha. */
.cm-alerta-txt b,
.cm-p b {
    font-weight: 700;
    color: #1F2227;
}


/* Tabela de limiares: primeira coluna mais larga que os 150px partilhados.
   "Referência da TPS em 2025" e "Limite regulatório da TPS" quebravam em duas
   linhas ali e duplicavam a altura das quatro linhas da tabela. */


/* ---- AFINAÇÃO DE IMPRESSÃO ----
   Medido no PDF real: a capa de 264px + a faixa de indicadores + o alerta +
   a §1 deixavam a tabela comparativa sem espaço na folha 1, e como ela tem
   break-inside:avoid saltava inteira para a folha 2 — deixando um terço da
   folha 1 em branco. Numa peça que o cliente recebe em anexo, folha em branco
   lê-se como erro de montagem.
   A capa no ecrã é uma capa (foto grande, título grande); em papel é um
   cabeçalho. Reduzi-la é o que faz a tabela caber e o documento perder uma
   folha inteira. Nenhum conteúdo sai — só a moldura encolhe. */
@media print {
    .cm-cover {
        min-height: 168px;
        /* Com a capa a 168px em vez de 264px, o gradiente comprime-se e a
           etiqueta laranja volta a cair sobre a zona clara da foto (céu ao
           amanhecer) — ilegível no PDF. Aqui a foto é um cabeçalho, não uma
           capa, então o escurecimento pode ser bem mais forte sem prejuízo.
           A foto ainda se lê; a etiqueta e o título passam a ler-se sempre.
           Repetir o url() é necessário: `background` é uma shorthand e
           redeclará-la substitui a camada da imagem também. */
        background:
            linear-gradient(to top, rgba(14, 16, 18, 0.97) 0%, rgba(14, 16, 18, 0.94) 62%, rgba(14, 16, 18, 0.80) 84%, rgba(14, 16, 18, 0.55) 100%),
            url('../img/supporte_mana_port.png') center 46% / cover no-repeat;
    }
    .cm-cover-body { padding: 18px 30px 16px; }
    .cm-cover-title { font-size: 1.5rem; }
    .cm-cover-sub { font-size: 0.78rem; margin-top: 7px; }
    .cm-topbar { padding: 11px 30px; }
    .cm-wordmark { height: 24px; }
    /* A FAIXA DE INDICADORES EM PAPEL.
       Cada célula tem ~193px no ecrã e ~157px na folha A4. Com o corpo do ecrã
       as duas primeiras sublinhas ("-9 cm em 24 h · -2,87 m em 30 dias" e
       "vs. 12,11 m (2024) · 18,90 m (2025)") partiam em duas linhas no PDF e as
       outras duas não, e a faixa saía com quatro células visivelmente
       desalinhadas. Meio ponto menos de corpo nas sublinhas resolve as quatro
       de uma vez, sem tocar no rótulo nem no valor, que são o que se lê. */
    .cm-tldr-item { padding: 10px 13px 11px; }
    .cm-tldr-k { letter-spacing: 0.9px; }
    .cm-tldr-s { font-size: 0.58rem; line-height: 1.3; }
    .cm-body { padding: 22px 30px 18px; }
    /* Espaço entre secções: 27px no ecrã dá respiro numa página que rola; em
       papel, seis vezes 27px é meia folha. */
    .cm-h2 { margin: 18px 0 10px; }
    .cm-alerta { margin-bottom: 14px; }
    .cm-footer { padding: 11px 30px; }
    /* O QUADRO DUPLO EM PAPEL. A folha A4 com margens dá ~700px de coluna
       contra os 860px do ecrã, e cada um dos dois quadros fica com ~315px em
       vez de 390px. Com as medidas de ecrã a coluna do meio dos limiares
       apertava e "Atenção operacional" partia em duas linhas, duplicando a
       altura de todas as linhas do quadro. Menos padding, meio ponto menos de
       corpo e uma primeira coluna mais estreita devolvem esse espaço ao nome
       do limiar. */
    .cm-duo { gap: 10px; }
    .cm-duo > .cm-table { min-width: 0; }
    .cm-duo .cm-table-cap { padding: 6px 9px; }
    /* 0.69rem: em papel a coluna do meio e a da direita dos limiares
       ("Atenção operacional" e "~25 dias · Setembro") têm quase o mesmo
       comprimento e disputam o mesmo espaço. Repartir a largura de outra
       maneira só passava a quebra de uma para a outra; meio ponto menos de
       corpo faz as duas caberem. */
    /* AS TRÊS COLUNAS DOS LIMIARES EM PAPEL.
       A folha A4 com margens dá ~700px de coluna contra os 860px do ecrã, logo
       cada quadro fica com ~315px em vez de 390px. Nesse espaço as três colunas
       dos limiares têm quase o mesmo comprimento de conteúdo ("● 20,00 m",
       "Atenção operacional", "~25 dias · Setembro") e disputam a mesma largura:
       repartir a largura de outra maneira só passava a quebra de uma coluna
       para a outra. O que resolve é dar corpo menor a TODAS, e depois medir no
       PDF gerado — foi assim que estes valores foram fixados. */
    .cm-duo .cm-td { padding: 6px 7px; font-size: 0.66rem; }
    .cm-table--comp .cm-td--k { flex: 0 0 40px; }
    .cm-table--marcos .cm-td--k { flex: 0 0 74px; }
    .cm-table--marcos .cm-td--wide { flex: 1 1 0; }
    .cm-ico { width: 8px; margin-right: 3px; font-size: 0.76rem; }
    /* Aperto final: sem isto o rodape sobra sozinho numa 4a folha, com a
       pagina 3 a acabar na assinatura. Estes cortes somam ~70px, o suficiente
       para o rodape subir e o PDF fechar em 3 folhas. */
    .cm-p { margin-bottom: 11px; }
    .cm-impactos li { margin-bottom: 8px; }
    .cm-frente-t { margin-bottom: 3px; }
    .cm-fecho { margin-top: 18px; padding-top: 14px; }
    .cm-sign { margin-top: 12px; }
    .cm-frentes { margin-bottom: 4px; }
}

/* ======================================================================
   Aviso de publicação — inserido por build_publish.py.
   Só existe no pacote publicado; a cópia local de desenvolvimento não o tem.
   ====================================================================== */
.aviso-publicacao {
    /* Sem margem lateral e sem padding lateral: a borda de cima e o texto
       alinham com a coluna dos cartões, e não 24px para dentro dela. */
    margin: 24px 0 8px;
    padding: 12px 0 0;
    border-top: 1px solid var(--border-color, rgba(255,255,255,0.1));
    color: var(--text-secondary, #94a3b8);
    font-family: 'Fira Sans', system-ui, -apple-system, sans-serif;
    font-size: 0.7rem;
    line-height: 1.45;
}
/* SEM max-width, de propósito.
   A largura de leitura confortável (~105ch) é a regra certa para texto que se
   lê, e era o que estava aqui. Só que este aviso não se lê — confere-se. Com o
   corte em 105ch o parágrafo ficava com 630px dentro de um rodapé de 1128px, e
   as sobras iam todas para a ALTURA: 125px roubados aos gráficos em cada carga
   de página. Ocupando a largura toda, o mesmo texto cabe em metade das linhas. */
.aviso-publicacao p { margin: 0 0 4px; }
.aviso-publicacao p:last-child { margin-bottom: 0; }
@media print { .aviso-publicacao { display: none; } }
