/* The crawlable document around the practice screen.

   Deliberately a separate file from practice.css: that one owns the app, this
   one owns the page it sits in. Both are needed for a generated page; only
   practice.css is needed for the screen itself.

   Geometry follows the "Landing / Practice — Clip" frame (Jam8v): a floating
   nav pill, a 1140px content column, a two-column body with a 360px rail, the
   full transcript as one card below, a CTA band and a footer. Below the rail's
   breakpoint the whole thing is one column and the rail follows the exercise —
   nothing here is positioned, so that reflow is free. */

:root{
  --shell:  1140px;
  --rail:   360px;
  --pad:    14px;
}
@media (min-width:560px){ :root{ --pad:24px; } }

body{ display:flex; flex-direction:column; min-height:100dvh; }

/* The gutter sits OUTSIDE the 1140 column, so the document's content edge lands
   on the same pixel as the nav pill's and the footer's. With the padding inside
   the max-width the two were 24px apart at every desktop size. */
.shell{
  width:100%; max-width:calc(var(--shell) + var(--pad) * 2);
  margin:0 auto;
  padding-inline:var(--pad);
}

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

/* The pill lives in nav.css, which every generated page loads: the catalogue and
   the filter pages carry the same header, and it used to be three stylesheets
   with three different results. Nothing about it belongs here any more. */

/* --- clip header ---------------------------------------------------------- */

.clip-head{ padding-top:26px; }

.crumbs{
  display:flex; flex-wrap:wrap; align-items:center; gap:8px;
  font-size:.86rem; color:var(--ink-2);
  margin-bottom:14px;
}
/* Real links, so real tap targets: the row is one line either way, and 21px of
   it was not reliably hittable with a thumb. */
.crumbs a{
  display:inline-flex; align-items:center; min-height:44px;
  color:var(--ink-2); text-decoration:none; font-weight:500;
}
.crumbs a:hover{ color:var(--ink); }
.crumbs b{ color:var(--ink); font-weight:600; }
.crumbs .ic{ width:13px; height:13px; color:var(--ink-3); }
[dir="rtl"] .crumbs .ic{ transform:scaleX(-1); }
/* On a phone the last crumb is the page's own title, which the <h1> repeats two
   lines below — at 320px that cost three wrapped lines to say nothing. The
   links stay; only the leaf and its separator go. */
@media (max-width:559px){
  /* Two crumbs go on a phone: the leaf, which the <h1> repeats two lines below,
     and "SpeakFox", which the wordmark in the nav already links. What is left is
     the two links a visitor cannot reach any other way — and they fit one row
     without scrolling, where all four wrapped to three. */
  .crumbs b, .crumbs svg:last-of-type{ display:none; }
  .crumbs > a:first-child, .crumbs > svg:first-of-type{ display:none; }
  /* One row that scrolls, rather than two rows with a separator dangling at the
     end of the first. `contain:inline-size` so the trail cannot set the
     document's minimum width, as the control row below it once did. */
  .crumbs{
    flex-wrap:nowrap; overflow-x:auto; scrollbar-width:none;
    contain:inline-size; -webkit-overflow-scrolling:touch;
  }
  .crumbs::-webkit-scrollbar{ display:none; }
  .crumbs > *{ flex:none; }
}

.doc h1{
  font-size:clamp(1.75rem, 5.2vw, 2.9rem);
  font-weight:800; letter-spacing:-.025em; line-height:1.1;
  margin:0 0 14px;
}

.meta{
  display:flex; flex-wrap:wrap; gap:10px;
  list-style:none; margin:0; padding:0;
}
.mchip{
  display:inline-flex; align-items:center; gap:6px;
  background:var(--surface); border:1px solid var(--rule);
  border-radius:999px; padding:6px 12px;
  font-size:.81rem; font-weight:600; color:var(--ink-2);
  white-space:nowrap;
}
.mchip .ic{ width:14px; height:14px; color:var(--ink-3); }

/* No lede under the h1. It restated the four chips above it as a sentence
   ("… 79 lines, 6:46, intermediate level") and the design frame has no such
   paragraph — the h1, the crumb trail and the chips are the whole header. */

/* --- body: exercise + rail ------------------------------------------------ */

.body{
  display:grid; gap:32px;
  padding-top:26px;
}
/* 1140, not 1040: the rail is 360 and the column it leaves at 1040 is 640, which
   is narrower than the one-column layout gets on a tablet. The two-column shape
   starts where the design's own 1140 shell does. */
