/* Self-hosted, latin subset only. Pulled from Google Fonts once and
   committed, so the site makes no third-party request and nothing
   render-blocks on another origin. */
@font-face {
  font-family: 'Archivo Black';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/archivo-black-400-e6dca12e.woff2") format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/ibm-plex-mono-400-d13bb5b4.woff2") format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/assets/ibm-plex-mono-600-0fdd541f.woff2") format('woff2');
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/ibm-plex-sans-400-578a0041.woff2") format('woff2');
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/assets/ibm-plex-sans-500-578a0041.woff2") format('woff2');
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/assets/ibm-plex-sans-600-578a0041.woff2") format('woff2');
}

/* The site's whole look. Hand-written: it is one page, and a framework
   would be more code than the page. */

:root{
    --ground:#0B0D14; --surface:#141826; --surface-2:#1B2133;
    --line:#313A54; --line-strong:#556289;
    --ink:#F2F4F8; --muted:#8A93A8; --faint:#8089A0;
    --red:#ED4D54; --blue:#3366EB; --yellow:#FACC38; --cyan:#5CDBF0; --green:#5CE0A0;
    --display:"Archivo Black","Helvetica Neue",Arial,sans-serif;
    --body:"IBM Plex Sans","Helvetica Neue",Arial,sans-serif;
    --mono:"IBM Plex Mono",ui-monospace,Menlo,monospace;
    --gutter:clamp(20px,5vw,64px);
  }
  *{box-sizing:border-box}
  /* A short page — the scores page before anyone has played, most of all —
     used to leave its footer floating in the middle of a full-screen window
     with half the viewport empty beneath it.
     
     Sticky at top:100vh rather than a flex column on the body: making the body
     a flex container turns every top-level row into a flex item, and the one
     with margin:0 auto collapsed to its content width and centred, which took
     the invite, the scores and the language picker out of their corners. This
     way nothing above the footer is a flex item at all. */
  body{
    min-height:100vh;
    margin:0; background:var(--ground); color:var(--ink);
    font-family:var(--body); font-size:17px; line-height:1.6;
    -webkit-font-smoothing:antialiased;
  }
  .wrap{max-width:1080px; margin:0 auto; padding-inline:var(--gutter)}
  h1,h2,h3{font-family:var(--display); font-weight:400; text-wrap:balance; margin:0}
  p{margin:0}
  a{color:inherit}

  .eyebrow{
    font-family:var(--mono); font-size:12px; font-weight:600;
    letter-spacing:.16em; text-transform:uppercase; color:var(--cyan);
  }

  /* ---------- coming-soon banner ---------- */
  /* Sits above the hero, centred, and says the one thing a first-time
     visitor needs to know before they look for a download button. */
  .soon-wrap{ display:flex; justify-content:center; padding:22px 20px 0 }

  /* Its own row, sharing the page's gutter and max width, so the button's left
     edge lands on the same line as the eyebrow and the wordmark beneath it. */
  /* The invite on the text column's left edge, the language picker hard right.
     One row, so neither needs a row of its own. */
  /* Three columns, and the middle one is the version stamp. `1fr auto 1fr`
     rather than flex with space-between: space-between puts the middle item
     halfway between its neighbours, and the invite and scores are far wider
     than the language picker, so the stamp sat visibly left of centre. Equal
     side columns put it at the true centre of the page while the invite keeps
     the left edge and the picker keeps the right, exactly where they were. */
  .tell-row{
    display:grid; grid-template-columns:1fr auto 1fr;
    grid-template-areas:"actions version langs";
    align-items:center; gap:12px;
    max-width:1080px; margin:0 auto; padding:18px var(--gutter) 0;
  }
  .tell-row .tell-actions{ grid-area:actions; justify-self:start }
  .tell-row .version{ grid-area:version; justify-self:center }
  .tell-row .langs{ grid-area:langs; justify-self:end }
  /* A phone has no room for a fourth thing on that line. The stamp takes a row
     of its own above, still centred, and the invite, scores and picker keep
     the line they had. */
  @media (max-width:640px){
    .tell-row{
      grid-template-columns:1fr auto;
      grid-template-areas:"version version" "actions langs";
    }
  }

  .tell{
    display:inline-flex; align-items:center; gap:7px;
    padding:9px 16px; border-radius:999px; cursor:pointer;
    background:transparent; color:var(--cyan);
    border:1px solid rgba(92,219,240,.38);
    font-family:var(--body); font-weight:600; font-size:13.5px;
    white-space:nowrap;
    transition:border-color .16s ease, background .16s ease;
  }
  .tell:hover{ border-color:var(--cyan); background:rgba(92,219,240,.08) }
  .tell:focus-visible{ outline:2px solid var(--cyan); outline-offset:3px }
  /* The confirmation replaces the label, so nothing moves and nothing is
     announced twice. */
  .tell[data-said="1"]{ color:var(--ink); border-color:var(--line-strong) }
  .tell-heart{ width:14px; height:14px; fill:currentColor; flex:none }
  .tell-chart{ width:14px; height:14px; fill:currentColor; flex:none }
  /* The invite and the scores travel together on the left; the language picker
     keeps the right edge to itself. */
  .tell-actions{ display:flex; align-items:center; gap:10px; flex-wrap:wrap }
  a.tell{ text-decoration:none }

  .soon{
    /* Short enough for one line on any screen, so it is a pill again. The
       text lives in its own span rather than as loose flex children, and
       min-width:0 stops a flex item pushing past its own max-width. */
    display:inline-flex; align-items:center; gap:9px;
    box-sizing:border-box; min-width:0; max-width:100%;
    padding:8px 16px; border-radius:999px;
    background:rgba(92,219,240,.07); border:1px solid rgba(92,219,240,.28);
    color:var(--cyan); text-decoration:none;
    font-family:var(--mono); font-size:12.5px; font-weight:600;
    letter-spacing:.04em;
  }
  .soon:hover{ background:rgba(92,219,240,.13); border-color:rgba(92,219,240,.5) }
  .soon:focus-visible{ outline:2px solid var(--cyan); outline-offset:3px }
  /* The store name, not the brand — it is what a visitor has to type into a
     store search box, and the two differ. */
  .soon strong{ color:var(--ink); font-weight:600 }
  .soon-dot{
    flex:none;
    width:7px; height:7px; border-radius:50%; background:var(--cyan);
    box-shadow:0 0 0 0 rgba(92,219,240,.6);
    animation:soon-pulse 2.4s ease-out infinite;
  }
  @keyframes soon-pulse{
    70%{ box-shadow:0 0 0 7px rgba(92,219,240,0) }
    100%{ box-shadow:0 0 0 0 rgba(92,219,240,0) }
  }
  @media(prefers-reduced-motion:reduce){ .soon-dot{ animation:none } }

  /* ---------- hero ---------- */
  header{padding:clamp(48px,9vw,104px) 0 clamp(56px,8vw,96px)}
  .hero{display:grid; gap:clamp(40px,6vw,72px); align-items:center}
  /* minmax(0,1fr) lets the text column shrink below the wordmark's
     min-content width rather than forcing the row wider than the page, and the
     board column is fluid rather than fixed. Between about 900px and 1030px
     the old rule scrolled the page horizontally. */
  /* DOCKIT is one word and must never break. It is a single unbreakable
     token about 3.85x its font-size wide, so the two-column layout has to size
     it against the column it lives in rather than the whole viewport — at 13vw
     beside a fixed 400px board it was wider than the track it was given, which
     scrolled the page sideways from roughly 900px to 1030px. */
  @media(min-width:900px){
    .hero{ grid-template-columns:minmax(0,1fr) minmax(260px,380px) }
    .wordmark{ font-size:clamp(50px, 7.6vw, 100px) }
  }
  .wordmark{ white-space:nowrap }

  .wordmark{
    font-family:var(--display); font-size:clamp(56px,11.4vw,116px);
    line-height:.86; letter-spacing:-.035em; margin:14px 0 0;
  }
  .tagline{
    font-family:var(--mono); font-weight:600; color:var(--cyan);
    font-size:clamp(14px,2.4vw,19px); letter-spacing:.02em; margin-top:18px;
  }
  .pitch{color:var(--muted); max-width:44ch; margin-top:22px; font-size:1.05rem}
  .pitch strong{color:var(--ink); font-weight:600}

  .cta{display:flex; flex-wrap:wrap; gap:12px; align-items:center; margin-top:34px}
  .btn{
    font-family:var(--body); font-weight:600; font-size:15px;
    padding:13px 22px; border-radius:999px; text-decoration:none;
    background:var(--cyan); color:#06202A; border:1px solid transparent;
    transition:transform .16s ease, filter .16s ease;
  }
  .btn:hover{transform:translateY(-2px); filter:brightness(1.06)}
  .btn.ghost{background:transparent; color:var(--ink); border-color:var(--line)}
  .btn.ghost:hover{border-color:var(--cyan); color:var(--cyan)}
  .btn:focus-visible{outline:2px solid var(--cyan); outline-offset:3px}

  /* ---------- the board ---------- */
  /* The square lives on .grid, not on .stage. With aspect-ratio on the stage
     and height:100% on the grid, Safari resolved that percentage against the
     stage's full height rather than its content box, so the grid stood 44px
     taller than the room inside the padding and overflow:hidden ate the last
     row. Sizing the grid itself and letting the stage wrap it needs no
     percentage height at all. The padding is a length for the same reason:
     a percentage resolves against the *containing block's* width, which at
     768px is the whole hero column, not the 400px board. */
  .stage{
    position:relative; width:100%; max-width:400px; margin-inline:auto;
    background:var(--surface); border:1px solid var(--line);
    border-radius:26px; padding:22px; overflow:hidden;
  }
  .grid{position:relative; width:100%; aspect-ratio:1}

  /* Stackit and Queueit each draw a run of slots outside the board, so the box
     has to be bigger than a square by the room that run needs. The board itself
     stays square in both: the demo lays everything out in the board's own
     units and converts per axis, so the board and its slots never drift apart.

     Where that room goes is the difference, and it is the games' difference.
     Queueit's line grows from both ends, which only reads as a line if it lies
     flat — so its slots are a row under the board and its box is taller than
     square. Stackit's stack grows from one end, and a stack is a vertical idea
     — so its slots stand as a column to the right and its box is wider than
     square. Each ratio is the board's 100 units plus a double gap plus one
     slot, on whichever axis carries the run. */
  .grid-queueit{aspect-ratio:1 / 1.3}
  .grid-stackit{aspect-ratio:123.6 / 100}
  .grid-queueit .slot,
  .grid-stackit .slot{border-style:dashed; border-color:#2b3350}
  .cell{
    position:absolute; border-radius:16%;
    background:var(--surface-2); border:1px solid #222941;
  }
  .tile{
    position:absolute; border-radius:16%;
    display:grid; place-items:center;
    transition:transform .34s cubic-bezier(.22,.9,.3,1), opacity .22s ease;
    will-change:transform;
  }
  .tile svg{width:68%; height:68%; overflow:visible}
  .tile.pop{animation:pop .42s ease forwards}
  @keyframes pop{
    35%{transform:scale(1.16)}
    100%{transform:scale(.2); opacity:0}
  }

  /* ---------- today: the day as a shape ---------- */
  /* The distribution is bars rather than a chart library: ten rows of two divs
     weigh nothing and read the same in every browser. */
  @media(min-width:680px){ .figures.three{grid-template-columns:repeat(3,1fr)} }
  /* Same three columns as a bar row, so the words sit over what they name. */
  .dist-head{
    display:grid; grid-template-columns:64px 1fr 44px; gap:12px;
    margin-top:34px; font-family:var(--mono); font-size:10.5px;
    letter-spacing:.14em; text-transform:uppercase; color:var(--faint);
  }
  .dist-head span:first-child{ text-align:right }
  .dist{margin-top:9px; display:flex; flex-direction:column; gap:7px}
  .bar-row{display:grid; grid-template-columns:64px 1fr 44px; gap:12px; align-items:center}
  .bar-label{font-family:var(--mono); font-size:12px; color:var(--faint); text-align:right}
  .bar-track{background:var(--surface); border:1px solid var(--line); border-radius:6px; height:22px}
  .bar-fill{background:var(--cyan); height:100%; border-radius:5px; min-width:2px}
  .bar-count{font-family:var(--mono); font-size:12px; color:var(--muted); white-space:nowrap}
  /* The band a placed score falls in. Brightened rather than recoloured, so the
     chart still reads as one series and the marker does the pointing. */
  .bar-row.is-here .bar-fill{ background:var(--ink) }
  .bar-row.is-here .bar-label,
  .bar-row.is-here .bar-count{ color:var(--ink) }
  /* Green, not the page's cyan: this is the one line addressed to the person
     reading it rather than to everyone, and it should not read as another
     heading. The border follows the text so the callout is one colour. */
  .placed{
    margin-top:30px; padding:14px 18px; border-radius:14px;
    background:var(--surface); border:1px solid rgba(92,224,160,.35);
    color:var(--green); font-size:15px; font-weight:600;
  }
  .daily-link{margin-top:18px}
  .daily-link a{color:var(--cyan); text-decoration:none; font-weight:600}
  .daily-link a:hover{text-decoration:underline}
  .empty{color:var(--muted); margin-top:30px; font-size:1.05rem}
  .today-note{color:var(--faint); font-size:13.5px; margin-top:24px}
  /* The page ends in one quiet sentence, so it does not need a section's worth
     of air under it before the footer. Every other section here is followed by
     another section; this one is followed by the end of the page. */
  #today{ padding-bottom:clamp(20px,2.5vw,30px) }
  .today-note a{color:var(--cyan); text-decoration:none}
  .today-note a:hover{text-decoration:underline}

  /* ---------- sections ---------- */
  section{padding:clamp(48px,7vw,84px) 0; border-top:1px solid var(--line)}
  .head{max-width:56ch}
  .head h2{font-size:clamp(26px,4.4vw,38px); letter-spacing:-.02em; margin-top:12px}
  .head p{color:var(--muted); margin-top:14px}

  .steps{display:grid; gap:20px; margin-top:38px}
  @media(min-width:760px){ .steps{grid-template-columns:repeat(3,1fr)} }
  .step{background:var(--surface); border:1px solid var(--line); border-radius:18px; padding:24px}
  .step .n{
    font-family:var(--mono); font-size:12px; font-weight:600; color:var(--cyan);
    letter-spacing:.14em;
  }
  .step h3{font-size:18px; margin-top:12px; letter-spacing:-.01em}
  .step p{color:var(--muted); font-size:15px; margin-top:8px}

  /* rule examples */
  .examples{display:grid; gap:18px; margin-top:36px}
  @media(min-width:760px){ .examples{grid-template-columns:1fr 1fr} }
  .example{
    background:var(--surface); border:1px solid var(--line);
    border-radius:18px; padding:22px;
  }
  .example.good{border-color:rgba(92,224,160,.35)}
  .example.bad{border-color:rgba(237,77,84,.32)}
  .trio{display:flex; gap:10px; margin:4px 0 16px}
  .trio .tile{position:static; width:64px; height:64px; flex:0 0 auto}
  .verdict{font-family:var(--mono); font-size:13px; font-weight:600}
  .good .verdict{color:var(--green)}
  .bad .verdict{color:var(--red)}
  .example p{color:var(--muted); font-size:14.5px; margin-top:8px}

  /* attribute legend */
  .attrs{display:grid; gap:14px; margin-top:34px}
  @media(min-width:680px){ .attrs{grid-template-columns:repeat(4,1fr)} }
  .attr{
    background:var(--surface); border:1px solid var(--line);
    border-radius:16px; padding:18px;
  }
  .attr .k{font-family:var(--mono); font-size:11px; letter-spacing:.14em; color:var(--faint); text-transform:uppercase}
  .attr .v{font-family:var(--display); font-size:19px; margin-top:8px; letter-spacing:-.01em}
  .attr p{color:var(--muted); font-size:13.5px; margin-top:6px}
  .attr.locked{border-style:dashed}
  .attr.locked .v{color:var(--cyan)}

  /* figures */
  .figures{display:grid; gap:1px; margin-top:36px; background:var(--line);
           border:1px solid var(--line); border-radius:18px; overflow:hidden}
  @media(min-width:680px){ .figures{grid-template-columns:repeat(4,1fr)} }
  .fig{background:var(--surface); padding:22px}
  .fig .big{
    font-family:var(--mono); font-weight:600; font-size:clamp(24px,3.6vw,32px);
    letter-spacing:-.02em; font-variant-numeric:tabular-nums; color:var(--ink);
  }
  .fig .lab{color:var(--muted); font-size:13.5px; margin-top:6px}

  /* One line of legal text, so it gets one line's worth of room. The 40/60
     it had made it read as a section rather than a rule under the page. */
  footer{position:sticky; top:100vh; border-top:1px solid var(--line); padding:14px 0; color:var(--faint); font-size:13.5px}
  /* Three items across one row while they fit. When they do not, they wrap
     centred rather than spread: space-between leaves the last item alone and
     left-aligned on its own line, which reads as a mistake rather than a
     layout. Centring costs nothing at full width — with three items and
     space-between the outer two already sit on the edges. */
  footer .footer-row{
    display:flex; flex-wrap:wrap; align-items:center;
    justify-content:space-between; gap:10px 24px;
    text-align:center;
  }
  /* Below 700px the three genuinely cannot share a line — flex was keeping
     two on one row and letting the copyright run off the edge rather than
     wrapping it. Stacked and centred is the honest answer at that width. */
  @media(max-width:700px){
    footer .footer-row{ flex-direction:column; justify-content:center; gap:8px }
  }
  footer p{ margin:0 }
  footer .footer-strong{ color:var(--muted); font-weight:500 }
  footer .footer-swiss{ display:inline-flex; align-items:center; gap:8px }

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

/* ── Document pages (privacy, support) ─────────────────────────────────────
   Same type and colour as the rest of the site, set for reading rather than
   for a hero. */
.doc { max-width: 46rem; margin: 0 auto; padding: 5rem 1.5rem 6rem; }

/* A row of its own above the heading, sharing the text column's left edge so
   the arrow lines up with the prose rather than sitting off on its own. */
.back-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin: 0 0 1.6rem;
}
.back {
  display: inline-flex; align-items: center; gap: .5rem;
  color: var(--cyan); text-decoration: none;
  font-size: .9rem; font-weight: 600;
}
.back:hover { text-decoration: underline }
.back:focus-visible { outline: 2px solid var(--cyan); outline-offset: 3px }
.doc h1 { font-size: clamp(2rem, 6vw, 3rem); margin: 0 0 .35em; }
.doc h2 { margin: 2.4em 0 .5em; font-size: 1.15rem; }
.doc p, .doc li { line-height: 1.65; }
.doc ul { padding-left: 1.2rem; }
.doc a { color: inherit; }
.stamp { font-family: "IBM Plex Mono", monospace; font-size: .8rem; opacity: .55; }

