/* ============================================================================
   chess.gr · public brand stylesheet — served static (no build step needed).
   ----------------------------------------------------------------------------
   This is the LIVE port of the M-D3 signed-off hi-fi (M-RC3, 2026-06-11):

     [1] BASE   — ported from samples/m-d3/style.css (demo-only screens pruned;
                  the masthead search + nav are adapted from the demo's static
                  pill/▾ into the real <form>/<nav> the app renders).
     [2] THEME  — samples/m-d3/theme-cyan.css, the LOCKED "Cyan on White" layer,
                  applied verbatim AFTER the base so the cascade matches the
                  signed-off mockups exactly.
     [3] APP    — live-only additions the demos didn't need: the real masthead
                  search form, CSS nav dropdowns + mobile drawer, the search
                  as-you-type dropdown, and the CMS Divider/Board block styles
                  (moved here out of the base.twig inline <style>).

   Fonts (Inter + Space Grotesk) are loaded via <link> in base.twig. Greek body
   text renders in Inter; Space Grotesk has no Greek glyphs, so Greek headings
   fall back to Inter via the --disp stack — same as the signed-off mockups.
   ============================================================================ */

/* ========================================================================== */
/* [1] BASE — ported from style.css                                           */
/* ========================================================================== */
:root{
  --blue:#145398; --light:#2e74bc; --navy:#001e44; --grey:#7b858f;
  --ink:#16202c; --bg:#f6f8fb; --line:#e2e8f0; --chip:#e8f0fa;
  --sq-l:#e6edf5; --sq-d:#6f8fb3;
  --sans:"Inter",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
}
*{box-sizing:border-box}
body{margin:0;font-family:var(--sans);color:var(--ink);background:var(--bg);font-size:14px;line-height:1.5}
a{color:var(--blue);text-decoration:none}
a:hover{text-decoration:underline}
h1,h2,h3{margin:0}
img{max-width:100%}