@media (min-width:1140px){
  .body{ grid-template-columns:minmax(0,1fr) var(--rail); gap:40px; }
  /* The rail is the only thing on the page that may follow the scroll: the
     exercise is taller than the viewport and the download card is what the page
     is for. align-self rather than the grid's align-items, because a stretched
     grid item cannot be sticky. */
  .rail{ position:sticky; top:88px; align-self:start; }
}
.col-main{ min-width:0; }
.rail{ display:grid; gap:16px; align-content:start; min-width:0; }

/* The card is NOT stretched to the rail's height. It was, to close the gap
   between a short exercise and a tall rail — and it closed the gap by opening a
   ~140px empty hole inside a bordered white card, which reads as a rendering
   fault rather than as space. Unused height below the card is invisible; unused
   height inside it is not. */

/* The player wants to be edge to edge on a phone; everything else in the app
   keeps the document's gutter. */
@media (max-width:559px){
  .app{ margin-inline:calc(-1 * var(--pad)); }
  .stage{ border-radius:0; }
  .focus, .notice{ margin-inline:var(--pad); }
}

/* --- cards ---------------------------------------------------------------- */

.rcard{
  background:var(--surface);
  border:1px solid var(--rule);
  border-radius:16px;
  padding:20px;
  box-shadow:var(--shadow-card);
}
.rcard__h{
  margin:0 0 8px;
  font-size:1.3rem; font-weight:800; letter-spacing:-.02em; line-height:1.2;
}

/* --- the App Card's QR + badge row (rail) --------------------------------- */

/* The design's App Card is a QR row, a CTA and the feature list — no heading and
   no subheading, so there are none here. The QR and the button are ONE row: they
   are the same offer aimed at two devices, and stacked they read as two.

   The SVG is committed at lab/practice/qr-appstore.svg (see build_pages.py for
   the one line that made it) — public/img/qr.svg is NOT reused: it carries
   ct=landing_qr and would report these scans as one-pager traffic. */
.getrow{
  display:flex; align-items:center; flex-wrap:wrap; gap:14px;
}
.qr__box{
  flex:none; width:92px; height:92px;
  display:flex; align-items:center; justify-content:center;
  background:var(--quiet); border:1px solid var(--rule); border-radius:10px;
}
.qr__box img{ width:72px; height:72px; display:block; }
/* On a phone the visitor IS holding the device the QR points at — and it is also
   what makes 92 + 162 fit the 292px rail at 320px, by not being there. */
@media (max-width:1139px){
  .qr__box{ display:none; }
}

/* Apple's official badge artwork, used unmodified per their marketing
   guidelines — the same asset and the same rule as the one-pager's hero, so the
   two pages offer the same button rather than two lookalikes. */
.badge{ display:inline-block; flex:none; transition:transform .18s ease; }
.badge img{ height:54px; width:auto; display:block; }
.badge:hover{ transform:translateY(-1px); }
@media (prefers-reduced-motion:reduce){
  .badge{ transition:none; }
  .badge:hover{ transform:none; }
}

.feats{ list-style:none; margin:16px 0 0; padding:0; display:grid; gap:12px; }
.feats li{ display:flex; align-items:center; gap:10px; font-size:.88rem; line-height:1.35; }
.feat__ic{
  flex:none; width:28px; height:28px; border-radius:999px;
  background:var(--accent-w); color:var(--accent-t);
  display:flex; align-items:center; justify-content:center;
}
.feat__ic .ic{ width:15px; height:15px; }

/* --- more like this (rail) ------------------------------------------------ */

.rcard__head{ display:flex; align-items:center; flex-wrap:wrap; gap:4px 10px; margin-bottom:4px; }
.rcard__head .rcard__h{ margin:0; font-size:1.12rem; }
/* The design's "See all →" on the head row. It goes to the level page, which
   exists now — the four clips in this rail are the same category AND level, so
   "more like this" has a real, finite home to point at. */
.seeall{
  display:inline-flex; align-items:center; gap:5px;
  margin-inline-start:auto; min-height:44px;
  font-size:.86rem; font-weight:600; color:var(--accent-t); text-decoration:none;
}
.seeall:hover{ text-decoration:underline; }
.seeall .ic{ width:15px; height:15px; }
[dir="rtl"] .seeall .ic{ transform:scaleX(-1); }

.rels{ list-style:none; margin:0; padding:0; }
.rel{ padding:12px 0; border-top:1px solid var(--rule); }
.rel:first-child{ border-top:0; }
.rel__link{
  display:grid; grid-template-columns:80px minmax(0,1fr); gap:12px;
  align-items:center;
  text-decoration:none; color:var(--ink);
}
.rel__thumb{
  width:80px; height:54px; object-fit:cover;
  border-radius:8px; border:1px solid var(--rule); display:block;
}
/* Two lines, then an ellipsis. Catalogued YouTube titles run to 100 characters
   ("How to Find Directions in the UK | Easy English 65") and in a 200px column
   the long ones took five lines, which turned a four-item list into a column
   taller than the exercise beside it. `-webkit-line-clamp` is the only clamp with
   real support; it needs all four of these declarations, and `min-height` pins
   the two-line box so a one-line title does not shorten its row. */
