/* Bilateral Navigator — portal stylesheet, shared by every service.
   Palette and metrics are the demo files' in tmp/, kept verbatim so the two
   can be compared side by side. The demo hardcodes Croatia and Sweden as
   `hr`/`se`; here the two sides are `c1`/`c2`, because the Library renders
   any pair. */

:root{
  --navy:#0E1F33; --navy-deep:#091625; --navy-panel:#132A44; --navy-card:#10233B;
  --sky:#4FB8E7; --sky-soft:#9AD4F0;
  --c1-ink:#7FA3DD; --c2-ink:#29ADE4;
  --sim-c1:#2F5D9E; --sim-c2:#00A0E2;
  --text:#E7F0F7; --text-soft:#A9BDCF;
  --line:rgba(79,184,231,.16); --stripe:rgba(255,255,255,.045);
  --radius:14px; --shadow:0 12px 32px rgba(4,12,22,.5);
}

*{margin:0;padding:0;box-sizing:border-box}
html{scroll-behavior:smooth}
html,body{overflow-x:hidden;max-width:100vw}
body{font-family:'Albert Sans',system-ui,sans-serif;background:var(--navy);
  color:var(--text);min-height:100vh}
button{font:inherit;color:inherit;background:none;border:none;cursor:pointer}
a{color:var(--sky);text-decoration:none}
img{max-width:100%}

@media (prefers-reduced-motion: reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation:none!important;transition:none!important}
}

/* Barely-there scrollbars, everywhere. */
*{scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.16) transparent}
*::-webkit-scrollbar{width:5px;height:5px}
*::-webkit-scrollbar-track{background:transparent}
*::-webkit-scrollbar-thumb{background:rgba(255,255,255,.16);border-radius:99px}
*::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,.3)}

/* ===== topbar ===== */
.topbar{position:sticky;top:0;z-index:60;display:flex;align-items:center;
  gap:14px;padding:12px 22px;background:rgba(9,22,37,.93);
  backdrop-filter:blur(9px);border-bottom:1px solid var(--line)}
.brand{display:flex;align-items:baseline;gap:7px;white-space:nowrap;font-size:15px}
.brand b{font-weight:800}
.brand span{color:var(--sky);font-weight:600}
.topnav{font-size:12.5px;color:var(--text-soft);white-space:nowrap;min-width:0;
  overflow:hidden;text-overflow:ellipsis}
.topnav a{color:var(--text-soft)}
.topnav a:hover{color:var(--text)}
.topnav .sep{opacity:.5;margin:0 8px}

/* ===== flag disc ===== */
.cflag{display:inline-flex;width:18px;height:18px;border-radius:50%;
  overflow:hidden;flex:0 0 auto;background:#28466B;
  box-shadow:0 0 0 1px rgba(255,255,255,.22)}
.cflag img{width:100%;height:100%;object-fit:cover}
.cflag.big{width:24px;height:24px}
.cflag.sm{width:15px;height:15px}

/* ===== page frame ===== */
.wrap,.subwrap{max-width:1220px;margin:0 auto;padding:28px 20px 80px}
.pv-foot{max-width:1220px;margin:0 auto;padding:16px 20px 40px;font-size:12px;
  color:var(--text-soft);border-top:1px solid var(--line);line-height:1.6}
@media (max-width:640px){.wrap,.subwrap{padding:20px 12px 60px}}

/* The Library index carried a heading block here -- a .flags pair, an h1 of
   the two country names, a .lede and a .hint. All four went when the index
   became a card menu (library/index.html.j2), the same shape the prototype's
   own `_live/site/library.html` has: `<div class="wrap cards-first">` and the
   grid, nothing above it but the shared bar. .flags, .lede and .hint had no
   other user in the portal and are gone with them; the h1 rule below stays,
   because every other page's own h1 uses it. */
h1{font-size:clamp(26px,4vw,44px);font-weight:800;line-height:1.1;margin-bottom:10px}

/* ===== index: ten square flip tiles ===== */
/* margin-top:0 because there is no longer anything above the grid to be
   separated from -- the same reason .tgrid dropped the prototype's 14px when
   the service matrix went cards-first. .wrap's own top padding is the gap. */
.chgrid{display:grid;grid-template-columns:repeat(2,1fr);gap:14px;margin-top:0}
@media(min-width:900px){.chgrid{grid-template-columns:repeat(5,1fr);gap:18px}}
.tile{position:relative;aspect-ratio:1/1;perspective:1100px;cursor:pointer}
.flip{position:absolute;inset:0;transform-style:preserve-3d;
  transition:transform .6s cubic-bezier(.22,1,.36,1)}
.tile.flipped .flip{transform:rotateY(180deg)}
@media(hover:hover){.tile:hover:not(.noflip) .flip{transform:rotateY(180deg)}}
/* Focus is not gated on hover: a Tab key exists on touch hardware too, and
   without this the next tab stop after the tile is a link on the hidden
   back face. */
.tile:focus-within:not(.noflip) .flip{transform:rotateY(180deg)}
.face{position:absolute;inset:0;backface-visibility:hidden;
  -webkit-backface-visibility:hidden;border-radius:var(--radius);overflow:hidden;
  border:1px solid var(--line)}
/* A chapter with no opener picture keeps the tile, on a flat panel ground. */
.front{background:var(--navy-panel)}
.front img{width:100%;height:100%;object-fit:cover;display:block}
.front::after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(9,22,37,.03),rgba(9,22,37,.42) 52%,rgba(9,22,37,.95))}
/* The menu title standard, shared with the service matrix (.mtile .lab): the
   number sits in a fixed-width right-aligned column so chapter 10 lines up
   with the single digits beside it, a hairline separates it from the title,
   and the title breaks across two lines. Replaces a stacked "CHAPTER 01" that
   spent a line on a word every tile repeated. */
.front .fl{position:absolute;left:12px;right:12px;bottom:11px;z-index:2;
  display:flex;align-items:center;gap:9px}
.front .n{font-family:'IBM Plex Mono',monospace;font-size:15px;font-weight:600;
  color:var(--sky-soft);line-height:1;flex:0 0 auto;
  font-variant-numeric:tabular-nums;min-width:2ch;text-align:right}
.front .vr{flex:0 0 auto;width:1px;align-self:stretch;background:var(--sky-soft);
  opacity:.5}
.front .cn{font-size:clamp(13.5px,1.5vw,19px);font-weight:800;line-height:1.15;
  min-width:0;color:var(--text);text-shadow:0 2px 12px rgba(0,0,0,.65)}
.front .cn w{display:block}
/* The connector in a title like "Communication & Media" is greyed so the two
   real words carry the weight. */
