/* ============================================================================
   Colour theme — ported from the Grand Tours 2026 project (theme.css).
   Light palette in :root; the dark palette overrides the same custom
   properties in the prefers-color-scheme block. The app's App.razor script
   keeps Bootstrap's data-bs-theme in sync with this same OS preference.
   ============================================================================ */
:root {
    color-scheme: light dark;

    --paper: #E9ECE4;         /* page background */
    --paper-panel: #F4F6EF;   /* cards / panels */
    --ink: #1E2A22;           /* primary text */
    --ink-soft: #4C5A50;      /* secondary text */
    --line: #C6CCBC;          /* borders / rules */
    --shadow: 0 2px 10px rgba(30, 42, 34, 0.08);
    --shadow-lift: 0 8px 26px rgba(30, 42, 34, 0.14);
    --solid-bg: #1E2A22;
    --solid-fg: #ffffff;

    --gold: #C99A2E;
    --gold-deep: #9C7620;
    --red: #B23B32;
    --green: #3E7A57;
    --green-deep: #234A34;
    --blue: #3B6485;
    --olive: #7E8A46;

    /* The header band always carries light text, so its gradient needs its own
       stops rather than --ink/--green: --ink flips to a near-white in dark mode,
       which would wash the brand out. */
    --header-from: #1E2A22;
    --header-via: #3E7A57;
    --header-to: #234A34;
    --header-fg: #ffffff;
    --header-fg-soft: rgba(255, 255, 255, 0.82);

    /* Map Bootstrap's theming onto the palette so buttons, links, tables and
       form validation all follow the same colours. */
    --bs-body-bg: var(--paper);
    --bs-body-color: var(--ink);
    --bs-border-color: var(--line);
    --bs-link-color: var(--green);
    --bs-link-color-rgb: 62, 122, 87;
    --bs-link-hover-color: var(--green-deep);
    --bs-primary: var(--green-deep);
    --bs-primary-rgb: 35, 74, 52;
}

@media (prefers-color-scheme: dark) {
    :root {
        --paper: #12160F;
        --paper-panel: #1B211A;
        --ink: #E7ECDF;
        --ink-soft: #9FA99A;
        --line: #333B31;
        --shadow: 0 2px 14px rgba(0, 0, 0, 0.45);
        --shadow-lift: 0 10px 30px rgba(0, 0, 0, 0.55);
        --solid-bg: #E7ECDF;
        --solid-fg: #12160F;

        --gold: #D8AC44;
        --gold-deep: #E3BE63;
        --red: #D3574C;
        --blue: #77ABD2;
        --green: #5AA179;
        --green-deep: #3E7A57;

        --header-from: #0C1710;
        --header-via: #24543B;
        --header-to: #143222;

        --bs-link-color-rgb: 90, 161, 121;
        --bs-primary-rgb: 62, 122, 87;
    }
}

/* The paper colour lives on html alone. body carries the background drawing in
   a z-index: -1 pseudo-element, and any background on body itself paints
   straight over it — including Bootstrap reboot's own
   `body { background-color: var(--bs-body-bg) }`, which is why body is cleared
   explicitly rather than just left out here. app.css loads after Bootstrap, so
   this wins. html's colour still propagates to the viewport canvas as before. */
html {
    background-color: var(--paper);
}

body {
    background-color: transparent;
}

/* ============================================================================
   Typefaces — Newsreader for display, Public Sans for everything else.

   Both are self-hosted rather than linked from Google's CDN: hot-linking sends
   every visitor's IP to a third country, and a local file is faster besides.
   Both are SIL OFL, so redistributing them here is fine.

   The latin / latin-ext split with matching unicode-range is Google's own, kept
   deliberately: a reading's note is free text, so the faces have to cover more
   than Finnish, but nobody writing Finnish pays for the extra file — the
   browser fetches latin-ext only if a page actually contains one of its
   characters.

   Both faces are variable on weight, so one file per subset covers 400 through
   600 (Public Sans through 700). Newsreader also has an optical-size axis; it
   is not requested here because adding it takes the latin file from 58 kB to
   132 kB, which is a poor trade for a face used on the brand line and two
   headings.
   ============================================================================ */
@font-face {
    font-family: 'Newsreader';
    src: url('fonts/newsreader-latin.woff2') format('woff2');
    font-weight: 400 600;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'Newsreader';
    src: url('fonts/newsreader-latin-ext.woff2') format('woff2');
    font-weight: 400 600;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
    font-family: 'Public Sans';
    src: url('fonts/public-sans-latin.woff2') format('woff2');
    font-weight: 400 700;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'Public Sans';
    src: url('fonts/public-sans-latin-ext.woff2') format('woff2');
    font-weight: 400 700;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
    --font-ui: 'Public Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif;
    --font-display: 'Newsreader', Georgia, 'Times New Roman', serif;
}

html, body {
    font-family: var(--font-ui);
    color: var(--ink);
}

/* Newsreader is a display face here, not a text face: the brand line and the
   page headings only. Body copy and the readings table stay on Public Sans,
   which was drawn for interface text at these sizes. */
