/* ── Fonts, self-hosted ──────────────────────────────────────────────────
   These were loaded from fonts.googleapis.com, which sends every visitor's
   IP address to Google on every page view. The legal page says "Two
   companies process data on our behalf, and no others" — so publishing that
   sentence beside a Google font request would have made it false on arrival,
   on the one site whose whole argument is that we say what is true.

   IBM Plex is OFL 1.1, so self-hosting is permitted outright. Latin and
   latin-ext only: the copy is English, and latin-ext covers the country
   names that need it (Curaçao, Åland, Côte d'Ivoire). Dropping cyrillic,
   greek and vietnamese saves ~70% of the bytes for glyphs no page renders.

   Also faster than Google Fonts ever was: same-origin, no third-party DNS
   lookup, no second TLS handshake, and cache-partitioning killed the
   shared-cache argument for this years ago. */
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;
  font-display:swap;src:url('fonts/IBMPlexMono-400-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:'IBM Plex Mono';font-style:normal;font-weight:400;
  font-display:swap;src:url('fonts/IBMPlexMono-400-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:'IBM Plex Mono';font-style:normal;font-weight:500;
  font-display:swap;src:url('fonts/IBMPlexMono-500-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:'IBM Plex Mono';font-style:normal;font-weight:500;
  font-display:swap;src:url('fonts/IBMPlexMono-500-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:'IBM Plex Sans';font-style:normal;font-weight:400;
  font-display:swap;src:url('fonts/IBMPlexSans-400-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:'IBM Plex Sans';font-style:normal;font-weight:400;
  font-display:swap;src:url('fonts/IBMPlexSans-400-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:'IBM Plex Sans';font-style:normal;font-weight:500;
  font-display:swap;src:url('fonts/IBMPlexSans-500-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:'IBM Plex Sans';font-style:normal;font-weight:500;
  font-display:swap;src:url('fonts/IBMPlexSans-500-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:'IBM Plex Sans';font-style:normal;font-weight:600;
  font-display:swap;src:url('fonts/IBMPlexSans-600-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:'IBM Plex Sans';font-style:normal;font-weight:600;
  font-display:swap;src:url('fonts/IBMPlexSans-600-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}

/* 1752.io v4 — shared shell.
   One stylesheet for every page, so the Astro port is a mechanical translation
   rather than five separate reconciliations. Design language is v3's, unchanged:
   IBM Carbon greys, Plex Sans/Mono, teal accent. */

:root{
  --g100:#0b0b0b; --g90:#161616; --g80:#262626; --g70:#393939;
  /* CONTRAST, MEASURED AGAINST THE PAGE GROUND (#0b0b0b).
     --g50 was #8d8d8d — 5.93:1, which clears WCAG AA and stops there. It is
     the dim-text token and carries ~222 usages, most of them small mono type,
     which is exactly the case that punishes a reader with low vision. It went
     to #9b9b9b: 7.08:1 on the page and 6.51:1 on a card.

     THAT SECOND NUMBER IS THE ONE THAT MATTERS, and the note here used to
     claim #9b9b9b was "AAA where the text actually sits". It was not. Most of
     these 222 usages are inside panels and cards on --g90, not on the page
     ground, so the figure a reader actually gets was 6.51 — AA comfortably,
     AAA not at all. Measuring against the page ground flattered the token.

     --g50 is #a4a4a4 now: 7.90:1 on the page, 7.26:1 on a card. AAA on both,
     with margin, rather than AAA on the surface the text is least often on.

     --g40 MOVED WITH IT, and had to. At #a8a8a8 it sat four steps above the
     new --g50 and the two became indistinguishable — the hierarchy would have
     been bought away for half a contrast point. At #b8b8b8 the gap is twenty
     steps, wider than the thirteen it had before, and --g30 is still fourteen
     above that.

     --g60 was #525252 — 2.52:1, which fails AA for normal text, fails the 3:1
     large-text bar, and failed the 3:1 bar for UI components too. There is no
     value between it and --g50 that passes for text, so it stops being a text
     colour: it is borders and hover states now, at #666666 (3.43:1), and the
     twenty places using it for type moved to --g50. */
  --g60:#666666; --g50:#a4a4a4;
  /* WCAG 1.4.11: the visible boundary of a CONTROL needs 3:1, which --g70
     (1.7:1) fails. --edge is that boundary; --g70 stays for decorative rules. */
  /* INK ON TEAL. #00302f was 6.15:1 against --teal40 — the inverse case to
     the greys above, dark text on a bright ground, and it misses AAA by the
     same margin they did. #001f1e is 7.41:1 and still reads as deep teal
     rather than black, so a pressed chip does not turn into a hole. */
  --edge:#6f6f6f; --g40:#b8b8b8; --g30:#c6c6c6; --g10:#f4f4f4;
  --teal40:#08bdba; --teal-d:#009d9a; --blue40:#78a9ff;
  --green40:#42be65; --yellow30:#f1c21b; --red40:#fa4d56; --purple40:#be95ff;
  --sans:'IBM Plex Sans',system-ui,-apple-system,sans-serif;
  --mono:'IBM Plex Mono',ui-monospace,SFMono-Regular,Menlo,monospace;
  --wrap:1120px;

  /* THESE THREE WERE USED 16 TIMES AND DEFINED ZERO TIMES.
     var(--line) with no fallback makes the whole declaration invalid at
     computed-value time — the property does not fall back to something
     sensible, it unsets. So `border:1px solid var(--line)` rendered NO
     BORDER, silently, on every .cp-card, .lyr, .uc, .h-box and .cp table,
     and `background:var(--bg)` on the sticky table headers rendered
     TRANSPARENT, which is why rows showed through the region headings.

     Defining them as aliases rather than rewriting 16 call sites: the names
     carry intent (a hairline, dim text, the page ground) that --g80/--g40/
     --g100 do not, and that intent is worth keeping. */
  --bg:var(--g100);      /* page ground — opaque, for anything sticky */
  --line:var(--g80);     /* hairline rule and card border */
  --dim:var(--g40);      /* dim body text, same as .dim */

  /* Measured onto the root by shell.js. The fallback is the height at the
     default font size; anything sticky offsets by it. Raised from 69px when
     the utility row was added above the masthead — the measurement corrects
     it a frame later, but the fallback is what the first paint uses, and a
     stale one puts every sticky table header under the header it should sit
     below. */
  --nav-h:104px;
}
*{box-sizing:border-box}
/* WCAG 2.4.7 Focus Visible. Links and buttons had no focus style at all, so a
   keyboard user could not tell where they were. One rule covers every control;
   :focus-visible keeps it off for mouse clicks. */
:focus-visible{outline:2px solid var(--teal40);outline-offset:2px;border-radius:2px}
/* the teal ring is invisible ON teal, so the primary button inverts it */
.btn-p:focus-visible{outline-color:var(--g10)}
html{scroll-behavior:smooth}
body{margin:0;background:var(--g100);color:var(--g10);font-family:var(--sans);
  font-size:17px;line-height:1.62;-webkit-font-smoothing:antialiased}
a{color:inherit}
.wrap{max-width:var(--wrap);margin:0 auto;padding-left:24px;padding-right:24px}
section[id]{scroll-margin-top:72px}

/* ── type ── */
h1{font-size:clamp(33px,4.4vw,50px);line-height:1.08;letter-spacing:-.02em;
  font-weight:600;margin:0 0 14px}
h2{font-size:clamp(25px,2.8vw,34px);line-height:1.14;letter-spacing:-.015em;
  font-weight:600;margin:0 0 12px}
h3{font-size:19px;font-weight:600;margin:0 0 6px;line-height:1.25}
p{margin:0 0 14px}
.lede{font-size:19.5px;color:var(--g30);max-width:60ch}
.eyebrow{font-family:var(--mono);font-size:12px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--teal40);margin-bottom:14px}
.dim{color:var(--g40)}
.mono{font-family:var(--mono)}
.small{font-size:14.5px}

/* ── masthead ── */
header.site{position:sticky;top:0;z-index:40;background:rgba(11,11,11,.94);
  backdrop-filter:blur(8px);border-bottom:1px solid var(--g80)}
/* A FIXED HEIGHT, so the webfont swap cannot change it. The masthead measured
   69px with the fallback face and 91px once IBM Plex loaded, and everything
   that offsets by --nav-h — the section bar, the table headers, every anchor's
   scroll-margin — jumped at that moment. Reserving the final height removes the
   event rather than reacting to it. */
/* ── utility row ──────────────────────────────────────────────────────
   Slim by design: a shelf for the things a visitor reaches FOR, not a second
   navigation. If it ever needs to be as tall as the masthead, something has
   been put up here that belongs below. */
.util{border-bottom:1px solid var(--g80);background:rgba(0,0,0,.3)}
.util-in{display:flex;align-items:center;gap:20px;min-height:34px;
  font-size:12.5px;line-height:1}
.util-note{color:var(--g50);min-width:0;overflow:hidden;white-space:nowrap;
  text-overflow:ellipsis}
/* Once it is showing real observances rather than the slogan. The date is
   given weight because it is the claim being made; the rest is the evidence. */
.util-today{color:var(--g40)}
/* THE GAP AFTER THE DATE. With two or more observances the counter sits
   between the date and the text and supplies its own air; with ONE there is
   no counter, and "Today 4 Aug🇨🇰 Cook Islands" ran the flag straight into
   the date. The date owns the space either way now, so the single-observance
   case — which is most days — reads as a sentence rather than a collision. */
.util-today .ut-d{color:var(--g20,#e0e0e0);font-family:var(--mono);font-weight:500;
  text-decoration:none;border-bottom:1px solid transparent;margin-right:7px}
.util-today .ut-d:hover{color:var(--teal40);border-bottom-color:var(--teal40)}
.util-today b{color:var(--g20,#e0e0e0);font-family:var(--mono);font-weight:500;
  margin-right:2px}
.ut-slot{transition:opacity .22s}
/* A button, not a label. It advances the line, which is the only way a reader
   with reduced-motion set can see the second observance at all. */
/* Between the date and the observance now, so it needs air on both sides. */
/* --g50, NOT --g60. At 11px this is normal-size text, so WCAG AA wants 4.5:1,
   and --g60 (#525252) on the black bar measures 2.69:1 — the only element in
   that row that failed. Everything beside it sits between 8.8 and 15.9.
   --g50 (#8d8d8d) measures 6.33:1.

   The border moves too, because this is a BUTTON and 1.4.11 asks 3:1 of a
   control's boundary. Measured rather than guessed: --g80 is 1.39:1 and --g70
   only 1.82:1, so the next step up the scale would still have failed. The
   lowest grey that reaches 3:1 on black is #595959, which is past --g60
   (2.69:1) — so the boundary takes --g50 as well. */
.ut-n{font-family:var(--mono);font-size:11px;color:var(--g50);margin:0 8px 0 0;
  background:transparent;border:1px solid var(--g50);border-radius:3px;
  padding:2px 6px;cursor:pointer;line-height:1}
.ut-n:hover{color:var(--g10);border-color:var(--g30)}
@media (prefers-reduced-motion:reduce){.ut-slot{transition:none}}

/* WHEN THE READER HAS ASKED THE OS FOR MORE CONTRAST, GIVE IT TO THEM.
   The defaults above clear AAA for dim text on the page ground, which is the
   right resting place for a design that has to stay readable as a whole. This
   is for people who have gone into their system settings and said it is still
   not enough — every dim step goes up one, borders included, and the eyebrow
   and caption type that carries the most small mono text goes furthest.
   Tokens only: nothing here restyles a component, so it cannot drift from the
   layout it is meant to be describing. */
@media (prefers-contrast:more){
  :root{
    --g50:#b8b8b8;     /* 10.2:1 — dim text */
    --g40:#d0d0d0;     /* 12.9:1 — body */
    --g30:#e4e4e4;     /* 15.4:1 — emphasis */
    --g60:#8a8a8a;     /* 5.6:1  — borders and hover states */
    --edge:#949494;    /* 6.5:1  — input and control edges */
    --line:#3a3a3a;    /* hairlines lift too, or the grid disappears */
  }
}
.util-nav{display:flex;gap:18px;margin-left:auto;align-items:center}
/* A CONTROL, so it takes a control's contrast. 1.4.11 asks 3:1 of a
   boundary and --g50 is the lowest grey on this bar that reaches it — the
   same reasoning as the ticker's counter directly above. */
.a-plus{font-family:var(--mono);font-size:11px;line-height:1;color:var(--g50);
  background:transparent;border:1px solid var(--g50);border-radius:3px;
  padding:3px 7px;cursor:pointer;white-space:nowrap}
.a-plus:hover{color:var(--g10);border-color:var(--g30)}
.a-plus:focus-visible{outline:2px solid var(--teal40);outline-offset:2px}
.a-plus[data-level="0"]{color:var(--g50)}
.a-plus:not([data-level="0"]){color:var(--teal40);border-color:var(--teal40)}
.util-nav a{color:var(--g40);text-decoration:none;padding:10px 0}
.util-nav a:hover{color:var(--g10)}
.util-nav a[aria-current=page]{color:var(--g10)}
/* The sign-in gets a little weight: it is the one thing up here a RETURNING
   customer is scanning for, and nothing else in this row competes for that
   glance. It is not a button, because it is not what we want a new visitor
   to press — that is the CTA below. */
.util-nav a:last-child{color:var(--g30);font-weight:500}
.util-nav a:last-child:hover{color:var(--teal40)}
@media (max-width:860px){
  /* The note goes first. It is reassurance, and reassurance is what a phone
     header has no room for. */
  .util-note{display:none}
  .util-nav{margin:0 auto}
}

/* padding-block, NOT `padding:14px 0`. The shorthand also set left and right
   to zero, which overrode the 24px .wrap gives every other row on the page —
   invisible on desktop, where .wrap is centred inside a max-width anyway, and
   very visible on a phone, where it put the wordmark hard against the bezel. */
.mast{display:flex;align-items:center;gap:26px;padding-block:14px;min-height:63px}
.brand{font-family:var(--mono);font-size:16px;letter-spacing:-.01em;
  text-decoration:none;font-weight:500}
.brand b{color:var(--teal40);font-weight:500}
nav.site{display:flex;gap:20px;margin-left:auto;font-size:15px}
nav.site a{color:var(--g30);text-decoration:none;padding-bottom:3px}
nav.site a:hover{color:var(--g10)}
nav.site a[aria-current=page]{color:var(--g10);box-shadow:inset 0 -2px 0 var(--teal40)}

/* ── buttons ── */
.btn{display:inline-flex;align-items:center;gap:8px;font-family:var(--sans);
  font-size:15.5px;font-weight:500;padding:11px 18px;border-radius:2px;
  text-decoration:none;border:1px solid transparent;cursor:pointer}
.btn-p{background:var(--teal40);color:var(--g100);border-color:var(--teal40)}
.btn-p:hover{background:var(--teal-d);border-color:var(--teal-d)}
.btn-s{background:transparent;color:var(--g10);border-color:var(--edge)}
.btn-s:hover{border-color:var(--g50)}

/* ── surfaces ── */
.card{background:var(--g90);border:1px solid var(--g80);border-radius:3px;padding:22px}
.grid{display:grid;gap:18px}
.g2{grid-template-columns:repeat(auto-fit,minmax(280px,1fr))}
.g3{grid-template-columns:repeat(auto-fit,minmax(240px,1fr))}
.g4{grid-template-columns:repeat(auto-fit,minmax(200px,1fr))}
/* SIX TILES, NEVER FIVE-AND-ONE. auto-fit is right when the item count is
   unknown; this row holds exactly six, and at a common desktop width auto-fit
   put five on one line and orphaned the sixth. Six divides evenly three ways,
   so the breakpoints are stated rather than left to the browser's arithmetic. */
.g6{grid-template-columns:repeat(2,1fr)}
@media (min-width:640px){ .g6{grid-template-columns:repeat(3,1fr)} }
@media (min-width:1000px){ .g6{grid-template-columns:repeat(6,1fr)} }

/* ── status + assurance pills ── */
.pill{display:inline-flex;align-items:center;gap:6px;font-family:var(--mono);
  font-size:11px;letter-spacing:.09em;text-transform:uppercase;
  padding:3px 8px;border:1px solid currentColor;border-radius:2px}
.p-live{color:var(--green40)}
.p-verified{color:#ffffff}
.p-partial{color:var(--yellow30)}
.p-corroborated{color:#a7b4c2}
.p-soon{color:var(--g50)}
/* #8b97a5 was 6.09:1 on a card — AA, not AAA, and `compiled` is the pill
   most often shown because most of the corpus is compiled. #9ba7b5 is
   7.40:1 and still twelve steps below `corroborated`, so the assurance
   ladder still reads as a ladder. Colour is never the only cue here in
   any case: every pill carries its word. */
.p-compiled{color:#9ba7b5}
.p-estimate{color:var(--purple40)}
.dot{width:6px;height:6px;border-radius:50%;background:currentColor;flex:0 0 auto}

/* ── stat ── */
.stat{border-left:2px solid var(--teal40);padding-left:14px}
.stat .v{font-family:var(--mono);font-size:29px;line-height:1.1;color:var(--g10)}
.stat .k{font-family:var(--mono);font-size:11.5px;letter-spacing:.11em;
  text-transform:uppercase;color:var(--g50);margin-top:5px}
/* THE QUALIFIER LINE. A count with no unit invites the wrong reading: "3,847
   observances" is asked back as "per year?" by anyone seeing it cold, and a
   dated total means nothing without the span it covers. Lower-case and
   un-tracked so it reads as a clarification rather than a second label. */
.stat .w{font-family:var(--mono);font-size:11px;color:var(--g50);
  margin-top:3px;letter-spacing:0}

/* ── tables ── */
/* STICKY HEADERS AND HORIZONTAL SCROLL ARE IN TENSION, and the previous fix
   did not resolve it. The reasoning was right — overflow-x:auto makes this a
   scroll container, so a sticky <th> anchors to a box that never scrolls
   vertically and therefore never sticks. The chosen escape, overflow-y:clip,
   does not work: per CSS Overflow 3, `clip` on one axis COMPUTES TO `hidden`
   when the other axis is not visible or clip. Measured: overflow-y resolved
   to hidden, and the header sat at -231px, scrolled away with the page.

   So the container is removed on wide viewports instead of being tricked.
   The table's min-width is 560px inside a 1120px wrap: on desktop it fits
   and needs no horizontal scroll, and with no scroll container between the
   <th> and the viewport, sticky resolves against the viewport and works.

   Below 760px the table genuinely cannot fit, so horizontal scrolling comes
   back and sticky headers are given up — which is the right trade at that
   size, where a six-column header would eat a third of the screen. */
.scroller{-webkit-overflow-scrolling:touch}
@media(max-width:760px){.scroller{overflow-x:auto}}
/* THE MIN-WIDTH BELONGS TO THE SCROLLER, NOT TO EVERY TABLE.
   It was set globally to serve the case above: a wide table inside .scroller
   needs a floor so that on desktop it exceeds nothing, no scroll container is
   created, and sticky <th> resolves against the viewport.

   But it applied to every <table> on the site, and only four pages use
   .scroller at all. On the 482 generated pages — every jurisdiction and every
   coverage record — the tables sit directly in a <section>, inherited a 560px
   floor inside a 375px phone, and pushed the whole DOCUMENT sideways. The
   columns that fell off the right edge were the observance name and its
   assurance grade: the answer, and the reason to believe it.

   Scoped to .scroller, the sticky-header case keeps exactly the floor it was
   given and every other table is free to fit the screen it is on. */
table{width:100%;border-collapse:collapse;font-size:15px}
.scroller table{min-width:560px}
th{font-family:var(--mono);font-size:11.5px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--g50);font-weight:400;text-align:left;
  padding:10px 12px;border-bottom:1px solid var(--g80)}
td{padding:11px 12px;border-bottom:1px solid var(--g80);vertical-align:middle}
tr:hover td{background:var(--g90)}

/* ── assurance bar ── */
/* ── Assurance bar ───────────────────────────────────────────────────────
   REGION USES HUE, ASSURANCE USES LIGHTNESS. Previously both were categorical
   and all three assurance colours were byte-identical to a region swatch on
   the same page: verified == Americas (#42be65), corroborated == Africa
   (#f1c21b), compiled == Europe (#78a9ff). A reader could reasonably think a
   blue bar meant "Europe".

   The deeper reason for the change: assurance is ORDINAL — compiled sits below
   corroborated sits below verified — and painting an order in unrelated hues
   throws that order away. A lightness ramp encodes it. Region stays
   categorical, and two orthogonal channels cannot collide.

   Adjacent steps land near 2.8:1, short of 3:1, because a three-step
   achromatic ramp on a dark ground cannot do better without losing the
   darkest step against the background. So colour is not asked to carry the
   separation: a 1px gap does that, and the hover tooltip carries the exact
   counts — which is also what keeps this out of "colour alone" territory. */
.abar{display:flex;gap:1px;height:6px;border-radius:2px;overflow:hidden;
  background:var(--g80);min-width:88px;cursor:help}
.abar i{display:block;height:100%}
.abar .v{background:#ffffff} .abar .c{background:#a7b4c2}
.abar .k{background:#5b6470}

.abar-w{position:relative;display:block}
.abar-t{position:absolute;left:0;bottom:calc(100% + 8px);z-index:20;
  background:var(--g90,#12161b);border:1px solid var(--line);border-radius:8px;
  padding:9px 12px;font:12px/1.7 var(--mono);white-space:nowrap;
  box-shadow:0 8px 24px rgba(0,0,0,.45);opacity:0;visibility:hidden;
  transition:opacity .12s ease}
.abar-w:hover .abar-t,.abar-w:focus-within .abar-t{opacity:1;visibility:visible}
.abar-t b{font-weight:500;display:inline-block;min-width:2.6em;text-align:right;
  margin-right:9px;color:var(--g10)}
.abar-t s{text-decoration:none;display:inline-block;width:9px;height:9px;
  border-radius:2px;margin-right:7px;vertical-align:baseline}

/* ── code ── */
code{font-family:var(--mono);font-size:13.5px;background:var(--g80);
  padding:2px 6px;border-radius:2px;color:var(--g30)}
pre{background:#000;border:1px solid var(--g80);border-radius:3px;padding:16px;
  overflow-x:auto;font-family:var(--mono);font-size:13.5px;line-height:1.55;margin:0}
pre .k{color:var(--blue40)} pre .s{color:var(--teal40)} pre .n{color:var(--purple40)}

/* ── notices ── */
.note{border-left:2px solid var(--blue40);background:var(--g90);
  padding:12px 16px;font-size:15px;color:var(--g30);margin:16px 0}
.note b{color:var(--g10)}
.draft{border-left-color:var(--yellow30)}

/* ── footer ── */
footer.site{border-top:1px solid var(--g80);margin-top:72px;padding:38px 0 54px;
  font-size:14.5px;color:var(--g40)}
/* FIVE COLUMNS. The blurb column keeps its extra weight, but 2fr against four
   siblings squeezed the link columns to the point where "API configurator"
   wrapped onto three lines. 1.6fr holds the sentence and gives the rest room.

   SUPERSEDED. The first column no longer holds a sentence — it holds Products,
   and all five carry links now. An unequal grid was correct when one column was
   doing a different job; five columns doing the same job want the same width,
   and a fifth each is what a reader's eye expects when it scans a row of
   headings. The brand line moved down to the legal bar, where it costs no
   navigational space. */
.foot-g{display:grid;grid-template-columns:repeat(5,1fr);gap:30px;margin-bottom:30px}
.foot-g h5,.foot-g .fg-h{font-family:var(--mono);font-size:11px;letter-spacing:.13em;
  text-transform:uppercase;color:var(--g50);margin:0 0 12px;font-weight:400}
.foot-g a{display:block;color:var(--g30);text-decoration:none;padding:5px 0;font-size:14.5px}
.foot-g a:hover{color:var(--g10)}
.foot-bar{display:flex;gap:20px;flex-wrap:wrap;align-items:baseline;
  border-top:1px solid var(--g80);padding-top:20px;font-family:var(--mono);
  font-size:12px;color:var(--g40)}
.foot-bar a{color:var(--g30);text-decoration:none}
.foot-bar a:hover{color:var(--g30)}
.accuracy{color:var(--g30);font-size:15px;max-width:58ch;margin:0 0 18px}
/* ── newsletter signup ── */
.signup{border-top:1px solid var(--g80);border-bottom:1px solid var(--g80);
  padding:26px 0;margin:0 0 30px;display:grid;grid-template-columns:1fr 1fr;
  gap:20px 40px;align-items:center}
.signup h5,.signup .su-h{font-weight:600;font-size:17px;color:var(--g10);margin:0 0 6px;font-weight:600}
.su-row{display:flex;gap:10px;flex-wrap:wrap}
.su-row input{flex:1 1 220px;min-width:0;background:var(--g100);
  border:1px solid var(--edge);color:var(--g10);font:inherit;font-size:15px;
  padding:11px 13px;border-radius:2px}
.su-row input:focus-visible{outline:2px solid var(--teal40);outline-offset:1px}
.su-row .btn{flex:0 0 auto}
.su-msg{grid-column:1/-1;margin:0;font-size:13.5px;min-height:1.2em}
.su-msg.ok{color:var(--green40)}
.su-msg.err{color:var(--yellow30)}
.vh{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
@media(max-width:640px){.signup{grid-template-columns:1fr;gap:14px}}
/* The edition line. Small, but never grey-on-grey: it carries the currency
   limitation the liability position depends on, so it holds AA against the
   footer background rather than fading into it. */
.edition-bar{font-family:var(--mono);font-size:12px;line-height:1.75;
  color:var(--g30);margin:18px 0 0;padding-top:16px;
  border-top:1px solid var(--g80);max-width:88ch}
.edition-bar b{color:var(--g10);font-weight:500}
.edition-bar a{color:var(--teal40)}

/* ── data-freshness stamp: every generated page carries one ── */
.stamp{font-family:var(--mono);font-size:12px;color:var(--g40);
  display:inline-flex;align-items:center;gap:8px}
.stamp .dot{background:var(--green40)}

/* ── Mobile menu ─────────────────────────────────────────────────────────
   `nav.site{display:none}` used to be the whole of the mobile navigation:
   below 860px the header kept the wordmark and the CTA and silently dropped
   every link. Coverage, Use cases, Reports and Pricing were reachable only
   from the footer, which nobody scrolls to in order to navigate.

   The panel is driven by [data-open] rather than a class, so the same
   attribute the JS sets for aria state also drives the CSS — one source of
   truth for "is this open", visible and announced together. */
.nav-toggle{display:none;background:none;border:0;cursor:pointer;padding:10px;
  margin-left:6px;width:44px;height:44px;align-items:center;justify-content:center}
/* 44px is the minimum comfortable touch target; the bars are drawn inside it
   rather than being the target themselves. */
.nav-toggle span,
.nav-toggle span::before,
.nav-toggle span::after{display:block;width:20px;height:2px;background:var(--g10);
  border-radius:1px;transition:transform .2s ease,opacity .15s ease}
.nav-toggle span::before,.nav-toggle span::after{content:"";position:relative}
.nav-toggle span::before{top:-6px}
.nav-toggle span::after{top:4px}
/* Bars become an X when open — the control shows its own state, so the
   reader never has to guess whether tapping again will close it. */
.nav-toggle[aria-expanded="true"] span{background:transparent}
.nav-toggle[aria-expanded="true"] span::before{transform:translateY(6px) rotate(45deg)}
.nav-toggle[aria-expanded="true"] span::after{transform:translateY(-4px) rotate(-45deg)}

@media(max-width:860px){
  /* Three columns at this width, not two: five items divide 3+2 with the wider
     column-count, where 2+2+1 leaves a lone column looking orphaned. And the
     first child no longer spans the full row — that rule existed for the brand
     block, which has moved to the legal bar. Products is an ordinary link
     column and must not be given a headline's worth of space. */
  .foot-g{grid-template-columns:repeat(3,1fr)}
  .nav-toggle{display:inline-flex}
  /* The CTA takes the spacing job the nav had, since the nav leaves the flow. */
  .mast .btn-p{margin-left:auto}
  nav.site{position:absolute;top:100%;left:0;right:0;display:none;
    flex-direction:column;gap:0;margin:0;
    background:var(--g100);border-bottom:1px solid var(--g80);
    box-shadow:0 18px 34px -20px rgba(0,0,0,.9)}
  nav.site[data-open="true"]{display:flex}
  nav.site a{padding:15px 24px;font-size:16px;color:var(--g30);
    border-top:1px solid var(--g90)}
  nav.site a:first-child{border-top:0}
  /* The underline that marks the current page reads as an underline in a
     row, not as a tab, so it moves to a left rule at this width. */
  nav.site a[aria-current=page]{box-shadow:inset 3px 0 0 var(--teal40);
    color:var(--g10);background:var(--g90)}
}
@media(prefers-reduced-motion:reduce){
  .nav-toggle span,.nav-toggle span::before,.nav-toggle span::after{transition:none}
}
@media(max-width:560px){
  .foot-g{grid-template-columns:1fr}
}

/* ── Layer grid (index) ──────────────────────────────────────────────────
   Four families side by side, because the POINT is that they are different
   kinds of claim. Rendering them as one undifferentiated feature list would
   undo the distinction the whole product rests on. */
.lyr-grid{display:grid;gap:14px;margin-top:26px;
  grid-template-columns:repeat(auto-fit,minmax(230px,1fr))}
.lyr{border:1px solid var(--line);border-radius:10px;padding:18px 20px}
.lyr-h{font-weight:600;font-size:1rem;display:flex;gap:9px;align-items:center;
  margin-bottom:8px}
.lyr-tag{font:500 10px/1.6 var(--mono);text-transform:uppercase;letter-spacing:.08em;
  padding:1px 7px;border-radius:9px;border:1px solid currentColor}
.lyr-tag.live{color:var(--g10)}
.lyr-tag.soon{color:var(--dim)}
.lyr-l{list-style:none;margin:12px 0 0;padding:0;font-size:.88rem}
.lyr-l li{padding:4px 0;border-top:1px solid var(--line)}
.lyr-l li.soon{color:var(--dim)}
.lyr-l li.soon::after{content:" · building";font:500 10px var(--mono);
  text-transform:uppercase;letter-spacing:.06em;opacity:.75}

/* ── Country page ────────────────────────────────────────────────────────
   These are the pages strangers arrive on from search, so they must read as
   a document rather than an app: no loading state, no empty frame, nothing
   that depends on JS to make sense. */
.cp{width:100%;border-collapse:collapse;margin-top:14px;font-size:.94rem}
.cp th{text-align:left;font-weight:500;color:var(--dim);white-space:nowrap;
  padding:10px 18px 10px 0;border-bottom:1px solid var(--line);vertical-align:top;width:1%}
.cp td{padding:10px 0;border-bottom:1px solid var(--line)}
.cp-cta{display:grid;gap:14px;margin-top:16px;
  grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}
.cp-card{border:1px solid var(--line);border-radius:10px;padding:20px}
.cp-card h3{margin:0 0 8px;font-size:1.05rem}

/* Crawlable escape hatch from a card that is otherwise a <button>. Visible and
   focusable — hiding it from sight but not from crawlers would be cloaking. */
.rc-permalink{display:block;font-size:.82rem;padding:8px 2px 0;color:var(--dim);
  text-decoration:none}
.rc-permalink:hover,.rc-permalink:focus-visible{color:var(--g10);text-decoration:underline}
.c-link{color:inherit;text-decoration:none;border-bottom:1px solid var(--line)}
.c-link:hover,.c-link:focus-visible{color:var(--teal40);border-bottom-color:currentColor}

/* Sticky column headers per region table. Each table has its own <thead>, so
   each sticks under the site header as you pass through its section — with 240
   rows across five regions, losing the headings is losing the meaning. */
.scroller table thead th{position:sticky;top:var(--nav-h,56px);z-index:2;
  background:var(--bg);box-shadow:inset 0 -1px 0 var(--line)}

.edition-bar{display:flex;gap:22px;flex-wrap:wrap;font-size:12.5px}
.eb-l{color:var(--g50)}
.eb-l b{color:var(--g30);font-weight:500}

/* ── Hero ────────────────────────────────────────────────────────────── */
/* 19ch was set for a single fixed headline. The rotating lines are longer and
   more variable, and the longest of them ran to FOUR lines at that width —
   which changes the height of the hero every few seconds and shoves everything
   below it up and down. 26ch holds the longest line in three, so the block
   settles to one height and stops jumping. */
/* Exactly three line-heights (1.08 × 3). At 3.06em a two-line headline was
   padded to slightly UNDER three lines, so a three-line one still nudged
   everything below it — a reserved height that does not match the tallest case
   reserves the wrong thing. */
.h-promise{max-width:26ch;min-height:3.24em}
.h-box{border:1px solid var(--line);border-left:3px solid var(--teal40);
  border-radius:0 8px 8px 0;padding:16px 20px;margin:22px 0 0;max-width:62ch;
  color:var(--g30);font-size:15px;line-height:1.65}
.h-clocks{display:flex;gap:24px;flex-wrap:wrap;margin:18px 0 0;
  font-family:var(--mono);font-size:12px;color:var(--g50)}
.h-clocks b{color:var(--g30);font-weight:500}

/* ── Use-case grid ───────────────────────────────────────────────────── */
.uc-grid{display:grid;gap:12px;margin-top:26px;
  grid-template-columns:repeat(auto-fit,minmax(230px,1fr))}
.uc{border:1px solid var(--line);border-radius:10px;padding:16px 18px;
  display:flex;flex-direction:column;gap:8px;min-height:0}
.uc-i{font-family:var(--mono);font-size:10px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--teal40)}
.uc h3{margin:0;font-size:1rem;line-height:1.32;font-weight:600}
.uc p{margin:0;font-size:.85rem;color:var(--g50);line-height:1.55}
.uc-q{margin-top:auto;font-family:var(--mono);font-size:11px;color:var(--g30);
  border-top:1px solid var(--line);padding-top:9px}

/* ── Sign-up form ────────────────────────────────────────────────────────
   ONE RHYTHM, NOT TEN. The first version carried ten font sizes, nine
   colours and six weight/decoration treatments across four fields — every
   field wearing a label, a REQUIRED or OPTIONAL chip in uppercase mono, an
   input, and a paragraph of our own reasoning. Stacked four times that
   reads as a document with boxes in it, and the reader cannot tell which
   words are the question.

   A form is a sequence of questions. What earns space is the question, the
   box, and only the help that would change the answer. The rest of the
   reasoning belongs in one note at the foot of the page, where a reader who
   wants it can find it and everyone else can ignore it.

   The scale below is deliberately small: label 15, input 16, help 14.5,
   and a single accent (teal) that means "focus or success" everywhere it
   appears. Yellow appears only when something is wrong. */
.su-form{margin-top:32px;max-width:34rem}
.su-form .f{margin-top:26px}
.su-form label{display:block;margin-bottom:8px;font-weight:500;font-size:15px}
/* "optional" as plain words at the same size — a chip in a second family and
   a third colour is a lot of design for one bit of information. */
.su-form label .o{font-weight:400;color:var(--g50)}
.su-form input,.su-form textarea{width:100%;font:inherit;padding:11px 13px;
  background:var(--g90);border:1px solid var(--g70);border-radius:6px;
  color:var(--g10);transition:border-color .12s}
.su-form input:hover,.su-form textarea:hover{border-color:var(--g60)}
.su-form input::placeholder,.su-form textarea::placeholder{color:var(--g50)}
.su-form textarea{resize:vertical;line-height:1.55;min-height:96px}
.su-form .fh{margin:8px 0 0;font-size:14.5px;color:var(--g50);line-height:1.5}
/* Errors sit under the field they belong to, not in one status line at the
   bottom — by the time you have scrolled to a global error you have lost
   which question it was about. Driven by aria-invalid so the visual state
   and the state announced to a screen reader cannot drift apart. */
.su-form .fe{display:none;margin:8px 0 0;font-size:14.5px;color:var(--yellow30)}
.su-form [aria-invalid="true"]{border-color:var(--yellow30)}
.su-form [aria-invalid="true"] ~ .fe{display:block}
.su-form button{margin-top:30px}
.su-out{margin-top:16px;font-size:14.5px;color:var(--teal40)}

/* ── Dossier: cover, manifest, pills ──────────────────────────────────────
   Shared by the Reports grid (inside a dialog) and by every country page
   (as page content). It lived in reports.html, where the .toc/.mi/.pills
   block was also pasted in TWICE — two identical copies drifting one edit
   apart from each other. One copy, one file, both pages import it. */
.rgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(268px,1fr));
  gap:48px 34px;margin-top:30px}
.rcard{display:flex;flex-direction:column;gap:15px;align-items:center;
  text-align:center;text-decoration:none;background:none;border:0;
  font:inherit;color:inherit;cursor:pointer;padding:0}
.rc-cover{--cover-bg:linear-gradient(155deg,#1f1f1f,#0a0a0a);
  position:relative;width:100%;max-width:236px;aspect-ratio:7/10;
  border-radius:7px;overflow:hidden;background:var(--cover-bg);
  box-shadow:0 18px 36px -18px rgba(0,0,0,.8);
  border:1px solid rgba(255,255,255,.16);
  transition:transform .4s cubic-bezier(.2,.8,.2,1),box-shadow .4s ease}
.rc-cover::before{content:"";position:absolute;left:0;top:0;bottom:0;width:6px;
  background:var(--accent,var(--teal40));z-index:3}
.rc-cover::after{content:"";position:absolute;right:0;bottom:0;width:22px;height:22px;
  background:linear-gradient(135deg,transparent 50%,rgba(0,0,0,.55) 50%);z-index:3}
.rc-sheen{position:absolute;inset:0;z-index:2;pointer-events:none;
  background:linear-gradient(135deg,transparent 42%,rgba(255,255,255,.18) 50%,transparent 58%);
  opacity:0;transform:translateX(-28%);
  transition:opacity .35s ease,transform .7s cubic-bezier(.2,.8,.2,1)}
.rc-eyebrow{position:absolute;top:16px;left:20px;z-index:3;font-family:var(--mono);
  font-size:10px;letter-spacing:.18em;text-transform:uppercase;color:var(--accent,var(--teal40))}
.rc-title{position:absolute;left:20px;right:16px;top:42px;z-index:3;margin:0;
  font-size:20px;line-height:1.15;font-weight:600;letter-spacing:-.01em;
  color:var(--g10);text-align:left}
.rc-title::after{content:"";display:block;width:30px;height:2px;margin-top:11px;
  border-radius:2px;background:var(--accent,var(--teal40))}
.rc-meta{position:absolute;left:20px;bottom:16px;z-index:3;font-family:var(--mono);
  font-size:10px;letter-spacing:.08em;color:var(--yellow30)}
.rcard:hover .rc-cover,.rcard:focus-visible .rc-cover{transform:translateY(-6px);
  box-shadow:0 26px 48px -18px rgba(0,0,0,.85)}
.rcard:hover .rc-sheen,.rcard:focus-visible .rc-sheen{opacity:1;transform:translateX(28%)}
/* Spine colour is a GEOGRAPHIC FACT, taken from the UN M49 region in the
   feed — not a per-card design choice. Same region, same colour, always. */
.rc-cover.r-europe  {--accent:#78a9ff} .rc-cover.r-africa {--accent:#f1c21b}
.rc-cover.r-asia    {--accent:#be95ff} .rc-cover.r-americas{--accent:#42be65}
.rc-cover.r-oceania {--accent:#08bdba}
/* Transcontinental countries get BOTH colours rather than the generator
   silently picking a side — Russia, Turkey, Egypt, Indonesia and friends. */
.rc-cover.split::before{background:linear-gradient(180deg,
   var(--accent) 0 50%, var(--accent2) 50% 100%)}
.rc-info{display:flex;flex-direction:column;gap:5px;align-items:center}
.rc-info .who{font-family:var(--mono);font-size:11px;letter-spacing:.09em;
  text-transform:uppercase;color:var(--g50)}
.rc-info .nm{font-size:16px;font-weight:600}
/* SUBDIVISIONS, AS A TAG. The one fact that changes what the buyer receives,
   given the weight of a label rather than the weight of a footnote. Draft
   layers are outlined instead of filled — they ship inside the dossier and are
   not part of its price, and the difference should be visible at a glance
   rather than only in the modal. */
.rc-pill{display:inline-flex;align-items:center;font-family:var(--mono);
  font-size:10.5px;letter-spacing:.05em;text-transform:uppercase;
  color:var(--teal40);background:color-mix(in srgb,var(--teal40) 12%,transparent);
  border:1px solid color-mix(in srgb,var(--teal40) 32%,transparent);
  border-radius:999px;padding:3px 9px;line-height:1.4}
.rc-pill.draft{color:var(--g40);background:none;border-color:var(--g70);
  border-style:dashed}
.rc-info .pr{font-family:var(--mono);font-size:13.5px;color:var(--teal40)}
@media(prefers-reduced-motion:reduce){
  .rc-cover,.rc-sheen{transition-duration:.01ms!important}}

.caret{width:9px;height:9px;border-right:2px solid var(--g50);
  border-bottom:2px solid var(--g50);transform:rotate(-45deg);transition:transform .18s;
  flex:0 0 auto;margin-right:2px}
details[open] > summary .caret{transform:rotate(45deg)}

.toc{list-style:none;margin:0;padding:0}
.toc li{border-bottom:1px solid var(--g80)}
/* One row shape whether the item expands or not, so the numbered column
   stays a straight line down the manifest. */
.mi > summary, .mi-flat{display:grid;grid-template-columns:26px 1fr auto 14px;
  gap:12px;padding:10px 0;align-items:baseline}
.mi > summary{cursor:pointer;list-style:none}
.mi > summary::-webkit-details-marker{display:none}
.mi > summary:focus-visible{outline:2px solid var(--teal40);outline-offset:2px}
.mi > summary:hover .t{color:var(--g10)}
.mi > summary .caret{margin:0;align-self:center}
.toc .n{font-family:var(--mono);font-size:12px;color:var(--g50)}
.toc .t{font-size:15.5px}
.toc .t small{display:block;color:var(--g40);font-size:13.5px;margin-top:3px}
.toc .c{font-family:var(--mono);font-size:12.5px;color:var(--g50);white-space:nowrap}
/* Pills, not a table: the US has 54 subdivisions and India 41. They wrap,
   they stay scannable, and they never trap a scroll inside a dialog. */
.pills{display:flex;flex-wrap:wrap;gap:6px;padding:2px 0 14px 38px}
.pl{font-family:var(--mono);font-size:12px;color:var(--g30);
  border:1px solid var(--edge);border-radius:2px;padding:4px 8px;
  display:inline-flex;align-items:baseline;gap:6px}
.pl b{color:var(--teal40);font-weight:400}
@media(max-width:520px){.pills{padding-left:0}}

/* ── Country page: dossier block ─────────────────────────────────────────
   The Reports dialog, unwrapped onto the page. Same manifest markup, but no
   cover button and no dialog — on a country page the contents ARE the page,
   so a cover that opens a copy of what you are reading is a dead control. */
.cd-wrap{display:grid;grid-template-columns:192px 1fr;gap:34px;align-items:start;
  margin-top:24px}
.cd-buy{display:flex;gap:10px;flex-wrap:wrap;margin-top:22px}
.cd-buy .btn{flex:1;justify-content:center;min-width:210px}
@media(max-width:680px){.cd-wrap{grid-template-columns:1fr}
  .cd-wrap .rc-cover{margin:0 auto}}

/* The free-account offer at the foot of a country page. Bordered rather than
   filled: a solid teal panel would outrank the dossier contents above it, and
   the contents are what the reader came for. */
.cp-free{margin:44px 0 0;padding:28px;border:1px solid var(--edge);
  border-left:3px solid var(--teal40);border-radius:4px;background:var(--g90)}
.cp-free .lede{max-width:52ch}

/* Country-page header: facts left, cover right. The cover is a link to the
   dossier section, so it is sized down and given a real hover/focus state —
   an image that scrolls the page on click must look clickable. */
.cp-head{display:grid;grid-template-columns:1fr 168px;gap:36px;align-items:start}
.cp-thumb{display:block;text-decoration:none;border-radius:8px;
  transition:transform .25s cubic-bezier(.2,.8,.2,1)}
.cp-thumb .rc-cover{max-width:168px}
.cp-thumb:hover{transform:translateY(-4px)}
.cp-thumb:hover .rc-sheen{opacity:1;transform:translateX(28%)}
.cp-thumb:focus-visible{outline:2px solid var(--teal40);outline-offset:6px}
@media(max-width:740px){
  /* Below this the cover competes with the h1 for the first screen, and the
     h1 is what tells you where you are. It drops out; the dossier section
     still carries one. */
  .cp-head{grid-template-columns:1fr}
  .cp-thumb{display:none}
}
@media(prefers-reduced-motion:reduce){.cp-thumb{transition-duration:.01ms}}

/* ── The provenance diagram ──────────────────────────────────────────────
   THE ONE SECTION THAT BREAKS THE PATTERN. Every other block on the
   homepage is headline → paragraph → cards → button, so by the fourth one
   the rhythm is predictable and everything reads as equally important.
   This is full-bleed, has no cards and no button, and states the whole
   argument in one picture: authorities in, one engine, every date labelled
   by how well it is evidenced, four ways out.

   Built from type and rules rather than an image: it stays sharp at any
   size, reflows on a phone, is readable by a screen reader, costs no
   request, and cannot go stale the way an exported PNG does. */
.flow{background:var(--g90);border-top:1px solid var(--line);
  border-bottom:1px solid var(--line);padding:64px 0}
.flow-grid{display:grid;grid-template-columns:1fr auto 1fr auto 1fr;gap:26px;
  align-items:center;margin-top:34px}
.flow-col h4{font-family:var(--mono);font-size:11px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--g50);font-weight:400;margin:0 0 14px}
.flow-item{border-left:2px solid var(--g70);padding:7px 0 7px 13px;
  margin-bottom:9px;font-size:14.5px;color:var(--g30);line-height:1.4}
.flow-item:last-child{margin-bottom:0}
.flow-item b{display:block;color:var(--g10);font-weight:500}
.flow-item small{color:var(--g50);font-size:12.5px}
/* The engine is the only filled box: it is the thing being sold. */
.flow-engine{background:var(--g100);border:1px solid var(--teal40);
  border-radius:4px;padding:20px 18px;text-align:center}
.flow-engine b{display:block;font-size:16px;color:var(--g10);margin-bottom:6px}
.flow-engine span{font-family:var(--mono);font-size:11.5px;color:var(--teal40);
  letter-spacing:.09em}
.flow-arrow{font-family:var(--mono);color:var(--g50);font-size:19px;
  text-align:center;user-select:none}
/* Assurance keeps the achromatic ramp it uses everywhere else, so the
   diagram teaches the same vocabulary the rest of the site uses. */
.flow-a{display:flex;align-items:center;gap:9px;margin-bottom:9px;font-size:14px}
.flow-a i{width:9px;height:9px;border-radius:2px;flex:0 0 auto}
.flow-a .v{background:#ffffff} .flow-a .c{background:#a7b4c2}
.flow-a .k{background:#5b6470}
.flow-a small{color:var(--g50);font-size:12.5px;margin-left:auto;
  font-family:var(--mono)}
@media(max-width:900px){
  .flow-grid{grid-template-columns:1fr;gap:8px}
  .flow-arrow{transform:rotate(90deg);padding:6px 0}
}

/* ── Filter controls: search box + chips ─────────────────────────────────
   THESE WERE COLLATERAL DAMAGE. Extracting the cover/manifest CSS out of
   reports.html cut from `.toc` to the end of that <style> block, and
   `.chip`, `.chips`, `.controls` and `.ctl-lb` happened to sit after it.
   They were never moved anywhere, so the band and bloc filters on Reports
   have been rendering as unstyled <button> elements ever since — no border,
   no monospace, no pressed state, and the count running straight into the
   price: "Standard · €49129".

   The filtering logic was never broken; only the evidence that it existed.
   Living in shell.css now because Coverage carries an identical local copy —
   two files, one control, which is how they drift. */
.controls{display:flex;gap:14px;flex-wrap:wrap;align-items:center;margin-bottom:6px}
.controls input{flex:0 0 auto;width:min(320px,100%);background:var(--g90);
  border:1px solid var(--edge);color:var(--g10);font:inherit;font-size:15px;
  padding:10px 12px;border-radius:2px}
.controls input:focus-visible{outline:2px solid var(--teal40);outline-offset:1px}
.ctl-lb{font-family:var(--mono);font-size:12px;letter-spacing:.09em;
  text-transform:uppercase;color:var(--g40)}
.chips{display:flex;gap:7px;flex-wrap:wrap}
.chip{font-family:var(--mono);font-size:12px;letter-spacing:.04em;
  background:transparent;color:var(--g30);border:1px solid var(--edge);
  border-radius:2px;padding:6px 11px;cursor:pointer}
.chip:hover{border-color:var(--g50);color:var(--g10)}
.chip[aria-pressed=true]{background:var(--teal40);color:#001f1e;border-color:var(--teal40)}
/* The separator that was missing: the count is a distinct fact from the
   price beside it, and without spacing they read as one number. */
.chip .n{opacity:.7;margin-left:6px}

/* One grid cell per dossier: the cover button and its permalink are a pair,
   not two neighbours. Without this wrapper each dossier took two cells of
   .rgrid and the link rendered beside its own cover. */
.rc-wrap{display:flex;flex-direction:column;align-items:center}
.rc-wrap .rcard{width:100%}
.rc-permalink{display:block;text-align:center;font-size:13px;padding:9px 2px 0;
  color:var(--dim);text-decoration:none;border-bottom:1px solid transparent}
.rc-permalink:hover{color:var(--teal40);border-bottom-color:currentColor}

/* Pricing header: title left, currency switch right, on one line. The switch
   was previously two blocks above the first price, which is far enough that
   changing it appeared to do nothing. */
.price-head{display:flex;align-items:baseline;gap:16px;flex-wrap:wrap;
  margin:22px 0 12px}
.price-head .curnote{margin:0}

/* The community-access note. Quiet on purpose: a reader comparing prices
   should not meet it, and a reader looking for it should find it. */
.foot-give{border-top:1px solid var(--g80);margin:26px 0 0;padding-top:18px;
  font-size:14.5px;color:var(--g50);max-width:78ch;line-height:1.6}
.foot-give b{color:var(--g30);font-weight:500}
.foot-give a{color:var(--teal40);text-decoration:none;
  border-bottom:1px solid transparent;margin-left:4px}
.foot-give a:hover{border-bottom-color:currentColor}

/* ── Signup: two paths ───────────────────────────────────────────────────
   Free access is an application we read; a paid plan is a purchase that
   starts immediately. One button served both badly — it asked a
   purchase-ready buyer to write an essay. */
.path-pick{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:28px}
.path-pick [role=tab]{text-align:left;background:var(--g90);border:1px solid var(--g70);
  border-radius:5px;padding:15px 17px;cursor:pointer;font:inherit;color:var(--g30);
  display:flex;flex-direction:column;gap:5px}
.path-pick [role=tab] b{color:var(--g10);font-weight:500;font-size:16px}
.path-pick [role=tab] span{font-size:13.5px;color:var(--g50);line-height:1.45}
.path-pick [role=tab]:hover{border-color:var(--g50)}
/* The selected path is marked by a teal edge and a lift in contrast, not by
   colour alone — the same reason the assurance bar uses a lightness ramp. */
.path-pick [role=tab][aria-selected=true]{border-color:var(--teal40);
  background:var(--g100);box-shadow:inset 3px 0 0 var(--teal40)}
.path-pick [role=tab][aria-selected=true] span{color:var(--g40)}
@media(max-width:560px){.path-pick{grid-template-columns:1fr}}

.plan-pick{display:grid;gap:10px;margin-top:24px;
  grid-template-columns:repeat(auto-fit,minmax(190px,1fr))}
.plan-opt{text-align:left;background:var(--g90);border:1px solid var(--g70);
  border-radius:5px;padding:15px 16px;cursor:pointer;font:inherit;
  display:flex;flex-direction:column;gap:5px}
.plan-opt .pn{color:var(--g10);font-size:16px;font-weight:500}
.plan-opt .pp{font-family:var(--mono);font-size:15px;color:var(--teal40)}
.plan-opt .ps{font-size:13px;color:var(--g50);line-height:1.4}
.plan-opt:hover{border-color:var(--g50)}
.plan-opt[aria-pressed=true]{border-color:var(--teal40);background:var(--g100);
  box-shadow:inset 3px 0 0 var(--teal40)}

/* ── live release panel, fed by api.1752.io/version.json ────────────────
   THIS SITE'S GREY SCALE RUNS DARK-FIRST: --g90 is #161616, a near-black
   SURFACE, and --g40 is #a8a8a8, a mid grey TEXT. I read the numbers as a
   light-theme scale, wrote background:var(--g98,#fafafa) — a variable that does
   not exist here — and shipped a white card onto a #0b0b0b page with #f4f4f4
   text on it. The version number was white on white and the panel was, in
   practice, blank.

   No fallback values below. If a variable is missing the panel should look
   wrong in a way I notice, not silently resolve to a colour from another
   theme. */
.live-rel{border:1px solid var(--g70);border-radius:6px;padding:14px 16px;
  margin:18px 0 8px;background:var(--g90)}
.live-rel[hidden]{display:none}
.lr-head{display:flex;align-items:baseline;gap:10px;margin-bottom:10px}
.lr-ver{font-weight:600;font-size:14px;color:var(--teal40,#3ddbd9)}
.lr-date{font-size:12px;color:var(--g40)}
.lr-bars{display:flex;height:8px;border-radius:4px;overflow:hidden;
  background:var(--g70);margin-bottom:6px}
.lr-bars span{display:block;height:100%}
.lr-bars .v{background:var(--green40)}
.lr-bars .c{background:var(--yellow30)}
.lr-bars .p{background:var(--g70)}
.lr-legend{font-size:11px;color:var(--g40);font-family:var(--mono);
  margin:0 0 10px;display:flex;gap:14px;flex-wrap:wrap}
.lr-notes{list-style:none;margin:0;padding:0;font-size:13px;line-height:1.5}
.lr-notes li{display:flex;gap:8px;padding:2px 0}
.lr-notes .k{font-family:var(--mono);font-size:11px;color:var(--g40);
  min-width:44px;padding-top:2px;text-transform:lowercase}
@media (max-width:640px){.lr-notes .k{min-width:38px}}


/* Stat tiles are links now. They must not look like body links — the number is
   the thing, the underline would fight it. */
a.stat{text-decoration:none;color:inherit;display:block;border-radius:6px;
  transition:background .15s ease}
a.stat:hover,a.stat:focus-visible{background:var(--g90)}
a.stat:focus-visible{outline:2px solid var(--teal40,#3ddbd9);outline-offset:2px}
a.stat .k{text-decoration:underline;text-decoration-color:var(--g70);
  text-underline-offset:3px}

/* ── rotating-headline control ───────────────────────────────────────────────
   Sixteen dashes, and the active one IS the progress bar: it fills left to
   right over its own turn. A separate bar plus a row of dots would be two
   controls reporting the same fact, and the reader would have to work out that
   they were related. */
.rot-ctl{display:flex;align-items:center;gap:12px;margin:0 0 18px}
.rot-dots{display:flex;gap:5px;flex-wrap:wrap;align-items:center}
.rot-dot{appearance:none;border:0;padding:6px 0;background:none;cursor:pointer;
  width:22px;line-height:0;border-radius:2px}
.rot-dot i{display:block;height:2px;width:100%;background:var(--g70);
  border-radius:2px;position:relative;overflow:hidden}
/* The fill is a pseudo-element so the track stays visible underneath it. */
.rot-dot i::after{content:"";position:absolute;inset:0;
  width:var(--fill,0%);transition:width var(--dur,0ms) linear;
  background:var(--teal40,#3ddbd9);border-radius:2px}
.rot-dot.on i{background:var(--g70)}
.rot-dot.done i{background:var(--g40)}
.rot-dot:hover i,.rot-dot:focus-visible i{background:var(--g40)}
.rot-dot:focus-visible{outline:2px solid var(--teal40,#3ddbd9);outline-offset:3px}

/* Play/pause. A triangle and two bars drawn in CSS — an icon font or an SVG
   sprite for two shapes is more machinery than the shapes are worth. */
.rot-pause{appearance:none;border:1px solid var(--g70);background:none;
  width:22px;height:22px;border-radius:50%;cursor:pointer;flex:none;
  display:flex;align-items:center;justify-content:center;padding:0}
.rot-pause::before{content:"";width:7px;height:8px;
  border-left:2px solid var(--g40);border-right:2px solid var(--g40)}
.rot-ctl.paused .rot-pause::before{width:0;height:0;border:0;
  border-left:8px solid var(--g40);border-top:5px solid transparent;
  border-bottom:5px solid transparent;margin-left:2px}
.rot-pause:hover{border-color:var(--g40)}
.rot-pause:hover::before{border-color:var(--fg,#f4f4f4)}
.rot-pause:focus-visible{outline:2px solid var(--teal40,#3ddbd9);outline-offset:2px}

/* On a phone sixteen dashes wrap to three rows and read as a rash. Halve them
   and drop the gap; the control is a convenience, not the content. */
@media (max-width:560px){
  .rot-dot{width:14px}
  .rot-dots{gap:4px}
}

/* ── second sticky layer: section nav ────────────────────────────────────────
   Sits under the masthead and above the table headers. Three sticky layers only
   work if each one knows the height of the one above it, so nothing here is a
   guessed pixel: --nav-h is measured from the masthead, --secnav-h from this
   bar, and --stick-h is their sum, used by both the table headers and every
   section's scroll-margin. */
.secnav{position:sticky;top:var(--nav-h,69px);z-index:30;
  background:rgba(11,11,11,.94);backdrop-filter:blur(8px);
  border-bottom:1px solid var(--g80)}
.secnav-in{display:flex;gap:22px;padding:11px 24px;overflow-x:auto;
  scrollbar-width:none}
.secnav-in::-webkit-scrollbar{display:none}
.secnav a{color:var(--g30);text-decoration:none;font-size:14px;
  white-space:nowrap;padding-bottom:3px}
.secnav a:hover{color:var(--g10)}
/* Same underline as the masthead's current page, because it is the same idea
   one level down — a reader who has learned what that mark means upstairs
   should not have to learn a second vocabulary here. */
.secnav a[aria-current=true]{color:var(--g10);box-shadow:inset 0 -2px 0 var(--teal40)}
.secnav a:focus-visible{outline:2px solid var(--teal40);outline-offset:3px}

/* Table headers clear BOTH bars. --stick-h is only ever set by sectionNav(),
   so on pages without a section bar this rule never fires and the headers keep
   offsetting by --nav-h alone. No :has(), which would make the whole block a
   no-op in a browser that does not support it. */
.scroller table thead th{top:var(--stick-h,var(--nav-h,56px))}

/* ── rotating headline: the transition itself ────────────────────────────────
   A full second, half each way, driven by --fade from the script so the timing
   lives in one place. The old 420ms read as a cut rather than a change: at this
   type size the eye needs long enough to see one sentence BECOME another.

   Only opacity moves for a reduced-motion reader (.rot-still). The 4px rise is
   the part that setting is actually about; a slow crossfade is not, and
   removing it made the swap look broken while leaving the dashes inert. */
.h-promise.rot-anim{transition:opacity var(--fade,500ms) ease-in-out,
  transform var(--fade,500ms) ease-in-out;will-change:opacity,transform}
.h-promise.rot-anim.out{opacity:0;transform:translateY(-4px)}
.h-promise.rot-still{transition:opacity var(--fade,500ms) ease-in-out}
.h-promise.rot-still.out{opacity:0;transform:none}

/* ── pricing: the custom-package note ────────────────────────────────────────
   Deliberately not a card. A sixth box in a row of five reads as a sixth plan,
   and this is the opposite of a plan — it is what to do when none of them fit. */
.custom{border-left:2px solid var(--teal40);background:var(--g90);
  padding:18px 22px;margin:24px 0 0;max-width:74ch}
.custom h4{margin:0 0 10px;font-size:16px}
.custom p{margin:0 0 12px;font-size:15px;line-height:1.6;color:var(--g30)}
.custom p:last-of-type{margin-bottom:14px}

/* ── one engine, two products ────────────────────────────────────────────────
   Sits at the top of both product pages. The current product is stated rather
   than linked — a link back to the page you are on is a small betrayal of
   attention — and the other is a real destination. */
.ps{margin:0 0 26px}
.ps-note{font-size:15px;color:var(--g30);margin:0 0 12px;max-width:74ch}
.ps-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:12px}
.ps-card{display:block;border:1px solid var(--g70);border-radius:6px;
  padding:14px 16px;text-decoration:none;color:inherit;background:var(--g90)}
.ps-card.on{border-color:var(--teal40);background:transparent}
.ps-card:not(.on):hover{border-color:var(--g40)}
.ps-card .ps-k{display:block;font-family:var(--mono);font-size:11px;
  text-transform:uppercase;letter-spacing:.06em;color:var(--g40);margin-bottom:6px}
.ps-card b{display:block;font-size:16px;margin-bottom:3px}
.ps-card span:last-child{font-size:14px;color:var(--g30)}
.ps-card:not(.on) b::after{content:" →";color:var(--teal40)}

/* ── tools: the calculators ──────────────────────────────────────────────────
   Two pages share this because they are the same tool asked in two directions,
   and a second copy of the stylesheet is a second thing to forget to change.
   The shape is: controls in a band, then one loud answer, then the working —
   because the answer is what the visitor came for and the working is what
   makes it worth trusting. */
.tk{padding:34px 24px 0;max-width:940px}
.tk h1{font-size:32px;margin:0 0 10px}
.tk-form{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));
  gap:14px 18px;border:1px solid var(--g70);border-radius:8px;background:var(--g90);
  padding:18px 20px;margin:22px 0 0}
.fld{display:flex;flex-direction:column;gap:5px;min-width:0}
.fld label{font-family:var(--mono);font-size:10.5px;text-transform:uppercase;
  letter-spacing:.07em;color:var(--g40)}
.fld input,.fld select{background:var(--g100);border:1px solid var(--g70);
  color:var(--g10);font:inherit;font-size:14.5px;padding:8px 10px;border-radius:3px;
  width:100%;min-width:0}
.fld input:focus,.fld select:focus{outline:2px solid var(--teal40);outline-offset:1px}
.fld .hint{font-size:11.5px;color:var(--g50);line-height:1.4}
/* The working week is a control and not an assumption, so it is drawn as seven
   things you can press rather than hidden in a select someone will not open. */
/* SCOPED TO THE FORM, and the reason is a bug worth remembering.
   This was a bare `.wk`, meaning "the working-week toggle row". But `wk` also
   means "weekend" on the Operating Calendar's day grid — and `grid-column:1/-1`
   turned every weekend cell into a full-width flex row, folding the calendar
   into 202 broken lines. Two stylesheets' worth of meaning on one two-letter
   class, in a file both pages load. Scope, or rename; never a bare short class
   in a shared sheet. */
.tk-form .wk{grid-column:1/-1;display:flex;flex-wrap:wrap;gap:6px;align-items:center}
.tk-form .wk button{font-family:var(--mono);font-size:12px;padding:5px 9px;border-radius:3px;
  border:1px solid var(--g70);background:none;color:var(--g40);cursor:pointer}
.tk-form .wk button[aria-pressed=true]{border-color:var(--teal40);color:var(--teal40)}
.tk-form .wk .sep{width:1px;height:20px;background:var(--g70);margin:0 6px}
.tk-form .wk .pre{font-size:11.5px;color:var(--g50);text-transform:none;letter-spacing:0}
.tk-caveat{font-size:12.5px;color:var(--g50);line-height:1.55;margin:10px 0 0;
  max-width:78ch}
/* The answer. One number, said once, in the size that says "this is it". */
.ansbox{border:1px solid var(--g70);border-left:2px solid var(--teal40);
  border-radius:6px;background:var(--g90);padding:20px 22px;margin:20px 0 0}
.ansbox .big{font-size:38px;line-height:1.05;margin:0 0 6px}
.ansbox .sub{font-size:15.5px;color:var(--g20);line-height:1.6;max-width:70ch}
.ansbox .sub b{color:var(--fg,#f4f4f4)}
.ansbox.bad{border-left-color:var(--yellow30)}
/* The working: every day the count refused, and why. This is the part that
   distinguishes an answer from a number. */
.dl{border:1px solid var(--g70);border-radius:8px;margin:20px 0 0;overflow:hidden}
.dl h3{margin:0;font-size:15px;padding:13px 16px;background:var(--g90);
  border-bottom:1px solid var(--g80)}
.dl table{width:100%;border-collapse:collapse;font-size:14px}
.dl td{padding:8px 16px;border-bottom:1px solid var(--g90);color:var(--g20)}
.dl tr:last-child td{border-bottom:0}
.dl td.d{font-family:var(--mono);white-space:nowrap;width:1%;color:var(--g30)}
.dl td.a{text-align:right;width:1%;white-space:nowrap}
.dl .none{padding:14px 16px;color:var(--g40);font-size:14px}
/* The hub. Built things first, honestly labelled; planned things after, and
   also honestly labelled — a coming-soon card that looks like a live one is
   just a broken link with better manners. */
.tk-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));
  gap:14px;margin:22px 0 0}
.tk-card{display:block;border:1px solid var(--g70);border-radius:6px;padding:16px 18px;
  background:var(--g90);text-decoration:none;color:inherit}
.tk-card:hover{border-color:var(--teal40)}
.tk-card b{display:block;font-size:16px;margin:0 0 5px}
.tk-card b::after{content:" →";color:var(--teal40)}
.tk-card span{font-size:14px;color:var(--g30);line-height:1.5}
.tk-card.soon{background:none;border-style:dashed;cursor:default}
.tk-card.soon:hover{border-color:var(--g70)}
.tk-card.soon b::after{content:""}

/* ── homepage: the three products ────────────────────────────────────────────
   A buyer arriving cold has one question before any other — "what do you sell
   and roughly what does it cost" — and the homepage answered neither. These
   cards answer both in the first screen after the hero. The price is an
   ENTRY POINT, not a table: enough to self-qualify, not enough to replace the
   pricing page. */
.prod{display:grid;grid-template-columns:repeat(auto-fit,minmax(272px,1fr));
  gap:16px;margin:26px 0 0}
.prod-c{display:flex;flex-direction:column;border:1px solid var(--g70);
  border-radius:8px;background:var(--g90);padding:22px 24px}
.prod-c .who{font-family:var(--mono);font-size:10.5px;text-transform:uppercase;
  letter-spacing:.08em;color:var(--teal40);margin:0 0 10px}
.prod-c h3{margin:0 0 8px;font-size:20px}
.prod-c p{font-size:15px;line-height:1.6;color:var(--g30);margin:0 0 16px}
.prod-c .from{margin-top:auto;padding-top:16px;border-top:1px solid var(--g80);
  font-size:14px;color:var(--g30)}
.prod-c .from b{color:var(--fg,#f4f4f4);font-size:19px}
.prod-c .from .per{color:var(--g50)}
.prod-c .act{margin:14px 0 0}
/* The one that is not finished says so on its face rather than in small print
   at the bottom of the page. */
.prod-c.soon{border-style:dashed;background:none}
.prod-c.soon .who{color:var(--g50)}

/* ── homepage: free tools ────────────────────────────────────────────────────
   The strongest thing we can offer a stranger is a correct answer to a real
   question, before any conversation about money. Drawn tighter and flatter
   than the product cards because it is a doorway, not a purchase. */
.tools-strip{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));
  gap:12px;margin:22px 0 0}
.tool-l{display:block;border:1px solid var(--g70);border-radius:6px;
  padding:15px 17px;text-decoration:none;color:inherit;background:var(--g90)}
.tool-l:hover{border-color:var(--teal40)}
.tool-l b{display:block;font-size:15.5px;margin-bottom:4px}
.tool-l b::after{content:" →";color:var(--teal40)}
.tool-l span{font-size:13.5px;color:var(--g30);line-height:1.5}

/* ── the shared country picker ───────────────────────────────────────────────
   Replaces a <datalist>, which could search but could not show a flag, a code,
   or which row the keyboard was on. */
.cpick{position:relative}
.cpick input{width:100%;background:var(--g100);border:1px solid var(--g70);
  color:var(--g10);font:inherit;font-size:14.5px;padding:8px 10px;border-radius:3px}
.cpick input:focus{outline:2px solid var(--teal40);outline-offset:1px}
.cpick ul{position:absolute;z-index:40;left:0;right:0;top:calc(100% + 4px);
  margin:0;padding:4px;list-style:none;max-height:290px;overflow-y:auto;
  background:var(--g95,#111);border:1px solid var(--g70);border-radius:6px;
  box-shadow:0 12px 28px rgba(0,0,0,.5)}
.cpick li{display:flex;align-items:center;gap:9px;padding:7px 9px;
  border-radius:3px;cursor:pointer;font-size:14px;color:var(--g20)}
/* Hover AND keyboard highlight share one look, so the two never disagree about
   which row Enter will take. */
.cpick li:hover,.cpick li.on{background:var(--g80)}
.cpick li[aria-selected=true] .nm{color:var(--teal40)}
.cpick li .fl{font-size:17px;line-height:1;width:22px;flex:none;text-align:center}
.cpick li .nm{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.cpick li .cd{font-family:var(--mono);font-size:11px;color:var(--g50);flex:none}
.cpick li.none{color:var(--g50);cursor:default;font-size:13.5px}
.cpick li.none:hover{background:none}
/* Scrollbar hidden here too — the list is short and the track is noise. */
.cpick ul{scrollbar-width:none}
.cpick ul::-webkit-scrollbar{width:0}

/* ── date presets ────────────────────────────────────────────────────────────
   A native date input is a fine way to pick ONE arbitrary day and a poor way
   to express "this quarter". These are the ranges people actually ask for. */
.dpre{display:flex;flex-wrap:wrap;gap:6px;margin-top:6px}
.dpre button{font-family:var(--mono);font-size:11.5px;padding:4px 9px;
  border:1px solid var(--g70);background:none;color:var(--g40);
  border-radius:3px;cursor:pointer}
.dpre button:hover{border-color:var(--g50);color:var(--g20)}
.dpre button[aria-pressed=true]{border-color:var(--teal40);color:var(--teal40)}

/* ── docs: two columns and a table of contents ──────────────────────────
   The rail is narrow on purpose. It is an index, not a second column of
   reading — at much over 240px it starts competing with the prose for the
   eye, and the prose is the thing. */
.docs-shell{display:grid;grid-template-columns:minmax(190px,17%) minmax(0,1fr);
  gap:48px;align-items:start}
.docs-body{min-width:0;padding-bottom:60px}
.docs-body h2{scroll-margin-top:calc(var(--nav-h,104px) + 20px)}
.docs-body h3{scroll-margin-top:calc(var(--nav-h,104px) + 20px)}

.docs-toc{position:sticky;top:calc(var(--nav-h,104px) + 22px);
  max-height:calc(100vh - var(--nav-h,104px) - 44px);overflow-y:auto;
  padding:2px 0 24px;scrollbar-width:thin}
.docs-toc::-webkit-scrollbar{width:4px}
.docs-toc::-webkit-scrollbar-thumb{background:var(--g70)}
.toc-t{font-family:var(--mono);font-size:10.5px;letter-spacing:.13em;
  text-transform:uppercase;color:var(--g50);margin-bottom:10px}
.toc-page{margin-bottom:2px}
.toc-p{display:block;padding:5px 0;font-size:14px;color:var(--g40);
  text-decoration:none;line-height:1.4}
.toc-p:hover{color:var(--g10)}
.toc-page.on > .toc-p{color:var(--g10);font-weight:600}

.toc-secs,.toc-subs{list-style:none;margin:2px 0 10px;padding:0}
/* A hairline the active marker sits on, so the highlight reads as a position
   in a list rather than a floating box. */
.toc-secs{border-left:1px solid var(--g80);padding-left:0}
.toc-secs > li > a{display:block;padding:5px 0 5px 12px;margin-left:-1px;
  border-left:2px solid transparent;font-size:13.5px;color:var(--g50);
  text-decoration:none;line-height:1.45}
.toc-secs > li > a:hover{color:var(--g30)}
.toc-secs > li > a.on{color:var(--g10);border-left-color:var(--teal40)}

/* Third level appears only inside the section you are in. The API reference
   has sixteen endpoints across eight sections; all of them at once is a rail
   longer than the page it indexes. */
.toc-subs{display:none;margin:0 0 6px}
.toc-secs > li.open .toc-subs{display:block}
.toc-subs a{display:block;padding:4px 0 4px 26px;font-size:12.5px;
  color:var(--g50);text-decoration:none;font-family:var(--mono);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.toc-subs a:hover{color:var(--g30)}
.toc-subs a.on{color:var(--teal40)}

@media (max-width:900px){
  /* No rail. A sticky sidebar on a phone is a sticky sidebar covering the
     text — and the page is already one column of headings you can scroll. */
  .docs-shell{grid-template-columns:1fr;gap:0}
  .docs-toc{display:none}
}

/* ── the standing accuracy note ─────────────────────────────────────────── */
.foot-note{max-width:78ch;margin:26px 0 18px;padding-top:18px;
  border-top:1px solid var(--g80);font-size:13px;line-height:1.6;color:var(--g40)}
.foot-note a{color:var(--g30)}

/* ── megamenu ───────────────────────────────────────────────────────────
   FULL WIDTH, not a dropdown. `.mega` is position:static so the absolutely
   positioned panel resolves against header.site (sticky, therefore a
   containing block) rather than against the one word that triggers it. That
   is what lets the panel's inner .wrap line up with the page grid below it,
   and it is what makes room for a sentence per item instead of four words
   squeezed under a link.

   top:100% is the bottom of the WHOLE header, utility row included, so the
   panel never covers the bar it belongs to. */
.mega{position:static;display:inline-block}
.caret{display:inline-block;width:0;height:0;margin-left:6px;
  vertical-align:middle;border:4px solid transparent;border-top-color:currentColor;
  transform:translateY(2px);opacity:.55}
.mega[data-open=true] .caret{opacity:1}
/* OPAQUE, and no backdrop-filter. The masthead is translucent because it
   floats over content you are still reading; this panel is content you are
   reading, and at a full 1440px wide even a 1.5% alpha let the hero headline
   ghost through it. A surface with text on it is not a scrim. */
.mega-p{position:absolute;left:0;right:0;top:100%;z-index:70;
  background:var(--g100,#0b0b0b);
  border-bottom:1px solid var(--g80);box-shadow:0 22px 44px rgba(0,0,0,.5);
  opacity:0;visibility:hidden;transform:translateY(-6px);
  transition:opacity .14s,transform .14s,visibility .14s}
.mega[data-open=true] .mega-p{opacity:1;visibility:visible;transform:none}
/* padding-block again — see .mast. `padding:28px 0 32px` would zero the 24px
   .wrap contributes, and the panel's first column would sit a full gutter left
   of the wordmark above it, which is exactly the alignment this panel exists
   to get right. */
.mega-in{display:grid;grid-template-columns:minmax(0,1fr) 330px;
  gap:44px;padding-block:28px 32px;align-items:start}
/* Columns are capped rather than stretched. With two groups sharing a 1fr
   track each, they sat a third of the screen apart and the eye had to travel
   between two short lists across empty space. Bounded and packed left, they
   read as one block. */
.mega-cols{display:grid;justify-content:start;
  grid-template-columns:repeat(auto-fit,minmax(190px,235px));gap:14px 40px}
.mega-gt{font-family:var(--mono);font-size:10.5px;letter-spacing:.13em;
  text-transform:uppercase;color:var(--g50);margin-bottom:10px}
.mega-col a{display:block;padding:7px 10px;margin-left:-10px;border-radius:4px;
  text-decoration:none;font-size:15px;color:var(--g30);line-height:1.35}
.mega-col a:hover,.mega-col a:focus-visible{background:var(--g85);color:var(--g10)}

/* The context pane. A blurb long enough to be worth reading needs somewhere
   to be read; putting one under every link would make the panel a wall of
   text and force the eye to scan prose instead of labels. */
.mega-ctx{border-left:1px solid var(--g80);padding-left:26px;min-height:112px}
.mega-ctx-t{font-size:15px;font-weight:600;color:var(--g10);margin-bottom:7px}
.mega-ctx-b{font-size:13.5px;line-height:1.65;color:var(--g40);margin:0}

@media (max-width:1040px){
  /* Below this the context pane is stealing width from the links it
     describes, which is the wrong trade — the labels are the navigation. */
  .mega-in{grid-template-columns:1fr;gap:0}
  .mega-ctx{display:none}
}
/* On a phone there is no hover, and the mobile menu is already a list — so
   the panel stops being a panel and becomes part of it. */
@media (max-width:860px){
  .mega{display:block}
  .caret{display:none}
  .mega-p{position:static;opacity:1;visibility:visible;transform:none;
    box-shadow:none;border:0;background:none;backdrop-filter:none}
  .mega-in{padding:0}
  .mega-cols{display:block}
  .mega-gt{padding:12px 24px 2px;margin:0}
  .mega-col a{padding:11px 24px 11px 36px;margin:0;font-size:15px;border-radius:0}
}

/* ── Country timeline: last · now · next ──────────────────────────────────────
   Three cells answering the three questions someone opens a country page to
   ask, with the middle one being the only live thing on an otherwise static
   site. Styled here rather than inline because the last time markup was
   invented for this page and styled nowhere, `.stat-row` rendered as an
   unspaced list reading "42observances". */
.tl{margin:30px 0 0;border:1px solid var(--g80);border-radius:12px;overflow:hidden}

/* ── THE HERO ─────────────────────────────────────────
   Replaces three equal cells — Last / Now / Next at 19px each in a
   1fr 1fr 1fr grid. Three things of identical weight give the eye no entry
   point, so the one fact a visitor came for had to be hunted for among two
   they did not ask about.

   THE CLARITY IS THE SIZE, NOT THE COLOUR. The first version filled this
   band with solid teal, gov.uk-style. It read as a call to action, because
   on this site teal IS the call to action — it is the Get started button, the
   primary .btn-p, the one colour that means "press me". A block of it around
   a date promises something to click. So the field is a plain panel and the
   accent survives only in the countdown chip, where teal is doing what it
   does everywhere else on the site: marking a figure, not inviting a press. */
.tl-hero{background:var(--g90);padding:34px 24px 30px;text-align:center;
         border-bottom:1px solid var(--g80)}
.tl-lede{margin:0;font-size:15px;font-weight:500;color:var(--g40)}
/* clamp, not a fixed size: 62px is right on a desktop and overflows a 375px
   phone, and "National Day for Truth and Reconciliation" is a long name to
   sit under a date that has already wrapped. */
.tl-date{margin:8px 0 3px;font-size:clamp(36px,7.4vw,62px);font-weight:700;
         line-height:1.02;letter-spacing:-.02em;color:var(--g10)}
.tl-name{margin:0;font-size:clamp(16px,2.2vw,20px);font-weight:600;color:var(--g30)}
/* 6.5:1 on the chip, computed. The chip is the only teal left in the band. */
.tl-away{display:inline-block;margin:15px 0 0;padding:5px 12px;border-radius:999px;
         background:var(--g80);color:var(--teal40);font-size:12.5px;font-weight:600;
         letter-spacing:.04em}

/* ── THE DEMOTED STRIP ─────────────────────────────────
   Everything that used to compete with the date: the clock, whether today is
   a working day, and the last observance. Still on the page, no longer
   shouting. One line on a desktop, wrapping on a phone. */
.tl-strip{display:flex;flex-wrap:wrap;gap:6px 20px;align-items:baseline;
          padding:13px 20px;font-size:13.5px;color:var(--g40)}
.tl-s{display:inline-flex;gap:6px;align-items:baseline}
.tl-s + .tl-s::before{content:"\00b7";margin-right:14px;color:var(--g50)}
.tl-strip b{color:var(--g10);font-weight:600;font-variant-numeric:tabular-nums;
            font-family:ui-monospace,SFMono-Regular,Menlo,monospace}
/* The last observance is the least useful of the three and goes first when
   there is no room for it. */
.tl-last{color:var(--g50)}
@media (max-width:600px){
  .tl-hero{padding:26px 18px 24px}
  .tl-s + .tl-s::before{content:none}
  .tl-strip{gap:4px 0;flex-direction:column}
}
.tl-asof{margin:0;padding:11px 20px;border-top:1px solid var(--g80);
         background:var(--g95,rgba(0,0,0,.02));font-size:12.5px;color:var(--g50)}
@media (max-width:600px){
  .tl-hero{padding:26px 18px 24px}
  .tl-s + .tl-s::before{content:none}
  .tl-strip{gap:4px 0;flex-direction:column}
}
}

/* ── Country hub ──────────────────────────────────────────────────────────── */
.hub-find{margin:26px 0 0}
.hub-find input{width:100%;max-width:420px;padding:11px 14px;border:1px solid var(--g80);
  border-radius:9px;background:transparent;color:var(--g10);font:inherit;font-size:15px}
.hub-list{list-style:none;margin:14px 0 0;padding:0;
  display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:2px 18px}
.hub-list li{display:flex;justify-content:space-between;align-items:baseline;gap:10px;
  padding:7px 0;border-bottom:1px solid var(--g90,rgba(255,255,255,.05))}
.hub-list a{text-decoration:none;color:var(--g10)}
.hub-list a:hover{color:var(--teal40)}
/* The count is context, not content — it must not compete with the name. */
.hub-n{font-size:12px;color:var(--g50);font-variant-numeric:tabular-nums}
/* Secondary text inside a heading — a count that gives context without
   competing with the name beside it. Was used in markup and defined nowhere. */
.muted{color:var(--g50);font-weight:400;font-size:.62em;letter-spacing:.01em}

/* ── Annual calendar + subdivision tables ─────────────────────────────────── */
.cal-tbl{width:100%;border-collapse:collapse;margin-top:14px;font-size:15px}
.cal-tbl th{text-align:left;font-size:11px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--g50);font-weight:500;padding:0 12px 9px 0;border-bottom:1px solid var(--g80)}
.cal-tbl td{padding:10px 12px 10px 0;border-bottom:1px solid var(--g90,rgba(255,255,255,.05));
  vertical-align:baseline}
.cal-tbl tr:last-child td{border-bottom:0}
.cal-tbl .ad{white-space:nowrap;font-variant-numeric:tabular-nums;color:var(--g30)}
.muted-row{color:var(--g50)}

/* ── THE TABLE MUST FIT THE PHONE ─────────────────────────────────────────
   Measured 2026-08-22: at 375px this table was 560px wide inside a <section>
   with overflow-x:visible, so the whole DOCUMENT slid sideways and the columns
   pushed off the right edge were Observance and Evidence — the holiday's name
   and the reason to believe the date. On every one of the 241 jurisdiction
   pages, which is where most readers arrive.

   The width was not the layout's doing. Three separate nowrap rules set a
   min-content floor no container could talk it out of: the date (.ad), the
   assurance chip (.lv) and the "expected" chip (.ann). Auto table layout then
   honoured that floor exactly as it is supposed to.

   So the nowraps lift here rather than the table being rebuilt. It stays a
   real <table> — display:block on rows and cells would drop the implicit row
   and cell roles and take the column associations away from a screen reader,
   which trades a visual bug for an invisible one.

   700px rather than 640: the four-column long-weekends table runs out of room
   before the three-column ones do, and its last column is the bridge-day
   advice, which is the most useful thing on the page. */
@media (max-width:700px){
  .cal-tbl{font-size:14.5px}
  .cal-tbl th,.cal-tbl td{padding-right:9px;overflow-wrap:break-word}
  /* Dates wrap to two lines before they push a column off-screen. Tabular
     figures stay, because a wrapped date is still a date being compared. */
  .cal-tbl .ad{white-space:normal}
  .cal-tbl .lv{white-space:normal}
  /* The bridge-day advice is the most useful cell on the page — "take Fri 16
     Jan" is the whole reason to read the long-weekends table — and it was the
     last column, so it went off the edge first. Let it wrap rather than lose
     it. */
  .cal-tbl .bd{white-space:normal}
  /* The chip drops under the name instead of extending the row past the edge. */
  .cal-tbl .ann{margin-left:0;margin-top:4px}
  .cal-tbl td .ann{display:inline-block}
}

/* Below 380px a FOUR-column table (when · length · because of · leave) has
   roughly 60px a column once padding is taken out, which no amount of wrapping
   rescues. Tighten it rather than hide a column: a 320px phone is a real phone
   and the Leave column is the point of the table. */
@media (max-width:380px){
  .cal-tbl{font-size:13.5px}
  .cal-tbl th,.cal-tbl td{padding-right:6px}
  .cal-tbl .bd{font-size:11px;padding:2px 6px}
  .cal-tbl .lv{font-size:10.5px;padding:2px 6px}
}

/* A wrapper is still worth having for the pathological case — a jurisdiction
   whose observance names are very long in a script that does not break. It
   costs nothing when the table already fits. */
.tbl-fit{overflow-x:auto;-webkit-overflow-scrolling:touch}
/* The assurance level is the reason to read this table rather than the first
   result on the query, so it is a chip and not a word in a corner. */
.lv{display:inline-block;padding:2px 8px;border-radius:20px;font-size:11.5px;
  letter-spacing:.03em;border:1px solid transparent;white-space:nowrap}
.lv-verified{color:var(--teal40);border-color:rgba(80,200,180,.35)}
.lv-corroborated{color:var(--g30);border-color:var(--g70)}
.lv-compiled{color:var(--g50);border-color:var(--g80)}
/* Evidence tiers. The same four steps the dossier marks with a shape: the
   instrument itself is the one colour that stands out; the rest step down in
   contrast, never in alarm. The three rules above stay for the tools that still
   filter on the retired levels. */
.lv-t1{color:var(--teal40);border-color:rgba(80,200,180,.35)}
.lv-t2{color:var(--g30);border-color:var(--g70)}
.lv-t3{color:var(--g30);border-color:var(--g80)}
.lv-t4{color:var(--g50);border-color:var(--g80)}
/* "expected" sits next to a date that is a projection. Deliberately quiet —
   it qualifies the date, it does not shout over the name. */
.ann{font-size:11.5px;color:var(--g50);border:1px dashed var(--g70);
  padding:1px 6px;border-radius:20px;margin-left:6px;white-space:nowrap}
.sub{color:var(--g40);font-size:14.5px;margin:6px 0 0;max-width:62ch;line-height:1.55}

/* ── Country page: onward links into the tools ────────────────────────────── */
.rel-list{list-style:none;margin:14px 0 0;padding:0;
  display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:2px 22px}
.rel-list li{padding:11px 0;border-bottom:1px solid var(--g90,rgba(255,255,255,.05))}
.rel-list a{display:block;text-decoration:none;color:var(--teal40);font-size:15.5px}
.rel-list span{display:block;margin-top:3px;color:var(--g50);font-size:13px;line-height:1.5}

/* ── Year switcher ────────────────────────────────────────────────────────── */
/* ── YEAR TABS ─────────────────────────────────────────
   Every tab is an <a> to a page that exists, except the current one, which
   is a <span> because you are already on it. They are not JS panels: a panel
   set would collapse /2027/ and /2028/ into one address, and "germany public
   holidays 2027" is a query that needs a URL of its own to answer.

   Styled as tabs rather than the pills they replace so the row reads as a
   position — you are IN 2026, and 2027 is somewhere to go — instead of as
   three equal buttons. The active tab sits on a 2px teal rule; teal here is
   an indicator, which is the only job it should have outside a button. */
.yt-bar{display:flex;flex-wrap:wrap;gap:2px;margin:14px 0 0;
        border-bottom:1px solid var(--g80)}
.yt{display:inline-block;padding:9px 16px 8px;font-size:14px;font-weight:500;
    color:var(--g40);text-decoration:none;border-bottom:2px solid transparent;
    margin-bottom:-1px;transition:color .12s,border-color .12s}
.yt:hover{color:var(--g10);border-bottom-color:var(--g60)}
.yt.on{color:var(--g10);font-weight:600;border-bottom-color:var(--teal40)}
/* A tab is a hit target before it is a label. 44px is the floor. */
@media (max-width:600px){
  .yt{padding:12px 14px 10px}
}

.yr-switch{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}
.yr{display:inline-block;padding:5px 13px;border:1px solid var(--g80);border-radius:20px;
  font-size:13.5px;text-decoration:none;color:var(--g30);font-variant-numeric:tabular-nums}
.yr:hover{border-color:var(--g60);color:var(--g10)}
.yr.on{background:var(--g10);color:var(--bg,#0d0d0e);border-color:var(--g10);font-weight:600}
.yr-now{border-style:dashed;color:var(--teal40);border-color:rgba(80,200,180,.4)}
/* Subscribe row: the button and its explanation on one line where there is
   room, stacked where there is not. */
.ics-line{display:flex;flex-wrap:wrap;align-items:center;gap:12px;margin:22px 0 0}
.ics-line .small{max-width:52ch;line-height:1.55}
/* Bridge-day chip. "no leave needed" is the good news, so it reads as such;
   "take Fri 2 Jan" is an instruction and gets the neutral treatment. */
.bd{font-size:12px;white-space:nowrap;padding:2px 8px;border-radius:20px;
  border:1px solid var(--g70);color:var(--g30)}
.bd-free{border-color:rgba(80,200,180,.35);color:var(--teal40)}

/* ── Coverage table: one column grid for every region ─────────────────────────
   Each region renders its own table, so widths were computed per table and the
   Exchanges column — four MICs for the United States, empty for most of Africa
   — pushed every other column somewhere different in each block. Reading down
   the page meant re-finding the same column six times. Fixed layout with
   declared widths makes the six tables one grid. */
.cov-tbl{table-layout:fixed;width:100%;min-width:860px}
.cov-tbl .c-jur{width:26%}
.cov-tbl .c-obs{width:11%}
.cov-tbl .c-mix{width:21%}
.cov-tbl .c-exch{width:15%}
.cov-tbl .c-cal{width:15%}
.cov-tbl .c-rev{width:12%}
/* Long MIC lists and calendar-system lists wrap inside their column rather
   than widening it. */
.cov-tbl td{overflow-wrap:anywhere}

/* ── "What's this?" ──────────────────────────────────────────────────────────
   A question mark that explains a column without sending anyone to the docs
   for one sentence. */
.qm{display:inline-flex;align-items:center;justify-content:center;width:15px;height:15px;
  margin-left:5px;padding:0;border:1px solid var(--g60);border-radius:50%;
  background:transparent;color:var(--g40);font:inherit;font-size:10px;line-height:1;
  cursor:help;vertical-align:middle}
.qm:hover,.qm:focus-visible{border-color:var(--g30);color:var(--g10)}
.qm-pop{position:absolute;z-index:60;max-width:290px;padding:11px 13px;
  background:var(--g90);border:1px solid var(--g70);border-radius:8px;
  font-size:12.5px;line-height:1.55;color:var(--g20,#e0e0e0);
  box-shadow:0 8px 26px rgba(0,0,0,.5);text-transform:none;letter-spacing:0;
  font-weight:400}
.qm-pop b{display:block;margin-bottom:5px;color:var(--g10)}
.qm-pop a{display:inline-block;margin-top:8px;color:var(--teal40)}


/* ─────────────────────────────────────────────────────────────────────
   AT A GLANCE — the scope of a dossier in five seconds, above a contents
   list that runs to twenty-nine rows. Every figure is read from the feed
   the cover is drawn from, so it cannot disagree with the document.
   ───────────────────────────────────────────────────────────────────── */
.glance{display:grid;grid-template-columns:repeat(auto-fit,minmax(96px,1fr));
  gap:1px;background:var(--g80);border:1px solid var(--g80);border-radius:3px;
  margin:0 0 16px;overflow:hidden}
.glance .gl{background:var(--g95,var(--bg));padding:11px 12px}
.glance .gl b{display:block;font-family:var(--mono);font-size:19px;
  color:var(--g10);letter-spacing:-.01em;font-variant-numeric:tabular-nums}
.glance .gl span{display:block;font-size:11px;color:var(--g50);margin-top:3px;
  line-height:1.35}
.glance .gl.wide{grid-column:1/-1}
.glance .gl.wide b{font-size:14px;color:var(--teal40)}

/* KEY CHAPTERS. The buyer is not being told the document changed — they are
   being told where to look first in a list too long to scan. */
.toc .star{color:var(--teal40);margin-right:7px;font-size:11px;
  vertical-align:1px}
.toc li.key .t{color:var(--g10)}

/* PUBLISHING FURNITURE, FOLDED. Still declared, still counted, no longer
   occupying nine of the first eleven lines. */
.toc li.fold>.mi>summary .t{color:var(--g40)}
.toc li.fold>.mi>summary .c{color:var(--g55,var(--g50))}
.toc .sub{margin:2px 0 6px;padding-left:0}
.toc .sub .n{opacity:.65}

/* THE PURCHASE BLOCK. Three equal buttons in a row gave the eye nowhere to
   land; the subscription is the offer and the single edition is the fallback,
   so they are two panels with their own prices rather than two labels. */
.buy{display:grid;grid-template-columns:repeat(auto-fit,minmax(216px,1fr));
  gap:12px;width:100%}
.buy-opt{border:1px solid var(--g80);border-radius:3px;padding:14px 15px 15px}
.buy-opt:first-child{border-color:var(--teal40)}
.buy-k{font-family:var(--mono);font-size:10.5px;letter-spacing:.09em;
  text-transform:uppercase;color:var(--g50)}
.buy-v{font-size:25px;color:var(--g10);margin:5px 0 0;letter-spacing:-.02em;
  font-variant-numeric:tabular-nums}
.buy-v span{font-size:13px;color:var(--g50);letter-spacing:0}
.buy-l{list-style:none;padding:0;margin:9px 0 13px}
.buy-l li{font-size:12.5px;color:var(--g40);line-height:1.75}
.buy-l li::before{content:"✓";color:var(--teal40);margin-right:7px;
  font-size:11px}


/* PAGE ONE OF THE ACTUAL PDF, over the drawn cover.
   Absolutely positioned so it covers the fallback exactly rather than
   displacing it — if it 404s its onerror removes it and the drawing beneath is
   already in place, with no reflow. object-fit:contain, not cover: the page is
   7:10 and so is the box, so contain is exact, and if a future edition changes
   trim size a letterbox is a better failure than a cropped colophon. */
.rc-shot{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;
  border-radius:inherit;z-index:4;background:#0a0a0a;transition:opacity .18s}
.rcard:hover .rc-shot,.rc-wrap:hover .rc-shot{opacity:.94}
/* The sheen rides above the photograph, or it is doing nothing. */
.rc-sheen{z-index:5}

/* THE SWAP IS EXPLICIT, NOT A Z-INDEX RACE. The drawn title, eyebrow and meta
   all sit at z-index 3, so simply stacking the image over them left them
   showing through the thin letterbox the 7:10 box leaves around a 472x674
   render — every cover printed its country name twice. The image announces
   itself on load and the drawing steps aside; if it never loads, onerror
   removes it and nothing here fires. */
.rc-cover.has-shot .rc-eyebrow,
.rc-cover.has-shot .rc-title,
.rc-cover.has-shot .rc-meta{display:none}


/* The clear on a picker that can hold a value the user did not choose.
   Positioned over the input's right edge rather than beside it, so adding one
   never changes the control's width or reflows the panel it sits in. */
.cpick{position:relative}
.cpick .cp-x{position:absolute;top:0;right:0;height:100%;width:34px;
  background:none;border:0;padding:0;cursor:pointer;
  color:var(--g50);font-size:19px;line-height:1;
  display:flex;align-items:center;justify-content:center}
.cpick .cp-x:hover,.cpick .cp-x:focus-visible{color:var(--teal40)}
.cpick:has(.cp-x:not([hidden])) input{padding-right:34px}


/* ─────────────────────────────────────────────────────────────────────
   THE FINGERPRINT — a country's operating year as one shape.
   Sized in em so it scales with the reader's text size rather than
   ignoring it, and scrolls rather than shrinking below legibility on a
   phone: 52 columns cannot be squeezed into 320px and stay readable.
   ───────────────────────────────────────────────────────────────────── */
.fp{width:100%;min-width:520px;height:auto;display:block;margin:18px 0 0}
.fp-open{fill:#2e2e2e}         /* any day that is not a closure */
.fp-shut{fill:var(--teal40)}
/* No weekend fill: the corpus does not record rest days, so the strip does not
   claim to know them. See DQ-95. */
.fp-m{fill:var(--g50);font-family:var(--mono);font-size:8px}
/* The strip is wider than a phone. A scroller beats illegible squares. */
.fp-scroll{overflow-x:auto;scrollbar-width:thin}
.fp-key{font-family:var(--mono);font-size:11.5px;color:var(--g50);
  margin:12px 0 0;display:flex;align-items:center;gap:7px;flex-wrap:wrap}
.fp-sw{display:inline-block;width:9px;height:9px;border-radius:1.5px;
  margin-left:10px}
.fp-key .fp-sw:first-child{margin-left:0}
.fp-sw.fp-open{background:#2e2e2e;outline:1px solid var(--g80)}
.fp-sw.fp-shut{background:var(--teal40)}


/* THE NAMED SUBDIVISIONS. Was modal-only styling in reports.html; the
   jurisdiction page renders this list now, so the rules move with it. */
.m-subs{border-top:1px solid var(--g80);margin-top:16px;padding-top:14px}
.m-subs h3{font-size:12px;letter-spacing:.06em;text-transform:uppercase;
  color:var(--g40);font-weight:500;margin:0 0 10px}
.m-subs ul{column-count:2;column-gap:22px;list-style:none;margin:0;padding:0}
@media (max-width:640px){.m-subs ul{column-count:2}}
.m-subs li{break-inside:avoid;font-size:12.5px;line-height:1.75;color:var(--g20)}
.m-subs li .n{font-family:var(--mono);color:var(--g50);font-size:11px}


/* The band, legible at catalogue size. Above .rc-shot (z-index 4) and below
   the sheen (5), so it survives the real cover being laid over the drawing. */
.rc-badge{position:absolute;top:8px;left:8px;z-index:6;
  font-family:var(--mono);font-size:9.5px;letter-spacing:.09em;
  text-transform:uppercase;color:var(--g10);
  background:rgba(0,0,0,.72);backdrop-filter:blur(3px);
  border:1px solid rgba(255,255,255,.16);border-radius:3px;padding:3px 7px}


/* THE CURRENCY SWITCH. currencySwitch() in shell.js emits this on any page that
   asks for it, but the styling lived in pricing.html's own <style> — so the
   Dossiers catalogue, which has called the same function all along, rendered
   three unstyled buttons. A shared component's CSS belongs with the component,
   not with the first page that happened to use it. */
.cur{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin:0 0 6px}
.cur .lb{font-family:var(--mono);font-size:12px;letter-spacing:.09em;
  text-transform:uppercase;color:var(--g40);margin-right:2px}
.cur button{font-family:var(--mono);font-size:13px;background:transparent;
  color:var(--g30);border:1px solid var(--edge);border-radius:2px;
  padding:7px 13px;cursor:pointer}
.cur button:hover{border-color:var(--g50);color:var(--g10)}
.cur button[aria-checked=true]{background:var(--teal40);color:#001f1e;
  border-color:var(--teal40)}
.cur button:focus-visible{outline:2px solid var(--teal40);outline-offset:2px}


/* The free sample, offered beside the thing it is a sample of. */
.samp{font-size:14px;color:var(--g40);background:var(--g95,#0d0d0d);
  border:1px solid var(--g80);border-left:2px solid var(--teal40);
  border-radius:3px;padding:12px 14px;margin:14px 0 0;line-height:1.65}
.samp a{color:var(--teal40)}

/* PRODUCT CODES — DOS · API · OPC.
   Two of the three product names contain the word "calendar", so a reader who
   meets one first assumes the other is the same thing. The code is set in the
   mono face at label size so it reads as an identifier rather than a word, and
   it appears wherever a product is named: the switcher, the pricing cards, the
   account. Stable across a rename, which is most of the point. */
.pcode{display:inline-block;font-style:normal;font-family:var(--mono);
  font-size:10.5px;letter-spacing:.1em;color:var(--teal40);
  border:1px solid var(--teal40);border-radius:3px;padding:1px 5px;
  margin-right:7px;vertical-align:2px}


/* SKIP LINK. Off-screen rather than display:none, because a hidden element is
   not focusable and the link would never be reachable by the keyboard users it
   exists for. */
.skip{position:absolute;left:8px;top:-64px;z-index:200;
  background:var(--teal40);color:#000;font:600 14px/1 var(--sans);
  padding:12px 16px;border-radius:3px;text-decoration:none;
  transition:top .12s ease}
.skip:focus{top:8px}
@media (prefers-reduced-motion:reduce){.skip{transition:none}}
main:focus{outline:none}


/* The plain-text escape hatch on /legal. Quiet, but above the fold — a reader
   who needs it is a reader for whom the page has already failed. */
.legal-fallback{font-size:14.5px;color:var(--g50);margin:14px 0 0}
.legal-fallback a{color:var(--teal40)}


/* The OGL acknowledgement. Below the legal strip, quieter than it: naming a
   licence we rely on is an obligation discharged, not a thing to sell. */
.foot-ogl{margin:14px 0 0;font-size:11.5px;line-height:1.55;color:var(--g50);
  max-width:92ch}
.foot-ogl a{color:var(--g40);text-decoration:underline;
  text-underline-offset:2px}
.foot-ogl a:hover{color:var(--teal40)}


/* ── The record, folded into the jurisdiction page ────────────────────────
   Was a standalone page at /coverage/<slug>: 10 KB, absent from the sitemap,
   indexable anyway, and about our corpus rather than the country. It is
   evidence for what the reader just read, so it sits under the data and is
   built to be SCANNED rather than read — a table, a ratio, two sentences.

   Deliberately quieter than the holiday table above it. That one is the
   answer; this one is the reason to believe it, and a section that shouts as
   loudly as the answer competes with it. */
.ev-head{display:flex;align-items:baseline;gap:10px;margin:18px 0 6px}
.ev-meter{font-family:var(--mono);font-size:26px;color:var(--g10);line-height:1}
.ev-meter b{font-weight:500}
.ev-meter span{font-size:16px;color:var(--g50)}
.ev-meter-l{font-family:var(--mono);font-size:11px;letter-spacing:.11em;
  text-transform:uppercase;color:var(--g50)}
.ev-tbl{font-size:14px}
.ev-tbl th{font-size:10.5px}
.ev-tbl th.num,.ev-tbl td.num{text-align:right;white-space:nowrap}
/* THE LABEL IS THE WHOLE CELL. The sentence explaining each layer used to sit
   under the name as a dimmed block, which doubled every row: "Tax and filing
   deadlines" became four lines the moment "Statutory dates that move when a
   closure lands on them" was set beneath it. The definition still matters and
   still ships — it moved into the `.qm` popover, one hover away, costing the
   table no height and no width. */
.ev-tbl td:first-child b{font-weight:600;color:var(--g10)}
.ev-tbl td:first-child{white-space:nowrap}
/* A date must not wrap: "2026-08-03" broken after the month reads as two
   values stacked, and this column exists to be scanned. */
.ev-tbl td:nth-child(4){white-space:nowrap}
/* The notes column is the only one allowed to run long — MIC lists and
   "3 calendars, 2 parallel" — so it is the one that gets the leftover width. */
.ev-tbl td:last-child{white-space:normal;min-width:14ch}
.ev-notes{margin-top:16px;font-size:14px;color:var(--g40);max-width:74ch}
.ev-notes p{margin:0 0 10px}
.ev-notes .hosts{display:flex;flex-wrap:wrap;gap:5px}
.ev-notes .hosts span{font-family:var(--mono);font-size:11.5px;color:var(--g40);
  border:1px solid var(--g80);border-radius:3px;padding:2px 7px}
@media(max-width:700px){
  .ev-meter{font-size:22px}
}


/* ── The Bulletin, on a jurisdiction page ─────────────────────────────────
   Two shapes for two jobs. The NOTICE is time-critical, sits above the
   calendar, and is allowed to be the loudest thing on the page after the
   headline — a reader who scrolls past a live notice has been failed by the
   page, not by their attention.

   The ROWS below the record are the opposite: a reading list for someone who
   already got what they came for. Text, dates, no cards, no images. If they
   competed with the holiday table they would be pulling people away from the
   answer. */
.cp-notice{display:block;margin:22px 0 0;padding:13px 16px;border-radius:9px;
  text-decoration:none;background:var(--g90);
  border:1px solid var(--teal70,#1c4a45);border-left:3px solid var(--teal40)}
.cp-notice:hover{background:var(--g88,#14181d);border-color:var(--teal40)}
.cp-notice-k{display:inline-block;font-family:var(--mono);font-size:10.5px;
  letter-spacing:.11em;text-transform:uppercase;color:var(--teal40)}
.cp-notice-t{display:block;margin-top:3px;font-size:15.5px;font-weight:600;
  color:var(--g10);line-height:1.35}
.cp-notice-s{display:block;margin-top:4px;font-size:13px;color:var(--g40);
  line-height:1.5;max-width:78ch}
.bl-rows{display:flex;flex-direction:column;margin-top:14px}
.bl-row{display:block;padding:13px 0;text-decoration:none;
  border-top:1px solid var(--g85)}
.bl-row:last-child{border-bottom:1px solid var(--g85)}
.bl-row:hover .bl-row-t{color:var(--teal40)}
.bl-row-m{display:block;font-family:var(--mono);font-size:10.5px;
  letter-spacing:.09em;text-transform:uppercase;color:var(--g50)}
.bl-row-t{display:block;margin-top:4px;font-size:15.5px;font-weight:600;
  color:var(--g10);line-height:1.35}
.bl-row-s{display:block;margin-top:3px;font-size:13.5px;color:var(--g40);
  line-height:1.55;max-width:82ch}


/* ── The Bulletin ─────────────────────────────────────────────────────────
   Reading pages, not product pages: one column, generous measure, and nothing
   in the margin competing with the prose. The entries are long-form and the
   voice is the argument, so the type does the work and the furniture stays
   out of the way. */
.bl-index h1,.bl-entry h1{margin:6px 0 14px}
.bl-depts{display:flex;flex-wrap:wrap;gap:8px;margin:26px 0 34px;
  padding-bottom:26px;border-bottom:1px solid var(--g80)}
.bl-depts a{font-family:var(--mono);font-size:12px;letter-spacing:.04em;
  color:var(--g30);text-decoration:none;border:1px solid var(--g80);
  border-radius:3px;padding:6px 11px}
.bl-depts a:hover{border-color:var(--teal40);color:var(--g10)}
.bl-depts a span{color:var(--g50);margin-left:5px}

.bl-list{list-style:none;margin:0;padding:0}
.bl-item{padding:24px 0;border-bottom:1px solid var(--g90,rgba(255,255,255,.05))}
.bl-item:last-child{border-bottom:0}
.bl-item h2{font-size:22px;line-height:1.28;margin:6px 0 8px}
.bl-item h2 a{color:var(--g10);text-decoration:none}
.bl-item h2 a:hover{color:var(--teal40)}
.bl-item p{color:var(--g40);margin:0;max-width:74ch;line-height:1.6}
.bl-meta{font-family:var(--mono);font-size:11px;letter-spacing:.09em;
  text-transform:uppercase;color:var(--g50)}
.bl-meta .bl-dept{color:var(--teal40);text-decoration:none}

/* A NOTICE SAYS WHERE IT IS IN ITS OWN LIFE. Live and passed are different
   claims and a reader must not have to work out which they are reading. */
.bl-badge{font-family:var(--mono);font-size:10px;letter-spacing:.08em;
  text-transform:uppercase;padding:1px 6px;border-radius:20px;margin-left:6px}
.bl-badge.live{color:var(--teal40);border:1px solid rgba(80,200,180,.4)}
.bl-badge.past{color:var(--g50);border:1px solid var(--g80)}

.bl-kind{font-family:var(--mono);font-size:11px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--g50);margin:0}
.bl-live,.bl-expired{border-left:2px solid;padding:12px 16px;margin:22px 0;
  font-size:14.5px;line-height:1.55;border-radius:0 3px 3px 0}
.bl-live{border-color:rgba(80,200,180,.5);background:rgba(80,200,180,.06);color:var(--g30)}
.bl-expired{border-color:var(--g70);background:var(--g95,rgba(255,255,255,.02));color:var(--g40)}

.bl-body{max-width:68ch;font-size:17px;line-height:1.68;color:var(--g25,var(--g30))}
.bl-body h2{font-size:22px;margin:38px 0 10px;line-height:1.3}
.bl-body h3{font-size:18px;margin:30px 0 8px}
.bl-body p{margin:0 0 17px}
.bl-body blockquote{margin:22px 0;padding:0 0 0 20px;border-left:2px solid var(--teal40);
  color:var(--g20,var(--g10));font-size:18px;line-height:1.55}
.bl-body table{width:100%;border-collapse:collapse;font-size:15px;margin:22px 0}
.bl-body th,.bl-body td{text-align:left;padding:9px 12px 9px 0;
  border-bottom:1px solid var(--g90,rgba(255,255,255,.05));vertical-align:top}
.bl-body code{font-family:var(--mono);font-size:.88em;color:var(--g20,var(--g10))}
.bl-juris{font-size:13.5px;color:var(--g50);max-width:74ch}
.bl-juris code{font-family:var(--mono);font-size:12px;color:var(--g40)}
.bl-edition{font-family:var(--mono);font-size:12px;color:var(--g50);
  border-top:1px solid var(--g80);padding-top:16px;margin-top:34px}
.bl-rel{margin-top:44px;border-top:1px solid var(--g80);padding-top:26px}
.bl-rel h2{font-size:13px;font-family:var(--mono);letter-spacing:.1em;
  text-transform:uppercase;color:var(--g50);margin:0 0 14px;font-weight:400}
.bl-rel ul{list-style:none;margin:0;padding:0}
.bl-rel li{padding:10px 0;border-bottom:1px solid var(--g90,rgba(255,255,255,.05))}
.bl-rel a{color:var(--teal40);text-decoration:none;font-size:16px}
.bl-rel span{display:block;color:var(--g50);font-size:13.5px;margin-top:3px}
.bl-feed{margin-top:34px;font-family:var(--mono);font-size:12px}
.bl-feed a{color:var(--g50)}
@media(max-width:700px){.bl-body{font-size:16px}.bl-item h2{font-size:19px}}