/* ── Download ──────────────────────────────────────────────────────────────
   Two tiles, side by side and equal: neither platform is the afterthought.
   A store that is not live yet renders dimmed and unlinked rather than being
   hidden, so the page reads as "both are coming" rather than "iPhone only". */
.stores{
  display:grid; grid-template-columns:repeat(auto-fit, minmax(15rem, 1fr));
  gap:1rem; margin:2.5rem 0 1.75rem;
}
.store{
  display:flex; align-items:center; gap:1rem;
  padding:1.1rem 1.4rem; border:1px solid var(--line); border-radius:14px;
  text-decoration:none; color:var(--ink); background:rgba(255,255,255,.02);
  transition:border-color .18s ease, transform .18s ease, background .18s ease;
}
a.store:hover{
  border-color:var(--cyan); background:rgba(255,255,255,.05);
  transform:translateY(-2px);
}
a.store:focus-visible{ outline:2px solid var(--cyan); outline-offset:3px }
/* Not opacity. Fading the whole tile took the platform line to 1.6:1,
   which is unreadable — and this is the state every visitor sees until the
   apps are live. It reads as pending through a dashed border instead. */
.store.soon{ cursor:default; border-style:dashed; background:transparent }
.store-glyph{ display:flex; align-items:center; color:var(--ink) }
.store-text{ display:flex; flex-direction:column; gap:.1rem }
.store-lead{ font-size:.72rem; letter-spacing:.04em; text-transform:uppercase; color:var(--muted) }
.store-name{ font-size:1.15rem; font-weight:600 }
.store-plat{ font-family:"IBM Plex Mono", monospace; font-size:.72rem; color:var(--faint) }
/* The two tiers, side by side. Structure rather than a sentence: the prose
   above already states the shape, and saying it twice read as a fragment. */
