/* unbleep.ai — i18n additions: the language switcher in the nav and the
   translation notice on the legal pages. Tokens come from styles.css; nothing
   here overrides it. Generated pages load this after styles.css. */

/* ===== language switcher =====================================================
   A <details> menu of twenty languages. It works with JavaScript off: the
   summary toggles the panel and every entry is a real <a> to the same page in
   that language.

   Twenty entries in one column is a 24rem scroller with a grey system
   scrollbar down its side — nothing to scan by. So the panel is a GRID: two
   columns of ten on desktop, which fits all twenty with no scroll at all;
   one column below 560px, where a scroll is expected and the viewport has no
   room for two.

   Placement and flow are logical (inset-inline-end, padding-inline, grid
   flow), so under dir="rtl" the panel hangs off the other side and the
   columns read right-to-left without a single mirrored rule. */

/* the sprite itself: flags.py emits it once per page, it draws nothing */
.flag-sprite{position:absolute;width:0;height:0;overflow:hidden;}

/* A flag. The 1px border is a real CSS border, not a stroke inside the
   artwork: with border-box sizing it eats into the 20x14 box, so it is an
   inset hairline that keeps a white or light flag (JP, KR, IL) off the dark
   surface instead of letting it bleed into it. */
.flag{flex:none;display:block;width:20px;height:14px;border:1px solid rgba(216,216,216,.22);border-radius:3px;background:var(--surface-2);overflow:hidden;}

.lang-sw{position:relative;}

/* the trigger — the existing pill, now carrying the current flag and name so
   the state is legible before anything is opened */
.lang-sw summary{display:inline-flex;align-items:center;gap:7px;list-style:none;cursor:pointer;font-family:var(--label);font-size:.56rem;letter-spacing:.12em;text-transform:uppercase;color:var(--text-dim);border:1px solid var(--border);border-radius:999px;padding:4px 9px 4px 5px;line-height:1;white-space:nowrap;user-select:none;transition:color .14s,border-color .14s,background .14s;}
.lang-sw summary::-webkit-details-marker{display:none;}
.lang-sw summary::after{content:"";flex:none;width:0;height:0;border-left:3px solid transparent;border-right:3px solid transparent;border-top:4px solid currentColor;opacity:.7;transition:transform .16s;}
.lang-sw summary:hover{color:var(--text);border-color:var(--text-dim);background:var(--surface-2);}
.lang-sw[open] summary{color:var(--text);border-color:var(--text-dim);background:var(--surface-2);}
.lang-sw[open] summary::after{transform:rotate(180deg);}
.lang-sw summary:focus-visible{outline:2px solid var(--green);outline-offset:2px;}
.lang-sw summary .flag{width:22px;height:15px;}
/* The native name on the trigger. It is its own element so it can ellipsize
   (an anonymous flex item cannot) and so an RTL name is isolated from the
   caret beside it. */
.lang-sw summary .lang-cur{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;unicode-bidi:isolate;line-height:1.6;}

/* the panel — a two-by-ten grid, filled down the first column then down the
   second, so the list still reads in the site's language order */
.lang-sw ul{position:absolute;top:calc(100% + 9px);inset-inline-end:0;z-index:60;display:grid;grid-auto-flow:column;grid-template-rows:auto repeat(10,auto);grid-template-columns:repeat(2,minmax(9.6rem,1fr));gap:1px 5px;margin:0;padding:7px;list-style:none;width:max-content;max-width:calc(100vw - 28px);max-height:calc(100dvh - 5.5rem);overflow-y:auto;overscroll-behavior:contain;scrollbar-width:thin;scrollbar-color:var(--border) transparent;background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);box-shadow:0 18px 44px rgba(0,0,0,.55),0 0 0 1px rgba(0,0,0,.4);}

/* The panel's heading, taken from the <ul aria-label> the generators already
   write — so it is translated, and no generator has to emit a second copy of
   the word. It spans both columns and sits above the first row. */
