/* Responsive thresholds remain in scoped rules because CSS custom properties cannot be used in media queries. */
:root {
    --color-ink: #17212b;
    --color-muted: #5d6873;
    --color-muted-generation: #64707b;
    --color-border: #dce1e5;
    --color-border-generation: #d9dfe3;
    --color-border-control: #aeb7bf;
    --color-surface: #fff;
    --color-surface-muted: #f4f6f7;
    --color-surface-table: #f2f4f5;
    --color-solar: #d97706;
    --color-solar-soft: #fff7e6;
    --color-wind: #087f5b;
    --color-wind-soft: #e9f7f1;
    --color-temperature: #b33a3a;
    --color-temperature-soft: #fff0f0;
    --color-demand: #176b5b;
    --color-demand-soft: #e8f5f1;
    --color-generation: #b33b24;
    --color-generation-soft: #fff1eb;
    --color-generation-dark: #792615;
    --color-production-solar: #2563a8;
    --color-production-wind: #087f5b;
    --color-home-copy: #33414d;
    --color-border-strong: #cbd3d9;
    --color-accent-border: #82b6aa;
    /* Darkened from #a86000, which fell to 4.47:1 against the muted surface the weather-basis note
       sits on — just under the 4.5:1 needed for text at that size. */
    --color-notice: #915300;
    --color-track: #e3e7ea;
    --color-track-fill: #3d667a;
    --color-track-border: #9da8b1;
    --color-chart-surface: #fbfcfc;
    --color-demand-line: #101820;
    --color-empty-storage: #f5f8f7;
    --color-accent-warm: #b8613f;
    --color-accent-cool: #4372a8;
    --color-positive: #176b5b;
    --color-negative: #b3341f;
    --color-positive-soft: #e8f5f1;
    --color-negative-soft: #fdeeea;
    --color-notice-soft: #fdf4e3;
    --font-body: Inter, 'Segoe UI', system-ui, -apple-system, sans-serif;
    --font-display: 'Source Serif 4', Georgia, "Times New Roman", serif;
    --type-eyebrow: 0.78rem;
    /* Brand chrome. Deliberately separate from the data palette above: the colours below dress
       the sidebar, the dark bands, the buttons and the mark, and none of them ever encodes a
       measured quantity. A chart's teal always means demand, never "this is a NEMSweep page". */
    --color-ink-surface: #141b2d;
    --color-ink-surface-raised: #1e2740;
    --color-on-ink: #f2f4f8;
    --color-on-ink-muted: #b3bcd0;
    --color-on-ink-accent: #e39a3c;
    --color-brand: #141b2d;
    --color-brand-hover: #26314c;
    /* The amber above fails contrast as text on white, so light surfaces get this darker ochre
       instead of the accent they sit beside on dark. */
    --color-brand-accent: #9a5b12;
    --color-brand-accent-soft: #fbf2e6;
    --color-brand-rule: #c8cedd;
    --radius-sm: 6px;
    --radius-md: 10px;
    --radius-lg: 16px;
    /* Tinted with the ink colour rather than pure black: a neutral-black shadow reads as grime
       over the warm-grey surfaces this palette uses. */
    --shadow-sm: 0 1px 2px rgba(23, 33, 43, 0.06), 0 1px 3px rgba(23, 33, 43, 0.05);
    --shadow-md: 0 2px 4px rgba(23, 33, 43, 0.05), 0 6px 16px rgba(23, 33, 43, 0.08);
    --shadow-lg: 0 4px 8px rgba(23, 33, 43, 0.05), 0 16px 40px rgba(23, 33, 43, 0.12);
    --measure: 68ch;
    --space-page-x: 1.25rem;
    --space-page-top: 1.5rem;
    --space-page-bottom: 3rem;
    --breakpoint-wide: 980px;
    --breakpoint-medium: 900px;
    --breakpoint-compact: 760px;
    --breakpoint-narrow: 700px;
    --breakpoint-mobile: 640px;
    --breakpoint-small: 420px;
    /* MainLayout's .top-row is only position: sticky from 641px up (see MainLayout.razor.css);
       below that it scrolls away with the page, so nothing needs to compensate for it there. */
    --sticky-header-height: 0px;
}

.page,
.home-page {
    --radius-sm: 0px;
    --radius-md: 4px;
    --radius-lg: 6px;
}

@media (min-width: 641px) {
    :root {
        --sticky-header-height: 3.5rem;
    }
}

