/* 'app' flavour: search-1 / map-1 layouts (modern single-page look). */
/* fixed chrome: the header sticks to the top (solid background, natural height) and the footer is pinned to the
   bottom of the viewport at a fixed height; the body reserves the footer's height so nothing hides behind it. */
:root{--foot-h:84px}
body.flavour-app{padding-bottom:var(--foot-h)}
.topnav{position:sticky;top:0;z-index:1100;background:var(--bg);display:flex;align-items:center;gap:18px;padding:12px 22px;border-bottom:1px solid var(--border)}
/* top-right nav: bordered buttons like the Light/Dark toggle (.toggle-btn, left untouched), all one fixed width (fits
   the longest label, text centred). Hover = the home filter toggles' selected marker (.seg input:checked+span: inset
   2px accent bar) drawn on the TOP edge; the current page keeps that bar plus the selected surface background. */
.topnav nav{--nav-w:82px;display:flex;gap:6px;font-size:13px}
.topnav nav a{box-sizing:border-box;width:var(--nav-w);flex:none;display:inline-flex;align-items:center;justify-content:center;text-align:center;white-space:nowrap;color:var(--muted);text-decoration:none;background:transparent;border:1px solid var(--border);border-radius:8px;padding:7px 4px;font:600 13px/1.1 inherit;font-family:inherit;transition:color .12s ease,background-color .12s ease,box-shadow .12s ease}
.topnav nav a:hover{color:var(--text);box-shadow:inset 0 2px 0 var(--accent)}
.topnav nav a.on{color:var(--text);background:var(--surface);box-shadow:inset 0 2px 0 var(--accent)}
.topnav nav a:focus-visible{outline:2px solid var(--accent-2);outline-offset:2px}
.topnav .prefs{flex:none}   /* never squeezed: the Light/Dark button keeps its own size and look */
/* too narrow for logo + one row of buttons + prefs: the buttons move to their own full-width row (right-aligned, wrapping) */
@media (min-width:701px) and (max-width:1199px){.topnav{flex-wrap:wrap;row-gap:10px}.topnav nav{order:3;width:100%;flex-wrap:wrap;justify-content:flex-end}}
@media (min-width:701px) and (max-width:919px){.topnav nav{display:grid;grid-template-columns:repeat(5,var(--nav-w));justify-content:end}}   /* two even rows of five */
.topnav .prefs{display:flex;gap:8px}
/* wide screens: three columns - logo left, the nav button group centred on the header, Light/Dark pinned right
   (the side columns never shrink below their content, so a wide logo only nudges the group, never overlaps it) */
@media (min-width:1200px){.topnav{display:grid;grid-template-columns:minmax(max-content,1fr) auto minmax(max-content,1fr)}.topnav>.spacer{display:none}.topnav>nav{justify-self:center}.topnav>:first-child{justify-self:start}.topnav>.prefs{justify-self:end}}
.spacer{flex:1}
.crumbs-bar{display:none}
.side{display:none}
.foot{position:fixed;left:0;right:0;bottom:0;z-index:1100;height:var(--foot-h);overflow:hidden;display:flex;flex-direction:column;background:var(--bg);text-align:center;font-size:12px;line-height:1.45;color:var(--muted);padding:9px 14px 8px;border-top:1px solid var(--border)}
.foot a{color:var(--muted)}.foot a:hover{color:var(--accent)}
/* /map: two extra lines above the notice (attribution + a blank line), 12px; taller footer */
.foot .foot-attrib,.foot .foot-gap{display:none;margin:0;flex:none;white-space:nowrap;overflow-x:auto;scrollbar-width:none}
.foot .foot-gap{height:1.45em}
body.page-map{--foot-h:119px}
body.page-map .foot .foot-attrib,body.page-map .foot .foot-gap{display:block}
/* the notice: 11px, 1000px wide = two lines from 1024 px up, three below; --foot-h fits it with no inner scroll
   (no links line since the footer links moved to the header: 9 pad + 3 + 2 x 14.85 + 2 + 16 powered + 8 pad + 1 border
   = 69 -> 70; three lines -> 84; /map +34 for attribution + gap). Phones: 95/130, the notice scrolls inside. */
