/* The language picker (js/ui/langpicker.js) — one component, two surfaces.
   Its own stylesheet because it is the only chrome loaded by BOTH shells: dashboard.css is
   not on the landing page and landing.css is not on the dashboard, so anything shared has to
   live here (css/servermark.css is the same case and the same answer).

   Every surface, line, glyph and accent below is a TOKEN, so the control repaints itself
   under all eight themes — including the per-game deck themes the landing stage swaps on
   hover — without one rule being added here. Two literals are deliberate and are not theme
   colour: the drop shadow's rgba(), copied from .notif-panel so the two popovers cast the
   same shadow, and the `Highlight` system colour inside the forced-colors block, where using
   a token would defeat the point. */

/* ── the trigger ────────────────────────────────────────────────────────────── */
.lang-chip {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--mono); font-size: var(--fs-sm); letter-spacing: 0.06em;
  color: var(--muted); background: var(--surf-3);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: 0 8px; height: 30px; cursor: pointer; white-space: nowrap;
  transition: color .13s, border-color .13s, background .13s;
}
.lang-chip:hover, .lang-chip.open { color: var(--green); border-color: var(--line-2); }
.lang-chip:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; }
.lang-glb { width: 16px; height: 16px; flex: none; }
.lang-code { font-weight: 700; }
/* The caret is the affordance that says "this opens something" — it is the only part of the
   trigger that moves, and it moves once, 180deg, to mirror the menu's state. */
/* .78, not .62. The caret is the expanded/collapsed indicator — a UI state graphic under SC
   1.4.11, not decoration — and --muted composited at 62% over its ground measured 2.79:1 on
   matrix and 2.93:1 on nebula, under the 3:1 floor. .78 clears it in all eight themes. */
.lang-caret { width: 11px; height: 11px; flex: none; opacity: .78; transition: transform .16s, opacity .13s; }
.lang-chip.open .lang-caret { transform: rotate(180deg); opacity: 1; }

/* Row variant — the landing burger panel. A 30px chip parked among full-width links reads as
   debris, so at that size the control becomes a row like its neighbours and spends the extra
   width saying, in words, what it is and what it is currently set to. */
.lang-chip--row {
  width: 100%; height: auto; padding: 11px 4px; gap: 9px;
  font-size: var(--fs-lg); background: none; border: 0;
  border-bottom: 1px solid var(--line-hair); border-radius: 0;
  color: var(--text);
  /* The panel's own links compute to 39px from the same padding — over SC 2.5.8's 24px AA
     floor, under the 44px this project holds phone CONTROLS to everywhere else (the topbar
     block at the foot of this file, and css/dashboard.css). A link that missed its target
     costs a scroll; a language control that missed its target is unreachable for the one
     person who needs it, so this one takes the 44px and reads 5px taller than its
     neighbours. Measured at 390px before the floor was added: 39px. */
  min-height: 44px;
}
.lang-chip--row .lang-row-lbl { flex: 1; text-align: left; }
/* min-width:0 + ellipsis, because .lang-chip sets `white-space: nowrap` and neither of these
   two could otherwise shrink: the row's min-content width was rigid, and the worst pairing
   (an English UI, whose "Language" is the longest of the eleven, currently set to
   "Português (Brasil)") had exactly 0px of slack at 320px and scrolled the document sideways
   below ~296px. Truncating here costs nothing — the endonym is restated in full on the first
   row of the menu this opens. */
.lang-chip--row .lang-row-val { color: var(--muted); font-size: var(--fs-md); min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.lang-chip--row:hover, .lang-chip--row.open { background: none; border-color: var(--line-hair); color: var(--green); }

/* ── the menu ───────────────────────────────────────────────────────────────── */
.lang-menu {
  /* 9705, not 9700: .notif-panel (css/shell-extras.css) is also fixed, also appended to
     <body>, and was also 9700 — a tie broken only by mount order in js/app.js. They cannot
     actually be open at once (both close on outside click), so this is not a live bug; it is
     a one-digit way to stop it becoming one if the mount order is ever swapped.
     Everything that must cover this still does: palette 9800, toasts 10000, modals 10001. */
  position: fixed; z-index: 9705; width: min(288px, 92vw); display: none;
  background: var(--surf-2); border: 1px solid var(--line-2); border-radius: var(--r-md);
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.7); overflow: hidden;
}
.lang-menu.open { display: block; animation: lang-in .14s cubic-bezier(.2,.7,.2,1); }
@keyframes lang-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
.lang-menu-head {
  padding: 10px 13px; border-bottom: 1px solid var(--line);
  font-family: var(--mono); font-size: var(--fs-2xs); letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--green-dim);
}
/* This cap is only the value the menu is MEASURED at — placeMenu() in js/ui/langpicker.js
   overwrites it on every open with the room the chosen side actually has, because a cap
   declared here limits how tall the menu gets but not where it then sits (an 11-row menu
   opened from the burger row at 390x780 ran 62px off the bottom of the screen). The list is
   what scrolls, so the "// LANGUAGE" header stays pinned above it. */