/* A target of revealIfOffScreen (nem.js): scrollIntoView honours scroll-margin-top natively, so
   the reveal never has to separately measure the sticky header's height or race its layout. */
.scroll-reveal-target {
    scroll-margin-top: calc(var(--sticky-header-height) + 0.75rem);
}

html {
    /* Anchors in the marketing nav and the chart reveals in nem.js both scroll the document, and
       both read better as a movement than as a jump. */
    scroll-behavior: smooth;
    /* Tells the browser which palette to render form controls and scrollbars against. */
    color-scheme: light;
}

@media (prefers-reduced-motion: reduce) {
    html {
        scroll-behavior: auto;
    }
}

::selection {
    background: rgba(227, 154, 60, 0.3);
    color: var(--color-ink);
}

/* Headings set their own line breaks badly at the sizes this site uses, leaving one word alone on
   the last line of a two-line heading. */
h1, h2, h3 {
    text-wrap: balance;
}

/* The sidebar is ink, so a default light scrollbar sits on it as a bright stripe. */
.sidebar {
    scrollbar-width: thin;
    scrollbar-color: rgba(255, 255, 255, 0.25) transparent;
}

.sidebar ::-webkit-scrollbar {
    width: 8px;
}

.sidebar ::-webkit-scrollbar-thumb {
    border-radius: 4px;
    background: rgba(255, 255, 255, 0.22);
}

.sidebar ::-webkit-scrollbar-track {
    background: transparent;
}

html, body {
    font-family: var(--font-body);
    /* Inter's default figures are proportional, which makes a column of MWh values ragged. */
    font-feature-settings: 'cv05' 1;
    -webkit-font-smoothing: antialiased;
}

h1:focus {
    outline: none;
}

/* ---------------------------------------------------------------------------
   Focus

   Nothing in this stylesheet defined a focus ring, so keyboard focus fell back
   to the browser default and then to nothing at all wherever a component set
   outline: none. The double ring holds on both grounds the site uses: the
   accent reads on white, the white halo reads on the ink sidebar.
   --------------------------------------------------------------------------- */

/* Written out rather than wrapped in :where(): MudBlazor ships a:focus-visible { outline: none },
   and a :where() selector contributes no specificity, so the reset won and focus stayed invisible.
   These match its specificity and app.css loads after it. */
a:focus-visible,
button:focus-visible,
[role="button"]:focus-visible,
summary:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
    outline: 2px solid var(--color-brand-accent);
    outline-offset: 2px;
    box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.85);
    border-radius: 2px;
}

/* On the ink surfaces the halo has to be the dark ground instead, or it draws a white box. */
.sidebar a:focus-visible,
.sidebar button:focus-visible,
.sweep-band a:focus-visible,
.sweep-band button:focus-visible {
    outline-color: var(--color-on-ink-accent);
    box-shadow: 0 0 0 4px rgba(20, 27, 45, 0.9);
}

/* The first focusable element on every app page, so a keyboard reader is not walked through the
   whole sidebar before reaching the content. Visible only while focused. */
.skip-link {
    position: absolute;
    top: 0.5rem;
    left: 0.5rem;
    z-index: 100;
    padding: 0.6rem 1rem;
    background: var(--color-brand);
    color: #fff;
    font-size: 0.9rem;
    font-weight: 600;
    text-decoration: none;
    transform: translateY(-200%);
}

.skip-link:focus {
    transform: translateY(0);
}

@media (prefers-reduced-motion: no-preference) {
    .skip-link {
        transition: transform 0.15s ease;
    }
}

a, .btn-link {
    color: #0071c1;
}

.btn-primary {
    color: #fff;
    background-color: #1b6ec2;
    border-color: #1861ac;
}

.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
  box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
}

.content {
    padding-top: 1.1rem;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid red;
}

.validation-message {
    color: red;
}

#blazor-error-ui {
    color-scheme: light only;
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

    #blazor-error-ui .dismiss {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

/* ---------------------------------------------------------------------------
   Boot splash

   Runs before Blazor has started, so it can use nothing but this stylesheet.

   It fills the viewport and is centred, which is what keeps it reading as a
   page loading rather than as a broken hero: it makes no attempt to imitate the
   page underneath it, so nothing is conspicuously missing from it.

   The width of .boot-fill is driven by --blazor-load-percentage, which the
   framework sets on the document as assemblies arrive, so the bar is honest.
   --------------------------------------------------------------------------- */

