/* Sazbauer — minimal serverful app: main page + import by link. */
:root{
  --blue:#3B82F6;--blue-deep:#1D4ED8;--red:#ED2939;--ink:#0F1B2D;--mut:#5B7186;
  --line:#E2E8F0;--surface:#fff;--bg:#F6F8FB;
  accent-color:var(--blue);color-scheme:light dark;
}
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html,body{margin:0;padding:0}
body{
  font:500 15px/1.5 -apple-system,'Segoe UI',Roboto,Inter,sans-serif;color:var(--ink);
  background:radial-gradient(900px 500px at 90% -12%,rgba(59,130,246,.12),transparent 60%),linear-gradient(180deg,#FBFDFF,#F1F6FC);
  min-height:100vh;padding:196px 14px calc(30px + env(safe-area-inset-bottom));
}
.hidden{display:none!important}
.sr-only{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}
/* a press should be FELT. Nothing moved under a finger anywhere in the app —
   on a touch screen that reads as a tap that did not land, and it is the
   cheapest modern polish there is. */
.btn{border:0;border-radius:999px;padding:10px 16px;font:700 14px/1 inherit;font-family:inherit;cursor:pointer;min-height:44px;
  transition:transform .08s ease,filter .15s ease,background .15s ease}
.btn:active{transform:scale(.97)}
.btn-primary{background:var(--blue-deep);color:#fff;box-shadow:0 10px 24px -12px rgba(29,78,216,.5)}
.btn-primary:hover{filter:brightness(1.08)}
.btn-ghost{background:rgba(59,130,246,.12);color:var(--blue-deep)}
.btn-ghost:hover{background:rgba(59,130,246,.22)}
/* every button responds INSTANTLY to a press, so nothing feels dead on tap */
button:active{transform:scale(.97)}
button:disabled{opacity:.55;cursor:default;transform:none}
/* the top loading bar (indeterminate) — visible while any request is in flight */
#loadBar{position:fixed;top:0;left:0;right:0;height:3px;z-index:2000;pointer-events:none;opacity:0;transition:opacity .25s;overflow:hidden}
#loadBar.on{opacity:1}
#loadBar::before{content:"";position:absolute;top:0;left:0;height:100%;width:35%;border-radius:0 3px 3px 0;background:linear-gradient(90deg,transparent,var(--blue),var(--blue-deep))}
#loadBar.on::before{animation:loadbar 1.1s ease-in-out infinite}
@keyframes loadbar{0%{left:-35%}70%{left:100%}100%{left:100%}}
@media(prefers-reduced-motion:reduce){#loadBar.on::before{animation:none;width:100%;opacity:.5}}

/* ── the chat box, fixed to the upper part of every view ── */
/* flat, calm composer — like the ChatGPT / Claude input: a solid surface
   with a thin border, no shadow */
.composer{
  position:fixed;top:calc(10px + env(safe-area-inset-top));left:0;right:0;margin-inline:auto;z-index:600;
  width:min(720px,calc(100vw - 20px));
  display:flex;flex-direction:column;gap:9px;padding:10px;border-radius:24px;
  background:#fff;border:1px solid var(--line);
}
#composerInput{
  width:100%;min-height:48px;max-height:140px;resize:none;border:1px solid var(--line);border-radius:16px;
  padding:12px 14px;font:500 15px/1.45 inherit;font-family:inherit;color:var(--ink);background:rgba(255,255,255,.9);
}
#composerInput:focus{outline:2px solid rgba(59,130,246,.5);outline-offset:1px}
.composer-actions{display:flex;align-items:center;justify-content:space-between}
#helpBtn{width:44px;min-width:44px;padding:0;border-radius:50%}
.composer-status{min-height:18px;margin:0 6px;font-size:12.5px;color:var(--mut)}
.composer-status.is-working{color:var(--blue-deep)}
.composer-status.is-error{color:var(--red)}
.composer-status.is-ready{color:#2E8540}
.help-panel{display:flex;flex-direction:column;gap:6px;max-height:45vh;overflow-y:auto}
.help-row{display:flex;flex-direction:column;gap:1px;text-align:left;border:1px solid var(--line);border-radius:13px;padding:9px 12px;background:#fff;cursor:pointer;font:inherit;font-family:inherit}
.help-row:hover{border-color:var(--blue)}
.help-row strong{color:var(--blue-deep);font-size:13.5px}
.help-row span{color:var(--mut);font-size:12px}
/* live command autocomplete under the input */
.composer-suggest{display:flex;flex-direction:column;gap:2px;max-height:44vh;overflow-y:auto}
.suggest-row{display:flex;flex-direction:column;gap:1px;text-align:left;width:100%;border:none;background:none;border-radius:11px;padding:7px 11px;cursor:pointer;font:inherit;font-family:inherit}
.suggest-row:hover,.suggest-row.is-active{background:rgba(59,130,246,.12)}
.suggest-row strong{color:var(--blue-deep);font-size:13.5px;pointer-events:none}
.suggest-row span{color:var(--mut);font-size:11.5px;line-height:1.35;pointer-events:none}

/* ── content ── */
.content{max-width:760px;margin:0 auto}
.view-head{display:flex;align-items:baseline;justify-content:space-between;gap:10px;margin:2px 2px 12px}
.view-head strong{font-size:16px;color:var(--blue-deep)}
.view-head span{color:var(--mut);font-size:12.5px;flex:0 0 auto}
.empty-note{color:var(--mut);text-align:center;margin-top:28px}
/* media cards: every imported text */
/* ── the media library: a filter bar over a grid of preview cards ── */
.cards-controls{margin:0 0 12px}
.cards-filters{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 10px}
.cards-search{display:block;width:100%;padding:9px 13px;border:1px solid var(--line);border-radius:12px;font:500 13.5px/1.2 inherit;font-family:inherit;color:var(--ink);background:var(--surface)}
.cards-search:focus{outline:none;border-color:var(--blue)}
/* ── THE TAB BAR ──────────────────────────────────────────────────────────
   A phone app puts its destinations along the bottom where a thumb already is.
   PHONE ONLY: on a desktop the header row is fine navigation and a bottom bar
   there is a phone imitation. It sits UNDER the full-screen sheets (z 900+) on
   purpose — nothing should float over the feed, the lyrics or a drill — and it
   goes away entirely in full-page reading. */
.tabbar{display:none}
@media (max-width:620px){
  .tabbar{
    display:grid;grid-template-columns:repeat(5,1fr);
    /* ABOVE the sheets (Themen, Sproochentest, the reading page) so the menu is
       on every page, which is what a phone app does — you never have to find
       your way out of a screen before you can go somewhere else. It stays BELOW
       the immersive ones: the video feed and the lyrics stage are full-screen
       on purpose and have their own controls, and below a modal dialog, which
       should own the screen until it is answered. */
    position:fixed;left:0;right:0;bottom:0;z-index:920;
    background:var(--surface);border-top:1px solid var(--line);
    padding:5px 2px calc(4px + env(safe-area-inset-bottom));
    box-shadow:0 -1px 12px rgba(15,40,70,.06);
  }
  .tab{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;
    border:0;background:none;cursor:pointer;font:inherit;color:var(--mut);
    padding:3px 2px;min-height:52px;border-radius:12px;
    transition:color .16s}
  /* the PILL behind the icon of the place you are — the one thing that makes a
     modern bar read at a glance, before you have finished reading the label */
  .tab-ic{display:flex;align-items:center;justify-content:center;
    width:52px;height:28px;border-radius:999px;background:transparent;
    transition:background .18s ease,transform .18s ease}
  .tab-ic svg{width:22px;height:22px;display:block}
  .tab-lb{font-size:10.5px;font-weight:700;letter-spacing:.005em;line-height:1.15;
    max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .tab.is-on{color:var(--blue-deep)}
  .tab.is-on .tab-lb{font-weight:800}
  .tab.is-on .tab-ic{background:rgba(59,130,246,.20)}
  .tab:active .tab-ic{transform:scale(.9)}
  /* the room for the bar is made at the END of this file — the phone media
     query further down sets `padding` in shorthand, which would wipe a
     padding-bottom written here */
}
body.fullread .tabbar{display:none}
/* ── THE FRONT DOOR ───────────────────────────────────────────────────────
   The home header carries eight ways into the app, and on a phone they were a
   single sideways-scrolling strip — so half of them sat off the right edge,
   unseen, which is the exact failure this project has already been bitten by
   twice. Everything is visible now: the title and ⚙ share the top line, and the
   seven ways in are a two-column grid of real, thumb-sized tiles.
   Scoped to #cardsHead ON PURPOSE. The generic .view-head stays a one-row strip
   for the reading view and the drills, where a head of five short buttons over
   a text really should not become a wall. */
#cardsHead{gap:8px}
@media (min-width:621px){
  #cardsHead{flex-wrap:wrap;row-gap:8px}
}
@media (max-width:620px){
  #cardsHead{
    display:grid;grid-template-columns:1fr 1fr;gap:8px;
    overflow:visible;align-items:stretch;margin:2px 0 14px;padding:0;
  }
  #cardsHead>strong{grid-row:1;grid-column:1;max-width:none;font-size:19px;letter-spacing:-.01em;align-self:center}
  #cardsHead>span{grid-row:2;grid-column:1/-1;margin:-6px 0 0}
  #cardsHead>span:empty{display:none}
  /* ⚙ keeps the top line beside the title — placed explicitly, so it does not
     matter that it is last in the markup. Its own height, not a tile's. */
  #cardsHead #settingsBtn{grid-row:1;grid-column:2;justify-self:end;align-self:center;
    width:44px;min-width:0;min-height:44px;padding:0;
    display:flex;align-items:center;justify-content:center;font-size:17px}
  /* …and the four that are now IN THE TAB BAR leave the header. They stay in
     the markup — the desktop layout and every pinned check still want them —
     they are simply not shown twice on a phone. What is left is what the bar
     does not carry. */
  /* …the ones the BAR carries. Haut is not one of them any more, so it comes
     back as a chip — a place you can still reach beats a tidy bar. */
  #cardsHead #chatBtn,#cardsHead #sproochBtn,#cardsHead #topicsBtn{display:none}
  /* THE LIBRARY IS THE HOME, and the launcher must not eat it. At 58px these
     eight tiles took 347px — 43% of the screen before a single text showed.
     48px is still a comfortable thumb target and gives that back. */
  #cardsHead .btn{
    width:100%;min-height:48px;display:flex;align-items:center;gap:2px;
    justify-content:flex-start;text-align:left;white-space:normal;line-height:1.2;
    border-radius:14px;padding:8px 11px;font-size:12.75px;font-weight:700;
    background:var(--surface);border:1px solid var(--line);color:var(--ink);
    box-shadow:0 1px 2px rgba(15,40,70,.05);
  }
}
.cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(288px,1fr));gap:16px}
.card{
  position:relative;display:flex;flex-direction:column;text-align:left;padding:0;border:1px solid var(--line);
  border-radius:18px;background:var(--surface);cursor:pointer;font:inherit;font-family:inherit;overflow:hidden;
  box-shadow:0 1px 2px rgba(15,40,70,.04);transition:transform .16s ease,border-color .16s,box-shadow .16s;
}
.card:hover{transform:translateY(-3px);border-color:var(--blue);box-shadow:0 18px 34px -18px rgba(29,78,216,.42)}
/* preview thumbnail: a video's first frame (bigger now, so it reads), or a tile */
.card-thumb{position:relative;height:172px;display:flex;align-items:center;justify-content:center;overflow:hidden}
.card-thumb-video{background:linear-gradient(135deg,#cfe0f2,#b6d0ea)}
.card-thumb-audio{background:linear-gradient(135deg,#e7dcf7,#ccbdec)}
.card-thumb-text{background:linear-gradient(135deg,#dcefe1,#bfe3cd)}
.card-thumb-video video.card-thumb-video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;background:#0c1622}
.card-thumb-play{position:relative;z-index:1;width:54px;height:54px;border-radius:50%;background:rgba(0,0,0,.46);color:#fff;display:flex;align-items:center;justify-content:center;font-size:17px;padding-left:3px;pointer-events:none;backdrop-filter:blur(2px);box-shadow:0 4px 14px rgba(0,0,0,.3)}
.card-thumb-glyph{font-size:40px;line-height:1}
.card-wave{position:absolute;bottom:13px;display:flex;align-items:flex-end;gap:3px;height:22px}
.card-wave i{width:3px;background:rgba(70,45,120,.55);border-radius:2px}
.card-wave i:nth-child(1){height:40%}.card-wave i:nth-child(2){height:78%}.card-wave i:nth-child(3){height:55%}
.card-wave i:nth-child(4){height:100%}.card-wave i:nth-child(5){height:62%}.card-wave i:nth-child(6){height:85%}.card-wave i:nth-child(7){height:47%}
.card-body{display:flex;flex-direction:column;gap:5px;padding:13px 15px 15px}
.card strong{color:var(--blue-deep);font-size:14.5px;font-weight:700;overflow-wrap:anywhere;padding-right:34px}
/* the ⋮ overflow menu button (modern kebab), top-right over the thumbnail */
.card-new{position:absolute;top:12px;left:12px;z-index:2;background:var(--blue-deep);color:#fff;font-size:10px;font-weight:800;line-height:1;letter-spacing:.09em;text-transform:uppercase;padding:5px 8px;border-radius:999px;box-shadow:0 2px 8px rgba(15,40,70,.25)} /* not yet viewed — why this card sits on top */
.card-menu-btn{position:absolute;top:9px;right:9px;z-index:2;width:32px;height:32px;border:none;border-radius:50%;background:rgba(255,255,255,.85);color:var(--mut);font:700 20px/1 inherit;font-family:inherit;cursor:pointer;display:flex;align-items:center;justify-content:center;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);box-shadow:0 2px 8px rgba(15,40,70,.14);opacity:.92;transition:background .15s,color .15s,opacity .15s}
.card-menu-btn:hover{background:#fff;color:var(--blue-deep);opacity:1}
.card-menu{min-width:186px}
.card-menu-item .cm-ic{width:20px;flex:0 0 auto;text-align:center}
.card-menu-item.cm-del{color:var(--red)}
.card-menu-item.cm-del:hover{background:rgba(200,60,60,.12)}
.card .card-meta{color:var(--mut);font-size:11.5px;font-weight:650}
.card .card-snippet{color:var(--ink);font-size:12.5px;line-height:1.45}

/* ── your saved games: the sets you can carry on with ── */
.saved{margin:24px 0 0;padding-top:18px;border-top:1px solid var(--line)}
.saved-note{color:var(--mut);font-size:12.5px;margin:0 2px 10px;line-height:1.5}
.saved-list{display:flex;flex-direction:column;gap:7px}
.saved-row{display:flex;align-items:stretch;border:1.5px solid var(--line);border-radius:14px;background:var(--surface);overflow:hidden;transition:border-color .15s}
.saved-row:hover{border-color:var(--blue)}
.saved-go{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px;text-align:left;background:none;border:none;padding:11px 13px;font:inherit;font-family:inherit;cursor:pointer}
.saved-go:hover{background:rgba(59,130,246,.07)}
.saved-title{font-size:14.5px;color:var(--ink);font-weight:600;line-height:1.4}
.saved-meta{font-size:11px;color:var(--mut);font-weight:650}
.saved-progress{align-self:flex-start;margin-top:3px;padding:3px 9px;border-radius:999px;background:rgba(46,139,114,.14);color:#2E8B72;font-size:11px;font-weight:750}
.saved-del{flex:0 0 auto;width:44px;border:none;border-left:1px solid var(--line);background:none;font-size:14px;cursor:pointer;transition:background .15s}
.saved-del:hover{background:rgba(237,41,57,.1)}
.saved-more{align-self:center;margin-top:4px;border:1px dashed var(--line);border-radius:999px;padding:7px 15px;font:600 12px/1 inherit;font-family:inherit;color:var(--blue-deep);background:none;cursor:pointer}
.saved-more:hover{border-color:var(--blue);border-style:solid}

/* ── create sentences: describe → the AI writes a set → straight into the game ── */
.make-note{color:var(--mut);font-size:12.5px;margin:0 2px 12px;line-height:1.5}
.make-input{display:block;width:100%;margin:0 0 10px;padding:11px 13px;border:1px solid var(--line);border-radius:12px;font:500 14px/1.4 inherit;font-family:inherit;color:var(--ink);background:var(--surface);resize:vertical;min-height:64px}
.make-input:focus{outline:none;border-color:var(--blue)}
.make-words{min-height:0;margin:0 0 10px;font-size:13.5px}
/* the upload page: the file row + the category chips */
.upload-file{display:flex;align-items:center;gap:10px;margin:0 0 10px}
.upload-name{color:var(--mut);font-size:12.5px;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.upload-tags{margin:0 0 12px}
.make-examples{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 12px}
.make-example{border:1px dashed var(--line);border-radius:999px;padding:6px 11px;font:500 12px/1.2 inherit;font-family:inherit;color:var(--blue-deep);background:transparent;cursor:pointer;transition:background .12s,border-color .12s}
.make-example:hover{border-color:var(--blue);border-style:solid}
.make-row{display:flex;flex-wrap:wrap;gap:14px;margin:0 0 4px}
.make-chips{display:flex;flex-wrap:wrap;align-items:center;gap:6px}
.make-chip{border:1px solid var(--line);border-radius:999px;padding:6px 12px;font:600 12px/1 inherit;font-family:inherit;color:var(--blue-deep);background:var(--surface);cursor:pointer;transition:background .12s,border-color .12s}
.make-chip:hover{border-color:var(--blue)}
.make-chip.is-on{background:var(--blue-deep);border-color:var(--blue-deep);color:#fff}
/* upload: the LuxASR on/off switch + its explanation */
.upload-asr{display:flex;align-items:center;gap:8px;font-size:13.5px;font-weight:600;color:var(--ink);margin:2px 0 8px;cursor:pointer}
.upload-asr input{width:17px;height:17px;accent-color:var(--blue-deep)}
.upload-asr-note{font-size:12px;color:var(--mut);margin:-4px 0 8px}
/* 📅 Today: three due-rows and the day's tally */
.today-row{display:flex;align-items:center;justify-content:space-between;gap:10px;border:1.5px solid var(--line);border-radius:16px;padding:13px 15px;margin:0 0 10px;background:var(--surface)}
.today-row.is-done{opacity:.62}
.today-info{display:flex;flex-direction:column;gap:3px;min-width:0}
.today-note{font-size:12.5px;color:var(--mut)}
/* 🎧 the dictation toggle lights when on */
.game-actions .btn.is-on{background:var(--blue-deep);border-color:var(--blue-deep);color:#fff}
/* 📚 the word across the library — the popup's footer row */
.word-pop-uses{display:block;width:100%;text-align:left;background:rgba(59,130,246,.08);border:none;border-top:1px solid var(--line);border-radius:0 0 12px 12px;padding:9px 12px;font-size:12.5px;font-weight:700;color:var(--blue-deep);cursor:pointer;font-family:inherit}
.word-pop-uses:hover{background:rgba(59,130,246,.16)}
/* 📅 the 14-day strip */
.today-chart{display:flex;align-items:flex-end;gap:4px;height:46px;margin:6px 2px 8px}
.today-bar{flex:1;background:rgba(59,130,246,.4);border-radius:4px 4px 0 0}
.today-bar.is-zero{background:rgba(120,140,160,.16)}
.today-bar.is-today{background:var(--blue-deep)}
/* the roomier card the timing dialogs share (⏱ tapping moved to the lyrics
   stage itself, so the card that used to name the current line went with it) */
.sync-card{gap:10px}
.align-when{display:flex;align-items:center;gap:8px}
.align-at{flex:1;min-width:0;margin:0;font-variant-numeric:tabular-nums;transition:background .2s}
.align-at.is-taken{background:rgba(46,139,114,.18)} /* the moment just landed here */
.align-clock{font:800 15px/1 inherit;color:var(--blue-deep);font-variant-numeric:tabular-nums;min-height:15px}
.align-grab{align-self:flex-start}
.align-modes{margin-top:2px}
/* 🎙 say it */
/* ── 🗺 THEMEN: the picture course ────────────────────────────────────────
   A full-screen sheet rather than a view, so it needs no place in the eight
   hide-lists a new view has to be added to — the trap this project warns about
   in its own notes. It sits above the composer and below the feed. */
.tp-overlay{position:fixed;inset:0;z-index:900;background:var(--bg);display:flex;flex-direction:column}
.tp-head{flex:0 0 auto;display:flex;align-items:center;gap:8px;padding:10px 12px;border-bottom:1px solid var(--line);background:var(--surface)}
.tp-title{flex:1;min-width:0;font-size:16px}
.tp-x{width:34px;height:34px;flex:0 0 auto;border:none;border-radius:50%;background:transparent;color:var(--mut);font-size:15px;cursor:pointer}
.tp-x:hover{background:rgba(0,0,0,.06);color:var(--ink)}
.tp-body{flex:1;min-height:0;overflow-y:auto;padding:14px;max-width:760px;width:100%;margin:0 auto}
.tp-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:10px;margin-top:10px}
.tp-card{display:flex;flex-direction:column;align-items:flex-start;gap:3px;padding:12px;border:1px solid var(--line);border-radius:14px;background:var(--surface);cursor:pointer;text-align:left}
.tp-card:hover{border-color:var(--blue)}
.tp-ic{font-size:26px;line-height:1.1}
.tp-nm{font-weight:800;font-size:14.5px;color:var(--ink)}
.tp-en{font-size:11.5px;color:var(--mut)}
.tp-bar{display:block;width:100%;height:5px;border-radius:3px;background:rgba(127,127,127,.22);margin-top:6px;overflow:hidden}
.tp-bar i{display:block;height:100%;background:var(--blue-deep);border-radius:3px}
.tp-n{font-size:11px;color:var(--mut)}
.tp-sub{margin:0 0 10px;font-size:12.5px;color:var(--mut)}
.tp-modes{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:8px;margin-bottom:14px}
.tp-mode{display:flex;flex-direction:column;gap:2px;padding:11px 13px;border:1px solid var(--line);border-radius:12px;background:var(--surface);cursor:pointer;text-align:left;font:inherit;color:var(--ink)}
.tp-mode:hover{border-color:var(--blue)}
.tp-mode span{font-size:11.5px;color:var(--mut)}
.tp-list{display:flex;flex-direction:column;gap:4px}
.tp-row{display:flex;align-items:center;gap:10px;padding:6px 8px;border:1px solid transparent;border-radius:10px;background:none;cursor:pointer;font:inherit;text-align:left}
.tp-row:hover{background:rgba(127,127,127,.08)}
.tp-row.is-known{border-color:rgba(46,158,91,.4)}
/* written FOR you and not yet checked — visibly not the same thing as an answer
   you gave, because these get memorised for an exam about your own life */
.tp-row.is-draft{border-color:rgba(255,180,60,.5);background:rgba(255,180,60,.06)}
.tp-thumb{width:38px;height:38px;flex:0 0 auto;border-radius:8px;background:rgba(127,127,127,.15) center/cover no-repeat}
/* 🧩 the conjugation, which is the thing a learner opens a verb FOR — a plain
   two-column list rather than a table, so it stays readable on a phone where a
   six-row table would either scroll sideways or shrink out of legibility */
/* 🗂 THE SUBJECT DRAWERS — their own grid and card, because .tp-card is shared
   chrome across Themen and the Sproochentest and restyling it would restyle
   both. The shape is the one every modern list uses and for the reason it uses
   it: a tinted icon tile on the left, the name and the count stacked beside it,
   so the eye lands on a picture, then a word, then a number, in that order.
   The icon tile is the tab bar's own pill, squared off. */
.subj-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(232px,1fr));gap:10px;margin-top:12px}
.subj-card{display:flex;align-items:center;gap:13px;width:100%;text-align:left;
  padding:13px 14px;border:1px solid var(--line);border-radius:16px;background:var(--surface);
  color:var(--ink);cursor:pointer;font-family:inherit;
  box-shadow:0 10px 22px -20px rgba(29,78,216,.6);
  transition:transform .08s ease,border-color .16s ease,box-shadow .16s ease}
.subj-card:hover{border-color:var(--blue);box-shadow:0 14px 26px -18px rgba(29,78,216,.7)}
.subj-card:active{transform:scale(.985)}
.subj-ic{flex:0 0 auto;display:flex;align-items:center;justify-content:center;
  width:42px;height:42px;border-radius:13px;background:rgba(59,130,246,.16);color:var(--blue-deep)}
.subj-ic svg{width:22px;height:22px;display:block}
.subj-card:hover .subj-ic{background:rgba(59,130,246,.26)}
.subj-txt{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}
.subj-nm{font-size:14.5px;font-weight:800;line-height:1.25;color:var(--ink)}
.subj-n{font-size:11.5px;font-weight:600;color:var(--mut)}
/* a topic finished says so on its edge, the way the old rows did — the whole
   card, not a tick you have to find */
.subj-card.is-known{border-color:rgba(46,158,91,.55);background:rgba(46,158,91,.06)}
.subj-card.is-known .subj-ic{background:rgba(46,158,91,.16);color:#2E9E5B}
.subj-card .tp-bar{margin-top:5px}
@media(prefers-color-scheme:dark){
  .subj-ic{background:rgba(59,130,246,.22);color:var(--blue)}
  .subj-card:hover .subj-ic{background:rgba(59,130,246,.32)}
}
/* 📖 the reading list: each row is a door into the practice card, so it looks
   like one — a surface, not a line. The words inside are live and the mouth
   is its own button, exactly the word-order card's arrangement. */
.vs-form{margin:16px 0 6px;font-size:12px;font-weight:800;letter-spacing:.04em;
  text-transform:uppercase;color:var(--mut)}
.vs-row{display:flex;align-items:center;gap:10px;padding:10px 12px;margin:0 0 8px;
  border:1px solid var(--line);border-radius:12px;background:var(--surface);cursor:pointer;
  transition:border-color .15s ease,transform .08s ease}
.vs-row:hover{border-color:var(--blue)}
.vs-row:active{transform:scale(.99)}
.vs-row:focus-visible{outline:2px solid var(--blue);outline-offset:2px}
.vs-row.is-known{border-color:rgba(46,158,91,.45)}
.vs-txt{flex:1;min-width:0}
.vs-lb{margin:0;font-size:15.5px;font-weight:600;line-height:1.5}
.vs-en{margin:2px 0 0;font-size:12.5px;font-weight:600;color:var(--mut)}
.vs-hear{flex:0 0 auto;display:flex;align-items:center;justify-content:center;
  width:38px;height:38px;border-radius:999px;border:0;padding:0;cursor:pointer;
  background:rgba(59,130,246,.14);color:var(--blue-deep)}
.vs-hear svg{width:18px;height:18px;display:block}
.vs-hear:hover{background:rgba(59,130,246,.26)}
@media(prefers-color-scheme:dark){.vs-hear{color:var(--blue)}}
.tp-count{margin:2px 0 8px;opacity:.7;font-size:13px}
.tp-practise{margin:10px 0}
.vb-conj{display:grid;grid-template-columns:auto 1fr;gap:2px 12px;margin:4px 0 10px;
  padding:10px 12px;border:1px solid rgba(127,127,127,.25);border-radius:12px}
.vb-cell{display:contents}
/* 🔀 FOUR BIG CARDS, one of them right. They were stacked rows first and read
   as a list of settings rather than a choice — you scan a list, you PICK a
   card. So: real surfaces with their own weight, big type, a thumb-sized
   target, and a press you can feel. Two up where there is room, one up on a
   phone, because a Luxembourgish sentence with a subordinate clause in a
   half-width column becomes four cramped lines and the question stops being
   about grammar and starts being about reading. */
.vo-ask{font-size:21px;font-weight:800;line-height:1.35;margin:10px 0 2px;color:var(--ink)}
.vo-opts{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:12px;margin:14px 0}
.vo-opt{display:flex;align-items:center;gap:10px;min-height:104px;
  width:100%;text-align:left;padding:18px 20px;border:2px solid var(--line);border-radius:18px;
  background:var(--surface);color:var(--ink);cursor:pointer;
  /* LONGHANDS, deliberately: `font:600 17px/1.5 inherit` is an invalid
     shorthand — `inherit` may not be the family inside `font:` — so the whole
     declaration is dropped and the card keeps the browser's 13px button face.
     Measured in the pane before this was written. */
  font-family:inherit;font-size:17px;font-weight:600;line-height:1.5;
  box-shadow:0 10px 24px -18px rgba(29,78,216,.55);
  transition:transform .08s ease,border-color .15s ease,box-shadow .15s ease}
.vo-body{display:flex;flex-direction:column;gap:6px;flex:1;min-width:0}
/* the chooser: always there, always the same place, so a card packed edge to
   edge with tappable words still has one unmistakable spot that PICKS it */
.vo-pick{flex:0 0 auto;display:flex;align-items:center;justify-content:center;
  width:40px;height:40px;border-radius:999px;border:0;padding:0;cursor:pointer;
  background:rgba(59,130,246,.16);color:var(--blue-deep);
  transition:background .15s ease,transform .08s ease}
.vo-pick svg{width:21px;height:21px;display:block}
.vo-opt:hover .vo-pick{background:rgba(59,130,246,.3)}
.vo-pick:active{transform:scale(.92)}
.vo-opt:not(.is-out):hover{border-color:var(--blue);box-shadow:0 14px 30px -18px rgba(29,78,216,.7)}
.vo-opt:not(.is-out):active{transform:scale(.985)}
.vo-opt:focus-visible{outline:2px solid var(--blue);outline-offset:2px}
/* the answered board must stay READABLE — this is where the teaching is, so
   nothing is dimmed away and the three wrong ones keep their full contrast.
   The words stay live: looking one up is most wanted once it is settled. */
.vo-opt.is-out{cursor:default;opacity:1;box-shadow:none}
.vo-opt.is-right{border-color:#2E9E5B;background:rgba(46,158,91,.12)}
.vo-opt.is-wrong{border-color:rgba(237,41,57,.55);background:rgba(237,41,57,.06)}
.vo-lb{display:block}
/* the nudge after a wrong pick: it must be readable without pulling the eye off
   the cards, because the cards are where the next try happens */
.vo-nudge{min-height:20px;margin:6px 0 0;font-size:14px;font-weight:700;color:var(--mut)}
.vo-why{display:block;font-size:13.5px;font-weight:600;line-height:1.4;color:var(--mut)}
@media(prefers-color-scheme:dark){
  .vo-opt.is-right{background:rgba(46,158,91,.18)}
  .vo-opt.is-wrong{background:rgba(237,41,57,.12)}
}
@media (max-width:620px){
  .vo-ask{font-size:19px}
  .vo-opt{min-height:96px;padding:16px 17px;font-size:16.5px}
}
.vb-who{opacity:.6;font-size:13px;white-space:nowrap}
.vb-form{font-weight:600}
.tp-wbox{display:flex;flex-direction:column;min-width:0}
.tp-w{font-weight:700;color:var(--ink)}
/* the plural, where Luxembourgish actually catches people out */
.tp-pl{font-size:11.5px;color:var(--mut)}
.tp-tr{font-size:12px;color:var(--mut);margin-left:auto;text-align:right;padding-left:8px}
/* an own theme's word carries its way out; the theme its own */
.tp-del{flex:0 0 auto;color:var(--mut);font-size:13px;padding:5px 8px;border-radius:8px}
.tp-del:hover{color:var(--ink);background:rgba(0,0,0,.06)}
.tp-remove{display:block;margin:12px auto 26px}
.tp-plural{margin:2px 0 0;border:none;background:none;font:inherit;font-size:13.5px;font-weight:700;
  color:var(--blue-deep);cursor:pointer}
.tp-plural.is-same{color:var(--mut);font-weight:500;cursor:default}
/* the drill itself */
.tp-stage{display:flex;flex-direction:column;align-items:center;gap:12px;padding-top:6px}
.tp-count{margin:0;font-size:11.5px;font-weight:700;color:var(--mut)}
.tp-wait{margin:0;font-size:13px;color:var(--mut)}
.tp-card-big{display:flex;flex-direction:column;align-items:center;gap:8px;width:100%;max-width:340px}
.tp-imgwrap{position:relative;width:100%}
.tp-img{width:100%;aspect-ratio:1/1;border-radius:16px;background:rgba(127,127,127,.15) center/cover no-repeat;display:flex;align-items:center;justify-content:center;font-size:40px}
/* ↻ another picture, and where this one came from — the same pair the word
   popup has had for ages, on the card where the picture actually is */
.tp-reload{position:absolute;top:8px;right:8px;width:38px;height:38px;border:none;border-radius:50%;
  background:rgba(0,0,0,.55);color:#fff;font-size:17px;line-height:1;cursor:pointer;backdrop-filter:blur(4px)}
.tp-reload:hover{background:rgba(0,0,0,.75)}
.tp-reload.is-busy{animation:tap-pulse 1s ease-in-out infinite;cursor:default}
.tp-imgsrc{position:absolute;left:8px;bottom:8px;max-width:calc(100% - 60px);padding:3px 8px;border-radius:8px;
  background:rgba(0,0,0,.55);color:#fff;font-size:10.5px;font-weight:600;backdrop-filter:blur(4px);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tp-imgsrc:empty{display:none}
.tp-word{border:none;background:none;font:inherit;font-size:26px;font-weight:800;color:var(--ink);cursor:pointer;line-height:1.2}
.tp-mean{margin:0;font-size:14px;color:var(--mut);text-align:center}
.tp-actions{display:flex;gap:8px;flex-wrap:wrap;justify-content:center}
.tp-ask{border:none;background:none;font:inherit;font-size:26px;font-weight:800;color:var(--ink);cursor:pointer}
.tp-opts{display:grid;grid-template-columns:1fr 1fr;gap:10px;width:100%;max-width:400px}
.tp-opt{aspect-ratio:1/1;border:2px solid var(--line);border-radius:14px;background:rgba(127,127,127,.12) center/cover no-repeat;cursor:pointer;font:inherit;font-weight:700;color:var(--ink)}
.tp-opt:hover{border-color:var(--blue)}
.tp-opt.is-right{border-color:#2E9E5B;box-shadow:0 0 0 3px rgba(46,158,91,.3)}
.tp-opt.is-wrong{border-color:var(--red);opacity:.5}
.tp-done{margin:0;font-size:17px;font-weight:800;color:var(--ink);text-align:center}
/* ── THE SHEET ON A PHONE ─────────────────────────────────────────────────
   Bigger targets, a card that fills the width, and the actions parked at the
   bottom where a thumb is — with the home-bar inset respected so the primary
   button is never half under it. */
@media (max-width:620px){
  .tp-body{padding:10px 10px calc(14px + env(safe-area-inset-bottom))}
  .tp-grid{grid-template-columns:1fr 1fr;gap:8px}
  .tp-card{padding:11px;border-radius:16px}
  .tp-ic{font-size:24px}
  .tp-modes{grid-template-columns:1fr;gap:7px}
  .tp-mode{padding:13px 14px;border-radius:14px}
  .tp-row{padding:9px 8px}
  .tp-thumb{width:44px;height:44px}
  .tp-card-big{max-width:100%}
  .tp-img{border-radius:20px}
  .tp-word{font-size:30px}
  .tp-opts{gap:8px;max-width:100%}
  .tp-opt{border-radius:16px}
  .tp-actions{position:sticky;bottom:0;width:100%;padding:8px 0 calc(4px + env(safe-area-inset-bottom));
    background:linear-gradient(to top,var(--bg) 70%,transparent)}
  .tp-actions .btn{flex:1;min-height:46px}
}
.say-card{gap:12px}
.say-target{font-size:19px;font-weight:700;margin:0;cursor:pointer;line-height:1.4}
.say-status{font-size:13px;color:var(--mut);margin:0}
.say-actions{display:flex;gap:8px;flex-wrap:wrap}
/* walking a list of saved lines: where you are, and what the line means */
.say-count{margin:0;font-size:11.5px;font-weight:700;color:var(--mut);letter-spacing:.02em}
.say-tr{margin:0;font-size:13px;color:var(--mut);line-height:1.4}
.say-tr.hidden{display:none}
/* ── MEANING FIRST: the question is what you must EXPRESS ─────────────────
   When the drill asks you to produce the sentence, the meaning is the prompt
   and has to read like one — large and plain — while the Luxembourgish waits
   behind 👁 as three dots. Showing the answer next to the question is not a
   test. */
.say-tr.is-ask{font-size:20px;font-weight:700;color:var(--ink);line-height:1.35}
.say-target.is-hidden{color:var(--mut);opacity:.5;letter-spacing:.22em;font-size:22px}
.say-reveal{align-self:flex-start}
/* answering a question about yourself: room to write, in either language */
.me-answer{width:100%;box-sizing:border-box;padding:10px 12px;border:1px solid var(--line);border-radius:12px;
  background:var(--bg);color:var(--ink);font:inherit;font-size:15px;line-height:1.45;resize:vertical}
.me-answer:focus{outline:none;border-color:var(--blue)}
/* answering OUT LOUD, which is how the test is taken */
.me-mics{display:flex;gap:8px;flex-wrap:wrap}
.me-mic{flex:1;min-width:140px;min-height:44px;font-size:13.5px}
.me-mic.is-rec{background:var(--red);border-color:var(--red);color:#fff;animation:tap-pulse 1.2s ease-in-out infinite}
.say-verdict{margin:8px 0 0;font-size:14px;font-weight:700;line-height:1.4}
.say-verdict.is-ok{color:#2E9E5B}
.say-verdict.is-no{color:#a35a00}
.say-better,.say-model{margin:4px 0 0;font-size:13.5px;color:var(--ink);font-weight:600;line-height:1.4}
.say-model{color:var(--mut);font-weight:500}
@media(prefers-color-scheme:dark){
  .say-verdict.is-ok{color:#6fe3a1}
  .say-verdict.is-no{color:#ffcf6b}
}
/* the sheet is a PHONE surface first: a big thumb-reachable primary action,
   room under it for the home bar, and nothing that needs a mouse */
@media (max-width:620px){
  .say-card{gap:10px}
  .say-target{font-size:21px}
  .say-tr.is-ask{font-size:19px}
  .say-actions{position:sticky;bottom:0;padding:8px 0 calc(4px + env(safe-area-inset-bottom));
    background:linear-gradient(to top,var(--surface) 70%,transparent);gap:6px}
  .say-actions .btn{flex:1;min-height:46px;font-size:14px}
  .say-actions .btn-primary{flex:2 1 100%;order:-1}
}
.say-diff{font-size:17px;line-height:1.6;margin:0}
.say-ok{color:#1f8a4c;font-weight:700}
.say-miss{color:#c0392b;font-weight:700;text-decoration:underline dotted;cursor:pointer}
.say-score{font-size:12.5px;color:var(--mut);margin:0}
@media(prefers-color-scheme:dark){.say-ok{color:#6fe3a1}.say-miss{color:#ff9d8a}}
/* ⚙ settings: small titled groups, a hint under the active choice */
.set-group{display:flex;flex-direction:column;gap:8px;border:1.5px solid var(--line);border-radius:16px;padding:14px 16px;margin:0 0 14px;background:var(--surface)}
.set-title{font-size:15px;color:var(--ink)}
.set-hint{font-size:12.5px;color:var(--mut);margin:2px 0 0}
.set-check{display:flex;align-items:center;gap:8px;font-size:13.5px;font-weight:600;color:var(--ink);cursor:pointer}
.set-check input{width:17px;height:17px;accent-color:var(--blue-deep)}
.set-check input:disabled{opacity:.5}
.make-actions{display:flex;justify-content:flex-end}
.make-status{min-height:18px;margin:8px 2px 0;font-size:12.5px;color:var(--mut)}
.make-status.is-working{color:var(--blue-deep)}
.make-status.is-error{color:var(--red)}

/* filter chips: level (A1/A2…) and grammar (Present/Past/Adverbs…) */
.mfilter-group{display:flex;flex-wrap:wrap;align-items:center;gap:6px}
.mfilter-label{flex:0 0 auto;min-width:52px;font-size:10px;font-weight:800;letter-spacing:.07em;text-transform:uppercase;color:var(--mut);opacity:.8}
.mfilter{display:inline-flex;align-items:center;gap:5px;border:1px solid var(--line);border-radius:999px;padding:6px 11px;font:600 12px/1 inherit;font-family:inherit;color:var(--blue-deep);background:var(--surface);cursor:pointer;transition:background .12s,border-color .12s}
.mfilter:hover{border-color:var(--blue)}
.mfilter.is-on{background:var(--blue-deep);border-color:var(--blue-deep);color:#fff}
.mfilter-n{font-size:10px;font-weight:700;opacity:.6}
.mfilter.is-on .mfilter-n{opacity:.8}
.mfilter-clear{color:var(--red);border-color:transparent}
.mfilter.pl-chip.is-on{background:#2E8B72;border-color:#2E8B72;color:#fff} /* a distinct hue from the type/grammar filters (beats the dark .mfilter.is-on) */
.pl-new{border-style:dashed;color:var(--mut)}
.pl-act{padding:6px 9px;font-weight:700}
.pl-act.pl-del{color:var(--red)}
/* above the bottom tab bar (920) — a card's menu near the foot of the library
   was opening UNDER it; below the feed (950), whose own menu instance carries
   its inline 1200 */
.pl-menu{position:fixed;z-index:930;min-width:220px;max-width:280px;background:var(--surface);border:1.5px solid var(--line);border-radius:14px;box-shadow:0 18px 44px -18px rgba(15,40,70,.35);padding:8px;display:flex;flex-direction:column;gap:2px}
.pl-menu-head{font-size:11.5px;font-weight:700;color:var(--mut);padding:2px 6px 6px}
.pl-menu-empty{font-size:12px;color:var(--mut);padding:2px 6px 8px}
.pl-menu-row{display:flex;align-items:center;gap:8px;width:100%;text-align:left;border:none;background:none;border-radius:9px;padding:8px 8px;font:600 13.5px/1.2 inherit;font-family:inherit;color:var(--ink);cursor:pointer}
.pl-menu-row:hover{background:rgba(46,139,114,.1)}
.pl-menu-row.is-in{color:#2E8B72}
.pl-check{width:16px;flex:0 0 auto;color:#2E8B72;font-weight:800}
.pl-menu-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pl-menu-count{font-size:10.5px;font-weight:700;color:var(--mut)}
.pl-menu-new{display:flex;gap:6px;margin-top:6px;border-top:1px solid var(--line);padding-top:8px}
.pl-menu-input{flex:1;min-width:0;padding:7px 10px;border:1px solid var(--line);border-radius:9px;font:500 13px/1.2 inherit;font-family:inherit;color:var(--ink);background:var(--bg)}
.pl-menu-input:focus{outline:none;border-color:var(--blue)}
.pl-menu-add{flex:0 0 auto;width:34px;border:none;border-radius:9px;background:#2E8B72;color:#fff;font:700 15px/1 inherit;font-family:inherit;cursor:pointer}
/* the reading-view bar shown while a media playlist plays through */
.media-list-bar{display:flex;align-items:center;gap:10px;margin:0 0 12px;padding:9px 12px;border-radius:12px;background:rgba(46,139,114,.12);border:1px solid rgba(46,139,114,.35)}
.mlb-label{flex:1;min-width:0;font-size:12.5px;font-weight:700;color:#1f6b57;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mlb-btn{flex:0 0 auto;border:1px solid rgba(46,139,114,.5);background:var(--surface);color:#1f6b57;border-radius:9px;padding:6px 10px;font:700 12px/1 inherit;font-family:inherit;cursor:pointer}
.mlb-btn:disabled{opacity:.45;cursor:default}
.mlb-btn.mlb-stop{color:var(--red);border-color:transparent;background:none;font-size:14px}
/* drag-ordered word-type filter: build "Verb → Adverb" and match that order */
.word-chip{display:inline-flex;align-items:center;gap:4px;padding:4px 5px 4px 10px;border-radius:9px;background:rgba(59,130,246,.1);border:1px solid rgba(59,130,246,.3);font-size:12.5px;font-weight:600;color:var(--ink)}
.word-chip-x{background:none;border:none;padding:2px 5px;font:600 10.5px/1 inherit;font-family:inherit;color:var(--mut);cursor:pointer;border-radius:6px}
.word-chip-x:hover{color:var(--red);background:rgba(200,60,60,.1)}
.sen-dot{width:7px;height:7px;min-width:7px;border-radius:50%;background:var(--line);align-self:center}
.sen-dot.is-mid{background:var(--blue)}
.sen-dot.is-strong{background:#2E9E5B}
/* closed rows preview the skeleton as role-only mini chips */
/* the row head + its ▶ drill button side by side */

/* ── the game: build the set's sentence from its shuffled words ── */
#gameView{max-width:620px;margin:0 auto}
.game-top{display:flex;align-items:center;gap:10px;margin:0 0 8px}
.game-machine{flex:1;min-width:0;font-size:12px;color:var(--mut);font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.game-score{font-size:13px;font-weight:800;color:var(--blue-deep);white-space:nowrap;font-variant-numeric:tabular-nums}
.prep-review-btn{flex:none;font-size:11px;padding:3px 9px;white-space:nowrap}
.prep-review-btn.is-off{opacity:.62;text-decoration:line-through}
.prep-list-btn{flex:none;padding:3px 9px}
.prep-list-body{gap:18px}
.prep-list-sec{display:flex;flex-direction:column;gap:6px}
.prep-list-sechead{display:flex;align-items:baseline;gap:8px;padding:2px 0}
.prep-list-prep{font:800 15px/1 inherit;color:var(--blue-deep)}
.prep-list-count{font-size:12px;font-weight:700;color:var(--mut)}
.prep-list-item{display:flex;flex-direction:column;align-items:flex-start;gap:2px;text-align:left;background:rgba(59,130,246,.06);border:none;border-radius:10px;padding:9px 11px;cursor:pointer;width:100%;font-family:inherit}
.prep-list-item:hover{background:rgba(59,130,246,.12)}
.prep-list-main{display:flex;align-items:center;gap:8px;font:600 15.5px/1.4 inherit;color:var(--ink)}
.prep-list-sen .prep-hi{color:var(--blue-deep);font-weight:800}
.prep-list-tr{font-size:12.5px;color:var(--mut);padding-left:16px}
/* the modal shell openPrepList (📜) builds from — these classes lost their CSS
   when the lesson feature was removed, leaving the 📜 list an unstyled block
   below the page (the button looked dead) */
.lesson-overlay{position:fixed;inset:0;z-index:1000;display:flex;align-items:flex-start;justify-content:center;padding:0;background:rgba(14,20,28,.55);backdrop-filter:blur(6px);overflow-y:auto}
.lesson-card{width:min(680px,100%);min-height:100dvh;display:flex;flex-direction:column;gap:12px;background:var(--surface);padding:16px max(18px,calc((100vw - 680px)/2)) calc(20px + env(safe-area-inset-bottom))}
.lesson-header{display:flex;align-items:center;justify-content:space-between;gap:10px;position:sticky;top:0;background:var(--surface);padding:2px 0 6px;border-bottom:1px solid var(--line)}
.lesson-title{font-size:18px;color:var(--ink);line-height:1.3}
.lesson-body{display:flex;flex-direction:column;gap:12px;flex:1}
@media(prefers-color-scheme:dark){.prep-list-item{background:rgba(59,130,246,.1)}.lesson-card,.lesson-header{background:#111A25}}
#gameView>.game-mastery{margin:0 2px 14px;max-width:none;height:5px}
.game-card{background:var(--surface);border:1.5px solid var(--line);border-radius:20px;padding:18px;display:flex;flex-direction:column;gap:14px;box-shadow:0 18px 44px -22px rgba(15,40,70,.25)}
.game-prompt{font-size:18px;font-weight:650;color:var(--ink);line-height:1.5}
.game-hint{font-size:12.5px;color:var(--mut);margin-top:3px;line-height:1.45}
.game-answer{min-height:58px;display:flex;flex-wrap:wrap;gap:8px;align-items:center;padding:10px;border:2px dashed var(--line);border-radius:14px;transition:border-color .2s,background .2s}
.game-answer.is-right{border-color:#2E9E5B;background:rgba(46,158,91,.09)}
.game-answer.is-wrong{border-color:var(--red);background:rgba(200,60,60,.06)}
.game-placeholder{color:var(--mut);font-size:13px;padding:0 4px}
.game-bank{display:flex;flex-wrap:wrap;gap:8px;min-height:46px}
.tile{background:var(--surface);border:1.5px solid var(--line);border-bottom-width:3px;border-radius:12px;padding:9px 13px;font:600 16px/1.2 inherit;font-family:inherit;color:var(--ink);cursor:pointer;transition:border-color .15s,background .15s}
.tile:hover{border-color:var(--blue)}
.tile:active{background:rgba(59,130,246,.12)}
.game-answer .tile{background:rgba(59,130,246,.1);border-color:rgba(59,130,246,.45)}
/* after a wrong check: each tile tells whether ITS place was right */
.game-answer .tile.is-ok{border-color:#2E9E5B;background:rgba(46,158,91,.12)}
.game-answer .tile.is-off{border-color:var(--red);background:rgba(200,60,60,.09)}
/* picked up, waiting for the word to swap it with */
.game-answer .tile.is-sel{border-color:var(--blue-deep);background:rgba(59,130,246,.3);box-shadow:0 0 0 2px var(--blue-deep) inset;transform:translateY(-2px)}
/* free dragging: the finger owns the tile, so the page must not scroll under it */
.game-answer .tile,.game-bank .tile{touch-action:none} /* bank tiles too — without it the phone claims the upward drag as a page scroll */
.tile.is-dragging{opacity:.8;box-shadow:0 12px 24px -8px rgba(15,40,70,.5);border-color:var(--blue-deep);position:relative;z-index:6;transition:none} /* the transform is inline (the float follows the finger) */
.tile.tile-ghost{border-style:dashed;border-color:var(--blue-deep);background:rgba(59,130,246,.14);color:transparent;pointer-events:none} /* the open slot: exactly where the word will land */
.game-solution{font-size:15.5px;font-weight:650;color:#2E9E5B;line-height:1.5;cursor:pointer}
.game-actions{display:flex;gap:10px;align-items:center}
.game-check{flex:1;min-height:46px;font-size:15px}
.game-status{min-height:18px;font-size:12.5px;font-weight:600;color:var(--mut)}
/* the round-complete panel: replaces the play surface when every sentence is done */
.game-done{display:none;flex-direction:column;gap:6px;align-items:center;text-align:center;padding:8px 0 4px}
.game-card.is-done>:not(.game-done){display:none}
.game-card.is-done>.game-done{display:flex}
.game-done-title{font-size:20px;font-weight:800;color:var(--blue-deep)}
.game-done-sub{font-size:13.5px;color:var(--mut);line-height:1.5;margin-bottom:10px}
.game-done-actions{display:flex;flex-direction:column;gap:9px;width:100%;max-width:340px}
.game-done-actions .btn{width:100%;min-height:46px}
/* ── the preposition game: fill the blank, then bind the whole chunk ── */
#prepView{max-width:620px;margin:0 auto}
#prepView>.game-mastery{margin:0 2px 14px;max-width:none;height:5px}
.prep-sentence{font-size:19px;font-weight:650;color:var(--ink);line-height:1.65;letter-spacing:.1px}
.prep-slot{display:inline-block;min-width:56px;text-align:center;padding:1px 10px;margin:0 2px;border-bottom:2.5px solid var(--blue);border-radius:6px 6px 3px 3px;color:var(--blue-deep);font-weight:800;background:rgba(59,130,246,.08)}
.prep-slot.is-right{color:#2E9E5B;border-color:#2E9E5B;background:rgba(46,158,91,.12)}
.prep-slot.is-shown{color:var(--red);border-color:var(--red);background:rgba(200,60,60,.09)}
.prep-say{margin-left:8px;background:none;border:0;color:var(--blue);font-size:15px;cursor:pointer;vertical-align:middle;padding:2px 4px}
.prep-options{display:flex;flex-wrap:wrap;gap:9px}
.prep-opt{background:var(--surface);border:1.5px solid var(--line);border-bottom-width:3px;border-radius:12px;padding:11px 16px;font:700 16px/1.2 inherit;font-family:inherit;color:var(--ink);cursor:pointer;transition:border-color .15s,background .15s;min-width:58px}
.prep-opt:hover:not(:disabled){border-color:var(--blue)}
.prep-opt:active:not(:disabled){background:rgba(59,130,246,.12)}
.prep-opt:disabled{cursor:default}
.prep-opt.is-right{border-color:#2E9E5B;background:rgba(46,158,91,.14);color:#2E9E5B}
.prep-opt.is-wrong{border-color:var(--red);background:rgba(200,60,60,.1);color:var(--red)}
.prep-feedback{display:flex;flex-direction:column;gap:8px;align-items:flex-start;padding:12px 14px;border-radius:14px;background:var(--bg);border:1px solid var(--line)}
.prep-fb-line{font-size:15px;font-weight:800}
.prep-fb-line.is-right{color:#2E9E5B}
.prep-fb-line.is-wrong{color:var(--red)}
.prep-chunk{background:rgba(59,130,246,.1);border:1.5px solid rgba(59,130,246,.4);border-radius:12px;padding:8px 14px;font:700 17px/1.2 inherit;font-family:inherit;color:var(--blue-deep);cursor:pointer}
.prep-chunk:hover{border-color:var(--blue)}
.prep-fb-meta{font-size:12px;color:var(--mut);font-weight:600;line-height:1.4}
/* ── 🗣 pronunciation: the word, big, and what the machine heard ── */
#sayGameView{max-width:620px;margin:0 auto}
.sg-word{margin:0;font-size:34px;font-weight:800;letter-spacing:-.01em;color:var(--ink);line-height:1.15;overflow-wrap:anywhere}
.sg-meaning{margin:0;font-size:14px;color:var(--mut)}
.sg-meaning:empty{display:none}
.sg-heardbox:empty{display:none}
.sg-heard{margin:0;font-size:15px;font-weight:700;overflow-wrap:anywhere}
.sg-heard.is-right{color:#2E9E5B}
.sg-heard.is-wrong{color:var(--red)}
/* how CLEARLY it came through — never a mark: the machine scores its own voice
   around .5, so a percentage here would read as a verdict on the learner */
.sg-clarity{height:6px;border-radius:999px;background:rgba(59,130,246,.16);overflow:hidden}
.sg-clarity span{display:block;height:100%;border-radius:999px;background:var(--blue);transition:width .3s}
#sgSayBtn.is-rec{background:#ff5c8a;border-color:#ff5c8a;color:#fff;animation:tap-pulse 1.2s ease-in-out infinite}
/* ── My words: uTalk-style picture multiple-choice ── */
#wordGameView{max-width:620px;margin:0 auto}
#wordGameView>.game-mastery{margin:0 2px 14px;max-width:none;height:5px}
.wg-prompt{display:flex;align-items:center;justify-content:center;gap:8px;font-size:30px;font-weight:750;color:var(--blue-deep);text-align:center;padding:2px 0}
.wg-say{background:none;border:0;color:var(--blue);cursor:pointer;padding:4px;display:inline-flex}
.wg-say svg{width:22px;height:22px;display:block}
.wg-hint{text-align:center;font-size:12.5px;color:var(--mut);min-height:16px}
/* the reversed round: picture + meaning ask, the word tiles answer */
.wg-prompt{flex-direction:column}
.wg-prompt-imgwrap{position:relative;display:inline-flex}
.wg-prompt-img{width:150px;height:150px;object-fit:cover;border-radius:14px;box-shadow:0 10px 24px -14px rgba(15,40,70,.45)}
/* ↻ the game picture can be swapped, same control as the popup's */
.wg-img-reload{position:absolute;right:5px;bottom:5px;width:27px;height:27px;border-radius:50%;border:none;padding:0;display:flex;align-items:center;justify-content:center;background:rgba(10,18,28,.5);color:#fff;cursor:pointer;transition:background .12s}
.wg-img-reload:hover{background:rgba(10,18,28,.72)}
.wg-img-reload svg{width:14px;height:14px;display:block}
.wg-img-reload.is-busy svg{animation:wp-spin 1s linear infinite}
.wg-prompt-tr{font-size:23px;font-weight:750;color:var(--blue-deep);line-height:1.3}
.wg-remove{border:none;background:none;padding:4px;color:var(--mut);cursor:pointer;display:inline-flex}
.wg-remove:hover{color:var(--red)}
.wg-remove svg{width:16px;height:16px;display:block}
.wg-tile.is-word{aspect-ratio:auto;min-height:64px;padding:14px 10px;touch-action:none;transition:border-color .15s,transform .18s,box-shadow .15s}
/* picked up: the tile rides the finger; released off-target it glides back */
.wg-tile.is-dragging{transition:none;position:relative;z-index:50;cursor:grabbing;border-color:var(--blue);box-shadow:0 16px 32px -12px rgba(15,40,70,.5)}
/* the question card arms while a word hovers over it */
.wg-prompt.is-drop{outline:2.5px dashed var(--blue);outline-offset:8px;border-radius:14px}
.wg-after{margin:10px 0 0;text-align:center}
.wg-after-ex{border:none;background:none;color:var(--mut);font:500 13px/1.5 inherit;font-family:inherit;cursor:pointer}
.wg-after-ex:hover{color:var(--ink)}
.wg-after-tr{color:var(--mut);font-size:12px;opacity:.85;margin-top:2px}
.wg-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.wg-tile{position:relative;aspect-ratio:1/1;border:1.5px solid var(--line);border-radius:16px;background:var(--surface);overflow:hidden;cursor:pointer;padding:0;display:flex;align-items:center;justify-content:center;transition:border-color .15s,transform .12s,box-shadow .15s}
.wg-tile:hover:not(:disabled){border-color:var(--blue);box-shadow:0 8px 20px -14px rgba(29,78,216,.4)}
.wg-tile:active:not(:disabled){transform:scale(.97)}
.wg-tile img{width:100%;height:100%;object-fit:cover;display:block}
.wg-tile.is-text{padding:12px}
.wg-tile-word{font-size:18px;font-weight:700;color:var(--ink);text-align:center;line-height:1.3;overflow-wrap:anywhere}
/* the meaning caption, revealed after answering — pictures teach */
.wg-tile-cap{position:absolute;left:0;right:0;bottom:0;padding:5px 8px;font-size:12px;font-weight:650;color:#fff;background:linear-gradient(to top,rgba(0,0,0,.72),transparent);text-align:center}
.wg-tile.is-text .wg-tile-cap{position:static;color:var(--mut);background:none;padding:6px 0 0}
.wg-tile.is-right{border-color:#2E9E5B;box-shadow:0 0 0 2px #2E9E5B inset}
.wg-tile.is-wrong{border-color:var(--red);box-shadow:0 0 0 2px var(--red) inset}
.wg-tile:disabled{cursor:default}
/* the saved-words list under the game: browse, hear, remove */
.wg-words{margin:16px 2px 0}
.wg-words-head{font-weight:700;font-size:13px;color:var(--mut);margin:0 0 6px}
.wg-words-list{display:flex;flex-direction:column;gap:2px}
.wg-word-row{display:flex;align-items:center;gap:9px;padding:6px 8px;border-radius:10px}
.wg-word-row:hover{background:var(--surface)}
.wg-word-img{width:30px;height:30px;border-radius:8px;object-fit:cover;flex:0 0 auto}
.wg-word-w{font-weight:650;flex:0 0 auto}
.wg-word-tr{color:var(--mut);font-size:12.5px;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.wg-word-rm{flex:0 0 auto;font-size:14px;line-height:1}
.wg-word-rm:hover{color:var(--red)}
/* the ★ save-word button in the popup head */
.word-pop-learn{margin-left:auto;align-self:center;flex:0 0 auto;background:none;border:0;padding:2px 4px;color:var(--mut);cursor:pointer;display:inline-flex;align-items:center}
.word-pop-learn svg{width:19px;height:19px;display:block}
.word-pop-learn:hover,.word-pop-learn.is-on{color:#f0a92e}
.word-pop-say{margin-left:0;font-size:17px;line-height:1} /* the ★ keeps the auto margin; the 🗣 rides beside it */

/* the text: player + speaker turns, every sentence tappable */
.player{display:block;width:100%;height:40px;margin:0 0 14px}
/* floating play/pause — always reachable while reading, no scroll back to the top */
.play-fab{position:fixed;right:16px;bottom:calc(18px + env(safe-area-inset-bottom));z-index:960;width:54px;height:54px;border-radius:50%;border:none;background:var(--blue-deep);color:#fff;font-size:20px;line-height:1;display:flex;align-items:center;justify-content:center;padding:0;cursor:pointer;box-shadow:0 12px 28px -8px rgba(15,40,70,.55);transition:transform .12s}
.play-fab:active{transform:scale(.94)}
/* a VIDEO text (a TikTok): vertical, centered, rounded — like where it came from */
.video-player{display:block;margin:0 auto 14px;max-width:100%;max-height:54vh;border-radius:20px;background:#000;box-shadow:0 18px 44px -20px rgba(10,25,45,.5)}
body.fullread .video-player{max-height:62vh}
.transcript{display:flex;flex-direction:column;gap:14px}
.turn-head{display:block;font-size:12px;font-weight:700;color:var(--mut);font-variant-numeric:tabular-nums;margin-bottom:3px;text-align:left}
button.turn-head{font-family:inherit;background:none;border:none;padding:2px 6px;margin:-2px -6px 1px;border-radius:8px;cursor:pointer;transition:background .15s}
button.turn-head:hover{background:rgba(59,130,246,.16)}
button.turn-head.is-playing{background:rgba(59,130,246,.28);color:var(--blue-deep)}
.turn-flow{margin:0;font-size:15.5px;line-height:1.75}
/* (a fullread "watching" block lived here for one commit — but a VIDEO card
   never reaches ⛶ Full page at all: its button says 🎬 Full screen and opens
   the FEED, so the rules were unreachable. The watching treatment lives on
   the feed now, where the watching happens; body.watching still drives the
   reading-view stage buttons' fade below.) */
/* 🎬 THE VIDEO STAGE — the video with its own subtitles and its own ⛶.
   Native fullscreen shows only the <video>: anything laid over the picture
   must fullscreen WITH it, so the video sits in a stage and the ⛶ fullscreens
   the stage. The subtitles are TV subtitles: white on the picture, shadowed,
   the translation under the line, and ⇅ moves the block to the top for anyone
   whose player controls sit where the words do. The stage's own buttons fade
   with watch-idle, exactly like the rest of the watching chrome. */
.video-stage{position:relative;width:fit-content;max-width:100%;margin:0 auto 14px}
.video-stage .video-player{margin:0}
.video-cap{position:absolute;left:5%;right:5%;bottom:7%;display:none;text-align:center;pointer-events:none}
.video-stage.cap-top .video-cap{bottom:auto;top:5%}
.video-cap.shown{display:block}
/* the reading stage's own pair takes the same outline — it never wore a box,
   but a shadow alone leaves half of every letter against the picture */
.video-cap-lb{margin:0;color:#fff;font-size:clamp(15px,2.4vw,28px);font-weight:700;line-height:1.35;
  paint-order:stroke fill;-webkit-text-stroke:.15em rgba(0,0,0,.95);
  text-shadow:0 1px 3px rgba(0,0,0,.95),0 0 14px rgba(0,0,0,.55)}
.video-cap-tr{margin:3px 0 0;color:#d7e6f4;font-size:clamp(12px,1.8vw,21px);font-weight:600;line-height:1.3;
  paint-order:stroke fill;-webkit-text-stroke:.15em rgba(0,0,0,.95);
  text-shadow:0 1px 3px rgba(0,0,0,.95)}
.stage-btns{position:absolute;top:10px;right:10px;display:flex;gap:8px;transition:opacity .35s ease}
.stage-btn{display:flex;align-items:center;justify-content:center;width:38px;height:38px;
  border:0;border-radius:999px;padding:0;cursor:pointer;background:rgba(10,16,24,.55);color:#fff;
  transition:background .15s ease,transform .08s ease}
.stage-btn svg{width:18px;height:18px;display:block}
.stage-btn:hover{background:rgba(10,16,24,.82)}
.stage-btn:active{transform:scale(.92)}
body.watching.watch-idle .stage-btns{opacity:0;pointer-events:none}
.video-stage:fullscreen{width:100%;height:100%;background:#000;display:flex;align-items:center;justify-content:center;margin:0}
.video-stage:fullscreen .video-player{width:100%;height:100%;max-height:none;border-radius:0}
/* the native fullscreen button showed a fullscreen WITHOUT the subtitles —
   ours is the one that keeps them, so it is the one that shows (Chromium;
   elsewhere both exist and ours still works) */
.video-stage video::-webkit-media-controls-fullscreen-button{display:none}
/* EVERY sentence on its own line — the page reads line by line, on any screen */
.sentence{display:block;margin:0 0 9px;padding:2px 3px;border-radius:8px;transition:background .15s}
.sentence.is-playing,.sentence.is-current{background:rgba(59,130,246,.28)}
/* words: tap → LOD sound + entry */
.word{
  display:inline;background:none;border:none;padding:2px 1px;margin:0;font:inherit;font-family:inherit;color:inherit;
  cursor:pointer;border-radius:6px;transition:background .15s;
  -webkit-box-decoration-break:clone;box-decoration-break:clone;
}
.word:hover{background:rgba(59,130,246,.18)}
/* the sentence's translation — each sentence has its own 🌐 to reveal it */
.sen-tr{display:none}
.sen-tr.shown{display:block;color:var(--mut);font-size:13px;line-height:1.5;margin:-5px 3px 11px;font-weight:500}
.tr-btn.is-on{opacity:1;background:rgba(59,130,246,.28)}
/* the sentence buttons: 🔊 speak and 🌐 translate — modern stroke icons */
.speak-btn{display:inline-flex;align-items:center;justify-content:center;vertical-align:middle;background:none;border:none;padding:3px 5px;margin:0 1px;cursor:pointer;color:var(--mut);opacity:.75;border-radius:8px;transition:opacity .15s,background .15s,color .15s}
.sen-menu-btn{opacity:.45} /* the per-sentence ⋮ stays quiet until wanted */
.sen-menu-btn:hover,.sen-menu-btn:focus-visible{opacity:1}
.speak-btn svg{width:14px;height:14px;display:block}
.speak-btn:hover{opacity:1;color:var(--blue-deep);background:rgba(59,130,246,.14)}
.speak-btn.is-playing,.speak-btn.is-on{opacity:1;color:var(--blue-deep);background:rgba(59,130,246,.26)}
/* the segment editor — a modern modal sheet */
.edit-backdrop{position:fixed;inset:0;z-index:880;background:rgba(10,18,28,.45);backdrop-filter:blur(2px);animation:fade-in .16s ease-out}
@keyframes fade-in{from{opacity:0}to{opacity:1}}
/* the segment editor fills the WHOLE page — the two text areas take the bulk of it */
.edit-pop{position:fixed;z-index:900;inset:0;transform:none;width:auto;max-width:none;height:100dvh;max-height:none;overflow-y:auto;overscroll-behavior:contain;display:flex;flex-direction:column;gap:11px;padding:16px max(18px,calc((100vw - 900px)/2)) calc(18px + env(safe-area-inset-bottom));background:var(--surface);border-radius:0;box-shadow:none}
.edit-pop .edit-field{flex:1 1 0;min-height:90px}
.edit-pop .edit-field textarea{flex:1 1 auto;min-height:90px;resize:none}
.sheet-handle{display:none;width:38px;height:4px;border-radius:2px;background:var(--line);margin:0 auto 2px;flex:0 0 auto}
.edit-header{display:flex;align-items:center;justify-content:space-between;gap:10px}
.edit-header strong{font-size:16px;color:var(--ink)}
.edit-header-btn{background:none;border:none;padding:8px 4px;font:600 14.5px/1 inherit;font-family:inherit;color:var(--mut);cursor:pointer}
.edit-header-btn:hover{color:var(--ink)}
.edit-header-save{color:var(--blue-deep);font-weight:800}
.edit-header-save:hover{color:var(--blue)}
.edit-field{display:flex;flex-direction:column;gap:4px;font-size:10.5px;color:var(--mut);font-weight:700;letter-spacing:.05em;text-transform:uppercase;flex:1}
.edit-field input,.edit-field textarea{border:1px solid transparent;border-radius:12px;padding:11px 13px;font:500 14px/1.5 inherit;font-family:inherit;color:var(--ink);background:rgba(59,130,246,.08);resize:vertical;text-transform:none;letter-spacing:0}
.edit-field input:focus,.edit-field textarea:focus{outline:none;border-color:var(--blue);background:var(--surface)}
/* the segment times, split like 8.23: [− 8 +] . [− 23 +] */
.edit-times{display:flex;flex-direction:column;gap:8px;align-items:stretch}
.time-row{display:flex;align-items:center;justify-content:space-between;gap:10px}
.time-label{font-size:10.5px;color:var(--mut);font-weight:700;letter-spacing:.05em;text-transform:uppercase}
.time-parts{display:flex;align-items:center;gap:3px}
.time-dot{font:800 17px/1 inherit;color:var(--mut)}
.mini-stepper{display:flex;align-items:stretch;border-radius:11px;background:rgba(59,130,246,.08);overflow:hidden}
.step-btn{width:32px;min-width:32px;border:none;background:none;font:700 17px/1 inherit;font-family:inherit;color:var(--blue-deep);cursor:pointer;padding:0}
.step-btn:hover{background:rgba(59,130,246,.14)}
.step-btn:active{background:rgba(59,130,246,.24)}
.mini-stepper input{width:44px;min-width:0;border:none;border-radius:0;background:none;text-align:center;font:600 15px/1 inherit;font-family:inherit;color:var(--ink);padding:11px 0}
.mini-stepper input:focus{outline:none;background:rgba(59,130,246,.06)}
.edit-test{align-self:flex-end}
.edit-test .btn{min-height:40px}
.edit-hint{font-size:11px;color:var(--mut);text-align:right;margin-top:-4px}
.edit-hint.is-bad{color:var(--red);font-weight:700}
.edit-head-label{font:700 12.5px/1.3 inherit;color:var(--blue-deep);font-variant-numeric:tabular-nums}
.turn-head-row{display:flex;align-items:center;gap:1px;margin-bottom:3px;flex-wrap:wrap}
.turn-head-row .turn-head{margin-bottom:0}
/* modern SVG glyphs on the small round controls */
.card-thumb-play svg{width:22px;height:22px;display:block}
.card-menu-btn svg{width:19px;height:19px;display:block}
.card-menu-item .cm-ic svg{width:16px;height:16px;display:block;margin:0 auto}
.prep-say svg{width:14px;height:14px;display:block}
.play-fab svg{width:22px;height:22px;display:block}
@media(max-width:620px){
  /* full-screen editor on the phone too, sliding up from the bottom */
  .edit-pop{inset:0;padding:10px 16px calc(18px + env(safe-area-inset-bottom));box-shadow:none;animation:sheet-up .2s ease-out}
  .sheet-handle{display:block}
  .edit-field input,.edit-field textarea{font-size:16px} /* no zoom-on-focus */
  .edit-header-btn{padding:10px 6px}
  /* ── THE PHONE: one row of actions, not three ────────────────────────────
     A view's head grew to five or six buttons, and wrapped them into stacks
     112 px tall before the text even began. They now sit in ONE row that
     SCROLLS sideways — the reading surface gets its screen back, and no
     button has to be shortened into a riddle. */
  .view-head{flex-wrap:nowrap;overflow-x:auto;overscroll-behavior-x:contain;scrollbar-width:none;-webkit-overflow-scrolling:touch;align-items:center;gap:6px;padding-bottom:2px}
  .view-head::-webkit-scrollbar{display:none}
  .view-head>strong{flex:0 0 auto;min-width:0;max-width:44vw;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .view-head>span{flex:0 0 auto;white-space:nowrap}
  .view-head .btn{flex:0 0 auto;white-space:nowrap;padding:8px 11px}
  .game-actions{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch}
  .game-actions::-webkit-scrollbar{display:none}
  .game-actions .btn{flex:0 0 auto;white-space:nowrap}
  /* the feed's rail keeps every control on ONE line: smaller targets, tighter
     nudge — the black menu shrinks with it and gives the song its screen.
     (Scoped through .feed: the base rules live further down the file and would
     otherwise win on order.) */
  /* a narrow phone SCROLLS the rail sideways instead of crushing its buttons */
  .feed .feed-rail{flex-wrap:nowrap;gap:1px;justify-content:space-between;overflow-x:auto;scrollbar-width:none}
  .feed .feed-rail::-webkit-scrollbar{display:none}
  .feed .rail-btn{flex:0 0 auto;width:38px;height:40px}
  .feed .rail-btn svg{width:21px;height:21px}
  .feed .feed-menu{gap:6px}
}

/* the word popup: the entry straight from the LOD API —
   lemma · class · IPA, translations, participle / plural */
.word-pop{position:fixed;z-index:1010;display:flex;flex-direction:column;gap:5px;padding:10px 13px;max-width:min(320px,calc(100vw - 20px));background:var(--surface);border:1.5px solid var(--line);border-radius:13px;box-shadow:0 12px 30px -12px rgba(15,40,70,.35);font-size:13px}
.word-pop-head{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}
.word-pop strong{color:var(--blue-deep);font-size:14.5px}
.word-pop-info{color:var(--mut);font-size:11.5px}
.word-pop-tr{line-height:1.45}
.word-pop-tr b{color:var(--blue);font-size:10.5px;letter-spacing:.04em;margin-right:2px}
/* all the word's meanings; each is TAPPABLE — pick the one used here and the
   examples regenerate for it. The one in use is highlighted. */
.word-pop-meanings{display:flex;flex-direction:column;gap:2px}
/* ONE translation — the sense used in this sentence */
.word-pop-meaning{display:flex;align-items:baseline;gap:5px;font:13px/1.4 inherit;font-family:inherit;color:var(--ink);border-radius:7px;padding:3px 5px;margin:0 -5px}
.word-pop-meaning.is-here{background:rgba(59,130,246,.16)}
.word-pop-meaning.is-here .wm-txt{font-weight:700;color:var(--blue-deep)}
/* the word's picture (concrete nouns): a dictionary photo or a generated one */
.word-pop-image{position:relative;margin:0 0 8px;border-radius:9px;overflow:hidden;background:var(--line)}
.word-pop-image img{display:block;width:100%;max-height:170px;object-fit:cover}
/* ↻ a different picture for this word */
.word-pop-img-reload{position:absolute;right:6px;bottom:6px;width:27px;height:27px;border-radius:50%;border:none;padding:0;display:flex;align-items:center;justify-content:center;background:rgba(10,18,28,.5);color:#fff;cursor:pointer;transition:background .12s}
/* the picture names its source (and says "looking…" while ↻ hunts) */
.word-pop-img-src,.wg-img-src{position:absolute;left:6px;bottom:6px;z-index:2;max-width:70%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;background:rgba(10,18,28,.62);color:#fff;font-size:10.5px;font-weight:700;line-height:1;padding:5px 8px;border-radius:999px;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);pointer-events:none}
.word-pop-img-reload:hover{background:rgba(10,18,28,.72)}
.word-pop-img-reload svg{width:14px;height:14px;display:block}
.word-pop-img-reload.is-busy svg{animation:wp-spin 1s linear infinite}
@keyframes wp-spin{to{transform:rotate(360deg)}}
.word-pop-extra{color:var(--mut);font-size:11.5px;border-top:1px solid var(--line);padding-top:5px;margin-top:2px}
.word-pop-register{color:#8a5a12;font-size:11px;font-weight:700}
.word-pop-example{display:flex;align-items:baseline;gap:6px;color:var(--ink);font-size:12.5px;font-style:italic;border-top:1px solid var(--line);padding-top:5px;margin-top:2px}
.word-pop-play{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;background:none;border:1px solid var(--line);border-radius:50%;width:24px;height:24px;padding:0;color:var(--blue-deep);cursor:pointer}
.word-pop-play svg{width:10px;height:10px;display:block}
.word-pop-play:hover{border-color:var(--blue)}
/* phone: a menu DOCKED to the bottom edge that starts compact and grows on tap.
   The grip is a chevron toggle (down = collapse, up = expand). */
.word-pop-grip{display:none;align-self:center;align-items:center;justify-content:center;width:66px;height:22px;padding:0;border:none;background:none;color:var(--mut);cursor:pointer;margin:-4px 0 2px;flex:0 0 auto}
.word-pop-grip svg{width:22px;height:22px;transition:transform .18s}
.word-pop.is-sheet .word-pop-grip{display:flex}
.word-pop.is-sheet.is-collapsed .word-pop-grip svg{transform:rotate(180deg)}   /* points UP when collapsed → tap to grow */
.word-pop.is-sheet.is-collapsed .word-pop-body{display:none}                   /* just the word bar until you expand */
.word-pop-head{padding-right:26px}
.word-pop-close{position:absolute;top:7px;right:8px;z-index:2;width:26px;height:26px;border:none;border-radius:8px;background:none;color:var(--mut);font:600 14px/1 inherit;font-family:inherit;cursor:pointer;padding:0}
.word-pop-close:hover{background:var(--line);color:var(--ink)}
.view-actions{margin-top:16px}

/* ── full page: ONLY the text — no chat box, no chrome ── */
.btn-small{min-height:34px;padding:6px 12px;font-size:12.5px}
body.fullread{padding-top:calc(16px + env(safe-area-inset-top));background:var(--surface)}
body.fullread .composer,body.fullread .view-head,body.fullread .view-actions,body.fullread .player{display:none}
.exit-full{
  position:fixed;top:calc(10px + env(safe-area-inset-top));right:12px;z-index:700;
  width:38px;height:38px;border-radius:50%;border:1px solid var(--line);background:var(--surface);
  color:var(--mut);font:700 15px/1 inherit;font-family:inherit;cursor:pointer;
}
.exit-full:hover{color:var(--ink);border-color:var(--blue)}

/* ── sign in ── */
.auth-overlay{position:fixed;inset:0;z-index:1000;display:flex;align-items:center;justify-content:center;padding:18px;background:rgba(14,20,28,.55);backdrop-filter:blur(6px)}
.auth-card{width:min(380px,94vw);display:flex;flex-direction:column;gap:10px;background:var(--surface);border-radius:20px;padding:24px;box-shadow:0 30px 70px -20px rgba(0,0,0,.5)}
/* fix-the-transcript overlay: paste the real transcript, correct the matches */
.fix-overlay{position:fixed;inset:0;z-index:1000;display:flex;align-items:center;justify-content:center;padding:18px;background:rgba(14,20,28,.55);backdrop-filter:blur(6px)}
.fix-card{width:min(560px,96vw);display:flex;flex-direction:column;gap:12px;background:var(--surface);border-radius:20px;padding:22px;box-shadow:0 30px 70px -20px rgba(0,0,0,.5)}
.fix-title{margin:0;font-size:19px}
.fix-note{margin:0;font-size:13px;color:var(--mut);line-height:1.5}
.fix-ta{width:100%;min-height:200px;max-height:52vh;resize:vertical;padding:12px 14px;border:1px solid var(--line);border-radius:12px;background:var(--bg);color:var(--fg);font-size:15px;line-height:1.55;font-family:inherit}
.fix-ta:focus{outline:none;border-color:var(--blue)}
.fix-status{min-height:18px;font-size:13px;color:var(--mut)}
.fix-actions{display:flex;justify-content:flex-end;gap:10px}
/* a corrected sentence flashes once so you can see what changed */
.sentence.is-fixed{animation:fixGlow 2.4s ease-out 1;border-radius:6px}
@keyframes fixGlow{0%,55%{background:rgba(80,190,120,.34)}100%{background:transparent}}
/* a ✓ badge on a card whose transcript has been corrected from the real one */
.card-corrected{display:inline-block;margin-left:6px;padding:0 6px;border-radius:8px;background:rgba(80,190,120,.2);color:#2f9c5a;font:800 11px/1.5 inherit;vertical-align:middle}
@media (prefers-color-scheme:dark){.card-corrected{background:rgba(80,190,120,.26);color:#8fe0ab}}
.auth-card h1{margin:0;font-size:24px;color:var(--blue-deep)}
.auth-note{margin:0;color:var(--mut);font-size:13px}
.auth-note-small{font-size:11.5px}
.auth-card input{border:1.5px solid var(--line);border-radius:12px;padding:11px 13px;font:500 15px/1.4 inherit;font-family:inherit;background:#fff;color:var(--ink)}
.auth-actions{display:flex;gap:8px}
.auth-actions .btn{flex:1}
.auth-status{min-height:18px;font-size:12.5px;color:var(--red)}
/* Google sign-in: an "or" divider, then Google's own button, centred */
.auth-google{display:flex;flex-direction:column;gap:10px}
.auth-or{display:flex;align-items:center;gap:10px;color:var(--mut);font-size:11.5px;font-weight:600}
.auth-or::before,.auth-or::after{content:"";flex:1;height:1px;background:var(--line)}
.auth-google-btn{display:flex;justify-content:center;min-height:40px;color-scheme:light}

/* ── PC layout (default): centered column, cards in a grid ──
   ── phone layout: full-width app feel, one card per row, bigger touch targets ── */
@media(max-width:620px){
  body{padding:118px 10px calc(24px + env(safe-area-inset-bottom))}
  /* ONE compact row, like a messaging app: ❔ beside a small pill input */
  .composer{width:calc(100vw - 12px);border-radius:24px;top:calc(6px + env(safe-area-inset-top));
    padding:6px 8px;gap:6px;flex-direction:row;flex-wrap:wrap;align-items:flex-end;
    box-shadow:0 14px 34px -14px rgba(18,54,95,.38)} /* the phone composer floats; the PC one stays flat */
  .composer-actions{order:-1;width:auto;margin:0}
  #helpBtn{width:40px;min-width:40px;height:40px;min-height:40px}
  #composerInput{flex:1;width:auto;height:40px;min-height:40px;max-height:120px;border-radius:20px;padding:9px 14px;font-size:16px} /* 16px: no zoom-on-focus */
  @supports (field-sizing: content){#composerInput{height:auto;field-sizing:content}} /* grows only when the text does */
  .composer-status{flex-basis:100%;margin:0 8px}
  .composer-status:empty{display:none} /* idle composer stays tiny */
  .help-panel{flex-basis:100%}
  #goBtn{display:none} /* the keyboard's Enter submits; pasted links run by themselves */
  /* the head's actions ride in ONE sideways-scrolling row (see the rule above):
     wrapping them stacked 112 px of buttons over the text */
  #fullPageBtn{margin-left:0}
  /* words and the sentence buttons are finger targets */
  .word{padding:3px 2px}
  .speak-btn{padding:5px 7px}
  .speak-btn svg{width:17px;height:17px}
  .sen-tr.shown{font-size:12.5px} /* the line-per-sentence layout is the base now */
  /* the word popup becomes a bottom sheet — thumb-friendly, full width */
  /* docked flush to the bottom edge — full width, rounded top only, so it reads
     as a bottom menu and never floats over the middle of the screen */
  .word-pop.is-sheet{
    left:0;right:0;top:auto;bottom:0;
    max-width:none;max-height:58vh;overflow-y:auto;font-size:14px;
    padding:12px 16px calc(14px + env(safe-area-inset-bottom));gap:7px;
    border-radius:18px 18px 0 0;border-bottom:none;
    box-shadow:0 -14px 44px -12px rgba(15,40,70,.45);
    animation:sheet-up .2s ease-out;
  }
  .word-pop.is-sheet strong{font-size:17px}
  .word-pop.is-sheet .word-pop-info{font-size:12.5px}
  .word-pop.is-sheet .word-pop-tr{font-size:13.5px}
  .word-pop.is-sheet .word-pop-play{width:30px;height:30px;font-size:12px}
  .word-pop.is-sheet .word-pop-close{width:36px;height:36px;top:8px;right:9px;font-size:17px;background:var(--line);color:var(--ink)}
  .word-pop.is-sheet .word-pop-head{padding-right:40px}
  @keyframes sheet-up{from{opacity:.4;transform:translateY(14px)}to{opacity:1;transform:translateY(0)}}
  .cards{grid-template-columns:1fr;gap:13px}    /* a single column on the phone — full-width video previews */
  .card{border-radius:16px}
  .card-thumb{height:200px}                     /* even taller on the phone so the video reads */
  .content{max-width:none}
  .view-head{margin:0 2px 10px}
  /* ── FULL-PAGE reading: the whole screen becomes the book page ── */
  body.reading{background:var(--surface)}
  #textView{padding:2px 6px}
  #textView .view-head{margin:0 0 12px}
  .transcript{gap:18px}
  .turn-flow{font-size:17.5px;line-height:1.8;letter-spacing:.1px} /* comfortable reading type, still finger-sized */
  .sentence{padding:2px 2px}
  .turn-head{font-size:11px;letter-spacing:.06em;text-transform:uppercase;margin-bottom:4px}
  .player{height:40px;margin-bottom:14px}
  /* the video leaves room for the transcript on a phone screen */
  .video-player{max-height:42vh;border-radius:16px}
  /* the game breathes on a small screen */
  .game-card{padding:14px;border-radius:16px;gap:12px}
  .game-prompt{font-size:16.5px}
  .tile{padding:8px 11px;font-size:15px}
  .game-check{min-height:44px}
  .auth-card{padding:20px;border-radius:16px}
}

/* ── the video FEED: one video per screen, swipe up for the next ── */
.feed{position:fixed;inset:0;z-index:950;background:#000;overflow-y:auto;scroll-snap-type:y mandatory;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;
  /* a swipe is a swipe: no text selection mid-drag, no long-press callout over the captions */
  user-select:none;-webkit-user-select:none;-webkit-touch-callout:none;
  /* NO SCROLLBAR over the film (the learner, in true fullscreen: "I should
     not see the grey things") — the wheel, the swipe and the arrows all still
     scroll; only Windows' grey rail and its buttons go */
  scrollbar-width:none}
.feed::-webkit-scrollbar{display:none}
/* thumb rules: no double-tap zoom on the controls, no grey tap flash */
.feed button{touch-action:manipulation;-webkit-tap-highlight-color:transparent}
.feed-slide{position:relative;height:100%;scroll-snap-align:start;scroll-snap-stop:always;display:flex;align-items:center;justify-content:center}
.feed-slide video{width:100%;height:100%;object-fit:contain;background:#000}
/* MUSIC in the same layout: the song's "picture" IS the transcription — a
   full-screen lyric wall, the current line lit and centered as it is sung,
   under a small header (glyph · dancing waves · title) */
.feed-art{position:absolute;inset:0;display:flex;flex-direction:column;background:radial-gradient(130% 100% at 50% 18%,#22405c 0%,#0a1220 72%);cursor:pointer}
.feed-art-top{display:flex;align-items:center;justify-content:center;gap:10px;padding:calc(14px + env(safe-area-inset-top)) 56px 10px}
.feed-art-glyph{font-size:24px;line-height:1}
.feed-art-wave{display:flex;align-items:center;gap:3px;height:20px}
.feed-art-wave i{width:4px;height:7px;border-radius:2px;background:rgba(127,231,255,.85)}
.feed-art-wave i:nth-child(2n){height:14px}
.feed-art-wave i:nth-child(3n){height:19px}
.feed-art-wave i:nth-child(5n){height:10px}
.feed-art.is-playing .feed-art-wave i{animation:feedWave 1.1s ease-in-out infinite}
.feed-art.is-playing .feed-art-wave i:nth-child(2n){animation-delay:.14s}
.feed-art.is-playing .feed-art-wave i:nth-child(3n){animation-delay:.28s}
.feed-art.is-playing .feed-art-wave i:nth-child(5n){animation-delay:.42s}
@keyframes feedWave{0%,100%{transform:scaleY(.45)}50%{transform:scaleY(1.2)}}
.feed-art-name{font-size:14px;font-weight:700;color:#dcecf9;opacity:.85;max-width:60%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* ONE line on stage at a time: it enters a beat ahead (dimmed), LIGHTS while
   it is sung, and fades away when its moment has passed */
.feed-lyrics{position:relative;flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:0 26px 9vh;text-align:center;overflow:hidden}
.feed-lyr-line{background:none;border:none;padding:0;font:800 30px/1.32 'Playfair Display',Georgia,'Times New Roman',serif;letter-spacing:.2px;color:rgba(255,255,255,.6);cursor:pointer;opacity:0;transform:translateY(-14px);transition:opacity .5s,transform .5s,color .3s,text-shadow .3s}
.feed-lyrics:not(.is-on) .feed-lyr-line{pointer-events:none} /* the faded-out line must not swallow the pause tap during a gap */
.feed-lyrics.is-on .feed-lyr-line{animation:lyrIn .5s ease both}
/* the LINE no longer flips white whole — its words light one by one as the
   speech reaches them, the stage's own karaoke */
.feed-lyrics.is-live .feed-lyr-line{text-shadow:0 0 28px rgba(127,231,255,.38)}
.feed-lyr-word{background:none;border:none;padding:0;margin:0;font:inherit;letter-spacing:inherit;color:inherit;cursor:pointer}
.feed-lyr-word.is-spoken{color:#fff}
.feed-lyr-word.is-now{text-shadow:0 0 30px rgba(127,231,255,.65)}
.feed.hide-sub .feed-lyr-line{display:none} /* the rail's transcript toggle reaches the stage too */
@keyframes lyrIn{from{opacity:0;transform:translateY(20px) scale(.94)}to{opacity:1;transform:none}}
.feed-lyr-tr{font-size:14px;line-height:1.45;font-weight:600;color:rgba(220,236,249,.8);opacity:0;transition:opacity .5s} /* longhand — `inherit` in the font shorthand's family slot voids the whole declaration */
.feed-lyrics.is-on .feed-lyr-tr{opacity:1}
.feed.hide-tr .feed-lyr-tr{display:none}
.feed{--sub-color:#fff;--tr-color:#fff;--sub-size:16.5px;--tr-size:13px}
/* ONE solid-black MENU at the bottom holds EVERYTHING — transcript,
   translation and the controls — and slides away when hidden, leaving a
   handle to bring it back */
/* ABOVE the caption float (z 6), deliberately: the float defaults to the same
   low ground the menu rises into, and under it the rail read fine but could
   not be TOUCHED — the words took every click. When the box is up, the box
   wins; in stillness it leaves and the words have the screen. */
.feed-menu{position:absolute;left:0;right:0;bottom:0;z-index:7;background:#000;
  padding:2px 14px calc(12px + env(safe-area-inset-bottom));border-radius:20px 20px 0 0;
  display:flex;flex-direction:column;gap:9px;transition:transform .28s ease,opacity .18s ease;
  opacity:0;pointer-events:none} /* only the ACTIVE video's menu shows — no bleed mid-scroll */
.feed-slide.is-active .feed-menu{opacity:1;pointer-events:auto}
/* the peek stays ABOVE the home indicator — a handle under the gesture bar is no handle */
.feed.menu-hidden .feed-menu{transform:translateY(calc(100% - 46px - env(safe-area-inset-bottom)))}
/* 🎬 THE MENU DISAPPEARS ENTIRELY — ON A PC (the learner: 'this layout is
   good for PC, but for phone you let like it was before'). A phone's menu
   stays put, its tuck handle the only way it hides, exactly as it always
   worked; the idle class still comes and goes but styles nothing there.
   (2026-08-11, "the telephone is not like YouTube full video": the idle
   fade serves BOTH hands now — hover wakes a PC, a tap wakes a phone — so
   these rules left their pointer:fine wrapper.) */
/* …while the film runs and the pointer is
   still (the learner: "the other buttons should TOTALLY disappear, appearing
   on hover") — the whole black band, not just the buttons in it: the captions
   do not live there any more, so nothing of value goes down with it. Any
   pointer movement is the hover that brings it back. AFTER the is-active rule
   in specificity, or the active slide's own opacity:1 would win. */
.feed.feed-idle .feed-slide.is-active .feed-menu{opacity:0;pointer-events:none}
/* …and the ✕ goes with it (the learner, in true fullscreen: "the close button
   should be autohide") — same clock, same fade, back on the same movement */
.feed .feed-close{transition:opacity .35s ease}
.feed.feed-idle .feed-close{opacity:0;pointer-events:none}
.feed.feed-idle .feed-nav{opacity:0;pointer-events:none}
/* 📜 the sentence panel — YouTube's chapter list, with sentences for
   chapters: the one being spoken lit and kept in view, a tap seeks to any.
   Longhand font properties, as ever — inherit in the font shorthand's family
   slot voids the whole declaration. Above the menu (8 over 7): both can be
   open, and the open panel is the thing being used. */
.feed-nav{position:absolute;right:12px;top:12px;bottom:calc(120px + env(safe-area-inset-bottom));width:min(380px,38vw);z-index:8;
  display:flex;flex-direction:column;background:rgba(8,12,18,.92);border-radius:14px;padding:10px 0;
  transition:opacity .35s ease}
.feed-nav-head{padding:2px 14px 8px;font-size:11.5px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;color:rgba(255,255,255,.6)}
.feed-nav-list{flex:1;overflow-y:auto;scrollbar-width:thin}
.feed-nav-row{display:block;width:100%;text-align:left;padding:8px 14px;border:0;background:none;color:#fff;cursor:pointer;
  font-family:inherit;font-size:14px;font-weight:600;line-height:1.45}
.feed-nav-row:hover{background:rgba(255,255,255,.08)}
.feed-nav-row.is-now{background:rgba(59,130,246,.22);color:#9DB8FF}
/* 🎬 THE WORDS FLOAT FREE — the caption block is TV subtitles ON the picture,
   draggable anywhere, shadowed so they read over any frame. Default: low and
   centred, like television; once placed, wherever the learner put them. */
/* ONE fixed width and a CENTRE anchor — anchored by a corner, each new
   sentence re-shaped the block around it and the words wandered with their
   own content ("moving by themselves"). TWO PLACES, chosen by ⇅ and
   remembered: low like television, or high — free dragging lived here for
   one commit and read as instability. */
.feed-info.feed-float{position:absolute;z-index:6;left:50%;top:84%;transform:translate(-50%,-50%);
  width:min(88%,860px);align-items:center;text-align:center}
.feed.cap-top .feed-info.feed-float{top:13%}
/* 🔤 THE OUTLINE, NOT THE BOX (the learner: "I do not want the background,
   but the letters should be readable — find a solution"). The scrim WAS the
   bulletproof answer, and broadcast specs do rank a translucent box first
   for exactly that reason — but it is a box, and the picture was behind it.
   The next thing every caption spec names is an OUTLINE, and it beats a drop
   shadow for one concrete reason: a shadow falls on ONE side, leaving the
   other half of every letterform touching the picture bare, while a stroke
   surrounds the letter whatever is behind it. Two details make it work:
   `paint-order:stroke fill` paints the stroke BEHIND the fill (without it a
   centred stroke eats the letterform from the inside and thin type turns to
   mush), and the stroke wears the same halo that already flips with the
   letter's luminance — a black letter gets a white outline, a white letter a
   black one. The width is in em so it holds its proportion from 11px to
   44px, and a soft double shadow rides on top for the busiest frames. */
.feed-float .feed-sub,.feed-float .feed-sub-tr{background:none;
  paint-order:stroke fill;-webkit-text-stroke:.17em var(--sub-halo,rgba(0,0,0,.95))}
.feed-float .feed-sub{text-shadow:0 1px 4px var(--sub-halo,rgba(0,0,0,.95)),
  0 0 14px var(--sub-halo,rgba(0,0,0,.95))}
.feed-float .feed-sub-tr{-webkit-text-stroke-color:var(--tr-halo,rgba(0,0,0,.95));
  text-shadow:0 1px 4px var(--tr-halo,rgba(0,0,0,.95)),
  0 0 14px var(--tr-halo,rgba(0,0,0,.95));opacity:1}
.feed-float .feed-sub,.feed-float .feed-sub-tr{align-self:center;text-align:center;
  padding:3px 12px;border-radius:10px;
  -webkit-box-decoration-break:clone;box-decoration-break:clone}
.feed-float .feed-sub-tr{border-left:0;margin-top:5px}
.feed-menu-toggle{align-self:center;width:96px;height:34px;padding:0;border:none;background:none;color:#fff;cursor:pointer;flex:0 0 auto;opacity:.8}
.feed-menu-toggle svg{width:26px;height:26px;transition:transform .28s ease}
.feed.menu-hidden .feed-menu-toggle svg{transform:rotate(180deg)}
/* an elegant caption hierarchy inside the black menu:
   a quiet source label → the Luxembourgish line (the hero) → the translation,
   set off by a soft accent rule → the Read action */
.feed-info{display:flex;flex-direction:column;color:#fff}
.feed-sub,.feed-sub-tr{align-self:flex-start;max-width:100%;width:fit-content}
/* the Luxembourgish — the line that leads (compact, so the video keeps room) */
.feed-sub{font-size:var(--sub-size);font-weight:650;letter-spacing:-.012em;line-height:1.4;color:var(--sub-color)}
/* the translation — quieter, a hairline accent marks it as the meaning below */
.feed-sub-tr{font-size:var(--tr-size);font-weight:450;letter-spacing:-.004em;line-height:1.4;color:var(--tr-color);opacity:.82;margin-top:6px;padding-left:11px;border-left:2px solid rgba(255,255,255,.28)}
.feed-sub:empty,.feed-sub-tr:empty{display:none}
/* 🖥 WATCHING ON A PC: the caption block bigger and centred — the original
   ask, finally on the page it was asked about. AFTER the base rules above,
   deliberately: same specificity, and the later rule wins — placed before
   them, this block loses silently (measured: 16.5px where 24 was written). */
/* keyed to the DEVICE, not the width — two layouts, totally: a machine with
   a real hovering pointer is a PC at any window size; everything else is a
   phone, even a tablet or a desktop-site phone browser reporting 1000px */
@media (hover:hover) and (pointer:fine){
  .feed{--sub-size:24px;--tr-size:17px}
  .feed-sub{line-height:1.45}
  .feed-sub-tr{border-left:0;padding-left:0;opacity:.9}
  .feed-sub,.feed-sub-tr{align-self:center;text-align:center}
  /* (cover lived here for one commit — it fills by ZOOMING, and the learner
     saw the picture grow past the screen: "it is bigger than the screen".
     contain is the honest fit: the whole frame, edge to edge on the long
     axis, and the menu that made the black band below it hides itself now.) */
}
/* every subtitle word is tappable, and LIGHTS UP as the speech reaches it —
   karaoke: dim until spoken, full color once spoken, a soft box on the word
   being said right now */
.feed-word{background:none;border:none;padding:1px 3px;margin:0;font:inherit;font-family:inherit;color:inherit;cursor:pointer;border-radius:6px;opacity:.5;transition:opacity .12s,background .12s}
.feed-word.is-spoken{opacity:1}
.feed-word.is-now{background:rgba(255,255,255,.22)}
.feed-word:hover,.feed-word:active{opacity:1;background:rgba(255,255,255,.28)}
/* the controls: a row inside the black menu — white icons read on the black */
.feed-rail{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-around;gap:4px} /* wraps: a music slide carries ten controls */
.rail-btn.rail-like.is-liked{color:#ff5c8a} /* ♥ filled — this one is yours */
.rail-btn.rail-like.is-liked svg{fill:#ff5c8a}
.mfilter.mfilter-liked.is-on{background:#ff5c8a;border-color:#ff5c8a;color:#fff}
.rail-btn{display:inline-flex;align-items:center;justify-content:center;width:44px;height:44px;border:none;border-radius:50%;background:none;color:#fff;cursor:pointer;transition:background .15s,transform .12s}
/* (the − ±0s + whole-song nudge lived here; ✎ Edit fixes lines where they are
   actually wrong, so a blanket half-second apology had nothing left to do) */
.rail-btn svg{width:24px;height:24px}
.rail-btn:active{background:rgba(255,255,255,.16);transform:scale(.9)}
.feed.hide-sub .feed-sub{display:none}
.feed.hide-tr .feed-sub-tr{display:none}
.feed.hide-sub .rail-sub,.feed.hide-tr .rail-tr{opacity:.4}
/* the 🎨 palette: two rows of swatches, centered above the menu */
.feed-palette{position:absolute;left:50%;transform:translateX(-50%);bottom:calc(100% + 8px);z-index:6;display:flex;flex-direction:column;gap:8px;padding:12px;border-radius:14px;background:#000;border:1px solid rgba(255,255,255,.12)}
.feed-pal-row{display:flex;align-items:center;gap:6px}
.feed-pal-row>span{color:#fff;font-size:11px;font-weight:600;width:74px}
.feed-swatch{width:26px;height:26px;border:2px solid rgba(255,255,255,.5);border-radius:50%;cursor:pointer;padding:0}
/* A− / A+ beside the swatches: the letter size is a reading choice like the
   colour, so it lives in the same panel */
.feed-size{display:inline-flex;gap:5px;margin-left:8px}
.feed-size-btn{min-width:34px;height:26px;padding:0 7px;border:1px solid rgba(255,255,255,.4);border-radius:999px;background:none;color:#fff;font:700 12px/1 inherit;font-family:inherit;cursor:pointer}
.feed-size-btn:hover{background:rgba(255,255,255,.14)}
.feed-swatch:active{transform:scale(.9)}
/* ⏪⏩ the double-tap's answer: a brief glyph on the side the finger chose */
.feed-step{position:absolute;top:50%;transform:translateY(-50%);z-index:6;width:62px;height:62px;border-radius:50%;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.45);color:#fff;opacity:0;pointer-events:none;transition:opacity .16s}
.feed-step svg{width:30px;height:30px}
.feed-step.left{left:16px}
.feed-step.right{right:16px}
.feed-step.is-on{opacity:1}
.feed-unmute{display:inline-flex;align-items:center;gap:7px;position:absolute;top:calc(16px + env(safe-area-inset-top));left:14px;background:rgba(0,0,0,.45);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.1);border-radius:22px;color:#fff;padding:9px 15px;font:600 13px/1 inherit;font-family:inherit;cursor:pointer;z-index:5}
.feed-unmute svg{width:17px;height:17px}
.feed-close{display:inline-flex;align-items:center;justify-content:center;position:fixed;top:calc(14px + env(safe-area-inset-top));right:12px;width:44px;height:44px;border:none;border-radius:50%;background:rgba(0,0,0,.4);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.1);color:#fff;cursor:pointer;z-index:960}
.feed-close svg{width:20px;height:20px}
body.feed-open{overflow:hidden}

/* ── dark ── */
@media(prefers-color-scheme:dark){
  :root{--ink:#D8E8F8;--mut:#8FA9C4;--line:#233850;--surface:#111A25;--bg:#0E141C}
  body{background:#0E141C}
  .composer{background:#101a26;border-color:#233850}
  @media(max-width:620px){.composer{box-shadow:0 14px 34px -12px rgba(0,0,0,.55)}}
  #composerInput{background:#0E1622;border-color:#233850;color:var(--ink)}
  .help-row{background:#111A25;border-color:#233850}
  .suggest-row:hover,.suggest-row.is-active{background:rgba(59,130,246,.18)}
  .suggest-row strong{color:#A9CEEC}
  .card{background:#111A25;border-color:#233850}
  .saved-row{background:#111A25;border-color:#233850}
  .saved-del{border-left-color:#233850}
  .saved-progress{background:rgba(46,139,114,.24);color:#7fd3b8}
  .saved-more{border-color:#233850;color:#A9CEEC}
  .cards-search{background:#0E1622;border-color:#233850}
  .card-thumb-video{background:linear-gradient(135deg,#1b2937,#141f2c)}
  .card-thumb-audio{background:linear-gradient(135deg,#241a35,#191325)}
  .card-thumb-text{background:linear-gradient(135deg,#12261b,#0e1a14)}
  .card-wave i{background:rgba(160,150,220,.55)}
  .card-menu-btn{background:rgba(17,26,37,.82);color:#A9CEEC}
  .card-menu-btn:hover{background:#16222F}
  .pl-menu{background:#111A25;border-color:#233850}
  .pl-menu-row{color:var(--ink)}
  .pl-menu-input{background:#0E1622;border-color:#233850;color:var(--ink)}
  .media-list-bar{background:rgba(46,139,114,.16);border-color:rgba(46,139,114,.4)}
  .mlb-label{color:#7fd6bd}
  .mlb-btn{background:#111A25;border-color:rgba(46,139,114,.5);color:#7fd6bd}
  .mfilter{background:#111A25;border-color:#233850;color:#A9CEEC}
  .mfilter.is-on{background:var(--blue);border-color:var(--blue);color:#06121f}
  .make-input{background:#0E1622;border-color:#233850}
  .make-chip{background:#111A25;border-color:#233850;color:#A9CEEC}
  .make-chip.is-on{background:var(--blue);border-color:var(--blue);color:#06121f}
  .make-example{border-color:#233850;color:#A9CEEC}
  .game-card{background:#111A25;border-color:#233850}
  .tile{background:#16222F;border-color:#2A415C;color:var(--ink)}
  .wg-tile{background:#16222F;border-color:#2A415C}
  .game-answer .tile{background:rgba(59,130,246,.16)}
  .game-score{color:#A9CEEC}
  .sg-word{color:#E8F2FB}
  .sg-clarity{background:rgba(127,231,255,.14)}
  .game-solution{color:#4FBF7F}
  .game-answer.is-right{border-color:#2E9E5B;background:rgba(46,158,91,.14)}
  .prep-opt{background:#16222F;border-color:#2A415C;color:var(--ink)}
  .prep-slot{color:#A9CEEC}
  .prep-feedback{background:#0E1622;border-color:#233850}
  .prep-chunk{color:#A9CEEC}
  .auth-card{background:#111A25}
  .word-pop{background:#111A25;border-color:#233850}
  .word-pop strong{color:#A9CEEC}
  .auth-card input{background:#0E1622;border-color:#233850;color:var(--ink)}
  .btn-ghost{background:rgba(59,130,246,.14);color:#A9CEEC}
  .view-head strong{color:#A9CEEC}
  .card strong,.help-row strong{color:#A9CEEC}
}

/* ── LYRICS: full-screen music mode — its own dark stage, light or dark app ── */
.lyrics{position:fixed;inset:0;z-index:940;background:linear-gradient(165deg,#0E141C 0%,#16202E 55%,#1B2A3C 100%);color:#fff;display:flex;flex-direction:column}
body.lyrics-open{overflow:hidden}
.lyrics-head{display:flex;align-items:center;gap:10px;padding:14px 16px;padding-top:calc(14px + env(safe-area-inset-top))}
.lyrics-head strong{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:15px}
.lyrics-btn{border:none;background:rgba(255,255,255,.09);color:#fff;border-radius:50%;width:38px;height:38px;display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:15px;flex:0 0 auto;transition:background .12s}
.lyrics-btn:hover{background:rgba(255,255,255,.18)}
.lyrics-btn svg{width:17px;height:17px}
/* THE HALF-SCREEN OF AIR ABOVE AND BELOW THE SONG IS A MARGIN ON THE TRACK, NOT
   PADDING ON THE SCROLLER — and that is not a style choice. With border-box
   sizing an element can never be shorter than its own padding, whatever
   flex-basis or min-height say: 32vh top and bottom is 520px of floor on a
   phone, so the scroller refused to shrink, and everything below it — the ⏺
   panel, the whole control row — was pushed off the bottom of the window.
   min-height:0 does NOT fix that; it cannot compress padding. As a margin on
   the child the same air becomes scrollable CONTENT, the scroller is free to be
   any height at all, and the geometry is unchanged (every line is placed from
   .lyrics-track's own top, which is what moved down by 32vh either way). */
.lyrics-scroll{flex:1;overflow-y:auto;padding:0 20px;scrollbar-width:none;min-height:0}
.lyrics-scroll::-webkit-scrollbar{display:none}
/* THE SUBTITLE TIMELINE: one straight time axis. HORIZONTAL RULES cross the
   page at round seconds wearing their clock, every line sits at its own
   moment, and its band is as tall as it is sung. */
.lyrics-track{position:relative;margin-top:32vh;margin-bottom:32vh} /* the air that keeps the sung line near the middle — see .lyrics-scroll above for why it is here and not there */
/* 〰 the sound behind the words: amplitude across, time down, stretched by the
   zoom instead of redrawn (no pinch frame ever touches it) */
.lyrics-wave{position:absolute;left:0;top:0;width:100%;height:100%;z-index:0;opacity:0;transition:opacity .5s;pointer-events:none}
.lyrics-wave.is-on{opacity:.42} /* present, never competing with the words */
.lyrics-rule{position:absolute;left:0;right:0;height:0;border-top:1px dashed rgba(255,255,255,.11);pointer-events:none}
/* THE PLAYHEAD: the one line that says where time is, running with the music */
.lyrics-playhead{position:absolute;left:0;right:0;top:0;height:0;border-top:2px solid #ff5c8a;box-shadow:0 0 14px rgba(255,92,138,.45);pointer-events:none;z-index:6;will-change:transform}
.lyrics-playhead span{position:absolute;right:0;top:-9px;background:#ff5c8a;color:#12202e;font-family:inherit;font-size:10px;font-weight:800;line-height:1;letter-spacing:.04em;padding:4px 7px;border-radius:9px}
.lyrics-rule span{position:absolute;left:0;top:-6px;font-family:inherit;font-size:10px;font-weight:600;line-height:1;letter-spacing:.04em;color:rgba(220,236,249,.34)} /* it lives in the gutter the lines leave free */
/* the WORDS fade with the reading position, never the band beside them —
   a timeline broken into bright and dark pieces reads as damage, not as time */
/* the right gutter now holds TWO handles — ✎ and ⇅ — so the words stop clear of
   both instead of running underneath them */
.lyrics-line-wrap{position:absolute;left:46px;right:0;padding-right:72px;transition:transform .25s;transform-origin:left center}
.lyrics-line-wrap .lyrics-line,.lyrics-line-wrap .lyrics-tr{opacity:.42;transition:opacity .25s}
/* the band: it begins ON the line's moment and runs as long as the voice does,
   so the empty page beneath it is the music playing on alone */
.lyrics-line-wrap::before{content:'';position:absolute;left:-10px;right:0;top:0;height:var(--dur,3px);border-top:2px solid rgba(127,231,255,.45);background:linear-gradient(to bottom,rgba(127,231,255,.10),rgba(127,231,255,0));border-radius:2px;pointer-events:none}
.lyrics-line-wrap.is-now::before{border-top-color:#7fe7ff;background:linear-gradient(to bottom,rgba(127,231,255,.22),rgba(127,231,255,0));box-shadow:0 0 14px rgba(127,231,255,.35)}
/* where the time came from: heard (solid cyan) · reasoned out (dashed amber) ·
   placed by the learner's own hand (gold) */
.lyrics-line-wrap.is-guess::before{border-top-style:dashed;border-top-color:rgba(255,196,120,.6);background:linear-gradient(to bottom,rgba(255,196,120,.07),transparent)}
.lyrics-line-wrap.is-pin::before{border-top-color:#ffd166;box-shadow:0 0 10px rgba(255,209,102,.3)}
/* ↕ the box's own two edges, in the left gutter where no word ever goes:
   the top says where the voice comes in, the bottom where it stops */
.lyrics-edge{position:absolute;left:-40px;width:34px;height:20px;display:flex;align-items:center;justify-content:center;border:none;background:none;padding:0;cursor:ns-resize;touch-action:none;opacity:.45;transition:opacity .15s}
.lyrics-edge::before{content:'';width:20px;height:2px;border-radius:2px;background:#7fe7ff}
.lyrics-edge.top{top:-10px}
.lyrics-edge.bot{top:calc(var(--dur,3px) - 10px)}
.lyrics-edge:hover,.lyrics-edge:active{opacity:1}
.lyrics-edge:active::before{height:3px;box-shadow:0 0 10px rgba(127,231,255,.7)}
.lyrics-line-wrap.is-now .lyrics-edge{opacity:.8}
@media (max-width:620px){.lyrics-edge{left:-34px;width:30px}}
/* ── ↕ WHERE TWO LINES TOUCH, BOTH EDGES STAY ────────────────────────────────
   A tapped line reaches its neighbour, so boxes touch — and at a touching
   boundary the upper line's BOTTOM handle and the lower line's TOP handle sat
   at exactly the same point, in the same gutter, the same 20px tall. They
   overlapped completely: the later one in the DOM took every press and the
   other could not be grabbed at all.
   The first fix WELDED them — one handle dragging both sides — which cured the
   overlap and caused something worse: a song has silences, an instrumental, a
   verse the words do not carry, and a welded boundary can never be opened into
   one. Continuous is what tapping GIVES you; it must not be what the page
   FORCES on you. So both handles stay and are merely moved apart until each can
   be hit: the upper line's end just above the boundary, the lower line's start
   just below it, ~22px between their centres. Each still answers for one moment
   only, and pulling either away from the other is how a silence gets drawn. */
.lyrics-line-wrap.is-seambot .lyrics-edge.bot{top:calc(var(--dur,3px) - 21px)}
.lyrics-line-wrap.is-seamtop .lyrics-edge.top{top:1px}
/* …and a touching pair is drawn a little brighter, so it reads as a joint that
   CAN be opened rather than as two strays that happen to be near each other */
.lyrics-line-wrap.is-seambot .lyrics-edge.bot::before,
.lyrics-line-wrap.is-seamtop .lyrics-edge.top::before{width:26px;background:#9fdcff}
/* ⇅ glide: its own touch surface — the page still scrolls with a plain finger */
/* ✎ the whole line: its words, its meaning, its moment. It sits BESIDE the ⇅
   rather than above or below it — the wrap is only as tall as its own text, so
   two stacked 36px buttons would collide on any single-line lyric. */
.lyrics-editbtn{position:absolute;right:36px;top:50%;transform:translateY(-50%);width:32px;height:36px;border:none;background:none;color:rgba(220,236,249,.35);font-size:15px;line-height:1;cursor:pointer;padding:0;transition:color .12s}
.lyrics-editbtn:hover,.lyrics-editbtn:active{color:#fff}
.lyrics-line-wrap.is-now .lyrics-editbtn{color:rgba(220,236,249,.6)}
/* the two clocks in the ✎ card, each under its own word */
.lyrics-editclock{display:flex;flex-direction:column;gap:4px;flex:1;min-width:0}
.lyrics-editclock span{font-size:11.5px;font-weight:700;color:var(--mut)}
.lyrics-glide{position:absolute;right:0;top:50%;transform:translateY(-50%);width:36px;height:36px;border:none;background:none;color:rgba(220,236,249,.35);font-size:18px;line-height:1;cursor:grab;touch-action:none;padding:0}
.lyrics-glide:active{cursor:grabbing;color:#fff}
.lyrics-line-wrap.is-held{z-index:4}
.lyrics-line-wrap.is-now{z-index:3} /* where lines crowd, the one being sung stays legible */
.lyrics-line-wrap.is-held .lyrics-line{opacity:1;text-shadow:0 0 22px rgba(127,231,255,.35)}
.lyrics-chip{position:absolute;left:0;top:-26px;background:rgba(0,0,0,.7);border:1px solid rgba(255,255,255,.16);color:#fff;border-radius:10px;padding:4px 9px;font-size:12px;font-weight:700;pointer-events:none;white-space:nowrap;z-index:3}
.lyrics-line-wrap.is-past .lyrics-line,.lyrics-line-wrap.is-past .lyrics-tr{opacity:.22}
.lyrics-line-wrap.is-now{transform:scale(1.03)}
.lyrics-line-wrap.is-now .lyrics-line,.lyrics-line-wrap.is-now .lyrics-tr{opacity:1}
.lyrics-line{border:none;background:none;color:inherit;font:800 28px/1.3 'Playfair Display',Georgia,'Times New Roman',serif;text-align:left;cursor:pointer;padding:0}
/* a phone has little width to spare: a smaller face and a slimmer gutter keep
   a lyric to one or two lines, so the time axis stays compact and honest */
@media (max-width:620px){
  .lyrics-scroll{padding-left:14px;padding-right:14px}
  .lyrics-line-wrap{left:38px;padding-right:62px}
  .lyrics-editbtn{right:32px;width:28px}
  .lyrics-line{font-size:21px}
  .lyrics-glide{width:32px;height:32px}
}
.lyrics-tr{display:none;font-size:14px;color:rgba(255,255,255,.72);margin-top:3px}
.lyrics.show-tr .lyrics-tr{display:block}
/* IT MUST WRAP. Eight round buttons do not fit across a phone, and a row that
   overflows a CENTRED flex box is cut off at both ends at once — ⏺, the last of
   them and the one a hand reaches for on every beat, vanished off the right
   edge with no way to scroll to it. Wrapping costs a second line on a narrow
   screen and nothing at all on a wide one. */
.lyrics-ctrl{position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:14px;row-gap:8px;padding:12px 16px calc(16px + env(safe-area-inset-bottom))}
@media (max-width:620px){.lyrics-ctrl{gap:8px;row-gap:8px;padding-left:8px;padding-right:8px}}
/* − + resize the page itself; the reading appears when it changes and fades */
.lyrics-zoom{font-family:inherit;font-size:20px;font-weight:700;line-height:1}
.lyrics-rate,.lyrics-loop{font-family:inherit;font-size:13px;font-weight:800;line-height:1}
.lyrics-rate.is-on,.lyrics-loop.is-on{background:rgba(255,209,102,.22);color:#ffd166}
/* the looped stretch, drawn on the axis itself */
.lyrics-loopband{position:absolute;left:0;right:0;background:rgba(255,209,102,.10);border-top:1px solid rgba(255,209,102,.5);border-bottom:1px solid rgba(255,209,102,.5);pointer-events:none;z-index:1}
.lyrics-loopband.hidden{display:none}
/* ⏺ THE TAP PANEL — the line you are about to time, big enough to read at a
   glance while the music runs. It carries the playhead's red, because a tap and
   the playhead mark the same instant. The whole panel is the tap surface: a
   forgiving target beats an accurate one when a hand is keeping time. */
.lyrics-tapbar{position:relative;margin:0 12px 8px;padding:12px 15px 11px;border-radius:18px;cursor:pointer;
  background:linear-gradient(180deg,rgba(255,92,138,.17),rgba(255,92,138,.05));
  border:1px solid rgba(255,92,138,.4);box-shadow:0 -12px 34px -20px rgba(255,92,138,.65);
  -webkit-user-select:none;user-select:none;touch-action:manipulation}
/* 🎙 while the game is listening to you, the button IS the recorder — the one
   red thing on the board, so there is never a doubt that the mic is open */
#gameSayBtn.is-rec{background:#ff5c8a;border-color:#ff5c8a;color:#fff;animation:tap-pulse 1.2s ease-in-out infinite}
/* 🗣 why a word came out wrong: quieter than the sentence it is about, so it
   reads as an aside from a teacher rather than another thing to answer */
.say-tips{display:flex;flex-direction:column;gap:5px;margin:6px 0 0;font-size:13px;line-height:1.45;color:var(--mut)}
.say-tips:empty{display:none}
.say-tip{margin:0}
.say-tip b{color:#ffd479;font-weight:800}
/* ── 💬 THE CONVERSATION PAGE ───────────────────────────────────────────────
   Laid out the way an AI chat is: the talk fills the glass, the box waits at
   the foot of it, and the whole thing is a fixed sheet so the page behind
   cannot scroll under your thumb mid-sentence. A centred column, because a
   line of text running the full width of a monitor is unreadable — the same
   reason the lyrics stage has one. */
.chatpage{position:fixed;inset:0;z-index:60;display:flex;flex-direction:column;background:var(--bg)}
body.chat-open{overflow:hidden}
body.chat-open .composer{display:none} /* ONE box at a time: this page has its own */
.chatpage-head{flex:0 0 auto;display:flex;align-items:center;gap:10px;padding:10px 14px;border-bottom:1px solid var(--line);background:var(--surface)}
/* the two dials that belong mid-talk — corrections and language */
.chat-dials{flex:0 0 auto;display:flex;gap:7px;flex-wrap:wrap;padding:7px 14px;border-bottom:1px solid var(--line);background:var(--surface)}
.chat-dials .make-chip{font-size:12px;padding:5px 10px}
.chatpage-head strong{flex:1;text-align:center;font-size:14.5px;color:var(--ink)}
.chatpage-x{width:34px;height:34px;flex:0 0 auto;border:none;border-radius:50%;background:transparent;color:var(--mut);font-size:15px;cursor:pointer}
.chatpage-x:hover{background:rgba(0,0,0,.05);color:var(--ink)}
/* min-height:0 so the log — not the page — is what scrolls (the same trap the
   lyrics stage fell into: a flex child will not shrink without it) */
/* the subjects on an empty page: an invitation, not a wall of instruction */
/* the offer that appears over a selection: close to the words it is about,
   and gone the moment the selection is */
/* the words in a chosen run: the app draws this, because the browser will not
   select across buttons and these words are all buttons */
/* the bar that says how much is chosen — the phone's whole visible half of
   this feature, since there is no drag to see */
.sel-bar{position:fixed;left:50%;transform:translateX(-50%);z-index:960;
  bottom:calc(14px + env(safe-area-inset-bottom));display:flex;align-items:center;gap:9px;
  padding:8px 10px 8px 14px;border-radius:999px;background:var(--blue-deep);color:#fff;
  box-shadow:0 10px 26px -8px rgba(0,0,0,.55);font-size:13px;max-width:calc(100vw - 24px)}
.sel-bar-n{font-weight:600;white-space:nowrap;opacity:.92}
.sel-bar-go{border:none;border-radius:999px;padding:7px 12px;background:#fff;color:var(--blue-deep);
  font:inherit;font-weight:700;cursor:pointer;white-space:nowrap}
.sel-bar-go.is-off{opacity:.45;cursor:default}
.btn.is-on{background:var(--blue-deep);border-color:var(--blue-deep);color:#fff}
.sel-bar-no{border:none;background:none;color:#fff;font:inherit;font-size:16px;cursor:pointer;padding:2px 6px;opacity:.85}
/* iOS answers a long press with its own magnifier and callout — which would
   take the gesture this feature is opened with */
#transcript .word{-webkit-touch-callout:none}
/* while a run is being drawn the page must hold still under the finger */
body.is-selrun #transcript{touch-action:none}
body.is-selrun{-webkit-user-select:none;user-select:none}
/* a pale tint read as a smudge rather than a choice — the chosen words carry the
   app's own blue, at full strength, so there is no doubt what is held */
#transcript .word.is-selrange{background:var(--blue);color:#08243a;border-radius:4px}
/* iOS answers a long press on text with its magnifier and its own selection, which
   would take the very gesture this is opened with — and native selection across
   these buttons never worked anyway */
#transcript .word{-webkit-user-select:none;user-select:none}
.sel-make{position:absolute;z-index:900;padding:7px 12px;border:none;border-radius:999px;
  background:var(--blue-deep);color:#fff;font:inherit;font-size:13px;font-weight:700;
  box-shadow:0 6px 18px -6px rgba(0,0,0,.45);cursor:pointer;white-space:nowrap}
.sel-make:hover{filter:brightness(1.08)}
.chat-topics{display:flex;flex-wrap:wrap;gap:7px;margin:10px 0 0}
.chat-topic-own{font-style:italic}
/* …and once chosen it stays visible in the head, so you always know what the
   conversation is supposed to be about */
.chatpage-topic{font-size:11.5px;color:var(--mut);text-align:center;margin:2px 0 0}
.chatpage-log{flex:1;min-height:0;overflow-y:auto;padding:18px 14px 8px;display:flex;flex-direction:column;gap:14px}
.chatpage-inner{width:100%;max-width:720px;margin:0 auto;display:flex;flex-direction:column;gap:14px}
.chatpage-foot{flex:0 0 auto;padding:10px 14px calc(12px + env(safe-area-inset-bottom));border-top:1px solid var(--line);background:var(--surface)}
.chatpage-box{display:flex;align-items:flex-end;gap:8px;max-width:720px;margin:0 auto;padding:6px 6px 6px 14px;border:1px solid var(--line);border-radius:22px;background:var(--bg)}
.chatpage-box textarea{flex:1;min-width:0;border:none;background:none;resize:none;outline:none;font:inherit;font-size:15px;line-height:1.45;color:var(--ink);padding:8px 0;max-height:160px}
/* while a spoken turn is being recorded the send button ENDS it — the one live
   control on the page, and the same pink the other recorders use */
.chatpage-send.is-live{background:#ff5c8a;border-color:#ff5c8a;color:#fff;animation:tap-pulse 1.2s ease-in-out infinite}
/* 🎙 and 💡 share the send button's geometry. A stray `.chatpage-mic,` once sat
   on the pink rule above instead: the IDLE mic pulsed as if live, wore a pink
   outset border the browser invented, and had no shape of its own at all. */
.chatpage-mic,
.chatpage-send{flex:0 0 auto;width:38px;height:38px;border:none;border-radius:50%;cursor:pointer;font-size:16px;line-height:1}
.chatpage-mic{background:rgba(0,0,0,.06);color:var(--ink)}
.chatpage-mic:hover{background:rgba(0,0,0,.1)}
/* while it is listening the mic IS the recorder — the one red thing on a calm
   page, so there is never a doubt the microphone is open */
.chatpage-mic.is-rec{background:var(--red);color:#fff;animation:tap-pulse 1.2s ease-in-out infinite}
.chatpage-send{background:var(--blue-deep);color:#fff;font-weight:800}
.chatpage-send:hover{filter:brightness(1.1)}
.chatpage-status{max-width:720px;margin:6px auto 0;min-height:16px;font-size:12px;color:var(--mut);text-align:center}
/* …and the thinking dots, so a pause reads as thought rather than as breakage */
.chat-think{display:flex;gap:5px;align-self:flex-start;padding:12px 14px}
.chat-think i{width:7px;height:7px;border-radius:50%;background:var(--mut);opacity:.45;animation:chatdot 1.1s ease-in-out infinite}
.chat-think i:nth-child(2){animation-delay:.18s}
.chat-think i:nth-child(3){animation-delay:.36s}
@keyframes chatdot{0%,60%,100%{transform:translateY(0);opacity:.35}30%{transform:translateY(-4px);opacity:.9}}
@media (max-width:620px){.chatpage-log{padding:14px 10px 6px}.chatpage-foot{padding:8px 10px calc(10px + env(safe-area-inset-bottom))}}
/* 💬 the conversation: yours on the right, its answers on the left — the shape
   every messaging app has taught, so nothing needs explaining.
   IN THE APP'S OWN COLOURS, not the lyrics stage's. The stage is a dark
   full-screen thing and white text belongs there; this view sits in the normal
   light app, where white on pale blue is very nearly invisible. Every colour
   here comes from the palette so it cannot drift out of step again. */
.chat-log{display:flex;flex-direction:column;gap:10px;max-height:56vh;overflow-y:auto;padding:6px 2px;margin:8px 0}
.chat-turn{max-width:82%;padding:9px 12px;border-radius:16px;background:var(--surface);border:1px solid var(--line)}
.chat-you{align-self:flex-end;background:#e8f3fb;border-color:#c7e1f2}
/* EVERY LINE THE LEARNER WROTE WAS PALE TEXT ON A PALE-BLUE BUBBLE — measured at
   1.11:1, which is not low contrast, it is invisible. Your own half of the
   conversation was the half you could not read, on the phone, every time.
   The pair belongs HERE and not in the dark block near the top of this file:
   both rules are one class deep, so whichever comes last wins, and that block
   comes first. Written up there it changed nothing at all. */
@media(prefers-color-scheme:dark){
  .chat-you{background:#15304a;border-color:#26506f}
}
.chat-app{align-self:flex-start}
.chat-line{margin:0;font-size:15.5px;line-height:1.45;color:var(--ink);font-weight:600}
.chat-tr{margin:4px 0 0;font-size:12.5px;color:var(--mut)}
/* the correction sits UNDER what you said and never interrupts the talk */
.chat-fix{margin:6px 0 0;font-size:12.5px;color:#a35a00;font-weight:600}
/* …and hearing it again is a normal small button on the line, not something
   floating over the corner of the bubble */
/* a press must be visible AT ONCE: the voice takes ~2s to arrive, and two
   seconds of nothing is indistinguishable from a broken button */
.chat-said-btn.is-playing,.chat-again.is-playing{animation:chatSpeaking 1s ease-in-out infinite}
.chat-said-btn[disabled],.chat-again[disabled]{cursor:default}
@keyframes chatSpeaking{0%,100%{opacity:1}50%{opacity:.45}}
.chat-said-btn{display:block;width:100%;margin:5px 0 0;padding:6px 9px;text-align:left;border:1px solid var(--line);border-radius:10px;background:rgba(255,255,255,.55);font:inherit;font-size:13px;line-height:1.4;color:var(--ink);font-weight:600;cursor:pointer}
.chat-said-btn:hover{background:#fff;border-color:var(--blue)}
.chat-said{margin:5px 0 0;font-size:13px;line-height:1.4;color:var(--ink);font-weight:600}
/* what is happening to the line you wrote: the marking is a separate request now
   and lands a second or three after the reply, so the wait itself has to show */
.chat-mark{margin:3px 0 0;font-size:11.5px;font-weight:700;color:var(--mut)}
.chat-mark.is-ok{color:#2E9E5B}
.chat-mark.is-fail{color:var(--red)}
.chat-why{margin:3px 0 0;font-size:12px;line-height:1.4;color:var(--mut)}
/* how often this one has come up — the pattern is the lesson */
.chat-hits{margin:3px 0 0;font-size:11.5px;color:#ffd479;opacity:.85}
/* the words in a bubble are tappable, but must still read as prose */
.chat-line .word{display:inline;padding:0;border:none;background:none;font:inherit;color:inherit;cursor:pointer;border-radius:4px}
.chat-line .word:hover{background:rgba(127,231,255,.22)}
/* the end-of-lesson summary is ABOUT the language, so it wears no lb line */
.chat-summary{align-self:stretch;max-width:100%;background:rgba(255,212,121,.10);border:1px solid rgba(255,212,121,.35)}
.chat-summary .chat-tr{color:var(--ink);font-size:13.5px}
.chat-again{margin:6px 0 0;padding:2px 8px;font-size:12px}
/* ⭐ keep this line to practise later — quiet until it is saved */
.chat-keep{margin:6px 0 0 6px;padding:2px 8px;font-size:12px}
.chat-keep.is-kept{color:#c9920a}
/* 🔎 take the line apart without leaving the talk */
.chat-take{margin:6px 0 0 6px;padding:2px 8px;font-size:12px}
/* 🎙 …and what is happening WHILE you talk. The page used to show one grey
   "● …" at the very bottom and nothing else for the five seconds between
   finishing a sentence and seeing it — which reads as broken, not as busy.
   --lv is the live loudness (0…1), written per frame by chatLiveLevel. */
.chat-live{display:flex;align-items:center;gap:9px;opacity:.9}
.chat-live-txt{font-size:12.5px;color:var(--mut);font-weight:600}
.chat-live-bars{display:flex;align-items:center;gap:3px;height:18px;flex:0 0 auto}
.chat-live-bars i{width:3px;border-radius:2px;background:#ff5c8a;
  /* the middle bar leads, the outer two follow — a voice, not a progress bar */
  height:calc(4px + var(--lv,0) * 11px);transition:height .06s linear}
.chat-live-bars i:nth-child(2){height:calc(5px + var(--lv,0) * 13px)}
/* while it is being written down there is nothing to hear, so the bars idle */
.chat-live.is-hearing .chat-live-bars i{height:7px;animation:chatSpeaking 1s ease-in-out infinite}
.chat-live.is-hearing .chat-live-bars i:nth-child(2){height:7px;animation-delay:.15s}
.chat-live.is-hearing .chat-live-bars i:nth-child(3){animation-delay:.3s}
/* the microphone itself swells with the room — the one unmistakable sign that
   an open microphone really is reaching the page */
.chatpage-mic.is-rec{box-shadow:0 0 0 calc(var(--lv,0) * 14px) rgba(255,92,138,.28)}
/* the dark-mode recolours for the bubbles' small print live HERE, below their
   base rules: both sides are one class deep, so whichever comes last in the
   file wins. Written in the dark block beside .chat-you above — as
   .chat-mark.is-ok and .chat-hits were — they changed nothing at all: their
   base rules came later and won in dark mode too. */
@media(prefers-color-scheme:dark){
  .chat-mark.is-ok{color:#6fe3a1}
  .chat-hits{color:#ffcf6b;opacity:.95}
  .chat-keep.is-kept{color:#ffcf6b}
}
.chat-bar{display:flex;align-items:center;gap:8px;margin-top:6px}
.chat-mic{min-width:56px;font-size:20px;line-height:1}
.chat-mic.is-rec{background:var(--red);border-color:var(--red);animation:tap-pulse 1.2s ease-in-out infinite}
.chat-type{flex:1;min-width:0}
@media (max-width:620px){.chat-turn{max-width:92%}.chat-log{max-height:48vh}}
.lyrics-tapbar.hidden{display:none}
/* ── A RUN LOCKS THE PAGE'S OTHER EDITS ──────────────────────────────────────
   A hand keeping time is aiming at the panel, not at a 32px pencil beside a
   line — and a stray ✎, glide or edge drag mid-run rewrites the very moments
   the run is laying down, from a dialog that hides the song. They dim rather
   than disappear, so the page does not reflow under a thumb mid-beat. The
   transport stays live (play, zoom, loop, the playhead) because hearing the
   music is the whole point, and so does ↩, which is part of the run itself. */
.lyrics.is-tapping .lyrics-editbtn,
.lyrics.is-tapping .lyrics-glide,
.lyrics.is-tapping .lyrics-edge,
.lyrics.is-tapping .lyrics-order{pointer-events:none;opacity:.22}
/* …and when the run has reached the end it RESTS rather than closing: green
   instead of the playhead's red, nothing left beating, ◀ still able to reach
   the last tap — the one most likely to have been rushed — and ✕ to close when
   the learner is satisfied rather than when the song runs out. */
.lyrics-tapbar.is-done{cursor:default;background:linear-gradient(180deg,rgba(140,245,163,.15),rgba(140,245,163,.04));border-color:rgba(140,245,163,.4);box-shadow:0 -12px 34px -20px rgba(140,245,163,.6)}
.lyrics-tapbar.is-done:active{background:linear-gradient(180deg,rgba(140,245,163,.15),rgba(140,245,163,.04))}
.lyrics-tapbar.is-done .lyrics-tapdot{color:#8cf5a3;animation:none}
.lyrics-tapbar.is-done .lyrics-tapfill{background:#8cf5a3}
.lyrics-tapbar.is-done .lyrics-taphint{visibility:hidden}
.lyrics-tapbar:active{background:linear-gradient(180deg,rgba(255,92,138,.34),rgba(255,92,138,.13));border-color:rgba(255,92,138,.7)}
.lyrics-tapbar-top{display:flex;align-items:center;gap:10px}
.lyrics-tapdot{color:#ff5c8a;font-size:12px;line-height:1;flex:0 0 auto;animation:tap-pulse 1.4s ease-in-out infinite}
.lyrics-tapcount{flex:0 0 auto;font-size:11.5px;font-weight:800;color:rgba(220,236,249,.82);font-variant-numeric:tabular-nums}
.lyrics-taprail{flex:1;min-width:0;height:3px;border-radius:2px;background:rgba(255,255,255,.15);overflow:hidden}
.lyrics-tapfill{display:block;height:100%;width:0;background:#ff5c8a;transition:width .18s}
.lyrics-tapx,.lyrics-tapstep{flex:0 0 auto;border:none;background:rgba(255,255,255,.13);color:#fff;border-radius:50%;width:30px;height:30px;font-family:inherit;font-size:12px;line-height:1;cursor:pointer}
.lyrics-tapx:hover,.lyrics-tapstep:hover{background:rgba(255,255,255,.24)}
/* ◀ ▶ stepping the run: the way back from a mistap. Dimmed rather than removed
   at the ends of the song, so the row never changes width mid-run under a
   thumb that is aiming at it. */
.lyrics-tapstep:disabled{opacity:.28;cursor:default}
.lyrics-tapstep:disabled:hover{background:rgba(255,255,255,.13)}
/* the line itself, in the page's own display face — never truncated: a lyric
   you cannot finish reading is a lyric you cannot tap */
.lyrics-tapnow{margin-top:9px;font:800 25px/1.25 'Playfair Display',Georgia,'Times New Roman',serif;color:#fff}
.lyrics-tapnext{margin-top:5px;font-size:13px;color:rgba(220,236,249,.55);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lyrics-taphint{margin-top:8px;font-size:10.5px;letter-spacing:.03em;color:rgba(220,236,249,.42)}
@media (max-width:620px){
  .lyrics-tapbar{margin:0 10px 6px;padding:10px 13px 9px}
  .lyrics-tapnow{font-size:20px;margin-top:7px}
  .lyrics-taphint{margin-top:6px}
}
/* ⏺ tap in time: armed, it is the one red thing on the page — the same red as
   the playhead, because it marks the same instant the playhead is standing on */
.lyrics-tapbtn{font-size:15px;line-height:1}
.lyrics-tapbtn.is-on{background:#ff5c8a;color:#12202e;box-shadow:0 0 16px rgba(255,92,138,.5);animation:tap-pulse 1.4s ease-in-out infinite}
@keyframes tap-pulse{0%,100%{opacity:1}50%{opacity:.62}}
@media(prefers-reduced-motion:reduce){.lyrics-tapbtn.is-on{animation:none}}
/* 🎤 where a voice truly sounds — a green rail down the far left */
.lyrics-voiceband{position:absolute;left:-6px;width:4px;border-radius:3px;background:rgba(140,245,163,.55);pointer-events:none;z-index:1}
/* ⌖ the chosen line, and the bar that acts on it */
.lyrics-line-wrap.is-sel::before{border-top-color:#fff;box-shadow:0 0 16px rgba(255,255,255,.45)}
.lyrics-line-wrap.is-sel .lyrics-line{opacity:1}
.lyrics-selbar{display:flex;align-items:center;gap:8px;padding:8px 12px;margin:0 12px;border-radius:14px;background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.14);overflow-x:auto;scrollbar-width:none}
.lyrics-selbar.hidden{display:none}
.lyrics-selname{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-size:11.5px;font-weight:600;color:rgba(220,236,249,.85)}
.lyrics-selbtn{flex:0 0 auto;font-family:inherit;font-size:12px;font-weight:700;padding:7px 10px}
.lyrics-warn{font-family:inherit;font-size:12px;font-weight:800;line-height:1;background:rgba(255,196,120,.2);color:#ffc478}
.lyrics-warn.hidden{display:none}
.lyrics-zoomval{position:absolute;left:50%;transform:translateX(-50%);top:-6px;border:none;background:rgba(255,255,255,.10);color:#dcecf9;border-radius:9px;padding:3px 8px;font-family:inherit;font-size:10px;font-weight:700;line-height:1;cursor:pointer;opacity:0;transition:opacity .25s;pointer-events:none}
.lyrics-zoomval.is-on{opacity:1;pointer-events:auto}
.lyrics-undo,.lyrics-order{font-family:inherit;font-size:17px;font-weight:700;line-height:1}
.lyrics-sel{flex:1;min-width:0;padding:9px 10px;font-size:13px}
.lyrics-undo:disabled{opacity:.3;cursor:default}
/* the page explains itself — once */
/* …and the guide gets a ceiling of its own: it is the one child that grows with
   its prose, and a page that explains its buttons must never explain them off
   the screen. Past 38vh it scrolls inside itself. */
.lyrics-guide{position:relative;margin:0 14px 6px;padding:11px 13px 12px;border-radius:14px;background:rgba(127,231,255,.09);border:1px solid rgba(127,231,255,.20);color:#dcecf9;font-size:12.5px;line-height:1.5;max-height:38vh;overflow-y:auto}
.lyrics-guide b{display:block;margin-bottom:2px;color:#fff}
.lyrics-guide-x{display:block;margin-top:9px;border:none;background:rgba(255,255,255,.14);color:#fff;border-radius:9px;padding:6px 12px;font-family:inherit;font-size:12px;font-weight:700;line-height:1;cursor:pointer}
.lyrics-guide.hidden{display:none}
.lyrics-play{width:56px;height:56px;background:#fff;color:#10151C}
.lyrics-play:hover{background:#E4EAF2}
.lyrics-play svg{width:22px;height:22px}
/* ── PC: the stage is a CENTRED COLUMN, like every other view ──
   These rules were written for a phone, where the glass IS the column. On a
   monitor they stretched one sung line across two feet of it and left the ⇅
   that drags a line — and the playhead's clock beside it — a hand's width from
   the words they move. A time axis need only be as wide as a line is long, so
   the stage is capped at the app's own reading column (760px, the same as
   .content) and centred. Everything inside is measured from .lyrics-track, so
   capping THAT brings the rules, the bands, the green voice rail, the ↕ edges
   and the clock back beside the words in one move. The SCROLLER stays full
   width on purpose: a wheel over the dark margin must still turn the page.
   The head, the guide, the chosen-line bar and the controls are FLEX ITEMS of
   the stage, and an auto margin on a flex item eats the free space instead of
   centring a stretched box — so they are told to fill the column first (100%,
   capped) and centre second, or they shrink to their own buttons and stop
   lining up with the words.
   LAST IN THE SECTION on purpose: .lyrics-guide and .lyrics-selbar carry their
   phone gutter as a `margin` SHORTHAND, and a shorthand written further down
   the file would put the left margin back and hang the column off the edge.
   790px, not the 620px the phone rules use: the column is 760 and those two
   want ~14 either side, so anything narrower has no room to centre INTO — the
   auto margins would collapse to nothing and push them flush to the glass. A
   window between the two sizes simply keeps the full-width page it has now. */
@media (min-width:790px){
  .lyrics-head,.lyrics-guide,.lyrics-selbar,.lyrics-tapbar,.lyrics-ctrl{width:100%;max-width:760px;margin-left:auto;margin-right:auto}
  .lyrics-track{max-width:760px;margin-left:auto;margin-right:auto}
}

/* ── THE LIBRARY AS A FEED (phone) ────────────────────────────────────────
   On a phone a boxed card inside a padded page wastes the two things a phone
   has least of: width and attention. The picture goes edge to edge at 16:9 —
   the shape every thumbnail on earth is already cut to — the frame drops away,
   and the title with its line of detail sits under it. One item, then the next.

   AT THE END OF THE FILE ON PURPOSE. These override .card and .card-thumb,
   which are one class deep just like them, so the later rule is the one that
   wins — written up beside .cards where they belong by subject, they lost, and
   the cards kept their border and their 172px thumbnail. The same trap this
   file already documents for .chat-you and the dark-mode colours. */
@media (max-width:620px){
  .cards{grid-template-columns:1fr;gap:0;margin:0 -10px}
  .card{border:0;border-radius:0;background:none;box-shadow:none;padding:0 0 18px;overflow:visible}
  .card:hover{transform:none;box-shadow:none;border-color:transparent}
  .card-thumb{height:auto;aspect-ratio:16/9;border-radius:0}
  .card-thumb-video video.card-thumb-video{border-radius:0}
  .card-body{padding:10px 12px 0;gap:4px}
  .card-menu-btn{top:auto;bottom:12px;right:4px;background:none;box-shadow:none;opacity:.7}
  .card-new{top:8px;left:8px}
  .card .card-meta{font-size:12px}
}
/* …and the page ends ABOVE the tab bar, never behind it. Written last because
   the phone rule further up sets `padding` in shorthand and would wipe a
   padding-bottom declared before it. */
@media (max-width:620px){
  body{padding-bottom:calc(80px + env(safe-area-inset-bottom))}
}
/* ── ROOM FOR THE BAR ON THE SHEETS ───────────────────────────────────────
   The menu is on every page now, so every page that scrolls to its own bottom
   has to stop above it. Written last for the same reason as the rest of this
   block: these override paddings declared earlier at the same specificity. */
@media (max-width:620px){
  .tp-body{padding-bottom:calc(80px + env(safe-area-inset-bottom))}
  .chatpage-foot{padding-bottom:calc(74px + env(safe-area-inset-bottom))}
}
/* ── the question, its speaker, and the answer's ─────────────────────────── */
.me-qrow{display:flex;align-items:flex-start;gap:8px}
.me-qrow strong{flex:1;min-width:0;font-size:16px;line-height:1.35}
.me-say{flex:0 0 auto;width:38px;height:38px;border:1px solid var(--line);border-radius:50%;
  background:var(--surface);color:var(--blue-deep);cursor:pointer;display:flex;align-items:center;justify-content:center}
.me-say svg{width:19px;height:19px}
.me-say:hover{border-color:var(--blue);background:rgba(59,130,246,.12)}
.me-hear{align-self:flex-start;display:inline-flex;align-items:center;gap:6px}
.me-hear svg{width:16px;height:16px}

/* ── YOUTUBE'S PROPORTIONS, TIKTOK'S CENTRE BUTTON ────────────────────────
   Measured before this block: 401px of an 812px phone — half the screen — was
   chrome before the first card. Both of the apps this is modelled on put the
   content first and keep the furniture thin: a slim bar at the top, one row of
   chips, then the feed. So the heading goes (YouTube has no "Your media"
   caption over its feed), the ways in become ONE scrolling row of text chips
   the way YouTube's category row works, and the top padding stops reserving
   room that nothing occupies.

   At the end of the file with the rest — every one of these overrides a rule of
   the same weight declared earlier. */
@media (max-width:620px){
  /* the fixed composer is 61px tall; 118px of padding was reserving double */
  body{padding-top:76px}

  /* one scrolling row of chips, not a grid of tiles */
  #cardsHead{
    display:flex;flex-wrap:nowrap;overflow-x:auto;overscroll-behavior-x:contain;
    scrollbar-width:none;gap:7px;align-items:center;margin:0 -10px 10px;padding:0 10px 2px;
  }
  #cardsHead::-webkit-scrollbar{display:none}
  /* YouTube shows no caption over its feed, and neither does this */
  #cardsHead>strong,#cardsHead>span{display:none}
  #cardsHead .btn{
    flex:0 0 auto;width:auto;min-height:34px;border-radius:999px;
    padding:8px 14px;font-size:13px;font-weight:600;white-space:nowrap;
    background:rgba(59,130,246,.13);border:0;color:var(--blue-deep);box-shadow:none;
  }
  #cardsHead #settingsBtn{width:34px;padding:0;justify-self:auto}

  /* the filter row reads as chips too, not as form controls */
  .cards-controls{gap:8px}
  .mfilter{font-weight:600}
}

/* ── the ＋, TikTok's one unmistakable element ─────────────────────────────
   Wider than a tab and filled with the brand, because it is an ACTION and not
   a place: it never lights up, and tapping it never means "you are here". */
@media (max-width:620px){
  .tabbar{grid-template-columns:1fr 1fr 68px 1fr 1fr}
  .tab-add{padding:0}
  .tab-plus{display:flex;align-items:center;justify-content:center;
    width:46px;height:32px;border-radius:11px;background:var(--blue-deep);color:#fff;
    box-shadow:0 4px 12px -4px rgba(29,78,216,.6);transition:transform .16s ease}
  .tab-plus svg{width:22px;height:22px}
  .tab-add:active .tab-plus{transform:scale(.92)}
}

/* ── 🎤 the practice card in the app's own design language (2026-08-01): the
   record button is TikTok's big centre circle, the rest are YouTube's small
   icon-over-label actions, ✕ is a round corner button. Appended at the END
   of the file on purpose — the phone media query above styles .say-actions
   and would win on order otherwise (the cascade trap this file keeps
   re-teaching). Scoped to .say-run so the askMe editor keeps its layout. ── */
.say-run{position:relative;padding-top:20px}
.say-run .say-x{position:absolute;top:10px;right:10px;width:36px;height:36px;border-radius:50%;border:1px solid var(--line);background:none;color:var(--ink);display:flex;align-items:center;justify-content:center;padding:0;cursor:pointer}
.say-run .say-x svg{width:17px;height:17px}
.say-run .say-count{text-align:center}
.say-run .say-tr.is-ask{text-align:center;font-size:22px}
.say-run .say-target{text-align:center;font-family:'Playfair Display',Georgia,serif;font-weight:800;font-size:25px;line-height:1.3}
.say-run .say-target.is-hidden{font-family:inherit;font-size:20px}
.say-run .say-reveal{align-self:center}
.say-run .say-actions{align-items:center;justify-content:center;gap:6px;flex-wrap:nowrap}
.say-btn{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;min-width:56px;padding:4px 2px;background:none;border:none;color:var(--ink);font:inherit;font-size:10.5px;font-weight:700;letter-spacing:.02em;cursor:pointer;border-radius:12px}
.say-btn svg{width:22px;height:22px}
.say-btn:disabled{opacity:.3;cursor:default}
.say-rec{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;width:72px;height:72px;flex:0 0 auto;border-radius:50%;border:none;background:var(--blue-deep);color:#fff;font:inherit;font-size:10px;font-weight:800;cursor:pointer;box-shadow:0 10px 24px -12px rgba(29,78,216,.5)}
.say-rec svg{width:24px;height:24px}
.say-rec.is-rec{background:#c53030;animation:sayRecPulse 1.3s ease-in-out infinite}
@keyframes sayRecPulse{0%,100%{box-shadow:0 0 0 0 rgba(197,48,48,.45)}50%{box-shadow:0 0 0 12px rgba(197,48,48,0)}}
.tp-say{margin-left:auto;flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:50%;border:1px solid var(--line);color:var(--ink)}
.tp-say svg{width:15px;height:15px}
@media(max-width:620px){
  .say-run .say-actions{gap:4px}
  .say-btn{min-width:52px}
}
.say-run .say-list{right:auto;left:10px}
/* the topics stage borrows the practice card's action bar — centred, one row */
.tp-stage .say-actions{align-items:center;justify-content:center;gap:6px;flex-wrap:nowrap}
.say-qtools{display:flex;gap:10px;justify-content:center;margin:2px 0}
.say-trans{margin:0;font-size:13.5px;color:var(--mut);text-align:center;line-height:1.45}

/* ── 🎴 the practice card, modernised (2026-08-01): a softer card with a slim
   progress bar, the question as the examiner's SPEECH BUBBLE, the answer in
   its own reveal zone, the tools row breathing. Appended at the END of the
   file, as ever, so these win on order over the base rules above. ── */
.say-run{border-radius:22px;padding:22px 18px 14px;
  box-shadow:0 24px 60px -28px rgba(15,35,60,.5),0 2px 10px rgba(15,35,60,.08)}
.say-run .say-count{font-size:10.5px;letter-spacing:.09em;text-transform:uppercase}
.say-prog{height:4px;border-radius:99px;background:var(--line);overflow:hidden;margin:2px 0 8px}
.say-prog i{display:block;height:100%;width:0;border-radius:99px;background:var(--blue-deep);transition:width .25s ease}
.say-run .say-tr.is-ask{background:rgba(59,130,246,.12);border:1px solid rgba(59,130,246,.28);
  border-radius:18px 18px 18px 6px;padding:12px 16px;font-size:20px;text-align:left;cursor:pointer}
.say-run .say-target{background:rgba(127,150,175,.08);border-radius:14px;padding:14px 12px;margin:2px 0}
.say-run .say-target.is-hidden{background:none;border:1.5px dashed var(--line)}
.say-run .say-reveal{border-radius:99px}
.say-run .say-trans{background:rgba(127,150,175,.09);border-radius:12px;padding:8px 12px}
.say-run .say-actions{border-top:1px solid var(--line);padding-top:10px;margin-top:4px}
.say-run .me-answer{border-radius:14px}
@media(prefers-color-scheme:dark){
  .say-run .say-tr.is-ask{background:rgba(59,130,246,.16);border-color:rgba(59,130,246,.4)}
  .say-prog i{background:var(--blue)}
}

/* 🎛 THE DECK — the PC video menu as a player: a bottom gradient instead of a
   black slab, a seek bar whose ticks are the SENTENCES, ⏯ with the times, the
   rail right-aligned. Longhand fonts, as this file has learned. */
.feed-menu.feed-deck{background:linear-gradient(transparent,rgba(0,0,0,.88) 55%);border-radius:0;
  padding:30px 22px calc(12px + env(safe-area-inset-bottom));gap:10px}
.deck-seek{position:relative;height:14px;cursor:pointer;touch-action:none}
.deck-seek::before{content:'';position:absolute;left:0;right:0;top:5px;height:4px;border-radius:2px;
  background:rgba(255,255,255,.28);transition:height .12s ease,top .12s ease}
.deck-seek:hover::before{top:3.5px;height:7px}
.deck-fill{position:absolute;left:0;top:5px;height:4px;border-radius:2px;background:var(--blue);
  pointer-events:none;transition:height .12s ease,top .12s ease}
.deck-seek:hover .deck-fill{top:3.5px;height:7px}
.deck-ticks{position:absolute;inset:0;pointer-events:none}
.deck-ticks b{position:absolute;top:5px;width:2px;height:4px;background:rgba(255,255,255,.6)}
.deck-row{display:flex;align-items:center;gap:14px}
.deck-play{flex:0 0 auto;width:42px;height:42px;border:0;border-radius:50%;padding:0;cursor:pointer;
  background:rgba(255,255,255,.14);color:#fff;display:flex;align-items:center;justify-content:center;
  transition:background .15s ease,transform .08s ease}
.deck-play:hover{background:rgba(255,255,255,.26)}
.deck-play:active{transform:scale(.92)}
.deck-play svg{width:20px;height:20px;display:block}
.deck-time{color:#fff;font-size:13px;font-weight:600;opacity:.92;font-variant-numeric:tabular-nums;white-space:nowrap}
.feed-deck .feed-rail{flex:1;justify-content:flex-end;flex-wrap:nowrap}
/* the Netflix title — with the chrome, gone with the chrome */
.feed-title{position:absolute;top:16px;left:20px;z-index:6;max-width:58%;color:#fff;
  font-size:16.5px;font-weight:800;line-height:1.3;text-shadow:0 1px 3px rgba(0,0,0,.9);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;transition:opacity .35s ease}
.feed.feed-idle .feed-title{opacity:0}
/* YouTube's centre blip: a toggle is FELT even with the deck hidden */
.feed-blip{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);z-index:6;
  width:84px;height:84px;border-radius:50%;background:rgba(0,0,0,.55);color:#fff;
  display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none}
.feed-blip svg{width:36px;height:36px;display:block}
.feed-blip.is-on{animation:blipFade .6s ease-out forwards}
@keyframes blipFade{from{opacity:1;transform:translate(-50%,-50%) scale(.85)}to{opacity:0;transform:translate(-50%,-50%) scale(1.3)}}

/* 🏠 THE HOME, WIDE (the learner: 'make the main page better, like TikTok or
   YouTube, more modern, easier to navigate'). The library lived in the same
   760px column the READING view needs — right for a text, absurd for a video
   shelf on a 1920 screen. The home breaks out to the full window now, and the
   cards go frameless the way YouTube's are: the THUMBNAIL is the card, 16:9,
   rounded, lifting a breath on hover; the title under it in the page's own
   ink, clamped to two lines so the rows stay rows. The chips become one
   uniform row with the gear at its end, and the filters share a line with a
   rounder search. Desktop only — the phone home had its YouTube pass long ago
   and stays exactly as it is. */
@media (min-width:900px){
  /* centred by calc, NOT translateX(-50%): a transform makes this the containing
     block for position:fixed descendants, and the ☰ burger inside #cardsHead
     must be fixed to the VIEWPORT to sit on the composer's line */
  #cardsView{width:min(1720px,calc(100vw - 56px));position:relative;left:calc(50% - min(860px,50vw - 28px))}
  #cardsView .cards{grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:26px 18px}
  #cardsView .card{border:0;background:none;box-shadow:none;border-radius:0;overflow:visible}
  #cardsView .card:hover{transform:none;border-color:transparent;box-shadow:none}
  #cardsView .card-thumb{height:auto;aspect-ratio:16/9;border-radius:14px;
    transition:transform .16s ease,border-radius .16s ease}
  #cardsView .card:hover .card-thumb{transform:scale(1.015);border-radius:10px}
  #cardsView .card-body{padding:10px 4px 0}
  #cardsView .card strong{font-size:15px;color:var(--ink);line-height:1.35;padding-right:0;
    display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
  #cardsView .card .card-snippet{display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;overflow:hidden;color:var(--mut)}
  #cardsHead{align-items:center;flex-wrap:wrap;row-gap:8px}
  #cardsHead .btn{background:rgba(59,130,246,.10);border-radius:999px;min-height:38px;padding:8px 15px;font-size:13.5px}
  #cardsHead .btn:hover{background:rgba(59,130,246,.22)}
  #settingsBtn{margin-left:auto}
  .cards-controls{display:flex;align-items:center;gap:12px}
  .cards-filters{flex:1;margin:0;flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none}
  .cards-search{width:300px;flex:0 0 auto;border-radius:999px;padding:9px 16px}
}

/* 🏠 the chips' and glyphs' icon sizing — the last emoji on the main page
   became FSVG, and an svg needs told how big it is */
#cardsHead .btn{display:inline-flex;align-items:center;gap:7px}
#cardsHead .btn svg{width:17px;height:17px;flex:0 0 auto;display:block}
#settingsBtn svg{width:18px;height:18px}
.mfilter{display:inline-flex;align-items:center;gap:5px}
.mfilter svg{width:14px;height:14px;flex:0 0 auto;display:block}
.card-thumb-glyph svg{width:46px;height:46px;display:block;color:var(--blue-deep);opacity:.75}

/* ☰ THE SIDE MENU — YouTube's drawer for the app's destinations: the chips
   leave the desktop main page and live here, icon + label rows sliding in
   from the left over a scrim. The phone keeps its chip row (there it is the
   only road to half these features beyond the four tabs), so ☰ exists only
   where the chips are gone. */
/* the burger is CHROME now, a body-level sibling of the composer — it rides
   every page of the app, not just the home's shelf. Overlays that should be
   immersive (topics 900, lyrics 940, feed 950, auth 1000) simply out-stack
   its 601; the chat page (60) keeps it. */
#menuBtn{display:none}
@media (min-width:900px){
  /* the burger sits in YouTube's corner — far LEFT, on the composer's line.
     Anchoring it to the composer's edge put it mid-screen on a wide display
     while the drawer slid in at the window's edge, a 250px reach between the
     click and the menu; in the corner the drawer opens under the cursor, and
     .side-burger repeats the button in the same pixels so closing needs no
     travel either. */
  #menuBtn{display:flex;align-items:center;justify-content:center;
    position:fixed;top:calc(20px + env(safe-area-inset-top));left:calc(12px + env(safe-area-inset-left));z-index:601;
    width:42px;height:42px;min-height:42px;padding:0;border-radius:50%;
    background:var(--surface);border:1px solid var(--line);box-shadow:0 8px 22px -14px rgba(29,78,216,.35)}
  #menuBtn:hover{background:rgba(59,130,246,.10)}
  #menuBtn svg{width:21px;height:21px;display:block}
  #cardsHead .btn{display:none}
  #cardsHead{justify-content:flex-start;gap:14px}
}
/* the reading view's zen mode hides ALL chrome — the burger included */
body.fullread #menuBtn{display:none}
.side-scrim{position:fixed;inset:0;z-index:1090;background:rgba(10,18,28,.45)}
/* the panel's top-left padding EQUALS the page burger's fixed offsets — that
   is the whole zero-travel contract: the .side-burger in flow lands on the
   very pixels #menuBtn holds, and the two read as one button that never moved */
.side-menu{position:fixed;left:0;top:0;bottom:0;z-index:1100;width:304px;
  display:flex;flex-direction:column;gap:2px;
  padding:calc(20px + env(safe-area-inset-top)) 12px calc(18px + env(safe-area-inset-bottom)) calc(12px + env(safe-area-inset-left));
  background:rgba(255,255,255,.86);-webkit-backdrop-filter:blur(22px);backdrop-filter:blur(22px);
  border-radius:0 26px 26px 0;box-shadow:0 0 70px rgba(10,20,35,.35);
  transform:translateX(-100%);transition:transform .24s cubic-bezier(.2,.8,.25,1);overflow-y:auto}
@media(prefers-color-scheme:dark){.side-menu{background:rgba(15,23,33,.9)}}
/* flex-START, not center: the brand column is taller than the burger, and
   centring pushed the burger 10px off the pixels #menuBtn holds outside */
.side-top{display:flex;align-items:flex-start;gap:14px;padding-bottom:14px}
.side-burger{display:flex;align-items:center;justify-content:center;flex:0 0 auto;
  width:42px;height:42px;padding:0;border-radius:50%;cursor:pointer;
  background:var(--surface);border:1px solid var(--line);color:inherit}
.side-burger:hover{background:rgba(59,130,246,.10)}
.side-burger svg{width:21px;height:21px;display:block}
/* the wordmark over the tricolore — the drawer is unmistakably this app's.
   8px down so the wordmark's centre rides the burger's centre line */
.side-brand{display:flex;flex-direction:column;gap:4px;padding-top:8px}
.side-brand strong{font-size:21px;font-weight:800;letter-spacing:-.01em;color:var(--ink)}
.side-brand em{font-style:normal;font-size:12px;font-weight:650;color:var(--mut)}
.side-flag{display:flex;height:5px;border-radius:3px;overflow:hidden;width:64px}
.side-flag i{flex:1}
.side-flag i:nth-child(1){background:#ED2939}
.side-flag i:nth-child(2){background:#fff;box-shadow:inset 0 0 0 1px var(--line)}
.side-flag i:nth-child(3){background:#3B82F6}
.side-ic{display:flex;align-items:center;justify-content:center;width:38px;height:38px;flex:0 0 auto;
  border-radius:12px;background:rgba(59,130,246,.12);color:var(--blue-deep)}
.side-ic svg{width:19px;height:19px;display:block}
.side-row:hover .side-ic{background:rgba(59,130,246,.24)}
@media(prefers-color-scheme:dark){.side-ic{color:var(--blue)}}
.side-menu.is-open{transform:none}
.side-row{display:flex;align-items:center;gap:14px;transition:transform .12s ease,background .12s ease;width:100%;text-align:left;
  padding:12px 16px;border:0;border-radius:12px;background:none;cursor:pointer;
  color:var(--ink);font-family:inherit;font-size:14.5px;font-weight:650}
.side-row:hover{background:rgba(59,130,246,.12)}

.side-hr{width:100%;border:0;border-top:1px solid var(--line);margin:8px 0}


/* 🔍 ONE BOX — the media finder folded into the composer; the old input stays
   wired but unseen. And the home breathes: the composer compacts to a single
   modern bar on a PC (actions inline at its right), and the page starts
   closer to the top. */
#cardsSearch{display:none}
@media (min-width:900px){
  .composer{padding:8px;gap:6px}
  #composerInput{min-height:44px;padding:10px 138px 10px 16px;border-radius:999px}
  .composer-actions{position:absolute;right:14px;top:14px;gap:8px}
  #helpBtn{width:38px;min-width:38px;min-height:38px}
  #goBtn{min-height:38px;padding:8px 14px}
  .composer-status:empty{display:none}
  body{padding-top:118px}
}

/* 📅 TODAY — first stop of the page-by-page pass ('make all pages the same
   layout, optimised and modern'). The row icons ride tinted tiles — the
   drawer's own mark — on every size; on a PC the due-rows take the home's
   card language (soft shadow, hover ring) and the 14-day chart grows past
   postage-stamp size. */
.today-ic{display:inline-flex;align-items:center;justify-content:center;width:34px;height:34px;flex:0 0 auto;border-radius:10px;background:rgba(59,130,246,.12);color:var(--blue-deep)}
.today-ic svg{width:18px;height:18px;display:block}
.today-row strong{display:flex;align-items:center;gap:11px;min-width:0}
#todayView .view-head strong{display:flex;align-items:center;gap:9px}
#todayView .view-head strong svg{width:19px;height:19px;flex:0 0 auto}
#todayCloseBtn svg{width:16px;height:16px;display:block}
@media (min-width:900px){
  #todayView .view-head strong{font-size:20px;letter-spacing:-.01em;color:var(--ink)}
  #todayCloseBtn{width:38px;min-width:38px;min-height:38px;padding:0;border-radius:50%;display:flex;align-items:center;justify-content:center}
  #todayView .today-row{padding:18px 22px;border-radius:18px;border-color:transparent;box-shadow:0 12px 30px -22px rgba(29,78,216,.28);transition:box-shadow .15s ease,border-color .15s ease}
  #todayView .today-row:hover{border-color:rgba(59,130,246,.5)}
  #todayView .today-note{font-size:13.5px}
  #todayView .today-chart{height:76px;gap:6px}
  #todayView .today-bar{border-radius:6px 6px 0 0}
}

/* ⚙ SETTINGS — the page-by-page pass continues. Thirteen boxes in one thin
   column was a very long scroll on a PC: the view widens by the home's calc
   trick (never translateX — a transform would orphan the fixed burger) and
   folds into two columns of soft-shadowed cards; the section titles carry
   FSVG marks in the drawer's voice, on every size. */
#settingsView .set-title{display:flex;align-items:center;gap:9px}
#settingsView .set-title svg{width:18px;height:18px;flex:0 0 auto;color:var(--blue-deep)}
#settingsView .view-head strong{display:flex;align-items:center;gap:9px}
#settingsView .view-head strong svg{width:19px;height:19px;flex:0 0 auto}
#settingsCloseBtn svg{width:16px;height:16px;display:block}
@media(prefers-color-scheme:dark){#settingsView .set-title svg{color:var(--blue)}}
@media (min-width:900px){
  #settingsView{width:min(1060px,calc(100vw - 56px));position:relative;left:calc(50% - min(530px,50vw - 28px));
    display:grid;grid-template-columns:1fr 1fr;gap:16px;align-items:start}
  #settingsView .view-head{grid-column:1/-1}
  #settingsView .view-head strong{font-size:20px;letter-spacing:-.01em;color:var(--ink)}
  #settingsCloseBtn{width:38px;min-width:38px;min-height:38px;padding:0;border-radius:50%;display:flex;align-items:center;justify-content:center;margin-left:auto}
  #settingsView .set-group{border:1px solid var(--line);border-radius:18px;padding:18px 20px;margin:0;background:var(--surface);box-shadow:0 12px 30px -22px rgba(29,78,216,.22)}
  #settingsView .set-title{font-size:16px}
  #settingsView .make-chip{min-height:36px;padding:8px 14px;font-size:13px}
}

/* ✏️ CREATE — the maker page joins the pass: head and button speak icon, the
   form fields grow to the composer's own scale on a PC, the words field goes
   pill like the bar it echoes, and the saved rows learn the home's hover
   lift. The phone keeps its compact form. */
#makeView .view-head strong{display:flex;align-items:center;gap:9px}
#makeView .view-head strong svg{width:18px;height:18px;flex:0 0 auto;color:var(--blue-deep)}
#makeGoBtn{display:inline-flex;align-items:center;justify-content:center;gap:8px}
#makeGoBtn svg{width:16px;height:16px;display:block}
.saved-del{display:flex;align-items:center;justify-content:center;color:var(--mut)}
.saved-del svg{width:16px;height:16px;display:block}
@media(prefers-color-scheme:dark){#makeView .view-head strong svg{color:var(--blue)}}
@media (min-width:900px){
  #makeView .view-head strong{font-size:20px;letter-spacing:-.01em;color:var(--ink)}
  #makeView .make-input{padding:13px 16px;border-radius:14px;font-size:15px}
  #makeView .make-words{border-radius:999px}
  #makeView .make-chip{padding:9px 15px;font-size:13px}
  #makeView .make-example{padding:8px 13px;font-size:12.5px}
  #makeGoBtn{min-height:44px;padding:11px 22px;border-radius:999px}
  #makeView .saved-row{transition:border-color .15s,box-shadow .15s}
  #makeView .saved-row:hover{box-shadow:0 12px 28px -18px rgba(29,78,216,.3)}
  #makeView .saved-go{padding:13px 16px}
}

/* 📁 UPLOAD — the command-only page joins the pass: a card surface on a PC,
   the two pick rows go softly dashed like the drop zones they are, and the
   chrome speaks icon with the rest. The phone keeps its flat strip. */
#uploadView .view-head strong{display:flex;align-items:center;gap:9px}
#uploadView .view-head strong svg{width:18px;height:18px;flex:0 0 auto;color:var(--blue-deep)}
#uploadView .btn{display:inline-flex;align-items:center;gap:7px}
#uploadView .btn svg{width:16px;height:16px;flex:0 0 auto;display:block}
@media(prefers-color-scheme:dark){#uploadView .view-head strong svg{color:var(--blue)}}
@media (min-width:900px){
  #uploadView{background:var(--surface);border:1px solid var(--line);border-radius:20px;padding:26px 28px;
    box-shadow:0 18px 44px -28px rgba(15,40,70,.25)}
  #uploadView .view-head strong{font-size:20px;letter-spacing:-.01em;color:var(--ink)}
  #uploadView .upload-file{padding:12px 14px;border:1.5px dashed var(--line);border-radius:14px;background:rgba(59,130,246,.04)}
  #uploadView .upload-name{font-size:13px}
  #uploadView .make-input{padding:13px 16px;border-radius:14px;font-size:15px}
  #uploadGoBtn{min-height:44px;padding:11px 22px;border-radius:999px}
}

/* 🧭 PREPOSITIONS — the drill joins the pass: the 620px phone column grows to
   the reading width on a PC, the sentence and options take pointer scale, and
   the toolbar goes pill in the home's language. The icons ride every size. */
#prepView .game-top .btn{display:inline-flex;align-items:center;gap:6px}
#prepView .game-top .btn svg{width:15px;height:15px;flex:0 0 auto;display:block}
#prepView .prep-chunk{display:inline-flex;align-items:center;gap:7px}
#prepView .prep-chunk svg{width:15px;height:15px;flex:0 0 auto;display:block}
#prepView .game-machine{display:inline-flex;align-items:center;gap:7px}
#prepView .game-machine svg{width:15px;height:15px;flex:0 0 auto;color:var(--blue-deep)}
@media(prefers-color-scheme:dark){#prepView .game-machine svg{color:var(--blue)}}
@media (min-width:900px){
  #prepView{max-width:760px}
  #prepView .game-card{padding:26px 30px;border-radius:22px}
  #prepView .prep-sentence{font-size:22px;line-height:1.7}
  #prepView .prep-opt{font-size:17px;padding:13px 20px;border-radius:14px}
  #prepView .game-machine{font-size:13.5px;color:var(--ink)}
  #prepView .game-top .btn{background:rgba(59,130,246,.10);border-radius:999px;min-height:38px;min-width:38px;padding:8px 14px}
  #prepView .game-top .btn:hover{background:rgba(59,130,246,.22)}
  #prepView .prep-review-btn{font-size:12.5px}
}

/* 🎲 THE SENTENCE GAME — joins the pass. And a bug dies in daylight: the
   mastery bar under the game head NEVER had a background or a fill rule —
   three views set its margins and height, app.js set a width%, and nothing
   ever painted. The base pair below makes the bar real on every size. */
.game-mastery{background:rgba(59,130,246,.14);border-radius:999px;overflow:hidden}
.game-mastery span{display:block;height:100%;width:0;background:var(--blue);border-radius:999px;transition:width .3s ease}
#gameView .game-top .btn,#gameView .game-actions .btn{display:inline-flex;align-items:center;justify-content:center;gap:7px}
#gameView .btn svg{width:17px;height:17px;flex:0 0 auto;display:block}
@media (min-width:900px){
  #gameView{max-width:680px}
  #gameView .game-card{padding:26px 28px;border-radius:22px;gap:16px}
  #gameView .game-prompt{font-size:20px}
  #gameView .tile{font-size:17px;padding:10px 15px}
  #gameView .game-machine{font-size:13px}
  #gameView .game-top .btn-small,#gameView .game-actions .btn-small{width:38px;min-width:38px;min-height:38px;padding:0;border-radius:50%}
  #gameView .game-top .btn-small svg,#gameView .game-actions .btn-small svg{width:18px;height:18px}
  #gameView .game-done-actions{flex-direction:row;justify-content:center;max-width:none}
  #gameView .game-done-actions .btn{width:auto;min-width:200px}
}

/* 📒 THE WORD GAME — joins the pass: four uTalk tiles in one desktop row, a
   bigger question, and the saved words fold into a two-column tinted grid.
   The machine label and row buttons speak FSVG on every size. */
#wordGameView .game-machine{display:inline-flex;align-items:center;gap:7px}
#wordGameView .game-machine svg{width:15px;height:15px;flex:0 0 auto;color:var(--blue-deep)}
#wordGameView .game-top .btn{display:inline-flex;align-items:center;justify-content:center}
#wordGameView .game-top .btn svg{width:15px;height:15px;display:block}
#wordGameView .wg-after-ex{display:inline-flex;align-items:center;gap:7px}
#wordGameView .wg-after-ex svg{width:15px;height:15px;flex:0 0 auto;display:block}
@media(prefers-color-scheme:dark){#wordGameView .game-machine svg{color:var(--blue)}}
@media (min-width:900px){
  #wordGameView{max-width:780px}
  #wordGameView .game-card{padding:26px 30px;border-radius:22px}
  #wordGameView .wg-grid{grid-template-columns:repeat(4,1fr);gap:14px}
  #wordGameView .wg-tile.is-word{min-height:88px}
  #wordGameView .wg-prompt-img{width:210px;height:210px;border-radius:16px}
  #wordGameView .wg-prompt-tr{font-size:26px}
  #wordGameView .wg-words-list{display:grid;grid-template-columns:1fr 1fr;gap:10px}
  #wordGameView .wg-word-row{background:rgba(59,130,246,.06);border-radius:12px;padding:9px 12px}
}

/* 🗣 PRONUNCIATION — joins the pass: the hero word at hero size on a PC, the
   three actions go pill at pointer scale, and the chrome speaks FSVG — the
   recorder repaints the say button itself so the mark survives every stop. */
#sayGameView .game-machine{display:inline-flex;align-items:center;gap:7px}
#sayGameView .game-machine svg{width:15px;height:15px;flex:0 0 auto;color:var(--blue-deep)}
#sayGameView .btn{display:inline-flex;align-items:center;justify-content:center;gap:7px}
#sayGameView .btn svg{width:17px;height:17px;flex:0 0 auto;display:block}
@media(prefers-color-scheme:dark){#sayGameView .game-machine svg{color:var(--blue)}}
@media (min-width:900px){
  #sayGameView{max-width:680px}
  #sayGameView .game-card{padding:28px 30px;border-radius:24px;gap:18px}
  #sayGameView .sg-word{font-size:46px}
  #sayGameView .sg-meaning{font-size:15px}
  #sayGameView .game-actions .btn{border-radius:999px;min-height:44px;padding:10px 18px;font-size:14px}
  #sayGameView .btn-ghost:hover{background:rgba(59,130,246,.10)}
  #sayGameView .game-machine{font-size:14px}
  #sgCloseBtn{width:38px;min-width:38px;min-height:38px;padding:0;border-radius:50%}
}

/* 💬 THE CONVERSATION — joins the pass. The head steps RIGHT of the fixed
   burger (68px: the ✕ was partly buried under it), the three wall-to-wall
   hairline bars go transparent so the thread floats on the page like the
   home, the dials centre over the column they steer, and the input box
   carries the composer's own shadow. Head icons are FSVG, painted once. */
.chatpage-x svg{width:18px;height:18px;display:block;margin:auto}
.chatpage-mic svg{width:18px;height:18px;display:block;margin:auto}
@media (min-width:900px){
  .chatpage-head{padding-left:68px;padding-top:14px;border-bottom:0;background:transparent}
  .chatpage-head strong{font-size:16px}
  .chat-dials{border-bottom:0;background:transparent;justify-content:center}
  .chatpage-foot{border-top:0;background:transparent}
  .chatpage-box{box-shadow:0 8px 22px -14px rgba(29,78,216,.35)}
  .chatpage-box:focus-within{border-color:var(--blue);box-shadow:0 0 0 3px rgba(59,130,246,.18)}
  .chatpage-inner{max-width:768px}
  .chatpage-box{max-width:768px}
  .chatpage-status{max-width:768px}
  .chatpage-x:hover{background:rgba(59,130,246,.10);color:var(--blue-deep)}
}

/* 📖 READING — the last page of the pass. The desktop gets the phone's calm
   reading surface, a slightly roomier column, the home's pill chips on the
   head and foot, and rounded media. The negative pins stand guard here —
   the head rule below must never OPEN with the wrap declaration, and the
   dead watching scopes stay dead. */
#textView .view-head .btn,#textView .view-actions .btn{display:inline-flex;align-items:center;gap:7px}
#textView .btn svg{width:16px;height:16px;flex:0 0 auto;display:block}
.exit-full svg{width:18px;height:18px;display:block;margin:auto}
@media (min-width:900px){
  body.reading{background:var(--surface)}
  body.reading .content{max-width:820px}
  #textView .view-head{align-items:center;row-gap:8px;flex-wrap:wrap;margin:0 0 18px}
  #textView .view-head strong{font-size:20px;letter-spacing:-.01em;color:var(--ink)}
  #textView .view-head span{font-size:13px}
  #textView .view-head .btn,#textView .view-actions .btn{background:rgba(59,130,246,.10);min-height:38px;padding:8px 15px;font-size:13.5px;border-radius:999px}
  #textView .view-head .btn:hover,#textView .view-actions .btn:hover{background:rgba(59,130,246,.22)}
  #textView .video-player{border-radius:14px}
}

/* 📱 THE PHONE'S CAPTIONS GO YOUTUBE (the learner: "the full video in phone
   are not good — it should be like YouTube, also the letters are too big;
   change only the phone"). The words leave the black band for the picture —
   the same scrimmed, centred, boxed captions the PC float wears — anchored
   above the rail, at YouTube's own modest size. The PC keeps 24/17 and its
   ⇅ places. Keyed to the DEVICE, matching feedPC in app.js: a touch hand is
   the phone layout at ANY width — tablet, landscape, desktop-site browser —
   and a real pointer never sees this block, however narrow the window. */
@media (hover:none),(pointer:coarse){
  .feed{--sub-size:14px;--tr-size:12px}
  /* bottom-anchored, never centre-84% (the band lives there), and the saved
     cap-top preference is a PC thing — the phone reads like YouTube, low */
  /* 160: the phone deck is ~156px tall (seek + ⏯/times + the rail's own
     row) — the words sit just clear of it, and stay put when it fades */
  .feed .feed-info.feed-float,.feed.cap-top .feed-info.feed-float{
    top:auto;bottom:calc(160px + env(safe-area-inset-bottom));transform:translateX(-50%);
    width:min(92%,540px)}
  .feed-float .feed-sub,.feed-float .feed-sub-tr{padding:2px 9px;border-radius:7px}
  /* the deck on a phone: ⏯ and the times on one line, the rail a full-width
     line of its own below — its one-row scroll is the phone's own grammar */
  .deck-row{flex-wrap:wrap;gap:8px 10px}
  .feed-deck .feed-rail{flex:1 1 100%;justify-content:space-around}
}

/* 📱↔ LANDSCAPE ON A TOUCH HAND — the film gets the HEIGHT: the deck
   compacts to the PC's own single row (landscape has width to spare, not
   height — the wrapped rail row alone ate 44px of a 375px screen) and the
   words step down to ride just above it. Appended after the portrait coarse
   block, deliberately: same specificity, the later rule wins sideways. */
@media (pointer:coarse) and (orientation:landscape),(hover:none) and (orientation:landscape){
  .deck-row{flex-wrap:nowrap;gap:12px}
  .feed-deck .feed-rail{flex:1 1 auto;justify-content:flex-end}
  .feed .feed-info.feed-float,.feed.cap-top .feed-info.feed-float{bottom:calc(92px + env(safe-area-inset-bottom))}
}

/* ⛶ THE FULL-SCREEN TOGGLE — YouTube's rightmost control, because Esc left
   no road back. On a PC it sits past the right-aligned rail; on a phone the
   rail is ordered below (its own line), so ⛶ rides the ⏯/times line at the
   right edge; landscape restores the one-row order with ⛶ last. */
.deck-fs{flex:0 0 auto;width:42px;height:42px;border:0;border-radius:50%;padding:0;cursor:pointer;
  background:none;color:#fff;display:flex;align-items:center;justify-content:center;transition:background .15s,transform .12s}
.deck-fs:hover{background:rgba(255,255,255,.26)}
.deck-fs:active{transform:scale(.92)}
.deck-fs svg{width:20px;height:20px;display:block}
@media (hover:none),(pointer:coarse){
  .feed-deck .feed-rail{order:5}
  .deck-fs{margin-left:auto}
}
@media (pointer:coarse) and (orientation:landscape),(hover:none) and (orientation:landscape){
  .feed-deck .feed-rail{order:0}
  .deck-fs{margin-left:0}
}

/* 🖥📖 READING AT PC SIZE ('the page should have big letters optimised for
   PC, and the translation should be open'): the transcript grows to a real
   reading size on a monitor — the words inherit it — and the open meaning
   under each line sits a step down in the quiet grey. The phone keeps its
   compact type and its tap-per-line translations. */
@media (min-width:900px){
  #textView .sentence{font-size:22px;line-height:1.7;margin:0 0 13px}
  #textView .sen-tr.shown{font-size:16.5px;line-height:1.6;margin:-8px 3px 15px}
  #textView .speak-btn svg{width:17px;height:17px}
}

/* 🎨📖 THE READING COLORS, WITH LIFE ('bigger, and colors for both with
   more life to attract reading' — the first pass's navy-on-slate read as
   two shades of dark). TWO VOICES now: the Luxembourgish in a vivid royal
   blue — the language is the headline — and the meaning in a deep teal
   behind its own teal hairline, unmistakably a different speaker. Dark mode
   sings the same pair in light. */
@media (min-width:900px){
  #textView .sentence{color:#1E40AF}
  #textView .sen-tr.shown{color:#0F766E;border-left:2px solid rgba(13,148,136,.45);padding-left:10px}
}
@media (min-width:900px) and (prefers-color-scheme:dark){
  #textView .sentence{color:#93C5FD}
  #textView .sen-tr.shown{color:#7DD3C8;border-left-color:rgba(45,212,191,.5)}
}

/* 🎨📖 THE READER HOLDS THE PEN ('we should be able to control the color and
   the size of sentences' — the grammar-color experiment was reversed for
   this). Aa on the reading head opens a small palette: swatches and A−/A+
   for the Luxembourgish line and for its translation, kept in the account
   (readColor/readSize/readTrColor/readTrSize) and honoured through the
   custom properties below. Unset, the page keeps its royal-blue-and-teal
   defaults — which the dark scheme lightens; a CHOSEN color is the
   learner's in both schemes. */
@media (min-width:900px){
  #textView{--read-color-default:#1E40AF;--read-tr-color-default:#0F766E}
  #textView .sentence{color:var(--read-color,var(--read-color-default));font-size:var(--read-size,22px)}
  #textView .sen-tr.shown{color:var(--read-tr-color,var(--read-tr-color-default));font-size:var(--read-tr-size,16.5px)}
}
@media (min-width:900px) and (prefers-color-scheme:dark){
  #textView{--read-color-default:#93C5FD;--read-tr-color-default:#7DD3C8}
}
.read-style-pop{position:fixed;z-index:920;background:var(--surface);border:1px solid var(--line);border-radius:14px;
  padding:12px 14px;box-shadow:0 18px 44px -20px rgba(15,40,70,.45);display:flex;flex-direction:column;gap:10px}
.rs-row{display:flex;align-items:center;gap:7px;flex-wrap:wrap}
.rs-label{flex:0 0 76px;font-size:12px;font-weight:700;color:var(--mut)}
.rs-sw{width:22px;height:22px;border-radius:50%;border:2px solid transparent;padding:0;cursor:pointer}
.rs-sw.is-on{border-color:var(--blue);box-shadow:0 0 0 2px rgba(59,130,246,.25)}
.rs-size{width:30px;height:30px;border-radius:9px;border:1px solid var(--line);background:none;color:var(--ink);
  font-weight:800;cursor:pointer;display:inline-flex;align-items:center;justify-content:center}
.rs-size:hover{background:rgba(59,130,246,.10)}
.rs-val{min-width:34px;text-align:center;font-size:12.5px;font-weight:700;color:var(--mut);font-variant-numeric:tabular-nums}

/* 🏠 the wordmark is YouTube's logo — a click goes home */
.side-brand{cursor:pointer}
.side-brand:hover strong{color:var(--blue-deep)}
@media(prefers-color-scheme:dark){.side-brand:hover strong{color:var(--blue)}}

/* 🎨📱 …AND THE PHONE HOLDS ITS OWN PEN ('the button should be present also
   in the bar menu, and the letter size of PC and mobile should be saved
   independently'): the same Aa control lives in the reading bar on every
   size, but it writes the -m keys here — the phone's color rides .sentence,
   its size rides .turn-flow exactly where the phone cascade sets it, and a
   choice made at the desk never resizes the phone in the pocket. */
@media (max-width:899px){
  #textView .turn-flow{font-size:var(--read-size-m,17.5px)}
  #textView .sentence{color:var(--read-color-m,inherit)}
  #textView .sen-tr.shown{color:var(--read-tr-color-m,var(--mut));font-size:var(--read-tr-size-m,12.5px)}
}

/* 📖 the Sproochentest thema's corner door — a tinted lines button on the
   topic card, opening the list where every sentence is a door */
.subj-list-btn{flex:0 0 auto;width:34px;height:34px;border:0;border-radius:10px;cursor:pointer;
  background:rgba(59,130,246,.10);color:var(--blue-deep);display:flex;align-items:center;justify-content:center}
.subj-list-btn:hover{background:rgba(59,130,246,.22)}
.subj-list-btn svg{width:16px;height:16px;display:block}
@media(prefers-color-scheme:dark){.subj-list-btn{color:var(--blue)}}

/* 🎨📱 THE SUBTITLE PALETTE, ON A PHONE (the learner: "the menu subtitle
   color — when we click on it the content is not optimised for phone").
   The panel was built for a mouse: label, nine swatches and A−/A+ on ONE
   line, ~470px of it, centre-anchored over a 375px screen — it hung off
   both edges and its buttons were 26px. On a touch hand (or any narrow
   window) it becomes a sheet the width of the screen: the label on its own
   line, the swatches wrapping at finger size, A−/A+ pushed to the end. */
@media (hover:none),(pointer:coarse),(max-width:620px){
  .feed-palette{left:10px;right:10px;transform:none;width:auto;
    max-height:52vh;overflow-y:auto;gap:12px;padding:12px}
  .feed-pal-row{flex-wrap:wrap;gap:8px}
  .feed-pal-row>span{width:100%;font-size:12px;opacity:.85}
  .feed-swatch{width:32px;height:32px}
  .feed-size{margin-left:auto;gap:8px}
  .feed-size-btn{min-width:44px;height:32px;font-size:13px}
}
/* …and the idle clock lets go while it is open — the deck fading mid-choice
   took the palette down with it. AFTER the idle rule, so this one wins. */
.feed.pal-open .feed-slide.is-active .feed-menu{opacity:1;pointer-events:auto}

/* 🧩 THE VERBEN SECTION JOINS THE PASS — the last corner of the app still
   wearing its first draft. Everything here is APPENDED and every rule is
   SCOPED to a hook the section adds at build time (.tp-verbs, .vb-sheet,
   .vb-verb, .vs-list, .vo-sheet), because .tp-* is shared chrome with Themen
   and the Sproochentest and this pass has no business in those. The base
   rules the pins name stay exactly where they are. */

/* the drawers: the tile joins the family (38/12/.12, the drawer row's own
   numbers), the card takes the soft shadow and the hover ring the Today rows
   wear, and a chevron says the thing is a door */
.subj-card{border-color:transparent;box-shadow:0 12px 30px -22px rgba(29,78,216,.28);
  transition:transform .08s ease,border-color .16s ease,box-shadow .16s ease}
.subj-card:hover{border-color:rgba(59,130,246,.5);box-shadow:0 16px 34px -20px rgba(29,78,216,.38)}
.subj-card:focus-visible{outline:2px solid var(--blue);outline-offset:2px}
.subj-ic{width:38px;height:38px;border-radius:12px;background:rgba(59,130,246,.12)}
.subj-card:hover .subj-ic{background:rgba(59,130,246,.24)}
.subj-go{margin-left:auto;flex:0 0 auto;display:flex;align-items:center;color:var(--mut);
  opacity:.5;transition:transform .14s ease,opacity .14s ease}
.subj-go svg{width:18px;height:18px;display:block}
.subj-card:hover .subj-go{opacity:1;transform:translateX(2px)}

/* the counts stop being grey prose and become the home's pill */
.tp-overlay.tp-verbs .tp-count,.vb-sheet .tp-count,.vs-list .tp-count{
  display:inline-flex;align-items:center;min-height:34px;margin:0 0 14px;padding:0 14px;
  border-radius:999px;background:rgba(59,130,246,.10);color:var(--blue-deep);
  font-size:12.5px;font-weight:700}

/* the verb list: cards, and the auxiliary — the one fact you need before you
   can say anything in the past — stops hiding inside grey prose */
.vb-card{border-color:transparent;box-shadow:0 12px 30px -22px rgba(29,78,216,.28);
  transition:transform .08s ease,border-color .16s ease,box-shadow .16s ease}
.vb-card:hover{border-color:rgba(59,130,246,.5);box-shadow:0 16px 34px -20px rgba(29,78,216,.38)}
.vb-aux{display:inline-block;margin-right:6px;padding:1px 7px;border-radius:999px;
  background:rgba(59,130,246,.10);color:var(--blue-deep);font-style:normal;
  font-size:10.5px;font-weight:800;vertical-align:1px}

/* one verb: its forms become rows with a card's weight, the mastery count a
   pill, and the conjugation a reference card instead of a bare table */
.vb-verb .tp-row{border-color:transparent;border-radius:14px;padding:13px 15px;
  background:var(--surface);box-shadow:0 12px 30px -22px rgba(29,78,216,.25);
  transition:border-color .15s ease,box-shadow .15s ease}
.vb-verb .tp-row:hover{border-color:rgba(59,130,246,.5);box-shadow:0 16px 34px -20px rgba(29,78,216,.35)}
.vb-verb .tp-n{margin-left:auto;flex:0 0 auto;padding:5px 11px;border-radius:999px;
  background:rgba(59,130,246,.10);color:var(--blue-deep);font-size:11.5px;font-weight:800}
.vb-verb .vb-conj{border-radius:16px;padding:12px 16px;background:var(--surface);
  border:1px solid var(--line);box-shadow:0 12px 30px -22px rgba(29,78,216,.25)}
.vb-verb .vb-who{opacity:1;color:var(--mut);font-weight:650}
.vb-verb .vb-form{font-weight:700;color:var(--ink)}
/* how far a form is from full. The mastery pill says what you can SAY; this
   says what has been WRITTEN, and it is the number the ✚ inside the form
   moves — so it belongs on the row that opens it. A finished cell goes green
   and stops nagging. */
.vb-verb .vb-owed{flex:0 0 auto;padding:5px 11px;border-radius:999px;
  background:rgba(127,127,127,.12);color:var(--mut);font-size:11.5px;font-weight:800;white-space:nowrap}
.vb-verb .vb-owed.is-full{background:rgba(46,158,91,.12);color:#2E9E5B}
/* ✚ Méi Sätz, and the line under it that reports what the round earned. The
   line is EMPTY most of the time and must take no room when it is. */
.vb-more-stat{margin:-2px 0 12px;font-size:12.5px;min-height:0}
.vb-more-stat:empty{display:none}
.vb-more[disabled]{opacity:.55;cursor:progress}

/* the sentence list: cards that lift, a finished one tinted the way a known
   drawer is (a green hairline alone was invisible), the form heading a chip */
.vs-row{border-color:transparent;border-radius:14px;
  box-shadow:0 12px 30px -22px rgba(29,78,216,.25);
  transition:border-color .15s ease,box-shadow .15s ease,background .15s ease}
.vs-row:hover{border-color:rgba(59,130,246,.5);box-shadow:0 16px 34px -20px rgba(29,78,216,.35)}
.vs-row:active{transform:none;background:rgba(59,130,246,.06)}
.vs-row.is-known{border-color:rgba(46,158,91,.45);background:rgba(46,158,91,.05)}
.vs-form{display:inline-flex;align-items:center;min-height:28px;margin:18px 0 8px;
  padding:5px 13px;border-radius:999px;background:rgba(59,130,246,.10);
  color:var(--blue-deep);font-size:11.5px;font-weight:800;letter-spacing:.04em;text-transform:uppercase}

/* the game's prompt sits on a card, so the question reads as the question */
.vo-sheet .vo-ask{padding:16px 18px;border:1px solid var(--line);border-radius:16px;
  background:var(--surface);box-shadow:0 12px 30px -22px rgba(29,78,216,.22)}

@media(prefers-color-scheme:dark){
  .tp-overlay.tp-verbs .tp-count,.vb-sheet .tp-count,.vs-list .tp-count,
  .vb-verb .tp-n,.vb-aux,.vs-form{color:var(--blue)}
  .vs-row.is-known{background:rgba(46,158,91,.12)}
}

/* …and on a PC the section stops being a 760px ribbon: the sheet widens and
   the sentence list — the longest scroll in the app — reads in two columns */
@media (min-width:900px){
  .tp-overlay.tp-verbs .tp-body,.vb-sheet,.vs-list{max-width:1040px}
  .tp-overlay.tp-verbs .subj-grid{grid-template-columns:repeat(auto-fill,minmax(300px,1fr))}
  .vs-list{display:grid;grid-template-columns:1fr 1fr;gap:0 14px;align-content:start}
  .vs-list .tp-count,.vs-list .vs-form,.vs-list .make-note,.vs-list .tp-wait{grid-column:1/-1}
  .vb-verb .vb-conj{grid-template-columns:auto 1fr auto 1fr;gap:2px 16px}
}

/* ⛶ THE WORD ENTRY, FULL SCREEN (the learner: "in the word popup we should be
   able to see full screen"). The bubble stays the bubble — a glance at a word
   while reading — and ⛶ lifts that same popup into a centred panel with the
   page dimmed behind it, which is what the meanings, the examples and the
   picture were always too big for. It reads over a film in true fullscreen
   too: the popup already mounts inside the fullscreen element, and a fixed
   panel inside it fills that same screen. */
.word-pop-big{background:none;border:0;padding:2px 4px;color:var(--mut);cursor:pointer;
  display:inline-flex;align-items:center;flex:0 0 auto}
.word-pop-big svg{width:17px;height:17px;display:block}
.word-pop-big:hover{color:var(--blue-deep)}
.word-pop-backdrop{position:fixed;inset:0;z-index:1009;background:rgba(8,14,22,.62);
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px)}
.word-pop.is-big{left:50%;top:50%;transform:translate(-50%,-50%);
  width:min(620px,calc(100vw - 28px));max-width:none;max-height:min(84vh,860px);overflow-y:auto;
  gap:9px;padding:20px 22px;border-radius:20px;font-size:15px;
  box-shadow:0 30px 70px -20px rgba(8,14,22,.65)}
.word-pop.is-big strong{font-size:26px}
.word-pop.is-big .word-pop-info{font-size:13.5px}
.word-pop.is-big .word-pop-tr{font-size:16px;line-height:1.55}
.word-pop.is-big .word-pop-meaning{font-size:15px;padding:6px 8px;margin:0 -8px}
.word-pop.is-big .word-pop-uses{border-radius:0 0 20px 20px;font-size:13.5px;padding:11px 14px;
  margin:6px -22px -20px}
.word-pop.is-big .word-pop-learn svg{width:23px;height:23px}
.word-pop.is-big .word-pop-image img{max-height:38vh;width:auto;max-width:100%}

/* ▶🔊✏️ THE SENTENCE'S THREE TOOLS — the original clip, the app voice, and an
   edit. The original is only built where the account holds the media. */
.vs-tools{display:flex;align-items:center;gap:4px;flex:0 0 auto}
.vs-orig.is-playing{color:var(--blue-deep);background:rgba(59,130,246,.16)}
@media(prefers-color-scheme:dark){.vs-orig.is-playing{color:var(--blue)}}
/* ✏️ the edit sheet: the same sentence and its translation, in two fields */
.vse-overlay{position:fixed;inset:0;z-index:1015;background:rgba(8,14,22,.55);
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px);display:flex;align-items:center;justify-content:center;padding:16px}
.vse-card{width:min(560px,100%);max-height:88vh;overflow-y:auto;background:var(--surface);
  border:1px solid var(--line);border-radius:18px;padding:20px 22px;
  box-shadow:0 30px 70px -20px rgba(8,14,22,.6);display:flex;flex-direction:column;gap:8px}
.vse-h{font-size:17px;color:var(--ink);margin-bottom:4px}
.vse-lab{font-size:12px;font-weight:700;color:var(--mut);margin-top:6px}
.vse-in{width:100%;border:1px solid var(--line);border-radius:12px;padding:11px 13px;
  font:inherit;font-family:inherit;font-size:15px;color:var(--ink);background:var(--bg);resize:vertical}
.vse-in:focus{outline:2px solid rgba(59,130,246,.5);outline-offset:1px}
.vse-in[lang=lb]{font-size:16px}
.vse-stat{min-height:16px;font-size:12.5px;color:var(--red);margin:2px 0}