.tiers{
  display:grid; grid-template-columns:repeat(auto-fit, minmax(15rem, 1fr));
  gap:1rem;
}
.tier{
  padding:1.25rem 1.4rem; border:1px solid var(--line); border-radius:14px;
  background:rgba(255,255,255,.015);
}
.tier-pro{ border-color:#2E3A5C }
.tier-name{
  display:flex; align-items:baseline; justify-content:space-between; gap:.6rem;
  font-weight:600; font-size:.95rem; margin-bottom:.7rem;
  color:var(--ink);
}
/* The price sits on the tier's own line rather than in the list: it is what
   the tier costs, not another thing the tier gives you. */
.tier-price{
  font-weight:400; font-size:.78rem; color:var(--faint);
  letter-spacing:.01em; white-space:nowrap;
}
.tier-pro .tier-price{ color:var(--muted) }
.tier-pro .tier-name{ color:var(--cyan) }
.tier ul{ margin:0; padding:0; list-style:none; display:grid; gap:.42rem }
.tier li{
  color:var(--muted); font-size:.9rem; line-height:1.45;
  padding-left:1.1rem; position:relative;
}
.tier li::before{
  content:"·"; position:absolute; left:.25rem; color:var(--faint);
}

  /* The ghost button's border is its only affordance, so it gets the token
     that actually clears 3:1 rather than the subtle one the cards use. */
  .btn.ghost{ border-color:var(--line-strong) }

  /* A skip link: the home page is one long column and the first thing in it
     is a banner. Off-screen until focused. */
  .skip{
    position:absolute; left:-9999px; top:0; z-index:50;
    background:var(--cyan); color:#06202A; padding:10px 16px;
    border-radius:0 0 10px 0; font-weight:600; text-decoration:none;
  }
  .skip:focus{ left:0 }

  /* Focus was styled for buttons and store tiles but not for prose or footer
     links, which fell back to the UA ring and looked like a different site. */
  .doc a:focus-visible, footer a:focus-visible{
    outline:2px solid var(--cyan); outline-offset:3px; border-radius:2px;
  }
  .doc a{ color:var(--cyan); text-decoration-color:rgba(92,219,240,.45) }
  footer a{ color:var(--muted) }
  footer a:hover{ color:var(--ink) }
  footer .footer-links{ display:flex; gap:16px }

  /* The two words the sentence turns on, in the same cyan as the section
     eyebrow above it — so "free" and "Pro" read as the two tiers rather than
     as emphasis. */
  .tier-word{ color:var(--cyan); font-weight:600 }

  /* The version stamp. The same pill as the availability banner — mono, cyan,
     a live dot — because it is saying the same kind of thing: what is in the
     stores right now. */
  .version{ position:relative }
  .version summary{
    display:inline-flex; align-items:center; gap:8px;
    list-style:none; cursor:pointer; white-space:nowrap;
    padding:7px 14px; border-radius:999px;
    background:rgba(92,219,240,.07); border:1px solid rgba(92,219,240,.28);
    color:var(--cyan); font-family:var(--mono); font-size:12.5px; font-weight:600;
    letter-spacing:.04em;
    transition:border-color .16s ease, background .16s ease;
  }
  .version summary::-webkit-details-marker{ display:none }
  .version summary:hover,
  .version[open] summary{ background:rgba(92,219,240,.13); border-color:rgba(92,219,240,.5) }
  .version summary:focus-visible{ outline:2px solid var(--cyan); outline-offset:3px }
  .version-dot{
    width:6px; height:6px; border-radius:50%; background:var(--green); flex:none;
  }
  /* Downward and centred under the stamp, which is centred on the page — so
     the panel is too. Capped so a long translation wraps instead of running
     off a phone. */
  .version-panel{
    position:absolute; top:calc(100% + 10px); left:50%; transform:translateX(-50%);
    z-index:20; box-sizing:border-box;
    width:min(360px, calc(100vw - 2 * var(--gutter)));
    padding:16px 18px; text-align:left;
    background:var(--panel, #12151F); border:1px solid var(--line-strong);
    border-radius:14px; box-shadow:0 12px 30px rgba(0,0,0,.45);
  }
  .version-head{
    margin:0 0 10px; color:var(--ink);
    font-family:var(--body); font-weight:600; font-size:14px;
  }
  .version-panel ul{ margin:0; padding:0 0 0 18px }
  .version-panel li{
    color:var(--muted); font-family:var(--body); font-size:13.5px; line-height:1.5;
    margin:0 0 6px;
  }
  .version-panel li:last-child{ margin-bottom:0 }
  .version-panel li::marker{ color:var(--cyan) }

  /* The language picker. A disclosure so sixteen links do not sit in the
     footer permanently, and a plain list inside so it works with scripting
     off and a crawler can follow every one of them. */
  .langs{ position:relative; font-size:15px }
  .langs summary{
    cursor:pointer; color:var(--muted); list-style:none;
    padding:4px 2px; border-bottom:1px dotted var(--line-strong);
  }
  .langs summary::-webkit-details-marker{ display:none }
  .langs summary:hover{ color:var(--cyan) }
  .langs[open] summary{ color:var(--cyan) }
  /* Downward and right-aligned. It used to open upward, from the footer; at
     the top of the page that put it off the screen entirely. Right-anchored
     because it now sits against the right edge, where a centred panel would
     hang past it. */
  .langs ul{
    position:absolute; top:calc(100% + 8px); right:0;
    z-index:20; margin:0; padding:8px; list-style:none;
    /* max-content, not 1fr: the panel is absolutely positioned, so it has no
       width for fractions to divide and the two columns collapsed on top of
       each other. It sizes to the longest language name instead. */
    width:max-content;
    display:grid; grid-template-columns:repeat(2, max-content); gap:2px 18px;
    background:var(--panel, #12151F); border:1px solid var(--line-strong);
    border-radius:12px; white-space:nowrap;
    box-shadow:0 12px 30px rgba(0,0,0,.45);
  }
  .langs a{ color:var(--muted); text-decoration:none; padding:5px 8px; display:block }
  /* On a narrow screen a two-column panel anchored right still fits, but the
     row above it wraps — keep the panel inside the viewport either way. */
  @media (max-width:520px){
    .langs ul{ grid-template-columns:1fr; max-height:60vh; overflow-y:auto }
  }
  .langs a:hover{ color:var(--cyan) }
  .langs [aria-current]{ color:var(--ink); padding:5px 8px; display:block }