.lang-sw ul::before{content:attr(aria-label);grid-row:1;grid-column:1/-1;position:sticky;top:-7px;z-index:1;margin:-7px 0 6px;padding:10px 10px 9px;background:var(--surface);box-shadow:7px 0 var(--surface),-7px 0 var(--surface);font-family:var(--label);font-size:.56rem;letter-spacing:.18em;text-transform:uppercase;color:var(--text-mute);border-bottom:1px solid var(--border-2);}
/* Martian Mono at .56rem is the site's label voice, and it is a Latin face:
   in Arabic, Hebrew, Thai, Devanagari or CJK the browser falls back to a
   substitute at 9px, which is unreadable, and uppercase means nothing there.
   Those scripts get the body font at a size they can actually be read at. */
:is([dir="rtl"],:lang(th),:lang(hi),:lang(ja),:lang(ko),:lang(zh)) .lang-sw ul::before{font-family:var(--sans);font-size:.74rem;letter-spacing:.03em;text-transform:none;}

.lang-sw li{display:flex;}
.lang-sw li a,.lang-sw li span{display:flex;flex:1;align-items:center;gap:10px;min-height:36px;padding-block:6px;padding-inline:9px;border-radius:8px;font-size:.88rem;line-height:1.2;text-decoration:none;color:var(--text-dim);white-space:nowrap;transition:color .12s,background .12s;}
.lang-sw li a:hover{color:var(--text);background:color-mix(in srgb,var(--text) 9%,var(--surface));box-shadow:inset 0 0 0 1px var(--border-2);}
.lang-sw li a:focus-visible{outline:2px solid var(--green);outline-offset:-2px;color:var(--text);background:color-mix(in srgb,var(--text) 9%,var(--surface));}
.lang-sw li a:hover .flag,.lang-sw li a:focus-visible .flag{border-color:rgba(216,216,216,.4);}

/* the current language — the green accent, not another grey box */
.lang-sw li [aria-current]{color:var(--green);background:color-mix(in srgb,var(--green) 9%,transparent);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--green) 26%,transparent);cursor:default;}
.lang-sw li [aria-current] .flag{border-color:color-mix(in srgb,var(--green) 45%,transparent);}
.lang-sw li [aria-current]::after{content:"";flex:none;margin-inline-start:auto;width:5px;height:5px;border-radius:50%;background:var(--green);box-shadow:0 0 7px color-mix(in srgb,var(--green) 70%,transparent);}

/* If the panel ever does scroll — a phone, or a desktop window too short for
   ten rows — the bar is the panel's own colours, not a grey system bar. */
.lang-sw ul::-webkit-scrollbar{width:8px;}
.lang-sw ul::-webkit-scrollbar-thumb{background:var(--border);border-radius:99px;border:2px solid var(--surface);}
.lang-sw ul::-webkit-scrollbar-track{background:transparent;}

/* Narrow screens: one column, and a scroll is fine here — there is no room
   for two columns and a phone list is expected to scroll. */
@media(max-width:560px){
  .lang-sw ul{grid-auto-flow:row;grid-template-rows:none;grid-template-columns:minmax(9.6rem,1fr);max-height:min(62dvh,20rem);}
  /* the trigger keeps its name here too — the flag alone would not say
     which of Bahasa Indonesia / Bahasa Melayu you are on. It is tightened
     instead, which buys back the width the phone nav does not have. */
  .lang-sw summary{font-size:.5rem;letter-spacing:.05em;gap:5px;padding:4px 7px 4px 4px;}
  .lang-sw summary .flag{width:18px;height:13px;}
  /* A phone nav is brand + this + "get a key" inside ~330px. Eighteen of the
     twenty names fit in 11ch; Bahasa Indonesia and Bahasa Melayu ellipsize,
     which is better than the CTA being pushed off the side of the screen. */
  .lang-sw summary .lang-cur{max-width:11ch;}
}
@media(prefers-reduced-motion:reduce){.lang-sw summary,.lang-sw summary::after,.lang-sw li a,.lang-sw li span{transition:none;}}