h1, h2, h3 {
    font-family: var(--font-display);
    font-weight: 600;
    letter-spacing: -0.01em;
}

/* Every number on this page belongs to a column that should line up — the
   temperatures, the dates beside them, the stat row. Public Sans' default
   figures are proportional, so a 1 is narrower than a 7 and the decimal commas
   wander down a long list. */
.readings .cell-temp,
.readings .cell-date,
.stat strong,
.stat .text-muted {
    font-variant-numeric: tabular-nums;
}

/* ============================================================================
   Page background — Peltoaukea.

   The view over the field to the Torniojoki, drawn flat: potato rows at the
   bottom edge, the mown field, single pines on the near bank, the river, and
   the unbroken forest line on the far shore.

   Applied as a mask rather than as a background-image. The SVG is monochrome
   and carries its depth in per-layer opacity, so masking lets --green supply
   the colour at paint time; one file then serves both themes, where a baked-in
   palette tuned for the light paper would smear grey over the dark one.

   On the 50% here: the drawing's own layers run between 0.03 and 0.18 alpha,
   and the mask multiplies, so peak coverage on the page is about 9% — a good
   deal quieter than the number suggests.
   ============================================================================ */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background: var(--green);
    opacity: 0.5;
    -webkit-mask-image: url("img/peltoaukea.svg");
            mask-image: url("img/peltoaukea.svg");
    -webkit-mask-size: cover;
            mask-size: cover;
    -webkit-mask-position: bottom center;
            mask-position: bottom center;
    -webkit-mask-repeat: no-repeat;
            mask-repeat: no-repeat;
}

/* Phone gets its own artboard rather than a reframing of the desktop one.
   1440x900 masked onto a 390x844 screen either scales to the height and throws
   away most of the width, or fits the width and leaves a thin strip of horizon
   along the bottom — neither uses the screen. peltoaukea-mobile.svg is the same
   view recomposed at 480x1040, close enough to a phone's proportions that
   `cover` crops almost nothing, with the field given the room it has in the
   photograph. */
@media (max-width: 640px) {
    body::before {
        -webkit-mask-image: url("img/peltoaukea-mobile.svg");
                mask-image: url("img/peltoaukea-mobile.svg");
    }
}

/* A phone turned sideways is wide, not narrow, so the rule above never fires —
   it falls through to the tall 1440x900 desktop artwork instead, still anchored
   bottom center. On a short landscape viewport `cover` scales that image up a
   lot to fill the width, and the birch clump (the tallest thing in the
   drawing, reaching ~140px above the horizon at full scale) ends up crowding
   or clipping under the header band.

   Anchoring top center instead guarantees the header only ever sits over sky:
   with the image scaled to cover width, the horizon lands at roughly 22% of
   the viewport height regardless of how wide the phone is (312px of headroom
   above it, of a 900px-tall source, times the same width-driven scale factor
   that determines the header's share of the screen) — comfortably below any
   real header height. Scoped to short + landscape + a phone-ish width so an
   ordinary short desktop window is untouched. */
@media (orientation: landscape) and (max-height: 500px) and (max-width: 960px) {
    body::before {
        -webkit-mask-image: url("img/peltoaukea.svg");
                mask-image: url("img/peltoaukea.svg");
        -webkit-mask-position: top center;
                mask-position: top center;
    }
}

/* Bootstrap paints every cell with `background-color: var(--bs-table-bg)`,
   which defaults to the body colour — an opaque block over the drawing for the
   full height of the readings list. The rows carry their own separation from
   the border rules, so they do not need a fill. */
.table {
    --bs-table-bg: transparent;
}

/* Some people turn background imagery off at the OS level; honour that. */
@media (prefers-reduced-transparency: reduce) {
    body::before {
        display: none;
    }
}

a, .btn-link {
    color: var(--green);
}

a:hover, .btn-link:hover {
    color: var(--green-deep);
}

.btn-primary {
    color: #fff;
    background-color: var(--green);
    border-color: var(--green);
}

.btn-primary:hover, .btn-primary:focus, .btn-primary:active {
    color: #fff;
    background-color: var(--green-deep);
    border-color: var(--green-deep);
}

.btn-outline-primary {
    color: var(--green-deep);
    background-color: transparent;
    border-color: var(--green-deep);
}

.btn-outline-primary:hover, .btn-outline-primary:focus, .btn-outline-primary:active {
    color: #fff;
    background-color: var(--green-deep);
    border-color: var(--green-deep);
}

/* Dark mode swaps which green can carry which text: on --paper, white on --green
   is only 3.1:1 and --green-deep as a foreground is 3.6:1, so both light-mode
   pairings fall short. Filled buttons rest on the darker green with white text
   and lift to the lighter green with dark text; outlined buttons take the
   lighter green, which reads at 6:1. Placed after the rules it overrides — a
   media query adds no specificity, so source order decides. */
