/* ══════════════════════════════════════════════════════════════════════════
   GTT — Global Threat Thermometer · International Security Ligue
   Corporate instrument panel built on the Ligue's own identity:
   institutional blue #105196, brand black #242020, page #FAFAFA, grey #E6E6E6
   (tokens read off international-security-ligue.org).
   One signature object (the thermometer). Light-only, offline-safe fonts.
   Band colours are injected by the server (see base.html) — never hard-code
   a band colour in this file or in JS.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Typography ──────────────────────────────────────────────────────────────
   The Ligue's web font is GILROY, and this page now loads the Ligue's own font
   files, from the Ligue's own Webflow CDN, to render the Ligue's own content.
   Verified 21 Sep 2026: the four weights their site actually uses all answer 200
   with `Access-Control-Allow-Origin: *` and a one-year cache, so a cross-origin
   @font-face works. Nothing is copied or re-hosted here — these are the exact
   URLs their own pages request.

   Note their 700 maps to Gilroy-ExtraBold, not Gilroy-Bold. That is their
   mapping, and matching it is the whole point: inside the iframe on their site
   the type has to be indistinguishable from the type around it.

   Why this is free in the case that matters: the HTTP cache is keyed on the
   top-level site, so when this page is framed on international-security-ligue.org
   the browser has already fetched these exact files for the parent page and
   reuses them. Only a standalone visit pays the download.

   `font-display: swap` plus the vendored Source Sans 3 keeps the old guarantee
   that this dashboard still works with NO external requests (it is also served
   on a LAN): if the CDN is unreachable the text renders in Source Sans 3 and
   nothing breaks. Source Sans is SIL OFL licensed and ships with the app —
   files in static/fonts/*.woff2, licence in OFL.txt. */
@font-face {
    font-family: "Gilroy";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("https://cdn.prod.website-files.com/6631523d581889857fab799d/6631523d581889857fab7b10_Gilroy-Regular.ttf") format("truetype");
}
@font-face {
    font-family: "Gilroy";
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url("https://cdn.prod.website-files.com/6631523d581889857fab799d/6631523d581889857fab7b18_Gilroy-Medium.ttf") format("truetype");
}
@font-face {
    font-family: "Gilroy";
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url("https://cdn.prod.website-files.com/6631523d581889857fab799d/6631523d581889857fab7b15_Gilroy-SemiBold.ttf") format("truetype");
}
@font-face {
    font-family: "Gilroy";
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    /* Two files, in this order, because that is exactly what their own stylesheet declares for
       700 — their bold IS Gilroy-ExtraBold, with Gilroy-Bold behind it. Copying the mapping
       rather than guessing is the whole point: inside the iframe the type has to be
       indistinguishable from the type around it. */
    src: url("https://cdn.prod.website-files.com/6631523d581889857fab799d/6631523d581889857fab7b11_Gilroy-ExtraBold.ttf") format("truetype"),
         url("https://cdn.prod.website-files.com/6631523d581889857fab799d/6631523d581889857fab7b13_Gilroy-Bold.ttf") format("truetype");
}

/* The page sets 300 on a few muted lines. Without this face the browser would synthesise it
   from 400 or jump to it, which reads as a weight change in the wrong direction. */