.lang-menu-list { max-height: min(64vh, 460px); overflow: auto; padding: 5px; overscroll-behavior: contain; }

.lang-opt {
  display: flex; align-items: center; gap: 9px;
  padding: 8px 9px; border-radius: var(--r-sm); border: 1px solid transparent;
  cursor: pointer; user-select: none;
}
.lang-opt + .lang-opt { margin-top: 1px; }
.lang-opt:hover { background: var(--green-soft); border-color: var(--line); }
/* Options take real DOM focus (roving tabindex), so the focus ring is the keyboard's cursor
   through this list and has to be unmissable — not the 2px outline used on ordinary
   controls, which an outline-offset would clip against the scrolling container. */
.lang-opt:focus { outline: none; background: var(--green-soft); border-color: var(--green); box-shadow: inset 0 0 0 1px var(--green); }
.lang-opt.on { background: color-mix(in srgb, var(--green-soft) 55%, transparent); }

/* Windows High Contrast Mode forces `box-shadow` to none and does NOT restore a suppressed
   outline, so the ring above is the entire focus indicator and HCM erases it — leaving a 1px
   border flip as the keyboard's only cursor through this list (SC 2.4.11/2.4.13). Nothing
   else in this codebase opts out of `outline`, which is why nothing else needed this. */
@media (forced-colors: active) {
  /* -2px keeps the ring inside the scrolling list instead of being clipped by it. */
  .lang-opt:focus { outline: 2px solid Highlight; outline-offset: -2px; }
}

.lang-opt-mark { width: 11px; flex: none; color: var(--green); font-size: var(--fs-sm); text-shadow: var(--glow); }
/* min-height reserves the two-line stack even on the one row that has no English hint (the
   endonym and the English name are the same word for English), so a list of eleven keeps one
   rhythm instead of showing a single short row that reads as a rendering fault. */
.lang-opt-body { flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: center; gap: 1px; min-height: 38px; }
/* The endonym is the primary text — it is what the person looking for their own language is
   scanning for, and it is never translated. */
