/* The "Practice by level" catalogue — design frame Ixvfs.

   Self-contained on purpose: this page does not load practice.css or page.css,
   because it is not the practice screen and must not inherit the app's chrome.
   Every directional property here is logical (inline-start/end, not left/right)
   — /ar/ renders dir="rtl" and a stray `margin-left` breaks only that locale,
   which nobody here reads. */

:root{
  --paper:#F2F0EC;
  --ink:#14130F;
  --ink-2:#56534B;
  --ink-3:#6E6A62;
  --rule:#DAD5CB;
  --card:#FFFFFF;
  --accent:#FF6B00;      /* fills and glyphs only — 2.5:1, never text */
  --accent-t:#A34300;    /* the accent as text */
  --wrap:1140px;
  --pad:20px;
  --font:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
  --mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  /* The site's own display face (public/index.html), copied verbatim so this
     page's headings are the same shape as speakfox.app's. Still no webfont:
     ui-rounded is Apple's SF Pro Rounded, the face the App Store screenshots
     use, and everything after it is a graceful fallback.
     Hiragino Maru Gothic is deliberately absent — Chrome ignores ui-rounded and
     Hiragino's Cyrillic is full-width, which rendered a Russian H1 as
     Т ы   п о н и м а е ш ь. It is re-added for lang="ja" below. */
  --display:ui-rounded,"SF Pro Rounded",
            -apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif;
}

html[lang="ja"]{
  --display:ui-rounded,"SF Pro Rounded","Hiragino Maru Gothic ProN",
            -apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif;
}

*,*::before,*::after{ box-sizing:border-box; }

html{ -webkit-text-size-adjust:100%; }

body{
  margin:0;
  background:var(--paper);
  color:var(--ink);
  font-family:var(--font);
  font-size:16px;
  line-height:1.5;
  /* German and Russian pushed a table 68px past a 320px viewport once. This is
     the only value that also lowers min-content sizing, so a long compound word
     can no longer set the page's minimum width. */
  overflow-wrap:anywhere;
}

img{ max-width:100%; display:block; }

.wrap{
  max-width:var(--wrap);
  margin:0 auto;
  padding:0 var(--pad) 64px;
}

.i{
  width:1em; height:1em; flex:none;
  fill:none; stroke:currentColor; stroke-width:2;
  stroke-linecap:round; stroke-linejoin:round;
}

/* --- nav ----------------------------------------------------------------- */

/* The pill lives in nav.css, loaded by this page, the clip page and the filter
   pages alike. It used to be duplicated here as .top/.pill with its links
   centred, so the header changed shape when a visitor moved between our own
   pages. Markup comes from chrome.py; do not re-add a header to by_level.html. */

/* --- page head ------------------------------------------------------------ */

/* 12px is the floor for anything a visitor has to read; .68rem (10.9px) was
   under it, and the links were 13px tall. */
.crumbs{
  font-family:var(--mono); font-size:.75rem; letter-spacing:.07em;
  text-transform:uppercase; color:var(--ink-3);
  padding-top:12px;
}
.crumbs a{
  display:inline-block; padding-block:13px;
  color:var(--ink-3); text-decoration:none;
}
.crumbs a:hover{ color:var(--ink); }

.h1{
  font-family:var(--display);
  font-size:clamp(1.9rem,6vw,2.875rem);
  font-weight:800; letter-spacing:-.02em; line-height:1.1;
  margin:16px 0 0;
}
.lede{
  max-width:560px;
  margin:16px 0 0;
  color:var(--ink-2);
  font-size:clamp(1rem,2.4vw,1.19rem);
}