@font-face {
    font-family: "Gilroy";
    font-style: normal;
    font-weight: 300;
    font-display: swap;
    src: url("https://cdn.prod.website-files.com/6631523d581889857fab799d/6631523d581889857fab7b0f_Gilroy-Light.ttf") format("truetype");
}
@font-face {
    font-family: "Source Sans 3";
    font-style: normal;
    font-weight: 300 800;
    font-display: swap;
    src: url("../fonts/source-sans-3-latin.woff2") format("woff2");
    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: "Source Sans 3";
    font-style: normal;
    font-weight: 300 800;
    font-display: swap;
    src: url("../fonts/source-sans-3-latin-ext.woff2") format("woff2");
    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: "Source Sans 3";
    font-style: italic;
    font-weight: 300 800;
    font-display: swap;
    src: url("../fonts/source-sans-3-italic-latin.woff2") format("woff2");
    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: "Source Sans 3";
    font-style: italic;
    font-weight: 300 800;
    font-display: swap;
    src: url("../fonts/source-sans-3-italic-latin-ext.woff2") format("woff2");
    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 {
    /* ── Ligue identity (official tokens) ───────────────────────────────── */
    --ligue-blue:  #105196;   /* institutional blue (CMYK 100C/70M), buttons + links */
    --ligue-black: #242020;   /* brand text / dark surfaces */
    --ligue-page:  #FAFAFA;   /* brand background */
    --ligue-grey:  #E6E6E6;   /* brand grey (gainsboro) */

    /* ── Derived UI tokens (names kept stable for /ops) ──────────────────── */
    --navy:   #242020;        /* masthead + display headings */
    --navy-2: #1F1E1C;
    --steel:  #105196;        /* section titles, secondary accents */
    --ink:    #242020;
    --muted:  #6B6767;
    --line:   #DEDBDB;
    --line-2: #ECE9E9;
    --surface:#FFFFFF;
    --page:   #FAFAFA;
    --accent: #105196;
    --ok:     #12855A;        /* /ops only: collection succeeded. NOT a band colour. */
    --warn:   #B25C04;
    --bad:    #A81D24;        /* /ops only: collection failed. NOT a band colour. */

    /* Month-on-month arrow. NOT defined here: it is the warmest and coolest bands' own ink,
       injected into :root by the server (templates/base.html and, separately, the embed page's
       own <head>) as --band-warmed-ink / --band-cooled-ink. That is the rule at the top of this
       file finally being kept — these two were the loophole, hand-copied band hexes that stayed
       behind whenever the palette moved. The literals below are a last-resort fallback for a
       page served without the injection, nothing more. */
    --warmer: var(--band-warmed-ink, #8E1616);
    --cooler: var(--band-cooled-ink, #0B3C85);

    /* The display face for the few large headings (the month, the one-line verdict).
       It used to be a serif, which read as a foreign object once this page was
       framed inside the Ligue's site — their whole site is Gilroy and has no serif
       anywhere. Kept as its own token because these headings are still set apart
       from body copy by size and weight, not by family. */
    --serif: "Gilroy", "Source Sans 3", system-ui, -apple-system, BlinkMacSystemFont,
             "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --sans: "Gilroy", "Source Sans 3", system-ui, -apple-system, BlinkMacSystemFont,
            "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --mono: ui-monospace, "SFMono-Regular", Menlo, Consolas, "Liberation Mono", monospace;

    --radius: 6px;
    --shadow: 0 1px 2px rgba(36, 32, 32, .06), 0 4px 14px rgba(36, 32, 32, .05);
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
    font-family: var(--sans);
    background: var(--page);
    color: var(--ink);
    line-height: 1.55;
    font-size: 15px;
}

a { color: var(--accent); }
a:focus-visible, button:focus-visible, input:focus-visible, [tabindex]:focus-visible {
    outline: 2px solid var(--accent); outline-offset: 2px;
}

/* ── Masthead ───────────────────────────────────────────────────────────── */
.masthead {
    background: var(--navy);
    color: #fff;
    border-bottom: 3px solid var(--ligue-blue);
}
.masthead-in {
    max-width: 1240px; margin: 0 auto; padding: 0 28px; height: 78px;
    display: flex; align-items: center; justify-content: space-between; gap: 20px;
}
.brand { display: flex; align-items: center; gap: 16px; min-width: 0; text-decoration: none; color: inherit; }
/* the official logo is white-on-transparent, so it lives on the dark bar.
   The file is 720×373 — far above its rendered size, i.e. crisp on retina. */
.brand .logo { height: 46px; width: auto; display: block; flex: none; }
.brand .rule { width: 1px; align-self: stretch; margin: 14px 0; background: rgba(255,255,255,.28); flex: none; }
.brand .lockup { min-width: 0; }
.brand .lockup .t1 {
    display: block; font-family: var(--serif); font-size: 18px; line-height: 1.2; white-space: nowrap;
}
.brand .lockup .t2 {
    display: block; font-size: 10.5px; letter-spacing: .16em; text-transform: uppercase;
    color: rgba(255,255,255,.62); white-space: nowrap;
}
.masthead .right { display: flex; align-items: center; gap: 18px; font-size: 13px; color: rgba(255,255,255,.78); }
.masthead .right .stamp { text-align: right; line-height: 1.35; }
.masthead .right .stamp b { color: #fff; font-weight: 600; }
.masthead a.navlink {
    color: #fff; text-decoration: none; font-size: 12px; letter-spacing: .1em;
    text-transform: uppercase; border: 1px solid rgba(255,255,255,.38);
    padding: 6px 12px; border-radius: 3px; white-space: nowrap;
}
.masthead a.navlink:hover { background: var(--ligue-blue); border-color: var(--ligue-blue); }
.masthead.is-ops { background: var(--navy-2); border-bottom-color: rgba(255,255,255,.35); }

/* ── Page frame ─────────────────────────────────────────────────────────── */
.wrap { max-width: 1240px; margin: 0 auto; padding: 26px 28px 64px; }
.card {
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--radius); box-shadow: var(--shadow); padding: 22px 24px;
    margin-bottom: 20px;
}
.card > h2, .sec-title {
    font-size: 12px; letter-spacing: .14em; text-transform: uppercase;
    color: var(--steel); font-weight: 700; margin-bottom: 4px;
}
.card > .sub { font-size: 13.5px; color: var(--muted); margin-bottom: 16px; max-width: 78ch; }
.grid { display: grid; gap: 20px; }
.grid.two { grid-template-columns: 1fr 1fr; }
/* auto-fit, so the three source cards stay side by side on a tablet instead of
   snapping to one full-width column at the 860px breakpoint */
.grid.three { grid-template-columns: repeat(auto-fit, minmax(246px, 1fr)); }
/* Australia is close to square once projected, so the map takes the NARROWER
   column: a full-width band would be mostly empty background. The explanation of
   why the reading is national sits beside it. */
.note { font-size: 13px; color: var(--muted); }
.empty {
    border: 1px dashed var(--line); border-radius: var(--radius);
    padding: 18px; color: var(--muted); font-size: 13.5px; background: #FCFBFB;
}

/* "How these were chosen" — the selection rule, stated in the open next to
   every set of examples. Deliberately quiet but always present. */
.how {
    margin-top: 10px; padding: 9px 0 0 12px; border-left: 2px solid var(--ligue-grey);
    font-size: 12.5px; line-height: 1.5; color: var(--muted); max-width: 62ch;
}
.how b { color: var(--ink); font-weight: 600; }
.card > .sub .lede { color: var(--ink); font-weight: 600; }

/* ── Hero ───────────────────────────────────────────────────────────────── */
.hero { display: grid; grid-template-columns: 300px 1fr; gap: 34px; align-items: stretch; }
.hero-instrument { display: flex; flex-direction: column; align-items: center; gap: 14px; }
.hero-read .eyebrow {
    font-size: 11.5px; letter-spacing: .18em; text-transform: uppercase;
    color: var(--steel); font-weight: 700;
}
.hero-read h1 {
    font-family: var(--serif); font-weight: 400; font-size: 34px; line-height: 1.15;
    margin: 2px 0 14px; color: var(--navy);
}
.reading { display: flex; align-items: flex-end; gap: 16px; flex-wrap: wrap; }
.reading .value {
    font-size: 78px; line-height: .9; font-weight: 700; letter-spacing: -.03em;
    font-variant-numeric: tabular-nums;
}
.reading .of { font-size: 17px; color: var(--muted); padding-bottom: 8px; }
.band-pill {
    /* No colour here on purpose. The band fill comes from Garett's ramp, which has light stops,
       so the text colour is computed against that fill and sent inline — app.readable_on() for the
       server render, readableOn() in the JS for the live update. Pinning #fff here made the
       neutral band unreadable. */
    display: inline-flex; align-items: center; gap: 7px;
    padding: 5px 14px; border-radius: 999px; font-size: 13px; font-weight: 700;
    letter-spacing: .04em; margin-bottom: 6px;
}
/* currentColor, not white: the pill text colour is computed against the band fill and sent
   inline, so the dot follows it. A white dot vanished on the neutral band (#FFD54F). */
.band-pill .dot { width: 8px; height: 8px; border-radius: 50%; background: currentColor; opacity: .8; }
/* The band word names a comparison; this names what it is compared WITH. Without it the
   reader anchors on the nearest other number on the page, which is last month's — and then
   "Stable" beside a 22-point move looks like a contradiction. It is also where the one
   sentence worth keeping from the retired "Where this reading applies" section landed. */
.hero-ref { font-size: 12.5px; line-height: 1.5; color: var(--muted); margin: 10px 0 0; max-width: 46ch; }
.hero-say {
    font-family: var(--serif); font-size: 20px; line-height: 1.45;
    color: var(--navy); margin: 18px 0 10px; max-width: 46ch;
}
.delta { display: inline-flex; align-items: center; gap: 8px; font-size: 14.5px; font-weight: 600; }
.delta .arrow { font-size: 16px; }
.delta.up { color: var(--warmer); } .delta.down { color: var(--cooler); } .delta.flat { color: var(--muted); }
.hero-facts { margin-top: 18px; border-top: 1px solid var(--line-2); padding-top: 14px; }
.hero-facts li {
    list-style: none; font-size: 13.5px; color: var(--ink); padding: 5px 0 5px 18px;
    position: relative; max-width: 62ch;
}
.hero-facts li::before {
    content: ""; position: absolute; left: 0; top: 12px;
    width: 7px; height: 1px; background: var(--steel);
}

/* provisional / progress */
.provisional {
    margin-top: 16px; background: #FBF7EE; border: 1px solid #EBD9B4;
    border-radius: var(--radius); padding: 11px 14px; font-size: 13px; color: #6B4F17;
    max-width: 56ch;
}
.provisional b { font-weight: 700; }
.bar-track { height: 6px; background: #E7E2D5; border-radius: 3px; margin-top: 8px; overflow: hidden; }
.bar-fill { height: 100%; background: var(--warn); border-radius: 3px; }

/* thermometer scale legend */
.scale-key { display: flex; flex-direction: column; gap: 6px; width: 100%; max-width: 190px; }
.scale-key .row { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--muted); cursor: help; }
.scale-key .sw { width: 12px; height: 12px; border-radius: 3px; flex: none; }
.scale-key .row b { color: var(--ink); font-weight: 600; }
/* the plain meaning stays available to screen readers and as a tooltip */
.scale-key .meaning { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* ── Source cards ───────────────────────────────────────────────────────── */
.src { border: 1px solid var(--line); border-radius: var(--radius); padding: 16px 18px; background: #FDFDFD; }
.src .head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.src .name { font-size: 15px; font-weight: 700; color: var(--navy); }
.src .w { font-size: 11px; color: var(--steel); background: #E9EFF6; border-radius: 3px; padding: 2px 7px; white-space: nowrap; }
.src .status { display: flex; align-items: center; gap: 8px; margin: 12px 0 8px; font-size: 14px; font-weight: 600; }
.src .status .glyph { font-size: 15px; width: 16px; text-align: center; }
.src .blurb { font-size: 12.5px; color: var(--muted); }
.diverge { position: relative; height: 12px; background: #F0EEEE; border-radius: 3px; margin: 4px 0 4px; }
.diverge .mid { position: absolute; left: 50%; top: -3px; bottom: -3px; width: 1px; background: #BDB9B9; }
.diverge .fill { position: absolute; top: 0; bottom: 0; border-radius: 3px; }
/* the bar carries no numbers on purpose — this scale says which way is which */
.diverge-key {
    display: flex; justify-content: space-between; font-size: 10.5px; color: var(--muted);
    letter-spacing: .04em; margin-bottom: 10px;
}
.src.nodata { background: #F8F7F7; }
.src.nodata .name, .src.nodata .status { color: var(--muted); }

/* The map is gone. "Where this reading applies" was removed from the page on
   21 September 2026 (Garett, 10 Sep: not needed on each country page — it belongs in
   the methodology note), so #map, .map-key, .map-side, .grid.mapx and the Leaflet
   tooltip overrides went with it. Leaflet itself is still vendored and unreferenced;
   data/australian-states.geojson is still on disk. Reopening the map is a stakeholder
   decision, not a CSS one. */

/* ── Evidence panels ──────────────────────────────────────────────────────
   Two columns. Row 1 holds the two long lists of examples, row 2 the two compact
   breakdowns — pairing long with short left a ~400px hole in the grid row.
   `align-items: start` keeps every panel at its natural height. */
.ev { display: grid; grid-template-columns: 1fr 1fr; gap: 20px 28px; align-items: start; }
/* Framed on the Ligue's site this panel can be handed the full viewport width — measured at
   1728px on their /gtt/australia page, where two columns left ~850px lines and pushed the page
   past 2800px tall. Height is the scarce resource inside an iframe (the parent decides it and
   cannot grow to fit), so above 1500px the four panels sit side by side and the section is about
   half as tall. Below that nothing changes. */
@media (min-width: 1500px) {
    .ev { grid-template-columns: repeat(4, 1fr); gap: 24px; }
    .ev .how { max-width: none; }
}
.ev-list { list-style: none; }
.ev-list li { padding: 10px 0; border-bottom: 1px solid var(--line-2); font-size: 13.5px; }
.ev-list li:last-child { border-bottom: none; }
.ev-list .meta { font-size: 11.5px; color: var(--muted); text-transform: uppercase; letter-spacing: .06em; }
.ev-list a { text-decoration: none; }
.ev-list a:hover { text-decoration: underline; }
.theme-row { display: grid; grid-template-columns: 150px 1fr 48px; gap: 10px; align-items: center; padding: 6px 0; font-size: 13px; }
.theme-row .tb { height: 9px; background: #F0EEEE; border-radius: 2px; }
.theme-row .tb i { display: block; height: 100%; border-radius: 2px; background: var(--ligue-blue); }
.theme-row .tv { text-align: right; font-variant-numeric: tabular-nums; color: var(--muted); }
.search-row { display: grid; grid-template-columns: 1fr 140px 150px; gap: 12px; align-items: center; padding: 8px 0; border-bottom: 1px solid var(--line-2); font-size: 13.5px; }
.search-row:last-child { border-bottom: none; }
.search-row .st { font-size: 12.5px; font-weight: 600; }
.search-row svg { display: block; }

/* ── Footer ─────────────────────────────────────────────────────────────── */
.foot {
    max-width: 1240px; margin: 0 auto; padding: 22px 28px 44px;
    color: var(--muted); font-size: 12.5px; border-top: 1px solid var(--line);
}
.foot b { color: var(--steel); }

/* ══════════════════════════════════════════════════════════════════════════
   Operations
   ══════════════════════════════════════════════════════════════════════════ */
.op-strip { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 14px; }
.op-tile { border: 1px solid var(--line); border-radius: var(--radius); padding: 13px 15px; background: #FDFDFD; }
.op-tile .h { font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); font-weight: 700; }
.op-tile .v { font-size: 20px; font-weight: 700; font-variant-numeric: tabular-nums; margin-top: 3px; }
.op-tile .s { font-size: 12px; color: var(--muted); }
.op-tile.alert { background: #FDF3F3; border-color: #E9C4C4; }
.op-tile.warn  { background: #FBF7EE; border-color: #EBD9B4; }

.pill { display: inline-flex; align-items: center; gap: 6px; border-radius: 999px; padding: 3px 11px; font-size: 12px; font-weight: 700; }
.pill.ok { background: #E7F5EE; color: #0B6B47; }
.pill.run { background: #FBF1E0; color: #8A5209; }
.pill.warn { background: #FBF1E0; color: #8A5209; }
.pill.bad { background: #FBEBEC; color: #8E1319; }
.pill.idle { background: #E9EFF6; color: var(--steel); }
.pill.grey { background: #F0EEEE; color: var(--muted); }

/* collection calendar */
.cal { overflow-x: auto; }
.cal table { border-collapse: separate; border-spacing: 3px; }
.cal th.lab { text-align: left; font-size: 12.5px; font-weight: 600; color: var(--ink); padding-right: 12px; white-space: nowrap; }
.cal th.day { font-size: 9px; color: var(--muted); font-weight: 500; width: 18px; padding: 0; }
.cal td { padding: 0; }
.cal th.mstart, .cal td.mstart { border-left: 2px solid #BDB9B9; }   /* new month starts here */
/* the swatch is shared by the grid and its legend — keep it selector-independent */
.cell { width: 18px; height: 18px; border-radius: 3px; display: block; border: 1px solid transparent; }
.cell.ok { background: var(--ok); }
.cell.missing { background: #FBEBEC; border-color: var(--bad); background-image: repeating-linear-gradient(45deg, var(--bad) 0 2px, transparent 2px 5px); }
.cell.pending { background: #FBF7EE; border-color: #D9B978; border-style: dashed; }
.cell.na { background: #F0EEEE; border-color: var(--line); }
.cal .tot { font-size: 11.5px; color: var(--muted); white-space: nowrap; padding-left: 10px; font-variant-numeric: tabular-nums; }
.cal-key { display: flex; gap: 18px; flex-wrap: wrap; margin-top: 12px; font-size: 12px; color: var(--muted); align-items: center; }
.cal-key .k { display: inline-flex; align-items: center; gap: 6px; }
.cal-key .cell { width: 14px; height: 14px; }

/* tables */
.tbl { width: 100%; border-collapse: collapse; font-size: 13px; }
.tbl th {
    text-align: left; padding: 8px 10px; background: #F4F6F9; color: var(--steel);
    font-size: 11px; letter-spacing: .08em; text-transform: uppercase; border-bottom: 1px solid var(--line);
}
.tbl td { padding: 8px 10px; border-bottom: 1px solid var(--line-2); vertical-align: top; }
.tbl tbody tr:hover { background: #FAFBFD; }
.tbl .num { text-align: right; font-variant-numeric: tabular-nums; }
.tbl .dim { color: var(--muted); }

/* controls */
.controls { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.btn {
    border: 1px solid transparent; border-radius: 4px; padding: 9px 16px; font-size: 13.5px;
    font-weight: 600; cursor: pointer; font-family: inherit; background: #E9EFF6; color: var(--steel);
}
.btn.primary { background: var(--ligue-blue); color: #fff; }
.btn.ai { background: var(--navy); color: #fff; }
.btn.stop { background: #fff; color: var(--bad); border-color: var(--bad); }
.btn:disabled { opacity: .45; cursor: not-allowed; }
.btn:hover:not(:disabled) { filter: brightness(1.07); }
.field {
    padding: 8px 10px; border: 1px solid var(--line); border-radius: 4px;
    font-family: inherit; font-size: 13.5px; background: #fff; color: var(--ink);
}
.field.num { width: 74px; }
.hint { font-size: 12.5px; color: var(--muted); }

.log {
    background: var(--navy); color: #DCD8D8; font-family: var(--mono); font-size: 11.5px;
    padding: 14px 16px; border-radius: var(--radius); max-height: 300px; overflow: auto;
    white-space: pre-wrap; line-height: 1.5;
}
.stage-chip { display: inline-block; font-size: 11px; padding: 2px 8px; border-radius: 3px; margin: 1px 2px 1px 0; }

/* unlock gate */
.gate { max-width: 430px; margin: 60px auto; text-align: center; }
.gate .card { padding: 30px 28px; }
.gate h1 { font-family: var(--serif); font-weight: 400; font-size: 24px; color: var(--navy); margin-bottom: 6px; }
.gate p { font-size: 13.5px; color: var(--muted); margin-bottom: 18px; }
.gate form { display: flex; gap: 8px; }
.gate .field { flex: 1; }
.gate .err { color: var(--bad); font-size: 13px; margin-top: 12px; min-height: 18px; }

/* ── Responsive ───────────────────────────────────────────────────────────
   Checked at 1440 (desktop), 834 (tablet portrait) and 390 (phone): no
   horizontal scroll at any of them, and nothing is clipped. */
@media (max-width: 1040px) {
    .hero { grid-template-columns: 250px 1fr; gap: 24px; }
}
@media (max-width: 860px) {
    .wrap { padding: 20px 18px 48px; }
    .masthead-in { padding: 0 18px; height: auto; min-height: 60px; flex-wrap: wrap; gap: 10px; padding-top: 10px; padding-bottom: 10px; }
    .brand .logo { height: 38px; }
    .brand .lockup .t1 { font-size: 16px; }
    .hero { grid-template-columns: 210px 1fr; gap: 20px; }
    .grid.two, .ev { grid-template-columns: 1fr; }
    .reading .value { font-size: 62px; }
    .hero-read h1 { font-size: 28px; }
    .how { max-width: none; }
}
/* phone: the instrument moves below the reading so the number stays first */
@media (max-width: 700px) {
    .hero { grid-template-columns: 1fr; }
    .hero-instrument { order: 2; }
    .scale-key { max-width: none; }
    .brand .rule, .brand .lockup .t2 { display: none; }
    .brand .lockup .t1 { font-size: 15px; white-space: normal; }
    .brand { gap: 10px; }
    .theme-row { grid-template-columns: 118px 1fr 44px; }
}
@media (max-width: 560px) {
    /* the sparkline is the first thing to go: the words carry the meaning */
    .search-row { grid-template-columns: 1fr 130px; }
    .search-row svg { display: none; }
}

@media print {
    body { background: #fff; }
    /* the logo is white: keep the bar dark or it disappears on paper */
    .masthead { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
    .card { box-shadow: none; break-inside: avoid; }
}

@media (prefers-reduced-motion: reduce) {
    * { animation: none !important; transition: none !important; }
}

/* Collection has stopped — see PAGE_STALE_DAYS in app.py. Amber, not red: the data is
   old, which is a fact about the page, not a failure of the reading it is showing. */
.stale-note {
    margin: 0 0 18px; padding: 12px 14px; border-radius: 8px;
    background: #FBF1E0; color: #6B4406; border: 1px solid #E8D3A8;
    font-size: 14px; line-height: 1.5;
}
.stale-note b { font-weight: 700; }