.lang-opt-name { font-size: var(--fs-lg); color: var(--head); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The English name, for the person reading a screenshot or writing a support ticket. */
.lang-opt-hint { font-size: var(--fs-xs); color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lang-opt-code { flex: none; font-family: var(--mono); font-size: var(--fs-2xs); letter-spacing: 0.1em; color: var(--faint); }
/* HOVER IS A STATE THESE TWO HAVE TO BE RE-COLOURED FOR, not just focus and selection: the
   row's ground becomes --green-soft under the pointer, and the quiet text tiers do not
   survive the move off --surf-2. Measured against --green-soft across all eight themes:
   --faint 2.96 (matrix) to 4.45 (zomboid-red) — an SC 1.4.3 failure in EVERY theme — and
   --muted 3.58 on matrix. --green-dim, the previous value here, is 4.43 on nebula and also
   fails. --green-text (9.08-10.67) and --text (9.24-13.98) clear AA everywhere.
   This is the same trap css/dashboard.css:1330 and css/shell-extras.css:38-46 already
   documented: a quiet tier that passes on the idle surface and fails on the active one. */
.lang-opt.on .lang-opt-code, .lang-opt:focus .lang-opt-code, .lang-opt:hover .lang-opt-code { color: var(--green-text); }
.lang-opt:hover .lang-opt-hint, .lang-opt:focus .lang-opt-hint, .lang-opt.on .lang-opt-hint { color: var(--text); }

:root[data-motion="reduced"] .lang-menu.open,
:root[data-motion="reduced"] .lang-chip .lang-caret { animation: none; transition: none; }
@media (prefers-reduced-motion: reduce) {
  .lang-menu.open { animation: none; }
  .lang-caret { transition: none; }
}

/* ── landing header ─────────────────────────────────────────────────────────────
   Quieter here than on the dashboard, and deliberately so. The nav row is the page's
   conversion strip — "Sign in" and "Deploy a server" — and the argument that kept this
   control in the footer for so long (index.html, footer) was that a language menu competing
   with the primary CTA is exactly the wrong kind of loud. It is in the header now because
   that is where a visitor notices they are reading the wrong language; it earns the place by
   matching .lnav-signin's weight instead of the boxed chip's, so it reads as one more quiet
   nav item and the CTA keeps the only filled surface in the row. */
.lnav .lang-chip--chip {
  background: none; border-color: transparent; padding: 0 4px;
  font-size: 12.5px; color: var(--muted);
}
.lnav .lang-chip--chip:hover, .lnav .lang-chip--chip.open { color: var(--head); border-color: transparent; }
/* Scoped to the header chip: #lnav-mobile is a child of .lnav too, so an unscoped .lnav
   .lang-glb also shrank the burger row's globe to 15px beside its 14px label. */
.lnav-inner .lang-chip--chip .lang-glb { width: 15px; height: 15px; }

/* THE NAV ROW HAS NO SLACK TO GIVE. .lnav-inner is a fixed 58px non-wrapping flex row whose
   only flexible element is .lnav-spacer, and measured across all eleven shipped catalogs that
   spacer is ALREADY 0 at 901px — the first width above the burger breakpoint — in seven of
   them. So the chip's 65px came straight out of the two controls beside it, breaking "Sign in"
   and "Deploy a server ❯" onto a second line inside a 58px bar: 901-960px in English,
   901-1040px in French and Spanish.
   The fix is split in two. HERE, the chip drops to the globe alone until the row can afford
   its code — the same trade it makes in the topbar, and the one .kchip makes with "⌘K"; the
   globe is the half that means "language", the code is the half that is merely nice.
   THERE, in css/landing.css, the conversion strip is made to never give, because it is what
   the row is for. Those rules change .lnav-signin and .lnav-cta rather than anything of this
   component's, and this file is shared with the dashboard shell, so they belong beside the
   rest of the nav row rather than here. */
@media (max-width: 1100px) {
  .lnav-inner .lang-chip--chip .lang-code,
  .lnav-inner .lang-chip--chip .lang-caret { display: none; }
  .lnav-inner .lang-chip--chip { gap: 0; }
}

/* At the burger breakpoint the header chip stands down and the row inside the panel takes
   over — the same handover .lnav-links and .lnav-signin already make at this width. */
@media (max-width: 900px) {
  .lnav-inner .lang-chip--chip { display: none; }
}

/* ── dashboard topbar ───────────────────────────────────────────────────────────
   The bar's width budget is measured to the pixel in css/dashboard.css: every control is
   `flex: none` and only .crumbs gives width back, and that comment records that with
   everything at full size the bar needed ~658px and pushed the document 17px sideways in the
   641-659 band — the first widths ABOVE the phone breakpoint, where the drawer has just
   handed the rail back and every control returns at once.

   This chip is the seventh control and it reopened exactly that wound. Measured on the live
   rig before this block existed: 25px of document overflow at 641px, 16px at 650px, 7px at
   659px, clean again from 700px. So above the phone breakpoint but below the width where the
   bar can afford it, the chip sheds its code and caret and becomes the globe alone — the same
   trade .kchip makes when "⌘K" turns into the search icon, one breakpoint earlier.
   The globe keeps the control legible on its own: it is the part that means "language". */
@media (max-width: 760px) {
  .topbar .lang-code, .topbar .lang-caret { display: none; }
  .topbar .lang-chip { padding: 0 7px; gap: 0; }
}

/* Phones: the same globe-only chip, at the 44px target the rest of this bar takes. */
/* Phones: the chip LEAVES the bar and the drawer takes over. A sixth 44px control does not
   fit — measured on the rig it cost a flat 52px and squeezed .crumbs to 17px at 320px, worse
   than the 19px that already justified dropping the balance chip (css/dashboard.css). This is
   the same handover the landing page makes at 900px, and the drawer is where this shell
   already keeps every nav-level control at this width. */
@media (max-width: 640px) {
  .topbar .lang-chip { display: none; }
}

/* The drawer's copy: a row like its neighbours, and ONLY in drawer mode — the desktop rail is
   an icon column (or a 190px labelled one) that a full-width row would blow apart.
   The hide is on the WRAPPER, not the button: the rail styles its children by element, and
   `:root[data-sidebar="labeled"] .rail button` at (0,3,1) beat every reasonable selector for
   the button itself — which is how this shipped rendering in the desktop sidebar. */
.rail-lang { display: none; }
@media (max-width: 640px) {
  .rail-lang { display: block; margin: 6px 8px 0; border-top: 1px solid var(--line-hair); }
  .rail-lang .lang-chip--row { padding: 11px 10px; border-bottom: 0; font-size: var(--fs-md); }
  .rail-lang .lang-glb { width: 17px; height: 17px; } /* matches the rail's own icons */
}