.chips{
  display:flex; flex-wrap:wrap; gap:10px;
  margin-top:24px;
}
/* Baseline-aligned, not centre-aligned, and the height comes from padding rather
   than from min-height: `align-items:center` centred the two BOXES, and the count
   is a 12px mono glyph inside a box with different metrics from the 15px label,
   so it sat ~2px low against a word it is supposed to read as part of. Baseline
   alignment lines up the digits with the label whatever the two fonts do.
   The height is then padding + the baseline-aligned line box (22px, not 20: the
   12px count's descent hangs below the label's) + borders = the same 44px tap
   target min-height was buying. Every chip measures 44 whether it carries a
   count or not, which min-height could not promise once the box grew. */
.chip{
  display:inline-flex; align-items:baseline; gap:7px;
  padding:10px 16px; border-radius:999px;
  line-height:20px;
  border:1px solid var(--rule); background:var(--card);
  color:var(--ink); text-decoration:none;
  font-size:15px; font-weight:600;
}
.chip:hover{ border-color:var(--ink-3); }
.chip[aria-current]{
  background:var(--ink); border-color:var(--ink); color:#fff;
}
/* No line-height of its own: it must inherit the chip's, or its box grows the
   row and the baseline it was aligned to moves. */
.chip__n{
  font-family:var(--mono); font-size:12px; font-weight:600;
  color:var(--ink-3);
}
.chip[aria-current] .chip__n{ color:#ffffffa6; }

/* --- level sections ------------------------------------------------------- */

/* minmax(0,1fr), not 1fr: a grid item's automatic minimum is its content, so
   the scrolling row would size the column to all twelve cards and push the
   whole page sideways instead of scrolling. */
.lvls{ margin-top:44px; display:grid; grid-template-columns:minmax(0,1fr); gap:46px; }
.lvl{ min-width:0; }

.lvl__head{
  display:flex; align-items:center; justify-content:space-between;
  flex-wrap:wrap; gap:10px 16px;
  margin-bottom:20px;
}
.lvl__h{
  font-family:var(--display);
  font-size:clamp(1.35rem,4vw,1.625rem);
  font-weight:800; letter-spacing:-.5px; line-height:1.2;
  margin:0;
}
.lvl__ctl{ display:flex; align-items:center; gap:14px; }

.seeall{
  display:inline-flex; align-items:center; gap:4px;
  min-height:44px;
  color:var(--accent-t); text-decoration:none;
  font-size:15px; font-weight:600;
}
.seeall:hover{ text-decoration:underline; }
.seeall .i{ width:15px; height:15px; }
[dir="rtl"] .seeall .i,[dir="rtl"] .rowbtn .i{ transform:scaleX(-1); }

.rowbtn{
  width:44px; height:44px; flex:none;
  display:inline-flex; align-items:center; justify-content:center;
  border:1px solid var(--rule); border-radius:999px;
  background:var(--card); color:var(--ink);
  cursor:pointer;
}
.rowbtn .i{ width:18px; height:18px; }
.rowbtn:hover{ border-color:var(--ink-3); }
.rowbtn:disabled{ opacity:.35; cursor:default; }
.rowbtn[hidden]{ display:none; }

/* The row is a native scroller. The buttons above only nudge it, so with the
   script absent (or on any touch device) the section still works. */
.lvl__row{
  display:flex; gap:20px;
  margin:0; padding:0 0 6px; list-style:none;
  overflow-x:auto;
  /* mandatory, not proximity: proximity is a suggestion Safari mostly ignores,
     and the shelf idiom this borrows (every card snap-aligned to start) is what
     makes a half-visible next card feel like a swipe rather than a drag. */
  scroll-snap-type:x mandatory;
  /* a horizontal fling inside the row must not become the browser's back
     gesture or scroll the page sideways */
  overscroll-behavior-x:contain;
  -webkit-overflow-scrolling:touch;
  scrollbar-width:thin;
  /* the row bleeds to the viewport edge on phones, so a card is never cut off
     flush against the screen */
  scroll-padding-inline-start:var(--pad);
}
.lvl__row > .card{ scroll-snap-align:start; }
/* The row is a tab stop (tabindex="0") so it can be scrolled from the keyboard,
   and a tab stop with no visible ring is a keyboard user lost on the page. The
   :focus-visible rule at the end of this file only covers a/button/summary.
   The offset is inset because on phones the row bleeds past both viewport
   edges, where an outer ring would be drawn off-screen. */
.lvl__row:focus-visible{
  outline:2px solid var(--accent-t); outline-offset:-2px;
  border-radius:10px;
}

.lvl__grid{
  display:grid; gap:24px 20px;
  grid-template-columns:repeat(auto-fill,minmax(220px,1fr));
  margin:0; padding:0; list-style:none;
}

/* --- card ----------------------------------------------------------------- */

.card{ min-width:0; display:flex; flex-direction:column; }
.card__link{ display:flex; flex-direction:column; flex:1; }
/* the title takes the slack so the meta line sits on one baseline across a
   row whose titles wrap to different heights */
.card__title{ flex:1; }
.lvl__row > .card{ flex:0 0 252px; max-width:78vw; }

.card__link{ text-decoration:none; color:inherit; }
.card__thumb{
  position:relative; display:block;
  aspect-ratio:16/9;
  border-radius:14px; overflow:hidden;
  /* Sits behind the thumbnail: if YouTube's image never arrives the card is
     still a card, not a hole. */
  background:linear-gradient(120deg,#3B5BDB,#7048E8);
}
.card__thumb img{
  width:100%; height:100%; object-fit:cover;
}
/* The level label sits under the thumbnail, not on it. Two reasons, and the
   first one is a rule:
   1. On the thumbnail it was 11px white on #FF6B00 — 2.86:1, and CLAUDE.md is
      explicit that #FF6B00 is for fills and glyphs, never behind text. Here the
      accent is a 6% tint and the text is --accent-t on it: 7.4:1.
   2. It was sized for "A1" and holds up to eleven characters — "Intermediate",
      "Продвинутый". At 320px that overlay covered 33–40% of the image, and
      shrinking the type to fit would have taken it under 12px. Off the image it
      can be as long as the locale needs and costs no picture.
   The duration badge stays on the thumbnail: it is never longer than 7
   characters and white on a near-black scrim is 12:1. */
.card__lvl{
  align-self:flex-start;
  margin-top:10px; padding:2px 9px;
  border-radius:999px;
  background:#FF6B0014; color:var(--accent-t);
  font-size:12px; font-weight:700; line-height:18px;
  letter-spacing:.01em;
  /* No white-space:nowrap. Both current locales fit on one line at every width,
     but a longer level name in a locale added later would have overflowed the
     card instead of wrapping inside the pill. */
  max-inline-size:100%;
}
[dir="rtl"] .card__lvl{ align-self:flex-end; }
.card__dur{
  position:absolute;
  inset-block-end:8px; inset-inline-end:8px;
  font-family:var(--mono); font-size:12px; line-height:1.4;
  color:#fff;
  background:#000000b3; font-weight:600;
  padding:2px 7px; border-radius:5px;
}
.card__title{
  display:block; margin-top:7px;
  font-size:16px; font-weight:600; line-height:1.3;
}
.card__link:hover .card__title{ text-decoration:underline; }
.card__meta{
  margin:8px 0 0;
  color:var(--ink-3); font-size:13px;
}

/* --- get the app ---------------------------------------------------------- */

.get{
  margin-top:56px; padding:28px;
  background:var(--card); border:1px solid var(--rule); border-radius:20px;
}
.get__h{ margin:0; font-family:var(--display); font-size:1.25rem; font-weight:800; letter-spacing:-.3px; }
.get__p{ margin:8px 0 0; color:var(--ink-2); }
.get__cta{
  display:inline-flex; align-items:center; justify-content:center;
  min-height:48px; margin-top:18px;
  padding:12px 24px; border-radius:999px;
  background:var(--ink); color:#fff;
  font-weight:600; text-decoration:none;
}
.get__cta:hover{ background:#2b2924; }

/* --- footer --------------------------------------------------------------- */

.foot{ border-top:1px solid var(--rule); }
.foot__in{
  max-width:var(--wrap); margin:0 auto;
  padding:30px var(--pad) 50px;
  display:flex; flex-wrap:wrap; justify-content:space-between; gap:20px 22px;
}
.foot__c{ margin:6px 0 0; color:var(--ink-3); font-size:14px; }
.foot__nav{ display:flex; flex-wrap:wrap; align-items:center; gap:0 22px; }
/* min-width as well as min-height: "Terms" and "TikTok" render 40-42px wide,
   so a 44px-tall link was still a sub-44px target on the axis nobody checks. */
.foot__nav a{
  display:inline-flex; align-items:center; justify-content:center;
  min-height:44px; min-width:44px;
  color:var(--ink-2); text-decoration:none; font-size:14px;
}
.foot__nav a:hover{ color:var(--ink); }

/* --- small screens -------------------------------------------------------- */

/* The language menu's own small-screen behaviour lives in nav.css with the rest
   of the header. */

@media (max-width:760px){
  :root{ --pad:16px; }
  .wrap{ padding-bottom:44px; }
  /* Arrow buttons are a mouse affordance; a finger already scrolls the row. */
  .lvl__ctl .rowbtn{ display:none; }
  /* Let the row run to both edges of the viewport so it reads as scrollable, and
     end with a gutter so the last card does not sit flush against the glass. */
  .lvl__row{
    margin-inline:calc(var(--pad) * -1);
    padding-inline:var(--pad);
    scroll-padding-inline:var(--pad);
  }
  .lvls{ margin-top:30px; gap:34px; }
  .lvl__head{ margin-bottom:14px; }
  /* Stacked, always. Whether "See all X" fit beside the heading depended on how
     long that level's name is in that language, so three sections on one screen
     showed three different layouts — "Смотреть все (Начальный)" wrapped where
     "Смотреть все (Средний)" did not. */
  .lvl__head{ flex-direction:column; align-items:flex-start; gap:0; }

  .get{ margin-top:40px; padding:20px; }
  .foot__in{ padding-block:16px 34px; }
  .foot__nav{ gap:0 18px; }
}

@media (max-width:560px){
  .lvl__row > .card{ flex-basis:220px; }
  /* One shelf idiom, used twice: the chips scroll for the same reason the rows
     do. Wrapped, four long Russian labels took three lines and pushed the first
     shelf below the fold; crushed, they would have been unreadable. */
  .chips{
    flex-wrap:nowrap; overflow-x:auto;
    margin-inline:calc(var(--pad) * -1);
    padding-inline:var(--pad);
    scroll-snap-type:x proximity;
    scroll-padding-inline:var(--pad);
    overscroll-behavior-x:contain;
    -webkit-overflow-scrolling:touch;
    scrollbar-width:none;
  }
  .chips::-webkit-scrollbar{ display:none; }
  .chip{ flex:none; scroll-snap-align:start; }
  .chips:focus-visible{ outline:2px solid var(--accent-t); outline-offset:-2px; }
  /* 320px: the h1 is the only thing that needs the full width, so the lede and
     the crumbs give some of their leading back. */
  .lede{ margin-top:12px; }
}

@media (max-width:380px){
  /* 200px, not 190: at 190 the Russian card title wrapped to four lines. 200
     still leaves an ~88px peek of the next card at 320px, which is what makes
     the shelf read as swipeable. */
  .lvl__row > .card{ flex-basis:200px; }
}

@media (prefers-reduced-motion:reduce){
  *{ scroll-behavior:auto !important; }
}

:where(a,button,summary):focus-visible{
  outline:2px solid var(--accent-t); outline-offset:2px; border-radius:6px;
}

.sr{
  position:absolute; width:1px; height:1px;
  margin:-1px; padding:0; border:0;
  overflow:hidden; clip-path:inset(50%); white-space:nowrap;
}