.amp{color:rgba(255,255,255,.42);font-weight:700}
.front .turn{position:absolute;top:10px;right:11px;z-index:2;font-size:15px;
  color:#fff;opacity:.8}
/* THE BACK OF A CHAPTER CARD. A band down the left turns the card back over,
   and the sections are rows, each flex:1 1 0 so it is exactly a quarter of the
   tile -- about 45px on a 430px phone, which clears the 44px a thumb needs.
   The 8.5px uppercase chapter header is gone; the band replaces it, and the
   number and rule carry the same menu-title grammar the fronts use. */
.back{transform:rotateY(180deg);background:linear-gradient(160deg,#123457,#0a1a2e);
  display:flex;flex-direction:row}
.back .band{flex:0 0 34px;align-self:stretch;padding:0;border:none;cursor:pointer;
  background:rgba(154,212,240,.5);display:flex;align-items:center;
  justify-content:center;transition:background .15s}
.back .band:hover,.back .band:focus-visible{background:rgba(154,212,240,.72);outline:none}
.back .band::before{content:"‹";font-family:'IBM Plex Mono',monospace;
  font-size:19px;line-height:1;color:#0E1F33;opacity:.62;margin-top:-2px}
.back .rows{flex:1 1 auto;min-width:0;display:flex;flex-direction:column}
.back .rows a{flex:1 1 0;min-height:0;display:flex;align-items:center;gap:8px;
  padding:0 10px;color:var(--text);text-decoration:none;
  border-top:1px solid rgba(255,255,255,.07);transition:background .14s}
.back .rows a:first-child{border-top:none}
.back .rows a:hover,.back .rows a:focus-visible{background:rgba(79,184,231,.17);outline:none}
.back .sn{font-family:'IBM Plex Mono',monospace;font-size:11.5px;font-weight:600;
  color:var(--sky-soft);line-height:1;flex:0 0 auto;min-width:1ch;text-align:right}
.back .sr{flex:0 0 auto;width:1px;align-self:stretch;margin:9px 0;
  background:var(--sky-soft);opacity:.4}
.back .sname{font-size:clamp(10.5px,1.15vw,13.5px);font-weight:700;
  line-height:1.16;min-width:0}
.back .sname w{display:block}

/* The face turned AWAY must not capture clicks. backface-visibility:hidden stops
   a face being painted but not hit tested, and the front label sits exactly over
   the fourth row of the flipped back. These mirror the flip conditions exactly,
   .noflip included, so whichever face you can see is the one that answers. */
.face.back{pointer-events:none}
.tile:hover:not(.noflip) .face.back,
.tile:focus-within:not(.noflip) .face.back{pointer-events:auto}
.tile:hover:not(.noflip) .face.front,
.tile:focus-within:not(.noflip) .face.front{pointer-events:none}

/* ===== section: sub-head ===== */
.sub-head{display:flex;gap:22px;align-items:center;flex-wrap:wrap;
  padding-bottom:20px;border-bottom:1px solid var(--line)}
.sub-head h1{font-size:clamp(24px,3.4vw,40px);font-weight:800;margin:6px 0 8px}
/* B1 of the prototype's 2026-08-30 change set: the header is the badge and the
   title, and the title column carries no width floor. `flex:1 1 0` with
   `min-width:0` is what lets a long title WRAP inside its own column instead of
   pushing the header wider; the old `min-width:240px` forced the whole title
   block onto its own line under the badge on a narrow phone. Two lines of title
   beside the badge is the intended look. The `.flagpair` and `.signrow` rules
   that stood here went with the markup B1 removed. */
.sub-head .headtitle{flex:1 1 0;min-width:0}
.sub-head .headtitle h1{margin:0}

.outcome{font-family:'Source Serif 4',serif;font-style:italic;font-size:16px;
  color:var(--text-soft);max-width:680px;line-height:1.6}
.outcome mark{background:none;color:var(--sky);font-style:normal;font-weight:600}
/* B2: the third-country paragraph now closes the page under the similarity
   chart, where it is a paragraph of its own rather than part of the header
   block. The prototype writes this as `.closenote+.outcome`; here every element
   is wrapped in a `.pv-el`, so the chart's `.closenote` is not the outcome's
   sibling and the rule is hung on the position instead. */
main>.outcome{margin-top:16px}

.section-label{font-size:11.5px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--sky);font-weight:700;margin:34px 0 13px}

/* ===== section: similarity ring ===== */
.headviz{display:flex;flex-direction:column;align-items:center;gap:12px;flex:0 0 auto}
.ring{flex:0 0 auto;width:96px;height:96px;position:relative}
.ring svg{width:100%;height:100%;transform:rotate(-90deg)}
.ring .track{fill:none;stroke:rgba(255,255,255,.09);stroke-width:8}
.ring .arc{fill:none;stroke:var(--sky);stroke-width:8;stroke-linecap:round;
  transition:stroke-dashoffset 1.1s cubic-bezier(.22,1,.36,1)}
.ring .val{position:absolute;inset:0;display:flex;align-items:center;
  justify-content:center;font-family:'IBM Plex Mono',monospace;font-weight:600;
  font-size:19px;color:#fff}
.ring .val small{font-size:12px;color:var(--sky);margin-left:1px}
@media (max-width:640px){.headviz{flex-direction:row;align-items:center;gap:14px}}

/* ===== section: two-column layout ===== */
.sublayout{display:grid;grid-template-columns:minmax(0,1fr) 250px;gap:30px;
  align-items:start;margin-top:4px}
.pv-el{min-width:0}
.rail .section-label{margin-top:0}

/* ===== section: reader card ===== */
.reader{background:var(--navy-card);border:1px solid var(--line);
  border-radius:var(--radius);padding:22px 24px}
.prose{font-family:'Source Serif 4',serif;font-size:15.5px;line-height:1.72;color:#D5E2ED}
.prose p+p,.prose .more p{margin-top:12px}
.pv-h3{font-size:16px;font-weight:800;margin-bottom:10px}
/* Open by default so the page reads with the script blocked; library.js adds
   .folded on load and .expanded on click. */
.reader.folded .more,.narr.folded .more{display:none}
.reader.folded.expanded .more,.narr.folded.expanded .more{display:block;margin-top:12px}
.linkbtn{margin-top:13px;color:var(--sky);font-weight:700;font-size:13px;
  display:none;align-items:center;gap:6px}
.reader.folded>.linkbtn,.narr.folded>.linkbtn{display:inline-flex}
.linkbtn:hover{text-decoration:underline}
.linkbtn .chev{transition:transform .25s;display:inline-block}
.reader.expanded>.linkbtn .chev,.narr.expanded .linkbtn .chev{transform:rotate(180deg)}

@media (max-width:1020px){
  /* align-items:stretch is REQUIRED. The base .sublayout rule sets
     align-items:start for the two-column grid, and in a flex column that same
     declaration stops the children stretching: .rail collapses to its content
     width (58px measured in WebKit) and the image strip shows two thirds of one
     thumbnail. Chromium stretches regardless, which is why this only ever
     showed on iPhone. The prototype's _tools/fix_mobile_rail.py. */
  .sublayout{display:flex;flex-direction:column;align-items:stretch;
    /* B3 of the 2026-08-30 change set: the rail moves above the text here, so
       the gallery sits directly on top of the Introduction heading. The 30px
       column gap plus the 34px heading margin left 64px of air between a strip
       of thumbnails and the first line of reading. Halved, on both halves --
       the heading half is the rule below. */
    gap:15px}
  /* Named by position, not by wrapper class. The renderer's own wrapper is
     `.pv-el` and the prototype has a bare `.section-label`; hanging the rule on
     either one alone means a template change on the other side silently
     restores the 34px. Both forms are covered. */
  .sublayout>main>:first-child .section-label:first-child,
  .sublayout>main>.section-label:first-child{margin-top:17px}
  .rail{order:-1;min-width:0;max-width:100%;width:100%;align-self:stretch}
}

/* ===== section: image rail ===== */
.thumbs{display:flex;flex-direction:column;gap:13px}
.thumb{border-radius:12px;overflow:hidden;background:var(--navy-card);
  border:1px solid var(--line);text-align:left;
  transition:transform .25s ease,border-color .25s ease;flex:0 0 auto}
.thumb:hover,.thumb:focus-visible{transform:translateY(-3px);border-color:var(--sky)}
/* Two frames, because the pictures come in two shapes: the RESIZED_V
   derivative is 536x720 and the RESIZED_H one 720x521. One 3/4 frame for both
   meant `cover` cut a landscape photo down to 54% of its width. `.h` is set
   from the picture's `format` (see el/images.html.j2), so the frame matches
   the file and nothing is lost. Custom uploads that follow neither shape are
   still cover-cropped into whichever frame their format names. */
.thumb .ph{aspect-ratio:536/720;position:relative;display:block}
.thumb .ph.h{aspect-ratio:720/521}
.thumb .ph .phimg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
/* A third frame, for the two country graphs -- the knowledge graphs of 05#2
   (el/knowledge.html.j2) and the flavour networks of 10#4
   (el/cuisine.html.j2). Their derivative is the graph's own bounding box, not
   one of the two picture shapes: 720px wide against 576-728px tall for the
   199 SKILLS_SVG files and 524-713px for the 193 CUISINE_SVG ones. So it is
   square -- the widest letterboxes by ~27%, the tallest by ~1% -- and
   `contain`, because cropping a diagram to fill a frame cuts labels off it.
   White, which is the PNGs' own background, so the letterbox bands are not
   visible as bands. */
.thumb .ph.g{aspect-ratio:1/1;background:#fff}
.thumb .ph.g .phimg{object-fit:contain}
/* Whose picture this is. Top left over the photograph, above the image but
   below nothing else -- the thumb has no other overlay. The ring is what keeps
   an 18px flag legible against an arbitrary photograph. */
.thumb .cc{position:absolute;top:9px;left:9px;z-index:1;display:block}
.thumb .cc .cflag{width:18px;height:18px;box-shadow:0 0 0 1px rgba(255,255,255,.5),
  0 1px 4px rgba(0,0,0,.55)}
.thumb .tt{display:block;padding:8px 11px;font-size:11.5px;font-weight:600;
  line-height:1.35;color:var(--text)}
.thumb.selected{border-color:var(--sky);box-shadow:0 0 0 1px var(--sky)}

/* The caption is in the markup so it is readable without JavaScript. Once
   the script runs the viewer shows it in full, so the rail hides it. */
.thumb .tcap{display:block;padding:0 11px 9px;font-size:11px;line-height:1.4;
  color:var(--text-soft)}
.js .thumb .tcap{display:none}

/* ===== section: image viewer popup =====
   A fixed panel, vertically centred in the viewport, whose right edge tracks
   the image rail's left edge through `--vx` (library.js measures the rail).
   It used to be an in-flow panel above the two columns, which meant opening a
   thumb from halfway down a long section threw the reader back to the top of
   the page. Nothing scrolls now.

   With the script blocked the panel is never filled and `.open` never added,
   so it stays invisible and inert and the rail's own `.tcap` captions carry
   the text instead (see `.js .thumb .tcap`). */
.viewer{position:fixed;z-index:70;top:50%;right:var(--vx,20px);
  transform:translateY(-50%) scale(.97);transform-origin:100% 50%;
  opacity:0;pointer-events:none;
  transition:opacity .28s ease,transform .28s cubic-bezier(.22,1,.36,1)}
.viewer.open{opacity:1;pointer-events:auto;transform:translateY(-50%) scale(1)}
/* The dimmed page behind the popup. A pseudo-element rather than a node: there
   is nothing to keep in sync, and a click on it reports `.viewer` itself as
   the target (pseudo-element boxes hit-test as their originator), which is how
   library.js separates a backdrop click from a click on the panel. */
.viewer.open::before{content:'';position:fixed;inset:0;z-index:-1;
  background:rgba(4,10,18,.62);backdrop-filter:blur(2px)}
/* The panel is shaped by the picture, like the rail's frames above: `--ar` and
   `--wmax` hold the two shapes and library.js flips them by adding `.h` from
   the thumb's data-fmt. Landscape gets the wider cap since 400px would leave
   it only 290px tall.

   Width follows the viewport height as well as the cap, not a flat --wmax: a
   400px-wide portrait panel stands 537px tall, and a vertically centred panel
   that tall overflows a short window at both ends, where an in-flow one merely
   got scrolled past. The third term keeps a wide panel off the left edge —
   --vx is the gap the popup keeps from the right (see .viewer), so it is also
   how much room is left. The vh line is the fallback for browsers without svh
   — a dropped `width` would collapse the panel, since .big's img is
   positioned. */
.viewer-in{--ar:.744;--wmax:400px;position:relative;
  width:min(var(--wmax),calc((100vh - 48px) * var(--ar)),
            calc(100vw - var(--vx,20px) - 24px));
  width:min(var(--wmax),calc((100svh - 48px) * var(--ar)),
            calc(100vw - var(--vx,20px) - 24px));
  border-radius:var(--radius);overflow:hidden;border:1px solid var(--sky);
  box-shadow:var(--shadow)}
.viewer-in.h{--ar:1.382;--wmax:560px}
/* The country graphs' frame, matching `.thumb .ph.g` above: square, white,
   contained. library.js sets `.g` from the thumb's data-fmt, as it does `.h`.
   520px because a graph is read for its labels, and it is the one thing in
   the rail that is worth the extra width. */
.viewer-in.g{--ar:1;--wmax:520px;background:#fff}
.viewer-in .big{aspect-ratio:var(--ar);position:relative;display:block}
.viewer-in .big img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.viewer-in.g .big img{object-fit:contain}
.vcap{position:absolute;left:0;right:0;bottom:0;z-index:2;max-height:40%;
  overflow-y:auto;background:linear-gradient(180deg,rgba(4,10,18,0),rgba(4,10,18,.78) 26%);
  padding:16px 14px 10px}
.vcap .vt{font-size:13.5px;font-weight:800;color:#fff;line-height:1.3}
.vcap .vd{font-size:11px;color:#D9E6F0;line-height:1.5;margin-top:4px}
.vclose{position:absolute;top:8px;right:8px;z-index:3;width:30px;height:30px;
  border-radius:50%;background:rgba(4,10,18,.6);color:#fff;font-size:14px;
  display:flex;align-items:center;justify-content:center;
  border:1px solid rgba(255,255,255,.3)}
.vclose:hover{background:rgba(4,10,18,.85)}

@media (max-width:1020px){
  /* align-items:flex-start, because the row holds both frames now: the default
     stretch would give a 104px-wide landscape card the height of a portrait
     one and leave the difference blank under the photo. */
  .thumbs{flex-direction:row;align-items:flex-start;
    overflow-x:auto;overflow-y:hidden;padding-bottom:8px;
    overscroll-behavior-x:contain;-webkit-overflow-scrolling:touch;
    touch-action:pan-x;scroll-snap-type:x proximity}
  .thumb{flex:0 0 104px;scroll-snap-align:start}
  .thumb .tt{display:none}
  .thumb:hover,.thumb:focus-visible{transform:none}
  /* The rail is above the main column here, so "left of the images" has no
     meaning: centre the popup instead. --vx is left unread. */
  .viewer{right:auto;left:50%;transform:translate(-50%,-50%) scale(.97);
    transform-origin:50% 50%}
  .viewer.open{transform:translate(-50%,-50%) scale(1)}
  .viewer-in{width:min(var(--wmax),calc(100vw - 32px),
                       calc((100vh - 48px) * var(--ar)));
    width:min(var(--wmax),calc(100vw - 32px),
              calc((100svh - 48px) * var(--ar)))}
}

/* ===== section: table =====
   .trow0, .thead and .trowbtn share one column template so the three stay
   aligned; the responsive rules below drop Source, then Year, from all of
   them at once. */
.tblwrap{background:var(--navy-card);border:1px solid var(--line);
  border-radius:var(--radius);overflow:hidden}
.tscroll{overflow-x:auto}
.trow0,.thead,.trowbtn{display:grid;gap:2px;align-items:center;padding:0 12px;
  grid-template-columns:minmax(200px,1fr) 74px 24px 30px 24px 74px 38px 48px 20px}
.trow0{background:var(--navy-deep);padding-top:10px;padding-bottom:2px}
.trow0 .t-title{font-weight:800;font-size:14px;color:#fff}
.trow0 .t-cty{font-weight:800;font-size:14px;letter-spacing:.02em;
  display:inline-flex;align-items:center;gap:7px}
.trow0 .t-cty.c1{grid-column:2/4;justify-content:flex-end;color:var(--c1-ink)}
.trow0 .t-cty.c2{grid-column:5/7;justify-content:flex-start;color:var(--c2-ink)}
.thead{background:var(--navy-deep);font-size:10px;letter-spacing:.08em;
  text-transform:uppercase;font-weight:700;color:var(--text-soft)}
.thead>span{padding:7px 0 9px;text-align:center}
.thead .h-ind{text-align:left}
.tgroup{padding:9px 16px 5px;font-size:11px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--sky);font-weight:700;
  background:rgba(79,184,231,.06);border-top:1px solid var(--line)}
.trow{border-top:1px solid rgba(255,255,255,.05)}
.trow.tint .trowbtn{background:var(--stripe)}
.trowbtn{width:100%;text-align:left;padding-top:8px;padding-bottom:8px;
  transition:background .2s}
.trowbtn:hover:not(.noexpand){background:rgba(79,184,231,.09)!important}
.trowbtn:focus-visible{outline:2px solid var(--c2-ink);outline-offset:-2px}
/* A row with detail is an <a> now (an hx-get alone has no href for the
   script-blocked case; region.qs() builds a real one), not a <button> --
   so it no longer picks up the plain `button{...}` reset above, and needs
   its own: an anchor's own default underline and link colour would show
   through every child span otherwise, since none of them sets its own. */
a.trowbtn{color:inherit;text-decoration:none;cursor:pointer}
/* A row with nothing to expand into is rendered as a plain div (see
   table.html.j2), not a link — no hover/focus affordance that would
   promise an expand that isn't there. */
.trowbtn.noexpand{cursor:default}
.tind{font-size:13.5px;font-weight:600;color:var(--text);min-width:0}
.tind .pv-smalldesc{display:block;font-weight:400;font-size:11px;
  color:var(--text-soft);margin-top:1px}
.tval{font-family:'IBM Plex Mono',monospace;font-size:12.5px;text-align:right;
  white-space:nowrap;color:#fff;padding-right:10px}
.tval.c2{text-align:left;padding-left:10px;padding-right:0}
.tmid{display:flex;justify-content:center;align-items:center}
.trend{display:flex;align-items:flex-end;gap:2.5px;height:16px}
.trend i{width:4.5px;border-radius:1.5px 1.5px 0 0;display:block}
.trend.c1 i{background:var(--c1-ink)}
.trend.c2 i{background:var(--c2-ink)}
.trend i:last-child{box-shadow:0 0 6px rgba(79,184,231,.55)}
.tsrc{font-family:'IBM Plex Mono',monospace;font-size:10px;color:var(--text-soft);
  text-align:center;white-space:nowrap}
.tchev{color:var(--text-soft);transition:transform .25s;text-align:center;font-size:11px}
.trow.open .tchev{transform:rotate(180deg)}
.gapsvg{display:block}
.closenote{font-size:11.5px;color:var(--text-soft);margin-top:10px;
  line-height:1.55}
/* Only inside the table wrapper is this an inset caption at a reading
   measure; the similarity figure caption spans its full-width chart. */
.tblwrap .closenote{max-width:760px;padding:0 12px 12px}

/* ===== section: table tabs ===== */
.tbltabs{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:12px}
.tbltab{font-size:12.5px;font-weight:700;padding:7px 14px;border-radius:999px;
  border:1.5px solid var(--line);background:rgba(9,22,37,.6);color:var(--text-soft);
  transition:all .18s}
.tbltab:hover{border-color:var(--sky);color:var(--text)}
.tbltab.on{background:rgba(79,184,231,.18);border-color:var(--sky);color:#fff}
/* Every pane is in the HTML; the script hides the inactive ones, so with the
   script blocked both tables read one after the other. */
.tblpane+.tblpane{margin-top:18px}
.js .tblpane{display:none}
.js .tblpane.on{display:block}

/* ===== section: table responsive — drop Source, then Year, then squeeze ===== */
@media (max-width:880px){
  .c-src{display:none!important}
  .trow0,.thead,.trowbtn{grid-template-columns:minmax(150px,1fr) 68px 22px 28px 22px 68px 36px 20px}
}
@media (max-width:640px){
  .c-yr{display:none!important}
  .trow0,.thead,.trowbtn{grid-template-columns:minmax(120px,1fr) 62px 21px 27px 21px 62px 18px}
  .tind{font-size:12.5px}
  .tval{font-size:11.5px}
}
@media (max-width:420px){
  .trow0,.thead,.trowbtn{grid-template-columns:minmax(96px,1fr) 54px 20px 25px 20px 54px 16px;
    gap:2px;padding:0 8px}
  .tind{font-size:12px}
  .tind .pv-smalldesc{font-size:10px}
  .tval{font-size:10.5px}
  .trow0 .t-cty{font-size:12.5px;gap:5px}
  .trow0 .t-title{font-size:12.5px}
}

/* ===== section: table row detail ===== */
/* Open in the markup; library.js adds .js-fold, which closes them. */
.tdetail{padding:15px 16px 18px;background:rgba(9,22,37,.55);
  border-top:1px dashed var(--line)}
/* THE LIBRARY'S OWN ROWS, AND ONLY THOSE. `.trow` and `.tdetail` are this
   stylesheet's names for the Library's fold, and this stylesheet is loaded on
   every page of every service -- so written as `.js .trow .tdetail` the rule
   reached UN Insights' rows as well. Those are a <details>, they never get
   the `.open` class this rule waits for, and at (0,3,0) nothing in un.css
   outranked it: every expandable row in that service turned its chevron,
   took `[open]`, and showed nothing at all, on every browser, whenever
   script was enabled.
 *
 * A <details> needs no rule here -- the browser hides and shows its own
 * content -- so the distinction is drawn where it really lies: the Library's
 * row is a <div> with a <button> and a class its script toggles. */
.js div.trow .tdetail{display:none}
.js div.trow.open .tdetail{display:block;animation:fadeUp .3s ease both}
@keyframes fadeUp{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
/* The publisher's own definition of the indicator, set in the reading serif
   because it is prose and can run to a paragraph. */
.method{font-family:'Source Serif 4',serif;font-size:14px;line-height:1.6;
  color:#CBDAE7;max-width:760px}
.method b{color:var(--text)}
/* Two one-liners of the same weight: the unit/topics of the measurement, and
   which end of the value range holds rank #1. */
.arrownote,.detmeta{margin-top:7px;font-size:11.5px;color:var(--text-soft)}
.arrownote b,.detmeta b{color:var(--sky);font-weight:600}
.worldctx{margin-top:9px;font-size:11px;color:var(--text-soft);max-width:760px}
.srcfull{margin-top:12px;font-size:11px;color:var(--text-soft);line-height:1.5}
.srcfull b{font-family:'IBM Plex Mono',monospace;color:var(--sky);font-weight:500}

/* ===== section: rank ruler ===== */
.ruler{margin-top:14px;max-width:760px}
/* Each end is a span holding "#1 Country" / "Country #193", so the rank number
   and its country name stay together when the two ends are pushed apart. */
.rends{display:flex;justify-content:space-between;font-size:11px;
  color:var(--text-soft);margin-bottom:7px;min-height:14px;gap:12px}
.rends>span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rends>span:last-child{text-align:right}
.rends b{font-family:'IBM Plex Mono',monospace;font-weight:500;color:var(--text)}
.rbody{position:relative}
.rtrack{position:relative;height:12px;border-radius:7px;
  background:linear-gradient(90deg,#4FB8E7,#2F6FB0 45%,#1B3A5E 80%,#122740)}
.rdot{position:absolute;top:50%;transform:translate(-50%,-50%);z-index:2}
.rdot .cflag{width:20px;height:20px;
  box-shadow:0 0 0 2px #0B1B2E,0 0 0 3px rgba(255,255,255,.35)}
.rlabels{position:relative;height:20px;margin-top:8px}
.rlab{position:absolute;top:0;font-size:11.5px;white-space:nowrap;color:var(--text);
  transform:translateX(-50%)}
.rlab b{font-family:'IBM Plex Mono',monospace;font-weight:600;color:var(--sky)}

/* ===== section: two narratives ===== */
.narratives{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.narr{background:var(--navy-card);border:1px solid var(--line);
  border-radius:var(--radius);padding:20px 22px;display:flex;flex-direction:column}
.narr h3{font-size:16px;font-weight:800;margin-bottom:10px;display:flex;
  align-items:center;gap:9px}
@media (max-width:840px){.narratives{grid-template-columns:1fr}}

/* ===== section: closing similarity chart ===== */
.closegrid{display:flex;gap:16px;flex-wrap:wrap}
/* Full width by request, rather than the reference's content-sized boxes. */
.cbox{border-radius:12px;overflow:hidden;border:1px solid var(--line);
  background:var(--navy-card);display:flex;flex-direction:column;flex:1 1 260px;
  min-width:0}
.cbox .cbh{padding:8px 13px;font-weight:700;font-size:13px;color:#fff}
.cbox.a .cbh{background:#1E3864}
.cbox.b .cbh{background:#1786B5}
.cbscale{display:flex;justify-content:space-between;padding:6px 13px 2px;
  font-size:9.5px;letter-spacing:.08em;color:var(--text-soft);text-transform:uppercase}
.cblist{position:relative;max-height:400px;overflow-y:auto;padding:6px 8px 8px}
.crow{display:grid;grid-template-columns:18px 1fr;gap:6px;align-items:center;
  padding:2.5px 1px}
.crow .cbar{position:relative;height:19px;border-radius:5px;
  background:rgba(255,255,255,.05);overflow:hidden}
.crow .cbar i{position:absolute;left:0;top:0;bottom:0;border-radius:5px;opacity:.32}
.cbox.a .cbar i{background:linear-gradient(90deg,#2F5D9E,#4FB8E7)}
.cbox.b .cbar i{background:linear-gradient(90deg,#0E6E96,#29ADE4)}
.crow .cname{position:absolute;left:7px;top:50%;transform:translateY(-50%);
  display:flex;gap:5px;align-items:baseline;font-size:10.5px;white-space:nowrap}
.crow .cname b{font-family:'IBM Plex Mono',monospace;font-weight:500;
  color:var(--text-soft);font-size:9.5px}
.crow .cpct{position:absolute;top:50%;transform:translate(-100%,-50%);
  font-family:'IBM Plex Mono',monospace;font-size:9.5px;color:var(--sky-soft);
  white-space:nowrap;background:rgba(9,22,37,.6);padding:1px 4px;border-radius:5px}
.crow.mark .cbar{box-shadow:inset 0 0 0 1.5px var(--sky)}
.crow.mark .cbar i{opacity:.6}
.crow.mark .cname{font-weight:800;color:#fff}
.crow.break{justify-items:center}
/* The break glyph is one flat dark shape on transparent, so it would vanish
   here. Drawn as a mask, not an <img>: the PNG's alpha gives the shape and
   the fill is the row's own colour. */
.cdots{display:inline-block;width:1.2rem;height:1.2rem;background:var(--text-soft);
  -webkit-mask:var(--dots) center / contain no-repeat;
          mask:var(--dots) center / contain no-repeat}
@media (max-width:640px){.closegrid{flex-direction:column;align-items:stretch}}

/* section: the similarity window's own control -- the portal's load-more
   button, which is `.tbltab` at full width: the pill UN Insights' and
   Foreign Missions' own "Show all (N)" already uses (ui.css's
   `.xmore .tbltab{width:100%;justify-content:center}`). This is one more
   instance of that control, so it REUSES the component rather than
   duplicating it -- `.tbltab` lives here in portal.css, not in ui.css, so
   the Library can carry it without loading the sheet that would re-claim
   .trow/.trowbtn/.tdetail from it (CLAUDE.md, *The shared components*).

   `display:flex` is set here because `.tbltab` gets its flex box from
   `.tbltabs` when it sits in a tab strip, and this one stands alone.

   The anchor deliberately does NOT carry `.linkbtn` any more: that class
   defaults to display:none outside .reader.folded/.narr.folded and did
   nothing else for this control but supply the trap that has shipped an
   invisible control three times in this codebase. */
.simmore{margin:10px 0 0}
.simmore .simfull{display:flex;width:100%;justify-content:center;
  align-items:center;text-decoration:none}
.simmore .simfull:hover,.simmore .simfull:focus-visible{text-decoration:none;
  border-color:var(--sky);color:var(--text);outline:none}

/* section: the Outlet Explorer's own two controls -- the filter's Filter
   button and the "Show 100 more" link. Same fault as .simfull above: bare
   .linkbtn defaults to display:none outside .reader.folded/.narr.folded,
   which neither <form class="cbsearch"> nor <p class="medfoot"> is, so each
   ancestor restates the display its own control needs. A two-class selector
   (0,0,2,0) beats the bare .linkbtn rule (0,0,1,0) regardless of source
   order, the same specificity argument .simmore .simfull already relies on. */
.cbsearch .linkbtn{display:inline-flex;flex:0 0 auto}
.medfoot .linkbtn{display:inline-flex}

/* ===== section: generic element cards =====
   The vocabulary every element the demo does not cover uses. One card idiom,
   so a timeline and an expert quote sit on the same ground as a reader. */
.pv-card{background:var(--navy-card);border:1px solid var(--line);
  border-radius:var(--radius);padding:18px 20px;margin-bottom:14px}
.pv-muted{font-size:11.5px;color:var(--text-soft);line-height:1.55}
.pv-note{background:var(--navy-panel);border:1px solid var(--line);
  border-radius:12px;padding:10px 14px;font-size:12.5px;color:var(--text-soft)}
.pv-tag{font-family:'IBM Plex Mono',monospace;font-size:10px;color:var(--sky);
  background:rgba(79,184,231,.13);border:1px solid rgba(79,184,231,.35);
  padding:2px 8px;border-radius:6px}
.pv-quote{font-family:'Source Serif 4',serif;font-style:italic;font-size:14.5px;
  line-height:1.65;color:#D5E2ED}
.pv-byline{font-size:12px;margin-top:8px}
.pv-byline strong{color:var(--text)}
.pv-scroll{overflow-x:auto}
.pv-smalldesc{font-size:.85em;color:var(--text-soft)}
.pv-cols{display:grid;gap:1.5rem;grid-template-columns:repeat(2,minmax(0,1fr))}
@media (max-width:48rem){.pv-cols{grid-template-columns:1fr}}

/* The plain ranked/grouped tables: the Library's treaties and members
   elements, and both UN Insights doors' tables (door 01's seats/memberships
   and officials, door 02's seats and co-service) — inout is no longer a
   table at all (it is .iotbl, a grid), and the rest of the "generic card"
   templates aren't tables either. */
.pv-t{width:100%;font-size:.8rem;border-collapse:collapse}
.pv-t td{padding:.1rem .3rem}
.pv-t td:not(:first-child){text-align:right;white-space:nowrap}
.pv-t tbody tr:nth-child(odd){background:var(--stripe)}
.pv-key{font-weight:600;color:var(--sky)}
/* members, and the UN Insights and Missions tables: the ordinal is the visual
   first column, but the description after it is prose, not a short
   right-aligned figure — override .pv-t's default assumption that later
   columns are numeric. (Treaties used these until it became the tabbed card
   list below; five templates still do.) */
.pv-t td.pv-t-idx{text-align:right;white-space:nowrap;vertical-align:top}
.pv-t td.pv-t-desc{text-align:left;white-space:normal}

/* ===== section: members — the organization explorer =====
   Ported from the prototype's 07-3 widget. The book prints three tables --
   both countries, then each alone. Here they are one corpus with three
   groupings and ONE search box over all of them, because the question a
   reader has is "are they both in X?", which is answered by finding X
   anywhere rather than inside a chosen grouping.

   The row's [data-nm][hidden] rule that makes filtering stick lives with the
   outlet explorer above; both use the one filter handler in library.js. */
.orgsearch{width:100%;max-width:420px;padding:10px 16px;border-radius:10px;
  border:1px solid var(--line);background:var(--navy-deep);color:var(--text);
  font:inherit;font-size:14px;margin-bottom:14px}
.orgsearch::placeholder{color:var(--text-soft)}
.orgsearch:focus{outline:none;border-color:var(--sky)}
.orggroup{font-size:11.5px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--sky);font-weight:700;margin:20px 0 9px}
.orggroup:first-of-type{margin-top:0}
.orglist{background:var(--navy-card);border:1px solid var(--line);
  border-radius:var(--radius);overflow:hidden}
.org-item{display:grid;grid-template-columns:34px 1fr;gap:10px;
  padding:11px 18px;border-top:1px solid rgba(255,255,255,.05)}
.org-item:nth-child(odd){background:var(--stripe)}
.org-item .no{font-family:'IBM Plex Mono',monospace;font-size:12px;
  color:var(--text-soft);text-align:right}
.org-item .nm{font-size:14px;font-weight:600}
.org-item .nm a{text-decoration:none;font-weight:800;color:var(--sky)}
.org-item .nm a:hover{text-decoration:underline}
.org-meta{display:flex;gap:6px;flex-wrap:wrap;margin-top:5px}
.org-meta span{font-family:'IBM Plex Mono',monospace;font-size:10px;
  color:var(--text-soft);background:rgba(255,255,255,.05);padding:2px 8px;
  border-radius:6px}
@media (max-width:1020px){
  .org-item{grid-template-columns:24px 1fr;padding:10px 12px}
}

/* ===== section: treaties — the tabbed card list =====
   Ported from the prototype's 07-2 widget. The book prints three tables in a
   row — each country's unreciprocated treaties, then the divergent set — and
   runs each treaty's actions into one paragraph. Here the three are panes of
   one tab group (markup in section.html.j2, driven by library.js's existing
   .tbltab/.tblpane handler) and each ACTION is its own chip.

   .tgroup is the table element's own category heading, reused here; inside a
   .trty card it loses the top border the table gives it.

   The prototype's --hr-ink/--se-ink are this stylesheet's --c1-ink/--c2-ink,
   and the chips are .act.c1/.act.c2 rather than .act.hr/.act.se so they follow
   the pair rather than two fixed countries. */
.trtyhead{font-size:12.5px;font-weight:700;color:var(--text-soft);
  margin:0 0 9px;letter-spacing:.02em}
.trty{background:var(--navy-card);border:1px solid var(--line);
  border-radius:var(--radius);overflow:hidden}
.trty .tgroup{border-top:none}
.trty-item{display:grid;grid-template-columns:34px 1fr;gap:10px;
  padding:13px 18px;border-top:1px solid rgba(255,255,255,.05)}
.trty-item:nth-child(odd){background:var(--stripe)}
.trty-item .no{font-family:'IBM Plex Mono',monospace;font-size:12px;
  color:var(--text-soft);text-align:right;padding-top:2px}
.trty-item .nm{font-size:14px;font-weight:600;line-height:1.45}
.trty-item .code{font-family:'IBM Plex Mono',monospace;font-size:10.5px;
  color:var(--sky);background:rgba(79,184,231,.1);
  border:1px solid rgba(79,184,231,.3);padding:1px 7px;border-radius:6px;
  margin-left:8px;white-space:nowrap}
.trty-acts{display:flex;gap:6px;flex-wrap:wrap;margin-top:7px}
.act{display:inline-flex;align-items:center;gap:5px;font-size:11px;
  padding:3px 9px;border-radius:999px;border:1px solid;font-weight:600}
.act.c1{color:var(--c1-ink);border-color:rgba(127,163,221,.4);
  background:rgba(127,163,221,.08)}
.act.c2{color:var(--c2-ink);border-color:rgba(41,173,228,.4);
  background:rgba(41,173,228,.08)}
.untc{display:inline-flex;align-items:center;gap:6px;margin-top:9px;
  font-size:12px;font-weight:700;color:var(--sky);text-decoration:none;
  border:1px solid rgba(79,184,231,.4);padding:5px 12px;border-radius:8px}
.untc:hover{background:rgba(79,184,231,.14)}
/* The card is already narrow at 34px + prose; on a phone the ordinal column
   costs more than it says. */
@media (max-width:1020px){
  .trty-item{grid-template-columns:24px 1fr;padding:11px 12px}
}

/* .pv-fig: img-fluid/d-block/mx-auto's replacement — a centred, capped figure
   image, used by knowledge, cuisine and dipfootprint. Leadership's portrait
   is .pv-lead-img instead: it floats rather than centres. */
.pv-fig{display:block;margin:0 auto;max-width:100%}

/* leadership: portrait floated at the top-left of a bio that wraps around
   it — was Bootstrap's clearfix + float-start. */
.pv-lead-country{color:var(--text-soft)}
.pv-lead{overflow:hidden;margin-bottom:14px}
.pv-lead-img{float:left;width:30%;border-radius:8px;margin:0 10px 6px 0}

/* ===== section: timeline =====
   A card on the same ground as the table: a header naming the two sides, a
   chip row, and the timeline itself scrolling inside a fixed-height box rather
   than running the length of the page (a leadership pair is ~130 entries over
   as many centuries).

   .tlbox scrolls on both axes: the grid keeps a min-width because the book
   gives the timeline a whole page and much under 34rem every second name
   wraps, so on a narrow viewport this box takes over rather than the page. */
.tlwrap{background:var(--navy-card);border:1px solid var(--line);
  border-radius:var(--radius);overflow:hidden}
.tlhead,.tlgrid{display:grid;grid-template-columns:1fr 60px 1fr}
.tlhead{padding:10px 18px;background:var(--navy-deep)}
.tlhead div{font-weight:800;font-size:14px}
.tlhead div:first-child{text-align:right;color:var(--c1-ink)}
.tlhead div:last-child{color:var(--c2-ink)}
.tlchips{display:flex;gap:8px;padding:10px 18px;flex-wrap:wrap;
  align-items:center;border-bottom:1px solid var(--line)}
.tlchip{padding:5px 13px;border-radius:999px;border:1px solid var(--line);
  font-size:12.5px;font-weight:700;color:var(--text-soft);text-decoration:none;
  transition:border-color .2s,color .2s,background .2s}
.tlchip:hover,.tlchip:focus-visible{border-color:var(--sky);color:#fff;
  background:rgba(79,184,231,.14)}
/* The caption the book prints under the figure. Pushed to the far end of the
   chip row so it reads as the card's subtitle without taking its own line. */
.tlcap{margin-left:auto;font-size:11px;color:var(--text-soft)}
.tlbox{max-height:560px;overflow:auto;padding:14px 18px;position:relative}
.tlgrid{row-gap:3px;min-width:34rem}
/* One element spanning every slot. Empty slots collapse to nothing and leave
   only their row gap, so a century with no entries reads as a quiet stretch of
   axis — the sparseness of `rbr` becomes the timeline's sense of scale. */
.tlaxis{grid-column:2;justify-self:center;width:2px;
  background:linear-gradient(180deg,rgba(79,184,231,.5),rgba(79,184,231,.12))}
.tle{font-size:12.5px;line-height:1.45;padding:1px 0;scroll-margin-top:40px}
.tle.l{grid-column:1;text-align:right;padding-right:14px}
.tle.r{grid-column:3;padding-left:14px}
.tle .yy{font-family:'IBM Plex Mono',monospace;color:var(--sky);font-size:11.5px;
  white-space:nowrap}
/* type=2: an era or event, not a person — the book sets it all bold. */
.tle.ev{font-weight:800;color:#fff}
.tle a{color:var(--text);text-decoration:none;
  border-bottom:1px dotted rgba(79,184,231,.55)}
.tle a:hover,.tle a:focus-visible{color:var(--sky)}
.wikinote{font-size:11.5px;color:var(--text-soft);padding:9px 18px;
  border-top:1px solid var(--line)}
/* On a phone the card takes the horizontal scroll over rather than the page,
   which is the wrong way round for the one element whose whole point is that
   the two countries are read side by side: the reader had to scroll right to
   see the second country and back again for the first, one entry at a time.

   The mirrored shape stays at every width. What goes is `.tlgrid`'s 34rem
   floor -- the single rule forcing the scrollbar -- so the two columns
   squeeze and their entries WRAP inside them instead. The centre axis column
   drops from 60px to 22px and every horizontal padding is cut, because at
   this width each pixel spent on gutters is a pixel a name cannot have; the
   row gap grows a little in exchange, since a wrapped three-line entry needs
   more than 3px to read as one entry rather than two. `overflow-wrap` is the
   guard on a column this narrow: a single token longer than the column would
   otherwise reintroduce the overflow this whole block removes.

   `.tlbox` keeps `overflow:auto` and so keeps scrolling VERTICALLY, which is
   what holds a ~130-entry leadership timeline inside its own card. */
@media (max-width:640px){
  .tlhead,.tlgrid{grid-template-columns:1fr 22px 1fr}
  .tlgrid{min-width:0;row-gap:7px}
  .tlhead,.tlchips{padding-left:10px;padding-right:10px}
  .tlbox{padding:12px 10px}
  .tle{overflow-wrap:anywhere}
  .tle.l{padding-right:7px}
  .tle.r{padding-left:7px}
  .wikinote{padding-left:10px;padding-right:10px}
}

/* ===== section: inout — the ranking whose rows open their composition =====
   Ported from the prototype's 08-1/2/3 widget, and it replaced a two-column
   grid: the book gives this a whole two-column page, a ranking on the left and
   a breakout of its top few rows on the right, joined by TikZ arrows. Here the
   right hand panel is gone — each composition opens under its own row — which
   is what lets the table run full width.

   The rows reuse .trow/.trowbtn/.tdetail, so library.js's existing row toggle
   drives them; only the grid and the composition's own rows are new here.
   The 4th column is the chevron's, and it is present on every row so the three
   data columns line up whether or not a row expands. */
.iotbl{background:var(--navy-card);border:1px solid var(--line);
  border-radius:var(--radius);overflow:hidden}
.iohead,.iorow{display:grid;grid-template-columns:1fr 110px 70px 20px;gap:8px}
.iohead{padding:10px 16px;background:var(--navy-deep);font-size:11px;
  text-transform:uppercase;letter-spacing:.08em;color:var(--text-soft);
  font-weight:700}
.iohead span:not(:first-child){text-align:right}
/* Forty rows per tab, two tabs, three sections: the list is capped and
   scrolls inside the card rather than running down the page. The header sits
   outside it so the column headings stay put. */
.ioscroll{max-height:520px;overflow-y:auto;scrollbar-width:thin}
.iorow{width:100%;text-align:left;padding:7px 16px;background:none;border:0;
  color:var(--text);font:inherit;font-size:13px;align-items:center}
.iorow:not(.noexpand){cursor:pointer}
.iorow:not(.noexpand):hover{background:rgba(79,184,231,.09)}
.iorow .co{font-weight:600;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.iorow span:not(.co){font-family:'IBM Plex Mono',monospace;font-size:12px;
  text-align:right;color:var(--text-soft)}
.trow.iorow-wrap:nth-child(odd) .iorow{background:var(--stripe)}
/* The rows that have a composition: the book sets them bold and in the
   country's colour and hangs the arrows off them. The arrow is kept as a
   pseudo-element rather than markup — it is decoration, not content. */
.trow.iorow-wrap.key .co{color:var(--sky);font-weight:800}
.trow.iorow-wrap.key .co::after{content:" \2190";opacity:.7}
.trow.iorow-wrap.open>.iorow{background:rgba(79,184,231,.16);
  box-shadow:inset 2px 0 0 var(--sky)}
.trow.iorow-wrap .tchev{font-size:11px;color:var(--sky);text-align:center;
  transition:transform .25s}
.trow.iorow-wrap.open .tchev{transform:rotate(180deg)}
/* The composition itself, inside the row's own .tdetail. */
.iogh{font-weight:800;font-size:15px;margin-bottom:4px}
.iogh .ioarrow{opacity:.7;color:var(--sky)}
/* The composition as one bar before it is a list: the shape of it -- one
   dominant partner, or a long tail -- reads before any row does. Segment
   widths are the entries' own percentages, so the bar IS the data. The
   hues are set inline, one step down the ramp per rank, because they are
   per-row values and not a fixed palette. */
.iostack{display:flex;height:14px;border-radius:7px;overflow:hidden;
  margin-bottom:14px;background:rgba(255,255,255,.05)}
.iostack i{display:block;height:100%}
.iostack .iostack-other{background:rgba(255,255,255,.12)}
/* A grid, not a flex row: three columns are what line the percentages up
   down the list instead of leaving them to float after names of varying
   length. */
.iogrow{display:grid;grid-template-columns:22px 1fr auto;gap:8px;
  align-items:center;padding:5px 4px;font-size:13px;
  border-top:1px solid rgba(255,255,255,.05)}
.iogrow .iopos{font-family:'IBM Plex Mono',monospace;font-size:11px;
  color:var(--text-soft);text-align:right}
.iogrow .ioname{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  display:flex;align-items:center;gap:7px}
.iogrow .ioname.x{color:var(--sky);font-weight:800}
.iogrow .iocty{color:var(--text-soft);font-size:11px}
/* Mono so the figures line up down the column, as in the indicator table and
   the outlet explorer. Was Bootstrap's ms-auto, then .pv-io-p. */
.iogrow .iop{font-family:'IBM Plex Mono',monospace;font-size:12px;
  white-space:nowrap}
.iogrow.other{font-style:italic;color:var(--text-soft)}
/* The detail of a row the book did not break out: its own two figures, then
   the note. Both had markup and no rules, which rendered them as default
   browser paragraphs — unstyled text running the full width beside the
   styled compositions of the five rows that do have one. */
.iosub{font-size:12px;color:var(--text-soft);margin-bottom:12px}
/* No max-width: .tdetail is already bounded by the table, and narrowing the
   note to a reading column inside it read as a mistake rather than a measure. */
.ionote{font-family:'Source Serif 4',serif;font-size:14px;
  color:var(--text-soft);line-height:1.6;padding:8px 0;margin:0}
/* The line that closes a composition, as against the one that stands in for
   a missing one: it follows a list rather than a heading. */
.ioclose{margin-top:10px}
@media (max-width:1020px){
  .iohead,.iorow{grid-template-columns:1fr 72px 54px 18px;padding-left:12px;
    padding-right:12px}
  /* The columns are now 72px and 54px, and a tracked uppercase heading no
     longer fits one: "Experience" measures 77px at .08em on 08-1 and hangs
     into the gap. Easing the tracking recovers the 9px without breaking the
     word or ellipsing a heading. */
  .iohead{letter-spacing:.02em}
  .iohead span{min-width:0}
}

/* ===== section: media — the Outlet Explorer =====
   Ported from the prototype's 09-3 widget. It replaced the book's 4-column
   striped block, which printed the top 80 of 92 outlets as plain text; this
   shows every one, as a ranked bar list with a filter over it.

   Colour follows the OUTLETS' country, not the covered one — see the note in
   el/media.html.j2. The prototype hard-codes #1E3864/#1786B5 for the two
   headers and two gradients beneath them; those are this stylesheet's own
   --sim-c1 / --c2-ink / --sky, so they are written as tokens here.

   The list is capped and scrolls rather than running to 92 rows down the
   page: the filter is the way through a long list, not the scrollbar. */
.medgrid{display:grid;grid-template-columns:1fr 1fr;gap:16px;align-items:start}
.medbox{background:var(--navy-card);border:1px solid var(--line);
  border-radius:var(--radius);overflow:hidden}
.medbox .cbh{padding:8px 14px;font-weight:700;font-size:13.5px;color:#fff}
.medbox.c1 .cbh{background:#1E3864}
.medbox.c2 .cbh{background:#1786B5}
.medbox .cbsearch{padding:8px 12px}
.medbox input{width:100%;padding:7px 12px;border-radius:8px;
  border:1px solid var(--line);background:var(--navy-deep);color:var(--text);
  font:inherit;font-size:12.5px}
.medlist{max-height:380px;overflow-y:auto;padding:4px 10px 10px;
  scrollbar-width:thin}
.medrow{display:grid;grid-template-columns:1fr;padding:2.5px 2px}
/* The filter hides a row with `row.hidden = true`, and the line above is what
   would stop that working: the UA stylesheet's [hidden]{display:none} is
   user-agent origin, so ANY author rule setting display on the same element
   beats it -- specificity never enters into it. Without this override the
   attribute is set and the row stays on screen. bar.css relies on the same
   fact in the other direction, keeping a [hidden] drawer displayed.

   Written against [data-nm] rather than .medrow so it covers everything the
   one filter handler in library.js can hide -- 09#3's outlets and 07#3's
   organizations both, and whatever comes next. */
[data-nm][hidden]{display:none}
.medrow .cbar{position:relative;height:20px;border-radius:5px;
  background:rgba(255,255,255,.05);overflow:hidden}
.medrow .cbar i{position:absolute;left:0;top:0;bottom:0;border-radius:5px;
  opacity:.3}
.medbox.c1 .cbar i{background:linear-gradient(90deg,var(--sim-c1),var(--sky))}
.medbox.c2 .cbar i{background:linear-gradient(90deg,#0E6E96,var(--c2-ink))}
.medrow .clab{position:absolute;top:50%;transform:translateY(-50%);
  display:flex;gap:8px;align-items:baseline;font-size:11.5px;
  white-space:nowrap;padding-left:8px}
.medrow .clab a{color:var(--text);text-decoration:none;font-weight:600}
.medrow .clab a:hover{color:var(--sky);text-decoration:underline}
.medrow .clab em{font-style:normal;font-family:'IBM Plex Mono',monospace;
  font-size:10.5px;color:var(--sky-soft)}
/* Two boxes side by side do not fit a phone. Same breakpoint the rest of the
   section layout uses. */
@media (max-width:1020px){
  .medgrid{grid-template-columns:1fr}
}

/* ===== portal shell =====
   The rules above this point predate the portal shell -- they came from the
   Library (formerly preview) stylesheet, which portal.css started life as a
   copy of. These rules are the shell's own: the pair label, the ten-service
   tile grid and its two states, and the footer stamp. The .tile class name
   collides with the Library's chapter flip-tile above (square, 3D
   perspective, hover flip) -- these service tiles are a plain list, not a
   flip card, so the first three declarations undo the
   perspective/aspect-ratio/cursor this class inherits from that earlier
   rule. Minimal by decision: this is the shell's skeleton, not a visual
   design pass -- unlike the Library, which got one (see
   docs/portal-design-drift.md). */
.pair{font-size:12.5px;color:var(--text-soft)}

@media(min-width:900px){.tiles{grid-template-columns:repeat(5,1fr)}}

.sourceline{max-width:1220px;margin:0 auto;padding:16px 20px 40px;font-size:12px;
  color:var(--text-soft);border-top:1px solid var(--line)}

/* ======================================================================
   THE CARD MENU (portal/home.html.j2)

   Ported from the prototype's _live/site/index.html. Two numbers here are
   deliberately NOT the ones .wrap/.subwrap use: a card menu is 1260px wide
   against the 1220px of a Library page, and its top padding is 26px against
   28px. The prototype sets both explicitly, so they are an opinion, not drift.
   ====================================================================== */
.menuwrap{max-width:1260px;margin:0 auto;padding:26px 20px 80px}

.tgrid{display:grid;grid-template-columns:repeat(2,1fr);gap:13px}
@media(min-width:900px){.tgrid{grid-template-columns:repeat(5,1fr);gap:16px}}

/* A tile is square and the photograph fills it. `overflow:hidden` is what
   keeps the image inside the 14px radius. */
.mtile{position:relative;aspect-ratio:1/1;border-radius:var(--radius);
  overflow:hidden;border:1px solid var(--line);display:block;min-width:0;
  transition:transform .18s,border-color .18s,box-shadow .18s}
a.mtile:hover,a.mtile:focus-visible{transform:translateY(-3px);
  border-color:rgba(79,184,231,.55);box-shadow:0 14px 30px rgba(4,12,22,.55);
  outline:none}
.mtile picture,.mtile img{display:block;width:100%;height:100%;object-fit:cover}
/* The scrim. Without it the title is unreadable over a light photograph. */
.mtile::after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(9,22,37,.05),rgba(9,22,37,.44) 50%,rgba(9,22,37,.95))}

/* The menu title standard: a bare number left of a two-line title, a hairline
   between them, nothing else on the photograph. */
.mtile .lab{position:absolute;left:12px;right:12px;bottom:10px;z-index:2;
  display:flex;align-items:center;gap:9px}
.mtile .n{font-family:'IBM Plex Mono',monospace;font-size:15px;font-weight:600;
  color:var(--sky-soft);line-height:1;flex:0 0 auto;
  font-variant-numeric:tabular-nums;min-width:2ch;text-align:right}
.mtile .vr{flex:0 0 auto;width:1px;align-self:stretch;background:var(--sky-soft);
  opacity:.5}
/* Colour set explicitly: an open tile is an <a>, and the global a{color:--sky}
   would otherwise tint the title blue. The standard says the title is white. */
.mtile .cn{font-size:clamp(12.5px,1.35vw,16.5px);font-weight:800;line-height:1.15;
  min-width:0;color:var(--text);text-shadow:0 2px 12px rgba(0,0,0,.7)}
.mtile .cn w{display:block}

/* An announced service: the photograph drains of colour and the title greys.
   Desaturating rather than hiding keeps the shape of the finished platform
   visible from the first screen. */
.mtile.off{cursor:default;filter:saturate(.3)}
.mtile.off .cn{color:var(--text-soft)}
.mtile.off::after{background:linear-gradient(180deg,rgba(9,22,37,.5),
  rgba(9,22,37,.8) 45%,rgba(9,22,37,.97))}

/* ===== service 02: UN Insights =====
   The service's components live in portal/uninsights/static/uninsights/un.css,
   loaded by its own pages alone. Only the CSS-only filters stay portal-side --
   no: they moved too. Nothing of service 02 is left here, which is the point:
   .chip and .fig are names generic enough that a shared stylesheet should not
   claim them. */

/* ===== library: the chapter strip at the foot of a section page =====
   The Library's answer to `ui.doorstrip`. It is deliberately NOT that
   component: every other service is one level deep, so ten tiles are its
   whole navigation, and the book is two, so this strip is the ten chapters
   AND the sections of the one the reader is in.

   The tile rules below duplicate ui.css's `.door` rules on purpose. The
   Library cannot load ui.css: that sheet re-claims `.trow`/`.trowbtn`/
   `.tdetail`, which portal.css already holds for the Library's own folds,
   and a shared stylesheet that hides a row component it does not own is the
   exact fault that cost all ten UN Insights doors their row expansion. The
   standing cleanup this repository already names -- getting the Library's
   component CSS out of portal.css so it can load ui.css like any other
   service -- is what would let these two become one component; until then,
   duplicated-and-said-so beats a collision. */
.chapstrip{margin-top:34px;padding-top:6px;border-top:1px solid var(--line)}
.chappath{display:flex;align-items:center;gap:5px;flex-wrap:wrap;
  font-size:12px;margin:0 0 4px}
.chappath a{color:var(--text-soft);text-decoration:none;
  border-bottom:1px solid transparent}
.chappath a:hover{color:var(--sky);border-bottom-color:var(--sky)}
.chappath a:focus-visible{outline:2px solid var(--sky);outline-offset:2px;
  border-radius:3px}
.chappath i{font-style:normal;color:var(--text-soft);opacity:.55}

.chaps{display:grid;--chap-gap:10px;
  grid-template-columns:repeat(10, minmax(0, 1fr));
  gap:var(--chap-gap);padding:2px 0 10px;margin-top:10px}
.chap{text-decoration:none;color:var(--text-soft);display:flex;
  flex-direction:column;gap:5px;min-width:0}
.chap:hover{text-decoration:none}
.chap-pic{position:relative;display:block;aspect-ratio:1/1;
  border-radius:var(--radius);overflow:hidden;border:1px solid var(--line);
  background:var(--navy-panel)}
.chap-pic img{width:100%;height:100%;object-fit:cover;display:block;
  /* the chapters you are not in sit back, so the one you are in reads
     without being loud */
  filter:saturate(.55) brightness(.62);
  transition:filter .18s ease,transform .18s ease}
/* No number on the tile: the cover and the title are what a reader
   navigates by, and the chapter number is already in the breadcrumb and in
   every section link below. */
.chap-nm{font-size:10.5px;line-height:1.25;text-align:center;
  overflow-wrap:break-word;display:-webkit-box;-webkit-line-clamp:2;
  -webkit-box-orient:vertical;overflow:hidden}
.chap:hover .chap-pic img,.chap:focus-visible .chap-pic img{
  filter:saturate(.9) brightness(.85);transform:scale(1.04)}
.chap:hover .chap-nm{color:var(--text)}
/* WHERE YOU ARE: brighter, and framed in light blue. Two signals rather than
   one, because colour alone is not enough for a reader who cannot separate
   these hues. */
.chap.here .chap-pic{border-color:var(--sky);
  box-shadow:0 0 0 2px var(--sky) inset,0 0 0 1px var(--sky)}
.chap.here .chap-pic img{filter:saturate(1) brightness(1)}
.chap.here .chap-nm{color:var(--sky);font-weight:600}
/* a chapter with no section to open is not a link, and reads as unavailable
   rather than as one you failed to click */
.chap.off{cursor:default}
.chap.off .chap-pic img{filter:saturate(.2) brightness(.42)}

/* The second level. Text rows, not tiles: these are four titles a reader
   compares by reading, where the ten above are compared by picture. */
.chapsecs{display:grid;gap:7px;grid-template-columns:1fr;margin-top:10px}
@media(min-width:640px){.chapsecs{grid-template-columns:repeat(2,1fr)}}
@media(min-width:1000px){.chapsecs{grid-template-columns:repeat(4,1fr)}}
.chapsec{display:flex;align-items:center;gap:9px;padding:8px 11px;
  border:1px solid var(--line);border-radius:var(--radius);min-width:0;
  text-decoration:none;color:var(--text);font-size:13px;
  transition:border-color .18s ease,background .18s ease}
.chapsec:hover,.chapsec:focus-visible{text-decoration:none;
  border-color:rgba(79,184,231,.5);background:rgba(79,184,231,.08);
  outline:none}
.chapsec-n{font-family:'IBM Plex Mono',monospace;font-size:11.5px;
  color:var(--sky);flex:0 0 auto}
.chapsec-t{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.chapsec.here{border-color:rgba(79,184,231,.6);
  background:rgba(79,184,231,.13);font-weight:600}

/* TWO ROWS OF FIVE below 900px, which is where ten columns stop leaving room
   for a readable two-line title. */
@media (max-width:900px){.chaps{grid-template-columns:repeat(5, minmax(0, 1fr))}}
@media (max-width:420px){.chaps{--chap-gap:7px}.chap-nm{font-size:9.5px}}

@media print{.chapstrip{display:none!important}}

/* section: the organization list's cap. Gated on html.js, like every other
   fold here: with the script blocked nothing is hidden. */
.js .org-item.over-cap{display:none}
.orgcap{margin:8px 0 0}
/* The cap button carries .linkbtn too, whose own bare rule (line 185-187)
   defaults to display:none outside .reader.folded/.narr.folded -- the same
   fault .simmore .simfull / .cbsearch .linkbtn / .medfoot .linkbtn above
   already override, and #orgscope is none of those three either. Without
   this the button ships invisible regardless of what library.js does to
   it -- the third time this exact defect has appeared on this branch (Task
   1 caught it in its own control, Task 4 shipped it and review caught it).
   The button also ships with the `hidden` attribute, cleared by library.js
   only once draw() has counted more rows than the cap -- an author
   `display` rule beats the UA stylesheet's own [hidden]{display:none}
   outright, the same fact [data-nm][hidden] above restores in the other
   direction, so this rule folds :not([hidden]) into itself rather than
   trusting a second, order-dependent rule to win: a still-`hidden` button
   (script blocked, or ten rows or fewer) stays hidden either way. */
.orgcap.linkbtn:not([hidden]){display:inline-flex}

/* The portal's two-way switch, as the business pages use it (08#1 to 08#3).
   Copied from ui.css rather than loaded from it: ui.css re-claims .trow,
   .trowbtn and .tdetail, and the Library's own row folds answer to those
   names. Anchors, not radios, because each choice is a URL the server
   answers -- it works with no script and can be sent to somebody. */
.segset.iosw{display:block;margin:0 0 10px}
.iosw-label{margin-bottom:6px}
.segset.iosw .seg{display:inline-flex;flex-wrap:wrap;gap:0;
  border:1px solid var(--line);border-radius:10px;overflow:hidden;
  background:var(--navy-deep)}
.segset.iosw .seg a{display:inline-flex;align-items:center;gap:6px;
  padding:9px 13px;color:var(--text-soft);font-size:12.5px;font-weight:700;
  min-height:38px;text-decoration:none}
.segset.iosw .seg a+a{border-left:1px solid var(--line)}
.segset.iosw .seg a:hover{background:rgba(79,184,231,.1);color:var(--text);
  text-decoration:none}
.segset.iosw .seg a.on{background:rgba(79,184,231,.2);color:#fff}
.segset.iosw .seg a:focus-visible{outline:2px solid var(--sky);
  outline-offset:-2px}
.segset.iosw .seg .cflag{width:16px;height:16px}
@media(max-width:520px){
  .segset.iosw .seg{width:100%}
  .segset.iosw .seg a{flex:1 1 0;justify-content:center;padding:9px 8px;
    font-size:11.5px}
}

/* The second kind of ranking: a list ranked INSIDE each country rather than
   the countries ranked against each other. Two tracks, one per country, each
   scaled to that country's own list -- see library/_inddetail.html.j2 and
   region.PERSPECTIVE_TABLES. The prototype's own classes and measurements,
   so the two read identically. */
.dualrank{margin-top:12px;max-width:620px}
.dr-cap{font-size:11px;color:var(--text-soft);margin-bottom:9px}
.dr-cap b{font-family:'IBM Plex Mono',monospace;color:var(--sky)}
.dr-row{display:grid;grid-template-columns:96px 1fr 40px;gap:10px;
  align-items:center;margin:7px 0}
.dr-lab{display:flex;align-items:center;gap:6px;font-size:12px;
  font-weight:600;white-space:nowrap}
.dr-track{position:relative;height:12px;border-radius:7px;
  background:linear-gradient(90deg,#4FB8E7,#2F6FB0 45%,#1B3A5E 80%,#122740)}
.dr-dot{position:absolute;top:50%;transform:translate(-50%,-50%)}
.dr-dot .cflag{width:18px;height:18px;
  box-shadow:0 0 0 2px #0B1B2E,0 0 0 3px rgba(255,255,255,.35)}
.dr-dot .cflag.dr-neu{background:var(--sky)}
.dr-rank{font-family:'IBM Plex Mono',monospace;font-weight:600;
  color:var(--sky);font-size:12px;text-align:right}
.dr-none{grid-column:2/4;font-size:11px;color:var(--text-soft);
  font-style:italic}
@media(max-width:520px){
  .dr-row{grid-template-columns:78px 1fr 34px;gap:7px}
  .dr-lab{font-size:11px}
}

/* A business row with no composition is not a button: only the five the book
   breaks out open, and the rest carry a link to the company instead. It still
   has to look like a row -- same columns, same height -- so it inherits
   .iorow and only makes good the padding a <button> brought with it. */
/* Geometry is .iorow's own -- overriding the padding here is what pulled the
   columns out of line the first time. Only the button's affordances go. */
.iorow-flat{cursor:default}
.iorow-flat:hover{background:none}
.iorow-flat .co a{color:var(--text);text-decoration:none;
  border-bottom:1px solid rgba(79,184,231,.35)}
.iorow-flat .co a:hover{color:#fff;border-bottom-color:var(--sky)}
.iorow-flat .co a:focus-visible{outline:2px solid var(--sky);outline-offset:2px}
/* Inside a composition the company names link too, where a tap on the row
   itself already means "open this". */
.ioname a{color:inherit;text-decoration:none;
  border-bottom:1px solid rgba(79,184,231,.3)}
.ioname a:hover{color:#fff;border-bottom-color:var(--sky)}

/* ON A PHONE ONLY, the closing lists are as wide as their own longest line
   rather than as wide as the column: a full-width list swallows the drag that
   was meant to scroll the page, and the bare strip beside it is where a thumb
   takes hold. library.js sets --cboxw from the rows actually rendered; 300px
   is the prototype's own fallback for a page whose script has not run.

   NOT ON A WIDE SCREEN, where the opposite was asked for and still holds: a
   fixed max-width there leaves dead space beside two lists that could have
   used it. Both requests are about the same boxes and neither is wrong; they
   are about different widths. 640px is the prototype's own breakpoint. */
@media (max-width:640px){
  .closegrid .cbox{max-width:var(--cboxw,300px)}
}

/* ===== section: 05#2's clusters and sophistication table ===== */
/* THE CLUSTERS TABLE IS THREE COLUMNS, NOT NINE. Everything else about these
   rows -- the hairline, the stripe, the hover, the chevron, the fold -- is
   the Library's own and is inherited rather than restated. The override is
   scoped to `.clusters` so no other table on any other section moves. */
.clusters .clpct{font-family:'IBM Plex Mono',monospace;font-size:12.5px;
  color:var(--sky);text-align:center}
.clusters .clmt{color:var(--text-soft)}
/* Dimmed, not hidden: the cluster is still compared -- both countries record
   skills in it -- but only one of them draws it among its own twelve, and a
   reader has to be able to see which rows those are. */
.clusters .clmt.dim{opacity:.55;font-style:italic}
.clusters .t-cty{font-size:11px}

.cldetail,.skdetail{padding:10px 12px 14px}
.clnote,.skmethod{font-size:13px;line-height:1.55;color:var(--text-soft);
  margin:0 0 10px;max-width:70ch}
.clnote b{color:var(--text)}
.clranks,.skranks{display:flex;gap:14px;flex-wrap:wrap;align-items:center;
  font-size:12px;color:var(--text-soft);margin-bottom:10px}
.clrank,.skrank{display:inline-flex;align-items:center;gap:5px;
  font-family:'IBM Plex Mono',monospace;color:var(--text)}
.clends,.skends{color:var(--text-soft)}
.clcols{display:grid;grid-template-columns:repeat(3,1fr);gap:14px}
@media(max-width:760px){.clcols{grid-template-columns:1fr}}
.clcol h4{font-size:11px;letter-spacing:.09em;text-transform:uppercase;
  color:var(--sky);margin:0 0 5px;font-weight:700}
.clcol.mid h4{color:var(--sky-soft)}
.clcol ul{margin:0;padding-left:16px;font-size:13px;line-height:1.55}
.clcol li{margin:2px 0}

/* The group heading inside the sophistication table -- "The record", then
   "World standing". `.trow0` is already the Library's heading row; this only
   stops it repeating the country columns. */
.skgroup .t-title{color:var(--sky-soft);font-size:11.5px;letter-spacing:.14em;
  text-transform:uppercase}
.tsmall{color:var(--text-soft);font-size:11.5px}

/* ----- 05#2 on a phone, measured against the demo at 412px ------------ */
/* A 1fr column with a 120px floor cannot shrink, so the second country's
   name ran off a 412px screen. These may shrink; the text wraps instead. */
/* The cluster this side draws is the row's subject, so it carries the weight;
   its counterpart is reference and does not. */
.clusters .trowbtn .tind{font-weight:700;color:var(--text);white-space:normal;
  line-height:1.3}
.clusters .trowbtn .clmt{font-weight:400;color:var(--text-soft);
  text-align:right;white-space:normal;line-height:1.3}
.clusters .clpct{text-align:center}
.clusters .t-title,.clusters .t-cty{font-size:10.5px;letter-spacing:.1em;
  text-transform:uppercase;white-space:normal}
.clusters .t-cty.c2{text-align:right}

/* The sophistication table: the description belongs under the name, not
   beside it. */
.skilltbl-ind{display:block}
.tsmall{display:block;font-size:11px;color:var(--text-soft);
  letter-spacing:.02em;margin-top:1px;font-weight:400}
/* A heading row is a heading, not a first column: without this the nine
   column grid folded "World standing, per person recorded" into the 1fr
   column and broke it over four lines. */
.tscroll .trow0.skgroup{grid-template-columns:1fr;padding-top:12px;
  padding-bottom:6px}
.tscroll .trow0.skgroup .t-title{color:var(--sky);font-size:11px;
  letter-spacing:.14em;text-transform:uppercase;white-space:normal}

@media (max-width:640px){
  /* Below this the three columns stop being three: the two names need the
     width more than the chevron does. */
  .clusters .trow0,
  .clusters .trowbtn{grid-template-columns:minmax(0,1fr) 46px minmax(0,1fr) 12px;
    gap:6px;padding:9px 10px}
  .clusters .trowbtn .tind,
  .clusters .trowbtn .clmt{font-size:13.5px}
  .clusters .clpct{font-size:12px}
  .clcols{grid-template-columns:1fr}
}

/* ----- 05#2: the last three, measured off the demo ------------------- */
/* 16px, which is the demo's own: these rows are words, and the Library's
   13.5px is the size it uses for a row of numbers. */
.clusters .trowbtn .tind,
.clusters .trowbtn .clmt{font-size:15px}
.clusters .clpct{font-size:13px}
/* Dimmer, not italic. The right-hand name is the other half of a comparison,
   not a caption on the left-hand one. */
.clusters .trowbtn .clmt.dim{opacity:1;font-style:normal;color:var(--text-soft)}
.clusters .trowbtn .clmt{color:var(--text)}
.clusters .trowbtn .clmt.dim{color:var(--text-soft)}
/* On its own line, middle of the column, and big enough to read as the
   control that changes whose table this is. */

@media (max-width:640px){
  .clusters .trowbtn .tind,
  .clusters .trowbtn .clmt{font-size:14.5px}
  .clusters .clpct{font-size:12.5px}
}

/* ----- 05#2's clusters: the demo's own header, toggle and chips ------- */
/* Read from the demo's stylesheet, not approximated. `gap` is what keeps the
   flag off the country's name, and the two justify rules are what centre the
   match column and right-align the second country. */
.clusters .dhead2{display:grid;
  grid-template-columns:minmax(0,1fr) 58px minmax(0,1fr) 16px;
  gap:8px;background:var(--navy-deep);
  border-bottom:1px solid rgba(255,255,255,.06)}
.clusters .sorth{display:flex;align-items:center;gap:6px;width:100%;
  padding:9px 0;font:inherit;font-size:9.5px;letter-spacing:.08em;
  text-transform:uppercase;font-weight:700;color:var(--text-soft);
  background:none;border:none;cursor:pointer;white-space:nowrap;
  transition:color .18s}
.clusters .dhead2 .sorth:first-child{padding-left:14px}
.clusters .sorth.c{justify-content:center}
.clusters .sorth.r{justify-content:flex-end;padding-right:0}
.clusters .sorth:hover{color:var(--text)}
.clusters .sorth.on{color:var(--sky)}
.clusters .sar{margin-left:3px;font-size:10px;opacity:.85}

/* The side toggle, as the demo draws it: one pill, centred, two halves. */
.clusters .dishtoggle{display:flex;justify-content:center;margin:0 0 14px}
.clusters .dishtoggle{gap:0}
.clusters .dseg{display:inline-flex;align-items:center;gap:8px;
  padding:9px 18px;font:inherit;font-size:14px;font-weight:600;
  color:var(--text-soft);background:transparent;border:1px solid var(--line);
  cursor:pointer;transition:background .15s,color .15s}
.clusters .dseg:first-child{border-radius:999px 0 0 999px}
.clusters .dseg:last-child{border-radius:0 999px 999px 0;border-left:none}
.clusters .dseg:hover{color:var(--text);background:rgba(79,184,231,.08)}
.clusters .dseg.on{background:rgba(79,184,231,.18);color:#fff}

/* The three columns inside an open row: chips, not a bulleted list. */
.cldetail .ddesc{font-size:13.5px;line-height:1.6;color:var(--text-soft);
  margin:0 0 12px;max-width:72ch}
.cldetail .ddesc b{color:var(--text)}
.diffgrid{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;
  margin-bottom:12px}
@media(max-width:760px){.diffgrid{grid-template-columns:1fr}}
.diffcol h5{font-size:11px;letter-spacing:.09em;text-transform:uppercase;
  margin:0 0 6px;font-weight:700}
.diffcol.l h5{color:var(--c1-ink)}
.diffcol.mid h5{color:var(--text-soft)}
.diffcol.r h5{color:var(--c2-ink)}
.diffcol .chip{display:inline-block;font-size:12px;padding:3px 9px;
  margin:0 5px 5px 0;border-radius:999px;background:rgba(79,184,231,.12);
  border:1px solid var(--line);color:var(--text)}

/* ----- 05#2's own detail prose ---------------------------------------- */
/* `.method` is the Library's, and `test_no_page_ships_closed_indicator_detail`
   asserts no page ships it closed: there it marks prose fetched by `?ind=`
   when a row opens. These two blocks ship their own details with the page, as
   10#4's does, so they wear their own name and the same rules. */
.skmethod{font-family:'Source Serif 4',serif;font-size:14px;line-height:1.6;
  color:var(--text-soft);margin:0}
.skmethod b{color:var(--text)}
/* The slider's label, mirrored: the left marker reads "Croatia #49" and the
   right "#149 Sweden", so the two ranks face each other across the gap. */
.rlab .rhash{font-family:'IBM Plex Mono',monospace;font-weight:600;
  color:var(--sky)}
/* Sentence case, as the demo sets them -- "Croatia leads", not "CROATIA
   LEADS". */
.diffcol h5{text-transform:none;letter-spacing:0;font-size:12.5px}

/* ----- 05#2: no table on this page scrolls sideways on a phone -------- */
/* A grid child keeps an automatic minimum the width of its longest
   unbreakable word, so `minmax(0,1fr)` on the track is not enough on its own:
   "Telecommunications" is 139px and the cell overflowed below ~390px. */
.clusters .trowbtn .tind,
.clusters .trowbtn .clmt,
.clusters .trow0 .t-title,
.clusters .trow0 .t-cty,
.skilltbl-ind{min-width:0;overflow-wrap:break-word;word-break:normal}

@media (max-width:640px){
  /* NO WIDTH CLAMP HERE. The closing similarity listings are sized to leave
     a lane beside them because they are one tall list a thumb lands in; that
     is not a width for every table on the page. The clusters table takes the
     full column, like the sophistication table stacked under it -- and it
     cannot steal a swipe anyway, since its grid fits any width and its
     `.tscroll` never has anything to scroll. */
  /* The clusters grid steps down with it. Its middle column is a percentage,
     so it needs far less than the nine-column table's 74px value columns. */
  .clusters .trow0,
  .clusters .trowbtn{grid-template-columns:minmax(0,1fr) 40px minmax(0,1fr) 10px;
    gap:5px;padding:9px 8px}
  .clusters .trowbtn .tind,
  .clusters .trowbtn .clmt{font-size:13.5px;line-height:1.3}
  .clusters .clpct{font-size:12px}
  /* The detail is prose and chips, which wrap on their own, so it keeps the
     full column rather than being squeezed into the lane. */
  .clusters .tdetail{max-width:none}
}

@media (max-width:400px){
  /* Below this the nine fixed columns of the sophistication table no longer
     fit, so they step again rather than the table starting to scroll.

     SCOPED TO `.skilltbl`, NOT TO `.tscroll`. Every table in the Library sits
     inside a `.tscroll`, the clusters table among them -- addressed that way
     this rule gave a four-column row a seven-column grid and broke the second
     country's name one character per line. */
  .skilltbl .trow0,
  .skilltbl .trowbtn{grid-template-columns:minmax(0,1fr) 46px 18px 22px 18px 46px 14px}
  .skilltbl .c-yr,
  .skilltbl .c-src{display:none}
  .skilltbl-ind{font-size:12.5px}
}

/* ----- no Library row cell scrolls sideways -------------------------- */
/* A grid item's automatic minimum is its min-content, so `minmax(0,1fr)` on
   the track does not stop a long unbreakable name spilling out of the span
   inside it -- the cell then becomes its own horizontal scroller and catches
   a thumb meant for the page. Found on 04-1 and 08-1 (`.tind`), 08-3
   (`.co`) and 05-2's own sort header by the all-sections sweep. */
.trowbtn > span,
.trow0 > span,
.dhead2 > button{min-width:0}
.trowbtn .tind,
.trowbtn .co,
.trow0 .t-title,
.trow0 .t-cty{overflow-wrap:break-word}
/* The sort header may wrap its two words rather than spill: at the closing
   lists' own width a flag, a country and an arrow do not fit on one line. */
.clusters .sorth{white-space:normal;line-height:1.25}
.clusters .sorth .sar{flex:0 0 auto}

/* A flex container's children do not wrap unless it says they may, so
   `white-space` alone left the sort header 14px over its own cell. */
.clusters .sorth{flex-wrap:wrap}
/* And `overflow-wrap` is inert against `white-space:nowrap`, which is what
   held 08-3's company names four pixels past their cell. */
.trowbtn .co,
.trowbtn .tind,
.trowbtn .tind span{white-space:normal}

/* ----- the narrowest supported phone, 320px ------------------------------ */
/* Below 340px the nine-column grid's own minimum (305px) is wider than the
   scroller it sits in (294px), so `.tscroll` takes 11px of sideways travel --
   enough to capture a downward swipe, not enough to reveal a column. Trimming
   the indicator floor and the two value columns brings the minimum to 287px
   and the travel to nothing. Scoped below 340 so no phone in current use
   (360px and up) is affected. */
@media (max-width:340px){
  .trow0,.thead,.trowbtn{grid-template-columns:minmax(88px,1fr) 48px 20px 25px 20px 48px 14px;
    padding:0 6px}
}

/* ----- the world ruler's live and dead parts ---------------------------- */
/* The track is the whole field of compared countries. The coloured part
   covers those actually on the scale; what remains is countries at zero in a
   block too large to be a measurement, or countries never measured. The
   SPLIT IS BY COUNTRY COUNT, never by rank: "Small Companies (%)" ranks all
   193 countries into just two ranks, and splitting that by rank would grey
   out 99% of a track with no missing data behind it. */
.rtrack{background:var(--navy-deep);overflow:hidden}
.rlive{position:absolute;left:0;top:0;bottom:0;border-radius:7px;
  background:linear-gradient(90deg,#4FB8E7,#2F6FB0 45%,#1B3A5E 80%,#122740)}
/* The end labels: the first pinned left, the last pinned to where the live
   part ends rather than to the right of the track -- the last ranked country
   is not at the end of the world. */
.rends{position:relative;display:block;min-height:15px}
.rend-a,.rend-b{position:absolute;top:0;white-space:nowrap;max-width:60%;
  overflow:hidden;text-overflow:ellipsis}
.rend-a{left:0}
.rend-b{transform:translateX(-100%);padding-left:8px}
/* The sentence under the track, which carries what the grey actually means. */
.rnote{font-size:11.5px;line-height:1.5;color:var(--text-soft);
  margin:9px 0 0}

/* The dead part is a light wash, not another dark one: it follows a blue
   whose gradient used to end near black, and two dark things meeting is not
   a boundary a reader can see. The live gradient now stops at its mid blue
   for the same reason. */
.rtrack{background:rgba(255,255,255,.12)}
.rlive{background:linear-gradient(90deg,#4FB8E7,#3C87C4 55%,#2F6FB0)}

/* NO `overflow:hidden` ON `.rtrack`. The markers live inside it and stand
   20px tall in a 12px track, so clipping the track decapitates both flags --
   which is exactly what shipped to the owner's screen. The live bar carries
   its own border-radius, so nothing needed the clip. */
.rtrack{overflow:visible}

/* ----- the ruler's end labels, by the same rule as the ones below --------- */
/* Each end is centred on its own point and then bounded and separated by
   layoutRulers(), exactly as `.rlab` is. Pinning them by hand -- left edge at
   0, right edge dragged to where the live part stopped -- printed the two on
   top of each other ("Po#1 Sa#34land") whenever coverage was thin. */
.rends{position:relative;display:block;height:16px;margin-bottom:7px}
.rend{position:absolute;top:0;white-space:nowrap;transform:translateX(-50%)}

/* ----- the timeline's label tail and its chips outside the card ---------- */
/* The caption reads as one sentence with the label above the card, so it
   drops the label's uppercase and takes the quiet colour. */
.section-label .ltail{color:var(--text-soft);font-weight:600;
  text-transform:none;letter-spacing:.01em;font-size:12.5px}
/* The chips navigate the card from outside it now, so they lose the card's
   inner padding and its dividing rule and keep only the gap above it. */
.tlchips{padding:0 0 10px;border-bottom:0}
/* The header is the first thing in the card again. */
.tlhead{border-bottom:1px solid var(--line)}
.tlhead div{display:flex;align-items:center;gap:7px}
.tlhead div:first-child{justify-content:flex-end}
@media (max-width:640px){
  .tlchips{padding-left:0;padding-right:0}
}

/* ----- the organizations tab group -------------------------------------- */
/* Three lists under one cap showed ten rows of the first and two empty
   headings; they are three tabs now, like the treaties block, and each pane
   caps and searches only itself. */
.orggroup-tabs .tabn{
  font-family:'IBM Plex Mono',monospace; font-size:11px; font-weight:600;
  color:var(--text-soft); margin-left:7px;
}
.orggroup-tabs .tbltab.on .tabn{color:var(--sky)}
.orggroup-tabs .orgsearch{margin-top:14px}

/* ----- where else to go: the round badges the demo draws ----------------- */
/* A sentence ("Hoxha, Ferit on Wikipedia") repeated the name the reader had
   just read and spent a line on it. The demo prints a label and a mark.
   Drawn from letterforms: every asset here is local, and two glyphs in
   circles do not need a sprite to hash and keep in step with the manifest. */
.pmore{display:flex;align-items:center;gap:9px;margin-top:10px}
.pmore-lab{font-size:12.5px;color:var(--text-soft)}
.mbadge{display:inline-flex;align-items:center;justify-content:center;
  width:24px;height:24px;border-radius:50%;text-decoration:none;
  font-weight:700;line-height:1;flex:0 0 auto;
  transition:transform .15s,box-shadow .15s}
.mbadge:hover,.mbadge:focus-visible{transform:translateY(-1px)}
.mbadge:focus-visible{outline:2px solid var(--sky);outline-offset:2px}
/* Wikipedia: its own serif W on white, as the demo sets it. */
.mbadge.wp{background:#fff;color:#111;font-family:'Source Serif 4',Georgia,serif;
  font-size:14px;box-shadow:0 0 0 1px rgba(255,255,255,.25)}
.mbadge.wp:hover{box-shadow:0 0 0 2px var(--sky)}
/* LinkedIn: its own blue and its lower-case mark. */
.mbadge.li{background:#0A66C2;color:#fff;font-size:11px;letter-spacing:-.02em;
  box-shadow:0 0 0 1px rgba(10,102,194,.5)}
.mbadge.li:hover{box-shadow:0 0 0 2px var(--sky)}