.boot {
    display: flex;
    position: absolute;
    inset: 0;
    align-items: center;
    justify-content: center;
    padding: clamp(1.25rem, 6vw, 2rem);
    background: var(--color-surface);
}

.boot-shell {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.9rem;
    /* A character measure alone overflows a narrow screen, so the shell is the narrower of the
       comfortable reading width and the space actually available. */
    max-width: min(54ch, 100%);
    text-align: center;
}

.boot-mark {
    color: var(--color-brand);
}

/* The wedges light in sequence and repeat, so the mark is drawing itself for as long as the wait
   lasts rather than animating in once and then standing still. */
.boot-mark path {
    opacity: 0.28;
    animation: boot-sweep 1.5s ease-in-out infinite;
}

.boot-mark path:nth-of-type(1) { animation-delay: 0s; }
.boot-mark path:nth-of-type(2) { animation-delay: 0.11s; }
.boot-mark path:nth-of-type(3) { animation-delay: 0.22s; }
.boot-mark path:nth-of-type(4) { animation-delay: 0.33s; }

.boot-name {
    margin: 0;
    color: var(--color-ink);
    font-family: var(--font-display);
    font-size: 1.15rem;
    font-weight: 700;
    letter-spacing: -0.01em;
}

.boot-name span {
    color: var(--color-brand-accent);
    font-weight: 400;
}

/* The proposition, at reading size rather than hero size. This is a splash carrying the sentence,
   not the page's opening screen rendered twice. */
.boot h1 {
    max-width: min(22ch, 100%);
    margin: 0.35rem 0 0;
    color: var(--color-ink);
    font-family: var(--font-display);
    font-size: clamp(1.4rem, 3.4vw, 1.85rem);
    font-weight: 600;
    letter-spacing: -0.015em;
    line-height: 1.2;
    text-wrap: balance;
}

.boot-lead {
    max-width: 100%;
    margin: 0;
    color: var(--color-home-copy);
    font-size: 0.94rem;
    line-height: 1.6;
}

.boot-track {
    width: min(210px, 60vw);
    height: 2px;
    margin-top: 0.5rem;
    background: var(--color-border);
    overflow: hidden;
}

.boot-fill {
    width: var(--blazor-load-percentage, 0%);
    height: 100%;
    background: var(--color-on-ink-accent);
    transition: width 0.2s ease-out;
}

.boot-caption {
    margin: 0;
    color: var(--color-muted);
    font-size: 0.78rem;
    letter-spacing: 0.02em;
}

.boot-caption::after {
    /* Blazor publishes the rounded percentage as a quoted string in this property. */
    content: var(--blazor-load-percentage-text, "");
    margin-left: 0.35rem;
    font-variant-numeric: tabular-nums;
}

