/* i18n.css — everything the multi-language engine (assets/js/i18n.js) needs
   that styles.css does not have: the language picker, the right-to-left
   mirror, per-script font stacks, and rules that keep long translations
   inside a 390px phone. Load after styles.css (app.html already does). */

/* ---------- Language pickers ---------------------------------------------- */
/* Gate + register screens: a small "🌐 English" pill, top right (top left in RTL). */
.i18n-gate { display: flex; justify-content: flex-end; margin: -6px 0 8px; font-size: .84rem; }
.i18n-trigger {
  display: inline-flex; align-items: center; gap: 6px; min-height: 44px; padding: 6px 14px;
  border: 1px solid var(--line-2); border-radius: 999px; background: var(--surface); color: var(--ink-2);
  font: inherit; font-size: .84rem; font-weight: 600; line-height: 1.2; text-decoration: none;
  cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.i18n-trigger:hover { border-color: var(--primary); color: var(--primary-dark); }
.i18n-trigger:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.i18n-globe { font-size: 1.02em; line-height: 1; }
.i18n-name, .i18n-opt-name { font-family: var(--sans); }

/* Both lists are role="listbox": one tab stop, arrow keys move, Enter / Space / tap applies. */
.i18n-listbox { list-style: none; margin: 0; padding: 0; }
.i18n-opt {
  display: flex; align-items: center; gap: 10px; min-height: 44px; color: var(--ink);
  font-size: 1rem; line-height: 1.25; text-align: start; cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.i18n-opt:focus { outline: none; }
.i18n-opt:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
.i18n-opt-name { min-width: 0; overflow-wrap: anywhere; }
.i18n-opt-sub { margin-inline-start: auto; font-size: .78rem; font-weight: 400; color: var(--muted); text-align: end; }
.i18n-opt-mark { flex: 0 0 18px; margin-inline-start: auto; text-align: center; color: var(--primary); font-weight: 700; }
.i18n-opt-sub + .i18n-opt-mark { margin-inline-start: 0; }
.i18n-opt[aria-selected="true"] .i18n-opt-mark::before { content: "\2713"; }
.i18n-opt[aria-busy="true"] .i18n-opt-mark::before { content: "\2026"; color: var(--muted); }
.i18n-opt.i18n-fail { opacity: .55; }
.i18n-opt.i18n-fail .i18n-opt-mark::before { content: "\2715"; color: var(--muted); }

/* Settings → Language: all 29 at a glance, two columns on a phone. */
.i18n-langs { display: grid; grid-template-columns: repeat(auto-fill, minmax(136px, 1fr)); gap: 6px; margin: 10px 0 2px; }
.i18n-langs .i18n-opt {
  gap: 6px; padding: 8px 10px; padding-inline: 11px 9px; border: 1px solid var(--line-2); border-radius: var(--radius-sm);
  background: var(--surface); font-size: .92rem;
}
.i18n-langs .i18n-opt:not([aria-selected="true"]):not([aria-busy]):not(.i18n-fail) .i18n-opt-mark { display: none; }
.i18n-langs .i18n-opt:hover { border-color: var(--primary); }
.i18n-langs .i18n-opt[aria-selected="true"] {
  background: var(--primary-soft); border-color: var(--primary); color: var(--primary-dark); font-weight: 650;
}

/* The overlay list: a bottom sheet on phones, a centred dialog on wider screens. */
.i18n-sheet { position: fixed; inset: 0; z-index: 400; display: flex; align-items: flex-end; justify-content: center; }
.i18n-sheet[hidden] { display: none; }
.i18n-sheet-backdrop { position: absolute; inset: 0; background: rgba(6, 36, 30, .5); }
.i18n-sheet-panel {
  position: relative; width: 100%; max-width: 480px; max-height: 86vh; max-height: min(86dvh, 680px);
  display: flex; flex-direction: column; background: var(--surface); color: var(--ink);
  border-radius: 18px 18px 0 0; box-shadow: 0 -10px 40px rgba(6, 36, 30, .25);
  padding-bottom: env(safe-area-inset-bottom); animation: i18nIn .18s ease-out;
}
@keyframes i18nIn { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .i18n-sheet-panel { animation: none; } }
.i18n-sheet-head { display: flex; align-items: center; gap: 8px; padding: 6px 6px 6px 18px; padding-inline: 18px 6px; border-bottom: 1px solid var(--line); }
.i18n-sheet-title { margin: 0; font-size: 1.05rem; line-height: 1.3; }
.i18n-sheet-x {
  margin-inline-start: auto; width: 44px; height: 44px; flex: 0 0 44px; border: 0; border-radius: 50%;
  background: none; color: var(--muted); font: inherit; font-size: 1.1rem; cursor: pointer;
}
.i18n-sheet-x:hover { background: var(--surface-2); color: var(--ink); }
.i18n-sheet-x:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
.i18n-sheet-list { padding: 6px 0 10px; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }
.i18n-sheet-list .i18n-opt { min-height: 48px; padding: 8px 18px; }
.i18n-sheet-list .i18n-opt:hover { background: var(--surface-2); }
.i18n-sheet-list .i18n-opt[aria-selected="true"] { background: var(--primary-soft); color: var(--primary-dark); font-weight: 650; }
html.i18n-sheet-open, html.i18n-sheet-open body { overflow: hidden; }
@media (min-width: 600px) {
  .i18n-sheet { align-items: center; padding: 24px; }
  .i18n-sheet-panel { max-width: 420px; border-radius: 18px; box-shadow: 0 24px 60px rgba(6, 36, 30, .35); }
}

/* First paint for a returning non-English visitor: hidden until the
   dictionary has been applied (i18n.js lifts it after 2.5 s at the latest). */
html.i18n-wait body { visibility: hidden; }
/* Before i18n.js has run at all (it sits near the end of <body>), the static tab
   bar would paint in English while the scripts above it download. It waits for
   i18n.js (html.i18n-ready), and shows after 3 s whatever happens. Skipped under
   reduced motion, where styles.css switches animations (the failsafe) off. */
@media (prefers-reduced-motion: no-preference) {
  html:not(.i18n-ready) #tabbar { visibility: hidden; animation: i18nReveal 0s linear 3s forwards; }
}
@keyframes i18nReveal { to { visibility: visible; } }

/* ---------- 7-tab bar: every language fits ------------------------------
   dates.css keeps labels on one clipped line (fine for English). Translated
   labels may wrap to two lines and are never clipped; i18n.js steps the font
   down when one word is still wider than its tab. */
@media (max-width: 899px) {
  html:not([lang="en"]) .tabbar .tab {
    white-space: normal; overflow: visible; line-height: 1.15; text-align: center;
    overflow-wrap: anywhere; text-wrap: balance;
  }
}

/* ---------- Script fonts (system fonts only) -----------------------------
   The base --sans stack (SF, Segoe UI, Inter, Roboto, Helvetica Neue, Arial) has
   Latin, Greek, Cyrillic and Vietnamese glyphs, so el/ru/uk/vi need nothing.
   CJK, Thai, Devanagari and Arabic get their platform fonts by name before
   the generic fallback, so the right glyph variant is used (SC vs TC vs JP). */
:root:lang(zh-CN), :lang(zh-CN) {
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB",
    "Microsoft YaHei UI", "Microsoft YaHei", "Noto Sans CJK SC", "Noto Sans SC", "Source Han Sans SC",
    "WenQuanYi Micro Hei", sans-serif;
}
:root:lang(zh-TW), :lang(zh-TW) {
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang TC", "Microsoft JhengHei UI",
    "Microsoft JhengHei", "Noto Sans CJK TC", "Noto Sans TC", "Source Han Sans TC", sans-serif;
}
:root:lang(ja), :lang(ja) {
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Hiragino Sans", "Hiragino Kaku Gothic ProN",
    "Yu Gothic UI", "Yu Gothic", Meiryo, "Noto Sans CJK JP", "Noto Sans JP", sans-serif;
}
:root:lang(ko), :lang(ko) {
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Apple SD Gothic Neo", "Malgun Gothic",
    "Noto Sans CJK KR", "Noto Sans KR", "Nanum Gothic", sans-serif;
}
:root:lang(th), :lang(th) {
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Thonburi, "Leelawadee UI", Leelawadee,
    "Noto Sans Thai UI", "Noto Sans Thai", Tahoma, sans-serif;
}
:root:lang(hi), :lang(hi) {
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Kohinoor Devanagari", "Devanagari Sangam MN",
    "Nirmala UI", "Noto Sans Devanagari UI", "Noto Sans Devanagari", Mangal, sans-serif;
}
:root:lang(ar), :lang(ar) {
  --sans: -apple-system, BlinkMacSystemFont, "SF Arabic", "Geeza Pro", "Segoe UI", Roboto,
    "Noto Sans Arabic UI", "Noto Sans Arabic", "Noto Naskh Arabic", Tahoma, sans-serif;
}

/* Taller scripts: room for marks above and below the line. */
html:is([lang="th"], [lang="hi"], [lang="ar"]) body { line-height: 1.75; }
html:is([lang="th"], [lang="hi"], [lang="ar"]) :is(h1, h2, h3, h4, .step h2, .study-what, .dates-title, .sess-main, .month-title) { line-height: 1.45; }
html:is([lang="th"], [lang="hi"], [lang="ar"]) .tabbar .tab { line-height: 1.35; }
/* Letter-spacing breaks Arabic joining and spaces out Thai / Devanagari clusters. */
html:is([lang="th"], [lang="hi"], [lang="ar"]) * { letter-spacing: normal !important; }

/* ---------- Line breaking ------------------------------------------------ */
/* Safety net for every translation: a word longer than its whole line breaks
   instead of overflowing. break-word (not anywhere): it does not shrink a flex
   item's minimum width, so "Entfernen" or "8/28/2026" are never cut in two to
   make room for their neighbour. */
html:not([lang="en"]) body { overflow-wrap: break-word; }
/* Chinese / Japanese: strict kinsoku (no line starts with 。、」 or small kana). Korean: break between words. */
html:is([lang="ja"], [lang="zh-CN"], [lang="zh-TW"]) body { line-break: strict; word-break: normal; }
html[lang="ko"] body { word-break: keep-all; }
/* Long compounds (de, fi, hu, nl, ru …): real hyphens in running text … */
html:is([lang="de"], [lang="nl"], [lang="da"], [lang="sv"], [lang="no"], [lang="fi"], [lang="hu"], [lang="pl"],
  [lang="cs"], [lang="ru"], [lang="uk"], [lang="el"]) body {
  -webkit-hyphens: auto; hyphens: auto; hyphenate-limit-chars: 12 5 5;
  -webkit-hyphenate-limit-before: 5; -webkit-hyphenate-limit-after: 5;
}
/* … and in the narrow UI pieces of every alphabetic language. */
html:is([lang="de"], [lang="nl"], [lang="da"], [lang="sv"], [lang="no"], [lang="fi"], [lang="hu"], [lang="pl"],
  [lang="cs"], [lang="ru"], [lang="uk"], [lang="el"], [lang="ro"], [lang="tr"], [lang="fr"], [lang="it"],
  [lang="es"], [lang="pt-BR"], [lang="id"], [lang="ms"])
  :is(h1, h2, h3, h4, button, .btn, .chip, .tab, label, .card-head, .pill, .sev, .lvl, .gpa-lab, .qbtn,
      .month-title, .goal-name, .dates-title, .course-name, .meter-label, .step-eyebrow, .dates-tag) {
  -webkit-hyphens: auto; hyphens: auto; hyphenate-limit-chars: 7 3 3;
  -webkit-hyphenate-limit-before: 3; -webkit-hyphenate-limit-after: 3;
}
/* A placeholder (or chosen option) longer than its field ends in "…" instead of a cut letter. */
html:not([lang="en"]) :is(input:not([type="checkbox"]):not([type="radio"]), select) { text-overflow: ellipsis; }
/* GPA boxes: three equal columns even when one label is a long word ("НЕВЗВЕШЕННЫЙ");
   i18n.js then steps the label font down until the word fits. */
html:not([lang="en"]) .gpa-row { grid-template-columns: repeat(3, minmax(0, 1fr)); }
/* Roadmap year chips: all four stay visible (wrap) instead of scrolling the current one away. */
html:not([lang="en"]) .yearpick { flex-wrap: wrap; overflow-x: visible; }
/* One-line pills that may now hold a longer phrase: let them wrap. */
html:not([lang="en"]) .parent-banner { white-space: normal; max-width: calc(100vw - 24px); text-align: center; }
html:not([lang="en"]) .share-grid .btn { white-space: normal; }
/* styles.css's landing-page ".meter-row { grid-template-columns: 92px 1fr 52px }"
   also hits the app's meters (#meters, #parent-meters): a translated track name
   ("Kursanspruch", "Волонтёрство") needs more than 92px. Same look, flexible label. */
html:not([lang="en"]) .meters .meter-row { grid-template-columns: minmax(0, 1fr) auto; }
/* Two-part rows (History totals, logs, dates): a long value wraps instead of
   squeezing the label down to one letter per line. */
html:not([lang="en"]) .logitem .when { white-space: normal; text-align: end; }
html:not([lang="en"]) .logitem > span:not(.when):not(.dot) { overflow-wrap: break-word; }
/* Card heads: the button keeps its word whole; the heading wraps at spaces. */
html:not([lang="en"]) .card-head > :is(.btn, button) { flex-shrink: 0; max-width: 62%; overflow-wrap: break-word; }
html:not([lang="en"]) .card-head > :is(h2, h3) { overflow-wrap: break-word; }
/* Roadmap month tags: the column is as wide as the longest tag (i18n.js sets
   --i18n-mtag; unset = the English 34px) and the step list lines up under it. */
#view-roadmap .month-tag { width: var(--i18n-mtag, 34px); flex-basis: var(--i18n-mtag, 34px); }
#view-roadmap .nudges { padding-left: calc(var(--i18n-mtag, 34px) + 10px); }
/* Dates tab: the date column likewise ("Toukokuu 1", "травень 1"; --i18n-dwhen, 64px in English). */
#view-dates .dates-when { flex: 0 0 var(--i18n-dwhen, 64px); }

/* ---------- Right-to-left (ar; any language with dir=rtl) ----------------
   Flex and grid rows, inputs and text already follow dir; these are the
   places styles.css spells out a physical left or right. */
html[dir="rtl"] .stage-chip,
html[dir="rtl"] .card-head .muted,
html[dir="rtl"] #view-dates .card-head > .btn,
html[dir="rtl"] .streak,
html[dir="rtl"] .goal-val,
html[dir="rtl"] .logitem .when,
html[dir="rtl"] .picker-item .premed { margin-left: 0; margin-right: auto; }
html[dir="rtl"] .chip { margin: 0 0 6px 6px; }
html[dir="rtl"] .step { border-left: 1px solid var(--line); border-right: 5px solid var(--step-color, var(--primary)); }
html[dir="rtl"] .step-why { padding-left: 0; padding-right: 12px; border-left: 0; border-right: 2px solid var(--line-2); }
html[dir="rtl"] .study-why { padding-left: 0; padding-right: 11px; border-left: 0; border-right: 2px solid var(--line-2); }
html[dir="rtl"] .note-inline {
  border-left: 0; border-right: 3px solid var(--slipping);
  border-radius: var(--radius-sm) 0 0 var(--radius-sm);
}
html[dir="rtl"] .qbtn { text-align: right; }
html[dir="rtl"] .nudges,
html[dir="rtl"] #view-roadmap .nudges { padding-left: 0; padding-right: calc(var(--i18n-mtag, 34px) + 10px); }
html[dir="rtl"] .nudges li { padding: 5px 20px 5px 0; }
html[dir="rtl"] .nudges li::before { left: auto; right: 0; }
/* The chevron "›" is mirrored by bidi to "‹"; open it downwards, not upwards. */
html[dir="rtl"] .month.open .chev { transform: rotate(-90deg); }
html[dir="rtl"] .ask-user { margin-left: 0; margin-right: auto; border-radius: 14px 14px 14px 3px; }
html[dir="rtl"] .ask-bot { border-radius: 14px 14px 3px 14px; }
html[dir="rtl"] .ask-msg ul { padding-left: 0; padding-right: 1.15em; }
html[dir="rtl"] .step-how ol { padding-left: 0; padding-right: 22px; }
html[dir="rtl"] .pw-wrap input { padding-right: 12px; padding-left: 44px; }
html[dir="rtl"] .pw-toggle { right: auto; left: 6px; }
html[dir="rtl"] .parent-back { right: auto; left: 14px; }
html[dir="rtl"] .course-grade input,
html[dir="rtl"] .sectionscore input { text-align: left; }
/* Progress bars fill from the right; the inline left:% tick moves with them. */
html[dir="rtl"] .meter-bar,
html[dir="rtl"] .goal-bar { direction: ltr; transform: scaleX(-1); }
/* Emails, URLs, phone numbers and numbers are typed left to right. */
html[dir="rtl"] :is(input[type="email"], input[type="url"], input[type="tel"], input[type="number"]) { direction: ltr; text-align: right; }
html[dir="rtl"] .code-input { direction: ltr; }
/* Inline styles in app.html / app.js that name a side. */
html[dir="rtl"] input[type="checkbox"][style*="margin-right"] { margin-right: 0 !important; margin-left: 8px !important; }
html[dir="rtl"] .card[style*="border-left"] { border-left: 1px solid var(--line) !important; border-right: 4px solid var(--primary) !important; }
html[dir="rtl"] .card[style*="border-left"][style*="critical"] { border-right-color: var(--critical, #B3261E) !important; }
html[dir="rtl"] .card[style*="border-left"][style*="#C2661C"] { border-right-color: #C2661C !important; }
/* Uppercase eyebrows: tracking only suits Latin capitals. */
html[dir="rtl"] :is(.step-eyebrow, .tour-eyebrow, .gpa-lab, .month-tag, .lvl, .sev, .dates-month, .feas .verdict) { letter-spacing: 0; }
/* English content inside an RTL page keeps its own direction (i18n.js sets
   dir="ltr" + data-i18n-dir on it), so it gets the left-to-right sides back. */
html[dir="rtl"] .nudges li[data-i18n-dir] { padding: 5px 0 5px 20px; }
html[dir="rtl"] .nudges li[data-i18n-dir]::before { left: 0; right: auto; }
html[dir="rtl"] li[data-i18n-dir] { list-style-position: inside; }
html[dir="rtl"] .step-why[data-i18n-dir] { padding-right: 0; padding-left: 12px; border-right: 0; border-left: 2px solid var(--line-2); }
html[dir="rtl"] .study-why[data-i18n-dir] { padding-right: 0; padding-left: 11px; border-right: 0; border-left: 2px solid var(--line-2); }
html[dir="rtl"] .note-inline[data-i18n-dir] {
  border-right: 0; border-left: 3px solid var(--slipping); border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
html[dir="rtl"] .ask-msg[data-i18n-dir] ul { padding-right: 0; padding-left: 1.15em; }