/* masthead */
header.mast{background:#fff;border-bottom:1px solid var(--line)}
.mast .in{max-width:1440px;margin:0 auto;display:flex;align-items:center;justify-content:space-between;gap:24px;padding:12px 40px}
.site-brand{display:inline-flex;align-items:center;line-height:0}
.site-brand img{height:56px;width:auto}
nav.main{display:flex;gap:22px;flex-wrap:wrap;align-items:center}
nav.main a{color:var(--ink);font-weight:500;font-size:15px}
nav.main a.on{color:var(--blue)}

main{max-width:1440px;margin:0 auto;padding:30px 40px 56px}

/* boards (decorative hero / diagrams) */
.board{border-radius:6px;flex:none;background-image:
  linear-gradient(45deg,var(--sq-d) 25%,transparent 25%,transparent 75%,var(--sq-d) 75%),
  linear-gradient(45deg,var(--sq-d) 25%,var(--sq-l) 25%,var(--sq-l) 75%,var(--sq-d) 75%);}
.b248{width:248px;height:248px;background-size:62px 62px;background-position:0 0,31px 31px}
.b156{width:156px;height:156px;background-size:39px 39px;background-position:0 0,19.5px 19.5px}

/* hero */
/* The stage is 6 columns wide. The LAST one is reserved for the sold ad rail and is
   out of bounds for zones — always, whether or not the rail is switched on, so an
   editor can never reclaim the slot. `.hero-grid` therefore occupies columns 1–5 and
   declares 5 tracks of its own; reserving at the GRID level (not by clamping spans)
   is what stops a 1-wide zone auto-flowing into column 6. Matches
   HeroZoneService::TOTAL_COLS / GRID_COLS and the CMS builder canvas. */
.hero{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:20px;margin-bottom:34px}
.hero>.hero-grid{grid-column:1 / 6}
/* The hero modules (live board, puzzle) can't be resized individually, so the
   whole stage is scaled to 67% on desktop — it was too tall. `zoom` reflows
   (no empty gap) and keeps the live board's pointer mapping correct, unlike a
   transform. Left at natural size on mobile (where it's already small). */
@media(min-width:761px){.hero{zoom:var(--hero-scale,67%)}}
/* CMS draft-hero preview banner (internal preview of unpublished builder hero). */
.hero-draft-banner{position:sticky;top:0;z-index:60;display:flex;gap:12px;align-items:center;justify-content:center;flex-wrap:wrap;background:#0c7f99;color:#fff;padding:10px 16px;font-size:13px;text-align:center}
.hero-draft-banner strong{background:#fff;color:#0c7f99;padding:2px 8px;border-radius:4px;font-weight:700;letter-spacing:.04em}
/* Hero zone grid — MUST match the builder's grid (HeroZoneService::GRID_COLS = 6)
   so a layout designed in the CMS canvas renders the same on the homepage. Rows
   share the builder's ~124px (hero-builder.js ROWH) baseline but grow for real
   content. Reflows to 2 columns on small screens (zone spans clamp to fit). */
.hero-grid{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));grid-auto-rows:minmax(124px,auto);gap:20px}
/* Phones: the mosaic (col/row span) is a desktop concept — stack every module
   as ONE equal full-width column so nothing (e.g. the live zone) juts wider than
   its siblings. !important overrides each zone's inline grid-column/row:span N. */
@media(max-width:760px){.hero-grid{grid-template-columns:1fr;grid-auto-rows:auto}.hero-grid>.zone{grid-column:1 / -1 !important;grid-row:auto !important;padding:16px}}

/* ── Hero ad rail (sold banner column) ──────────────────────────────────────
   The rail must NEVER be reflowed away by the zone mosaic, so it is not a zone: it
   drops straight into the hero's reserved last column (declared above), as a sibling
   of `.hero-grid`. A single-row grid item, so it stretches to the zone grid's height.
   When the rail is off the column stays empty and reads as page background. */
.hero>.hero-ad{grid-column:6 / 7;grid-row:1}
/* The column's height is content-driven (the live board's row-span, the puzzle
   board, how many zones the Owner arranged), so it moves whenever the hero is
   re-arranged — and it differs per host. Rather than chase it with a per-layout
   creative spec, the artwork keeps its OWN ratio and the column's leftover height
   simply takes the PAGE background, so the unused strip reads as page, not as a
   truncated banner. That decouples the designer's spec from the hero layout: any
   1:N portrait PNG works, it is never cropped and never distorted.
   The rail paints NO background of its own — transparent means the leftover strip
   shows the page background by definition, so it stays right if the theme ever
   changes (`body` is re-painted #fff by the Cyan-on-White block further down). */
.hero-ad{position:relative;display:block;background:transparent}
/* All creatives occupy ONE grid cell — they stack, and opacity picks the winner. */
.hero-ad__slides{display:grid;grid-template-areas:"slide";list-style:none;margin:0;padding:0;width:100%}
.hero-ad__slide{grid-area:slide;opacity:0;pointer-events:none;transition:opacity .6s ease}
.hero-ad__slide.is-active{opacity:1;pointer-events:auto}
.hero-ad__link{display:block}
/* Scales to the column width at its natural ratio — whole image, no crop. */
.hero-ad__img{display:block;width:100%;height:auto;border-radius:14px}
@media(prefers-reduced-motion:reduce){.hero-ad__slide{transition:none}}
/* Phones: the hero stacks to one column, where a 1:3 portrait banner would be an
   absurd tower. Default is to drop the rail entirely (Owner-toggleable); when it
   IS shown it becomes a normal full-width block in the stack. */
@media(max-width:760px){
  /* Phones stack: no reserved column, no mosaic. Must restate
     grid-template-columns on `.hero > .hero-grid` — the desktop rule out-specifies
     the plain `.hero-grid` stacking rule above (a media query adds no specificity),
     so without this the grid keeps 5 dead columns. */
  .hero{grid-template-columns:1fr}
  .hero>.hero-grid{grid-column:1 / -1;grid-template-columns:1fr}
  .hero>.hero-ad{grid-column:1 / -1;grid-row:auto}
  .hero-ad--hide-mobile{display:none}
}

.row{display:grid;gap:20px}
.row1,.row2{grid-template-columns:840px 1fr}
.zone{border-radius:14px;padding:22px}
/* Orthogonal (square) corners — an author toggle per zone (add-hero-zone-square-
   corners). Squares the card AND its inner rounded media so the whole tile reads
   as sharp-cornered. */
.homepage-hero__zone--square,
.homepage-hero__zone--square .zone-card__img,
.homepage-hero__zone--square .hero-puzzle__board,
.homepage-hero__zone--square .board{border-radius:0}
/* Author text-size scale (add-hero-zone-font-size). --hero-font-scale (default 1)
   is set inline on the zone root; the editorial text blocks zoom to it — font +
   their own spacing scale together, boards/images/games are left untouched. At
   scale 1 this is identity. Consistent with the hero's own zoom:67%. */
.homepage-hero__zone .info,
.homepage-hero__zone .hero-puzzle__head,
.homepage-hero__zone .live-head{zoom:var(--hero-font-scale, 1)}
.zone-card{display:flex;flex-direction:column;gap:10px;height:100%;color:inherit;text-decoration:none}
/* Real <img>, so the element takes the image's own shape — whole image, no grey
   letterbox, no crop, no distortion. Scales to the card width at natural ratio. */
.zone-card__img{display:block;width:100%;height:auto;border-radius:10px}
/* The podcast zone's artwork is landscape and uncapped, so it grew with the zone's
   width — at a 3-column span it stood 367px tall and dragged its whole grid ROW
   (and therefore the puzzle zone beside it) with it. Cap the height and `cover` it:
   the artwork stays full-bleed across the card, trimmed top and bottom (Owner chose
   this over `contain`, which left the zone's cyan showing either side). NOTE the
   value is PRE-zoom — `.hero` carries `zoom:67%`, so 336px here paints as ~225px.
   Paired with the puzzle board cap below; the two zones share a row, so the taller
   one sets the height for both. */
.zone[data-content-type-key="podcast_episode"] .zone-card__img{max-height:336px;object-fit:cover}
/* Video posters are 4:3 files containing a 16:9 frame — YouTube letterboxes
   `hqdefault.jpg` with black bars. `height:auto` above would render those bars,
   which is the "thumbnail looks off in the hero card" that made the PODCAST zone
   use a drawn illustration instead. A 16:9 box + cover crops them off and uses
   the poster's full width. */
.zone[data-content-type-key="media_item"] .zone-card__img{aspect-ratio:16/9;height:auto;object-fit:cover}
/* Article hero card — FIXED height regardless of the subtitle. The image fills
   the card's flexible space (object-fit:cover), so setting a subtitle shrinks the
   image a touch instead of growing the whole module + its grid row. (Same
   height-control pattern as the podcast zone above.) Portrait cards keep their
   side-by-side layout. DESKTOP ONLY — on the single-column mobile hero the zones
   are grid-row:auto (no fixed height), where flex:1 1 0 would collapse the image
   to nothing, so there the natural-ratio image stays. */
@media(min-width:761px){
  .zone[data-content-type-key="news_article"] .zone-card:not(.zone-card--portrait) .zone-card__img{flex:1 1 0;min-height:0;object-fit:cover}
}
/* Portrait images (detected by hero-card-orient.js) flip the card to side-by-side
   so the tall image covers one side and the text sits on the other, instead of
   forcing a very tall stacked card. */
.zone-card--portrait{flex-direction:row;align-items:stretch}
.zone-card--portrait .zone-card__img{width:44%;height:auto;align-self:stretch;object-fit:cover}
.zone-card--portrait .info{flex:1 1 auto;align-self:center}
.zone-card:hover :is(h2,h3){text-decoration:underline}
.card-b{border:1px solid var(--line);background:#fff}
.z1{background:var(--navy);display:flex;gap:20px;align-items:center;min-height:320px}
.z1 .info{flex:1;color:#fff;display:flex;flex-direction:column;gap:10px}
.badge{display:inline-flex;align-items:center;gap:6px;background:#c0392b;color:#fff;font-weight:700;font-size:11px;border-radius:4px;padding:3px 9px;width:max-content}
.z1 .eyebrow{color:#80a4cf;font-weight:500;font-size:12px}
.z1 h2{font-size:20px;font-weight:700}
.z1 .meta{color:#a9c0dc;font-size:13px}
.player{display:flex;justify-content:space-between;align-items:center;background:#0a2f5e;border-radius:7px;padding:8px 12px}
.player .nm{font-weight:600;font-size:14px} .player .clk{color:#cdd9ee;font-weight:500;font-size:13px}
.z1 .watch{color:#80a4cf;font-weight:600;font-size:13px;margin-top:2px}
.z2{background:var(--blue);color:#fff;display:flex;flex-direction:column;justify-content:center;gap:6px}
.z2 .eyebrow{color:#9dc0e8;font-weight:700;font-size:11px}
.z2 h3{font-size:19px;font-weight:700} .z2 .meta{color:#cfe0f4;font-size:13px}
.z2 .lk,.z5 .lk{color:#fff;font-weight:600;font-size:13px;margin-top:2px}
.z4{display:flex;gap:14px;align-items:center}
.thumb{width:120px;height:80px;border-radius:8px;background:var(--navy);flex:none;display:flex;align-items:center;justify-content:center}
.thumb .play{width:34px;height:34px;border-radius:50%;background:#fff;display:flex;align-items:center;justify-content:center}
.thumb .play::after{content:"";border-left:11px solid var(--navy);border-top:7px solid transparent;border-bottom:7px solid transparent;margin-left:3px}
.eyebrow{color:var(--grey);font-weight:700;font-size:10.5px;letter-spacing:.3px}
.z4 h3{font-size:15px;font-weight:600;margin:4px 0} .z4 .meta{color:var(--grey);font-size:12px}
.z3{background:#fff;display:flex;gap:20px;align-items:center;min-height:200px}
.z3 .info{display:flex;flex-direction:column;gap:9px}
.z3 h3{font-size:19px;font-weight:600} .z3 .diff{color:var(--grey);font-size:13px;font-weight:500}
.btn{background:var(--blue);color:#fff;font-weight:600;font-size:13px;border-radius:8px;padding:9px 16px;width:max-content;display:inline-block;border:0;cursor:pointer;text-decoration:none}
.btn:hover{text-decoration:none}
.btn.ghost{background:#fff;color:var(--blue);border:1px solid var(--blue)}
.z5{background:var(--light);color:#fff;display:flex;flex-direction:column;justify-content:center;gap:8px}
.z5 .k{color:#d4e4f6;font-weight:700;font-size:13px} .z5 .big{font-weight:900;font-size:26px;line-height:1.1}

/* section heads */
.sec-head{display:flex;justify-content:space-between;align-items:center;margin:30px 0 16px}
.sec-head h2{color:var(--navy);font-size:22px;font-weight:700}
.sec-head a{font-weight:600;font-size:14px}

/* news grid */
.news{display:grid;grid-template-columns:repeat(3,1fr);gap:20px}
/* Homepage «Πρόσφατα νέα»: one-row horizontal scroller — ~5 cards visible, the rest
   reachable by scrolling right. Card min-width keeps them readable + the row
   scrollable on narrower screens; a slim cyan scrollbar cues the overflow. Padding
   gives the cards' hover lift/shadow room within the clipped scroll area. */
.news--row{display:flex;gap:16px;overflow-x:auto;overflow-y:hidden;padding:16px 4px 18px;scrollbar-width:thin;scrollbar-color:var(--cyan) #e6eef4;-webkit-overflow-scrolling:touch}
/* Cards visible at once. `--cols` is set inline per category module
   (/cms/homepage-sections `per_row`); the main «Πρόσφατα νέα» row inherits the 5
   default. N cards + N-1 gaps of 16px fill the track exactly.
   min-width is a READABILITY FLOOR, and it wins over the computed basis — at 200px
   the whole 2..6 `per_row` range fits the 1352px desktop track (6 cards → 212px).
   On narrower viewports the floor takes over, fewer cards show, and the carousel
   just scrolls further; a 220px floor silently capped `per_row:6` at 5 cards. */
.news--row{--cols:5}
.news--row .ncard{flex:0 0 calc((100% - (var(--cols) - 1) * 16px) / var(--cols));min-width:200px}
.news--row::-webkit-scrollbar{height:10px}
.news--row::-webkit-scrollbar-track{background:#e9f0f5;border-radius:8px}
.news--row::-webkit-scrollbar-thumb{background:var(--cyan);border-radius:8px;border:2px solid #e9f0f5}
.news--row::-webkit-scrollbar-thumb:hover{background:var(--cyan-d)}
/* Paging arrows for the horizontal scrollers (scroll-arrows island). Large circular
   prev/next buttons overlaying the row edges; each pages by the visible-card count.
   Hidden on touch widths, when there's no overflow, and at the respective end. */
.scroller{position:relative;padding-inline:56px}
.scroller__btn{position:absolute;top:calc(50% - 7px);transform:translateY(-50%);z-index:6;display:flex;align-items:center;justify-content:center;width:50px;height:50px;border-radius:50%;border:1px solid var(--line);background:rgba(255,255,255,.96);color:var(--navy);box-shadow:0 8px 24px rgba(15,40,80,.18);cursor:pointer;transition:background .12s,color .12s,border-color .12s,opacity .15s}
.scroller__btn:hover{background:var(--cyan);color:#04222b;border-color:var(--cyan)}
.scroller__btn--prev{left:2px}
.scroller__btn--next{right:2px}
.scroller.no-overflow .scroller__btn{opacity:0;pointer-events:none}
@media (max-width:760px){.scroller__btn{display:none}.scroller{padding-inline:0}}
.ncard{background:#fff;border:1px solid var(--line);border-radius:12px;overflow:hidden}
.ncard > a{color:inherit;text-decoration:none;display:block}
.ncard .img{height:150px;background:#eef3f9;overflow:hidden;display:flex;align-items:center;justify-content:center} /* whole image visible (contain), smaller fixed height — was a large cropped 3:2 box */
.ncard .img:empty{display:none}
.ncard .img img{max-width:100%;max-height:100%;width:auto;height:auto;object-fit:contain;display:block}
/* Surfaces with no artwork (resources) — a branded cyan tile with the chess.gr mark,
   so a card keeps the same height as an illustrated one and the carousel stays even. */
.ncard .img--placeholder{background:linear-gradient(135deg,var(--cyan,#0fa3c4),var(--navy,#001e44))}
.ncard .img--placeholder img{width:52px;height:52px;max-width:52px;opacity:.9;filter:brightness(0) invert(1)}
.ncard .body{padding:14px 16px 16px}
.cat{display:inline-block;background:var(--chip);color:var(--blue);font-weight:700;font-size:10.5px;border-radius:4px;padding:3px 8px;margin-bottom:8px}
.ncard h3{font-size:16px;font-weight:600;line-height:1.3;margin-bottom:6px}
.ncard p{margin:0 0 8px;color:#5d6b7a;font-size:13px}
/* «Πρόσφατα νέα» card pills — clickable category labels + tags (card is no longer
   one big anchor; the thumbnail + title are the article links). */
.ncard__title{color:inherit;text-decoration:none}
.ncard__title:hover{color:var(--cyan-d)}
.ncard__cats{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px}
.ncard__cats .cat{margin-bottom:0;text-decoration:none;transition:background .12s,color .12s}
.ncard__cats .cat:hover{background:var(--cyan);color:#04222b}
.ncard__tags{display:flex;flex-wrap:wrap;gap:6px;margin:10px 0 0}
.ncard__tags a{background:#eef2f7;color:var(--grey);font-size:11.5px;border-radius:12px;padding:3px 9px;text-decoration:none;transition:background .12s,color .12s}
.ncard__tags a:hover{background:var(--cyan);color:#04222b}
.by{color:var(--grey);font-size:12px;font-weight:500}

/* secondary news (compact list) */
.snews{display:grid;grid-template-columns:repeat(3,1fr);gap:14px 26px}
.scard{display:flex;gap:12px;align-items:flex-start;padding:10px 0;border-top:1px solid var(--line)}
.scard > a{display:flex;gap:12px;align-items:flex-start;color:inherit;text-decoration:none}
.scard .th{width:72px;aspect-ratio:3/2;border-radius:6px;background:linear-gradient(135deg,#c9d6e8,#dde7f2);flex:none;overflow:hidden}
.scard .th img{width:100%;height:100%;object-fit:cover;display:block}
.scard h4{margin:0;font-size:13.5px;font-weight:600;line-height:1.3}
.scard .by{margin-top:3px}

/* horizontal rails (tournaments / podcast / eshop / courses) */
.rail{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(240px,1fr);gap:16px;overflow-x:auto;padding-bottom:4px}
/* «Πρόσφατα podcast»: exactly 3 cards visible, the rest reachable by scrolling /
   the paging arrows (max() keeps them ≥240px, so narrow screens show fewer + scroll). */
.homepage-podcasts .rail{grid-auto-columns:max(240px, calc((100% - 32px) / 3))}
.rcard{background:#fff;border:1px solid var(--line);border-radius:12px;padding:16px;min-width:240px}
.rcard > a{color:inherit;text-decoration:none;display:block}
.rcard .k{font-weight:700;font-size:10.5px;color:var(--grey);letter-spacing:.3px}
.rcard h4{margin:6px 0 4px;font-size:15px;font-weight:600}
.rcard .meta{color:var(--grey);font-size:12.5px}
.rcard .cover{height:110px;border-radius:8px;background:linear-gradient(135deg,#001e44,#145398);margin:-2px 0 12px}
/* Πρόσφατα podcasts: the brand podcast illustration (same as the hero zone). */
.homepage-podcasts .rcard .cover{overflow:hidden}
.homepage-podcasts .rcard .cover img{width:100%;height:100%;object-fit:cover;display:block}

/* calendar / tournaments listing */
.toolbar{display:flex;flex-wrap:wrap;gap:10px;align-items:center;background:#fff;border:1px solid var(--line);border-radius:12px;padding:12px 14px;margin-bottom:16px}
.toolbar .fl{font-weight:700;font-size:11px;color:var(--grey);letter-spacing:.4px;margin-right:4px}
.pill{background:#f1f5f9;border:1px solid var(--line);border-radius:18px;padding:7px 13px;font-size:13px;color:var(--ink);white-space:nowrap}
.cal-list{background:#fff;border:1px solid var(--line);border-radius:12px;overflow:hidden}
.cal-row{display:grid;grid-template-columns:84px 1fr 150px 130px 110px;gap:14px;align-items:center;padding:14px 18px;border-top:1px solid var(--line)}
.cal-row:first-child{border-top:0}
.cal-row > a{display:contents;color:inherit;text-decoration:none}
.cal-row .d{text-align:center;background:var(--bg);border-radius:8px;padding:6px 0}
.cal-row .d .day{font-weight:800;font-size:18px;color:var(--navy);line-height:1}
.cal-row .d .mon{font-size:11px;color:var(--grey);text-transform:uppercase}
.cal-row .nm{font-weight:600;font-size:15px}
.cal-row .nm small{display:block;color:var(--grey);font-weight:400;font-size:12px}
.cal-row .ven{color:var(--ink);font-size:13px}
.tag{display:inline-block;border-radius:5px;padding:2px 8px;font-size:11px;font-weight:700}
.tag.open{background:#e7f3ec;color:#2c6e49} .tag.soon{background:var(--chip);color:var(--blue)} .tag.live{background:#fdeaea;color:#c0392b}
.split{display:grid;grid-template-columns:1fr 460px;gap:16px}
.map{background:#dfe7f1;border:1px solid var(--line);border-radius:12px;min-height:480px;position:relative;overflow:hidden;
  background-image:linear-gradient(0deg,rgba(123,133,143,.18) 1px,transparent 1px),linear-gradient(90deg,rgba(123,133,143,.18) 1px,transparent 1px);background-size:38px 38px}
.map .pin{position:absolute;width:16px;height:16px;border-radius:50% 50% 50% 0;background:var(--blue);transform:rotate(-45deg);border:2px solid #fff;box-shadow:0 1px 4px rgba(0,0,0,.3)}
.map .lbl{position:absolute;top:12px;left:12px;background:#fff;border:1px solid var(--line);border-radius:8px;padding:6px 10px;font-size:12px;color:var(--grey)}

/* article */
.crumb{color:var(--grey);font-size:13px;margin-bottom:14px}
.article{display:grid;grid-template-columns:minmax(0,1fr) 200px;gap:34px;align-items:start}
/* Reader "hide the side rail" — a per-visitor UX toggle (rail-toggle.js). The
   `no-rail` class rides <html> (set pre-paint from localStorage, then toggled
   live), so an ancestor selector matches. Both halves are needed — hiding the
   aside AND collapsing the second track — so the body reclaims the 200px + gap
   rather than leaving an empty column. */
.no-rail .rail-side{display:none}
.no-rail .article{grid-template-columns:minmax(0,1fr)}
/* The toggle is a vertical DRAWER TAB hanging off the right edge of the article
   (rail-toggle.js sets its `left`), centred in the viewport and fixed so it stays
   put as the reader scrolls. Present in both states so it can bring the rail
   back. Hidden on mobile where the rail already stacks under the body. */
.rail-drawer{position:fixed;top:50%;transform:translateY(-50%);z-index:30;
  width:22px;height:72px;padding:0;display:flex;align-items:center;justify-content:center;
  background:#fff;border:1px solid var(--line);border-left:none;border-radius:0 9px 9px 0;
  box-shadow:5px 0 16px rgba(20,40,80,.10);cursor:pointer;color:var(--cyan-d,#0c7f99)}
.rail-drawer:hover{background:var(--cyan-bg,#e6f7fb)}
.rail-drawer__chev{font-size:17px;font-weight:700;line-height:1}
@media(max-width:1180px){.rail-drawer{display:none}}
/* Grid items default to min-width:auto (min-content), so a wide child (a sized
   image, a PGN board) forces the column past the track. Let them shrink to the
   track so the article never exceeds the screen. */
.article>*{min-width:0}
.article h1{font-family:var(--disp);font-size:31px;font-weight:700;color:#101822;line-height:1.16;letter-spacing:-.4px;margin-bottom:6px}
.article .lead{font-size:18px;color:#3a4654;margin-bottom:18px}
/* byline — batch2 compass: small grey meta closed by a hairline rule */
.public-news-show__meta{font-size:12.5px;color:var(--grey);margin:0 0 22px;padding-bottom:14px;border-bottom:1px solid var(--line)}
.article .feat{border-radius:14px;background:linear-gradient(135deg,#001e44,#2e74bc);margin-bottom:8px;overflow:hidden}
.article .feat img{display:block;width:100%;height:auto}
.article .feat--ph{height:360px}
.article .credit{color:var(--grey);font-size:12px;margin:7px 0 22px;text-align:right}
.article .body p{font-size:16px;line-height:1.7;color:#2a323b;margin:0 0 16px}
.article .body h2{font-size:21px;font-weight:600;color:var(--ink);margin:28px 0 10px}
.article .body h3{font-size:17px;font-weight:600;color:var(--ink);margin:22px 0 8px}
.article .body img{border-radius:8px;max-width:100%;height:auto}
/* CSV table block — a general data table in the article body (scrolls on mobile). */
.csv-table{overflow-x:auto;margin:22px 0;-webkit-overflow-scrolling:touch}
.csv-table__tbl{border-collapse:collapse;width:100%;font-size:14px;line-height:1.45}
.csv-table__tbl th,.csv-table__tbl td{border:1px solid var(--line);padding:8px 12px;text-align:left;vertical-align:top}
.csv-table__tbl thead th{background:var(--chip,#eef4f7);font-weight:700;color:var(--ink,#101822);white-space:nowrap}
.csv-table__tbl tbody tr:nth-child(even){background:#f7fafc}
/* Spacer block — one empty line; margin zeroed so each block is exactly one
   line's height (stack several for a bigger gap). */
.body-spacer{margin:0}
/* Rich table block — a styled "spreadsheet" table (per-cell colours via inline
   style; border toggle + colour via .rich-table--bordered + --rt-border). */
.rich-table{overflow-x:auto;margin:22px 0;-webkit-overflow-scrolling:touch}
.rich-table__tbl{border-collapse:collapse;width:100%;font-size:14px;line-height:1.45}
.rich-table__tbl th,.rich-table__tbl td{padding:8px 12px;text-align:left;vertical-align:top}
.rich-table__tbl thead th{font-weight:700;color:var(--ink,#101822)}
.rich-table--bordered .rich-table__tbl th,.rich-table--bordered .rich-table__tbl td{border:1px solid var(--rt-border,var(--line))}
/* PGN viewer (pgn/ engine) — SVG board + move list + nav. Theming via
   --pgnv-light/--pgnv-dark CSS vars. Shared by article embeds + editor preview. */
.pgnv{font-size:14px;margin:18px 0}
.pgnv-main{display:flex;gap:16px;flex-wrap:wrap;align-items:flex-start}
.pgnv-board-wrap{width:min(360px,100%);flex:0 0 auto;position:relative}
/* No touch-action at all: this board is `role="img"` and binds no pointer
   handler anywhere on the public side (moves are entered from the move list,
   never on the board). `none` only made a near-full-width diagram a scroll
   dead zone on a phone; the default also leaves double-tap zoom, which is
   worth having on a diagram. The editor copy in cms.css differs — the studio
   board IS an input surface. */
.pgnv-board{width:100%;height:auto;display:block;border-radius:6px}
/* Variation chooser — a small overlay centred on the board at a branch point.
   The board-wrap is position:relative (sticky in reader modes, also positioned)
   so this anchors to the board in every layout. */
.pgnv-branch{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);z-index:6;
  min-width:190px;max-width:94%;background:#fff;color:var(--ink,#16202c);
  border:1px solid #bfe3ec;border-radius:11px;padding:8px;
  box-shadow:0 16px 42px rgba(15,163,196,.24);font-size:14px}
.pgnv-branch__h{font-weight:700;font-size:11px;letter-spacing:.03em;text-transform:uppercase;
  color:var(--cyan-d,#0c7f99);padding:2px 6px 7px}
.pgnv-branch__list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:1px}
.pgnv-branch__item{display:flex;align-items:center;gap:9px;padding:6px 9px;border-radius:7px;cursor:pointer;line-height:1.2}
.pgnv-branch__item.is-sel{background:var(--cyan-bg,#e6f7fb)}
.pgnv-branch__item.is-sel .pgnv-branch__mv{color:var(--cyan-d,#0c7f99)}
.pgnv-branch__n{color:#8a94a0;min-width:26px;font-variant-numeric:tabular-nums}
.pgnv-branch__mv{font-weight:650}
.pgnv-branch__tag{margin-left:auto;font-size:10.5px;color:#9aa4af}
.pgnv-branch__hint{font-size:10.5px;color:#9aa4af;border-top:1px solid #eef4f7;margin-top:5px;padding:6px 6px 2px}
.pgnv-sq.pgnv-lt{fill:var(--pgnv-light,#e9f6fb)}
.pgnv-sq.pgnv-dk{fill:var(--pgnv-dark,#4a97ad)}
.pgnv-last{fill:#f6d34d;opacity:.5}
.pgnv-check{fill:#e5484d;opacity:.5}
.pgnv-co{fill:#00000066;font-size:.22px;pointer-events:none}
.pgnv-co-r{text-anchor:start}.pgnv-co-f{text-anchor:end}
.pgnv-pc{pointer-events:none}
.pgnv-side{flex:1 1 220px;min-width:200px;display:flex;flex-direction:column;gap:8px}
.pgnv-picker{padding:5px 8px;border:1px solid var(--line,#d9e2ec);border-radius:7px;font:inherit}
.pgnv-picker[hidden]{display:none}
/* round picker sits above the game list on multi-round (whole-tournament) PGNs */
.pgnv-rounds{font-weight:700;color:var(--pgnv-dark,#0c7f99)}
.pgnv-moves{max-height:320px;overflow:auto;line-height:1.75}
/* Stacked NAG symbol (compensation, $44-47): infinity over an equals sign.
   No precomposed character exists, so it is two lines crushed to roughly the
   height of one, sitting on the text baseline. Mirrored in cms.css. */
.pgnv-nagx{display:inline-flex;flex-direction:column;align-items:center;
  font-size:.72em;line-height:.76;font-style:normal;font-weight:600;
  /* `middle` centres the two-line box on the parent's x-height, so the symbol
     sits ON the text instead of hanging off the baseline as a subscript. */
  vertical-align:middle;margin-left:.14em}
.pgnv-nagx i{font-style:normal;display:block}
.pgnv-mv{cursor:pointer;padding:0 2px;border-radius:4px;font-weight:600}
.pgnv-mv:hover{background:#00000010}
.pgnv-mv.on{background:var(--pgnv-dark,#0c7f99);color:#fff}
.pgnv-var{color:#5b7280;font-style:italic}
.pgnv-var .pgnv-mv{font-weight:500}
.pgnv-cm{color:#3a4a5a}
.pgnv-mt{width:100%;border-collapse:collapse}
.pgnv-mt td{padding:1px 5px;vertical-align:top}
.pgnv-mt-no{color:#8393a0;text-align:right;width:2em}
.pgnv-mt-x{font-size:.92em;color:#5b7280}
/* The toolbar sits INSIDE the board column (mount.js), so it is bounded by the
   board's width, not the viewer's — it wraps rather than overflowing on a
   narrow board. Being in that column is what keeps it against the board's
   bottom edge when the engine makes the move-list column taller. */
.pgnv-bar{display:flex;flex-wrap:wrap;gap:4px;margin-top:10px}
.pgnv-nav{cursor:pointer;font-size:14px;line-height:1;padding:6px 10px;border:1px solid var(--line,#d9e2ec);background:#fff;border-radius:7px}
.pgnv-nav:hover:not(:disabled){background:#f0f6f8}
.pgnv-nav:disabled{opacity:.4;cursor:default}
.pgnv-error{font-size:13px}
.pgnv-raw{white-space:pre-wrap;background:#f7fafc;border:1px solid #e3edf1;border-radius:6px;padding:8px;max-height:200px;overflow:auto;font-size:12px}
.pgnv-moves--tree .pgnv-tl{padding:1px 0}
.pgnv-tbranch{display:flex;gap:4px;margin:2px 0 2px 14px;border-left:2px solid #e3edf1;padding-left:6px}
.pgnv-ttog{flex:0 0 auto;cursor:pointer;border:none;background:none;color:#8393a0;font-size:11px;line-height:1.7;padding:0}
.pgnv-tbody{flex:1 1 auto;color:#5b7280;font-style:italic}
.pgnv-tbody .pgnv-mv{font-weight:500}
.pgnv-warn{margin:0 0 10px;font-size:12.5px;border:1px solid #f0d8a8;background:#fff8ec;border-radius:8px;padding:6px 10px;color:#8a5a00}
.pgnv-warn summary{cursor:pointer;font-weight:600}
.pgnv-errs{margin:6px 0 0;padding-left:18px}
.pgnv-error .pgnv-errs{color:#b91c1c}
.embed{border:1px dashed #b9c6d8;border-radius:12px;background:#fff;padding:18px;color:var(--grey);font-size:13px;margin:22px 0;text-align:center}
/* analytics-consent §10.3 — third-party embed consent facade (click-to-load). */
.embed--loaded{border-style:solid;border-color:var(--line);padding:0;overflow:hidden}
.embed__facade{display:flex;flex-direction:column;align-items:center;gap:8px;padding:8px}
.embed__provider{font-family:var(--disp);font-weight:700;font-size:14px;color:var(--navy)}
.embed__note{margin:0;max-width:48ch;font-size:12.5px;color:var(--grey);line-height:1.5}
.embed__load{appearance:none;cursor:pointer;border:0;border-radius:8px;background:var(--cyan-d,#0c7f99);color:#fff;font-weight:600;font-size:13.5px;padding:9px 16px}
.embed__load:hover{background:var(--navy,#001a3d)}
.embed__load:focus-visible{outline:3px solid var(--cyan,#0fa3c4);outline-offset:2px}
.embed__direct{font-size:12.5px;color:var(--cyan-d,#0c7f99)}
.embed__frame{display:block;width:100%;aspect-ratio:16/9;height:auto;border:0}
.embed--facebook .embed__frame,.embed--twitter .embed__frame{aspect-ratio:auto;min-height:420px}
/* Facebook/Twitter have a natural plugin width. Cap them so the block-alignment
   classes (margin-inline:auto) can actually center/right them — a full-width
   embed has nothing to align. The FB post plugin renders at exactly 500px; with
   box-sizing:border-box + 1px border, 502px makes the loaded iframe exactly 500
   so it hugs the post (no empty strip / "extra border" on the right). */
.embed--facebook{max-width:502px}
.embed--twitter{max-width:550px}
/* video size caps (YouTube/Vimeo): full = column width (default, no cap). Pair
   with .align-center for a centred, sized player. */
.embed--small{max-width:400px}
.embed--medium{max-width:560px}
.embed--large{max-width:760px}
/* Homepage "Live streams" section — up to 3 YouTube embeds (CMS-toggled).
   Reuses the .embed / .embed__frame consent-facade styling above; this only
   lays the row out (1–3 responsive columns) and captions each stream. */
.home-streams{margin:26px 0}
/* Left-packed, capped so each 16:9 video is ~335px wide (≈1/4 the surface of a
   full-column embed) instead of stretching to fill the row. Inset to match the
   card columns of the news/category rows around it: those are horizontal
   scrollers wrapped in .scroller (padding-inline:56px, for the arrow buttons)
   plus the row's own 4px — 60px total. The streams grid isn't a scroller, so it
   would otherwise sit 60px to the left. Mirror the scroller's 760px breakpoint. */
.home-streams__grid{display:flex;flex-wrap:wrap;gap:18px;padding-inline:60px}
@media (max-width:760px){.home-streams__grid{padding-inline:4px}}
.home-streams__item{flex:0 1 335px;max-width:335px;min-width:0}
.home-streams__item .embed{margin:0}
.home-streams__title{margin:8px 2px 0;font-size:14px;font-weight:600;line-height:1.35;color:var(--ink)}
/* eshop-referral §13.3 — stock-aware referral product cards. */
.product-card .cover{position:relative}
.product-card .cover img{width:100%;height:100%;object-fit:cover;display:block}
.product-card__badge{position:absolute;top:8px;left:8px}
/* Backorder reads as "orderable, just slower" — amber, not the alarm colour the
   out-of-stock badge carries, since the product IS still buyable. */
.product-card__badge--backorder{background:#8a5a00;color:#fff}
.product-card__author{color:var(--grey);font-size:12.5px;margin:2px 0 0}
.product-card__price{font-weight:700;color:var(--navy);font-size:15px;margin:8px 0 0}
.product-card__cta{display:inline-block;margin-top:8px;font-size:12.5px;font-weight:600;color:var(--cyan-d,#0c7f99)}
.product-card--discontinued{opacity:.62}
.product-card__inert{display:block;cursor:not-allowed}
.public-eshop-show__disclaimer{color:var(--grey);font-size:12.5px;margin:0 0 18px}

/* analytics-consent §10.4 — informational cookie notice (not a wall). */
.cookie-notice{position:fixed;left:16px;right:16px;bottom:16px;z-index:50;max-width:760px;margin:0 auto;display:flex;gap:14px;align-items:center;justify-content:space-between;flex-wrap:wrap;background:var(--navy,#001a3d);color:#eaf4f8;border-radius:12px;padding:14px 18px;box-shadow:0 12px 36px rgba(0,20,48,.28)}
.cookie-notice__text{margin:0;font-size:13px;line-height:1.5;flex:1 1 360px}
.cookie-notice__text a{color:var(--cyan,#7fd6ea);font-weight:600}
.cookie-notice__dismiss{appearance:none;cursor:pointer;border:0;border-radius:8px;background:var(--cyan,#0fa3c4);color:#04222b;font-weight:700;font-size:13px;padding:9px 18px;white-space:nowrap}
.cookie-notice__dismiss:hover{background:#fff}
.cookie-notice__dismiss:focus-visible{outline:3px solid #fff;outline-offset:2px}
/* Phones: slimmer notice — smaller type, tighter padding, wider (less side
   margin) so the disclosure wraps to fewer lines and reserves less of the fold. */
@media(max-width:760px){
  /* Phones: take the notice OUT of fixed positioning so it never floats over the
     fold (it was covering /live & /puzzle controls, the /contact submit, the map
     canvas — mobile-audit finding #1). It rides in normal flow at page end
     (after the footer) instead — still ships visible + JS-dismissible. A fixed
     banner inherently covers mid-scroll content; only leaving the layer fixes it.
     cookie-notice.js reserves body padding ONLY while the notice is fixed, so
     there's no phantom gap here. */
  .cookie-notice{position:static;max-width:none;margin:0;border-radius:0;box-shadow:none;gap:8px;padding:12px 16px}
  .cookie-notice__text{font-size:12px;line-height:1.4}
  .cookie-notice__dismiss{padding:8px 16px;font-size:12px}
}
.rail-side{position:sticky;top:84px;background:#fff;border:1px solid var(--line);border-radius:12px;padding:16px}
.rail-side h4{font-size:12px;text-transform:uppercase;letter-spacing:.5px;color:var(--grey);margin-bottom:10px}
.rail-side .it{padding:8px 0;border-top:1px solid var(--line)}
.rail-side .it:first-of-type{border-top:0}
.rail-side .it b{font-size:13px;font-weight:600;display:block} .rail-side .it span{color:var(--grey);font-size:12px}
.rail-side .rail-logo{display:block;padding-bottom:14px;margin-bottom:4px;border-bottom:1px solid var(--line);text-align:center}
.rail-side .rail-logo img{display:inline-block;width:88%;max-width:240px;height:auto}
/* Long unbreakable URLs (image credits, links) must wrap, not force the column
   wide (a min-content blowout the minmax(0,1fr) above already guards against). */
.article .credit,.article .body,.article figcaption{overflow-wrap:anywhere}
/* Phones: stack the article — main content over the rail — so nothing is forced
   past the screen. Without this the 2-column grid stayed on mobile and the
   viewport zoomed out to fit it. The single track keeps the 0 min so wide media
   (figures, PGN boards) shrink to fit instead of blowing the layout out. */
@media(max-width:760px){
  .article{grid-template-columns:minmax(0,1fr);gap:22px}
  .article .rail-side{position:static;top:auto}
  /* Phones only: the fixed-px image-size presets (small/medium/large =
     300/480/640) can exceed the screen — cap every sized image + its credit to
     the column width here (!important beats the higher-specificity presets),
     leaving the desktop presets untouched. */
  .article .feat img,.article .body figure img,.article .credit{max-width:100%!important}
}
.shop{border:1px solid var(--blue);background:var(--chip);border-radius:12px;padding:16px 18px;margin:24px 0;display:flex;justify-content:space-between;align-items:center;gap:16px}
.tags{display:flex;gap:8px;flex-wrap:wrap;margin:8px 0 26px}
.tags span{background:#eef2f7;color:var(--grey);font-size:12px;border-radius:14px;padding:4px 11px}
/* Clickable rail tags/categories on the article page — mirror the card pills. */
.tags a{background:#eef2f7;color:var(--grey);font-size:12px;border-radius:14px;padding:4px 11px;text-decoration:none;transition:background .12s,color .12s}
.tags a:hover{background:var(--cyan);color:#04222b}
.public-news-show__cats{margin:0 0 8px}
.public-news-show__cats .cat{margin-bottom:0;text-decoration:none;transition:background .12s,color .12s}
.public-news-show__cats .cat:hover{background:var(--cyan);color:#04222b}
.public-news-index__tags{margin:8px 0 0}

/* News category filter bar (news-filter island) — 3-state chips: neutral →
   include → exclude. Chips are <a> links (server-rendered toggle hrefs); the
   island hijacks clicks to fetch the results fragment. */
/* On-demand disclosures (Φίλτρα + Ημερομηνίες). A visually-hidden checkbox per
   panel drives a pure-CSS toggle: the trigger LABELS stay in a fixed row while the
   panel BODIES (real siblings, flex-basis:100%) drop to their own full-width line
   below when their checkbox is checked — so a toggle never moves the buttons. */
.news-filter__controls{display:flex;flex-wrap:wrap;gap:8px 10px;align-items:flex-start;margin:0 0 8px}
.news-filter__cb{position:absolute;width:1px;height:1px;opacity:0;margin:0;pointer-events:none}
.news-filter__panel-body{flex-basis:100%;width:100%;margin:0;display:none}
#nf-cat:checked ~ [data-filter-body]{display:block}
#nf-date:checked ~ [data-date-body]{display:flex}
#nf-q:checked ~ [data-q-body]{display:flex}
#nf-cat:checked ~ [data-filter-summary]::after,
#nf-date:checked ~ [data-date-summary]::after,
#nf-q:checked ~ [data-q-summary]::after{transform:rotate(180deg)}
#nf-cat:focus-visible ~ [data-filter-summary],
#nf-date:focus-visible ~ [data-date-summary],
#nf-q:focus-visible ~ [data-q-summary]{outline:2px solid var(--cyan);outline-offset:1px}
/* Date-range + search panels — become a flex row only when shown. */
.news-datefilter__form,.news-search__form{flex-wrap:wrap;align-items:flex-end;gap:10px 14px}
.news-search__input{flex:1 1 260px;min-width:180px;border:1px solid var(--line);border-radius:8px;padding:7px 12px;font:inherit;font-size:14px;background:#fff;color:var(--ink)}
.news-search__input:focus{outline:none;border-color:var(--cyan);box-shadow:0 0 0 3px rgba(15,163,196,.15)}
.news-datefilter__field{display:flex;flex-direction:column;gap:4px}
.news-datefilter__field > span{font-size:11px;color:var(--grey);font-weight:600}
.news-datefilter__field input{border:1px solid var(--line);border-radius:8px;padding:6px 10px;font:inherit;font-size:13px;background:#fff;color:var(--ink)}
.news-datefilter__field input:focus{outline:none;border-color:var(--cyan);box-shadow:0 0 0 3px rgba(15,163,196,.15)}
.news-datefilter__apply{border:0;border-radius:8px;background:var(--cyan);color:#04222b;font:inherit;font-size:13px;font-weight:700;padding:7px 16px;cursor:pointer}
.news-datefilter__apply:hover{background:var(--cyan-d);color:#fff}
.news-datefilter__clear{font-size:12.5px;color:var(--grey);text-decoration:none}
.news-datefilter__clear:hover{color:#c0392b}
.news-datefilter__clear.is-hidden{display:none}
.news-filter__toggle{display:inline-flex;align-items:center;gap:6px;width:max-content;cursor:pointer;list-style:none;user-select:none;font-size:12px;font-weight:600;color:var(--grey);background:#fff;border:1px solid var(--line);border-radius:13px;padding:4px 11px;transition:background .12s,border-color .12s,color .12s}
.news-filter__toggle::-webkit-details-marker{display:none}
.news-filter__toggle::after{content:"▾";font-size:9px;transition:transform .12s}
.news-filter__panel[open] .news-filter__toggle::after{transform:rotate(180deg)}
.news-filter__toggle:hover{border-color:var(--cyan);color:var(--cyan-d)}
.news-filter__toggle.is-active{background:#eef7fa;border-color:#a9d8e4;color:#0a6273}
.news-filter__bar{display:flex;gap:6px;flex-wrap:wrap;margin:0 0 8px}
.news-filter__chip{display:inline-flex;align-items:center;gap:5px;padding:3px 9px;border:1px solid var(--line);border-radius:13px;background:#fff;color:var(--grey);font-size:11.5px;font-weight:500;text-decoration:none;cursor:pointer;transition:background .12s,border-color .12s,color .12s}
.news-filter__chip:hover{border-color:var(--cyan);color:var(--cyan-d)}
.news-filter__chip-mark{width:9px;height:9px;border-radius:50%;border:1px solid #cdd8e0;flex:none;position:relative;transition:background .12s,border-color .12s}
/* Per-filter article count in parentheses — a muted, tabular figure. */
.news-filter__chip-count{color:#9aa7b2;font-weight:400;font-variant-numeric:tabular-nums}
.news-filter__chip:hover .news-filter__chip-count,
.news-filter__chip.is-include .news-filter__chip-count,
.news-filter__chip--all.is-on .news-filter__chip-count{color:inherit;opacity:.75}
.news-filter__chip.is-include{background:#eef7fa;border-color:#a9d8e4;color:#0a6273}
.news-filter__chip.is-include .news-filter__chip-mark{background:var(--cyan);border-color:var(--cyan)}
.news-filter__chip.is-include .news-filter__chip-mark::after{content:"✓";position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:#fff;font-size:6px;line-height:1}
.news-filter__hint{margin:0 0 16px;font-size:11px;color:var(--grey);line-height:1.5}
.news-filter__results.is-loading{opacity:.5;transition:opacity .1s}
/* "Όλα" (clear-all) chip — active in the default no-filter view. */
.news-filter__chip--all.is-on{background:#eef7fa;border-color:#a9d8e4;color:#0a6273;font-weight:600}
/* Active single-tag filter indicator. */
.news-tagfilter{display:inline-flex;align-items:center;gap:8px;background:#eef7fa;border:1px solid #a9d8e4;border-radius:14px;padding:5px 12px;margin:0 0 16px;font-size:12.5px;color:#0a6273}
.news-tagfilter__label{color:var(--grey);font-size:11.5px}
.news-tagfilter__value{font-weight:600}
.news-tagfilter__clear{color:#0a6273;text-decoration:none;font-weight:700;line-height:1}
.news-tagfilter__clear:hover{color:#c0392b}
/* News-item pills are now links (the card is no longer one big anchor). */
.public-news-index__title{color:inherit;text-decoration:none}
.public-news-index__title:hover{color:var(--cyan-d)}
.public-news-index__cats{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px}
.public-news-index__cats .cat{margin-bottom:0;text-decoration:none;transition:background .12s,color .12s}
.public-news-index__cats .cat:hover{background:var(--cyan);color:#04222b}
.public-news-index__tags a{background:#eef2f7;color:var(--grey);font-size:12px;border-radius:14px;padding:4px 11px;text-decoration:none;transition:background .12s,color .12s}
.public-news-index__tags a:hover{background:var(--cyan);color:#04222b}

/* Media (video) index + show — category + tag pills (mirror the news pills). */
.public-media-index__cats,.public-media-show__cats{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px}
.public-media-index__cats .cat,.public-media-show__cats .cat{margin-bottom:0;text-decoration:none;transition:background .12s,color .12s}
.public-media-index__cats .cat:hover,.public-media-show__cats .cat:hover{background:var(--cyan);color:#04222b}
.public-media-index__tags,.public-media-show__tags{margin:8px 0 0}
.public-media-index__tags a,.public-media-show__tags a{background:#eef2f7;color:var(--grey);font-size:12px;border-radius:14px;padding:4px 11px;text-decoration:none;transition:background .12s,color .12s;margin-right:6px}
.public-media-index__tags a:hover,.public-media-show__tags a:hover{background:var(--cyan);color:#04222b}

/* News list pager (prev / status / next) */
.news-pager{display:flex;gap:10px;justify-content:center;align-items:center;margin-top:22px}
.news-pager__link{border:1px solid var(--line);background:#fff;border-radius:8px;padding:8px 14px;font-weight:600;font-size:13px;color:var(--ink);text-decoration:none}
.news-pager__link:not(.is-disabled):hover{border-color:var(--cyan);color:var(--cyan-d)}
.news-pager__link.is-disabled{color:var(--line);cursor:default}
.news-pager__status{font-size:13px;color:var(--grey);font-weight:600}

/* listing / section page */
.page-head{margin:0 0 22px}
.page-head h1{color:var(--navy);font-size:30px;font-weight:800;line-height:1.15}
.page-head p.sub{color:var(--grey);margin:8px 0 0;font-size:15px}
/* Podcasts listing search (FR-POD-01 add-on) — plain GET form, no JS. */
.list-search{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin:0 0 22px}
.list-search input[type=search]{flex:1 1 320px;min-width:200px;padding:10px 14px;border:1px solid var(--line);border-radius:10px;font:inherit;font-size:15px;background:#fff}
.list-search input[type=search]:focus{outline:none;border-color:var(--cyan);box-shadow:0 0 0 3px rgba(15,163,196,.18)}
.list-search button{padding:10px 18px;border:0;border-radius:10px;background:var(--cyan);color:#04222b;font-weight:700;font:inherit;font-size:15px;cursor:pointer}
.list-search button:hover{background:var(--cyan-d);color:#fff}
.list-search__clear{font-size:13px;color:var(--grey);text-decoration:none}
.list-search__clear:hover{color:var(--cyan-d)}
.list-search__hint{margin:-12px 0 22px;font-size:12.5px;color:var(--grey);line-height:1.5}
.listing{display:flex;flex-direction:column;background:#fff;border:1px solid var(--line);border-radius:12px;overflow:hidden}
/* Faint chess.gr knight-mark watermark on the right of the news listing (brand
   accent). It's a position:sticky element so it TRAVELS down the right as the list
   scrolls. isolation:isolate contains its negative-z so it sits above the card's
   white bg but behind the (transparent) article rows. overflow:CLIP (not hidden)
   clips the dissolving pixels at the right edge WITHOUT trapping the sticky
   positioning (overflow:hidden would make .listing the sticky container). */
.public-news-index__list{position:relative;isolation:isolate;overflow:clip}
/* The track is an out-of-flow (absolute) band spanning the card's right side, so it
   adds no layout height. The mark inside is position:sticky with a REAL height, so it
   pins at top:100px while scrolling, then RELEASES exactly when the card's bottom
   reaches the mark's bottom (top + height) — riding off cleanly instead of getting
   clipped in place. overflow:clip on .listing clips the right bleed. */
.public-news-index__wm{position:absolute;top:0;right:-60px;bottom:0;width:640px;z-index:-1;pointer-events:none}
.public-news-index__wm-mark{position:sticky;top:100px;display:block;height:358px;background:url(/assets/chessgr-mark.svg) center/contain no-repeat;opacity:.18}
@media (max-width:760px){.public-news-index__wm{display:none}}
.lrow{display:flex;gap:18px;padding:16px 18px;border-top:1px solid var(--line)}
.lrow:first-child{border-top:0}
.lrow > a{display:flex;gap:18px;flex:1;color:inherit;text-decoration:none}
.lrow .th{width:200px;aspect-ratio:3/2;border-radius:8px;background:linear-gradient(135deg,#c9d6e8,#dde7f2);flex:none;overflow:hidden}
.lrow .th img{width:100%;height:100%;object-fit:cover;display:block}
/* News listing: show the whole thumbnail (contain), smaller — not a cropped 200px box */
.public-news-index__item .th{width:150px;background:#eef3f9}
.public-news-index__item .th img{object-fit:contain}
.lrow .body{flex:1}
.lrow h3{font-size:18px;font-weight:600;margin:6px 0}
.lrow p{margin:0 0 8px;color:#5d6b7a;font-size:14px}
.empty{background:#fff;border:1px solid var(--line);border-radius:12px;padding:40px;text-align:center;color:var(--grey)}
.pager{display:flex;gap:6px;justify-content:center;margin-top:22px}
.pager a{border:1px solid var(--line);background:#fff;border-radius:8px;padding:8px 13px;font-weight:600;font-size:13px;color:var(--ink)}
.pager a.on{background:var(--blue);border-color:var(--blue);color:#fff}

/* tile grid (media / podcasts / courses index) */
.tiles{display:grid;grid-template-columns:repeat(3,1fr);gap:20px}
.tile{background:#fff;border:1px solid var(--line);border-radius:12px;overflow:hidden}
.tile > a{color:inherit;text-decoration:none;display:block}
.tile .cover{aspect-ratio:3/2;overflow:hidden;background:linear-gradient(135deg,#001e44,#145398)}
.tile .cover img{width:100%;height:100%;object-fit:cover;display:block}
/* video thumbnails (YouTube) — 16:9 window matching the video; object-fit crops
   YouTube's baked-in 4:3 letterbox to show the clean video frame. */
.tile .cover--video,.cover--video{aspect-ratio:16/9;background:#000;overflow:hidden}
.cover--video img{width:100%;height:100%;object-fit:cover;display:block}
.tile .body{padding:14px 16px 16px}
.tile h3{font-size:16px;font-weight:600;line-height:1.3;margin:0 0 6px}
.tile .meta{color:var(--grey);font-size:12.5px}
.tile p{margin:6px 0 0;color:#5d6b7a;font-size:13px}

/* live games page (broadcast) */
.broadcast{background:var(--navy);border-radius:14px;padding:24px;display:grid;grid-template-columns:1fr 330px;gap:24px;color:#fff;align-items:start}
.bmain{display:flex;gap:22px;align-items:flex-start}
.b360{width:360px;height:360px;background-size:90px 90px;background-position:0 0,45px 45px}
.bmeta{flex:1;display:flex;flex-direction:column;gap:10px}
.bmeta h2{font-size:22px;font-weight:700} .bmeta .meta{color:#a9c0dc;font-size:13px}

footer.site{margin-top:64px;padding:56px 40px 0;background:linear-gradient(180deg,#001a3d,#001124);color:#aeb9c6;font-size:13px}
footer.site .in{max-width:1440px;margin:0 auto;display:grid;grid-template-columns:1.7fr 1fr 1fr 1.3fr;gap:40px;align-items:start;padding-bottom:44px}
footer.site .site-foot__logo img{width:190px;height:auto;display:block}
footer.site .site-foot__tagline{margin:16px 0 0;color:#7f8da3;max-width:32ch;font-size:13.5px;line-height:1.6}
footer.site .site-foot__col h2{font-family:var(--disp);font-size:12.5px;letter-spacing:.07em;text-transform:uppercase;color:#9ec3e6;margin:0 0 14px}
footer.site .site-foot__col a{display:block;color:#cdd6e0;font-weight:500;padding:4px 0;text-decoration:none}
footer.site .site-foot__col a:hover{color:#fff;text-decoration:underline}
footer.site .site-foot__company address{font-style:normal;line-height:1.75;color:#aeb9c6}
footer.site .site-foot__bar{border-top:1px solid rgba(255,255,255,.09)}
footer.site .site-foot__bar .copy{max-width:1440px;margin:0 auto;padding:20px 0;color:#7f8da3;font-size:12.5px}
@media(max-width:860px){footer.site{padding:44px 20px 0}footer.site .in{grid-template-columns:1fr 1fr;gap:28px}}
@media(max-width:560px){footer.site .in{grid-template-columns:1fr}}

/* ========================================================================== */
/* [2] THEME — theme-cyan.css (LOCKED "Cyan on White"), applied verbatim       */
/* ========================================================================== */
:root {
  --cyan:   #0fa3c4;   /* cyan on dark surfaces */
  --cyan-d: #0c7f99;   /* cyan for links/accents on white (AA on #fff) */
  --cyan-bg:#d8f1f7;   /* tint chip background */
  --disp:   "Space Grotesk", var(--sans);
}
body { background: #ffffff; }
h1, h2, h3, h4, .big,
.sec-head h2, .rcard h4, .scard h4, .gamelist h4, .rail-side h4,
.page-head h1, .tile h3, .article h1, .article .body h2 {
  font-family: var(--disp);
  letter-spacing: -0.2px;
}
header.mast {
  position: sticky; top: 0; z-index: 20;
  background: rgba(255, 255, 255, 0.82);
  backdrop-filter: blur(10px) saturate(140%);
  -webkit-backdrop-filter: blur(10px) saturate(140%);
}
nav.main a.on {
  color: var(--cyan-d); font-weight: 600;
  box-shadow: inset 0 -2px 0 var(--cyan);
}
.cat { background: var(--cyan-bg); color: var(--cyan-d); }
.btn { background: var(--cyan); color: #04222b; }
.btn.ghost { background: #fff; color: var(--cyan-d); border-color: var(--cyan); }
.sec-head a, .lk, .watch, .crumb a, .tags span, .it b { color: var(--cyan-d); }
.eyebrow { color: var(--cyan-d); }
.z1 .eyebrow, .z2 .eyebrow, .bmeta .eyebrow { color: #7fd6ea; }

.ncard, .rcard, .scard .th, .cal-list, .zone.card-b, .rail-side, .it, .tile, .listing {
  box-shadow: 0 6px 22px rgba(20, 40, 80, 0.07);
}
.ncard, .rcard, .tile { transition: 0.16s; }
.ncard:hover, .rcard:hover, .tile:hover {
  transform: translateY(-3px);
  box-shadow: 0 16px 40px rgba(15, 163, 196, 0.18);
  border-color: #bfe3ec;
}
.z1 {
  position: relative; overflow: hidden; color: #fff;
  background: linear-gradient(115deg, #001a3d, #0c3e76, #0e6f93, #0c3e76, #001a3d);
  background-size: 300% 300%; animation: cg-flow 16s ease infinite;
}
.z1::after {
  content: ""; position: absolute; left: -30%; top: -70%; width: 160%; height: 240%;
  pointer-events: none; opacity: 0.16;
  background: conic-gradient(from 0deg, transparent, rgba(127, 214, 234, 0.8), transparent 40%);
  animation: cg-spin 22s linear infinite;
}
.z1 .info { position: relative; z-index: 1; }
.z2 { background: linear-gradient(135deg, #0c3e76, #0e6f93); }
.z5 { background: linear-gradient(135deg, var(--cyan-d), var(--cyan)); }
@keyframes cg-flow { 50% { background-position: 100% 50%; } }
@keyframes cg-spin { to { transform: rotate(360deg); } }
.toggle button.on { background: var(--cyan); color: #04222b; border-color: var(--cyan); }
.tag.open { background: var(--cyan-bg); color: var(--cyan-d); }
.pill:hover, .fl { color: var(--cyan-d); }
.pin { background: var(--cyan); box-shadow: 0 0 0 4px rgba(15, 163, 196, 0.22); }
.map { outline: 1px solid #e0eef3; }

/* ========================================================================== */
/* [3] APP — live-only additions (real search form, nav UI, block styles)      */
/* ========================================================================== */

/* --- masthead search: real <form> styled as the demo's pill ---------------- */
.site-search{position:relative;display:inline-flex;align-items:center;gap:0}
.site-search input[type="search"]{
  appearance:none;-webkit-appearance:none;
  background:#f1f5f9;border:1px solid transparent;border-radius:20px;
  padding:8px 16px;font:inherit;font-size:13px;color:var(--ink);width:230px;
}
.site-search input[type="search"]::placeholder{color:var(--grey)}
.site-search input[type="search"]:focus{outline:none;border-color:var(--cyan);background:#fff}
.site-search button{
  margin-left:-34px;background:none;border:0;cursor:pointer;color:var(--grey);
  font-size:14px;padding:6px 10px;line-height:1;
}
.site-search button:hover{color:var(--cyan-d)}

/* --- nav dropdowns (CSS hover / focus-within, JS-free) --------------------- */
.has-menu{position:relative}
.has-menu > .top::after{content:"▾";margin-left:4px;font-size:11px;color:var(--grey)}
.menu{
  position:absolute;top:calc(100% + 10px);left:0;min-width:220px;z-index:30;
  background:#fff;border:1px solid var(--line);border-top:2px solid var(--cyan);
  border-radius:0 0 12px 12px;box-shadow:0 18px 44px rgba(16,32,52,.18);
  padding:8px;opacity:0;visibility:hidden;transform:translateY(-6px);transition:.14s;
}
.menu a{display:block;padding:9px 12px;border-radius:7px;color:var(--ink);font-size:14px;font-weight:500}
.menu a:hover{background:var(--bg);color:var(--cyan-d);text-decoration:none}
.has-menu:hover > .menu,
.has-menu:focus-within > .menu{opacity:1;visibility:visible;transform:translateY(0)}

/* --- mobile drawer (checkbox hack — burger toggles the nav, JS-free) -------- */
.nav-toggle{display:none}
.burger{display:none;flex-direction:column;gap:4px;cursor:pointer;padding:8px}
.burger i{width:22px;height:2px;background:var(--ink);display:block;border-radius:2px}

@media (max-width:900px){
  .mast .in{flex-wrap:wrap;gap:12px;position:relative}
  .burger{display:flex;order:3}
  .site-search{order:4;flex:1}
  .site-search input[type="search"]{width:100%}
  nav.main{
    order:5;flex-basis:100%;flex-direction:column;align-items:stretch;gap:0;
    max-height:0;overflow:hidden;transition:max-height .2s ease;
  }
  .nav-toggle:checked ~ nav.main{max-height:1200px}
  nav.main > a,nav.main .top{padding:12px 4px;border-top:1px solid var(--line)}
  .has-menu{position:static}
  .menu{position:static;opacity:1;visibility:visible;transform:none;box-shadow:none;border:0;
    border-top:0;border-radius:0;padding:0 0 0 14px}
  .has-menu > .top::after{content:"+"}
}

/* --- search as-you-type dropdown (search §9 island) ------------------------ */
.visually-hidden{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
.search-suggest{
  position:absolute;top:100%;left:0;right:0;z-index:50;margin-top:6px;
  background:#fff;border:1px solid var(--line);border-radius:10px;
  box-shadow:0 14px 36px rgba(16,32,52,.16);padding:.5rem;max-height:70vh;overflow:auto;
}
.search-suggest[hidden]{display:none}
.search-suggest__group h3{
  font-size:.72rem;text-transform:uppercase;letter-spacing:.04em;
  color:var(--grey);margin:.4rem 0 .2rem;
}
.search-suggest__group ul{list-style:none;margin:0 0 .3rem;padding:0}
.search-suggest__group a{display:block;padding:.3rem .4rem;text-decoration:none;color:var(--ink);border-radius:5px}
.search-suggest__group a:hover{background:var(--bg)}
.search-suggest__all{display:block;padding:.4rem;font-weight:600;color:var(--cyan-d);text-decoration:none}
.search-suggest__empty{color:var(--grey);padding:.4rem;margin:0}

/* --- CMS Divider block (add-article-dividers) ------------------------------ */
.article-divider{display:flex;align-items:center;margin:2rem 0}
.article-divider svg{width:100%;height:auto}
.article-divider .rule{flex:1;height:2px;border-radius:1px;background:linear-gradient(90deg,transparent,var(--cyan),transparent)}
.article-divider--vertical{justify-content:center}
.article-divider--vertical svg{width:auto;height:12rem}
.article-divider--vertical .rule{width:2px;height:auto;align-self:stretch}
/* Responsive horizontal divider: the wide bar spans the desktop column; on
   phones the whole SVG would scale down with the column and the piece would
   shrink to ~11px, so we swap in a shorter (taller-banded) rendering that keeps
   the piece a readable ~24px. Specificity (0,2,1) beats `.article-divider svg`. */
.article-divider svg.article-divider__narrow{display:none}
@media(max-width:600px){
  .article-divider svg.article-divider__wide{display:none}
  .article-divider svg.article-divider__narrow{display:block;width:auto;height:44px;max-width:100%;margin-inline:auto}
}

/* --- CMS Board block (add-board-themes) ------------------------------------ */
.board-diagram{margin:2rem auto;max-width:28rem}
.board-diagram svg{width:100%;height:auto;display:block}

/* --- multi-column layout row (grid-layout-builder) ------------------------- */
/* Track template comes from the inline --article-row-cols custom property the
   RowBlock renderer emits (e.g. "8fr 4fr"). On narrow viewports columns stack
   to a single full-width column — the media query sets grid-template-columns
   directly, overriding the var. */
.article-row{display:grid;grid-template-columns:var(--article-row-cols,1fr);
  gap:1.5rem;align-items:start;margin:1.75rem 0}
.article-col{min-width:0}
.article-col>:first-child{margin-top:0}
.article-col>:last-child{margin-bottom:0}
.article-col .board-diagram,.article-col .article-divider{margin-top:0}
@media(max-width:640px){
  .article-row{grid-template-columns:1fr;gap:1rem}
}

/* --- draft preview ribbon (CMS preview of the public article) -------------- */
.preview-ribbon{position:sticky;top:0;z-index:60;background:#fff3cd;border-bottom:1px solid #f0d98a;color:#806000;text-align:center;padding:8px 14px;font-weight:700;font-size:13px}

/* --- tournament crosstable (standings / "Βαθμολογία" block) ---------------- */
.crosstable{margin:1.75rem 0}
.crosstable__title{font-weight:600;margin:0 0 .5rem;color:var(--ink)}
.crosstable__scroll{overflow-x:auto;-webkit-overflow-scrolling:touch}
.crosstable__table{border-collapse:collapse;width:100%;font-size:14px}
.crosstable__table th,.crosstable__table td{border:1px solid var(--line);padding:6px 9px;text-align:center;white-space:nowrap}
.crosstable__table thead th{background:#f3f8fc;font-weight:600;color:var(--ink)}
.crosstable__table .ct-name{text-align:left;font-weight:600}
.crosstable__table .ct-total{font-weight:700;background:#f7fafc}
.crosstable__table .ct-self{background:#cdd6e0}
.crosstable__table tbody tr:nth-child(even) td{background:#fbfdff}
.crosstable__table tbody tr:nth-child(even) .ct-total{background:#eef4f9}
/* the self/diagonal cell stays greyed on every row — must come AFTER the
   even-row stripe rule (equal specificity) so it isn't overridden. */
.crosstable__table tbody tr:nth-child(even) .ct-self{background:#cdd6e0}

/* --- decorative section divider (homepage signature cyan rule) ------------- */
.divx{display:flex;align-items:center;gap:14px;max-width:820px;margin:36px auto 8px}
.divx .rule{flex:1;height:2px;border-radius:1px;
  background:linear-gradient(90deg,transparent,var(--cyan),transparent);
  background-size:200% 100%;animation:cg-flow 6s linear infinite}
.divx .mark{height:26px;width:auto;opacity:.9}

/* --- content / detail pages (show views: prose, fact list, tables) --------- */
.content-page{max-width:860px}
.content-page h1{font-family:var(--disp);font-size:31px;font-weight:700;color:#101822;line-height:1.16;letter-spacing:-.4px;margin-bottom:6px}
.content-page .lead{font-size:18px;color:#3a4654;margin:0 0 18px}
.content-page .meta-row{color:var(--grey);font-size:12.5px;margin:0 0 22px;padding-bottom:14px;border-bottom:1px solid var(--line);display:flex;gap:10px;flex-wrap:wrap;align-items:center}
.content-page .body p,.content-page section p{font-size:16px;line-height:1.7;color:#2a323b;margin:0 0 16px}
.content-page .body h2,.content-page section > h2{font-size:21px;font-weight:600;color:var(--ink);margin:28px 0 10px;font-family:var(--disp);letter-spacing:-.2px}
.content-page .body h3{font-size:17px;font-weight:600;color:var(--ink);margin:22px 0 8px;font-family:var(--disp);letter-spacing:-.2px}
.content-page .body img,.content-page figure img{border-radius:8px;max-width:100%;height:auto}
.content-page figure{margin:20px 0}
.content-page figcaption,.content-page .credit{color:var(--grey);font-size:12.5px;margin-top:7px}
.content-page section{margin:0 0 26px}

/* Owner-pending placeholder note (terms/cookies/privacy until the legal copy
   lands) — a quiet, clearly-marked callout rather than a bare line of text. */
.content-page__pending,.public-privacy__pending{
  margin:0 0 24px;padding:12px 16px;border-left:4px solid var(--cyan);
  background:#f0fafc;border-radius:0 8px 8px 0;color:#3a4654;font-size:14.5px;line-height:1.6}
.content-page__pending em,.public-privacy__pending em{font-style:italic}

/* Contact form (Επικοινωνία) — public/contact.twig. Inputs reuse the brand
   field treatment; the .btn submit is already themed. */
.public-contact__form{display:flex;flex-direction:column;gap:16px;max-width:560px;margin-top:8px}
.public-contact__field{display:flex;flex-direction:column;gap:6px}
.public-contact__field span{font-size:13px;font-weight:600;color:var(--ink)}
.public-contact__field input,.public-contact__field textarea{
  padding:10px 14px;border:1px solid var(--line);border-radius:10px;font:inherit;font-size:15px;background:#fff}
.public-contact__field input:focus,.public-contact__field textarea:focus{
  outline:none;border-color:var(--cyan);box-shadow:0 0 0 3px rgba(15,163,196,.18)}
.public-contact__field textarea{resize:vertical;min-height:140px}
.public-contact__consent{font-size:13px;color:var(--grey);line-height:1.6;margin:0}
.public-contact__ok{
  padding:14px 18px;border-radius:10px;background:#e9f9ee;border:1px solid #b6e3c4;color:#1c7a3e;font-size:15px}
.public-contact__errors{
  margin:0 0 18px;padding:12px 18px;border-radius:10px;background:#fdeceb;border:1px solid #f3c0bd;color:#a3261d;font-size:14px;list-style-position:inside}
.public-contact__errors li{margin:2px 0}
/* Honeypot — must stay invisible to humans; bots fill it and get rejected. */
.public-contact__form .hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
/* Chess captcha — "click the piece". A themed 8×8 board (Unicode glyphs); the
   click is enhanced by chess-captcha.js, the text field is the no-JS fallback. */
.chess-captcha{padding:14px 16px;border:1px solid var(--line);border-radius:12px;background:#f7fbfd}
.chess-captcha__q{margin:0 0 10px;font-size:14px;font-weight:600;color:var(--ink)}
.chess-captcha__board{display:grid;grid-template-columns:repeat(8,1fr);width:min(320px,100%);aspect-ratio:1/1;border:1px solid #cfe0e6;border-radius:8px;overflow:hidden;margin:0 0 12px;touch-action:manipulation}
.chess-captcha__sq{border:0;margin:0;padding:0;display:flex;align-items:center;justify-content:center;font-size:clamp(15px,4.4vw,26px);line-height:1;cursor:pointer;aspect-ratio:1/1}
/* cburnett piece art (recolored SVG per square); the glyph fallback keeps font-size. */
.chess-captcha__sq svg{width:88%;height:88%;display:block;pointer-events:none}
/* Medium slate-blue board: the cburnett pieces are MONO (solid #fff white /
   #111 black, no outline), so both squares must be mid-tone — dark enough that
   white pieces read, light enough that black pieces read (each shade clears
   ~3.3:1 against BOTH piece colours). A near-white light square hid white pieces. */
.chess-captcha__sq.is-light{background:#6d90a8}
.chess-captcha__sq.is-dark{background:#46697d}
.chess-captcha__sq:hover{outline:2px solid var(--cyan);outline-offset:-2px}
.chess-captcha__sq.is-picked{outline:3px solid #d9534f;outline-offset:-3px}
.chess-captcha__field{max-width:180px}
.chess-captcha__bypass{font-size:12px;color:var(--grey);margin:8px 0 0}

/* --- CMS prose blocks — batch2 compass (09-article-templates-batch2.html) ----
   One treatment for every CMS-rendered body: news (.article .body), courses,
   and the content-page detail views. Covers the block types BlockRenderer
   emits — quote, list, image-with-caption — so they read identically wherever
   the editor's blocks land. */
.article .body blockquote,
.content-page .body blockquote,
.content-page section blockquote{
  margin:22px 0;padding:6px 0 6px 20px;border-left:4px solid var(--cyan);
  font-family:var(--disp);font-size:21px;line-height:1.4;color:#0c3e76}
.article .body blockquote p,
.content-page .body blockquote p,
.content-page section blockquote p{font:inherit;color:inherit;margin:0}
.article .body blockquote footer,
.content-page .body blockquote footer,
.content-page section blockquote footer{
  font-family:var(--sans);font-size:13px;font-weight:600;font-style:normal;color:var(--grey);margin-top:8px}

.article .body ul,.article .body ol,
.content-page .body ul,.content-page .body ol,
.content-page section ul,.content-page section ol{
  font-size:16px;line-height:1.7;color:#2a323b;padding-left:22px;margin:0 0 16px}
.article .body li,
.content-page .body li,
.content-page section li{margin:4px 0}

/* Text-size presets (fs-*; normal = default/omitted). Author-chosen per block —
   currently the list block. On the list element so the <li> children inherit. */
:is(.article .body, .content-page .body, .content-page section) .fs-sm{font-size:14px}
:is(.article .body, .content-page .body, .content-page section) .fs-lg{font-size:19px}
:is(.article .body, .content-page .body, .content-page section) .fs-xl{font-size:22px}

.article .body figure{margin:20px 0}
.article .body figcaption{color:var(--grey);font-size:12.5px;margin-top:7px}
.article .body figcaption cite,
.content-page figcaption cite{color:var(--grey);font-style:normal}

/* --- block alignment (author-chosen left/center/right; left = default/omitted)
   Works for text (text-align) AND block-level media — figures (image/board/
   standings), embed wrappers, the PGN/quiz mounts — via margin-inline. Scoped to
   the CMS-rendered bodies so it can't leak into chrome. */
:is(.article .body, .content-page .body, .content-page section) :is(.align-center, .align-right){display:block}
:is(.article .body, .content-page .body, .content-page section) .align-center{text-align:center;margin-inline:auto}
:is(.article .body, .content-page .body, .content-page section) .align-right{text-align:right;margin-inline-start:auto;margin-inline-end:0}
/* media children of an aligned figure/wrapper centre/right within the column */
:is(.article .body, .content-page .body, .content-page section) .align-center :is(img,svg,iframe,table,.cg-wrap){margin-inline:auto}
:is(.article .body, .content-page .body, .content-page section) .align-right :is(img,svg,iframe,table,.cg-wrap){margin-inline-start:auto;margin-inline-end:0}
/* a centred/right figure shrinks to its content so the rule reads visually */
:is(.article .body, .content-page .body, .content-page section) figure.align-center,
:is(.article .body, .content-page .body, .content-page section) figure.align-right{width:fit-content;max-width:100%}
/* Image size presets (img-w-*): featured image + body image blocks. The figure
   shrinks to the (capped) image so its caption lines up with the image's right
   edge; the credit line is capped to the same width for the featured image. */
.article .feat.img-w-small,.article .feat.img-w-medium,.article .feat.img-w-large{width:fit-content;max-width:100%}
.article .feat.img-w-small img{width:auto;max-width:300px}
.article .feat.img-w-medium img{width:auto;max-width:480px}
.article .feat.img-w-large img{width:auto;max-width:640px}
.article .credit.credit-w-small{max-width:300px}
.article .credit.credit-w-medium{max-width:480px}
.article .credit.credit-w-large{max-width:640px}
/* Featured-image alignment (img-a-*): only bites once the image is narrower than
   the column (a size preset). The figure/credit are width:fit-content blocks, so
   margins do the aligning; the credit text follows the image edge. */
.article .feat.img-a-center,.article .credit.img-a-center{margin-left:auto;margin-right:auto}
.article .feat.img-a-right,.article .credit.img-a-right{margin-left:auto;margin-right:0}
.article .credit.img-a-center{text-align:center}
.article .credit.img-a-right{text-align:right}
.article .body figure.img-w-small,.article .body figure.img-w-medium,.article .body figure.img-w-large{width:fit-content;max-width:100%}
.article .body figure.img-w-small img{max-width:300px}
.article .body figure.img-w-medium img{max-width:480px}
.article .body figure.img-w-large img{max-width:640px}
.article .body figure.img-w-small figcaption,.article .body figure.img-w-medium figcaption,.article .body figure.img-w-large figcaption{text-align:right}
/* Media item display size (media-w-*): caps the video/embed on the media page. */
.public-media-show__media.media-w-small :is(video,img,iframe){max-width:300px;width:100%}
.public-media-show__media.media-w-medium :is(video,img,iframe){max-width:480px;width:100%}
.public-media-show__media.media-w-large :is(video,img,iframe){max-width:640px;width:100%}
/* Product "Σχετικά" rail on the /media page — lay the shared .bcast-sg cards out
   as a grid (they default to a narrow vertical rail on the live board). */
.public-media-suggest{margin:28px 0 8px}
.public-media-suggest .bcast-suggest-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:12px}
/* Editor-curated related media at the bottom of the /media page (add-media-related). */
.public-media-related{margin:28px 0 8px}
.public-media-related__h{font-size:18px;font-weight:700;color:var(--navy);margin:0 0 12px}
.public-media-related__list{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:14px}
.public-media-related__item a{display:block;color:inherit;text-decoration:none}
.public-media-related__thumb{display:block;aspect-ratio:16/9;border-radius:8px;overflow:hidden;background:linear-gradient(135deg,#001e44,#0e6f93)}
.public-media-related__thumb img{width:100%;height:100%;object-fit:cover;display:block}
.public-media-related__thumb--ph{display:flex;align-items:center;justify-content:center;height:100%;color:#cdeefb;font-size:24px}
.public-media-related__ti{display:block;margin-top:7px;font-size:13.5px;font-weight:600;line-height:1.35;color:var(--ink)}
.public-media-related__item a:hover .public-media-related__ti{color:var(--cyan-d)}
.content-page .cover{border-radius:14px;overflow:hidden;margin:0 0 18px;background:linear-gradient(135deg,#001e44,#0e6f93)}
.content-page .cover img{display:block;width:100%;height:auto}
/* Podcast episode page — video (left) + a right rail (Κεφάλαια timestamps +
   Πηγές bibliography) that starts where the video stops, with a gutter between.
   The 2-column layout needs more room than the 860px reading column; it stacks
   to one column on narrow screens. */
.public-podcast-show.content-page{max-width:1140px}
.public-podcast-show__cols{display:grid;grid-template-columns:600px minmax(0,1fr);gap:32px;align-items:start}
.public-podcast-show__main{min-width:0}
.public-podcast-show__player .embed{margin:0}
.public-podcast-show__spotify{margin:14px 0 0}
.public-podcast-show__rail{min-width:0;margin:0;color:#2a323b}
/* The body's section separators (imported ASCII dash rules → <hr>) render as a
   clean rule the FULL rail width instead of an overflowing run of characters. */
.public-podcast-show__rail hr,.content-page .body hr,.article .body hr{border:0;border-top:1px solid var(--line);width:100%;margin:14px 0}
.public-podcast-show__main-body{margin-top:20px}
/* Automated e-shop suggestions in the episode rail — compact cards (cover
   thumbnail beside the title), shown beneath the first block. */
.pod-suggest{margin-top:22px}
.pod-suggest h4{font-size:12px;text-transform:uppercase;letter-spacing:.5px;color:var(--grey);margin:0 0 10px}
.pod-suggest__list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}
.pod-suggest__card{display:flex;gap:11px;align-items:center;text-decoration:none;color:var(--ink);background:#fff;border:1px solid #cfe8f2;border-radius:10px;padding:8px;box-shadow:0 2px 8px rgba(20,40,80,.05)}
.pod-suggest__card:hover{background:#f3fbfd;border-color:var(--cyan)}
.pod-suggest__img{flex:none;width:46px;height:62px;object-fit:cover;border-radius:5px;background:#eef7fb}
.pod-suggest__ph{display:flex;align-items:center;justify-content:center;color:var(--cyan-d);font-size:24px}
.pod-suggest__tx{display:flex;flex-direction:column;min-width:0;gap:2px}
.pod-suggest__rs{font-size:10px;text-transform:uppercase;letter-spacing:.3px;color:var(--cyan-d);font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pod-suggest__ti{font-size:13px;font-weight:600;line-height:1.3;color:var(--ink);overflow:hidden;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical}
@media(max-width:1024px){.public-podcast-show__cols{grid-template-columns:1fr;gap:24px}.public-podcast-show.content-page{max-width:860px}}
dl.facts{display:grid;grid-template-columns:auto 1fr;gap:10px 20px;background:#fff;border:1px solid var(--line);border-radius:12px;padding:18px 20px;margin:0 0 24px;box-shadow:0 6px 22px rgba(20,40,80,.07)}
dl.facts dt{color:var(--grey);font-weight:600;font-size:13px}
dl.facts dd{margin:0;font-size:14px}
.rtable{width:100%;border-collapse:collapse;background:#fff;border:1px solid var(--line);border-radius:12px;overflow:hidden}
.rtable th{text-align:left;background:var(--bg);color:var(--navy);font-size:11px;text-transform:uppercase;letter-spacing:.4px;padding:10px 14px}
.rtable td{padding:10px 14px;border-top:1px solid var(--line);font-size:14px}
.lesson-nav{display:flex;justify-content:space-between;gap:12px;margin-top:30px;border-top:1px solid var(--line);padding-top:18px}
.lesson-nav a{color:var(--cyan-d);font-weight:600;font-size:14px;max-width:48%}
.lesson-nav .next{margin-left:auto;text-align:right}

/* --- venue / media photo grid --------------------------------------------- */
.photo-grid{list-style:none;padding:0;margin:0;display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:12px}
.photo-grid img{width:100%;aspect-ratio:3/2;object-fit:cover;border-radius:10px;display:block}

/* --- live games: hero widget + dedicated page (§11) ------------------------ */
.zone--live{background:var(--navy);color:#fff;display:flex;flex-direction:column;gap:10px;padding:14px;min-height:320px;overflow:hidden}
/* In a taller zone (e.g. 3 rows) let the board viewer grow and centre itself
   between the LIVE header and the attribution, instead of staying top-anchored. */
.zone--live [data-broadcast-viewer]{flex:1 1 auto;display:flex;flex-direction:column;justify-content:center;min-height:0}
/* Two pinned boards side by side (live_games.hero_game_id_2). */
.zone--live .live-duo{flex:1 1 auto;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;min-height:0}
.zone--live .live-duo [data-broadcast-viewer]{flex:initial;min-width:0}
.zone--live .live-head{display:flex;align-items:center;gap:10px}
.zone--live .eyebrow{color:#7fd6ea}
.live-attr{color:var(--cyan-d);font-size:12px;font-weight:600;align-self:flex-end;margin-top:auto}
.zone--live .live-attr{color:var(--hero-link,#7fd6ea)}
.live-attr:hover{text-decoration:none}

/* --- Tournament detail: facts left, venue map right (add-tournament-venue-map).
   `.has-map` is what turns the grid on, so a tournament with no coordinates keeps
   the original single-column page rather than reserving an empty column. The map
   is STICKY: the left column can run long (a finished event's facts plus source
   line), and an address that scrolls away is exactly the thing you were looking
   at. Slightly narrower than half — the facts list is the content, the map is
   the reference. */
.tshow-split{display:block}
.tshow-split.has-map{display:grid;grid-template-columns:minmax(0,1.25fr) minmax(0,.75fr);gap:24px;align-items:start}
.tshow-map{position:sticky;top:16px}
.tshow-map__canvas{height:min(52vh,420px);min-height:280px;border-radius:12px;background:#dceef4;z-index:0}
.tshow-map__meta{display:flex;flex-direction:column;gap:4px;margin:8px 0 0;font-size:13px}
.tshow-map__addr{color:var(--muted,#7b858f)}
.tshow-map__link{font-weight:600}
@media(max-width:860px){
  /* Stack, and let the map lose its sticky: on a phone a sticky map would eat
     half the viewport for the whole scroll. */
  .tshow-split.has-map{grid-template-columns:minmax(0,1fr)}
  .tshow-map{position:static}
  .tshow-map__canvas{height:260px;min-height:0}
}

/* --- Coming Tournaments hero widget (add-hero-upcoming-tournaments) — a
   VERTICAL stack of the next few tournaments, per-zone configurable. The date
   leads each row because in a list of things that have not happened yet, "when"
   is what the eye is scanning for; it is a fixed-width column so the names align
   into a readable second column instead of ragging against variable dates.
   The list is allowed to scroll inside a short zone rather than overflow the
   mosaic — a hero zone's height is set by the grid, not by its content. */
/* `flex:1 1 0` + `min-height:0` does TWO jobs at once, which is why there is no
   height arithmetic here or in the island:
     · the list takes exactly the space the zone has left over, so it scrolls
       rather than spilling past the zone;
     · a zero flex-basis with min-height:0 means its content does NOT feed the
       zone's min-content height, so a long list cannot push the grid row taller
       (rows are minmax(124px,auto) — an uncapped list would make the whole hero
       grow, which is a worse failure than a scrollable list).
   It also survives the hero's `zoom:67%` and any reflow for free, where measured
   pixels would not: layout and visual pixels differ under zoom, and mixing them
   is exactly the bug this replaced.
   scrollbar-width:none hides the bar — the fade below is the affordance, and a
   native bar inside a 216px-wide brand tile is visual noise. */
.hero-upcoming{list-style:none;margin:6px 0 0;padding:0;display:flex;flex-direction:column;gap:2px;
  flex:1 1 0;min-height:0;overflow:auto;scrollbar-width:none;overscroll-behavior:contain}
.hero-upcoming::-webkit-scrollbar{width:0;height:0}
/* Only marked when it actually overflows (the island sets it), so a short list
   gets no misleading "there is more" fade. */
.hero-upcoming.is-scrollable{-webkit-mask-image:linear-gradient(#000 78%,transparent);mask-image:linear-gradient(#000 78%,transparent)}
.hero-upcoming:focus-visible{outline:2px solid var(--hero-link,#7fd6ea);outline-offset:2px}
.hero-upcoming__item{border-bottom:1px solid rgba(255,255,255,.14)}
.hero-upcoming__item:last-child{border-bottom:0}
.hero-upcoming__link{display:grid;grid-template-columns:auto 1fr;column-gap:10px;align-items:baseline;padding:7px 0;text-decoration:none;color:inherit}
.hero-upcoming__link:hover .hero-upcoming__name{text-decoration:underline}
.hero-upcoming__date{font-variant-numeric:tabular-nums;font-weight:800;font-size:13px;color:var(--hero-eyebrow,#7fd6ea);white-space:nowrap}
.hero-upcoming__name{font-weight:700;font-size:14px;line-height:1.3}
/* The venue rides under the name, in the second column, so it never competes
   with the date for the row's leading edge. Clamped to two lines: real venue
   names run long ("Chess Square - Σκακιστικό Εντευκτήριο") and an unclamped one
   would push every other entry out of a 216px-wide strip. */
.hero-upcoming__venue{grid-column:2;font-size:12px;opacity:.75;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.hero-upcoming__all{margin-top:auto;align-self:flex-start;font-size:12px;font-weight:600}
@media(max-width:760px){
  /* Phones get the same rows a touch tighter — the stack is already the
     narrow-screen-friendly shape, so nothing needs to reflow. */
  .hero-upcoming__link{padding:6px 0}
  .hero-upcoming__name{font-size:13px}
}

/* --- Puzzle-of-the-Day hero widget (homepage hero zone) — today's puzzle on our
   own board, played in place. Light cyan palette; board centred in the module. */
.zone--puzzle{background:#eef9fc;color:#06303d;display:flex;flex-direction:column;gap:8px;padding:16px;overflow:hidden;border:1px solid #cfeaf3}
.hero-puzzle{display:flex;flex-direction:column;gap:8px;height:100%}
.hero-puzzle__head{display:flex;align-items:baseline;justify-content:space-between;gap:10px}
.hero-puzzle__head .eyebrow{color:var(--cyan-d);letter-spacing:.2px;font-size:13px;font-weight:700}
/* Rating + the nav/archive links follow the zone's "Ετικέτα" (eyebrow) colour
   override (--hero-eyebrow, set from zone.fgEyebrow) so one setting colours the
   label AND «Βαθμολογία»/«Προηγούμενος»/«Επόμενος»/«Δες όλους». Each keeps its
   own default when no override is set. */
.hero-puzzle__rating{color:var(--hero-eyebrow,#5a7282);font-size:12px;font-weight:600}
/* Body grows to fill the module and centres the board vertically + horizontally. */
.hero-puzzle__body{flex:1 1 auto;display:flex;flex-direction:column;justify-content:center;align-items:center;gap:8px}
/* 280 (pre-zoom) not 300: the board is the FLOOR under the puzzle zone's height, so
   capping the podcast artwork alone only bought 126px of the 140px asked for — the
   board held the shared row up. 8 squares × 35px. See .zone-card__img above. */
.hero-puzzle__board{width:100%;max-width:280px;box-shadow:0 4px 16px rgba(8,48,61,.16)}
.hero-puzzle__status{color:#06303d;font-weight:600;font-size:13px;min-height:1.3em;margin:0;text-align:center}
.hero-puzzle__status.is-correct{color:#127a2e}
.hero-puzzle__status.is-wrong{color:#c0392b}
.hero-puzzle__status.is-solved{color:#0a7d3a}
.hero-puzzle__moves{width:100%;max-width:280px;font-size:12.5px}
.hero-puzzle__nav{display:flex;justify-content:space-between;gap:10px;font-size:13px}
.hero-puzzle__nav a{color:var(--hero-eyebrow,var(--cyan-d));font-weight:600}
.hero-puzzle__cta{color:var(--hero-eyebrow,var(--cyan-d));font-weight:600;font-size:13px;align-self:center}
.hero-puzzle__cta:hover,.hero-puzzle__nav a:hover{text-decoration:none}

/* --- brand live board viewer island (live-games §11) — the M-D3 06-live
   "broadcast" look: a navy card, board + player meta left, game/move list right. */
.bcast{display:block}
.bcast--full{background:var(--navy);border-radius:14px;padding:22px;color:#fff;
  display:grid;grid-template-columns:minmax(0,1fr) 300px;gap:22px;align-items:start;margin:0 0 24px}

/* ---- stream layout (OBS browser source) -------------------------------------
   One job: the biggest possible square board, a name row above and below it, and
   nothing else.

   The board is sized by HEIGHT here, not by width as everywhere else on the site
   (.bcast-board is normally width:100% + aspect-ratio). That inversion is the
   whole trick: the frame's height is the binding constraint in a 16:9 source, so
   letting the board fill the leftover column height and take its width from that
   keeps it square and exactly as large as fits — at ANY frame size, with no
   magic row-height constant to drift out of date. */
.bcast--stream{display:block;width:100%;height:100vh;overflow:hidden}
/* The column's WIDTH is set in JS from the board's measured size (the board is
   height-driven here, and CSS cannot resolve fit-content against a width that
   comes from aspect-ratio + height). Until that lands it is simply full width,
   which is a correct-looking layout rather than a broken one. */
.bcast--stream .bcast-left{display:flex;flex-direction:column;gap:6px;height:100vh;max-width:100%;margin:0 auto;padding:6px 0}
.bcast--stream .bcast-player{flex:none}
.bcast--stream .bcast-board-wrap{flex:1;min-height:0;justify-content:center}
/* max-width:none defeats the phone rule (.bcast-board{max-width:420px} in the
   860px media query). A stream source is not a phone: an 800px-wide portrait
   frame was clamping the board to 420 wide while its height stayed 768. */
.bcast--stream .bcast-board-wrap .bcast-board{flex:0 0 auto;height:100%;width:auto;min-width:0;max-width:none;aspect-ratio:1/1;border-radius:0;box-shadow:none}
.bcast--stream .bcast-evalbar{flex:none;width:26px;border-radius:0}

/* ── stream side column: ?moves=1 / ?analysis=1 ───────────────────────────────
   Opt-in panels down the right of an OBS source. Everything here carries its own
   plate for the same reason the name rows do: the page is TRANSPARENT, so
   nothing may rely on the background for contrast — it could be composited over
   anything. Widths are in ch/rem rather than % so the board keeps the rest.  */
.bcast--stream{display:flex;gap:8px;align-items:stretch}
/* With panels the board is pushed against them instead of floating in the
   middle of the frame: `margin:0 auto` on the column centres it in whatever
   space is left, which left a wide gap between the board and the panel it
   belongs with. So exactly ONE auto margin, on the side away from the panels.
   The gap is small but not zero — flush read as cramped on air (Owner). fit()
   MEASURES this value rather than repeating it, so the two cannot drift.

   TWO columns, on opposite sides (Owner, 2026-08-31): the game's own move list
   on the right, the reference panels (Stockfish + openings) on the left. Which
   margin is auto depends on which sides are occupied — with a column on both
   sides the board sits between them and neither margin may collapse it. */
.bcast--stream-side{gap:10px;justify-content:center}
.bcast--side-r:not(.bcast--side-l) .bcast-left{margin-left:auto;margin-right:0}
.bcast--side-l:not(.bcast--side-r) .bcast-left{margin-left:0;margin-right:auto}
/* With a column on BOTH sides the board takes no auto margin at all. An auto
   margin absorbs every pixel of free space before justify-content sees any, so
   `margin:0 auto` here did not centre the board — it shoved both columns out to
   the frame edges and left a gap either side of the board. Zero margins let the
   three sit together and `justify-content:center` centres the group.
   The single-column rules above keep their auto margin on purpose: it swallows
   the free space, which is exactly how the board hugs its one column, and it
   makes justify-content moot there. ?align= still overrides both — those rules
   come later at equal specificity and zero the margins themselves. */
.bcast--side-l.bcast--side-r .bcast-left{margin-left:0;margin-right:0}

/* ?align= — where the whole assembly sits in the frame. It overrides the auto
   margins above, which is why each rule states BOTH margins: leaving one on auto
   would fight the justify-content and land the group somewhere between the two.
   No rule for "unset" on purpose — omitting the parameter must leave a scene
   framed before this option existed exactly where it was. */
.bcast--align-left{justify-content:flex-start}
.bcast--align-left .bcast-left{margin-left:0;margin-right:0}
.bcast--align-center{justify-content:center}
.bcast--align-center .bcast-left{margin-left:0;margin-right:0}
.bcast--align-right{justify-content:flex-end}
.bcast--align-right .bcast-left{margin-left:0;margin-right:0}
.bcast-stream-side{display:flex;flex-direction:column;gap:8px;width:min(26vw,340px);
  min-width:0;padding:6px 0;flex:none}
/* The reference panels go BEFORE the board, the move list after it. `order`
   rather than markup order: fit() measures both columns as siblings of the
   board to size it, and moving the DOM would gain nothing visually. */
/* fit() pins both columns to the frame height, so anything taller than that is
   simply lost off the bottom — Stockfish plus two opening panes plus a novelty
   list overruns a short frame easily. Scrolls only when it has to, and wears
   the same thin skin as the move list opposite so the two read as a pair.
   `min-height:0` because a flex child will not shrink below its content
   otherwise, and without it the column grows instead of scrolling. */
.bcast-stream-side--tools{order:-1;min-height:0;overflow-y:auto;
  scrollbar-width:thin;scrollbar-color:#2c5a6b transparent}
.bcast-stream-side--moves{order:1}
/* With a column on both sides they would otherwise eat 52vw between them and
   leave the board a strip. Narrower only when both are up — a single column
   keeps the width it always had, so those scenes do not reflow. */
.bcast--side-l.bcast--side-r .bcast-stream-side{width:min(21vw,300px)}
/* ── ?match=1 — one team meeting as a single OBS source ───────────────────────
   Every board of the meeting stacked, each with its eval bar and its two names.
   `flex:1 1 0` + `min-height:0` on the rows is what makes it fit ANY canvas: the
   boards divide whatever height is left after the header, so four boards in a
   1080 frame and eight in the same frame both work without a media query. */
/* `grid-template-rows:auto` is load-bearing: without it the header falls into
   the `grid-auto-rows:1fr` flow and takes an equal share of the frame — it was
   358px tall, letterboxing every board under it. The explicit first row sizes to
   the header; the implicit rows below split what is left. */
.bcast-mstack{display:grid;grid-template-columns:repeat(var(--ms-cols,2),1fr);
  grid-template-rows:auto;grid-auto-rows:1fr;height:100vh;gap:6px;padding:6px;
  box-sizing:border-box;width:100%}
.ms-head{grid-column:1/-1;display:flex;align-items:baseline;gap:10px;
  background:rgba(8,22,32,.86);border-radius:6px;padding:5px 10px;
  font:800 15px/1.2 var(--font-sans,system-ui),sans-serif;color:#eaf6fb}
.ms-head .ms-t{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ms-head .ms-t--b{text-align:right}
.ms-head .ms-sc{flex:none;color:#7fd6ea;font-variant-numeric:tabular-nums}
/* `grid-auto-rows:1fr` + `min-height:0` is what makes the tiling fit ANY canvas:
   the rows divide whatever height is left under the header, so four boards at
   2x2 and nine at 3x3 both work with no media query and no measurement. */
.ms-row{min-width:0;min-height:0;display:flex;flex-direction:column;gap:3px;
  align-items:center}
.ms-nm{flex:none;width:max-content;max-width:100%;background:rgba(8,22,32,.86);
  border-radius:5px;padding:3px 9px;white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis;font:700 14px/1.3 var(--font-sans,system-ui),sans-serif;
  color:#eaf6fb}
.ms-nm img{height:10px;width:auto;margin-right:5px;vertical-align:baseline}
.ms-nm i{font-style:normal;color:#7fd6ea;font-weight:600;margin-left:5px;font-size:12px}
.ms-v{margin:0 8px;color:#7fd6ea;opacity:.8}
.ms-res{margin-left:10px;padding:1px 7px;border-radius:4px;background:#0c7f99;
  color:#04222b;font-weight:800;font-size:12px}
/* The board is sized by what is left of the CELL under the name line and stays
   square via aspect-ratio, so a cell wider than it is tall (every sane 16:9
   canvas) gives a board as large as the cell height allows. */
.ms-b{flex:1;min-height:0;width:100%;display:flex;gap:4px;
  align-items:center;justify-content:center}
/* Both of these take their size from `--ms-board`, ONE pixel value the island
   measures off a laid-out cell. `aspect-ratio` cannot do this job: in a cell
   taller than it is wide it clamps the width and leaves the pinned height,
   which is a distorted board, not a smaller one. The fallback keeps a board on
   screen if the island never gets to write the property — this page runs
   unattended inside someone's broadcast. */
.ms-bar{flex:none;width:10px;height:var(--ms-board,40vh);background:#123243;
  border-radius:2px;display:flex;align-items:flex-end;overflow:hidden}
.ms-bar i{display:block;width:100%;height:0;background:#e8f4f8}
.ms-board{flex:none;width:var(--ms-board,40vh);height:var(--ms-board,40vh);
  display:grid;grid-template-columns:repeat(8,1fr);grid-template-rows:repeat(8,1fr);
  border-radius:3px;overflow:hidden}

/* A PHONE is not an OBS canvas — the same escape the rest of the stream layout
   takes. Tiling four boards into 100vh on a 390px screen gives a 195px board;
   one column that scrolls gives 340px. `height:auto` is what lets the page grow,
   so it must go with the single column, and `--ms-cols` is overridden rather
   than recomputed because bestCols is answering the OBS question correctly — it
   is the FRAME that is wrong here, not the arithmetic. */
@media (max-width: 760px) and (pointer: coarse) {
  .bcast-mstack{--ms-cols:1;height:auto;grid-auto-rows:auto}
  .bcast-mstack .ms-b{height:min(92vw, 60vh)}
}

/* ── the stream layout on a PHONE ─────────────────────────────────────────────
   These links get shared and opened on phones, where the OBS layout — three
   fixed columns sized to a 16:9 canvas — collapsed to a 174px board, an eval
   bar stretched down 844px of viewport, and both panels clipped to 82px.

   Stacked and scrollable instead: board first at full width, then the panels.
   `pointer: coarse` is in the query on purpose, so a SMALL OBS browser source
   cannot take this path — it is still a fine pointer, a phone is not. Desktop
   and every real OBS canvas are untouched by everything in this block. */
@media (max-width:760px) and (pointer:coarse){
  .bcast--stream{flex-direction:column;height:auto;gap:10px;padding:8px}
  /* fit() bails on a stacked layout (the side columns exceed the width, so its
     budget goes to zero and it returns early), but a rotate from landscape can
     leave its inline px behind — hence the !important on the board box. */
  .bcast--stream .bcast-left{width:100%!important;height:auto;margin:0}
  .bcast--stream .bcast-board-wrap{flex:none;height:auto}
  .bcast--stream .bcast-board-wrap .bcast-board{flex:1 1 auto;min-width:0;
    width:auto!important;height:auto!important}
  .bcast--stream .bcast-evalbar{width:18px}
  /* `display:contents` dissolves the two columns so their panels become direct
     children of the stack and can be ordered INDIVIDUALLY. Without it Stockfish
     and the openings are locked together in one column and the move list can
     only go above or below the pair — never between them, which is the order
     that actually reads on a phone:
        board → Stockfish → moves → openings/novelty
     Evaluation first because it is the glanceable number, then the moves for
     context, then the reference panels which are the longest and the least
     urgent. */
  .bcast-stream-side{display:contents}
  .bcast--stream .bcast-left{order:1}
  .bcast-stream-eng{order:2}
  .bcast-stream-moves{order:3}
  .bcast-stream-exp{order:4}
  .bcast-stream-mark{order:5}
  /* The move list keeps a cap so it cannot push the panels off the bottom. */
  .bcast-stream-moves{flex:none;max-height:46vh}
  .bcast-stream-exp{max-height:none}
  /* The fixed watermark sits over the scrolling content; inline it instead. */
  .bcast-stream-mark{position:static;text-align:right;padding:2px 4px 8px}
}

.bcast-stream-moves{flex:1 1 auto;min-height:0;overflow-y:auto;
  background:rgba(8,22,32,.82);border-radius:6px;padding:6px 8px;
  scrollbar-width:thin;scrollbar-color:#2c5a6b transparent}
/* The move list is the /live one; only its skin differs here. */
.bcast--stream .bcast-movelist{margin:0;padding:0;list-style:none;font-size:15px}
.bcast--stream .bcast-movelist li{display:grid;grid-template-columns:2.2em 1fr 1fr;gap:4px;
  padding:2px 4px;border-radius:4px}
.bcast--stream .bcast-movelist li:nth-child(odd){background:rgba(255,255,255,.03)}
.bcast--stream .mvn{color:#7fd6ea;font-variant-numeric:tabular-nums;opacity:.8}
.bcast--stream .mvcell .mv{font-weight:650;color:#eaf6fb}
.bcast--stream .mvcell.on{background:rgba(12,127,153,.92);border-radius:3px}
.bcast--stream .bcast-moves-empty{color:#7fd6ea;opacity:.7;margin:0;padding:4px}

/* Analysis: three lines, fixed order, so nothing jumps as depth climbs. */
.bcast-stream-eng{flex:none;background:rgba(8,22,32,.86);border-radius:6px;padding:7px 9px}
.bcast-eng-head{display:flex;align-items:baseline;justify-content:space-between;
  font-size:11px;letter-spacing:.04em;text-transform:uppercase;color:#7fd6ea;margin-bottom:5px}
.bcast-eng-t{font-weight:800}
.bcast-eng-d{opacity:.75;font-variant-numeric:tabular-nums;margin-left:auto}
/* Attribution inside the panel header — see renderAnalysis() for why it is not
   the column's last child any more. */
.bcast-eng-mark{margin-left:10px;font-weight:800;letter-spacing:0;text-transform:none;
  font-size:12px;color:#eaf6fb;opacity:.9}
.bcast-eng-mark b{color:#7fd6ea;font-weight:800}
.bcast-eng-row{display:flex;gap:8px;align-items:baseline;padding:2px 0;font-size:14px;line-height:1.35}
.bcast-eng-ev{flex:none;min-width:3.6em;font-weight:800;font-variant-numeric:tabular-nums;
  color:#eaf6fb}
.bcast-eng-ev.w{color:#dff3fa}
.bcast-eng-ev.b{color:#ffc9c9}
/* One line, clipped — a wrapped line moves the rows under it, which on a stream
   reads as flicker rather than as information. */
.bcast-eng-line{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  color:#cfe6ef;font-variant-numeric:tabular-nums}
.bcast-eng-line i{font-style:normal;color:#7fd6ea;opacity:.8;margin-right:1px}

/* Opening explorer (?explorer=1). Two panes — theory, then the fast games —
   on ONE plate, because they are two halves of one statement about the position
   rather than two competing boxes. Same plate/type language as the analysis
   panel above so a scene carrying both does not look assembled from parts. */
.bcast-stream-exp{flex:none;background:rgba(8,22,32,.86);border-radius:6px;padding:7px 9px}
.bcast-exp-pane+.bcast-exp-pane{margin-top:7px;padding-top:6px;
  border-top:1px solid rgba(127,214,234,.18)}
.bcast-exp-head{display:flex;align-items:baseline;gap:8px;font-size:11px;letter-spacing:.04em;
  text-transform:uppercase;color:#7fd6ea;margin-bottom:5px}
/* The pane titles name their venue/speed set ("Rapid, Blitz & Bullet"), which is
   longer than a one-word label — it must yield to the count rather than push it
   out of the panel. */
.bcast-exp-t{font-weight:800;min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.bcast-exp-n{margin-left:auto;font-variant-numeric:tabular-nums;color:#eaf6fb;font-weight:700}
.bcast-exp-y{opacity:.7;font-variant-numeric:tabular-nums;font-size:10px}
/* Flex-weighted by the RAW counts, not by rounded percentages, so the three
   segments always fill the bar exactly. */
.bcast-exp-bar{display:flex;height:6px;border-radius:3px;overflow:hidden;margin-bottom:6px;
  background:rgba(255,255,255,.06)}
.bcast-exp-bar .w{background:#e8f4f8}
.bcast-exp-bar .d{background:#5a8fa3}
/* Light enough to separate from the plate behind it. At #123243 the black share
   was very nearly the panel's own background, so a 30% black score read as a
   two-part bar — on a stream, at broadcast bitrates, it simply vanished. */
.bcast-exp-bar .b{background:#24596f}
.bcast-exp-moves{margin:0;padding:0;list-style:none;font-size:14px}
.bcast-exp-moves li{display:flex;gap:8px;align-items:baseline;padding:2px 4px;
  border-radius:4px;line-height:1.35}
.bcast-exp-moves li:nth-child(odd){background:rgba(255,255,255,.03)}
.bcast-exp-moves b{flex:none;min-width:3.4em;font-weight:700;color:#eaf6fb}
.bcast-exp-moves .n{flex:1;min-width:0;text-align:right;color:#cfe6ef;
  font-variant-numeric:tabular-nums}
.bcast-exp-moves .s{flex:none;min-width:2.8em;text-align:right;color:#7fd6ea;opacity:.85;
  font-variant-numeric:tabular-nums}
.bcast-exp-moves .more{color:#7fd6ea;opacity:.6;font-size:12px;justify-content:flex-end}
.bcast-exp-pane.is-compact .bcast-exp-moves{font-size:13px}
.bcast-exp-pane.is-compact .bcast-exp-bar{height:4px}
/* "No games" — the index holds nothing for this position. Amber rather than the
   column's blue: on a broadcast it is a finding, not a blank. */
.bcast-exp-none{color:#ffd9a0}
.bcast-exp-novel{margin:0;color:#ffd9a0;font-size:13px}
/* Novelty — where the game left the book. Amber, like "No games", because both
   are findings rather than statistics; the two never appear together. */
.bcast-exp-nov .bcast-exp-t{color:#ffd9a0}
.bcast-nov-row+.bcast-nov-row{margin-top:5px;padding-top:4px;
  border-top:1px dotted rgba(127,214,234,.15)}
.bcast-nov-mv{font-size:15px;font-weight:800;color:#ffd9a0;line-height:1.25}
.bcast-nov-mv i{font-style:normal;opacity:.7;margin-left:4px;font-size:12px}
.bcast-nov-prev{font-size:11px;color:#7fd6ea;opacity:.85;
  font-variant-numeric:tabular-nums}
/* One line, clipped: a wrapped citation moves everything under it, which on a
   stream reads as flicker rather than as information. */
.bcast-nov-cite{font-size:11px;color:#cfe6ef;opacity:.85;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
/* Year · tournament, under the pairing. */
.bcast-nov-ev{font-size:11px;color:#7fd6ea;opacity:.7;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}

/* The prior practice a novelty departs from. Scrolls rather than growing the
   panel: an early novelty can have tens of thousands of games behind it, and
   the board must not lose height to a citation list. */
.bcast-nov-list{margin-top:5px}
.bcast-nov-lh{display:flex;justify-content:space-between;align-items:baseline;
  gap:6px;font-size:10px;letter-spacing:.04em;text-transform:uppercase;
  color:#7fd6ea;opacity:.85;padding-bottom:3px;
  border-bottom:1px solid rgba(127,214,234,.18)}
.bcast-nov-lh span{opacity:.7;text-transform:none;letter-spacing:0}
.bcast-nov-list ul{margin:0;padding:0;list-style:none;
  max-height:min(34vh,260px);overflow-y:auto;
  scrollbar-width:thin;scrollbar-color:#2c5a6b transparent}
.bcast-nov-list li{padding:3px 0;line-height:1.3}
.bcast-nov-list li+li{border-top:1px solid rgba(127,214,234,.08)}
.bcast-nov-list .r1,.bcast-nov-list .r2{display:flex;gap:6px;align-items:baseline}
.bcast-nov-list .p{flex:1;min-width:0;white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis;color:#eaf6fb;font-size:12px}
/* What that game played instead — the reason the row is here at all. */
.bcast-nov-list .mv{flex:none;color:#ffd9a0;font-weight:700;font-size:12px}
.bcast-nov-list .y{flex:none;color:#7fd6ea;opacity:.8;font-size:11px;
  font-variant-numeric:tabular-nums}
.bcast-nov-list .ev{flex:1;min-width:0;white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis;color:#cfe6ef;opacity:.65;font-size:11px}
.bcast-nov-list .e{flex:none;color:#7fd6ea;opacity:.8;font-size:11px;
  font-variant-numeric:tabular-nums}
/* "instead of 20.Rd1" — what the deepest previous game did from here. */
.bcast-nov-inst{font-size:12px;color:#cfe6ef;opacity:.85}
.bcast-nov-inst b{color:#eaf6fb;font-weight:700}

/* A clickable continuation. Plays the move on the board: forward along the game
   when it is the move actually played, a variation when it is not. */
.bcast-exp-moves li[data-exp-uci]{cursor:pointer}
.bcast-exp-moves li[data-exp-uci]:hover,
.bcast-exp-moves li[data-exp-uci]:focus-visible{background:rgba(12,127,153,.55);
  outline:none}
.bcast-exp-moves li[data-exp-uci]:focus-visible{box-shadow:inset 0 0 0 1px #7fd6ea}

/* Hover card: the five highest-rated games that played that move. Fixed to the
   viewport and drawn to the LEFT of the column, over the board, because the
   column itself has no room for it. */
.bcast-mcard{position:fixed;z-index:40;width:270px;max-width:44vw;
  background:rgba(6,18,26,.97);border:1px solid rgba(127,214,234,.28);
  border-radius:6px;padding:6px 8px;color:#eaf6fb;
  box-shadow:0 6px 22px rgba(0,0,0,.45);pointer-events:none}
.bcast-mcard-h{display:flex;justify-content:space-between;align-items:baseline;
  gap:8px;font-size:11px;letter-spacing:.04em;text-transform:uppercase;
  color:#7fd6ea;margin-bottom:4px}
.bcast-mcard-h b{font-size:14px;text-transform:none;letter-spacing:0;color:#eaf6fb}
.bcast-mcard-h span{font-variant-numeric:tabular-nums}
.bcast-mcard ul{margin:0;padding:0;list-style:none;font-size:12px}
/* Two lines per game: pairing + rating, then year + tournament. */
.bcast-mcard li{padding:2px 0;line-height:1.3}
.bcast-mcard li+li{border-top:1px solid rgba(127,214,234,.10)}
.bcast-mcard .r1,.bcast-mcard .r2{display:flex;gap:6px;align-items:baseline}
.bcast-mcard .p{flex:1;min-width:0;white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis;color:#eaf6fb}
.bcast-mcard .e{flex:none;color:#7fd6ea;font-variant-numeric:tabular-nums}
.bcast-mcard .y{flex:none;color:#7fd6ea;opacity:.8;font-variant-numeric:tabular-nums}
.bcast-mcard .ev{flex:1;min-width:0;white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis;color:#cfe6ef;opacity:.72;font-size:11px}
.bcast-mcard-none{margin:0;font-size:12px;color:#7fd6ea;opacity:.7}

/* ── /live: the move box carries a «Θεωρία» tab ──────────────────────────────
   The openings panel gets no column of its own on /live — at 1280 the rail
   beside this box is already down to 110px — so it shares the move box. Same
   height, same width, no new real estate. */
.bcast-mtabs{display:flex;gap:4px;margin:0 0 6px}
.bcast-mtabs button{flex:0 0 auto;padding:3px 10px;border:1px solid transparent;
  background:none;color:#7fd6ea;font:800 12px/1.4 inherit;letter-spacing:.04em;
  text-transform:uppercase;border-radius:5px;cursor:pointer}
.bcast-mtabs button:hover{color:#eaf6fb;background:rgba(127,214,234,.10)}
.bcast-mtabs button.on,.bcast-mtabs button[aria-selected="true"]{background:#0c7f99;
  color:#04222b;border-color:#0c7f99}
.bcast-book{min-height:0;overflow-y:auto;
  scrollbar-width:thin;scrollbar-color:#2c5a6b transparent}
/* The hero board is a link to that game on /live. It fills the board (and the
   eval bar beside it — neither is interactive in this mode), sits above the
   squares, and carries no visible chrome of its own: the affordance is the
   cursor and a faint lift, because a homepage hero should not grow a button. */
.bcast--compact .bcast-board-wrap{position:relative}
.bcast-compact-link{position:absolute;inset:0;z-index:3;cursor:pointer;
  border-radius:inherit;transition:box-shadow .12s ease}
.bcast-compact-link:hover,
.bcast-compact-link:focus-visible{outline:none;
  box-shadow:0 0 0 2px rgba(127,214,234,.55)}
.bcast-compact-link:not([href]){pointer-events:none}

/* 📺 → this game as an OBS source, everything on. Pushed to the far end so it
   reads as an action rather than a third tab. */
.bcast-mtab-tv{margin-left:auto;padding:3px 7px;border-radius:5px;font-size:14px;
  line-height:1.4;text-decoration:none;cursor:pointer;opacity:.75}
.bcast-mtab-tv:hover{opacity:1;background:rgba(127,214,234,.14)}
.bcast-mtab-tv:not([href]){opacity:.3;pointer-events:none}

/* The novelty marker: one character, in a cell that already exists. */
.mv-nov{margin-left:3px;color:#c98a2b;font-weight:800;font-size:.92em;cursor:help}
.bcast--stream .mv-nov{color:#ffd9a0}

/* With a side column the watermark would sit on top of the analysis panel, so it
   stops being fixed to the frame corner and becomes the last item in the column.
   TWO classes on purpose: the base `.bcast-stream-mark{position:fixed}` is
   declared LATER in this file, and at equal specificity the later rule wins —
   this modifier lost that race when it was written as a single class. */
/* Always LAST in the row. It is a flex sibling of the two side columns, so once
   the move list took `order:1` the default-order watermark slid in between the
   board and the list and opened a 95px gap there. */
.bcast--stream .bcast-stream-mark--inline{order:2;position:static;align-self:flex-end;flex:none;
  margin-top:auto;padding:2px 6px;border-radius:4px;background:rgba(8,22,32,.7)}
/* The rows carry their own plate: the page is transparent, so they have to stay
   readable over whatever the streamer has behind them. They are centred on the
   board rather than the frame, so the three elements read as one unit. */
.bcast--stream .bcast-player{background:rgba(8,22,32,.82);border-radius:6px;padding:.4rem .7rem;
  width:100%;font-size:1.15rem;line-height:1.25;color:#eaf6fb}
.bcast--stream .bcast-player.on{background:rgba(12,127,153,.92)}
.bcast--stream .bcast-nm{font-weight:700}
.bcast--stream .bcast-rt{font-size:.8em;opacity:.75;margin-left:.4rem}
.bcast--stream .bcast-ti{font-size:.8em;color:#7fd6ea;font-weight:800}
.bcast--stream .bcast-clk{font-size:1.15em;font-weight:800;font-variant-numeric:tabular-nums;margin-left:auto;padding-left:.6rem}
.bcast--stream .bcast-flag{height:15px}
.bcast--stream .bcast-evalbar .eval-num{font-size:11px}
.bcast--stream .bcast-evalbar .eval-depth{font-size:8px}
/* Like the name rows, the watermark carries its own plate: the page is
   transparent, so this can end up over ANY colour the streamer has behind it,
   and light-text-at-half-opacity simply vanished on a pale backdrop. */
.bcast-stream-mark{position:fixed;right:12px;bottom:10px;font:800 15px/1 var(--font-sans,system-ui),sans-serif;
  color:#eaf6fb;letter-spacing:.02em;padding:.3rem .55rem;border-radius:5px;
  background:rgba(8,22,32,.72);pointer-events:none}
.bcast-stream-mark b{color:#7fd6ea;font-weight:800}
@media (max-height:620px){ .bcast--stream .bcast-player{font-size:.95rem;padding:.25rem .5rem} }

.bcast--compact{display:flex;flex-direction:column;gap:10px}
.bcast-main{display:flex;gap:20px;align-items:flex-start}
/* board + the two player rows that flank it (black above, white below) */
/* width = board 380 + eval bar 24 + gap 6, so the board keeps its full 380px with the bar present */
.bcast-left{display:flex;flex-direction:column;gap:8px;flex:none;width:min(410px,100%)}
.bcast--compact .bcast-left{width:min(320px,100%);margin:0 auto}
/* board: client-side grid of cyan squares + REAL (un-recolored) piece SVGs */
.bcast-board{position:relative;display:grid;grid-template-columns:repeat(8,1fr);grid-template-rows:repeat(8,1fr);width:100%;aspect-ratio:1/1;border-radius:8px;overflow:hidden;box-shadow:0 6px 22px rgba(0,0,0,.28)}
.bcast-sq{position:relative}
.bcast-sq.lt{background:var(--bsq-l,#d8f1f7)}
.bcast-sq.dk{background:var(--bsq-d,#0c7f99)}
/* last move — amber fill + ring, high-contrast against the cyan board */
.bcast-sq.hl::after{content:"";position:absolute;inset:0;background:rgba(255,193,7,.5);box-shadow:inset 0 0 0 3px rgba(255,179,0,.9)}
/* Move input: clickable squares, selected source, legal destinations.
   `manipulation` — NOT `none`. `touch-action` governs touch/pen panning only
   (a mouse drag is unaffected by it), and `none` over a square board that is
   full-bleed on /live and sits mid-page in the hero module turned the whole
   board into a scroll dead zone: a finger swipe starting on it moved nothing.
   `manipulation` gives the page its scroll back and still drops double-tap
   zoom, so two quick taps on neighbouring squares read as two taps and not as
   a zoom gesture. Touch keeps two-tap move input (live-broadcast.js refuses to
   start a drag for a touch/pen pointer); the mouse keeps press-and-drag. */
.bcast-board{touch-action:manipulation}
/* Texture themes (wood / walnut / marble) paint a tile image over the flat
   colour, which stays as the fallback while the JPG loads or if it 404s. The
   vars are unset for flat themes, so `none` keeps those on colour alone. */
.bcast-sq.lt{background-image:var(--bsq-l-img,none);background-size:cover;background-position:center}
.bcast-sq.dk{background-image:var(--bsq-d-img,none);background-size:cover;background-position:center}
.bcast-board .bcast-sq{cursor:pointer}
.bcast-drag{position:fixed;pointer-events:none;z-index:1000;transform:translate(-50%,-50%);filter:drop-shadow(0 4px 6px rgba(0,0,0,.5))}
/* underpromotion picker — Q/R/B/N over the promotion file */
.bcast-promo{position:absolute;inset:0;z-index:20;display:grid;grid-template-columns:repeat(8,1fr);grid-template-rows:repeat(8,1fr);background:rgba(7,20,30,.6)}
.bcast-promo-pc{border:0;padding:0;display:block;cursor:pointer;background:#eef3f6;box-shadow:0 0 0 2px rgba(127,214,234,.7)}
.bcast-promo-pc:hover{background:#fff}
.bcast-promo-pc img{width:100%;height:100%;display:block}
.bcast-sq.sel::before{content:"";position:absolute;inset:0;background:rgba(255,205,40,.42)}
.bcast-sq.dest::after{content:"";position:absolute;left:0;top:0;right:0;bottom:0;margin:auto;width:30%;height:30%;border-radius:50%;background:rgba(11,30,44,.32)}
.bcast-sq.dest:not([data-piece=""])::after{width:84%;height:84%;background:transparent;border:4px solid rgba(11,30,44,.32);box-sizing:border-box}
.bcast-pc{position:relative;z-index:1;display:block;width:100%;height:100%;pointer-events:none;-webkit-user-drag:none;user-select:none} /* pieces are inert: input goes to the square, no native img drag */
/* Stockfish eval bar — sits to the left of the board, full board height */
.bcast-board-wrap{display:flex;gap:6px;align-items:stretch;width:100%}
.bcast-board-wrap .bcast-board{flex:1;min-width:0}
.bcast-evalbar{position:relative;flex:none;width:24px;background:#16242f;border-radius:5px;overflow:hidden;box-shadow:0 6px 22px rgba(0,0,0,.28)}
.bcast-evalbar[hidden]{display:block;visibility:hidden} /* override UA display:none — keep the 24px reserved so toggling never resizes the board */
.bcast-evalbar .eval-fill{position:absolute;left:0;right:0;bottom:0;height:50%;background:#eef3f6;transition:height .35s ease}
.bcast-evalbar .eval-num{position:absolute;left:1px;right:1px;top:3px;text-align:center;font-size:9px;font-weight:800;font-variant-numeric:tabular-nums;line-height:1.35;z-index:2;color:#fff;background:rgba(11,26,38,.55);border-radius:3px}
.bcast-evalbar .eval-depth{position:absolute;left:1px;right:1px;bottom:3px;text-align:center;font-size:7px;font-weight:700;line-height:1.4;z-index:2;color:#cdeefb;background:rgba(11,26,38,.55);border-radius:3px}
.bcast-meta{flex:1;min-width:0;display:flex;flex-direction:column;gap:10px}
.bcast--compact .bcast-meta{width:min(300px,100%);margin:0 auto}
.bcast-eyebrow{color:#7fd6ea;font-weight:700;font-size:10.5px;letter-spacing:.4px;text-transform:uppercase}
.bcast-title{font-family:var(--disp);font-size:19px;font-weight:700;line-height:1.25;margin:0}
.bcast-title--compact{font-size:15px;text-align:center}
/* data panels (player names, game list, moves) — muted deep cyan on the navy card */
.bcast-player{display:flex;align-items:center;gap:8px;background:#0c5266;border-radius:8px;padding:9px 12px}
.bcast-player:empty{display:none}
.bcast-player.on{box-shadow:inset 3px 0 0 #7fd6ea}
/* Hero live: a long player name must NOT wrap to a 2nd row (it pushes the board
   down). Let the name shrink + ellipsis; keep the clock at its natural width. */
.zone--live .bcast-player{flex-wrap:nowrap}
.zone--live .bcast-nm{flex:1 1 auto;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.zone--live .bcast-clk{flex:0 0 auto;white-space:nowrap}
.bcast-nm{font-weight:600;font-size:14px}
.bcast-score{margin-left:auto;font-weight:800;font-size:15px;color:#fff;font-variant-numeric:tabular-nums;background:rgba(255,255,255,.14);border-radius:6px;padding:1px 9px;min-width:18px;text-align:center}
/* Running tournament score — a cyan chip right of the rating (left of the result
   badge / clock). Distinct from the white per-game result badge above. */
.bcast-tscore{font-weight:800;font-size:12.5px;color:#04222b;background:#7fd6ea;border-radius:6px;padding:1px 7px;font-variant-numeric:tabular-nums;text-align:center}
.bcast-flag{height:12px;width:auto;border-radius:2px;margin-right:6px;vertical-align:baseline;box-shadow:0 0 0 1px rgba(255,255,255,.15)}
.bcast-gtip-nm .bcast-flag{height:11px;margin-right:5px}
.bcast-ti{color:#bfe9f4;font-weight:700;font-size:.82em;margin-right:3px}
.bcast-rt{color:#bfe9f4;font-weight:400;font-size:.82em;margin-left:6px}
.bcast-clk{margin-left:auto;font-variant-numeric:tabular-nums;font-weight:800;font-size:1.05em;color:#eafcff}
.bcast-turn{color:#bfe3ec;font-size:13px;margin:2px 0 0}
.bcast-turn:empty{display:none} /* no live turn string any more — collapse when there's no result */
/* PV / best-line readout above the move list (live-games §11 — dedicated engine):
   one line = eval + depth + the principal variation as clickable moves. Truncates
   to fit (full-width on mobile since .bcast-meta stretches there). */
.bcast-pv{display:flex;align-items:baseline;gap:9px;background:#0c5266;border-radius:8px;padding:7px 11px;margin:6px 0 4px;font-size:13px;line-height:1.35}
.bcast-pv[hidden]{display:none}
.bcast-pv-ev{flex:none;font-weight:800;color:#8fe0b0;font-variant-numeric:tabular-nums}
.bcast-pv-ev.neg{color:#ff9b9b}
.bcast-pv-d{flex:none;font-size:10px;font-weight:700;letter-spacing:.02em;color:#7fd6ea;opacity:.85;white-space:nowrap}
.bcast-pv-line{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.bcast-pv-mv{background:none;border:0;color:#eafcff;font:inherit;font-weight:600;cursor:pointer;padding:1px 3px;border-radius:4px}
.bcast-pv-mv:hover,.bcast-pv-mv:focus-visible{background:rgba(255,255,255,.14);outline:none}
.bcast-pv-mv.on{background:rgba(127,214,234,.30);color:#fff}
.bcast-pv-n{color:#7fd6ea;font-weight:400;margin-right:1px;font-variant-numeric:tabular-nums}
.bcast-moves-box{margin-top:0}
/* right column: tournament info (top) + game list, aligned with the move list */
.bcast-side{display:flex;flex-direction:column;gap:16px;min-width:0}
.bcast-tourney h4,.bcast-box h4{font-size:11.5px;text-transform:uppercase;letter-spacing:.4px;color:#7fd6ea;margin:0 0 8px;font-family:var(--sans)}
.bcast-tourney-name{font-family:var(--disp);font-size:14px;font-weight:700;line-height:1.3;margin:0 0 10px;color:#fff}
.bcast-facts{margin:0;display:grid;grid-template-columns:auto 1fr;gap:5px 10px;font-size:12px}
.bcast-facts dt{color:#bfe9f4;white-space:nowrap}
.bcast-facts dd{margin:0;color:#fff}
/* games-list header: heading + name search + "next Greek game" jump */
.bcast-games-head{display:flex;align-items:center;gap:7px;margin:0 0 8px}
.bcast-games-head h4{margin:0;flex:none}
.bcast-games-search{flex:1;min-width:50px;background:#0c5266;border:0;border-radius:6px;color:#fff;font:inherit;font-size:12px;padding:5px 8px}
.bcast-games-search::placeholder{color:#bfe3ec;opacity:.7}
.bcast-games-search:focus-visible{outline:2px solid #7fd6ea;outline-offset:0}
.bcast-games-greek{flex:none;width:30px;height:26px;border:0;border-radius:6px;background:#0c5266;cursor:pointer;display:flex;align-items:center;justify-content:center;padding:0}
/* Scanning the event's other sections for Greek boards — the click already did
   something, so this says "working" rather than leaving the button inert. */
.bcast-games-greek.is-busy{opacity:.55;cursor:progress}
/* Matches in the event's OTHER sections, under the round's own games list. */
.bcast-xsec{display:flex;flex-direction:column;gap:2px;padding:6px 0 0;border-top:1px solid #12506a;margin-top:6px}
.bcast-xsec[hidden]{display:none}
.bcast-xsec-note{font-size:11px;color:#8fc4dc;padding:0 2px}
.bcast-xsec-hit{display:flex;flex-direction:column;gap:1px;text-align:left;background:none;border:0;border-radius:5px;padding:4px 6px;cursor:pointer;color:#eaf6fb}
.bcast-xsec-hit:hover{background:#0e6f93}
.bcast-xsec-pl{display:flex;align-items:center;gap:5px;font-size:12.5px;font-weight:700}
.bcast-xsec-sec{font-size:11px;color:#9dd3e8}
.bcast-games-greek img{height:13px;width:auto;border-radius:2px;box-shadow:0 0 0 1px rgba(255,255,255,.2)}
.bcast-games-greek:hover:not(:disabled){background:#0e6f93}
.bcast-games-greek:disabled{opacity:.3;cursor:default}
.bcast-grow[hidden]{display:none}
.bcast-grow-pl .bcast-flag{height:11px;margin-right:5px;vertical-align:-1px}
.bcast-games{max-height:300px;overflow:auto} /* JS caps to align with the board bottom */
.bcast-grow{display:flex;justify-content:space-between;align-items:center;gap:10px;width:100%;text-align:left;
  background:#0c5266;border:0;border-radius:8px;padding:9px 12px;margin-bottom:6px;color:#fff;cursor:pointer;font:inherit}
.bcast-grow:hover{background:#0e6f93}
.bcast-grow.gr{background:#1a7d95}            /* Greek/Cyprus interest — lighter hue */
.bcast-grow.gr:hover{background:#2090ab}
.bcast-grow.on{box-shadow:inset 3px 0 0 #7fd6ea}
.bcast-grow-pl{font-weight:600;font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.bcast-grow-res{font-size:12px;color:#dff4fa;white-space:nowrap}
.bcast-grow-res .lv{color:#c8f3ff;font-weight:600}
.bcast-growstream{flex:none;margin-left:2px;font-size:12px;line-height:1;opacity:.45;cursor:pointer;transition:opacity .15s}
.bcast-grow:hover .bcast-growstream{opacity:1}
.bcast-growstream:hover{transform:scale(1.2)}
/* Team events (Lichess broadcast `teamTable`) — matchup grouping in the games
   list, a team-pairing picker, and per-row team labels. Team STANDINGS live in
   the tournament-name hover popover (reuses .bcast-stip-rows), not on the surface. */
.bcast-team-filter[hidden],.bcast-match[hidden]{display:none}
.bcast-team-filter{width:100%;margin:0;background:#0c5266;border:0;border-radius:6px;color:#fff;font:inherit;font-size:12px;padding:6px 8px}
.bcast-team-filter:focus-visible{outline:2px solid #7fd6ea;outline-offset:0}
.bcast-match{margin:0 0 12px}
.bcast-match-head{display:flex;align-items:center;gap:8px;padding:0 2px 6px;margin-bottom:6px;font-size:12px;font-weight:700;color:#bfe9f4;border-bottom:1px solid rgba(127,214,234,.22)}
.bcast-match-head .bcast-match-t{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.bcast-match-head .bcast-match-t:last-child{text-align:right}
.bcast-match-head .bcast-match-sc{flex:none;color:#fff;background:#0c5266;border-radius:5px;padding:1px 8px;font-variant-numeric:tabular-nums}
.bcast-pteam{margin-left:7px;font-size:11px;font-weight:600;color:#7fd6ea;opacity:.9;white-space:nowrap}
.bcast-moves{max-height:340px;overflow:auto;background:#0c5266;border-radius:8px;padding:6px 4px} /* JS caps to the board bottom */
.bcast-moves:focus-visible{outline:2px solid #7fd6ea;outline-offset:1px} /* keyboard nav active */
.bcast-moves-hint{margin:5px 2px 0;font-size:10px;line-height:1.3;color:#7fd6ea;opacity:.75;text-align:center}
.bcast-movelist{list-style:none;margin:0;padding:0;font-variant-numeric:tabular-nums}
.bcast-movelist li{display:grid;grid-template-columns:24px 1fr 1fr;gap:4px;padding:1px 6px;font-size:13px;align-items:stretch}
/* analysis variations: indented inline sub-lines */
.bcast-movelist li.bcast-var{display:block;padding:1px 6px 3px}
.bcast-var .vline{font-size:12px;line-height:1.55;color:#bfe3ec;padding-left:7px;border-left:2px solid #0e6f93;margin:2px 0}
.bcast-var .vnum{color:#7fd6ea;margin-right:1px;font-variant-numeric:tabular-nums}
.bcast-var .vmv{cursor:pointer;color:#eafcff;font-weight:600;padding:0 2px;border-radius:3px}
.bcast-var .vmv:hover{background:rgba(255,255,255,.12)}
.bcast-var .vmv.on{background:rgba(216,241,247,.34)}
.bcast-movelist .mvn{color:#bfe9f4;align-self:center}
/* one move = SAN on the left, its stored eval on the right; the whole cell is clickable */
.mvcell{display:flex;justify-content:flex-start;align-items:baseline;gap:6px;min-width:0;cursor:pointer;border-radius:4px;padding:2px 5px}
.mvcell[data-ply]:hover{background:rgba(255,255,255,.10)}
.mvcell.on{background:rgba(216,241,247,.34)}
.mvcell .mv{font-weight:600;color:#fff;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mvcell .mvc{font-size:10.5px;color:#bfe9f4;opacity:.85;font-variant-numeric:tabular-nums;flex:none;margin-left:auto}
.bcast-moves-empty{color:#bfe3ec;text-align:center;padding:14px;margin:0}
.bcast-moves-box{margin-top:4px}
/* middle column lower row: narrowed move list (left) + suggestions rail (right) */
/* The move box never shrank (`flex:none;width:280px`) and the rail was
   `flex:1;min-width:0`, so the rail absorbed EVERY pixel of shortfall and was
   explicitly allowed to reach zero. Measured before this: 270px at 1500, 110px
   at 1280 with the titles clipped to "A Co…", and literally 0px below ~1150 —
   two product cards still in the DOM, still laid out, impossible to see. The
   only stacking rule was `max-width:860px`, leaving 860–1350 unhandled: exactly
   the common laptop widths.

   Now it WRAPS instead of collapsing. `min-width` on the rail is the floor a
   card is still readable at (42px thumbnail + a two-line title); once the pair
   cannot both hold their floor, the rail moves under the move list at full
   width, which is what already happened below 860 and reads fine. */
.bcast-mid{display:flex;flex-wrap:wrap;gap:14px;align-items:flex-start;margin-top:4px}
.bcast-mid .bcast-moves-box{flex:0 1 280px;min-width:0;margin-top:0}
/* `min(190px, 100%)`, not a bare 190px: between roughly 860 and 1150 the whole
   three-column layout squeezes this middle column to almost nothing (24px at
   900), and a hard floor there would spill the rail over the games list beside
   it. A floor that yields to the container keeps the fix an improvement
   everywhere instead of trading one defect for another. */
.bcast-suggest{flex:1 1 190px;min-width:min(190px,100%);margin-top:0}
/* A grid rather than a column: side by side it is one card wide exactly as
   before, and once the rail wraps to full width it uses that width instead of
   leaving a single column with empty space beside it. */
.bcast-suggest-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));
  gap:8px;align-content:start;overflow:auto} /* JS caps to board bottom */
/* At this point the pair can no longer both be usable, so make the stack
   deliberate: the move list takes the row and the rail follows underneath. */
@media (max-width:1330px){
  .bcast-mid .bcast-moves-box{flex-basis:100%;width:auto}
}
.bcast-sg{display:flex;gap:10px;align-items:center;background:#0c5266;border-radius:8px;padding:8px 10px;text-decoration:none;color:#fff}
.bcast-sg:hover{background:#0e6f93}
.bcast-sg-img{width:42px;height:42px;flex:none;border-radius:6px;object-fit:cover;background:#0a3a4a}
.bcast-sg-ph{display:flex;align-items:center;justify-content:center;color:#7fd6ea;font-size:20px}
.bcast-sg-tx{display:flex;flex-direction:column;min-width:0;gap:1px}
.bcast-sg-rs{font-size:10px;text-transform:uppercase;letter-spacing:.3px;color:#7fd6ea;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.bcast-sg-ti{font-size:12.5px;font-weight:600;line-height:1.25;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
/* article "Σχετικά" rail reuses the live .bcast-sg cards inside the news aside,
   but RE-SKINS them for the white article page: light surface (not the broadcast
   navy), and a large PORTRAIT book cover stacked above the text so each card is
   a tall "shelf" entry (~5–6 of the rail's compact rows). Scoped to
   .article-suggest so the dark broadcast cards are untouched. */
.article-suggest{margin-top:14px}
.article-suggest .bcast-suggest-list{overflow:visible;gap:16px}
.article-suggest .bcast-sg{flex-direction:column;align-items:stretch;gap:8px;background:#fff;border:1px solid #cfe8f2;border-radius:10px;padding:10px;color:var(--ink);box-shadow:0 4px 14px rgba(20,40,80,.06)}
.article-suggest .bcast-sg:hover{background:#f3fbfd;border-color:var(--cyan);box-shadow:0 6px 18px rgba(12,127,153,.14)}
.article-suggest .bcast-sg-img{width:100%;height:auto;aspect-ratio:3/4;border-radius:6px;background:#eef7fb}
.article-suggest .bcast-sg-ph{font-size:42px;color:var(--cyan-d)}
.article-suggest .bcast-sg-rs{color:var(--cyan-d)}
.article-suggest .bcast-sg-ti{color:var(--ink);font-size:13.5px;-webkit-line-clamp:3}
/* JS-fitted (article-rail-fit.js): when a short article can't hold the big
   stacked portrait covers, switch to COMPACT rows — a small portrait thumbnail
   BESIDE the text (far more height-efficient) sized to --sg-cover-h so all the
   cards fit the article height without a scrollbar. Scroll is only a last-resort
   fallback (inline max-height/overflow set by the island) for extreme cases. */
.article-suggest.is-compact .bcast-suggest-list{gap:8px}
.article-suggest.is-compact .bcast-sg{flex-direction:row;align-items:center;gap:10px;padding:8px}
.article-suggest.is-compact .bcast-sg-img{width:auto;height:var(--sg-cover-h);flex:none;margin:0}
.article-suggest.is-compact .bcast-sg-tx{flex:1;min-width:0}
.article-suggest.is-compact .bcast-sg-ti{-webkit-line-clamp:2;font-size:13px}
.article-suggest.is-compact .bcast-suggest-list{scrollbar-width:thin}
/* Editor-curated "Related articles" — the last block in the article rail. A
   compact vertical list of small horizontal cards (thumb left, title+date). */
.related-articles{margin-top:16px}
.related-articles>h4{margin:0 0 8px}
.related-articles__list{display:flex;flex-direction:column;gap:8px}
.related-articles__item{display:flex;gap:10px;align-items:center;text-decoration:none;color:var(--ink);background:#fff;border:1px solid #cfe8f2;border-radius:10px;padding:8px;box-shadow:0 4px 14px rgba(20,40,80,.06)}
.related-articles__item:hover{background:#f3fbfd;border-color:var(--cyan);box-shadow:0 6px 18px rgba(12,127,153,.14)}
.related-articles__img{width:56px;height:42px;flex:none;border-radius:6px;object-fit:cover;background:#eef7fb}
.related-articles__img--ph{display:flex;align-items:center;justify-content:center;color:var(--cyan-d);font-size:22px}
.related-articles__tx{display:flex;flex-direction:column;min-width:0;gap:2px}
.related-articles__ti{font-size:13px;font-weight:600;line-height:1.25;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.related-articles__dt{font-size:11px;color:var(--grey)}
/* hover preview popover for the round games list (mini board + full names) */
.bcast-gtip{position:fixed;z-index:60;width:196px;background:#001e44;border:1px solid #0e6f93;border-radius:10px;padding:8px;box-shadow:0 14px 44px rgba(0,0,0,.5);pointer-events:none}
.bcast-gtip[hidden]{display:none}
.bcast-gtip-row{display:flex;gap:6px;align-items:stretch}
.bcast-gtip-b{display:grid;grid-template-columns:repeat(8,1fr);grid-template-rows:repeat(8,1fr);flex:1;min-width:0;aspect-ratio:1/1;border-radius:4px;overflow:hidden}
.bcast-gtip-eval{position:relative;flex:none;width:13px;background:#16242f;border-radius:4px;overflow:hidden}
.bcast-gtip-eval .gte-fill{position:absolute;left:0;right:0;bottom:0;height:50%;background:#eef3f6;transition:height .3s ease}
.bcast-gtip-eval .gte-num{position:absolute;left:0;right:0;top:2px;text-align:center;font-size:8px;font-weight:800;font-variant-numeric:tabular-nums;line-height:1.25;z-index:2;color:#fff;background:rgba(11,26,38,.55);border-radius:3px}
.bcast-gtip-eval.thinking{opacity:.72}
.bcast-msq{position:relative}
.bcast-msq.lt{background:var(--bsq-l,#d8f1f7)}
.bcast-msq.dk{background:var(--bsq-d,#0c7f99)}
.bcast-msq.hl::after{content:"";position:absolute;inset:0;background:rgba(255,193,7,.55)} /* last move */
.bcast-gtip-nm{display:flex;flex-direction:column;gap:2px;margin-top:7px;font-size:11px;color:#eafcff}
.bcast-gtip-nm span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.bcast-gtip-bk{color:#cfe8f2}
/* Which player has which colour — same discs as the scorecard rows, so "filled
   light = White" means the same thing in both popovers. Drawn, not typed: a text
   glyph takes the light text colour, which inverts the pair on this dark panel. */
.bcast-gtip-nm .cdot{display:inline-block;flex:none;width:9px;height:9px;margin-right:5px;border-radius:50%;border:1px solid #7fa8bd;box-sizing:border-box;vertical-align:0}
.bcast-gtip-nm .cdot.w{background:#fff}
.bcast-gtip-nm .cdot.b{background:var(--navy)}
/* playback controls under the board */
.bcast-nav{display:flex;gap:6px;margin-top:2px}
.bcast-nav button{flex:1;background:#0c5266;border:0;border-radius:6px;color:#fff;font-size:14px;line-height:1;padding:7px 0;cursor:pointer}
.bcast-nav button:hover:not(:disabled){background:#0e6f93}
.bcast-nav button:disabled{opacity:.4;cursor:default}
.bcast-nav button.on{background:#0fa3c4;color:#04222b} /* following live (at the last move) */
.bcast-nav .bcast-snd{flex:none;margin-left:6px;font-size:13px} /* move-sound toggle */
.bcast-nav .bcast-evb{flex:none;margin-left:6px;font-size:13px} /* eval-bar toggle */
.bcast-nav .bcast-evb.off{opacity:.4}
.bcast-nav .bcast-tilesbtn{flex:none;margin-left:6px;font-size:15px} /* all-boards tiles toggle */
.bcast-nav .bcast-tilesbtn.on{background:#0fa3c4;color:#04222b}
/* Previous-rounds selector (Feature A) */
/* One selector per ROW (Όμιλος, then Γύρος). They shared a wrapping row before,
   which left the labels side by side and the round select stranded underneath. */
.bcast-rounds{display:flex;flex-direction:column;align-items:stretch;gap:6px;margin:0 0 12px}
.bcast-rounds-row{display:flex;align-items:center;gap:7px}
/* Fixed label column so the two selects start at the same x and end up the same
   width — «Όμιλος:» is wider than «Γύρος:», which otherwise left them ragged. */
.bcast-rounds-row .bcast-rounds-lbl{flex:0 0 3.9rem}
.bcast-rounds[hidden]{display:none}
.bcast-rounds-lbl{font-size:12px;font-weight:700;color:#cdeefb;letter-spacing:.02em}
.bcast-rounds-sel{flex:1;min-width:120px;background:#0c5266;color:#fff;border:1px solid #18708d;border-radius:6px;padding:6px 8px;font:inherit;font-size:13px;cursor:pointer}
.bcast-rounds-sel:hover{background:#0e6f93}
/* All-boards tiles view (Feature B) */
.bcast--tiles .bcast-main,.bcast--tiles .bcast-side{display:none} /* beats their flex display (the `hidden` attr alone wouldn't) */
.bcast--tiles .bcast-tiles{grid-column:1 / -1} /* span both grid columns — the 300px col is empty in tiles mode */
.bcast-tiles{margin-top:2px}
.bcast-tiles-head{display:flex;align-items:center;gap:12px;margin-bottom:14px;flex-wrap:wrap}
.bcast-tiles-back{background:#0c5266;border:0;border-radius:6px;color:#fff;font:inherit;font-size:13px;font-weight:700;padding:7px 12px;cursor:pointer}
/* prev/next team-meeting arrows flanking the tiles title */
/* Prev/next meeting hints — plain text on either side of the centered team
   names (not buttons); still clickable, brighten + underline on hover. */
.bcast-tiles-nav{flex:none;background:none;border:0;color:rgba(255,255,255,.62);font:inherit;font-size:13px;font-weight:600;line-height:1.1;padding:4px 2px;cursor:pointer;white-space:nowrap}
.bcast-tiles-nav:hover{background:none;color:#fff;text-decoration:underline}
.bcast-tiles-back:hover{background:#0e6f93}
/* Team-match meeting names sit centered between the prev/next meeting hints. */
.bcast-tiles-title{font-weight:800;font-size:16px;color:#fff;flex:1;min-width:0;text-align:center}
.bcast-tiles-head .bcast-rounds{margin:0;flex:none}
.bcast-tiles-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(148px,1fr));justify-content:center;gap:13px} /* JS sets explicit px columns to fill the module surface; this is the no-JS fallback */
.bcast-tiles-empty{color:#9fc4d4;text-align:center;padding:20px}
.bcast-tile{display:flex;flex-direction:column;gap:5px;background:#0e2c39;border:1px solid rgba(22,67,84,.5);border-radius:9px;padding:8px;cursor:pointer;text-align:left;color:#eaf6fb;font:inherit;transition:border-color .15s ease,transform .1s ease}
.bcast-tile:hover{border-color:#0fa3c4;transform:translateY(-1px)}
.bcast-tile.on{border-color:#0fa3c4;box-shadow:inset 0 0 0 1px #0fa3c4}
.bcast-tile-pl{display:flex;align-items:center;gap:5px;font-size:12px;font-weight:600;line-height:1.2;min-width:0}
.bcast-tile-pl img{flex:none}
.bcast-tile-nm{flex:1;min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis} /* one line, ellipsis — keeps every tile the same height */
/* team tag on a tile (multi-meeting grids only; a single meeting names the teams in the header) */
.bcast-tile-team{flex:none;max-width:74px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;font-size:9px;font-weight:700;letter-spacing:.02em;text-transform:uppercase;color:#7fd6ea;opacity:.8}
.bcast-tile-res{margin-left:6px;flex:none;font-weight:800;font-size:11px;color:#bfe3f1}
/* Running clock next to each tile player name (ticked every 250ms). */
.bcast-tile-clk{margin-left:6px;flex:none;font-weight:700;font-size:11px;color:#9fc7d6;font-variant-numeric:tabular-nums;line-height:1}
.bcast-tile-clk:empty{display:none}
.bcast-tile-clk.is-active{color:#fff;background:#0c5266;border-radius:4px;padding:1px 5px}
.bcast-tile-res .lv{color:#5fe0a0}
.bcast-tile-board{display:flex;gap:3px;align-items:stretch}
.bcast-tile-eval{position:relative;flex:none;width:9px;background:#16242f;border-radius:3px;overflow:hidden}
.bcast-tile-eval .te-fill{position:absolute;left:0;right:0;bottom:0;height:50%;background:#eef3f6;transition:height .35s ease}
.bcast-tile-eval.te-flip .te-fill{top:0;bottom:auto} /* Black-at-bottom board → White fill grows from the top */
.bcast-tile-sqs{display:grid;grid-template-columns:repeat(8,1fr);grid-template-rows:repeat(8,1fr);flex:1;min-width:0;aspect-ratio:1/1;border-radius:4px;overflow:hidden}
/* tiles header controls: count + show/hide-finished toggle + pick + round select */
.bcast-tiles-ctl{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.bcast-tiles-count{font-size:12px;font-weight:700;color:#bfe3ec;font-variant-numeric:tabular-nums}
.bcast-tiles-fin,.bcast-tiles-pick{background:#0c5266;border:0;border-radius:6px;color:#fff;font:inherit;font-size:12px;font-weight:700;padding:6px 10px;cursor:pointer}
.bcast-tiles-fin:hover,.bcast-tiles-pick:hover{background:#0e6f93}
.bcast-tiles-fin.on{background:#0fa3c4;color:#04222b}
/* ⊞ dropdown menu (All games / Pick games…) */
.bcast-tilesmenu{position:fixed;z-index:60;background:#0e2c39;border:1px solid #1d5366;border-radius:9px;padding:5px;box-shadow:0 12px 34px rgba(0,0,0,.45);display:flex;flex-direction:column;gap:2px;min-width:200px}
.bcast-tilesmenu[hidden]{display:none}
.bcast-tilesmenu button{background:none;border:0;border-radius:6px;color:#eaf6fb;font:inherit;font-size:13px;font-weight:600;text-align:left;padding:9px 11px;cursor:pointer}
.bcast-tilesmenu button:hover{background:#0e6f93}
.bcast-tilesmenu button[hidden]{display:none}
.bcast-tm-match{max-width:280px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* Team line-up drawers on the team-match tiles — a pair of vertical tabs at the
   left of the left-most board of each visual row; click opens the line-up panel. */
.bcast-tiles{position:relative}
.bcast-tiles.has-drawers{padding-left:26px}
.bcast-drawers{position:absolute;inset:0;pointer-events:none;z-index:5}
.bcast-drawer{position:absolute;pointer-events:auto;display:flex;align-items:center;justify-content:center;padding:0;border:1px solid #1d5366;border-right:0;border-radius:5px 0 0 5px;background:#123b49;color:#bfe1ec;cursor:pointer;font-size:8.5px;box-shadow:0 1px 3px rgba(0,0,0,.25);overflow:hidden;transition:background .12s,color .12s}
.bcast-drawer:hover{background:#0c7f99;color:#f2fafd}
.bcast-drawer.on{background:#0c7f99;color:#fff;border-color:#3aa9c6}
.bcast-drawer-lbl{writing-mode:vertical-rl;text-orientation:mixed;transform:rotate(180deg);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-height:calc(100% - 6px);line-height:1;font-size:8.5px;font-weight:700;letter-spacing:.01em;text-transform:uppercase}
.bcast-drawer-panel{position:fixed;z-index:61;min-width:210px;max-width:300px;background:#0e2c39;border:1px solid #1d5366;border-radius:9px;padding:8px;box-shadow:0 12px 34px rgba(0,0,0,.45);color:#eaf6fb}
.bcast-drawer-panel[hidden]{display:none}
.bcast-drawer-h{display:flex;align-items:center;justify-content:space-between;gap:8px;font-weight:800;font-size:13px;padding:2px 3px 7px;border-bottom:1px solid #1d5366;margin-bottom:5px}
.bcast-drawer-sc{flex:none;font-variant-numeric:tabular-nums;color:#7fd6ea}
.bcast-drawer-rows{list-style:none;margin:0;padding:0;max-height:60vh;overflow:auto}
.bcast-drawer-rows li{display:flex;align-items:center;gap:6px;padding:4px 3px;line-height:1.2;font-size:12.5px}
.bcast-drawer-rows li+li{border-top:1px solid #16404f}
.bcast-drawer-rows .bd{flex:none;width:16px;text-align:right;color:#8fb6c4;font-size:11px;font-variant-numeric:tabular-nums}
.bcast-drawer-rows img{flex:none}
.bcast-drawer-rows .nm{flex:1;min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
.bcast-drawer-rows .ti{color:#e6b800;font-weight:800;font-size:10px;margin-right:4px}
.bcast-drawer-rows .rt{color:#9fc7d4;font-weight:600;font-size:11px;margin-left:5px}
.bcast-drawer-res{flex:none;width:20px;text-align:center;font-weight:800;font-variant-numeric:tabular-nums}
.bcast-drawer-res.lv{color:#4fd08a}
.bcast-drawer-empty{color:#8fb6c4}
/* Rating right next to the player's name on team-match tiles. */
.bcast-tile-rt{flex:none;color:#8fd0e0;font-weight:600;font-size:10.5px;font-variant-numeric:tabular-nums}
/* multi-select game picker modal */
.bcast-modal{position:fixed;inset:0;z-index:70;background:rgba(5,16,24,.62);display:flex;align-items:center;justify-content:center;padding:20px}
.bcast-modal[hidden]{display:none}
.bcast-modal-box{background:var(--navy);border:1px solid #1d5366;border-radius:14px;width:min(440px,100%);max-height:84vh;display:flex;flex-direction:column;color:#fff;box-shadow:0 20px 60px rgba(0,0,0,.5)}
.bcast-modal-head{display:flex;align-items:center;gap:10px;padding:14px 16px 8px}
.bcast-modal-head h3{margin:0;font-family:var(--disp);font-size:16px;flex:1}
.bcast-modal-x{background:none;border:0;color:#bfe3ec;font-size:18px;line-height:1;cursor:pointer;padding:2px 6px}
.bcast-modal-x:hover{color:#fff}
.bcast-modal-tools{display:flex;gap:8px;padding:0 16px 8px}
.bcast-modal-tools button{background:#0c5266;border:0;border-radius:6px;color:#fff;font:inherit;font-size:12px;font-weight:700;padding:5px 12px;cursor:pointer}
.bcast-modal-tools button:hover{background:#0e6f93}
.bcast-modal-list{overflow:auto;padding:0 8px;margin:0 6px;flex:1}
.bcast-modal-row{display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:8px;cursor:pointer;font-size:13px}
.bcast-modal-row:hover{background:#0c5266}
.bcast-modal-row input{flex:none;width:16px;height:16px;accent-color:#0fa3c4;cursor:pointer}
.bcast-modal-pl{flex:1;min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;font-weight:600}
.bcast-modal-res{flex:none;color:#bfe3ec;font-size:12px;font-weight:700}
.bcast-modal-res .lv{color:#5fe0a0}
.bcast-modal-foot{display:flex;gap:10px;padding:12px 16px 16px}
.bcast-modal-go{flex:1;background:#0fa3c4;border:0;border-radius:8px;color:#04222b;font:inherit;font-size:14px;font-weight:800;padding:10px;cursor:pointer}
.bcast-modal-go:hover{background:#36b8d6}
.bcast-modal-cancel{background:#0c5266;border:0;border-radius:8px;color:#fff;font:inherit;font-size:13px;font-weight:700;padding:10px 16px;cursor:pointer}
.bcast-modal-cancel:hover{background:#0e6f93}
/* Compact hero keeps the eval slot reserved when off (visibility:hidden from the
   base .bcast-evalbar[hidden] rule) so toggling never resizes the board — same
   fix as the full /live page. */
.bcast-compact-foot{display:flex;align-items:center;gap:8px;width:min(320px,100%);margin:2px auto 0}
.bcast-compact-foot .bcast-evb{flex:none;background:#0c5266;border:0;border-radius:6px;color:#fff;font-size:13px;line-height:1;padding:6px 9px;cursor:pointer}
.bcast-compact-foot .bcast-evb:hover{background:#0e6f93}
.bcast-compact-foot .bcast-evb.off{opacity:.45}
/* The move-sound toggle sits beside the eval one and borrows its chrome, so
   the hero footer reads as one control group rather than two styles. Muted
   is dimmed exactly like the eval button's off state — same visual grammar
   as /live, which is what the pair is meant to share. */
.bcast-compact-foot .bcast-snd{flex:none;background:#0c5266;border:0;border-radius:6px;color:#fff;font-size:13px;line-height:1;padding:6px 9px;cursor:pointer}
.bcast-compact-foot .bcast-snd:hover{background:#0e6f93}
.bcast-compact-foot .bcast-snd[aria-pressed="false"]{opacity:.45}
/* Push the /live link to the far end so the two buttons group at the left. */
.bcast-compact-foot .bcast-live-link{margin-left:auto}
.bcast-live-link{margin-left:auto;color:var(--hero-link,#7fd6ea);font-size:13px;font-weight:600;text-decoration:none;white-space:nowrap}
.bcast-live-link:hover{text-decoration:underline}
.public-resource-show__tags{list-style:none;display:flex;flex-wrap:wrap;gap:8px;padding:0;margin:12px 0 0}
.public-resource-show__tags li{background:#e8f6fa;color:#0a6b82;border-radius:999px;padding:3px 12px;font-size:13px;font-weight:600}
.public-podcast-show__body{margin-top:18px}
.pod-ts{background:#e8f6fa;color:#0a6b82;border:0;border-radius:5px;padding:0 6px;margin:0 1px;font:inherit;font-weight:700;font-variant-numeric:tabular-nums;cursor:pointer;line-height:inherit}
.pod-ts:hover,.pod-ts:focus-visible{background:#0a6b82;color:#fff;outline:none}
/* TWO breakpoints, not one, because there are two fixed columns to give up and
   they are not worth the same.

   /live is a grid of [main | games 300px], and main is a flex row of [board
   410px | meta]. Both outer columns are FIXED, so `meta` — the move list and the
   suggestions rail — absorbs the shortfall from both at once. Measured with only
   the 860px rule in place, meta was 148px at 1024 and **24px at 900**: the move
   list had been overflowing its own container across that whole band, silently,
   for as long as the layout has existed.

   So the games list goes first, at 1150. It is a browse affordance and reads
   perfectly well full-width underneath, while the board and the move list are
   the thing people came to watch and are worth keeping side by side as long as
   possible. That alone takes meta from 148px to ~470px at 1024.

   Only below 860 does the board itself stop being a column. */
@media (max-width:1150px){ .bcast--full{grid-template-columns:minmax(0,1fr)} }
@media (max-width:860px){ .bcast--full{grid-template-columns:minmax(0,1fr)} .bcast-main{flex-direction:column;min-width:0} .bcast-board{width:100%;max-width:420px} .bcast-mid{flex-direction:column} .bcast-mid .bcast-moves-box{width:auto} }

.live-list{list-style:none;margin:0 0 26px;padding:0;display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px}
.live-card{background:#fff;border:1px solid var(--line);border-radius:12px;padding:16px;box-shadow:0 6px 22px rgba(20,40,80,.07);transition:.16s}
.live-card:hover{transform:translateY(-3px);box-shadow:0 16px 40px rgba(15,163,196,.18);border-color:#bfe3ec}
.live-card .live-dot{display:inline-flex;align-items:center;gap:6px;color:#c0392b;font-weight:700;font-size:11px}
.live-card .live-dot::before{content:"";width:8px;height:8px;border-radius:50%;background:#c0392b;display:inline-block}
.live-card h3{font-size:16px;font-weight:600;line-height:1.3;margin:8px 0 6px;display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;overflow:hidden} /* clamp to 2 rows; full title via title= tooltip */
.live-card .when{color:var(--grey);font-size:12.5px}
.live-card .gr{display:inline-block;background:var(--cyan-bg);color:var(--cyan-d);font-weight:700;font-size:10.5px;border-radius:4px;padding:3px 8px;margin-bottom:6px}
.live-card .gr[title]{cursor:help} /* federation tag names the player(s) on hover */
.live-card .live-dot.upcoming{color:#0c7f99} /* not started yet — dark cyan, no live dot pulse */
.live-card .live-dot.upcoming::before{background:#0c7f99}
.live-card a.watch{display:inline-block;margin-top:10px;color:var(--cyan-d);font-weight:600;font-size:13px}
.live-card a.watch[role="button"]{cursor:pointer} /* href stripped by JS — keep the affordance */
/* The two ways to watch, on one row: load into the board above (primary) or
   open the live module in a new tab already showing this tournament. */
.live-card__watch{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.live-card a.watch-tab{display:inline-block;margin-top:10px;color:var(--grey);
  font-weight:600;font-size:12px;text-decoration:none;border-bottom:1px dotted currentColor}
.live-card a.watch-tab:hover,.live-card a.watch-tab:focus-visible{color:var(--cyan-d)}
.live-card[hidden]{display:none}
.live-failure{background:#fdf7ec;border:1px solid #e8c884;color:#8a5a00;border-radius:12px;padding:18px 20px;margin:0 0 22px}
.live-filter{max-width:420px;margin:0 0 22px}
.live-filter input{width:100%;appearance:none;-webkit-appearance:none;background:#f1f5f9;border:1px solid var(--line);border-radius:24px;padding:11px 18px;font:inherit;font-size:15px;color:var(--ink)}
.live-filter input:focus{outline:none;border-color:var(--cyan);background:#fff}
.live-noresults{color:var(--grey)}
@media (max-width:680px){
  .live-embed{min-height:200px}
  /* Full-bleed /live on phones (owner: edge-to-edge, no side gutter). The board
     card + the broadcast list break out of main's 20px ≤680 gutter to both
     screen edges; the text rows (crumb, heading, filter, section heads,
     attribution) keep the inset by not being broken out. -20px === main's ≤680
     padding. `.bcast--full` is the [data-broadcast-viewer] node itself (JS adds
     the class at mount), so trimming its 22px inner padding widens the board too. */
  .public-live .bcast--full,
  .public-live .live-list{margin-left:-20px;margin-right:-20px}
  .public-live .bcast--full{border-radius:0;padding:14px 0}
  .public-live .live-card{border-radius:0;border-left:0;border-right:0}

  /* ── /live island: lichess-broadcast "restyle" on phones (structure/order
     kept; sub-blocks made to use the full-bleed width) ─────────────────────
     (1) Drop redundant meta chrome — the featured game's player names and the
     "live · Lichess" eyebrow already show on the board rows above. */
  .public-live .bcast-eyebrow,
  .public-live .bcast-title,
  .public-live .bcast-moves-box h4,
  .public-live .bcast-moves-hint{display:none}

  /* (2) Move list → the lichess BROADCAST paradigm: a full-width vertical
     two-column table (move#, white, black), roomier type/rows than the cramped
     desktop side-panel, kept capped + auto-scrolled to the live move (base
     scrollTop logic). The two column-flex ancestors default to
     align-items:flex-start (which sizes children to content); stretch them, with
     a min-width:0 chain, so the list fills the column width instead of shrinking
     to its content. The per-move cell shows the stored PGN [%eval] (set in
     moveCell) — visible on mobile too, unlike the old ribbon. */
  .public-live .bcast-main,
  .public-live .bcast-meta,
  .public-live .bcast-mid,
  .public-live .bcast-moves-box,
  .public-live .bcast-moves{min-width:0}
  .public-live .bcast-main,
  .public-live .bcast-mid{align-items:stretch}
  .public-live .bcast-movelist li{padding:4px 12px;font-size:14.5px}
  .public-live .bcast-movelist .mvn{font-size:13px}

  /* (3) Games list + suggestions → flow at full width; NO nested vertical scroll
     (it traps touch on a phone). Comfier tap targets on the game rows. */
  .public-live .bcast-games,
  .public-live .bcast-suggest-list{max-height:none;overflow:visible}
  .public-live .bcast-grow{padding:12px 14px}
  .public-live .bcast-grow-pl{font-size:14px}
}

/* --- search results page --------------------------------------------------- */
.search-page__form{display:flex;gap:10px;max-width:640px;margin:0 0 28px}
.search-page__label{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
.search-page__form input[type="search"]{
  flex:1;appearance:none;-webkit-appearance:none;background:#f1f5f9;border:1px solid var(--line);
  border-radius:24px;padding:12px 20px;font:inherit;font-size:15px;color:var(--ink)
}
.search-page__form input[type="search"]:focus{outline:none;border-color:var(--cyan);background:#fff}
.search-page__form button{border:0;cursor:pointer;background:var(--cyan);color:#04222b;font-weight:700;font-size:14px;border-radius:24px;padding:12px 22px}
.search-page__group ul{list-style:none;margin:0;padding:0}
.search-page__group li{border-top:1px solid var(--line);padding:11px 2px}
.search-page__group li:first-child{border-top:0}
.search-page__group li a{font-weight:600;font-size:15px}
.search-page__noresults{color:var(--grey)}

/* --- links page groups ----------------------------------------------------- */
.linkgroup{margin:0 0 26px}
.linkgroup .listing{padding:4px 0}
.linkrow{display:block;padding:14px 18px;border-top:1px solid var(--line)}
.linkrow:first-child{border-top:0}
.linkrow a{font-weight:600;font-size:15px}
.linkrow p{margin:4px 0 0;color:#5d6b7a;font-size:13px}

/* ========================================================================== */
/* responsive reflow (ported from style.css + live additions)                  */
/* ========================================================================== */
@media (max-width:1180px){
  .row1,.row2{grid-template-columns:1fr 1fr}
  .z1{grid-column:1 / -1}
  .news,.snews,.tiles{grid-template-columns:repeat(2,1fr)}
  .split{grid-template-columns:1fr} .map{min-height:320px}
  .article{grid-template-columns:1fr} .rail-side{position:static}
  .b248{width:200px;height:200px;background-size:50px 50px;background-position:0 0,25px 25px}
  .cal-row{grid-template-columns:72px 1fr 120px}
  .cal-row .ven,.cal-row .tag.type{display:none}
}
@media (max-width:680px){
  .mast .in{padding:14px 18px}
  .row1,.row2{grid-template-columns:1fr} .news,.snews,.tiles{grid-template-columns:1fr}
  .zone--live .live-duo{grid-template-columns:1fr} /* stack the two boards on phones */
  main{padding:20px} .cal-row{grid-template-columns:64px 1fr}
  .lrow{flex-direction:column} .lrow .th{width:100%;aspect-ratio:3/2}
  .article h1{font-size:27px}
}
@media (prefers-reduced-motion: reduce){
  .z1,.z1::after,.divx .rule{animation:none}
}

/* ── §8 unified club map (/map) ──────────────────────────────────────────── */
.club-map-wrap{position:relative;margin:0 0 28px}
/* calendar-results §12 — public Calendar view (Split + filter bar) */
.calendar-page{padding:8px 0 44px}
.calendar-page .crumb{font-size:13px;color:#688;margin:6px 0}
.calendar-page .crumb a{color:#0c7f99;text-decoration:none}
.calendar-bar{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin:12px 0 18px}
.calendar-bar input[data-cal-search]{flex:1 1 200px;min-width:150px;padding:9px 12px;border:1px solid #9cc7d6;border-radius:8px;font:inherit}
.calendar-bar select,.calendar-bar input[type=number]{padding:9px 10px;border:1px solid #9cc7d6;border-radius:8px;font:inherit;background:#fff}
.calendar-bar input[type=number]{width:120px}
.calendar-check{display:inline-flex;align-items:center;gap:6px;font-size:14px;color:#456}
.calendar-bar button[data-cal-nearest]{padding:9px 14px;border:0;border-radius:8px;background:#0c7f99;color:#fff;font:inherit;font-weight:700;cursor:pointer}
.calendar-bar button[data-cal-nearest][aria-pressed=true]{background:#0a6b82;box-shadow:inset 0 0 0 2px #fff,0 0 0 2px #0a6b82}
.calendar-bar button[data-cal-nearest]:disabled{opacity:.6;cursor:wait}
.calendar-count{margin-left:auto;font-size:13px;font-weight:700;color:#0c7f99;font-variant-numeric:tabular-nums}
.calendar-h2{margin:22px 0 12px;color:var(--navy,#06303d)}
.calendar-meta{color:#566;font-size:14px}
.calendar-results-link{color:#0c7f99;font-weight:700}
/* view switcher (list / map / split) — OQ-17 */
.calendar-views{display:inline-flex;gap:0;margin:0 0 6px;border:1px solid #9cc7d6;border-radius:8px;overflow:hidden;background:#fff}
.calendar-views[hidden]{display:none}
.calendar-views button{padding:8px 16px;border:0;background:#fff;color:#0c5266;font:inherit;font-weight:700;cursor:pointer;border-left:1px solid #cfe8f2}
.calendar-views button:first-child{border-left:0}
.calendar-views button[aria-pressed=true]{background:#0c7f99;color:#fff}
.calendar-views button[hidden]{display:none}
/* split stage: list + map side by side on desktop */
.calendar-stage{display:block}
.calendar-stage.is-split{display:grid;grid-template-columns:1fr 1fr;gap:16px;align-items:start}
.calendar-stage .listing[hidden]{display:none}
.calendar-map[hidden]{display:none}
.calendar-map-canvas{height:min(70vh,560px);min-height:340px;width:100%;background:#dceef4;border-radius:12px;z-index:0}
.calendar-stage.is-split .calendar-map{position:sticky;top:12px}
/* tournament map pin (distinct teal; green when registration is open) */
.tournament-pin span{display:block;width:18px;height:18px;background:#0c7f99;border:2px solid #fff;border-radius:50% 50% 50% 0;transform:rotate(-45deg);box-shadow:0 2px 6px rgba(0,0,0,.35)}
.tournament-pin.is-open span{background:#2c9a5e}
/* tournament popup card stacks (no logo column) */
.tcard.cm-card{min-width:190px;max-width:260px}
.tcard .cm-name .tag{margin-left:4px;vertical-align:middle}
@media (max-width:760px){
  /* split degrades to a single pane (the JS hides the inactive one) */
  .calendar-stage.is-split{grid-template-columns:1fr}
  .calendar-stage.is-split .calendar-map{position:static}
}
.club-map-bar{display:flex;flex-wrap:wrap;gap:8px;align-items:center;padding:12px clamp(14px,4vw,40px);background:#eef7fb;border-top:1px solid #cfe8f2;border-bottom:1px solid #cfe8f2}
.club-map-bar[hidden]{display:none}
.club-map-bar input[data-map-search]{flex:1 1 220px;min-width:150px;padding:9px 12px;border:1px solid #9cc7d6;border-radius:8px;font:inherit}
.club-map-bar select{padding:9px 10px;border:1px solid #9cc7d6;border-radius:8px;font:inherit;background:#fff;max-width:60vw}
.club-map-bar button[data-map-nearest]{padding:9px 14px;border:0;border-radius:8px;background:#0c7f99;color:#fff;font:inherit;font-weight:700;cursor:pointer}
.club-map-bar button[data-map-nearest]:hover{background:#0a6b82}
.club-map-bar button[data-map-nearest]:disabled{opacity:.6;cursor:wait}
.club-map-count{margin-left:auto;font-size:13px;font-weight:700;color:#0c7f99;font-variant-numeric:tabular-nums}
.club-map-canvas{height:min(72vh,640px);min-height:380px;width:100%;background:#dceef4;z-index:0}
.club-map-loading{display:grid;place-items:center;height:100%;margin:0;color:#0c7f99;font-weight:600}

/* brand teardrop pin (Leaflet divIcon) */
.club-pin span{display:block;width:18px;height:18px;background:#0fa3c4;border:2px solid #fff;border-radius:50% 50% 50% 0;transform:rotate(-45deg);box-shadow:0 2px 6px rgba(0,0,0,.35)}
/* venues layer pin (distinct amber) */
.venue-map-pin span{display:block;width:18px;height:18px;background:#e8833a;border:2px solid #fff;border-radius:50% 50% 50% 0;transform:rotate(-45deg);box-shadow:0 2px 6px rgba(0,0,0,.35)}
/* layer legend / toggle */
.club-map-legend{display:flex;gap:18px;flex-wrap:wrap;align-items:center;margin:0;padding:10px clamp(14px,4vw,40px);background:#f5fbfd;border-bottom:1px solid #cfe8f2;border:0}
.club-map-legend[hidden]{display:none}
.club-map-legend label{display:inline-flex;align-items:center;gap:6px;font-weight:600;font-size:14px;cursor:pointer}
.club-map-legend .lg{width:13px;height:13px;border-radius:50%;display:inline-block}
.club-map-legend .lg-clubs{background:#0fa3c4}
.club-map-legend .lg-venues{background:#e8833a}
.club-map-legend em{font-style:normal;color:#5a7785;font-weight:500}
/* venues page: tournament badge + hover card */
.public-venue-index__item{position:relative}
.venue-tourn{position:absolute;top:10px;right:12px;cursor:default}
.venue-tourn__icon{font-size:20px;line-height:1;opacity:.5;filter:grayscale(1)}
.venue-tourn.has-upcoming .venue-tourn__icon{opacity:1;filter:none}
.venue-tourn__pop{display:none;position:absolute;top:26px;right:0;z-index:20;min-width:230px;max-width:300px;background:#fff;border:1px solid #cfe8f2;border-radius:10px;box-shadow:0 6px 22px rgba(0,0,0,.16);padding:10px 12px;text-align:left}
.venue-tourn:hover .venue-tourn__pop,.venue-tourn:focus .venue-tourn__pop,.venue-tourn:focus-within .venue-tourn__pop{display:block}
.venue-tourn__pop strong{display:block;font-size:13px;color:#0c5266;margin:0 0 6px}
.venue-tourn__pop ul{list-style:none;margin:0;padding:0}
.venue-tourn__pop li{font-size:13px;padding:3px 0;border-top:1px solid #eef4f7}
.venue-tourn__pop li:first-child{border-top:0}
.venue-tourn__pop a{color:#0c7f99;font-weight:600;text-decoration:none}
.venue-tourn__pop a:hover{text-decoration:underline}
.venue-tourn__pop em{font-style:normal;color:#789;font-size:12px;margin-left:4px}
/* tournaments list: chess-results source link, right-aligned per entry */
.calendar-item{position:relative}
.calendar-src{position:absolute;top:12px;right:14px;font-size:12px;font-weight:600;color:#0c7f99;text-decoration:none;white-space:nowrap}
.calendar-src:hover{text-decoration:underline}
/* Tournament cards (new structure) — a responsive grid of stacked-info cards. */
.calendar-page .listing,.homepage-tournaments .tcal-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:16px;background:none;border:0;border-radius:0;overflow:visible}
/* «Επερχόμενα τουρνουά»: one-row horizontal scroller — ~4 cards visible, up to 20
   reachable by scrolling right. Overrides the grid above (declared after, same
   specificity). Scoped to the homepage so /tournaments keeps its grid. */
.homepage-tournaments .tcal-scroller{display:flex;overflow-x:auto;overflow-y:hidden;padding:6px 4px 18px;scrollbar-width:thin;scrollbar-color:var(--cyan) #e6eef4;-webkit-overflow-scrolling:touch}
.homepage-tournaments .tcal-scroller .tcal-card{flex:0 0 calc((100% - 3 * 16px) / 4);min-width:250px}
.homepage-tournaments .tcal-scroller::-webkit-scrollbar{height:10px}
.homepage-tournaments .tcal-scroller::-webkit-scrollbar-track{background:#e9f0f5;border-radius:8px}
.homepage-tournaments .tcal-scroller::-webkit-scrollbar-thumb{background:var(--cyan);border-radius:8px;border:2px solid #e9f0f5}
.homepage-tournaments .tcal-scroller::-webkit-scrollbar-thumb:hover{background:var(--cyan-d)}
.tcal-card{display:flex;flex-direction:column;align-items:flex-start;gap:5px;background:#fff;border:1px solid var(--line);border-radius:12px;padding:15px 17px}
.tcal-card__badge{font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;border-radius:6px;padding:3px 9px}
.tcal-card__badge--open{background:#e7f3ec;color:#2c6e49}
.tcal-card__badge--done{background:var(--chip);color:var(--blue)}
.tcal-card__name{font-family:var(--disp);font-weight:700;font-size:17px;line-height:1.25;color:var(--navy);text-decoration:none;margin-top:2px}
.tcal-card__name:hover{color:var(--cyan-d)}
/* Clamp the card title to 2 rows (full title via the title= tooltip). */
.tcal-card__name{display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.tcal-card__loc{display:flex;align-items:center;gap:7px;color:#566;font-size:14px;margin:0}
.tcal-card__pin{flex:none;font-size:16px;line-height:1;text-decoration:none}
.tcal-card__pin:hover{filter:brightness(1.15)}
.tcal-card__rounds{color:#566;font-size:13px;margin:0}
.tcal-card__fee{color:#566;font-size:13px;margin:0}
.tcal-card__dates{color:var(--ink);font-weight:600;font-size:14.5px;margin:0}
.tcal-card__src{margin-top:3px;color:var(--cyan-d);font-weight:600;font-size:13px;text-decoration:none}
.tcal-card__src:hover{text-decoration:underline}

/* popup card */
.leaflet-popup-content{margin:10px 12px;line-height:1.4}
.cm-card{display:flex;gap:10px;align-items:flex-start;min-width:170px;max-width:240px}
.cm-logo{width:42px;height:42px;object-fit:contain;border-radius:6px;flex:none;background:#fff}
.cm-body{display:flex;flex-direction:column;gap:2px;min-width:0}
.cm-name{font-size:14px;color:#06303d}
.cm-place{font-size:12px;color:#0c7f99;font-weight:600}
.cm-addr{font-size:12px;color:#456}
.cm-links{margin-top:4px;display:flex;gap:12px;font-size:13px}
.cm-links a{color:#0c7f99;font-weight:700;text-decoration:none}
.cm-links a:hover{text-decoration:underline}

/* engine comparison toggle (dev) */
.map-engine-switch{margin:6px 0 0;font-size:13px;color:#688}
.map-engine-switch a{color:#0c7f99;font-weight:700;text-decoration:none}
.map-engine-switch a:hover{text-decoration:underline}

/* OpenLayers popup (OL ships no popup; we mount an ol/Overlay with this card) */
.cm-ol-popup{position:relative;background:#fff;padding:10px 12px;border-radius:10px;box-shadow:0 2px 12px rgba(0,0,0,.18);line-height:1.4}
.cm-ol-popup::after{content:"";position:absolute;left:50%;bottom:-7px;transform:translateX(-50%);border:7px solid transparent;border-top-color:#fff;border-bottom:0}

/* ── education: Puzzle of the Day (§7.1) ───────────────────────────────── */
.puzzle-page,.puzzle-archive{padding:8px 0 44px}
.puzzle-page .crumb,.puzzle-archive .crumb{font-size:13px;color:#688;margin:6px 0}
.puzzle-page .crumb a,.puzzle-archive .crumb a{color:#0c7f99;text-decoration:none}
.puzzle-board-wrap{display:flex;gap:26px;align-items:flex-start;flex-wrap:wrap}
.puzzle-board{position:relative;display:grid;grid-template-columns:repeat(8,1fr);grid-template-rows:repeat(8,1fr);width:min(72vw,440px);aspect-ratio:1/1;border-radius:8px;overflow:hidden;box-shadow:0 6px 22px rgba(0,0,0,.28);touch-action:manipulation}
/* `manipulation`, not `none`: dragging a piece by finger would need `none`,
   which makes a board that is min(94vw,440px) on a phone — and that the
   homepage hero widget reuses — a scroll dead zone mid-page. Touch solves by
   tap-then-tap instead (puzzle-board.js starts no drag for a touch pointer);
   the mouse keeps drag. Only double-tap zoom is dropped, so two taps on
   adjacent squares stay two taps. */
.pz-sq{position:relative;cursor:pointer}
.pz-sq.lt{background:#d8f1f7}
.pz-sq.dk{background:#0c7f99}
.pz-sq.hl::after{content:"";position:absolute;inset:0;background:rgba(255,193,7,.5);box-shadow:inset 0 0 0 3px rgba(255,179,0,.9)}
.pz-sq:focus{outline:none}
.pz-sq:focus-visible{outline:3px solid #ffb300;outline-offset:-3px;z-index:4}
.pz-sq.sel::before{content:"";position:absolute;inset:0;background:rgba(255,205,40,.42)}
.pz-sq.dest::after{content:"";position:absolute;left:0;top:0;right:0;bottom:0;margin:auto;width:30%;height:30%;border-radius:50%;background:rgba(11,30,44,.32)}
.pz-sq.dest:not([data-piece=""])::after{width:84%;height:84%;background:transparent;border:4px solid rgba(11,30,44,.32);box-sizing:border-box}
.pz-pc{position:relative;z-index:1;display:block;width:100%;height:100%;pointer-events:none;-webkit-user-drag:none;user-select:none}
.pz-promo{position:absolute;inset:0;z-index:20;display:grid;place-items:center;background:rgba(7,20,30,.6)}
.pz-promo-row{display:flex;gap:6px;background:#0b1e2c;padding:6px;border-radius:10px}
.pz-promo-row button{width:14%;min-width:48px;aspect-ratio:1/1;border:0;padding:0;background:#eef3f6;border-radius:8px;cursor:pointer}
.pz-promo-row button:hover{background:#fff}
.pz-promo-row img{width:100%;height:100%;display:block}
.puzzle-loading{grid-column:1/-1;display:grid;place-items:center;color:#0c7f99;font-weight:600}
.puzzle-side{flex:1;min-width:220px;max-width:340px}
.puzzle-name{margin:0 0 8px;color:var(--navy,#06303d);font-size:20px}
.puzzle-meta{display:flex;flex-wrap:wrap;gap:8px 14px;align-items:center;font-size:13px;color:#456;margin:0 0 10px}
.puzzle-turn{font-weight:700;color:#0c7f99}
.puzzle-diff{letter-spacing:1px;color:#0fa3c4}
.puzzle-diff .off{color:#cde6ee}
.puzzle-status{font-weight:700;color:#06303d;min-height:1.4em;margin:0 0 12px}
.puzzle-status.is-correct{color:#127a2e}
.puzzle-status.is-wrong{color:#c0392b}
.puzzle-status.is-solved{color:#0a7d3a}
.puzzle-status.is-shown{color:#946b00}
.puzzle-controls{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 14px}
.puzzle-controls button{padding:8px 12px;border:1px solid #9cc7d6;border-radius:8px;background:#fff;font:inherit;font-weight:600;color:#0c7f99;cursor:pointer}
.puzzle-controls button:hover{background:#eaf7fb}
.puzzle-moves{margin:0 0 14px;padding:10px 12px;background:#f5fafc;border:1px solid var(--line);border-radius:8px;font-family:var(--mono,ui-monospace,SFMono-Regular,Menlo,Consolas,monospace);font-size:13.5px;line-height:1.7;color:#06303d}
.puzzle-moves .pz-mv-no{color:var(--grey)}
.puzzle-moves .pz-mv{font-weight:600;cursor:pointer;border-radius:4px;padding:0 2px}
.puzzle-moves .pz-mv:hover{background:#dff1f7}
.puzzle-moves .pz-mv.on{background:var(--cyan,#0fa3c4);color:#fff}
.puzzle-moves .pz-mv:focus-visible{outline:2px solid var(--cyan-d,#0c7f99);outline-offset:1px}
/* Board review nav (◀ ▶) — sits under the board. */
.puzzle-nav{display:flex;gap:6px;justify-content:center;margin:10px 0 0}
.puzzle-nav button{min-width:44px;padding:7px 10px;border:1px solid #9cc7d6;border-radius:8px;background:#fff;font:inherit;font-size:15px;color:#0c7f99;cursor:pointer}
.puzzle-nav button:hover:not(:disabled){background:#eaf7fb}
.puzzle-nav button:disabled{opacity:.4;cursor:default}
.puzzle-daynav{display:flex;justify-content:space-between;gap:12px;margin:0 0 6px;font-size:13.5px}
.puzzle-source{font-size:12px;color:#789;margin:0 0 6px}
.puzzle-next a{color:#0c7f99;font-weight:700;text-decoration:none}
.puzzle-nojs{color:#456;margin:10px 0 4px}
.puzzle-fen{background:#f3f7f9;padding:8px;border-radius:6px;font-size:12px;overflow:auto}
.puzzle-archive__list .puzzle-diff{letter-spacing:1px}
.puzzle-archive__pager{display:flex;gap:18px;margin:20px 0}
.puzzle-archive__pager a{color:#0c7f99;font-weight:700;text-decoration:none}
@media(max-width:720px){.puzzle-board{width:min(94vw,440px)}}

/* in-article quiz block (§7.2) — the puzzle engine embedded in a news body */
.puzzle-quiz{border:1px solid #cfe6ee;border-radius:12px;background:#f6fbfd;padding:16px;margin:22px 0;max-width:420px}
.puzzle-quiz .puzzle-board{width:min(86vw,340px);margin:0 0 10px}
.puzzle-quiz-head{display:flex;align-items:center;gap:8px;margin:0 0 10px;color:#06303d;font-size:15px}
.puzzle-quiz-tag{background:#0c7f99;color:#fff;font-size:12px;font-weight:700;padding:2px 8px;border-radius:999px}
.puzzle-quiz .puzzle-status{margin:0 0 8px}
.puzzle-quiz .puzzle-controls{margin:0 0 8px}
.puzzle-quiz .puzzle-controls button{padding:6px 10px;font-size:13px}
.puzzle-quiz-foot{margin:4px 0 0;font-size:13px}
.puzzle-quiz-foot a{color:#0c7f99;font-weight:700;text-decoration:none}

/* in-article PGN viewer — hydration placeholder only. The retired pgn-viewer.js
   styled its root as `.pgnv` (navy grid, `.pgnv__*` children); those rules were
   removed because they COLLIDED with the live pgn/ engine, which also roots at
   `.pgnv` — the old grid was squeezing the move panel underneath the board. The
   engine's own look lives in the `.pgnv` / `.pgnv-*` blocks (above + P2/P2.5). */
.pgn-loading{display:grid;place-items:center;min-height:240px;color:#0c7f99;font-weight:600;border:1px solid #cfe6ee;border-radius:10px;background:#f6fbfd}

/* School Chess landing (§7.5) — aggregation blocks */
.school-page{padding:8px 0 44px}
.school-page .crumb{font-size:13px;color:#688;margin:6px 0}
.school-page .crumb a{color:#0c7f99;text-decoration:none}
.school-block{margin:26px 0}
.school-block>h2{color:var(--navy,#06303d);margin:0 0 12px}
.school-excerpt{color:#566;font-size:14px;margin:4px 0 0}
.school-pdfs{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}
.school-pdfs a{color:#0c7f99;font-weight:700;text-decoration:none}
.school-pdfs a:hover{text-decoration:underline}

/* no-JS / SEO region list (island hides it once mounted) */
.club-list{padding:8px 0 40px}
.club-list[hidden]{display:none}
.club-list h2{margin:18px 0 12px;color:var(--navy)}
.club-list details{border:1px solid #d7e6ec;border-radius:8px;margin:0 0 8px;background:#fff}
.club-list summary{cursor:pointer;padding:10px 14px;font-weight:700;color:#06303d}
.club-list summary .n{color:#0c7f99;font-weight:600}
.club-list ul{list-style:none;margin:0;padding:0 14px 12px}
.club-list li{padding:8px 0;border-top:1px solid #eef3f6;font-size:14px;display:flex;flex-wrap:wrap;gap:4px 10px;align-items:baseline}
.club-list li strong{color:#06303d}
.club-list li .city{color:#0c7f99;font-weight:600}
.club-list li .addr{color:#688;font-size:13px;flex-basis:100%}
.club-list li .links{display:flex;gap:12px;margin-left:auto}
.club-list li .links a{color:#0c7f99;font-weight:600;text-decoration:none;font-size:13px}

/* ── live viewer: player scorecard + standings hover popovers ────────────────
   Themed to the locked "Cyan on White" palette (--navy / --cyan-d / --cyan-bg /
   --grey / --disp), with the brand's soft cyan-tinted card shadow + border, so
   they read as part of the site rather than generic tooltips. */
.bcast-nm{cursor:default;border-radius:4px;transition:background .12s}
.bcast-nm:hover,.bcast-nm:focus-visible{background:rgba(15,163,196,.14);outline:none}
.bcast-ptip{position:fixed;z-index:70;width:286px;max-width:92vw;background:#fff;border:1px solid #bfe3ec;border-radius:12px;padding:12px 13px;box-shadow:0 14px 38px rgba(15,163,196,.22);color:var(--ink);pointer-events:auto;font-size:13px}
.bcast-ptip[hidden]{display:none}
.bcast-ptip-h{font-family:var(--disp);font-size:14px;font-weight:700;letter-spacing:-.2px;line-height:1.3;color:var(--navy);border-bottom:1px solid #e7f3f6;padding-bottom:8px;margin-bottom:8px}
.bcast-ptip-h b{color:var(--cyan-d);font-weight:700}
.bcast-ptip-h .r{color:var(--grey);font-weight:600}
.bcast-ptip-h .bcast-flag{height:12px;margin-right:6px;vertical-align:baseline}
.bcast-ptip-score{font-family:var(--disp);font-size:16px;font-weight:700;color:var(--cyan-d);margin-bottom:2px}
.bcast-ptip-score span{font-family:var(--sans);font-size:11px;font-weight:600;color:var(--grey);margin-left:5px}
.bcast-ptip-perf{font-size:11.5px;color:var(--grey);font-weight:600;margin-bottom:7px}
.bcast-ptip-perf b{color:var(--navy);font-weight:700;font-variant-numeric:tabular-nums}
.bcast-ptip-perf span{color:#a7bcc6;font-weight:600}
.bcast-ptip-empty{color:var(--grey);font-size:12px;padding:2px 0 1px}
.bcast-ptip-rows{list-style:none;margin:0;padding:0;max-height:236px;overflow:auto}
/* round | colour-dot | opponent(flag/title/name/rating) … result pinned right */
.bcast-ptip-rows li{display:flex;align-items:center;gap:7px;padding:4px;margin:0 -4px;border-top:1px solid #eef4f7;line-height:1.25;cursor:pointer;border-radius:6px}
.bcast-ptip-rows li:first-child{border-top:0}
.bcast-ptip-rows li:hover{background:var(--cyan-bg)}
/* A round the broadcast did not carry: read from the official crosstable, so there is no game to open. */
.bcast-ptip-rows li.nb{cursor:default;opacity:.78}
.bcast-ptip-rows li.nb:hover{background:transparent}
.bcast-ptip-rows .bye{color:#a7bcc6}
.bcast-ptip-rows li.cur{border-top:2px solid #bfe3ec;margin-top:3px;padding-top:6px}  /* thin divider before the live round */
.bcast-ptip-rows .rd{flex:none;width:16px;color:#a7bcc6;font-size:11px;font-variant-numeric:tabular-nums;text-align:right}
.bcast-ptip-rows .cdot{flex:none;width:9px;height:9px;border-radius:50%;border:1px solid #b4c6cf;box-sizing:border-box}
.bcast-ptip-rows .cdot.w{background:#fff}
.bcast-ptip-rows .cdot.b{background:var(--navy)}
.bcast-ptip-rows .op{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--ink)}
.bcast-ptip-rows .op b{color:var(--cyan-d);font-weight:700}
.bcast-ptip-rows .op .bcast-flag{height:11px;margin-right:5px;vertical-align:baseline}
.bcast-ptip-rows .ort{flex:none;width:34px;text-align:right;color:var(--grey);font-size:11.5px;font-variant-numeric:tabular-nums}
.bcast-ptip-rows .pt{flex:none;width:20px;margin-left:8px;text-align:center;font-weight:800;font-variant-numeric:tabular-nums;border-radius:5px;font-size:12.5px}
.bcast-ptip-rows li.w .pt{color:#1c6b34;background:#cdeed4}
.bcast-ptip-rows li.l .pt{color:#9a2531;background:#f7d2d7}
.bcast-ptip-rows li.d .pt{color:var(--navy);background:var(--cyan-bg)}
.bcast-ptip-rows li.lv .pt{color:var(--cyan-d);background:transparent}
.bcast-ptip-rows li.lv .op{color:var(--cyan-d)}

/* tournament-name hover affordance (sits on the dark broadcast panel) + standings popover */
.bcast-tourney-name{cursor:help;border-radius:6px;transition:background .12s;display:inline-flex;align-items:flex-end;gap:6px;padding:2px 5px;margin:0 0 10px -5px}
.bcast-tourney-name .tn{text-decoration:underline dotted rgba(127,214,234,.55);text-underline-offset:3px;text-decoration-thickness:1px}
.bcast-tourney-name:hover,.bcast-tourney-name:focus-visible{background:rgba(15,163,196,.18);outline:none}
.bcast-tourney-name:hover .tn,.bcast-tourney-name:focus-visible .tn{text-decoration-color:#7fd6ea}
.bcast-stip-cue{flex:none;fill:#7fd6ea;opacity:.85;margin-bottom:2px;transition:opacity .12s,transform .12s}
.bcast-tourney-name:hover .bcast-stip-cue,.bcast-tourney-name:focus-visible .bcast-stip-cue{opacity:1;transform:translateY(-1px)}
.bcast-stip{width:308px}
.bcast-stip-rows{max-height:340px}
.bcast-stip-rows li{cursor:default}
/* Only rows whose player we actually broadcast can open a game (.go). The rest
   of the official field has nothing to click through to, so it stays inert. */
.bcast-stip-rows li.go{cursor:pointer}
.bcast-stip-rows li.go:hover{background:var(--cyan-bg)}
.bcast-stip-note{margin:8px 0 0;padding-top:8px;border-top:1px solid #e7f3f6;font-size:10.5px;line-height:1.4;color:var(--grey);font-style:italic}
.bcast-stip-rows .rk{flex:none;width:20px;text-align:right;color:#a7bcc6;font-size:11.5px;font-variant-numeric:tabular-nums}
.bcast-stip-rows .sp{flex:none;width:26px;margin-left:8px;text-align:right;font-weight:800;color:var(--cyan-d);font-variant-numeric:tabular-nums;font-size:13px}
.bcast-stip-rows li.me{background:var(--cyan-bg)}
.bcast-stip-rows li.me .op{color:var(--cyan-d);font-weight:700}

.pgnv-board-row{display:flex;gap:6px;align-items:stretch}
.pgnv-bwrap{flex:1 1 auto;min-width:0}
.pgnv-evalbar{position:relative;width:14px;flex:0 0 14px;background:#3a4a5a;border-radius:4px;overflow:hidden}
.pgnv-evalfill{position:absolute;left:0;right:0;bottom:0;height:50%;background:#f2f5f8;transition:height .25s}
.pgnv-evalnum{position:absolute;left:0;right:0;bottom:0;text-align:center;font-size:7.5px;font-weight:700;padding:1px 0;color:#16202b;background:rgba(255,255,255,.78)}
.pgnv-opening{font-size:12.5px;font-weight:600;color:var(--pgnv-dark,#0c7f99)}
.pgnv-graph{margin-top:2px}
.pgnv-graphsvg{width:100%;height:34px;display:block;background:#f7fafc;border:1px solid #e9eef2;border-radius:6px;cursor:pointer}
.pgnv-graphmid{stroke:#d3dde4;stroke-width:.4}
.pgnv-grapharea{fill:none;stroke:var(--pgnv-dark,#0c7f99);stroke-width:1;vector-effect:non-scaling-stroke}
.pgnv-graphcur{stroke:#e5484d;stroke-width:.6;vector-effect:non-scaling-stroke}
.pgnv-nav.on{background:var(--pgnv-dark,#0c7f99);color:#fff;border-color:var(--pgnv-dark,#0c7f99)}

/* ── Inline PDF viewer block (embed_pdf) ─────────────────────────────────── */
.pdf-embed{margin:1.5rem 0}
.pdf-embed__frame{position:relative;width:100%;background:#f1f5f9;border:1px solid #e2e8f0;border-radius:8px;overflow:hidden}
.pdf-embed__frame--short{height:480px}
.pdf-embed__frame--medium{height:720px}
.pdf-embed__frame--tall{height:1000px}
.pdf-embed__doc{width:100%;height:100%;border:0;display:block}
.pdf-embed__bar{display:flex;align-items:center;gap:1rem;padding:.5rem .25rem;font-size:.9rem}
.pdf-embed__title{font-weight:600;color:#334155}
.pdf-embed__dl{margin-left:auto;white-space:nowrap}
@media (max-width:760px){
  .pdf-embed__frame--short{height:60vh}
  .pdf-embed__frame--medium{height:75vh}
  .pdf-embed__frame--tall{height:85vh}
}

/* P2.5 layout: inline width by default (fits the reading column), .pgn-viewer--wide
   for a featured full-column game; and a container-query stack so a narrow column
   OR a phone gets the mobile layout (board full-width on top, moves below, bigger
   nav) — one own-width-driven rule for both. */
.pgn-viewer{max-width:640px}
.pgn-viewer.align-center{margin-inline:auto}
.pgn-viewer.align-right{margin-left:auto;margin-right:0}
.pgn-viewer--wide{max-width:100%}
.pgnv{container-type:inline-size}
.pgn-viewer--wide .pgnv-board-wrap{width:min(440px,100%)}
@container (max-width:520px){
  .pgnv-main{flex-direction:column;align-items:stretch}
    .pgnv-board-wrap,.pgn-viewer--wide .pgnv-board-wrap{width:100%;max-width:min(420px,86vw);margin-left:auto;margin-right:auto}
  .pgnv-board-row{width:100%}
  .pgnv-moves{max-height:150px}
  .pgnv-nav{padding:9px 13px;font-size:15px}
}

/* eval bar reserves its width when off (no board resize on toggle) + player
   name/rating strips above and below the board. */
.pgnv-evalbar.is-off{visibility:hidden}
.pgnv-player{display:flex;align-items:center;gap:7px;padding:2px 2px 2px 20px;font-size:13px;min-height:23px}
.pgnv-player[hidden]{display:none}
.pgnv-pl-dot{width:10px;height:10px;border-radius:2px;flex:0 0 auto;border:1px solid rgba(0,0,0,.25)}
.pgnv-pl-dot--white{background:#fff}
.pgnv-pl-dot--black{background:#2b2b2b}
.pgnv-pl-name{font-weight:650;color:var(--ink,#16202c);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pgnv-pl-elo{margin-left:auto;padding-left:8px;color:var(--grey,#7b858f);font-variant-numeric:tabular-nums;font-size:12.5px}

/* coords outside the board (default) + export menu */
.pgnv-co-out{fill:var(--grey,#7b858f);font-size:.34px;text-anchor:middle;font-weight:600}
.pgnv-export{position:relative;display:inline-block}
.pgnv-export>summary{list-style:none;cursor:pointer;font-size:13px;line-height:1;padding:7px 11px;border:1px solid var(--line,#e2e8f0);background:#fff;border-radius:8px;user-select:none;color:var(--ink,#16202c)}
.pgnv-export>summary::-webkit-details-marker{display:none}
.pgnv-export>summary:hover{border-color:var(--cyan,#0fa3c4)}
.pgnv-export__menu{position:absolute;z-index:20;top:calc(100% + 4px);left:0;min-width:210px;background:#fff;border:1px solid var(--line-2,#d2e0e7);border-radius:9px;box-shadow:0 10px 28px rgba(16,32,45,.14);padding:5px;display:flex;flex-direction:column;gap:2px}
.pgnv-export__it{text-align:left;font:inherit;font-size:13px;padding:7px 9px;border:none;background:none;border-radius:6px;cursor:pointer;color:var(--ink,#16202c)}
.pgnv-export__it:hover{background:var(--chip,#e8f0fa)}

/* engine principal-variation readout (eval on) */
.pgnv-pv{font-size:13px;line-height:1.7;color:var(--ink,#16202c);background:var(--cyan-bg,#f2fafc);border:1px solid var(--line,#e2e8f0);border-radius:8px;padding:6px 9px}
.pgnv-pv__ev{font-weight:700;color:var(--cyan-d,#0c7f99);margin-right:4px}
.pgnv-pv__mv{cursor:pointer;padding:0 2px;border-radius:4px;font-weight:600}
.pgnv-pv__mv:hover{background:var(--chip,#e8f0fa)}

/* no-JS / print / SEO fallback (inside the viewer mount; replaced on hydrate) */
.pgn-fallback{display:flex;gap:16px;flex-wrap:wrap;align-items:flex-start;margin:4px 0}
.pgn-fallback>figure{margin:0;width:min(280px,100%);flex:0 0 auto}
.pgn-fallback__meta{flex:1 1 220px;min-width:0}
.pgn-fallback__players{font-weight:700;margin:0 0 8px;color:var(--ink,#16202c)}
.pgn-fallback__moves{font-size:14px;line-height:1.6;color:#2a323b;margin:0;word-break:break-word}

/* ── PGN reader mode ────────────────────────────────────────────────────────
   Forward-Chess-style reading of a long annotated study INSIDE an article: the
   annotation is the body copy, the board is a companion pinned beside it.

   This is a LAYOUT of the existing viewer, not a second one. `renderProse()`
   already emits inline clickable moves, inline comments and parenthesised
   variations — board mode just confines that output to a 320px scroll panel.
   Reader mode releases it and makes the board sticky instead.

   `position:sticky` does the whole job with no scroll JS: it pins within its
   containing block and lets go at that block's end, which IS the requirement
   ("follow me while I'm in the study, then get out of the way").
   ⚠️ It is silently killed by ANY ancestor with overflow:hidden|auto, and it
   needs the flex/grid parent on align-items:flex-start — with `stretch` the
   item fills the height and has nowhere to travel. Both hold here; check again
   before nesting a reader block inside anything new. */
/* The sticky board must pin BELOW the site header, which is itself
   `position:sticky; top:0` (header.mast) at every width. The header is
   `.site-brand img` 56px + `.mast .in` padding 12px×2 = 80px tall, so the board
   clears it with a hair of gap at 84px — the SAME value the article's own
   `.rail-side` uses to clear the same header. The first cut used 16px, which
   tucked the top rank and a half behind the header. If the header height ever
   changes, this variable and `.rail-side` both move together. */
.pgn-viewer--reader{max-width:100%;--reader-board-top:84px}
.pgn-viewer--reader .pgnv-main{flex-wrap:nowrap;gap:26px}
.pgn-viewer--reader .pgnv-board-wrap{position:sticky;top:var(--reader-board-top);flex:0 0 auto;width:min(380px,42%)}
/* The release: the annotation flows at full length as prose, so the block grows
   tall enough for the sticky board to have travel. */
.pgn-viewer--reader .pgnv-moves{max-height:none;overflow:visible;flex:1 1 auto;
  font-size:16px;line-height:1.8;color:#2a323b}
.pgn-viewer--reader .pgnv-moves .pgnv-mv{font-weight:650;cursor:pointer}
/* Variations are the place readers get lost; set them back so the mainline
   stays visually dominant at a glance. */
.pgn-viewer--reader .pgnv-var{color:#55606c;font-size:.94em}

/* Bigger board (editor option). The board SVG fills its wrapper, so a wider
   wrapper IS a bigger board — no engine change. */
.pgn-viewer--reader.pgn-viewer--rlg .pgnv-board-wrap{width:min(460px,50%)}

/* Text under the board (editor option): the board is pinned to the TOP of the
   block and the annotation runs full-width BELOW it, scrolling under the board as
   you read. The board STAYS (sticky) — the Forward-Chess arrangement.

   Why this and not "text wrapping around a floated board that also travels": it
   can't be done, and not for want of trying. A board that stays on screen owns
   its screen space the whole time, so text can go BELOW it but never INTO the
   space under it — a floated board gives the wrap only by scrolling away, and a
   float can't be `position:sticky`. Pinned-top is the only layout that keeps the
   traveling board AND a full-width text measure.

   `display:block` (not flex) so the sticky is bulletproof; the board keeps the
   base rule's `position:sticky; top:var(--reader-board-top)`. `.pgnv-side` is the
   board's sibling holding the prose — it becomes a plain full-width block. The
   board carries an opaque background + a soft lower shadow so the text reads
   cleanly as it scrolls underneath. */
.pgn-viewer--reader.pgn-viewer--rtop .pgnv-main{display:block}
/* Pinned-top board follows the BLOCK'S alignment. The reader wrapper is
   max-width:100% so the block fills the column, which means the align-* class
   can't position the block itself — so the board is aligned within it here.
   Default (left) keeps the board at the start; center/right mirror the align
   classes the wrapper already carries. Without this the board was always
   centered regardless of the editor's alignment setting. */
.pgn-viewer--reader.pgn-viewer--rtop .pgnv-board-wrap{width:min(340px,100%);margin:0 auto 14px 0;
  background:#fff;z-index:2;padding-bottom:8px;box-shadow:0 10px 14px -10px rgba(20,40,80,.3)}
.pgn-viewer--reader.pgn-viewer--rtop.align-center .pgnv-board-wrap{margin-inline:auto}
.pgn-viewer--reader.pgn-viewer--rtop.align-right .pgnv-board-wrap{margin-inline:auto 0}
.pgn-viewer--reader.pgn-viewer--rtop.pgn-viewer--rlg .pgnv-board-wrap{width:min(440px,100%)}
.pgn-viewer--reader.pgn-viewer--rtop .pgnv-side{display:block;min-width:0}

/* Board side for the side-by-side reader (default is board-left). */
.pgn-viewer--reader.board-right .pgnv-main{flex-direction:row-reverse}

/* ── Split "book" reading (editor option) ───────────────────────────────────
   The Forward-Chess / Chessable arrangement: a fixed-height two-pane widget —
   the annotation scrolls in its OWN pane on one side, the board fixed on the
   other. Unlike the sticky layouts this scrolls the pane, not the page, so the
   board can never be lost behind anything and the move stays put beside its
   text. The board keeps the block's own palette (the `style` preset). */
.pgn-viewer--split{max-width:100%}
.pgn-viewer--split .pgnv-main{display:flex;flex-wrap:nowrap;gap:22px;align-items:stretch;
  height:min(78vh,640px)}
.pgn-viewer--split.board-right .pgnv-main{flex-direction:row-reverse}
.pgn-viewer--split .pgnv-board-wrap{position:static;flex:0 0 auto;align-self:center;
  width:min(72vh,520px);max-width:46%}
.pgn-viewer--split.pgn-viewer--rlg .pgnv-board-wrap{width:min(80vh,600px);max-width:52%}
/* The text pane: its own scrollbar, a soft framed card. `.pgnv-side` is the
   board's sibling that holds the move list; the prose fills it and scrolls. */
/* The text side is a COLUMN: the scrolling pane takes the free height, the
   print footer sits under it (mount.js builds the wrapper). */
.pgn-viewer--split .pgnv-sidecol{flex:1 1 auto;min-width:0;min-height:0;
  display:flex;flex-direction:column;gap:8px}
.pgn-viewer--split .pgnv-side{flex:1 1 auto;min-width:0;min-height:0;overflow:auto;
  border:1px solid var(--line);border-radius:12px;padding:16px 20px;background:#fff}
/* Reader's diagram switch (toolbar ▦ / key d) — the block option decides whether
   they exist, this decides whether they are shown. */
.pgnv--nodia .pgnv-bk-dia{display:none}
.pgn-viewer--split .pgnv-moves{max-height:none;overflow:visible;font-size:16px;line-height:1.8;color:#2a323b}
.pgn-viewer--split .pgnv-moves .pgnv-mv{font-weight:650;cursor:pointer}
.pgn-viewer--split .pgnv-var{color:#55606c;font-size:.94em}

/* ── controls travel with the board (reading layouts) ────────────────────────
   The toolbar is in the board column everywhere; here the engine PV joins it, so
   the column is board-plus-controls and has to fit the pane's fixed height. The
   bar is centred under the board rather than left-aligned, because in these
   layouts the board is the centred object on the page. */
.pgn-viewer--reader .pgnv-board-wrap > .pgnv-bar,
.pgn-viewer--split .pgnv-board-wrap > .pgnv-bar{justify-content:center;margin-top:8px}
.pgn-viewer--reader .pgnv-board-wrap > .pgnv-pv,
.pgn-viewer--split .pgnv-board-wrap > .pgnv-pv{margin-top:8px;font-size:12.5px;
  max-height:8.5em;overflow:auto}
/* The split column is a fixed-height box: centre the stack and let the BOARD
   give up space first, so a long engine line can never push the toolbar out of
   the widget. */
.pgn-viewer--split .pgnv-board-wrap{align-self:center;display:flex;
  flex-direction:column;justify-content:center;max-height:100%;min-height:0}
.pgn-viewer--split .pgnv-board-row{min-height:0}
/* Board sized against the row height (not just its own width) now that the
   controls share the column — otherwise a 520px board plus a toolbar plus a PV
   line overflows the 640px pane. */
.pgn-viewer--split .pgnv-board-wrap{width:min(60vh,460px)}
.pgn-viewer--split.pgn-viewer--rlg .pgnv-board-wrap{width:min(70vh,540px);max-width:52%}

/* A study's rights/credit line. Sits under the viewer as a sibling, so it shows
   in every reading layout and on the study's own page from one rule — and it is
   deliberately NOT in the print block's hide list: a copyright notice that
   vanishes when the page is printed is the one place it must not vanish.

   The `:is(...)` prefix is not decoration: this is a <p> inside `.article .body`,
   whose own `p` rule (0,2,1) outranks a bare `.pgn-copyright` (0,1,0) and would
   set the notice at full body size. Same trap the `[#]` diagrams hit. */
.pgn-copyright,
:is(.article .body, .content-page .body, .content-page section, .pgn-page) .pgn-copyright{
  margin:.5em 0 1.2em;font-size:12px;line-height:1.5;color:#6b7682}
.pgn-page__board + .pgn-copyright{margin-top:.8em}

/* The game's header line at the top of the text pane — «White (Elo) — Black
   (Elo)». Set in the book serif so it reads as the chapter head it is. */
.pgn-viewer--split .pgnv-gamehead,.pgn-viewer--reader .pgnv-gamehead{
  font-family:Georgia,'Times New Roman',serif;color:#1d242c;
  margin:0 0 .55em;padding-bottom:.45em;border-bottom:1px solid #e4e8ec}
.pgn-viewer--split .pgnv-gamehead__players,
.pgn-viewer--reader .pgnv-gamehead__players{font-weight:700;font-size:1.04em;line-height:1.35}
.pgn-viewer--split .pgnv-gamehead__res,
.pgn-viewer--reader .pgnv-gamehead__res{margin-left:.6em;color:#5b6672;white-space:nowrap}
/* Event · venue · round · date — subordinate to the names above it. */
.pgn-viewer--split .pgnv-gamehead__meta,
.pgn-viewer--reader .pgnv-gamehead__meta{font-size:.86em;line-height:1.4;
  color:#5b6672;margin-top:.15em}
.pgnv-gamehead[hidden]{display:none}

/* ── the BOOK move list (reader + split) ──────────────────────────────────────
   A printed study, not a PGN stream: bold main-line runs alternating with real
   annotation paragraphs, secondary lines indented under them. Sits AFTER the
   reader/split blocks above so its equal-specificity move rules win. */
.pgnv-moves--book{font-family:Georgia,'Times New Roman',serif}
/* The main-line run — the heading the annotation below belongs to. */
.pgnv-moves--book .pgnv-bk-line{margin:1.5em 0 .35em;font-weight:700;font-size:1.05em;
  line-height:1.6}
.pgnv-moves--book .pgnv-bk-line:first-child{margin-top:0}
/* The shared .pgnv-mv chip padding opens a gap after the move number ("1. e4");
   a book sets the number tight to its move, so trim it here. */
.pgnv-moves--book .pgnv-mv{padding:0 1px}
.pgnv-moves--book .pgnv-bk-line .pgnv-mv{font-weight:700;cursor:pointer}
/* Annotation set as body copy; the paragraph under a run is indented, its
   continuations set flush. */
.pgnv-moves--book .pgnv-bk-p{margin:0 0 .7em;line-height:1.75;text-indent:0}
.pgnv-moves--book .pgnv-bk-p--lead{text-indent:1.7em}
/* A secondary line: its own indented block, quieter than the main line. */
.pgnv-moves--book .pgnv-bk-var{margin:0 0 .8em;padding-left:1.1em;
  border-left:2px solid #e4e8ec;color:#4a555f;font-size:.96em;line-height:1.7;
  font-style:normal}
.pgnv-moves--book .pgnv-bk-var .pgnv-mv{font-weight:600;cursor:pointer}
.pgnv-moves--book .pgnv-bk-var .pgnv-cm{font-style:italic}
/* Reader switch B — the same secondary line set INLINE. It has to read as part
   of the sentence, so every block affordance (rule, indent, smaller type) comes
   off. After the block rules above: same specificity, source order decides. */
.pgnv-moves--book .pgnv-bk-var--inline{display:inline;margin:0;padding:0;border:0;
  font-size:inherit;line-height:inherit;color:inherit}
.pgnv-moves--book .pgnv-bk-res{margin:1.2em 0 0;font-weight:700}
/* An inline `[#]` diagram: a plate set into the column, centred, sized so it
   never crowds the text pane it sits in. */
/* `figure.` is not decoration: these diagrams live inside `.article .body`,
   whose `figure{margin:20px 0}` (0,2,1) outranks a plain `.pgnv-bk-dia` (0,2,0).
   Matching its specificity wins on source order — but only to set the VERTICAL
   rhythm. Horizontal placement is the block's alignment setting's business, so
   the inline margins stay 0 here and the align rules below move it; hard-coding
   `auto` centred every diagram in every block, whatever the editor had chosen. */
.pgnv-moves--book figure.pgnv-bk-dia{margin:1.1em 0;width:min(300px,80%)}
.pgn-viewer.align-center .pgnv-moves--book figure.pgnv-bk-dia{margin-inline:auto}
.pgn-viewer.align-right .pgnv-moves--book figure.pgnv-bk-dia{margin-inline:auto 0}
/* The alignment places the widget and its plates; it must NOT justify the
   annotation. `.align-*` sets `text-align` on the block root, which inherits
   into the prose and set whole paragraphs centred or ragged-left — a book sets
   its text flush however its figures sit. Reading layouts only. */
.pgn-viewer .pgnv-moves--book{text-align:start}
.pgnv-moves--book .pgnv-bk-dia .pgnv-board{width:100%;height:auto;display:block;
  border:1px solid #cbd3da;border-radius:4px}

@media (max-width:760px){
  /* On a phone the two panes can't sit side by side — stack them, board on top
     (capped) with the text pane scrolling below in its own box. */
  .pgn-viewer--split .pgnv-main{flex-direction:column;height:auto}
  .pgn-viewer--split .pgnv-board-wrap,
  .pgn-viewer--split.pgn-viewer--rlg .pgnv-board-wrap{width:100%;max-width:min(380px,86vw);
    align-self:center;margin-inline:auto}
  .pgn-viewer--split .pgnv-side{max-height:60vh}
}

@media (max-width:760px){
  /* Mobile keeps the sticky board — a long study is HARDEST to follow on a
     phone, so falling back to the panel would drop the benefit exactly where
     it is worth most. The board is capped so the text keeps room to read.
     The mobile header is 4px taller (padding 14px×2 at the ≤680px breakpoint),
     so the board clears it at 88px; the opaque background keeps the prose from
     showing through as it scrolls under. */
  .pgn-viewer--reader{--reader-board-top:88px}
  /* A phone is always the capped stacked board, whatever the DESKTOP arrangement.
     The rtop/rlg selectors are listed so their higher specificity does not defeat
     this reset — the bigger board's 50% width would otherwise leak onto mobile. */
  .pgn-viewer--reader .pgnv-main,
  .pgn-viewer--reader.pgn-viewer--rtop .pgnv-main{display:flex;flex-direction:column;flex-wrap:nowrap}
  .pgn-viewer--reader .pgnv-board-wrap,
  .pgn-viewer--reader.pgn-viewer--rlg .pgnv-board-wrap,
  .pgn-viewer--reader.pgn-viewer--rtop .pgnv-board-wrap,
  .pgn-viewer--reader.pgn-viewer--rtop.pgn-viewer--rlg .pgnv-board-wrap{
    position:sticky;top:var(--reader-board-top);
    width:100%;max-width:min(380px,86vw);margin-inline:auto;max-height:38vh;
    z-index:2;background:#fff;padding-bottom:6px;box-shadow:none}
  .pgn-viewer--reader .pgnv-side,
  .pgn-viewer--reader.pgn-viewer--rtop .pgnv-side{min-width:0}
  .pgn-viewer--reader .pgnv-moves{max-height:none;font-size:15.5px}
}

/* The print/PDF button, in a footer row UNDER the text pane — outside its
   scroll box, so it never sits over the prose. */
.pgnv-printbar{display:flex;justify-content:flex-end;align-items:center;gap:6px;
  flex:0 0 auto;flex-wrap:wrap}
/* Reader switch C — the book-like pink wash instead of the site's teal chip.
   Beats `.pgnv-mv.on` (0,2,0) on specificity, so it wins wherever that applies. */
.pgnv--pink .pgnv-mv.on{background:#ffd3d8;color:#7a1f2b}
/* The diagram toggle rides this row too, so match the PDF button's height. */
.pgnv-printbar .pgnv-nav{padding:4px 10px;font-size:13px}
.pgnv-print{border:1px solid var(--line,#e2e8f0);background:#fff;border-radius:8px;
  padding:4px 11px;font:600 12.5px/1.4 inherit;color:var(--cyan-d,#0c7f99);cursor:pointer}
.pgnv-print:hover,.pgnv-print:focus-visible{background:var(--cyan-bg,#f2fafc);
  border-color:#bfe3ec}

@media print{
  .pgn-viewer [data-pgn-mount]{display:block!important}

  /* ── the page as a document ────────────────────────────────────────────────
     Everything that is navigation, commerce or interaction comes off; what is
     left is the article. */
  @page{margin:16mm 14mm}
  header.mast,footer.site,.crumb,.rail-side,.rail-drawer,.cookie-notice,
  .preview-ribbon,.site-search,.pgnv-bar,.pgnv-printbar,.pgnv-graph-host,
  .pgnv-pv,.pgnv-export,.pgnv-warn,.live-card__sections{display:none!important}
  body{background:#fff!important}
  main{padding:0!important}
  /* The rail is gone, so the body takes the full measure. */
  .article{display:block!important}

  /* On screen the book is a FIXED-HEIGHT widget with its own scrollbar. Printed
     as-is that yields one page showing only the visible slice, so the pane is
     unclamped and the prose flows across pages like the book it imitates. */
  .pgn-viewer--split .pgnv-main,.pgn-viewer--reader .pgnv-main,
  .pgn-viewer--split .pgnv-sidecol{display:block!important;height:auto!important}
  .pgn-viewer--split .pgnv-side,.pgn-viewer--reader .pgnv-side{overflow:visible!important;
    max-height:none!important;border:0!important;padding:0!important;background:none!important}
  /* The board column comes OFF the page entirely. It shows wherever the reader
     happened to stop — one arbitrary position, printed as if it were the
     subject — while the `[#]` diagrams are the positions the author CHOSE, and
     they carry the study on paper. Its player strips go with it and are no
     loss: the text pane's game header names the players properly. */
  .pgn-viewer--split .pgnv-board-wrap,.pgn-viewer--reader .pgnv-board-wrap{
    display:none!important}

  /* A board split across a page break is unreadable, and a run of moves
     stranded at the foot of a page has lost the annotation it introduces. */
  .pgnv-bk-dia,.pgnv-board-wrap,.pgnv-bk-line,.pgnv-bk-var,figure,table{
    break-inside:avoid;page-break-inside:avoid}
  .pgnv-bk-line{break-after:avoid;page-break-after:avoid}
  h1,h2,h3{break-after:avoid;page-break-after:avoid}

  /* Browsers drop background fills when printing — which would print every
     board as eight empty rows. */
  .pgnv-board,.pgnv-bk-dia,.pgnv-sq{-webkit-print-color-adjust:exact;
    print-color-adjust:exact}

  /* Link colour carries no meaning on paper. */
  .article .body a{color:inherit!important;text-decoration:underline}
}

/* live broadcast download / copy / board-image menu — a positioned popover
   (like the ⊞ tiles menu) so it never grows the card; one button per feature,
   laid out horizontally (wraps on a narrow screen). */
.bcast-dlmenu{position:fixed;z-index:60;display:flex;flex-wrap:wrap;gap:6px;max-width:min(920px,94vw);background:#0e2c39;border:1px solid #1d5366;border-radius:9px;padding:8px;box-shadow:0 12px 34px rgba(0,0,0,.45)}

/* Left/Center/Right picker inside both copy popovers. A segmented row rather
   than three loose buttons, because the three are one choice — and clicking the
   active one clears it, which is how "leave the layout alone" stays reachable. */
/* The stream link buttons wrap freely on the first row; everything that CONFIGURES
   them shares a full-width second row. `flex-basis:100%` is what forces the break
   — as bare flex items the two groups wrapped in beside the links, which crammed
   the alignment picker onto the link row and left the toggles alone below it. The
   separator lives here, on the row, so it can never be drawn mid-row. */
.bcast-menurow{flex-basis:100%;display:flex;flex-wrap:wrap;align-items:center;
  gap:4px 14px;margin-top:6px;padding-top:6px;border-top:1px solid #1d5366}
.bcast-alignrow{display:flex;gap:4px}
.bcast-alignbtn{flex:1;padding:5px 6px;font:600 12px/1.2 inherit;color:#bfe1ec;
  background:#123b49;border:1px solid #1d5366;border-radius:5px;cursor:pointer;white-space:nowrap}
.bcast-alignbtn:hover{background:#17495a;color:#eaf6fb}
.bcast-alignbtn.on{background:#0c7f99;border-color:#0c7f99;color:#04222b}
.bcast-dlmenu[hidden]{display:none} /* the display:flex above beats the UA [hidden] rule — restore hide */
.bcast-dlmenu button{font:inherit;font-size:12.5px;white-space:nowrap;padding:7px 11px;border:1px solid rgba(127,214,234,.35);background:rgba(255,255,255,.06);color:#eaf6fb;border-radius:7px;cursor:pointer}
.bcast-dlmenu button:hover{background:rgba(127,214,234,.22)}

/* Homepage alert bar (HomepageAlert) — dark-red single row under the header menu. */
.site-alert{display:block;background:#fff;color:#8a1220;text-decoration:none;font-weight:600;border-bottom:1px solid #ecd8db}
.site-alert__in{display:block;max-width:1440px;margin:0 auto;padding:10px 40px;text-align:center;font-size:14.5px;line-height:1.4}
a.site-alert:hover{color:#a3162a;background:#fdf6f7}
.site-alert__arrow{margin-left:.5em;opacity:.7}
@media(max-width:760px){.site-alert__in{padding:9px 16px;font-size:13.5px}}

/* ===== Public PGN Studio page (/pgn/<slug>) ==============================
   Deliberately spare: the board is the content. The header carries only what
   the PGN itself knows (players, event, date, result), so a study pasted
   without a Seven Tag Roster degrades to just its title rather than showing
   empty rows. */
.pgn-page{padding:8px 0 44px;max-width:960px;margin:0 auto}
.pgn-page__head{margin:0 0 18px}
.pgn-page__title{margin:0 0 6px;color:var(--navy,#06303d)}
.pgn-page__players{margin:0 0 4px;font-size:18px;font-weight:700;color:#0c7f99}
.pgn-page__meta{margin:0;font-size:14px;color:#688}
.pgn-page__desc{margin:10px 0 0;color:#566}
.pgn-page__board{margin-top:18px}
/* The board block ships its own width rules; on this page it is the whole
   point, so let it use the full column rather than the article inline width. */
.pgn-page__board .pgn-viewer{max-width:none}

/* ===== /live multi-section events =======================================
   A festival (Biel 2026 has 21 sections) stays ONE card; the sections live in
   a picker so the list doesn't become unreadable. Hidden until the island has
   confirmed there really are siblings, so a single-tour card is unchanged. */
.live-card__sections{display:flex;flex-direction:column;gap:.3rem;margin:.4rem 0 .1rem}
.live-card__sections[hidden]{display:none}
/* Two rows: the control sits BESIDE what it affects. The finished-sections
   checkbox is on the dropdown's row, the Greek filter on the search box's — an
   earlier version put the finished toggle two rows below its own list, which
   gave no clue what it applied to. */
.live-sections__row{display:flex;align-items:center;gap:.3rem}
.live-sections__select,.live-sections__search{flex:1 1 auto;min-width:0;box-sizing:border-box;height:1.75rem;padding:.15rem .4rem;border:1px solid #cfe0e8;border-radius:6px;font:inherit;font-size:12.5px;background:#fff;color:#06303d}
/* Both trailing controls share a width so the two rows line up. */
.live-sections__done,.live-sections__greek{flex:0 0 2.6rem;display:inline-flex;align-items:center;justify-content:center;gap:.15rem;height:1.75rem;box-sizing:border-box}
.live-sections__done{font-size:11px;color:#4a5b6b;cursor:pointer;user-select:none;border:1px solid #cfe0e8;border-radius:6px;background:#fff}
.live-sections__done input{margin:0;width:.8rem;height:.8rem;cursor:pointer}
.live-sections__greek{border:1px solid #cfe0e8;border-radius:6px;background:#fff;cursor:pointer;padding:0}
.live-sections__greek[hidden]{display:none}
.live-sections__greek img{display:block;height:12px;width:auto}
.live-sections__greek.is-on{border-color:#0c7f99;box-shadow:inset 0 0 0 1px #0c7f99;background:#eef7fa}
/* Greyed out once we KNOW there is no Greek/Cypriot player to filter to. */
.live-sections__greek:disabled,.live-sections__greek.is-off{opacity:.35;cursor:not-allowed}
.live-sections__greek:disabled img{filter:grayscale(1)}
/* Greek-interest sections are bolded in the dropdown so they stand out while
   scanning a long section list. `font-weight` on <option> is honoured by
   Chrome/Firefox on desktop; the ★ prefix carries the same signal everywhere
   else (Safari and every mobile picker ignore option styling entirely). */
.live-sections__select option.is-greek{font-weight:800;color:#0c5b74}
.live-sections__note{margin:0;font-size:11.5px;color:#688;min-height:1em}
/* Matching players, listed as you type — clickable, because the point of
   finding a player is watching their game. Capped in height so a broad query
   can't push the rest of the card off screen. */
.live-sections__results{list-style:none;margin:.25rem 0 0;padding:0;max-height:11rem;overflow:auto;border:1px solid #dfeaf0;border-radius:6px;background:#fff}
.live-sections__results[hidden]{display:none}
.live-sections__results li+li{border-top:1px solid #eef3f6}
.live-sections__hit{display:flex;flex-direction:column;gap:.05rem;width:100%;text-align:left;border:0;background:none;padding:.3rem .45rem;font:inherit;cursor:pointer}
.live-sections__hit:hover,.live-sections__hit:focus-visible{background:#eef7fa}
.live-sections__hit-name{display:flex;align-items:center;gap:.25rem;font-size:12px;font-weight:700;color:#06303d}
.live-sections__hit-flag{height:9px;width:auto;flex:0 0 auto}
.live-sections__hit-sec{font-size:11px;color:#688}


/* The section picker carried up into the board module, beside the round picker. */
.bcast-sections-sel{max-width:15rem}

/* Study attribution under a PGN block's game head (see pgn/mount.js studyCredit). */
.pgnv-gamehead__credit,.pgnv-credit{font-size:.78rem;color:var(--grey);margin:2px 0 6px}
.pgnv-gamehead__credit a,.pgnv-credit a{color:var(--cyan-d);text-decoration:underline}

/* The meeting filter and its 📺 share one row. The select is width:100%, so a
   bare sibling after it wrapped onto a line of its own and read as a stray icon
   nobody found — the flex row is what keeps them together. The row carries the
   bottom margin the select used to. */
.bcast-team-row{display:flex;align-items:center;gap:6px;margin:0 0 8px}
.bcast-team-row .bcast-team-filter{flex:1;min-width:0}
.bcast-team-row:has(> [hidden]:only-child){margin:0}
/* 📺 — that meeting as one OBS source, every board stacked. Shown only while the
   filter names a meeting. */
.bcast-match-tv{flex:none;padding:5px 8px;border-radius:6px;background:#0c5266;
  font-size:14px;line-height:1;text-decoration:none;cursor:pointer}
.bcast-match-tv:hover{background:#0e6f93}
.bcast-match-tv[hidden]{display:none}