.rel__title{
  font-size:.88rem; font-weight:700; line-height:1.25;
  display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:2;
  overflow:hidden;
  min-height:calc(2 * 1.25em);
}
.rel__meta{ display:block; margin-top:4px; font-size:.75rem; font-weight:400; color:var(--ink-3); }
.rel__link:hover .rel__title{ color:var(--accent-t); }

/* --- sections below the fold ---------------------------------------------- */

.doc__section{ padding-top:52px; }
.doc h2{
  font-size:clamp(1.4rem, 3.4vw, 2.1rem);
  font-weight:800; letter-spacing:-.02em; line-height:1.15;
  margin:0 0 8px;
}
.doc p{ color:var(--ink-2); }

/* A "Phrases worth learning from this video" grid of mined phrase cards was
   styled here (`.cards`, `.card*`). The section is gone — the design frame has no
   such block between the exercise and the transcript. `.card__at`'s "#line-N"
   links were the in-page callers of app.js's transcript disclosure; the
   disclosure still opens on an incoming hash, which is now the only caller. */

/* --- full transcript ------------------------------------------------------ */

.tcard{
  background:var(--surface);
  border:1px solid var(--rule);
  border-radius:20px;
  padding:6px 20px;
  box-shadow:var(--shadow-card);
  list-style:none; margin:0;
}
@media (min-width:560px){ .tcard{ padding-inline:28px; } }

.tline{
  display:grid;
  grid-template-columns:34px minmax(0,1fr) auto;
  gap:12px;
  align-items:start;
  padding:18px 0;
  border-top:1px solid var(--rule);
}
.tline:first-child{ border-top:0; }
@media (min-width:560px){ .tline{ gap:18px; padding:20px 0; } }

.tline__n{
  width:34px; height:34px; border-radius:999px;
  background:var(--band); color:var(--ink-3);
  display:flex; align-items:center; justify-content:center;
  font-size:.82rem; font-weight:700;
}
/* 19px, not 17: this is the page's body — the whole lesson, and the thing a
   visitor reads longest. It should not be set smaller than the document's own
   font size. */
.tline__x{ font-size:1.12rem; font-weight:700; line-height:1.4; }
/* font-weight:400 explicitly: it is nested inside .tline__x, which is 700, and a
   bold translation under a bold line makes the pair one undifferentiated block
   of heavy text. */
.tline__tr{
  display:block; margin-top:6px;
  color:var(--ink-2); font-size:.92rem; font-weight:400; line-height:1.45;
}
.tline__t{
  font-family:var(--mono); font-size:.78rem; font-weight:500; color:var(--ink-3);
  padding-top:8px;
}
/* 320px: the timestamp is the least load-bearing column, and dropping it buys
   the line 50px it actually needs. It is still in the DOM for a crawler. */
@media (max-width:379px){
  .tline{ grid-template-columns:28px minmax(0,1fr); gap:10px; }
  .tline__n{ width:28px; height:28px; font-size:.76rem; }
  .tline__t{ grid-column:2; padding-top:6px; }
}

/* The transcript is the page's longest section by an order of magnitude: 79
   lines × 2 (English + translation) is 22,795px of Russian phone page, and the
   CTA band and footer are on the far side of it. Beyond TRANSCRIPT_HEAD lines the
   rest sits in a <details>, which keeps every line in the DOM — a crawler and a
   Ctrl+F both still see the whole lesson, and this is not the truncation Google
   penalises. app.js opens it when a phrase card links into it. */
.tmore__sum{
  list-style:none; cursor:pointer;
  display:flex; align-items:center; justify-content:center; gap:8px;
  min-height:48px; margin-top:14px;
  border:1px solid var(--rule); border-radius:999px;
  background:var(--surface);
  font-size:.92rem; font-weight:700; color:var(--ink);
  box-shadow:var(--shadow-card);
}
.tmore__sum::-webkit-details-marker{ display:none; }
.tmore__sum:hover{ background:var(--band); }
.tmore > .tcard{ margin-top:14px; }
/* One control, two labels: the summary says what tapping it will do. */
.tmore__less{ display:none; }
.tmore[open] .tmore__less{ display:inline; }
.tmore[open] .tmore__more{ display:none; }

/* --- closing CTA ---------------------------------------------------------- */

.ctaband{
  margin-top:64px;
  padding:56px var(--pad);
  text-align:center;
}
/* The badge, not a second-shaped dark pill: the one-pager's closing card carries
   the App Store badge in exactly this slot, and the rail's App Card now does too.
   Three download buttons on one page must be one button. */

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