@media (prefers-color-scheme: dark) {
    .btn-primary {
        background-color: var(--green-deep);
        border-color: var(--green-deep);
    }

    .btn-primary:hover, .btn-primary:focus, .btn-primary:active,
    .btn-outline-primary:hover, .btn-outline-primary:focus, .btn-outline-primary:active {
        color: var(--paper);
        background-color: var(--green);
        border-color: var(--green);
    }

    .btn-outline-primary {
        color: var(--green);
        border-color: var(--green);
    }
}

.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
  box-shadow: 0 0 0 0.1rem var(--paper), 0 0 0 0.25rem var(--green);
}

/* Phone: Bootstrap's controls come out 38px tall, under the 44px both Apple and
   Google ask for. Most readings are entered outdoors on a phone, so every button
   and field — including the .btn-sm ones in the duplicate/delete prompts — gets
   the full target. inline-flex keeps the label centred in the taller box. */
@media (max-width: 640px) {
    .btn, .form-control, .form-select {
        min-height: 44px;
    }

    .btn {
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }
}

.content {
    padding-top: 1.1rem;
}

h1:focus {
    outline: none;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid var(--green);
}

.invalid {
    outline: 1px solid var(--red);
}

.validation-message {
    color: var(--red);
}

.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."
    }

.darker-border-checkbox.form-check-input {
    border-color: #929292;
}

.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;
}

/* ============================================================================
   ApexCharts dark mode.

   The chart is built server-side, so it cannot know the visitor's colour
   preference and always renders with ApexCharts' light theme: dark grey text,
   near-white gridlines and a white tooltip. Restyling it here keeps the chart
   in step with the OS preference without a round trip, and switches live when
   the preference changes.

   !important throughout: ApexCharts injects its own stylesheet at runtime,
   after this file, and sets the legend label colour as an inline style.
   ============================================================================ */
/* ApexCharts ships its own font stack (Helvetica/Arial) and injects it at
   runtime, so the axis numbers would otherwise be the one thing on the page not
   set in Public Sans. Tabular figures keep the y-axis ticks from shifting as
   the chart is zoomed. Not inside the dark-mode block below: this applies to
   both themes. */
.apexcharts-canvas text {
    font-family: var(--font-ui) !important;
    font-variant-numeric: tabular-nums;
}

/* The canvas has no background by default, so the fixed Peltoaukea drawing
   behind the page shows straight through the plot area — fine over prose, too
   busy behind gridlines and data points. Matching it to --paper (which already
   flips per theme) opaques just the chart without needing a separate dark-mode
   rule here. */
.apexcharts-canvas {
    background: var(--paper);
}

@media (prefers-color-scheme: dark) {
    /* Title, axis labels and any other SVG text. */
    .apexcharts-canvas text {
        fill: var(--ink) !important;
    }

    .apexcharts-canvas .apexcharts-yaxis-label,
    .apexcharts-canvas .apexcharts-xaxis-label {
        fill: var(--ink-soft) !important;
    }

    /* Legend labels are HTML, not SVG. */
    .apexcharts-canvas .apexcharts-legend-text {
        color: var(--ink-soft) !important;
    }

    /* Gridlines and axis rules ship at #e0e0e0, which glares on a dark page. */
    .apexcharts-canvas .apexcharts-gridline,
    .apexcharts-canvas .apexcharts-grid-borders line,
    .apexcharts-canvas .apexcharts-xaxis line,
    .apexcharts-canvas .apexcharts-yaxis line {
        stroke: var(--line) !important;
    }

    .apexcharts-canvas .apexcharts-xcrosshairs,
    .apexcharts-canvas .apexcharts-ycrosshairs {
        stroke: var(--ink-soft) !important;
    }

    /* Tooltip: the default is a white card, and its text inherits --ink from the
       body, so the values come out near-white on near-white. */
    .apexcharts-canvas .apexcharts-tooltip {
        background: var(--paper-panel) !important;
        border-color: var(--line) !important;
        color: var(--ink) !important;
        box-shadow: var(--shadow-lift) !important;
    }

    .apexcharts-canvas .apexcharts-tooltip-title {
        background: var(--paper) !important;
        border-bottom-color: var(--line) !important;
        color: var(--ink) !important;
    }

    /* The date bubble under the x-axis, plus the little arrow that points at it. */
    .apexcharts-canvas .apexcharts-xaxistooltip,
    .apexcharts-canvas .apexcharts-yaxistooltip {
        background: var(--paper-panel) !important;
        border-color: var(--line) !important;
        color: var(--ink) !important;
    }

    .apexcharts-canvas .apexcharts-xaxistooltip-bottom::before {
        border-bottom-color: var(--line) !important;
    }

    .apexcharts-canvas .apexcharts-xaxistooltip-bottom::after {
        border-bottom-color: var(--paper-panel) !important;
    }

    /* Zoom / pan / export controls and the export menu. */
    .apexcharts-canvas .apexcharts-toolbar svg {
        fill: var(--ink-soft) !important;
    }

    .apexcharts-canvas .apexcharts-menu {
        background: var(--paper-panel) !important;
        border-color: var(--line) !important;
        color: var(--ink) !important;
    }

    .apexcharts-canvas .apexcharts-menu-item:hover {
        background: var(--line) !important;
    }
}