.foot .fine{max-width:1000px;margin:3px auto 0;font-size:11px;line-height:1.35;opacity:.85;min-height:0;overflow-y:auto;scrollbar-width:thin}
@media (min-width:1024px){:root{--foot-h:70px}body.page-map{--foot-h:104px}}
@media (min-width:701px) and (max-width:1023px){:root{--foot-h:84px}body.page-map{--foot-h:119px}}
/* last footer line, bottom right: what powers the site + the deployed version (orange accent, both themes) */
.foot .foot-powered{display:flex;flex:none;justify-content:center;align-items:baseline;flex-wrap:wrap;gap:0 14px;margin:2px 0 0;font-size:11px;line-height:1.4;color:var(--accent);text-align:center}
.foot .foot-powered .fp-ver{color:var(--accent);font-family:var(--mono);text-decoration:none;white-space:nowrap}
.foot .foot-powered .fp-ver:hover{text-decoration:underline;color:var(--accent)}
.wrap{max-width:900px;margin:0 auto;padding:26px 20px}
.hero{max-width:900px;margin:0 auto;padding:24px 20px 8px;text-align:center}
.hero .mascot{width:80px;height:auto;margin:0 auto 6px;display:block}
.hero h1{font:800 40px/1.1 system-ui;margin:0 0 6px;letter-spacing:-.02em}
.hero .lead{color:var(--muted);margin:0}
.searchbar.big{max-width:680px;margin:14px auto 10px}
.searchbar.big .input{font-size:18px;padding:14px 16px;border-radius:12px}
.searchbar.big .btn{padding:14px 20px;border-radius:12px;font-size:15px;width:var(--resolve-w);justify-content:center}
.ctl .opt-row{justify-content:center}
.ctl .adv{margin-top:10px}
.panel-h{font-size:13px;letter-spacing:.06em;text-transform:uppercase;color:var(--muted);margin:0 0 10px}
#result{margin-top:22px;padding:22px}
.pyw{text-align:left;margin-top:14px}
.pyw summary{margin:0}
#hits{margin-top:18px;text-align:left}
.page h1{font:800 32px/1.15 system-ui;letter-spacing:-.02em;margin:.2em 0 .4em}
.side-stats{display:none}
/* map-1: full-bleed map with floating cards */
body.page-map{overflow:hidden;height:100vh;height:100dvh;display:flex;flex-direction:column}
body.page-map main{flex:1;min-height:0;position:relative}
.mapwrap{position:absolute;inset:0}
body.page-map .map-attrib{display:none}
#map{position:absolute;inset:0;background:color-mix(in srgb,var(--accent) 6%,var(--bg))}
.map-float{position:absolute;z-index:500;box-shadow:0 12px 30px rgba(0,0,0,.4)}
#map-controls{top:16px;left:16px;display:flex;flex-direction:column;gap:9px;padding:12px 14px;width:min(352px,calc(100% - 32px));max-height:calc(100% - 32px);overflow:auto;margin:0}
/* the home page's filter form, compact in the panel (same markup: templates/_filters.html) */
#map-controls .ctl{max-width:none;margin:0;min-height:0}
#map-controls .ctl .opt-row{max-width:none;justify-content:flex-start;gap:7px 10px}
#map-controls .ctl .adv,#map-controls .ctl .stf{margin-top:7px}
#map-controls .seg span{padding:5px 7px;font-size:12px;white-space:nowrap}
#map-controls .stf .sel{max-width:100%}
#map-controls .stf .input.fin{width:8.6em}
.map-fstatus{margin:0;font-size:12px}.map-fstatus:empty{display:none}
/* compact: each option is one line (legend beside its toggle), mode + era share a line; the panel always ends above
   the bottom-left mascot (scrolls inside when "more filters" is open) */