/* rtl — nothing to mirror. inset-inline-end moves the panel to the other
   side, the grid's column flow reverses with the writing direction, and
   padding-inline / margin-inline-start follow on their own. */

/* translation notice — legal pages in every language but English */
.lang-notice{margin:-16px 0 32px;padding:12px 16px;border:1px solid var(--border);border-left:2px solid var(--text-dim);border-radius:var(--radius);background:var(--surface);color:var(--text);font-size:.92rem;line-height:1.5;}
[dir="rtl"] .lang-notice{border-left:1px solid var(--border);border-right:2px solid var(--text-dim);}

/* ===== app pages (console, signup, forgot, reset, admin) — runtime i18n via /i18n.js ===== */

/* i18n.js adds this class in <head> and removes it once the dictionary has
   been applied (or after its timeout). The background still paints, so the
   wait is a dark page, never a white one — and never English becoming Japanese. */
html.i18n-loading body{visibility:hidden;}

/* Where the switcher sits on an app page: the top corner of the auth screens,
   the topbar on the console and admin. Logical insets, so it crosses over
   under dir="rtl" on its own. */
.auth-lang{position:absolute;top:18px;inset-inline-end:20px;z-index:3;}
.topbar .lang-sw summary{padding:7px 10px;}

/* RTL for the app layout. styles.css mirrors the blog's physical left/right
   values; these are the app pages' own. Flex rows, text-align:start and the
   logical insets already follow `dir`, so only physical values need a twin.
   Machine strings — e-mail addresses, keys, ids, money, code — stay ltr. */
[dir="rtl"] .side{border-right:none;border-left:1px solid var(--border);}
@media(max-width:860px){[dir="rtl"] .side{border-left:none;}}
[dir="rtl"] .side-link{text-align:right;}
[dir="rtl"] .msg{border-left:1px solid var(--border);border-right:2px solid var(--text-dim);}
[dir="rtl"] .msg.err{border-right-color:var(--green);}
[dir="rtl"] .think{border-left:none;border-right:2px solid var(--border);border-radius:10px 0 0 10px;}
[dir="rtl"] .plan-ribbon{right:auto;left:0;border-radius:var(--radius) 0 10px 0;}
[dir="rtl"] .plan-feat li{padding-left:0;padding-right:18px;}
[dir="rtl"] .plan-feat li::before{left:auto;right:0;}
[dir="rtl"] .drawer{right:auto;left:0;border-left:none;border-right:1px solid var(--border);transform:translateX(-100%);}
[dir="rtl"] .drawer.open{transform:none;}
[dir="rtl"] .log .sum{text-align:right;}
[dir="rtl"] .log .sum .ip{margin-left:0;margin-right:auto;}
[dir="rtl"] .strip .cell,[dir="rtl"] .stat{text-align:right;}
[dir="rtl"] .auth-card h1,[dir="rtl"] .auth-card .sub,[dir="rtl"] .auth-card .alt,[dir="rtl"] .transcript .empty{text-align:center;}
[dir="rtl"] .auth-brand,[dir="rtl"] .side .brand{direction:ltr;}
[dir="rtl"] input[type="email"],[dir="rtl"] input[type="password"],[dir="rtl"] input[type="number"],
[dir="rtl"] .key-code,[dir="rtl"] .idcol,[dir="rtl"] .num,[dir="rtl"] .balance b,[dir="rtl"] .bal-big,
[dir="rtl"] .msg-turn .text,[dir="rtl"] .think-body,[dir="rtl"] .crypto-addr,[dir="rtl"] .log pre,
[dir="rtl"] .dl .v,[dir="rtl"] .strip .v,[dir="rtl"] .stat .big,[dir="rtl"] .chart-read,
[dir="rtl"] .plan-price,[dir="rtl"] .acct .av{direction:ltr;unicode-bidi:isolate;}
[dir="rtl"] .num{text-align:right;}