.foot{
  border-top:1px solid var(--rule);
  padding:30px var(--pad) 50px;
  margin-top:auto;
}
.foot__wrap{
  max-width:var(--shell); margin:0 auto;
  display:flex; flex-wrap:wrap; gap:16px 24px;
  align-items:flex-start; justify-content:space-between;
}
.foot__logo{
  display:inline-flex; align-items:center; min-height:44px;
  font-size:1.1rem; font-weight:800; letter-spacing:-.025em;
  text-decoration:none; color:var(--ink);
  direction:ltr; unicode-bidi:isolate;
}
.foot__logo b{ color:var(--accent); }
.foot__copy{ margin:6px 0 0; font-size:.86rem; color:var(--ink-3); }
/* Emitted by footer() in build_pages.py — the same four links the one-pager's
   footer carries, plus "Browse videos", which now has a page to point at. This
   rule styled nothing for a while; a stylesheet describing markup that does not
   exist is a claim that it does. */
.foot__links{ display:flex; flex-wrap:wrap; gap:2px 22px; list-style:none; margin:0; padding:0; }
.foot__links a{
  display:inline-flex; align-items:center; min-height:44px; min-width:44px;
  font-size:.86rem; color:var(--ink-2); text-decoration:none;
}
.foot__links a:hover{ color:var(--ink); }

/* --- written sections ------------------------------------------------------

   The prose about this recording, and the only text on the page that is ours.
   It shares the transcript's container exactly: heading at the shell edge, body
   in a .tcard. It was a 760px column auto-centred in a 1140px shell, which made
   the one block a visitor reads the only one on the page whose edges lined up
   with nothing above or below it.

   The reading measure moved inside the card, onto the paragraphs themselves —
   1140px of running text is ~150 characters a line, which is unreadable, but
   that is a property of the line, not of the block. */

.clipcopy__h{
  /* Not .doc h2's clamp up to 2.1rem: these headings carry a keyword phrase and
     run to eight or ten words, where "Full transcript" is two. At 2.1rem three of
     them in a row outshouted the h1. */
  margin:0 0 12px;
  font-size:clamp(1.2rem,2.8vw,1.45rem);
  font-weight:800; letter-spacing:-.015em; line-height:1.3;
  /* A quoted phrase from the clip can be one long token; on a 320px screen a
     heading is the first thing to push the page sideways. */
  overflow-wrap:anywhere;
}

/* .tcard's 6px block padding is tuned for rows that carry their own 18–20px:
   running text needs its own. */
.clipcopy__card{ padding-block:22px; }

.clipcopy p,
.clipcopy__list li{
  /* 72ch, ~640px: the block is 1140 wide like the transcript above it, but a
     1140px line of running text is ~150 characters and unreadable. The measure
     stays left-aligned rather than centred in the card so the prose lines up with
     its own heading and with the transcript's lines. */
  max-width:72ch;
  font-size:1rem;
  line-height:1.65;
  color:var(--ink-2);
  overflow-wrap:anywhere;
}
.clipcopy p{ margin:0 0 14px; }
.clipcopy p:last-child{ margin-bottom:0; }

.clipcopy__list{
  margin:0;
  padding-inline-start:20px;
}
.clipcopy__list li{ margin:0 0 10px; }
.clipcopy__list li:last-child{ margin-bottom:0; }

/* Paragraphs and a list in the same section: the list is a continuation of the
   sentence above it, not a new block. */
.clipcopy p + .clipcopy__list{ margin-top:-4px; }

/* --- measured -------------------------------------------------------------

   The per-clip figures under the transcript: pace, level, the reduced forms in
   this recording, its rare words. Quiet by design — it is evidence that the
   page knows what it is showing, not a feature pitch. */

/* Same edges as the transcript and the written sections above it — it used to
   be a 760px column centred under a full-width card. */
.measured{
  margin:40px 0 0;
  padding:24px 0 0;
  border-top:1px solid var(--rule,#DAD5CB);
}

.measured__h{
  margin:0 0 14px;
  font-size:1.0625rem;
  font-weight:700;
}

.measured__list{ margin:0; }

.measured__row{
  display:flex;
  flex-wrap:wrap;
  gap:4px 16px;
  padding:9px 0;
  border-bottom:1px solid var(--rule,#DAD5CB);
}

.measured__row dt{
  flex:0 0 200px;
  color:var(--ink-3,#6E6A62);
  font-size:.9375rem;
}

.measured__row dd{
  margin:0;
  flex:1 1 240px;
  font-size:.9375rem;
}

@media (max-width:560px){
  .measured__row dt{ flex-basis:100%; }
}