#map-controls fieldset.opt{flex-direction:row;align-items:center;gap:8px}
#map-controls fieldset.opt legend{float:left;width:4.6em;margin:0;flex:none}
#map-controls .ctl .opt-row:not(.adv):not(.stf){gap:7px 14px}
#map-controls .ctl .opt-row.adv{margin-top:7px}
#map-controls fieldset.opt[data-param=namespace]{flex-direction:column;align-items:flex-start;gap:4px}
#map-controls fieldset.opt[data-param=namespace] legend{width:auto}
#map-controls .stf .sel.prov{max-width:170px}
#mapwrap:has(#map-mascot) #map-controls{max-height:calc(100% - 32px - 192px)}
@media (max-width:1100px){#mapwrap:has(#map-mascot) #map-controls{max-height:calc(100% - 32px - 132px)}}
@media (max-width:900px){#mapwrap:has(#map-mascot) #map-controls{max-height:calc(100% - 32px)}}
#map-panel{top:16px;right:16px;width:430px;max-height:calc(100% - 32px);overflow:auto}
#map-legend{bottom:16px;right:16px;padding:7px 12px;font-size:12px;display:flex;gap:8px;align-items:center}
#stream-grid{position:absolute;z-index:450;inset:16px 382px 16px 300px;overflow:auto}
.map-links{font-size:12px}
.map-links a{margin-right:8px}
@media (max-width:900px){#map-panel{top:auto;bottom:0;right:0;left:0;width:auto;max-height:40vh}#stream-grid{inset:200px 8px 42vh 8px}#map-legend{display:none}}

/* search home: one compact unit. Options sit in two rows left-aligned under the 680 px search row; in the empty
   state the prompt sits under row 2 and the pointing mascot stands to the right of both rows with his raised finger
   (11.86% of the image width from its left edge) under the centre of the Resolve button (100% - --resolve-w/2). */
.hero{--resolve-w:120px;--m-w:165px}
.ctl{position:relative;max-width:680px;margin:0 auto}
.ctl-top{display:flow-root}   /* contains the floated mascot (+ the space reserved for the hint) */
/* desktop empty state: the hero fills the viewport between header and footer and the "click a language" line + tiles
   sit centred in what is left below the filters (open or closed). Not when a code panel is open or a query is shown. */
@media (min-width:901px){
  .hero:not(.has-q):not(.code-open){--head-h:62px;display:flex;flex-direction:column;box-sizing:border-box;
    min-height:calc(100vh - var(--head-h) - var(--foot-h))}
  .hero:not(.has-q):not(.code-open) .searchform{flex:1 0 auto;display:flex;flex-direction:column}
  .hero:not(.has-q):not(.code-open) .searchform>.searchbar{width:100%}   /* auto side margins would shrink it in the flex column */
  .hero:not(.has-q):not(.code-open) .ctl{flex:1 0 auto;display:flex;flex-direction:column;width:100%}
  .hero:not(.has-q):not(.code-open) .lang-pick{flex:1 0 auto;display:flex;flex-direction:column;justify-content:center;
    align-items:flex-start;padding:15px 0 10px}   /* 15 = 10 + the hero's 8px bottom padding - the line's 3px top margin */
}
/* the nav buttons sit on their own header row: 920-1199 px one row (header 108 px instead of 62), 901-919 two rows (149) */
@media (min-width:920px) and (max-width:1199px){.hero:not(.has-q):not(.code-open){--head-h:108px}}
@media (min-width:901px) and (max-width:919px){.hero:not(.has-q):not(.code-open){--head-h:149px}}
.ctl .opt-row{justify-content:flex-start;gap:8px 16px;max-width:calc(100% - var(--resolve-w) / 2 - var(--m-w) * .1186 - 12px)}
.ctl fieldset.opt legend{margin-bottom:3px}
/* the mascot floats at the top right of the form (overhanging it, pointing at Resolve). The orange hint is anchored to the
   top of the form (absolute in .ctl), just below him with its left edge at his left foot (58/320 of the image width), so
   opening or closing "more filters" never moves either; the float's bottom margin reserves two hint lines and the
   "click a language" line clears it, so only the tiles below shift. */
.hero{--m-left:calc(100% - var(--resolve-w) / 2 - var(--m-w) * .1186);--m-foot:calc(var(--m-w) * .181)}
/* --h-r = viewport right edge - 12px in .ctl coordinates; on narrow desktops the hint keeps >= 300px by starting a bit left of the foot */
.start-msg{--h-r:calc(50vw + 328px);--h-l:min(var(--m-left) + var(--m-foot), var(--h-r) - 300px);
  position:absolute;top:calc(2px + var(--m-w) * 1.176 + 4px);left:var(--h-l);margin:0;width:max-content;max-width:calc(var(--h-r) - var(--h-l));text-align:left;color:var(--accent);font:700 19px/1.3 Nunito,system-ui,sans-serif}
.start-mascot{float:right;margin:2px calc(var(--resolve-w) / 2 + var(--m-w) * .1186 - var(--m-w)) calc(4px + 2 * 19px * 1.3 + 6px) 0;width:var(--m-w);height:auto;
  filter:drop-shadow(0 6px 14px rgba(0,0,0,.25));pointer-events:none}
.hero.has-q .start-msg,.hero.has-q .start-mascot{display:none}
.hero.has-q .ctl .opt-row{max-width:none}
#result.start{display:none}
/* empty state: a checkerboard of identical language tiles (filled / outlined alternate) instead of the code panel;
   picking one opens the code panel in its place with that language selected, "x icons" brings the grid back.
   --lang-tile-shape is the tile corner radius: 11px = rounded square (default), 50% = circle. */
/* empty state: 30 identical language tiles in a brick grid of centred rows of 8 / 7 / 8 / 7 instead of the code panel; picking one opens
   the code panel in its place with that language selected, "x icons" brings the grid back.
   Admin site settings (tvlogo/sitesettings.py), rendered on <html> so there is no flash:
   data-tile = square (default, --lang-tile-shape 4px) | rounded (11px) | round (50%);
   data-tile-style = outlined (default) | filled | checkerboard (tf / to parity classes). */
[data-tile=rounded] .langgrid{--lang-tile-shape:11px}
[data-tile=round] .langgrid{--lang-tile-shape:50%}
.start-sub{clear:right;margin:3px 0 0;text-align:left;color:var(--muted);font-size:12.5px}
.langgrid{--lang-tile-shape:4px;--tile:46px;--glyph:24px;--gap:8px;display:flex;flex-direction:column;gap:var(--gap);
  width:max-content;max-width:100%;margin:10px 0 0;animation:tvl-in .22s ease-out}
.lg-row{display:flex;flex-wrap:wrap;justify-content:center;gap:var(--gap)}   /* 8 / 7 / 8 / 7 brick rows; 7s centred = half-tile stagger */
.lg-line{display:contents}
/* desktop: two lines of 15 across the hero column (mockup 3:42); --lg-x moves line 1, --lg-stagger offsets line 2
   (+ = right, as in the mockup; use calc(var(--tile) / -2 - var(--gap) / -2) for half a tile left) */
@media (min-width:901px){
  .hero:not(.has-q) .langgrid{--lg-x:-88px;--lg-stagger:calc(var(--tile) / 2 + var(--gap) / 2);max-width:none;margin-left:var(--lg-x)}
  .lg-line{display:flex;gap:var(--gap)}
  .lg-line+.lg-line{margin-left:var(--lg-stagger)}
}
.li{position:relative;box-sizing:border-box;width:var(--tile);height:var(--tile);display:grid;place-items:center;padding:0;border:1.5px solid var(--accent);border-radius:var(--lang-tile-shape);
  background:transparent;color:var(--accent);font:inherit;cursor:pointer;transition:transform .15s,filter .15s,background-color .15s,color .15s,box-shadow .15s}
.li svg{display:block;width:var(--glyph);height:var(--glyph);overflow:visible}
.li:hover,.li:focus-visible{background:var(--accent);color:var(--on-accent);transform:translateY(-2px) scale(1.07);box-shadow:0 0 12px color-mix(in srgb,var(--accent) 55%,transparent)}
[data-tile-style=filled] .li,[data-tile-style=checkerboard] .li.tf{background:var(--accent);color:var(--on-accent)}
[data-tile-style=filled] .li:hover,[data-tile-style=filled] .li:focus-visible,
[data-tile-style=checkerboard] .li.tf:hover,[data-tile-style=checkerboard] .li.tf:focus-visible{filter:brightness(1.15)}
.li:focus-visible{outline:2px solid var(--accent-2);outline-offset:2px}
.li::after{content:attr(data-tip);position:absolute;left:50%;bottom:calc(100% + 4px);z-index:5;transform:translate(-50%,4px);padding:5px 7px;border-radius:6px;background:var(--text);color:var(--bg);font:600 11px/1 var(--mono);white-space:nowrap;opacity:0;pointer-events:none;transition:opacity .12s,transform .12s}
.li:hover::after,.li:focus-visible::after{opacity:1;transform:translate(-50%,0)}
.langgrid .mg{font-family:var(--mono);font-weight:800}
.hero.has-q .start-sub,.hero.has-q .langgrid,.hero.code-open .start-sub,.hero.code-open .langgrid{display:none}
.hero:not(.has-q):not(.code-open) .pyw{display:none}
.hero:not(.has-q) .pyw>summary{display:none}
.code-close{display:none}
.hero.code-open:not(.has-q) .code-close{display:inline-flex}
.hero.code-open:not(.has-q) .pyw{animation:tvl-in .22s ease-out}
@keyframes tvl-in{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){.langgrid,.hero.code-open .pyw{animation:none}.li{transition:none}}
.hero:not(.has-q) .pyw{max-width:680px;margin:10px auto 0}
@media (max-width:900px){
  .ctl .opt-row{justify-content:center;max-width:none}
  .hero:not(.has-q) .ctl{min-height:0;display:flex;flex-direction:column;align-items:center}
  .start-msg,.start-sub{text-align:center}
  .langgrid{--tile:38px;--glyph:20px;--gap:6px;margin-top:8px}
  .ctl .opt-row:not(.adv) fieldset:nth-of-type(2){order:3}   /* mode + era share a line on phones */
  .ctl .opt-row.adv fieldset:nth-of-type(2){order:3}          /* "more filters" sits beside size, key type below */
  .start-msg{position:static;margin:8px 0 0;width:auto;max-width:none}
  .start-mascot{float:none;order:9;width:110px;margin:6px 0 0}
  .ctl-top,.lang-pick{display:contents}   /* phones: one centred column in normal flow, mascot last */
}
/* phones: header wraps (nav = two rows of five equal buttons); the footer keeps its fixed height (the notice scrolls inside) */
@media (max-width:700px){
  .topnav{flex-wrap:wrap;gap:8px 14px;padding:10px 14px}
  .topnav nav{order:3;width:100%;display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:5px;overflow:visible}   /* phones: two even rows of five equal buttons, never sideways */
  .topnav nav a{width:auto;padding:6px 2px;font-size:12px}
  .topnav .prefs{margin-left:auto}
  .foot .fine{font-size:10.5px}
  .foot .foot-powered{flex-direction:column;align-items:center;font-size:10px;line-height:1.35}   /* stack line, version below */
  :root{--foot-h:95px}body.page-map{--foot-h:130px}
  .hero h1{font-size:34px}
}
main:focus{outline:none}
main [id]{scroll-margin-top:84px}
/* Python code panel tabs (tvlogo client | requests) */
.langpick select{font:600 12px/1.2 inherit;font-family:inherit;color:var(--text);background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:5px 8px;max-width:240px;cursor:pointer}
.langpick select:focus-visible{outline:2px solid var(--accent-2);outline-offset:1px}
.chip{background:transparent;border:1px solid var(--border);border-radius:999px;color:var(--muted);font:600 12px/1 inherit;font-family:inherit;padding:5px 10px;cursor:pointer;transition:color .12s,background-color .12s,border-color .12s}
.chip:focus-visible{outline:2px solid var(--accent-2);outline-offset:1px}
.pyw pre.code{max-height:min(46vh,420px);overflow:auto}
.codehead .pyhint{flex:1;margin:0 10px}
@media (max-width:560px){.codehead .pyhint{display:none}.codehead{gap:6px}.codehead .langpick{flex:1 1 auto;min-width:0}.langpick select{width:100%;max-width:240px;text-overflow:ellipsis}}
/* /ai-prompt page: options, task chips (radio labels), preferred language, live Markdown box */
.aip h1{font:800 34px/1.1 Nunito,system-ui,sans-serif;margin:0 0 6px;letter-spacing:-.01em}
.aip .lead{color:var(--muted);margin:0 0 16px;max-width:720px}
.aip-form{display:flex;flex-direction:column;gap:12px;margin-bottom:14px}
.aip-form .opt-row{display:flex;flex-wrap:wrap;gap:8px 16px}
.aip-row{display:flex;flex-wrap:wrap;gap:10px 16px;align-items:flex-end}
.aip-field{display:flex;flex-direction:column;gap:5px;font:600 11px/1 inherit;text-transform:uppercase;letter-spacing:.08em;color:var(--muted)}
.aip-field small{text-transform:none;letter-spacing:0}
.aip-q{flex:1 1 280px}.aip-q .input{width:100%;box-sizing:border-box}
.aip-field select{font:600 13px/1.2 inherit;font-family:inherit;color:var(--text);background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:9px 10px;min-width:200px;text-transform:none;letter-spacing:0;cursor:pointer}
.aip-field select:focus-visible{outline:2px solid var(--accent-2);outline-offset:1px}
.aip-tasks{border:0;margin:0;padding:0}
.aip-tasks legend{font:600 11px/1 inherit;text-transform:uppercase;letter-spacing:.08em;color:var(--muted);padding:0;margin-bottom:6px}
.aip-tasks .chips{display:flex;flex-wrap:wrap;gap:6px}
.chip{display:inline-flex;align-items:center;position:relative}
.chip input{position:absolute;opacity:0;width:1px;height:1px;margin:0}
.chip:has(input:checked){background:var(--accent);border-color:var(--accent);color:var(--on-accent)}
.chip:has(input:focus-visible){outline:2px solid var(--accent-2);outline-offset:1px}
.chip small{font-weight:500;opacity:.8}
.aip-head{display:flex;align-items:center;gap:8px;margin-bottom:6px}
.aip-title{font:700 13px/1 inherit;color:var(--text)}
.aip-md{max-height:min(56vh,560px);overflow:auto;white-space:pre-wrap;word-break:break-word;font-size:12.5px;margin:0}
.aip-links{margin:8px 0 0}
/* decorative typing mascot: laptop base on the viewport's bottom edge (the "desk"), above the fixed footer, only in the
   free space right of the 900px content column (which also clears the centred footer text); hidden when it would not fit */
/* bottom-left, the browser's bottom edge is his desk; the image is already mirrored so he and his laptop face right,
   into the page. His width is the free gutter left of the column; the footer text is padded clear of him. */
.aip-mascot{position:fixed;left:0;bottom:0;z-index:1150;pointer-events:none;display:block;line-height:0;--aip-m-w:min(420px,calc(50vw - 438px))}
.aip-mascot img{display:block;width:var(--aip-m-w);height:auto}
@media (min-width:1176px){body.page-ai-prompt .foot{padding-left:calc(min(420px, 50vw - 438px) + 14px)}}
@media (max-width:1175px){.aip-mascot{display:none}}
/* coming-soon pages (/docs, /pypi) */

/* station search (home, third options row "more filters" -> /v1/stations); rows reuse the map's .st/.kv grid */
.stf-toggle{align-self:flex-end;font-size:12px;font-weight:600;color:var(--accent);text-decoration:none;padding:6px 2px;white-space:nowrap;cursor:pointer}
.stf-toggle::after{content:" \25BE"}.stf-toggle[aria-expanded=true]::after{content:" \25B4"}
.stf-toggle:hover{text-decoration:underline}.stf-toggle:focus-visible{outline:2px solid var(--accent-2);outline-offset:2px;border-radius:4px}
.ctl .stf{margin-top:7px;gap:6px 12px}
/* (no padding change when the station filters open: the search row, mascot and hint stay put) */
.stf[hidden],.stlist [hidden]{display:none}
.sel{font:600 12px/1.2 inherit;font-family:inherit;color:var(--text);background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:6px 8px;max-width:190px;cursor:pointer;height:29px}
.sel:focus-visible{outline:2px solid var(--accent-2);outline-offset:1px}
.input.fin{font:12px/1.2 var(--mono);padding:6px 8px;width:9.5em;border-radius:8px;height:29px}
.input.fin.num{width:5.2em}
.near-in{display:flex;gap:6px;align-items:center}
.near-in .btn{white-space:nowrap}
.unit{font-size:12px;color:var(--muted)}
.stf-clear{align-self:flex-end}
.stlist{margin-top:18px;text-align:left;padding:14px 16px}
.stlist .st-body,#st-body{display:grid;grid-template-columns:repeat(auto-fill,minmax(330px,1fr));column-gap:18px}
.stlist .st{display:grid;grid-template-columns:112px minmax(0,1fr);gap:12px;align-items:start;padding:10px 4px;border-bottom:1px solid var(--border);font-size:12.5px}
.stlist .st-logo{display:grid;gap:5px;justify-items:start}
.stlist .st-info{min-width:0}.stlist .st-info>b{display:block;margin:1px 0 3px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.stlist .logo-copy{display:block;padding:0;border:0;background:none;border-radius:10px;cursor:copy;line-height:0}
.stlist .logo-copy:hover .logo{outline:2px solid var(--accent);outline-offset:1px}
.stlist .logo-copy:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.stlist .logo-copy.copied .logo{outline:2px solid var(--ok);outline-offset:1px}
.stlist .kv{display:grid;grid-template-columns:5.6em minmax(0,1fr);column-gap:8px;row-gap:1px;margin:0;line-height:1.35}
.stlist .kv dt{color:var(--muted);font-size:11.5px;white-space:nowrap}
.stlist .kv dd{margin:0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.stlist .kv .mono{font:11.5px var(--mono)}
.stlist .kv a{color:var(--accent)}
.st-err{color:var(--err);font-size:13px;margin:4px 0 8px}
#st-more:not([hidden]){margin:12px auto 2px;display:flex}
.st-toast{position:fixed;left:50%;bottom:calc(var(--foot-h) + 14px);transform:translate(-50%,8px);z-index:1200;max-width:min(90%,520px);padding:7px 12px;border-radius:8px;background:var(--text);color:var(--bg);font:12px var(--mono);opacity:0;pointer-events:none;transition:opacity .15s,transform .15s;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.st-toast.on{opacity:1;transform:translate(-50%,0)}
.offscreen{position:fixed;left:-9999px;top:0}
@media (prefers-reduced-motion:reduce){.st-toast{transition:none}}
@media (max-width:700px){
  .ctl .stf{justify-content:center}
  #st-body{grid-template-columns:minmax(0,1fr)}
  .stlist .st{grid-template-columns:80px minmax(0,1fr)}.stlist .logo.sm{width:80px;height:80px}
}
.code-ai{margin-right:4px;line-height:normal}   /* same btn sm quiet look (and height) as the Icons button */
.aip-stf{font-size:12.5px;color:var(--muted);margin:12px 0 0;display:flex;flex-wrap:wrap;gap:6px;align-items:center}
.aip-stf code{font:12px var(--mono);color:var(--text)}
/* compact station filter bar: controls name themselves (placeholders / "any ..."), legends are screen-reader only */
.ctl .stf{align-items:center}
.ctl .stf .opt.bare{border:0;padding:0;margin:0;min-width:0}
.sel.prov{max-width:160px}
.sel{padding:0 8px;line-height:27px}
/* /pypi: the Python client page (release facts from <www>/search/pypi.json, built from the PyPI JSON API) */
.pypi-hero{display:grid;grid-template-columns:minmax(0,1fr) 260px;gap:8px 24px;align-items:center;padding:20px 22px;margin:8px 0 18px;overflow:hidden}
.pypi-hero h1{margin:0 0 4px}
.prose .pypi-hero h2{margin:16px 0 6px;border:0;padding:0}
.pypi-hero .lead{color:var(--accent);font:700 16px/1.4 Nunito,system-ui,sans-serif;margin:0 0 10px}
.pypi-hero .pypi-install{font-size:15px;margin:0}
.pypi-mascot{display:block;align-self:end}
.pypi-mascot img{display:block;width:260px;height:auto;filter:drop-shadow(0 10px 22px rgba(0,0,0,.35))}
@media (max-width:760px){.pypi-hero{grid-template-columns:1fr;text-align:center}.pypi-mascot{order:-1;justify-self:center;align-self:center}.pypi-mascot img{width:190px}.pypi-facts{justify-content:center}.pypi-hero .codehead{text-align:left}.pypi-hero .pypi-install{text-align:left}}
.pypi-facts{display:flex;flex-wrap:wrap;gap:6px 12px;align-items:center;margin:0;font-size:13px}
.pypi .codehead{margin-top:6px}
/* /legal mascot: sticky in the left gutter beside the text column (he points right, at the text); small above the
   heading on narrow screens. Decorative only. */
.legal-side{position:sticky;top:80px;height:0;z-index:1;pointer-events:none}
.legal-mascot{position:absolute;top:0;right:calc(100% + 18px);display:block;width:min(190px,calc(50vw - 460px));line-height:0;pointer-events:none}
.legal-mascot img{display:block;width:100%;max-width:none;height:auto}
/* /api mascot: sticky in the free gutter RIGHT of the 820px text column (mirror of the Legal one); on narrower
   screens a small static figure right-aligned above the text */
.api-side{position:sticky;top:80px;height:0;z-index:1;pointer-events:none}
.api-mascot{position:absolute;top:0;left:calc(100% + 18px);display:block;width:min(190px,calc(50vw - 420px));line-height:0;pointer-events:none}
.api-mascot img{display:block;width:100%;max-width:none;height:auto}
@media (max-width:1139px){.api-side{position:static;height:auto;display:flex;justify-content:flex-end}.api-mascot{position:static;width:104px;margin:0 0 -8px}}
@media (max-width:1139px){.legal-side{position:static;height:auto}.legal-mascot{position:static;width:104px;margin:0 0 6px}}
/* /docs mascot: beside the title/intro band, above the reference cards (never over them) */
/* /docs mascot: fixed bottom-right, 10px above the fixed footer and 10px from the window edge; decorative only */
.docs-mascot{position:fixed;right:10px;bottom:calc(var(--foot-h) + 10px);z-index:1050;width:138px;line-height:0;pointer-events:none}
.docs-mascot img{display:block;width:100%;max-width:none;height:auto}
@media (max-width:1023px){.docs-mascot{width:96px}}
@media (max-width:760px){.docs-mascot{display:none}}
/* /about mascot: cut-out, mirrored so his hard-cropped side is flush with the window's left edge and the crop at the
   bottom sits on the window's bottom edge (behind the fixed footer, which stays on top); text column to his right */
:root{--peek-w:min(42vw,620px)}
@media (max-width:1099px){:root{--peek-w:34vw}}
.about-peek{position:fixed;left:0;bottom:0;z-index:0;width:var(--peek-w);line-height:0;pointer-events:none}
.about-peek img{display:block;width:100%;max-width:none;height:auto}
.about-prose{position:relative;z-index:1}
@media (min-width:761px){main:has(.about-peek){margin-left:max(calc((100vw - 900px) / 2),calc(var(--peek-w) - 12px));margin-right:auto}}
@media (max-width:760px){.about-peek{display:none}}  /* phones: the text column is full width, he would cover it */
@media (max-width:374px){.topnav nav{gap:4px}.topnav nav a{font-size:11px;letter-spacing:-.01em}}
@media (max-width:420px){.prose code{overflow-wrap:anywhere}.prose>table.t{display:block;max-width:100%;overflow-x:auto}}
@media (max-width:380px){.langgrid{--tile:33px;--glyph:18px;--gap:5px}}   /* home tile rows of 8 stay on one line down to 320 px */
@media (max-width:340px){.langgrid{--tile:28px;--glyph:16px;--gap:4px}}
/* roadmap: About > Roadmap list and the /roadmap/<slug> coming-soon pages (text only, no third-party logos) */
.rm-badge{display:inline-block;font-size:.72em;font-weight:700;letter-spacing:.04em;text-transform:uppercase;padding:1px 7px;border-radius:999px;border:1px solid var(--border);color:var(--muted);vertical-align:.12em}
.rm-badge.done{color:var(--ok);border-color:currentColor}.rm-badge.now{color:var(--accent);border-color:currentColor}
ul.roadmap{list-style:none;padding-left:0}ul.roadmap li{margin:.55em 0}
.rm-status{margin:0 0 4px;color:var(--muted)}.rm-soon{font-size:.5em;font-weight:600;color:var(--accent);vertical-align:.35em;margin-left:6px;text-transform:uppercase;letter-spacing:.06em}
.rm-services{columns:2 220px;column-gap:28px}.rm-services li{break-inside:avoid}
.rm-note{margin-top:1.6em;font-size:.92em;color:var(--muted)}