@keyframes boot-sweep {
    0%, 65%, 100% { opacity: 0.28; }
    20% { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .boot-mark path { animation: none; opacity: 0.8; }
    .boot-fill { transition: none; }
}

code {
    color: #c02d76;
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
    color: var(--bs-secondary-color);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
    text-align: start;
}

/* MudBlazor's snackbar provider is a fixed, top-right container that is present and sized even
   with no snackbar in it, and at narrow widths its own margins push it past the viewport and give
   the whole page a horizontal scrollbar. */
.mud-snackbar-location-top-right {
    max-width: 100vw;
}

/* ---------------------------------------------------------------------------
   Selects

   MudBlazor's outlined select takes its width from the selected value, and some
   of the values on this site are full measure names such as "Achieved renewable
   share (grid scale)". Left alone, a select wider than the viewport scrolls the
   whole page sideways on a phone, so the value is allowed to shrink and clip
   instead. The full text stays available in the open menu.
   --------------------------------------------------------------------------- */

.mud-select {
    min-width: 0;
    max-width: 100%;
}

.mud-select .mud-input-slot {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ---------------------------------------------------------------------------
   Plot system

   These rules are global rather than component-scoped because the plots render
   their SVG text through a child component, which CSS isolation cannot reach,
   and because line, scatter and bar plots share one visual language that would
   otherwise be restated three times.
   --------------------------------------------------------------------------- */

.plot-scroll {
    width: 100%;
    overflow-x: auto;
    border-block: 1px solid var(--color-border);
    background: var(--color-chart-surface);
}

.plot-scroll svg {
    display: block;
    width: 100%;
    min-width: 620px;
}

.line-plot,
.scatter-plot {
    margin: 0;
}

.plot-grid {
    stroke: var(--color-border);
    stroke-width: 1;
}

.plot-grid-vertical {
    stroke-dasharray: 3 5;
}

.plot-baseline {
    stroke: var(--color-border-strong);
    stroke-width: 1;
}

.plot-tick {
    fill: var(--color-muted);
    font-family: var(--font-body);
    font-size: 13px;
    font-variant-numeric: tabular-nums;
}

.plot-tick-secondary {
    fill: var(--color-muted-generation);
}

.plot-axis-title {
    fill: var(--color-muted);
    font-family: var(--font-body);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
}

.plot-axis-title-secondary {
    fill: var(--color-muted-generation);
}

.plot-line {
    stroke-width: 2.5;
    stroke-linejoin: round;
    stroke-linecap: round;
}

.plot-line-dashed {
    stroke-width: 2;
    stroke-dasharray: 6 4;
}

.plot-fill {
    opacity: 0.1;
}

.plot-marker {
    stroke: var(--color-chart-surface);
    stroke-width: 1.5;
}

.plot-annotation-rule {
    stroke: var(--color-notice);
    stroke-width: 1.5;
    stroke-dasharray: 4 4;
}

.plot-annotation-label {
    fill: var(--color-notice);
    font-family: var(--font-body);
    font-size: 12.5px;
    font-weight: 700;
}

/* The crosshair stays invisible until pointed at, so it reads as a response rather than as chart
   furniture competing with the series. */
.plot-crosshair {
    stroke: var(--color-ink);
    stroke-width: 1;
    opacity: 0;
}

.plot-hit:hover .plot-crosshair,
.plot-hit.is-selected .plot-crosshair {
    opacity: 0.4;
}

.plot-hit[role="button"] {
    cursor: pointer;
}

.plot-hit:focus {
    outline: none;
}

.plot-hit:focus-visible .plot-crosshair {
    stroke-width: 2;
    opacity: 1;
}

.plot-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem 1.35rem;
    padding: 0.85rem 0 0;
    color: var(--color-muted);
    font-size: 0.82rem;
}

.plot-legend span {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}

.plot-legend i {
    display: inline-block;
    width: 14px;
    height: 8px;
}

.plot-legend i.dashed {
    height: 0;
    border-top: 3px dashed currentColor;
    background: none !important;
}

.plot-legend em {
    font-size: 0.72rem;
    font-style: normal;
    opacity: 0.8;
}

/* The connecting path is sweep order, not a fit: it shows whether the runs advance along a
   frontier or double back, which an unordered cloud of markers cannot. */
.scatter-path {
    stroke: var(--color-border-control);
    stroke-width: 1.5;
    stroke-dasharray: 5 4;
}

.scatter-marker circle {
    fill: var(--accent, #176b5b);
    stroke: var(--color-chart-surface);
    stroke-width: 2;
}

.scatter-marker a {
    cursor: pointer;
}

.scatter-marker:hover circle,
.scatter-marker a:focus-visible circle {
    fill: var(--color-ink);
    stroke-width: 3;
}

.scatter-marker.is-highlighted circle {
    fill: var(--color-notice);
}

.scatter-label {
    fill: var(--color-muted);
    font-family: var(--font-body);
    font-size: 12.5px;
    font-variant-numeric: tabular-nums;
    pointer-events: none;
}

.stack-plot {
    margin: 0;
    min-width: 0;
}

.stack-plot-title {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 0.4rem;
}

.stack-plot-title strong {
    font-family: var(--font-display);
    font-size: 1.05rem;
    font-weight: 600;
}

.stack-plot-title small {
    color: var(--color-muted);
    font-size: 0.76rem;
    font-variant-numeric: tabular-nums;
    text-align: right;
}

/* The detail is a sentence of figures and does not fit beside the region name on a phone. */
@media (max-width: 520px) {
    .stack-plot-title {
        display: block;
    }

    .stack-plot-title small {
        display: block;
        margin-top: 0.15rem;
        text-align: left;
    }
}

.stack-demand {
    stroke: var(--color-demand-line);
    stroke-width: 2;
    stroke-linejoin: round;
}

.scatter-caption {
    padding: 0.85rem 0 0;
    color: var(--color-muted);
    font-size: 0.82rem;
    line-height: 1.5;
}
/* ---------------------------------------------------------------------------
   Network map
   --------------------------------------------------------------------------- */

.network-map {
    margin: 0;
}

.network-link {
    fill: none;
    stroke: var(--color-accent-cool);
    stroke-linecap: round;
}

.network-edge.is-idle .network-link {
    stroke: var(--color-border-control);
    stroke-dasharray: 5 5;
}

.network-arrow {
    fill: var(--color-accent-cool);
}

/* A label sits in the margin beside the map rather than on the state it names, so it needs a
   hairline back to its own coastline. It is a pointer and not part of the drawing, so it is light
   enough that a reader follows it without reading it as a link. */
.network-leader {
    fill: none;
    stroke: var(--color-border);
    stroke-width: 1.2;
}

.network-node path {
    fill: var(--color-surface);
    stroke: var(--color-track-fill);
    stroke-width: 2.5;
    stroke-linejoin: round;
}

.network-node.is-importer path {
    fill: var(--color-negative-soft);
    stroke: var(--color-negative);
}

.network-node.is-exporter path {
    fill: var(--color-positive-soft);
    stroke: var(--color-positive);
}

.network-node-id {
    fill: var(--color-ink);
    font-family: var(--font-body);
    font-size: 14px;
    font-weight: 700;
}

.network-node-label {
    fill: var(--color-ink);
    font-family: var(--font-display);
    font-size: 14px;
    font-weight: 600;
}

.network-node-detail {
    fill: var(--color-muted);
    font-family: var(--font-body);
    font-size: 12.5px;
    font-variant-numeric: tabular-nums;
}

.network-caption {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem 1.25rem;
    padding: 0.85rem 0 0;
    color: var(--color-muted);
    font-size: 0.82rem;
}

.network-caption span {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}

.network-caption i {
    display: inline-block;
    width: 12px;
    height: 12px;
    border-radius: 3px;
    border: 2px solid var(--color-track-fill);
    background: var(--color-surface);
}

.network-caption .network-key-importer {
    border-color: var(--color-negative);
    background: var(--color-negative-soft);
}

.network-caption .network-key-exporter {
    border-color: var(--color-positive);
    background: var(--color-positive-soft);
}

.network-caption .network-note {
    display: block;
    flex: 1 1 100%;
    line-height: 1.5;
}

/* Data tables.

   CSS isolation cannot reach a child component's elements, and the same table appears on the
   comparison page, the dispatch page and inside the sizing-trajectory component. One definition
   here beats three that drift apart. A wide table scrolls inside its own box rather than widening
   the page. */

/* A wide table's own right border sits hundreds of pixels off screen at first scroll, so the box
   reads as cut off rather than as a table with more columns to reach. These four layers (the
   classic scroll-shadow technique) paint a soft edge that fades out once there is nothing further
   to scroll toward it: two gradients scroll with the content to mask the shadow at each true end,
   two stay fixed to the viewport to draw it everywhere else. No JS: the site keeps its scripting to
   the one module in nem.js, and a decorative cue is exactly the kind of thing that shouldn't need it. */
.table-wrap,
.is-scrollable {
    margin-top: 1.25rem;
    overflow-x: auto;
    border-block: 1px solid var(--color-border);
    background-color: var(--color-surface);
    background-image:
        linear-gradient(to right, var(--color-surface) 50%, transparent),
        linear-gradient(to left, var(--color-surface) 50%, transparent),
        linear-gradient(to right, rgba(23, 33, 43, 0.15), transparent),
        linear-gradient(to left, rgba(23, 33, 43, 0.15), transparent);
    background-position: left, right, left, right;
    background-repeat: no-repeat;
    background-size: 24px 100%, 24px 100%, 10px 100%, 10px 100%;
    background-attachment: local, local, scroll, scroll;
}

.section-pills {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-top: 1.25rem;
}

.section-pills a {
    padding: 0.35rem 0.7rem;
    border: 1px solid var(--color-border-strong);
    border-radius: 999px;
    color: var(--color-muted);
    font-size: 0.78rem;
    font-weight: 700;
    text-decoration: none;
}

.section-pills a:hover {
    border-color: var(--accent);
    background: var(--accent-soft);
    color: var(--accent);
}

.data-table {
    width: 100%;
    min-width: 720px;
    border-collapse: collapse;
    font-size: 0.83rem;
}

.data-table th,
.data-table td {
    padding: 0.65rem 0.8rem;
    border-bottom: 1px solid var(--color-border);
    font-variant-numeric: tabular-nums;
    text-align: right;
}

/* The row label stays visible while a narrow viewport scrolls across a wide row of figures —
   every one of these tables identifies its row in the first column (Technology, Link, Pass), so a
   generic :first-child rule reaches every table this stylesheet defines without each caller having
   to mark its own label column. */
.data-table th:first-child,
.data-table td:first-child {
    position: sticky;
    left: 0;
    z-index: 1;
    text-align: left;
    background: var(--color-surface);
}

.data-table thead th:first-child {
    z-index: 2;
    background: var(--color-surface-table);
}

.data-table thead th {
    color: var(--color-muted);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.data-table tbody th {
    font-weight: 700;
}

.data-table .row-system {
    background: var(--color-surface-table);
}

/* The sticky first cell paints its own opaque background over whatever the row sets, so a tinted
   row needs its tint restated there or the one cell that's always on screen is the one that loses
   the tint. */
.data-table .row-system td:first-child,
.data-table .row-system th:first-child {
    background: var(--color-surface-table);
}

.data-table .row-derived td,
.data-table .row-derived th {
    color: var(--color-muted);
    font-weight: 400;
}

.data-table .row-derived td:last-child {
    font-size: 0.78rem;
    text-align: right;
}

.data-table .row-idle {
    color: var(--color-muted);
}

.data-table .cell-emphasis {
    font-weight: 700;
}

.data-table .cell-absent {
    color: var(--color-muted);
    font-size: 0.76rem;
    font-variant-numeric: normal;
}

.data-table em {
    display: block;
    color: var(--color-muted);
    font-size: 0.72rem;
    font-style: normal;
}

.data-table .swatch {
    display: inline-block;
    width: 10px;
    height: 10px;
    margin-right: 0.5rem;
    border-radius: 2px;
    vertical-align: baseline;
}

/* Case study exhibits are numbered the way a report numbers them: figures, tables and code
   listings each in their own sequence, in page order. Counters rather than numbers written into
   the components, so a section that does not render (a sweep with no breach, say) never leaves a
   gap, and the same numbering carries into the PDF and the review snapshot. */
.case-study-page {
    counter-reset: case-figure case-table case-listing;
}

.case-caption {
    max-width: 72ch;
    margin: 0.65rem 0 0;
    color: var(--color-muted);
    font-size: 0.84rem;
    line-height: 1.5;
}

.case-caption::before {
    color: var(--color-ink);
    font-weight: 700;
}

.case-caption.is-figure::before {
    counter-increment: case-figure;
    content: "Figure " counter(case-figure) ". ";
}

.case-caption.is-table::before {
    counter-increment: case-table;
    content: "Table " counter(case-table) ". ";
}

.case-caption.is-listing::before {
    counter-increment: case-listing;
    content: "Listing " counter(case-listing) ". ";
}

/* Print: the page as a document. Used by a browser's Print to PDF and by tools/case-study-pdf.
   Chrome is stripped, anything folded is opened, nothing scrolls or clips, and cards are not
   split across pages. */
@page {
    size: A4 portrait;
}

@page wide {
    size: A4 landscape;
}

@media print {
    .skip-link,
    .sidebar,
    .top-row,
    .marketing-bar,
    .marketing-footer,
    .mud-popover-provider,
    .mud-snackbar-provider {
        display: none !important;
    }

    .page {
        display: block;
    }

    main,
    article.content {
        padding: 0 !important;
        max-width: none !important;
    }

    body {
        background: #fff;
        color: #000;
    }

    details > *:not(summary) {
        display: block;
    }

    details summary {
        list-style: none;
        font-weight: 600;
    }

    details summary::-webkit-details-marker {
        display: none;
    }

    [style*="overflow"],
    .mud-table-container,
    pre,
    table {
        overflow: visible !important;
        max-height: none !important;
    }

    td, th {
        white-space: normal !important;
        overflow: visible !important;
        text-overflow: clip !important;
    }

    /* Wide blocks that scroll on screen have nowhere to scroll on paper. */
    pre {
        white-space: pre-wrap;
        overflow-wrap: anywhere;
    }

    h1, h2, h3, h4 {
        break-after: avoid;
    }

    figure, table, .mud-paper, .mud-card, li {
        break-inside: avoid;
    }

    a {
        color: inherit;
        text-decoration: none;
    }

    svg {
        max-width: 100%;
    }

    /* The case study is read as a document, so its charts are set a little shorter on paper and
       two can share a page with the prose that introduces them. */
    .case-study-page .plot-scroll svg {
        min-width: 0;
        max-height: 46mm;
    }
}
