/* Parley. French practice, built on the Édito books.

   Bright studio. A warm paper ground with soft colour glows behind it, white
   cards with a hairline and a tinted shadow, one display face for the titles
   (Outfit) and one text face for everything that is read (Plus Jakarta Sans).

   The colour comes from the toucan: blue and teal for the controls and the
   brand, coral and pink for warmth, sun for notices. Every unit, section and
   lesson carries its own hue in --u, and that hue goes on its badge, its
   tiles, its wash and its waveform, so the app has colour everywhere without
   the controls changing meaning from page to page. French text still sits on
   white or a near-white tint, always. */

:root {
  color-scheme: light;

  --ground: #FBF8F3;
  --surface: #FFFFFF;
  --surface-2: #F7F5F0;

  --ink: #1B1A2E;
  --ink-2: #57556E;
  --ink-3: #8E8CA3;

  --line: rgba(27, 26, 46, .09);
  --line-soft: rgba(27, 26, 46, .055);

  /* The toucan. */
  --blue: #2F6BFF;  --blue-deep: #1F4FD6; --blue-wash: #E8EFFF;
  --teal: #14B8B0;  --teal-wash: #DFF6F4;
  --coral: #FF6B5C; --coral-wash: #FFE9E5;
  --pink: #FF3F8E;  --pink-wash: #FFE4EF;
  --sun: #FFC43D;   --sun-wash: #FFF3D1;
  --lilac: #8B7BFF; --lilac-wash: #EDEAFF;

  --accent: var(--blue);
  --accent-dark: var(--blue-deep);
  --accent-wash: var(--blue-wash);
  --accent-glow: rgba(47, 107, 255, .30);

  --ok: #17A86B; --ok-wash: #E3F8EE; --ok-line: rgba(23, 168, 107, .40);
  --no: #E5484D; --no-wash: #FFE9EA; --no-line: rgba(229, 72, 77, .40);

  /* Overridden per unit / section by app.js; the default is the brand blue. */
  --u: #2F6BFF;
  --u-wash: #E8EFFF;

  --grad-brand: linear-gradient(135deg, #2F6BFF 0%, #14B8B0 100%);
  --grad-brand-deep: linear-gradient(135deg, #2456E6 0%, #0E9C95 100%);
  --grad-warm: linear-gradient(135deg, #FF6B5C 0%, #FF3F8E 100%);
  --grad-hero: linear-gradient(115deg, #FFF3D6 0%, #FFE2E9 48%, #D9F4F3 100%);

  --r-xl: 30px;
  --r-lg: 22px;
  --r: 16px;
  --r-sm: 11px;

  --shadow-1: 0 1px 2px rgba(27, 26, 46, .04), 0 6px 22px rgba(27, 26, 46, .06);
  --shadow-2: 0 2px 4px rgba(27, 26, 46, .05), 0 18px 44px rgba(27, 26, 46, .11);
  --shadow-3: 0 4px 10px rgba(27, 26, 46, .06), 0 28px 70px rgba(27, 26, 46, .16);

  --ease: cubic-bezier(.4, 0, .2, 1);
  --spring: cubic-bezier(.34, 1.4, .64, 1);
  --display: "Outfit", "Plus Jakarta Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  --sans: "Plus Jakarta Sans", -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Inter, system-ui, sans-serif;

  --bar-h: 62px;

  /* ParleyTV. The subtitle face is Nunito, rounded and warm where Outfit is
     geometric, which is what a line of French read at a glance and tapped word
     by word wants. It is self-hosted, so the feed works with no network, and
     `ui-rounded` ahead of the fallbacks is SF Pro Rounded, already on an Apple
     device before the file lands. It goes on the subtitle line, the word card's
     headword and the two big numbers on the check. Nowhere else. */
  --tv-face: "Nunito", ui-rounded, "SF Pro Rounded", var(--sans);

  /* Grammar, as colour, drawn from the toucan and deepened until every one
     clears 4.5:1 both on white and on the sun wash behind an unknown word,
     these are read as text, not only seen as a signal. */
  --tv-m: #1F4FD6;              /* nom masculin, the brand blue, deep    */
  --tv-f: #C20F5C;              /* nom féminin, the pink, deep          */
  --tv-v: #067A73;              /* verbe, the teal, deep          */
  --tv-a: #5B3FD6;              /* adjectif, the lilac, deep         */
  --tv-new-ink: #8F6200;        /* a word you do not know yet, the sun    */
  --tv-new-wash: var(--sun-wash);
  --tv-name: #6F6D85;           /* a proper noun: not vocabulary           */
}

/* Two subsets of the Nunito variable font, Latin and Latin Extended, self
   hosted so the feed works offline and nothing goes stale. The licence sits
   beside them in web/assets/font/LICENSE.txt, which is what it requires. */
@font-face {
  font-family: "Nunito";
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url(assets/font/nunito-var-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Nunito";
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url(assets/font/nunito-var-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  /* How much the bar at the foot of a phone takes, and how much of the home
     indicator's room is left for whatever stacks above it: the bar keeps that
     room itself, so the check pill and the accent bar must not keep it twice.
     Both are set by the .tabbar rules at the end of this file. */
  --tab-h: 0px;
  --tab-safe: env(safe-area-inset-bottom);
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--ground);
  color: var(--ink);
  font: 16.5px/1.55 var(--sans);
  -webkit-font-smoothing: antialiased;
  letter-spacing: -.005em;
}

/* Three soft glows behind everything: sun top-left, teal top-right, pink at
   the foot. Fixed, so they stay put while the page scrolls; a pseudo-element
   rather than background-attachment, which iOS ignores. */
body::before {
  content: '';
  position: fixed; inset: 0; z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(760px 480px at -8% -12%, rgba(255, 196, 61, .26), transparent 62%),
    radial-gradient(720px 460px at 108% -6%, rgba(20, 184, 176, .18), transparent 62%),
    radial-gradient(680px 520px at 50% 112%, rgba(255, 63, 142, .10), transparent 62%);
}

/* The UA hides [hidden] with display:none, but any author display rule beats
   it, which is how the progress chip once showed "0 / 0" on the hub. */
[hidden] { display: none !important; }

a { color: inherit; text-decoration: none; }
button, input, textarea, select { font-family: inherit; }
img { max-width: 100%; display: block; }
h1, h2, h3 { font-family: var(--display); }

::selection { background: rgba(47, 107, 255, .18); }

:focus-visible {
  outline: 3px solid rgba(47, 107, 255, .45);
  outline-offset: 2px;
  border-radius: 8px;
}

/* ---------------------------------------------------------------- top bar */

.topbar {
  position: sticky;
  top: 0;
  z-index: 40;
  height: var(--bar-h);
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 max(18px, env(safe-area-inset-right)) 0 max(18px, env(safe-area-inset-left));
  background: rgba(255, 255, 255, .74);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  backdrop-filter: saturate(180%) blur(20px);
  border-bottom: 1px solid rgba(27, 26, 46, .06);
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: none;
  padding: 4px 8px 4px 2px;
  border-radius: 999px;
  transition: transform .18s var(--spring);
}
.brand:hover { transform: translateY(-1px); }
.brand-mark {
  width: 34px; height: 34px;
  flex: 0 0 auto;
  object-fit: contain;
  filter: drop-shadow(0 3px 6px rgba(31, 79, 214, .18));
}
.brand-text { line-height: 1.05; }
.brand-text b {
  display: block;
  font-family: var(--display);
  font-size: 20px; font-weight: 800;
  letter-spacing: -.015em;
  background: var(--grad-brand);
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
}
.brand-text small {
  display: block;
  font-size: 11px; font-weight: 600;
  color: var(--ink-3);
  letter-spacing: .01em;
  margin-top: 1px;
}

.topbar .spacer { flex: 1; }

/* Progress ring in the corner. */
.progress-chip {
  display: flex; align-items: center; gap: 8px;
  height: 36px; padding: 0 12px 0 6px;
  border-radius: 999px;
  background: #fff;
  border: 1px solid var(--line);
  font-size: 13px; font-weight: 700;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.ring { width: 24px; height: 24px; transform: rotate(-90deg); flex: none; }
.ring-bg { fill: none; stroke: rgba(27, 26, 46, .10); stroke-width: 3.6; }
.ring-fg {
  fill: none; stroke: var(--accent); stroke: url(#ringGrad); stroke-width: 3.6; stroke-linecap: round;
  stroke-dasharray: 97.4;
  transition: stroke-dashoffset .6s var(--ease);
}

.accent-toggle {
  height: 36px; padding: 0 13px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: #fff;
  color: var(--ink-2);
  font-size: 13px; font-weight: 700;
  letter-spacing: .04em;
  cursor: pointer;
  transition: background .15s var(--ease), color .15s var(--ease), border-color .15s var(--ease), transform .15s var(--spring);
}
.accent-toggle:hover { border-color: rgba(27, 26, 46, .18); }
.accent-toggle[aria-pressed="true"] {
  background: var(--accent-wash); border-color: rgba(47, 107, 255, .32); color: var(--accent-dark);
}
.accent-toggle:active { transform: scale(.95); }
/* The way into ParleyTV: the word, in the same pill as the other switches. */
.accent-toggle.tv { display: inline-flex; align-items: center; text-decoration: none; }

/* ------------------------------------------------------------------ shell */

.view { flex: 1; display: flex; flex-direction: column; }

.wrap {
  width: min(1180px, 100%);
  margin: 0 auto;
  padding: 0 max(24px, env(safe-area-inset-left)) 96px max(24px, env(safe-area-inset-right));
}
.wrap.narrow { width: min(940px, 100%); }
.unit-hero .wrap, .ex-hero .wrap { padding-bottom: 0; }

.foot {
  margin-top: auto;
  padding: 26px 24px calc(26px + env(safe-area-inset-bottom));
  text-align: center;
  color: var(--ink-3);
  font-size: 12.5px;
  line-height: 1.6;
}
.foot p { margin: 0; }
.foot-links { margin-top: 6px; }
.foot-links a { color: var(--accent); font-weight: 700; }
.foot-links a:hover { text-decoration: underline; text-underline-offset: 3px; }

/* ------------------------------------------------------------- page heads */

.page-head { padding: 22px 0 16px; }
.page-head h1 {
  margin: 0;
  font-size: clamp(34px, 5vw, 50px);
  font-weight: 800;
  letter-spacing: -.025em;
  line-height: 1.02;
}
.kicker {
  display: inline-flex; align-items: center; gap: 6px;
  margin: 0 0 12px;
  padding: 5px 12px;
  border-radius: 999px;
  background: var(--u-wash);
  color: var(--u);
  font-size: 12px; font-weight: 800;
  letter-spacing: .08em; text-transform: uppercase;
}
.page-head .sub, .ex-title .sub {
  margin: 12px 0 0;
  font-size: 17px;
  color: var(--ink-2);
}

/* The trail: Accueil › the manual › the unit › this page. Links are pills,
   the current page is quiet text, and on a phone the current page drops out
   because the title is right under it. */
.crumbs {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 6px 2px;
  margin: 18px 0 0;
  min-height: 34px;
}
.crumb {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 13px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .85);
  border: 1px solid var(--line);
  font-size: 13.5px; font-weight: 700;
  color: var(--ink-2);
  transition: transform .18s var(--spring), color .15s var(--ease), box-shadow .18s var(--ease), border-color .15s var(--ease);
}
a.crumb:hover { color: var(--ink); transform: translateY(-1px); box-shadow: var(--shadow-1); border-color: rgba(27, 26, 46, .16); }
.crumb.here {
  background: transparent; border-color: transparent;
  color: var(--ink-3); font-weight: 600;
  max-width: 34ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.crumb-sep { width: 8px; height: 13px; fill: var(--ink-3); opacity: .5; margin: 0 4px; flex: none; }

/* Section links in the top bar. */
.topnav { display: flex; align-items: center; gap: 2px; margin-left: 8px; }
.topnav-link {
  display: inline-flex; align-items: center;
  height: 36px; padding: 0 13px;
  border-radius: 999px;
  font-size: 14px; font-weight: 700;
  color: var(--ink-2);
  transition: background .15s var(--ease), color .15s var(--ease);
}
.topnav-link:hover { background: rgba(27, 26, 46, .06); color: var(--ink); }
.topnav-link.on { background: var(--accent-wash); color: var(--accent-dark); }

/* ------------------------------------------------------------------- hub */

/* The welcome: a light wash, the greeting in the display face, and the
   toucan, which is the one place the mascot is allowed to be large. */
.hub-hero {
  position: relative;
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 24px;
  margin: 28px 0 10px;
  padding: 36px 40px;
  border-radius: var(--r-xl);
  background: var(--grad-hero);
  box-shadow: var(--shadow-1);
  overflow: hidden;
}
.hub-hero::before, .hub-hero::after {
  content: '';
  position: absolute; border-radius: 50%;
  pointer-events: none;
}
.hub-hero::before {
  width: 320px; height: 320px; right: 120px; top: -180px;
  background: radial-gradient(circle, rgba(255, 255, 255, .8), rgba(255, 255, 255, 0) 70%);
}
.hub-hero::after {
  width: 260px; height: 260px; left: -90px; bottom: -160px;
  background: radial-gradient(circle, rgba(20, 184, 176, .22), rgba(20, 184, 176, 0) 70%);
}
.hub-hero > * { position: relative; z-index: 1; }
.hub-hero .kicker { background: rgba(255, 255, 255, .75); color: var(--blue-deep); }
.hub-hero h1 {
  margin: 0;
  font-size: clamp(36px, 5.6vw, 58px);
  font-weight: 800;
  letter-spacing: -.03em;
  line-height: 1;
}
.hub-hero .sub {
  margin: 14px 0 0;
  max-width: 46ch;
  font-size: 17px; line-height: 1.5;
  color: var(--ink-2);
}
.hub-hero-bird {
  width: 210px; height: 210px;
  object-fit: contain;
  filter: drop-shadow(0 22px 30px rgba(31, 79, 214, .22));
  animation: float 6s ease-in-out infinite;
}
@keyframes float {
  0%, 100% { transform: translateY(0) rotate(-2deg); }
  50% { transform: translateY(-10px) rotate(2deg); }
}

/* Pick up where you left off. The one strong colour block on the hub. */
.resume-card {
  position: relative;
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 16px;
  margin: 18px 0 8px;
  padding: 20px 24px;
  border-radius: var(--r-lg);
  background: var(--grad-brand-deep);
  color: #fff;
  box-shadow: 0 10px 30px rgba(36, 86, 230, .28);
  overflow: hidden;
  transition: transform .2s var(--spring), box-shadow .2s var(--ease);
}
.resume-card::after {
  content: '';
  position: absolute; right: -60px; top: -90px;
  width: 220px; height: 220px; border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 255, 255, .28), rgba(255, 255, 255, 0) 70%);
  pointer-events: none;
}
.resume-card:hover { transform: translateY(-3px); box-shadow: 0 16px 40px rgba(36, 86, 230, .34); }
.resume-card:active { transform: translateY(-1px) scale(.995); }
.resume-card > * { position: relative; z-index: 1; }
.resume-kicker {
  display: block;
  font-size: 11.5px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  opacity: .8;
}
.resume-title {
  display: block; margin-top: 4px;
  font-family: var(--display);
  font-size: 22px; font-weight: 700; letter-spacing: -.015em; line-height: 1.2;
}
.resume-sub { display: block; margin-top: 4px; font-size: 13.5px; opacity: .85; }
.resume-card .chev { fill: #fff; opacity: .9; width: 11px; height: 18px; }

.hub-h2 {
  margin: 38px 0 14px;
  font-size: 23px; font-weight: 700;
  letter-spacing: -.015em;
  color: var(--ink);
}
.hub-h2:first-of-type { margin-top: 26px; }
.hub-actions { display: flex; flex-wrap: wrap; gap: 10px; margin: 18px 0 0; }
/* The teacher's row only: on a desktop the top bar carries those links. Every
   other row of actions (the placement, the TV check) shows at every width. */
@media (min-width: 901px) { .hub-actions.hub-staff { display: none; } }

/* -------------------------------------------------------- tableau de bord */

/* The dashboard on the hub. Six columns; a tile is one, two or three wide,
   and the rows are built to add up to six. Two tiles sit on a wash, the
   week and the proverb, because they are the two that are looked at rather
   than read. */
.bento {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 14px;
  margin: 22px 0 6px;
}
.bento-tile {
  position: relative;
  display: flex; flex-direction: column; gap: 2px;
  min-height: 172px;
  padding: 18px 20px 16px;
  border-radius: var(--r-lg);
  background: var(--surface);
  border: 1px solid var(--line-soft);
  box-shadow: var(--shadow-1);
  overflow: hidden;
  transition: transform .22s var(--spring), box-shadow .22s var(--ease);
}
.bento-tile:hover { transform: translateY(-2px); box-shadow: var(--shadow-2); }
.bento-tile.wash { border: 0; border-radius: var(--r-lg); }
.b-1 { grid-column: span 1; }
.b-2 { grid-column: span 2; }
.b-3 { grid-column: span 3; }
/* The proverb, when Aujourd'hui has taken the goals tile out of the grid and
   left it half a row to close. */
.b-6 { grid-column: span 6; }

.bento-label {
  font-size: 11.5px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink-3);
}
.wash .bento-label { color: rgba(27, 27, 31, .55); }
.bento-big {
  margin: 8px 0 0;
  font-family: var(--display);
  font-size: 40px; font-weight: 800; letter-spacing: -.03em; line-height: 1;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.bento-big small {
  font-family: var(--sans);
  font-size: 14px; font-weight: 700; letter-spacing: 0;
  color: var(--ink-3);
  margin-left: 7px;
}
.bento-sub { margin: auto 0 0; padding-top: 10px; font-size: 13.5px; line-height: 1.45; color: var(--ink-2); }
.bento-sub b { color: var(--ink); font-weight: 700; }
.wash .bento-sub { color: rgba(27, 27, 31, .66); }
.wash .bento-big { color: #1B1B1F; }

.bento-row { display: flex; align-items: center; gap: 16px; margin-top: 8px; flex: 1; }
.bento-row > div { min-width: 0; flex: 1; display: flex; flex-direction: column; align-self: stretch; justify-content: center; gap: 6px; }
.bento-row .bento-big { margin-top: 0; }
.bento-row .bento-sub { margin-top: 0; padding-top: 0; }

.bento-ring { position: relative; width: 86px; height: 86px; flex: none; }
.bento-ring svg { width: 100%; height: 100%; transform: rotate(-90deg); }
.bento-ring .ring-bg { stroke-width: 3.2; }
.bento-ring .ring-fg { stroke-width: 3.2; transition: stroke-dashoffset .9s var(--ease); }
.bento-ring-mid { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; }
.bento-ring-mid b { font-family: var(--display); font-size: 18px; font-weight: 800; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }

.bento-delta {
  display: inline-flex; align-self: flex-start; align-items: center;
  margin-top: 8px; padding: 3px 9px;
  border-radius: 999px;
  font-size: 12.5px; font-weight: 800;
  background: var(--ok-wash); color: var(--ok);
}
.bento-delta.down { background: var(--sun-wash); color: #A06A00; }
.bento-row .bento-delta { margin-top: 0; }

.bento-bars { display: flex; align-items: flex-end; gap: 6px; height: 68px; margin-top: 12px; }
.bento-bar { flex: 1 1 0; height: 100%; display: flex; flex-direction: column; justify-content: flex-end; gap: 4px; }
.bento-bar i { display: block; min-height: 3px; background: rgba(27, 26, 46, .10); border-radius: 5px; transition: height .5s var(--ease); }
.bento-bar.on i { background: var(--grad-brand); }
.bento-tile.reached .bento-bar.on i { background: var(--ok); }
.bento-bar span { font-size: 10.5px; font-weight: 700; text-align: center; color: rgba(27, 27, 31, .5); }

.btn.small { height: 36px; padding: 0 16px; font-size: 14px; margin-top: 12px; align-self: flex-start; }
.bento-link { margin-top: auto; padding-top: 10px; font-size: 13.5px; font-weight: 700; color: var(--accent); }
.bento-link:hover { text-decoration: underline; text-underline-offset: 3px; }

.bento-next {
  display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 12px;
  margin-top: 8px; padding: 11px 14px;
  border-radius: var(--r);
  background: var(--surface-2);
  transition: background .15s var(--ease), transform .18s var(--spring);
}
.bento-next:hover { background: var(--u-wash); transform: translateX(2px); }
.bento-next > span { min-width: 0; }
.bento-next-kicker { display: block; font-size: 11px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--u); }
.bento-next-title {
  display: block; margin-top: 2px;
  font-family: var(--display); font-size: 17px; font-weight: 700; letter-spacing: -.01em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bento-next .chev { fill: var(--ink-3); }
.bento-next:hover .chev { transform: translateX(3px); opacity: 1; }

.bento-quote {
  margin: 10px 0 0;
  font-family: var(--display); font-size: 24px; font-weight: 700; letter-spacing: -.015em; line-height: 1.22;
  color: #1B1B1F;
  text-wrap: balance;
}

@media (max-width: 900px) {
  .bento { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .b-1, .b-2, .b-3.b-next { grid-column: span 2; }
  .b-3, .b-6 { grid-column: span 4; }
  .b-3.b-next { grid-column: span 2; }
}
@media (max-width: 640px) {
  .bento { grid-template-columns: 1fr; gap: 10px; }
  .b-1, .b-2, .b-3, .b-6, .b-3.b-next { grid-column: span 1; }
  .bento-tile { min-height: 0; padding: 16px 18px 14px; }
  .bento-big { font-size: 34px; }
  .bento-quote { font-size: 21px; }
}

/* ------------------------------------------------------------- unit grid */

.unit-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 18px;
}

.unit-card {
  position: relative;
  display: flex; flex-direction: column;
  min-height: 186px;
  padding: 20px 20px 18px;
  border-radius: var(--r-lg);
  background: var(--surface);
  border: 1px solid var(--line-soft);
  box-shadow: var(--shadow-1);
  overflow: hidden;
  transition: transform .22s var(--spring), box-shadow .22s var(--ease), border-color .22s var(--ease);
}
/* The unit's colour, as a soft field in the top-right corner. */
.unit-card::before {
  content: '';
  position: absolute; inset: -46% -34% auto auto;
  width: 220px; height: 220px;
  border-radius: 50%;
  background: var(--u-wash);
  background: radial-gradient(circle at 35% 35%, color-mix(in srgb, var(--u) 26%, #fff), var(--u-wash) 55%, rgba(255, 255, 255, 0) 72%);
  transition: transform .4s var(--ease);
}
.unit-card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-2);
  border-color: color-mix(in srgb, var(--u) 30%, transparent);
}
.unit-card:hover::before { transform: scale(1.2); }
.unit-card:active { transform: translateY(-1px) scale(.995); }
.unit-card > * { position: relative; }

.unit-no {
  display: inline-grid; place-items: center;
  align-self: flex-start;
  width: 40px; height: 40px;
  border-radius: 13px;
  background: var(--u);
  background-image: linear-gradient(160deg, rgba(255, 255, 255, .32), rgba(255, 255, 255, 0) 60%);
  color: #fff;
  font-family: var(--display);
  font-size: 17px; font-weight: 800;
  letter-spacing: -.01em;
  margin-bottom: 14px;
  box-shadow: 0 4px 12px color-mix(in srgb, var(--u) 38%, transparent);
}
.unit-no.wide { width: auto; padding: 0 12px; font-size: 13px; letter-spacing: .05em; }
/* Devoirs has no two-letter short the way Gr. and Voc. do, and an English
   one would not be the French one, so its tile carries the pen instead. */
.devoirs-way .unit-no svg { width: 19px; height: 19px; fill: currentColor; }

.unit-card h3 {
  margin: 0;
  font-size: 21px; font-weight: 700;
  letter-spacing: -.02em;
  line-height: 1.2;
}
.unit-card .meta {
  margin: 6px 0 0;
  font-size: 13.5px; font-weight: 500;
  color: var(--ink-3);
}
.unit-card .foot-row {
  margin-top: auto; padding-top: 18px;
  display: flex; align-items: center; gap: 10px;
}

.bar {
  flex: 1; height: 8px;
  border-radius: 999px;
  background: rgba(27, 26, 46, .07);
  overflow: hidden;
}
.bar i {
  display: block; height: 100%;
  border-radius: 999px;
  background: var(--u);
  background-image: linear-gradient(90deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, .35));
  transition: width .6s var(--ease);
}
.tally {
  font-size: 12.5px; font-weight: 700;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.unit-card.complete .tally { color: var(--ok); }
.unit-card.complete .bar i { background: var(--ok); }

.unit-card.soon {
  background: rgba(255, 255, 255, .55);
  border: 1.5px dashed var(--line);
  box-shadow: none;
}
.unit-card.soon::before { opacity: .5; }
.unit-card.soon .unit-no { box-shadow: none; opacity: .7; }
.unit-card.soon h3 { color: var(--ink-2); }
.unit-card.soon:hover { transform: none; box-shadow: none; border-color: var(--line); }

/* -------------------------------------------------- unit hero + the path */

/* Full-bleed colour field behind the sticky bar. */
.unit-hero, .ex-hero {
  position: relative;
  margin: 0;
  padding: 0;
  background: linear-gradient(180deg, color-mix(in srgb, var(--u) 13%, #fff) 0%, rgba(255, 255, 255, 0) 100%);
  overflow: hidden;
}
.unit-hero::before, .ex-hero::before {
  content: '';
  position: absolute; right: -140px; top: -200px;
  width: 480px; height: 480px; border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--u) 22%, #fff), rgba(255, 255, 255, 0) 66%);
  pointer-events: none;
}
.unit-hero .wrap, .ex-hero .wrap { position: relative; }
.unit-hero .wrap { padding-bottom: 0; }
.unit-hero + .wrap { padding-top: 14px; }
.ex-hero { padding-bottom: 4px; margin-bottom: 8px; }

/* The lesson: an ordered path, not a gallery. */
.path { display: flex; flex-direction: column; gap: 12px; }

.step {
  position: relative;
  display: grid;
  grid-template-columns: 100px 1fr auto;
  align-items: center;
  gap: 18px;
  padding: 12px 18px 12px 12px;
  border-radius: var(--r-lg);
  background: var(--surface);
  border: 1px solid var(--line-soft);
  box-shadow: var(--shadow-1);
  transition: transform .22s var(--spring), box-shadow .22s var(--ease), border-color .22s var(--ease);
}
.step:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-2);
  border-color: color-mix(in srgb, var(--u) 28%, transparent);
}
.step:active { transform: translateY(-1px) scale(.995); }

/* Left tile: the page photograph where the book has one, otherwise the section
   letter on the unit's colour. */
.step-mark {
  --pc: color-mix(in srgb, var(--u) 26%, transparent);
  position: relative;
  width: 100px; height: 70px;
  border-radius: 14px;
  overflow: hidden;
  background-color: color-mix(in srgb, var(--u) 9%, #fff);
  background-image: var(--pattern, none),
    linear-gradient(135deg, color-mix(in srgb, var(--u) 15%, #fff), color-mix(in srgb, var(--u) 3%, #fff));
  background-size: var(--pattern-size, auto), auto;
  background-position: var(--pattern-pos, 0 0), 0 0;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--u) 16%, transparent);
  color: var(--u);
  display: grid; place-items: center;
  font-family: var(--display);
  font-size: 24px; font-weight: 800;
  letter-spacing: -.02em;
  flex: none;
}
/* Eight textures, drawn in the hue and turned by --pa, which app.js sets
   from the item's id. Two-layer patterns carry two sizes so the base
   gradient underneath keeps its own. */
.pat-0 { --pattern: radial-gradient(var(--pc) 1.4px, transparent 1.7px); --pattern-size: 10px 10px; --pattern-pos: 2px 2px; }
.pat-1 { --pattern: repeating-linear-gradient(var(--pa, 45deg), var(--pc) 0 2px, transparent 2px 9px); }
.pat-2 { --pattern: repeating-radial-gradient(circle at 88% 12%, var(--pc) 0 1.4px, transparent 1.4px 10px); }
.pat-3 { --pattern: linear-gradient(var(--pc) 1px, transparent 1px), linear-gradient(90deg, var(--pc) 1px, transparent 1px); --pattern-size: 11px 11px, 11px 11px; --pattern-pos: 3px 3px, 3px 3px; }
.pat-4 { --pattern: radial-gradient(circle at 112% 112%, var(--pc) 0 28px, transparent 29px), radial-gradient(circle at -12% -12%, var(--pc) 0 22px, transparent 23px); --pattern-size: auto, auto; --pattern-pos: 0 0, 0 0; }
.pat-5 { --pattern: repeating-linear-gradient(var(--pa, -30deg), var(--pc) 0 5px, transparent 5px 14px); }
.pat-6 { --pattern: radial-gradient(var(--pc) 2.6px, transparent 3px); --pattern-size: 15px 15px; --pattern-pos: 4px 4px; }
.pat-7 { --pattern: repeating-linear-gradient(var(--pa, 90deg), var(--pc) 0 1px, transparent 1px 6px), repeating-linear-gradient(calc(var(--pa, 90deg) + 90deg), var(--pc) 0 1px, transparent 1px 6px); --pattern-size: auto, auto; --pattern-pos: 0 0, 0 0; }
.step-mark img { width: 100%; height: 100%; object-fit: cover; }
.step-mark svg { width: 26px; height: 26px; fill: currentColor; }
/* The letter, pinned over a photo so it stays readable. */
.step-mark .pin {
  position: absolute; left: 7px; bottom: 7px;
  min-width: 24px; height: 24px; padding: 0 7px;
  display: grid; place-items: center;
  border-radius: 8px;
  background: rgba(255, 255, 255, .94);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  color: var(--u);
  font-size: 12.5px; font-weight: 800;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .18);
}
.step-mark .pin svg { width: 13px; height: 13px; }
.step-mark.lvl { font-size: 15px; letter-spacing: .03em; }
.step.mine .step-mark.lvl { font-variant-numeric: tabular-nums; }

.step-body { min-width: 0; }
.step-body h3 {
  margin: 0;
  font-size: 19.5px; font-weight: 700;
  letter-spacing: -.015em;
  line-height: 1.25;
}
.step-body .meta {
  margin: 5px 0 0;
  font-size: 13.5px;
  color: var(--ink-3);
  display: flex; flex-wrap: wrap; gap: 4px 10px;
}
.step-body .meta b { font-weight: 700; color: var(--u); }

.step-end { display: flex; align-items: center; gap: 12px; flex: none; }

.state {
  width: 28px; height: 28px;
  border-radius: 50%;
  border: 2px solid rgba(27, 26, 46, .14);
  display: grid; place-items: center;
  flex: none;
  transition: background .2s var(--ease), border-color .2s var(--ease), transform .3s var(--spring);
}
.state svg { width: 14px; height: 14px; fill: #fff; opacity: 0; transform: scale(.4); transition: all .25s var(--spring); }
.state.started { border-color: var(--u); border-style: dashed; }
.state.done { background: var(--ok); border-color: var(--ok); box-shadow: 0 4px 12px rgba(23, 168, 107, .35); }
.state.done svg { opacity: 1; transform: scale(1); }

.chev { width: 9px; height: 15px; fill: var(--ink-3); opacity: .6; transition: transform .18s var(--ease); }
.btn .chev { fill: currentColor; opacity: .9; }
.step:hover .chev, .pager a:hover .chev { transform: translateX(3px); opacity: 1; }

/* ---------------------------------------------------------- exercise page */

.ex-title { padding: 16px 0 24px; }
.ex-title .tag-row { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }
.ex-title h1 {
  margin: 0;
  font-size: clamp(28px, 4.2vw, 42px);
  font-weight: 800;
  letter-spacing: -.025em;
  line-height: 1.08;
}
.ex-title .lead { margin: 12px 0 0; font-size: 16.5px; line-height: 1.5; color: var(--ink-2); max-width: 60ch; }

.tag {
  display: inline-flex; align-items: center; gap: 6px;
  height: 28px; padding: 0 12px;
  border-radius: 999px;
  background: var(--u);
  color: #fff;
  font-size: 12.5px; font-weight: 700;
  letter-spacing: 0;
  box-shadow: 0 3px 10px color-mix(in srgb, var(--u) 30%, transparent);
}
.tag.quiet { background: rgba(255, 255, 255, .8); color: var(--ink-2); border: 1px solid var(--line); box-shadow: none; }
.tag svg { width: 13px; height: 13px; fill: currentColor; }

/* Title on the left, the page photograph on the right, with a slight tilt so
   it reads as a snapshot from the book rather than a banner. */
.ex-head {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 28px;
}
.ex-head .ex-title { padding-bottom: 26px; }

.ex-photo {
  width: 300px; height: 196px;
  flex: none;
  border-radius: var(--r-lg);
  overflow: hidden;
  border: 4px solid #fff;
  box-shadow: var(--shadow-2);
  background: var(--surface-2);
  transform: rotate(-1.5deg);
  transition: transform .3s var(--spring);
}
.ex-photo:hover { transform: rotate(0) scale(1.02); }
.ex-photo img { width: 100%; height: 100%; object-fit: cover; object-position: center 45%; }

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

.card {
  background: var(--surface);
  border-radius: var(--r-lg);
  border: 1px solid var(--line-soft);
  box-shadow: var(--shadow-1);
  margin-bottom: 18px;
  overflow: hidden;
}
.card > h2 {
  margin: 0;
  padding: 18px 22px 0;
  font-family: var(--sans);
  font-size: 12.5px; font-weight: 800;
  letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink-3);
}
.card-body { padding: 18px 22px 20px; }

.notice {
  padding: 15px 18px;
  border-radius: var(--r);
  background: var(--sun-wash);
  border: 1px solid rgba(255, 196, 61, .4);
  color: var(--ink-2);
  font-size: 15px;
  line-height: 1.55;
}
.notice b { color: var(--ink); font-weight: 700; }

/* ----------------------------------------------------------------- player */

.player {
  padding: 20px 22px 22px;
  border-top: 1px solid var(--line-soft);
}
.player:first-child { border-top: 0; }

.track-label {
  display: block;
  font-size: 12px; font-weight: 800;
  letter-spacing: .07em; text-transform: uppercase;
  color: var(--u);
  margin-bottom: 12px;
}

/* Waveform, in the unit's colour. */
.wave {
  position: relative;
  width: 100%; height: 66px;
  cursor: pointer;
  touch-action: none;
  border-radius: 12px;
  transition: background .15s var(--ease);
}
.wave:hover { background: color-mix(in srgb, var(--u) 6%, transparent); }
.wave canvas { width: 100%; height: 100%; display: block; }

.wave-times {
  display: flex; justify-content: space-between;
  margin-top: 8px;
  font-size: 12.5px; font-weight: 700;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

.transport {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  margin-top: 14px;
  gap: 12px;
}
.transport .mid {
  grid-column: 2;
  display: flex; align-items: center; gap: 14px;
}
.transport .right {
  grid-column: 3;
  justify-self: end;
  display: flex; align-items: center; gap: 8px;
}

.play {
  width: 62px; height: 62px;
  flex: none;
  border: 0; border-radius: 50%;
  background: var(--grad-brand);
  color: #fff;
  display: grid; place-items: center;
  cursor: pointer;
  box-shadow: 0 4px 10px rgba(47, 107, 255, .25), 0 12px 28px rgba(20, 184, 176, .28);
  transition: transform .2s var(--spring), box-shadow .2s var(--ease), filter .2s var(--ease);
}
.play:hover { transform: scale(1.05); filter: brightness(1.05); box-shadow: 0 6px 14px rgba(47, 107, 255, .3), 0 16px 34px rgba(20, 184, 176, .32); }
.play:active { transform: scale(.94); }
.play svg { width: 22px; height: 22px; fill: #fff; transition: transform .2s var(--ease); }
.play.playing svg { width: 19px; height: 19px; }

.icon-btn {
  width: 42px; height: 42px;
  flex: none;
  display: grid; place-items: center;
  border: 0; border-radius: 50%;
  background: transparent;
  color: var(--ink-2);
  cursor: pointer;
  transition: background .15s var(--ease), color .15s var(--ease), transform .15s var(--spring);
}
.icon-btn svg { width: 23px; height: 23px; }
.icon-btn:hover { background: rgba(27, 26, 46, .06); color: var(--ink); }
.icon-btn:active { transform: scale(.9); }
.icon-btn.toggle[aria-pressed="true"] {
  background: var(--accent-wash);
  color: var(--accent-dark);
}

/* Segmented control. Shared by the player speed, the Mes mots sort, the
   profile language switch and the dashboard tabs. */
.seg {
  display: inline-flex;
  padding: 3px;
  border-radius: 999px;
  background: rgba(27, 26, 46, .06);
}
.seg > button {
  height: 30px; padding: 0 12px;
  border: 0; border-radius: 999px;
  background: none;
  color: var(--ink-3);
  font: inherit;
  font-size: 13px; font-weight: 700;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  transition: background .18s var(--ease), color .18s var(--ease), box-shadow .18s var(--ease);
}
.seg > button:hover { color: var(--ink-2); }
.seg > button[aria-pressed="true"] {
  background: #fff;
  color: var(--ink);
  box-shadow: 0 1px 3px rgba(27, 26, 46, .16);
}

/* video */
.video-frame {
  border-radius: var(--r-lg);
  overflow: hidden;
  background: #000;
  margin: 0 0 4px;
}
.video-frame video { width: 100%; display: block; }

/* One line under the player. Pointless on a phone, where there is no keyboard. */
.kbd-tip {
  margin: 0; padding: 0 22px 16px;
  font-size: 12.5px; line-height: 1.5;
  color: var(--ink-3);
  text-wrap: pretty;
}
@media (hover: none), (max-width: 640px) { .kbd-tip { display: none; } }

/* ----------------------------------------------------------- listen steps */

.stage { border-top: 1px solid var(--line-soft); }
.stage:first-of-type { border-top: 0; }

.stage-head {
  display: flex; align-items: center; gap: 12px;
  padding: 20px 22px 4px;
}
.stage-no {
  width: 28px; height: 28px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--u);
  background-image: linear-gradient(160deg, rgba(255, 255, 255, .3), rgba(255, 255, 255, 0) 60%);
  color: #fff;
  font-family: var(--display);
  font-size: 13.5px; font-weight: 800;
  flex: none;
  box-shadow: 0 3px 8px color-mix(in srgb, var(--u) 35%, transparent);
}
.stage-head h3 {
  margin: 0;
  font-size: 17.5px; font-weight: 700;
  letter-spacing: -.01em;
}
.stage-hint {
  margin: 4px 0 0 62px;
  font-size: 13.5px;
  color: var(--ink-3);
}

/* -------------------------------------------------------------- questions */

.q { padding: 16px 22px; transition: background .2s var(--ease); }
.q + .q { border-top: 1px solid var(--line-soft); }

.q-prompt { display: flex; gap: 11px; margin-bottom: 10px; }
.q-num {
  flex: none;
  min-width: 24px; height: 24px; padding: 0 7px;
  display: grid; place-items: center;
  border-radius: 8px;
  background: var(--u-wash);
  color: var(--u);
  font-size: 12px; font-weight: 800;
  margin-top: 1px;
}
.q-text { font-size: 16.5px; line-height: 1.45; font-weight: 500; }

/* The English sense of the verb, next to the prompt. */
.q-gloss {
  margin-left: auto; padding-left: 12px; flex: 0 0 auto;
  font-size: 13px; color: var(--ink-3); font-style: italic;
  align-self: baseline;
}

/* Multiple choice, as the book prints it. */
.choices { display: flex; flex-direction: column; gap: 8px; }
.choices.inline { flex-direction: row; flex-wrap: wrap; }
.choices.inline .choice { flex: 1 1 auto; min-width: 120px; }
.choice {
  display: flex; align-items: center; gap: 11px;
  padding: 11px 14px;
  border: 1.5px solid var(--line);
  border-radius: var(--r);
  background: #fff;
  cursor: pointer;
  font: inherit;
  font-size: 16px;
  text-align: left;
  color: var(--ink);
  transition: border-color .15s var(--ease), background .15s var(--ease), transform .15s var(--spring), box-shadow .15s var(--ease);
}
.choice:hover { border-color: rgba(47, 107, 255, .4); background: #FBFCFF; }
.choice:active { transform: scale(.99); }
.choice .key {
  width: 26px; height: 26px; flex: none;
  display: grid; place-items: center;
  border-radius: 50%;
  background: rgba(27, 26, 46, .06);
  font-size: 12.5px; font-weight: 800;
  color: var(--ink-2);
  transition: background .15s var(--ease), color .15s var(--ease);
}
.choice[aria-pressed="true"] { border-color: var(--accent); background: var(--accent-wash); box-shadow: 0 0 0 3px rgba(47, 107, 255, .12); }
.choice[aria-pressed="true"] .key { background: var(--accent); color: #fff; }

.q input[type=text], .q textarea {
  width: 100%;
  padding: 13px 15px;
  border: 1.5px solid var(--line);
  border-radius: var(--r);
  background: #FDFCFA;
  color: var(--ink);
  font-size: 16.5px;
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease), background .15s var(--ease);
}
.q textarea { min-height: 88px; resize: vertical; line-height: 1.5; }
.q input:focus, .q textarea:focus {
  outline: 0;
  background: #fff;
  border-color: var(--accent);
  box-shadow: 0 0 0 4px rgba(47, 107, 255, .14);
}
.q input::placeholder, .q textarea::placeholder { color: var(--ink-3); }

/* Field + microphone. */
.field { position: relative; display: flex; align-items: center; }
.field input, .field textarea { padding-right: 54px; }
.field textarea + .mic { top: 8px; }

.mic {
  position: absolute; right: 8px;
  width: 36px; height: 36px;
  display: grid; place-items: center;
  border: 0; border-radius: 50%;
  background: rgba(27, 26, 46, .05);
  color: var(--ink-2);
  cursor: pointer;
  transition: background .15s var(--ease), color .15s var(--ease), transform .15s var(--spring);
}
.mic svg { width: 16px; height: 16px; fill: currentColor; }
.mic:hover { background: var(--accent-wash); color: var(--accent-dark); }
.mic:active { transform: scale(.9); }
.mic.live { background: var(--no); color: #fff; animation: mic-pulse 1.5s var(--ease) infinite; }

@keyframes mic-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(229, 72, 77, .45); }
  60% { box-shadow: 0 0 0 10px rgba(229, 72, 77, 0); }
}

.q.correct { background: var(--ok-wash); }
.q.correct input, .q.correct textarea { border-color: var(--ok-line); background: #fff; }
.q.wrong { background: var(--no-wash); }
.q.wrong input, .q.wrong textarea { border-color: var(--no-line); background: #fff; }

.q.correct .choice[aria-pressed="true"] { border-color: var(--ok); background: #fff; box-shadow: none; }
.q.correct .choice[aria-pressed="true"] .key { background: var(--ok); }
.q.wrong .choice[aria-pressed="true"] { border-color: var(--no); background: #fff; box-shadow: none; }
.q.wrong .choice[aria-pressed="true"] .key { background: var(--no); }
.choice.is-answer { border-color: var(--ok); }
.choice.is-answer .key { background: var(--ok); color: #fff; }

.q-feedback {
  margin-top: 11px;
  font-size: 15px;
  line-height: 1.5;
  animation: rise .28s var(--ease);
}
@keyframes rise { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }

.verdict { display: flex; align-items: center; gap: 7px; font-weight: 700; }
.verdict.yes { color: var(--ok); }
.verdict.no { color: var(--no); }
.verdict svg { width: 15px; height: 15px; fill: currentColor; }

.q-feedback .given { color: var(--ink-2); }
.q-feedback .given b { color: var(--ink); font-weight: 700; }
.q-feedback .note { display: block; margin-top: 5px; color: var(--ink-3); font-size: 14px; font-style: italic; }
.q-feedback .note.aux { color: var(--ink-2); font-style: normal; }
.q-feedback .model { color: var(--ink-2); }
.q-feedback .model b { display: block; color: var(--ink-3); font-size: 12px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; margin-bottom: 3px; }
.q-feedback .blank-row { color: var(--ink-3); font-weight: 700; }
.q-feedback .blank-row .link-btn { margin-top: 0; }

.link-btn {
  margin-top: 7px;
  border: 0; padding: 0;
  background: none;
  color: var(--accent);
  font: inherit;
  font-size: 14.5px; font-weight: 700;
  cursor: pointer;
}
.link-btn:hover { text-decoration: underline; text-underline-offset: 3px; }
.link-btn.danger { color: var(--no); }

/* --------------------------------------------------------------- buttons */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 46px; padding: 0 24px;
  border: 0; border-radius: 999px;
  background: var(--accent);
  background-image: linear-gradient(180deg, rgba(255, 255, 255, .16), rgba(255, 255, 255, 0));
  color: #fff;
  font: inherit;
  font-size: 15.5px; font-weight: 700;
  letter-spacing: -.005em;
  cursor: pointer;
  box-shadow: 0 6px 18px var(--accent-glow);
  transition: background .15s var(--ease), transform .18s var(--spring), box-shadow .18s var(--ease);
  text-decoration: none;
}
.btn:hover { background-color: var(--accent-dark); transform: translateY(-1px); box-shadow: 0 10px 24px var(--accent-glow); }
.btn:active { transform: scale(.96); }
.btn.ghost {
  background: rgba(27, 26, 46, .06);
  background-image: none;
  color: var(--ink-2);
  box-shadow: none;
}
.btn.ghost:hover { background: rgba(27, 26, 46, .1); color: var(--ink); box-shadow: none; }
.btn:disabled { background: var(--ok-wash); background-image: none; color: var(--ok); cursor: default; box-shadow: none; transform: none; }
.btn.wide { width: 100%; }

.actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; padding: 4px 22px 20px; }

/* A floating pill, lifted clear of the page. */
.checkbar {
  position: sticky;
  bottom: calc(var(--tab-h) + max(16px, var(--tab-safe)));
  z-index: 20;
  display: flex; align-items: center; gap: 10px;
  margin: 22px 0 10px;
  padding: 8px 8px 8px 22px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .8);
  -webkit-backdrop-filter: saturate(180%) blur(24px);
  backdrop-filter: saturate(180%) blur(24px);
  border: 1px solid rgba(27, 26, 46, .07);
  box-shadow: 0 1px 2px rgba(27, 26, 46, .04), 0 12px 36px rgba(27, 26, 46, .16);
}
.checkbar .btn { height: 44px; }
.checkbar .btn.ghost { background: transparent; padding: 0 16px; }
.checkbar .btn.ghost:hover { background: rgba(27, 26, 46, .06); }
.checkbar .score {
  margin-right: auto;
  font-family: var(--display);
  font-size: 17px; font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  color: var(--ink-3);
  transition: color .25s var(--ease);
}
.checkbar .score.scored { color: var(--ink); }
.checkbar .score.good { color: var(--ok); }
.checkbar .bar-xp { margin-right: auto; }
.checkbar .score + .bar-xp { margin-left: 4px; }

/* -------------------------------------------------------------- disclosure */

.fold summary {
  list-style: none;
  cursor: pointer;
  padding: 18px 22px;
  display: flex; align-items: center; gap: 10px;
  font-family: var(--display);
  font-size: 17px; font-weight: 700;
  color: var(--ink-2);
  transition: color .15s var(--ease), background .15s var(--ease);
}
.fold summary::-webkit-details-marker { display: none; }
.fold summary:hover { color: var(--ink); background: var(--surface-2); }
.fold summary .caret {
  width: 11px; height: 11px; fill: var(--ink-3);
  transition: transform .25s var(--spring);
  margin-left: auto;
}
.fold[open] summary .caret { transform: rotate(180deg); }
/* A fold's title with a note beside it: « Page 12 du livre · à ouvrir pour
   répondre », the note quieter than the name. */
.fold summary .fold-title { display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; }
.fold summary .fold-note { font-weight: 500; color: var(--ink-3); }
.fold[open] summary { border-bottom: 1px solid var(--line-soft); color: var(--ink); }

.transcript { padding: 8px 22px 22px; }
.transcript p { margin: 0 0 13px; font-size: 16.5px; line-height: 1.65; color: var(--ink); }
.transcript p:last-child { margin-bottom: 0; }
.transcript .speaker { font-weight: 800; color: var(--u); }
.transcript img { border-radius: var(--r); margin-bottom: 12px; }

/* ------------------------------------------------------- speaking practice */

.transcript-tip {
  margin: 8px 0 14px;
  padding: 10px 14px;
  border-radius: var(--r-sm);
  background: var(--teal-wash);
  color: var(--ink-2);
  font-size: 13.5px !important;
  line-height: 1.45 !important;
}

.line {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 34px;
  align-items: start;
  gap: 8px;
  padding: 2px 0;
  border-radius: var(--r-sm);
}
.line > p { grid-column: 1; }
.line .say-result { grid-column: 1 / -1; }

.say {
  grid-column: 2;
  width: 30px; height: 30px;
  display: grid; place-items: center;
  border: 0; border-radius: 50%;
  background: transparent;
  color: var(--ink-3);
  cursor: pointer;
  opacity: 0;
  transition: opacity .15s var(--ease), background .15s var(--ease), color .15s var(--ease), transform .15s var(--spring);
}
.say svg { width: 14px; height: 14px; fill: currentColor; }
.line:hover .say, .say:focus-visible, .say.live { opacity: 1; }
.say:hover { background: var(--accent-wash); color: var(--accent-dark); }
.say:active { transform: scale(.9); }
.say.live {
  background: var(--no); color: #fff;
  animation: mic-pulse 1.5s var(--ease) infinite;
}

.say-result {
  margin: 6px 0 10px;
  padding: 12px 14px;
  border-radius: var(--r);
  background: var(--surface-2);
  animation: rise .28s var(--ease);
}
.say-score {
  margin: 0 0 8px !important;
  font-size: 14px !important; font-weight: 700;
  color: var(--ink-2);
}
.say-score.good { color: var(--ok); }
.say-words { margin: 0 0 8px !important; font-size: 16px !important; line-height: 1.7 !important; }
.w-ok { color: var(--ok); font-weight: 600; }
.w-miss {
  color: var(--no);
  font-weight: 600;
  text-decoration: underline;
  text-decoration-style: wavy;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
.say-hint {
  margin: 0 !important;
  font-size: 13px !important;
  color: var(--ink-3) !important;
  line-height: 1.45 !important;
}
.say-hint i { color: var(--ink-2); font-style: italic; }

/* Recorder for the book's speaking prompts. */
.recorder { margin-top: 12px; display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
.recorder audio { height: 38px; flex: 1 1 220px; min-width: 180px; }
/* Which microphone the browser picked, once it has: the system default,
   which is the headset when one is plugged in. */
.rec-device {
  flex: 1 1 100%;
  font-size: 12.5px; color: var(--ink-3);
}
.rec-device b { font-weight: 700; color: var(--ink-2); }

.btn.rec { display: inline-flex; align-items: center; gap: 9px; }
.rec-dot {
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--no);
  flex: none;
}
.btn.rec.live { background: var(--no-wash); color: var(--no); }
.btn.rec.live .rec-dot { animation: rec-blink 1.1s steps(2, start) infinite; }
@keyframes rec-blink { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }

.page-wrap { padding: 8px 22px 22px; }
.page-img {
  width: 100%;
  border-radius: var(--r);
  border: 1px solid var(--line);
  cursor: zoom-in;
  transition: transform .25s var(--ease);
}
.page-img.zoomed { cursor: zoom-out; transform: scale(1.9); transform-origin: top center; }

/* ------------------------------------------------------------------ pager */

.pager { display: flex; gap: 12px; margin-top: 22px; }
.pager a {
  flex: 1;
  display: flex; align-items: center; gap: 12px;
  padding: 16px 20px;
  border-radius: var(--r-lg);
  background: var(--surface);
  border: 1px solid var(--line-soft);
  box-shadow: var(--shadow-1);
  transition: transform .2s var(--spring), box-shadow .2s var(--ease), border-color .2s var(--ease);
}
.pager a:hover { transform: translateY(-2px); box-shadow: var(--shadow-2); border-color: color-mix(in srgb, var(--u) 28%, transparent); }
.pager a.next { justify-content: flex-end; text-align: right; }
.pager .dir { font-size: 11.5px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--u); }
.pager .name { font-family: var(--display); font-size: 16.5px; font-weight: 700; letter-spacing: -.01em; margin-top: 2px; }
.pager svg { width: 9px; height: 15px; fill: var(--ink-3); flex: none; }

/* ------------------------------------------------------------ accent keys */

.accent-bar {
  position: fixed;
  left: 0; right: 0; bottom: var(--tab-h);
  z-index: 60;
  padding: 8px max(10px, env(safe-area-inset-left)) calc(8px + var(--tab-safe));
  background: rgba(255, 255, 255, .84);
  -webkit-backdrop-filter: saturate(180%) blur(22px);
  backdrop-filter: saturate(180%) blur(22px);
  border-top: 1px solid var(--line);
  box-shadow: 0 -6px 24px rgba(27, 26, 46, .08);
  animation: slideUp .22s var(--ease);
}
@keyframes slideUp { from { transform: translateY(100%); } to { transform: none; } }

.accent-keys {
  display: flex; gap: 6px;
  overflow-x: auto;
  max-width: 980px; margin: 0 auto;
  scrollbar-width: none;
}
.accent-keys::-webkit-scrollbar { display: none; }
.accent-key {
  flex: 1 0 auto;
  min-width: 42px; height: 42px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: #fff;
  color: var(--ink);
  font-size: 18px;
  cursor: pointer;
  box-shadow: 0 1px 2px rgba(27, 26, 46, .05);
  transition: background .12s var(--ease), transform .12s var(--spring), border-color .12s var(--ease);
}
.accent-key:hover { background: var(--surface-2); border-color: rgba(27, 26, 46, .16); }
.accent-key:active { transform: scale(.9); background: var(--accent-wash); border-color: var(--accent); }
.accent-caps { font-size: 11px; font-weight: 800; letter-spacing: .04em; color: var(--ink-2); }
.accent-caps[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: #fff; }

/* ---------------------------------------------------------------- motion */

@keyframes rise-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
/* `backwards`, not `both`: the end state of every entrance is the element's
   own, and a filled animation would keep overriding the hover lift. */
.stagger > * {
  animation: rise-in .45s var(--ease) backwards;
  animation-delay: calc(min(var(--i, 0), 9) * 40ms);
}

@keyframes head-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
.page-head, .ex-title, .crumbs, .resume-card, .hub-hero { animation: head-in .45s var(--ease) backwards; }
.ex-title { animation-delay: .04s; }
.resume-card { animation-delay: .08s; }

@keyframes wash-in { from { opacity: 0; } to { opacity: 1; } }
.unit-hero, .ex-hero { animation: wash-in .6s var(--ease) backwards; }

@keyframes bar-in { from { transform: translateY(100%); opacity: 0; } to { transform: none; opacity: 1; } }
.checkbar { animation: bar-in .4s var(--ease) backwards; }

@keyframes pop-ok {
  0% { transform: scale(1); }
  45% { transform: scale(1.03); }
  100% { transform: scale(1); }
}
.q.correct { animation: pop-ok .34s var(--spring); }

@keyframes shake {
  0%, 100% { transform: translateX(0); }
  22% { transform: translateX(-5px); }
  46% { transform: translateX(4px); }
  70% { transform: translateX(-2px); }
}
.q.wrong { animation: shake .34s var(--ease); }

/* ------------------------------------------------------------ correction */

.fix { margin-top: 9px; font-size: 14.5px; line-height: 1.55; color: var(--ink-2); }
.fix-line { margin-top: 3px; }
.fix-label {
  display: inline-block; margin-right: 7px;
  font-size: 11.5px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  color: var(--ink-3);
  vertical-align: 1px;
}
.fix s { color: var(--no); text-decoration-color: rgba(229, 72, 77, .55); }
.fix b { color: var(--ink); font-weight: 700; }
.fix .fix-new { color: var(--ok); }
.fix mark.err {
  background: none; color: inherit;
  text-decoration: underline wavy var(--no);
  text-underline-offset: 3px;
}
.fix-notes { margin: 3px 0 0; padding-left: 18px; }
.fix-notes li { margin: 2px 0; }
.fix-notes .why { color: var(--ink-3); }
.fix-quiet { margin-top: 3px; font-size: 14px; font-style: italic; color: var(--ink-3); }

/* ---------------------------------------------------------------- lesson */

.lesson { padding: 10px 28px 26px; }
.lesson-section { margin-top: 28px; }
.lesson-section:first-child { margin-top: 18px; }
.lesson h2 {
  margin: 0 0 10px;
  font-size: 22px; font-weight: 700;
  letter-spacing: -.015em;
  color: var(--u);
}
.lesson p { margin: 8px 0; font-size: 16.5px; line-height: 1.62; }
.lesson ul { margin: 6px 0 8px; padding-left: 22px; }
.lesson li { margin: 6px 0; font-size: 16.5px; line-height: 1.62; }
.lesson li::marker { color: var(--u); }
.lesson b { font-weight: 800; }
.lesson .rule {
  margin: 14px 0; padding: 14px 18px;
  border-radius: var(--r);
  background: var(--u-wash);
  background: linear-gradient(135deg, var(--u-wash), color-mix(in srgb, var(--u-wash) 40%, #fff));
  border: 1px solid color-mix(in srgb, var(--u) 22%, transparent);
  border-left: 4px solid var(--u);
  color: var(--ink);
  font-size: 15.5px; font-weight: 600; line-height: 1.5;
}
.lesson .examples {
  margin: 12px 0; padding: 10px 18px;
  border-left: 3px solid var(--u);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  background: color-mix(in srgb, var(--u) 4%, #fff);
}
.lesson .examples p { margin: 4px 0; font-style: italic; }
.lesson .lesson-note {
  padding: 11px 15px;
  border-radius: var(--r);
  background: var(--sun-wash);
  font-size: 15px;
}
.lesson .table-title {
  margin: 16px 0 4px;
  font-size: 12px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  color: var(--ink-3);
}
.table-wrap { overflow-x: auto; }
.gtable { width: 100%; border-collapse: separate; border-spacing: 0; margin: 4px 0 12px; font-size: 15px; }
.gtable th, .gtable td {
  padding: 9px 12px;
  text-align: left; vertical-align: top;
  border-bottom: 1px solid var(--line-soft);
  line-height: 1.5;
}
.gtable th {
  font-size: 11.5px; font-weight: 800; letter-spacing: .05em; text-transform: uppercase;
  color: var(--u);
  background: var(--u-wash);
  border-bottom: 0;
}
.gtable th:first-child { border-radius: 10px 0 0 10px; }
.gtable th:last-child { border-radius: 0 10px 10px 0; }
.gtable tr:last-child td { border-bottom: 0; }
.gtable td:first-child { font-weight: 600; }
.lesson-credit { margin: 20px 0 0; font-size: 12.5px; color: var(--ink-3); }
.lesson-credit a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.exercises-head {
  margin: 30px 0 -6px;
  font-size: 23px; font-weight: 700; letter-spacing: -.015em;
  color: var(--ink);
}

/* ------------------------------------------------------------ activities */

.hub-h2.tight { margin-top: 8px; }
.path + .notice, .path + .hub-h2 { margin-top: 18px; }
.section-note {
  margin: -4px 0 14px; max-width: 62ch;
  font-size: 14px; line-height: 1.5; color: var(--ink-2);
}

.act-stats {
  display: flex; flex-wrap: wrap; gap: 10px;
  margin: 0 0 18px;
}
.act-stat {
  flex: 1 1 88px;
  display: flex; flex-direction: column; gap: 2px;
  padding: 14px 16px;
  background: var(--surface); border-radius: var(--r);
  border: 1px solid var(--line-soft);
  box-shadow: var(--shadow-1);
}
.act-stat b {
  font-family: var(--display);
  font-size: 26px; font-weight: 800; letter-spacing: -.02em; line-height: 1.1;
  font-variant-numeric: tabular-nums;
  background: var(--grad-brand);
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
}
.act-stat span { font-size: 12.5px; font-weight: 600; color: var(--ink-3); }

.act-weak {
  flex: 1 0 100%;
  padding: 12px 15px;
  background: var(--u-wash); border-radius: var(--r);
  font-size: 14px; color: var(--ink-2);
}
.act-weak b { color: var(--u); font-weight: 700; }

.act-goal {
  margin: 14px 0 0;
  font-size: 13.5px; line-height: 1.5; color: var(--ink-3);
}

/* ----------------------------------------------------------- dictionnaire */

.dict-btn {
  position: fixed; z-index: 60;
  padding: 8px 14px;
  font: inherit; font-size: 13.5px; font-weight: 700; color: #fff;
  background: var(--ink); border: 0; border-radius: 999px;
  box-shadow: 0 2px 6px rgba(27, 26, 46, .2), 0 8px 24px rgba(27, 26, 46, .18);
  cursor: pointer;
}
.dict-btn:hover { background: #000; }

.dict-pop {
  position: fixed; z-index: 61;
  width: min(340px, calc(100vw - 24px));
  padding: 16px 18px 14px;
  background: var(--surface); border-radius: var(--r-lg);
  border: 1px solid var(--line-soft);
  box-shadow: var(--shadow-3);
  animation: pop-in .2s var(--spring);
}
@keyframes pop-in { from { opacity: 0; transform: scale(.94) translateY(4px); } to { opacity: 1; transform: none; } }
.dict-close {
  position: absolute; top: 10px; right: 10px;
  width: 26px; height: 26px; padding: 0;
  font: inherit; font-size: 18px; line-height: 1; color: var(--ink-3);
  background: none; border: 0; border-radius: 50%; cursor: pointer;
}
.dict-close:hover { background: var(--surface-2); color: var(--ink); }

.dict-head { display: flex; align-items: baseline; gap: 8px; padding-right: 22px; }
.dict-word { font-family: var(--display); font-size: 21px; font-weight: 700; letter-spacing: -.01em; }
.dict-gram { font-size: 13px; font-style: italic; color: var(--ink-3); }
.dict-say {
  margin-left: auto; width: 28px; height: 28px; padding: 0; flex: 0 0 auto;
  font: inherit; font-size: 14px; color: var(--accent);
  background: var(--accent-wash); border: 0; border-radius: 50%; cursor: pointer;
  transition: background .15s var(--ease), color .15s var(--ease), transform .15s var(--spring);
}
.dict-say:hover { background: var(--accent); color: #fff; transform: scale(1.08); }

.dict-body { margin-top: 8px; }
.dict-body p { margin: 0 0 6px; font-size: 14.5px; line-height: 1.45; }
.dict-en { font-weight: 600; }
.dict-fr { color: var(--ink-2); }
.dict-ex { font-style: italic; color: var(--ink-2); }
.dict-ctx {
  margin-top: 9px !important; padding: 8px 11px;
  font-size: 13.5px !important; color: var(--ink-2);
  background: var(--surface-2); border-radius: 10px;
}
.dict-quiet { font-size: 13px !important; color: var(--ink-3); }

.dict-foot { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 4px; }
.dict-foot .link-btn { margin: 0; font-size: 13px; }

body.dict-mode #view { -webkit-touch-callout: none; }
::highlight(dict-seen) {
  text-decoration: underline dotted var(--accent) 1.5px;
  text-underline-offset: 3px;
}
.accent-toggle.dict[aria-pressed="true"] {
  background: var(--grad-brand); border-color: transparent; color: #fff;
}
/* The dictionary switch is the translate mark, 20 px in a 44 px pill, the
   width the phone pass gave it. */
.accent-toggle.dict { display: inline-flex; align-items: center; justify-content: center; width: 44px; padding: 0; }
.accent-toggle.dict svg { width: 20px; height: 20px; display: block; fill: currentColor; }

/* --------------------------------------------------------------- mes mots */

.word-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-bottom: 18px; }
.word-bar .btn { margin-left: auto; }

.word-grid {
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fill, minmax(268px, 1fr));
}
.word-card {
  padding: 16px 18px;
  background: var(--surface); border-radius: var(--r-lg);
  border: 1px solid var(--line-soft);
  box-shadow: var(--shadow-1);
  transition: transform .2s var(--spring), box-shadow .2s var(--ease);
}
.word-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-2); }
.word-head { display: flex; align-items: baseline; gap: 8px; }
.word-head b { font-family: var(--display); font-size: 19px; font-weight: 700; }
.word-gram { font-size: 12.5px; font-style: italic; color: var(--ink-3); }
.word-card p { margin: 6px 0 0; font-size: 14px; line-height: 1.45; }
.word-en { font-weight: 600; }
.word-fr, .word-ex { color: var(--ink-2); }
.word-ex { font-style: italic; }
.word-ctx {
  padding: 8px 10px;
  font-size: 13px !important; color: var(--ink-2);
  background: var(--surface-2); border-radius: 10px;
}
.word-ctx em { display: block; margin-top: 3px; font-size: 11.5px; color: var(--ink-3); font-style: normal; }

.word-foot {
  display: flex; align-items: center; flex-wrap: wrap; gap: 10px;
  margin-top: 12px; padding-top: 11px; border-top: 1px solid var(--line-soft);
}
.word-foot .link-btn { margin: 0; font-size: 12.5px; }
.word-status {
  padding: 3px 9px;
  font-size: 11.5px; font-weight: 700; letter-spacing: .01em;
  border-radius: 999px; background: rgba(27, 26, 46, .06); color: var(--ink-2);
}
.word-status.learning { background: var(--u-wash); color: var(--u); }
.word-status.known { background: var(--ok-wash); color: var(--ok); }
.word-tally { font-size: 12px; color: var(--ink-3); font-variant-numeric: tabular-nums; }

.word-exports { margin: 22px 0 0; font-size: 13.5px; color: var(--ink-3); }
.word-exports .link-btn { margin: 0; font-size: 13.5px; }

/* -------------------------------------------------------- liste de mots */

.wordlist-head {
  display: flex; align-items: flex-start; gap: 16px;
  padding: 20px 22px 6px;
}
.wordlist-head > div { flex: 1; min-width: 0; }
.wordlist-head h2 { margin: 0; font-size: 21px; font-weight: 700; letter-spacing: -.015em; }
.wordlist-lead { margin: 4px 0 0; font-size: 14px; line-height: 1.45; color: var(--ink-2); max-width: 56ch; }
.wordlist-head .btn { flex: none; height: 40px; padding: 0 18px; font-size: 14.5px; }
.wordlist-rows {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 4px 12px;
  padding: 10px 12px 16px;
}
.wordrow {
  display: grid; grid-template-columns: 30px 1fr; gap: 10px; align-items: start;
  padding: 10px 10px 10px 8px;
  border-radius: 12px;
  transition: background .15s var(--ease);
}
.wordrow:hover { background: var(--surface-2); }
.wordrow.in { background: color-mix(in srgb, var(--u) 7%, #fff); }
.wordrow .dict-say { margin-top: 3px; width: 28px; height: 28px; }
.wordrow-main { min-width: 0; }
.wordrow b { font-family: var(--display); font-size: 17.5px; font-weight: 700; letter-spacing: -.01em; }
.wordrow b .word-gram { font-family: var(--sans); font-size: 12.5px; font-weight: 500; }
.wordrow-en { display: block; font-size: 14px; color: var(--ink-2); }
.wordrow-ex { display: block; margin-top: 3px; font-size: 13.5px; line-height: 1.4; color: var(--ink-3); font-style: italic; }
.wordrow-ex b { font-family: var(--sans); font-size: inherit; font-weight: 700; color: var(--ink-2); }

.level-chip {
  display: inline-grid; place-items: center; vertical-align: 3px;
  min-width: 34px; height: 26px; padding: 0 9px; margin-right: 10px;
  border-radius: 8px;
  background: var(--u); color: #fff;
  font-size: 12.5px; font-weight: 800; letter-spacing: .03em;
}

@media (max-width: 620px) {
  .wordlist-head { flex-direction: column; }
  .wordlist-rows { grid-template-columns: 1fr; }
}

/* ------------------------------------------------------- niveaux (leçons) */

.level-tabs { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; }
.path + .level-tabs { margin-top: 22px; }
.level-tab {
  display: inline-flex; align-items: center;
  height: 34px; padding: 0 13px;
  border: 1px solid var(--line); border-radius: 999px;
  background: #fff; color: var(--ink-2);
  font: inherit; font-size: 13.5px; font-weight: 700;
  cursor: pointer;
  transition: background .15s var(--ease), color .15s var(--ease), border-color .15s var(--ease), transform .15s var(--spring);
}
.level-tab:hover { border-color: color-mix(in srgb, var(--u) 40%, transparent); color: var(--ink); }
.level-tab:active { transform: scale(.96); }
.level-tab[aria-pressed="true"] { background: var(--u); border-color: var(--u); color: #fff; }
.level-tab .n { margin-left: 7px; font-size: 12px; font-weight: 700; opacity: .65; }

.hub-h2.level { display: flex; align-items: center; gap: 10px; margin-top: 34px; }
.level-list > .hub-h2.level:first-child { margin-top: 20px; }
.hub-h2.level .level-chip { margin-right: 0; }
.lvl-tally { margin-left: auto; font-family: var(--sans); font-size: 13px; font-weight: 600; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.hub-h2.level + .sub-h3 { margin-top: 8px; }
.sub-h3 {
  margin: 22px 0 8px;
  font-family: var(--sans);
  font-size: 12px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink-3);
}
.path.two { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 12px; }
.path.two .step { grid-template-columns: 76px 1fr auto; gap: 12px; padding: 10px 14px 10px 10px; }
.path.two .step-mark { width: 76px; height: 54px; font-size: 20px; }
.path.two .step-mark.lvl { font-size: 13px; }
.path.two .step-body h3 { font-size: 16.5px; }
.path.two .step-body .meta { font-size: 13px; }
@media (max-width: 900px) { .path.two { grid-template-columns: 1fr; } }

/* ---------------------------------------------------------------- réviser */

.card.review { padding: 30px 28px; text-align: center; }
.review-count { margin: 0; font-size: 12.5px; font-weight: 700; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.review-prompt { margin: 18px 0 22px; }
.review-dir {
  display: inline-block;
  margin: 0 0 12px; padding: 4px 11px;
  border-radius: 999px;
  background: var(--u-wash); color: var(--u);
  font-size: 11.5px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
}
.review-prompt h2 { margin: 0; font-size: 34px; font-weight: 800; letter-spacing: -.02em; }
.review-gram { margin: 6px 0 0; font-size: 13px; font-style: italic; color: var(--ink-3); }
.card.review input[type=text] { text-align: center; font-size: 18px; }
.card.review .q-feedback { margin-top: 16px; text-align: left; }
.review-bar { display: flex; justify-content: center; gap: 10px; margin-top: 18px; }
.review-done h2 { margin: 0 0 8px; font-size: 28px; font-weight: 800; }
.review-done p { margin: 0 0 10px; color: var(--ink-2); }
.review-done .btn { margin-top: 8px; }

/* ---------------------------------------------------------------- compte */

.gate { padding-top: 8vh; }
.gate-card { padding: 32px 30px 28px; }
.gate-card h1 { margin: 0 0 8px; font-size: 30px; font-weight: 800; letter-spacing: -.02em; }
.gate-lead { margin: 0 0 22px; color: var(--ink-2); font-size: 15px; line-height: 1.5; }
.gate-form { display: flex; flex-direction: column; gap: 14px; }
.gate-form label,
.field-label {
  display: flex; flex-direction: column; gap: 6px;
  font-size: 13px; font-weight: 700; color: var(--ink-2);
}
.gate-wait { padding: 90px 0; text-align: center; color: var(--ink-3); font-size: 22px; }
.gate-form input, .field-label input, .field-label select, .field-label textarea, .card.review input[type=text] {
  width: 100%; padding: 12px 14px;
  font: inherit; font-size: 15.5px; color: var(--ink);
  background: #FDFCFA;
  border: 1.5px solid var(--line); border-radius: 13px;
  transition: border-color .15s var(--ease), background .15s var(--ease), box-shadow .15s var(--ease);
}
.gate-form input:focus, .field-label input:focus, .field-label select:focus,
.card.review input[type=text]:focus {
  outline: none; background: #fff;
  border-color: var(--accent); box-shadow: 0 0 0 4px rgba(47, 107, 255, .14);
}
.gate-form input::placeholder, .field-label input::placeholder { color: var(--ink-3); }
.gate-form .btn { align-self: flex-start; margin-top: 4px; }
.gate-problem {
  margin: 0; padding: 10px 13px;
  font-size: 13.5px; color: var(--no);
  background: var(--no-wash); border-radius: 11px;
}
.gate-note { margin: 18px 0 0; font-size: 13.5px; line-height: 1.5; color: var(--ink-3); }
.gate-note .link-btn { margin: 0; font-size: inherit; }

.account-chip {
  display: inline-flex; align-items: center; gap: 7px;
  height: 36px; padding: 0 12px 0 5px;
  font-size: 13.5px; font-weight: 700; color: var(--ink);
  background: #fff; border: 1px solid var(--line); border-radius: 999px; text-decoration: none;
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
}
.account-chip:hover { border-color: rgba(27, 26, 46, .18); box-shadow: var(--shadow-1); }
.chip-name { max-width: 9ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.avatar {
  display: inline-flex; align-items: center; justify-content: center;
  flex: 0 0 auto; border-radius: 50%; object-fit: cover;
  color: #fff; font-weight: 700; letter-spacing: .02em; line-height: 1;
}

/* --------------------------------------------------------------- profil */

.profile { padding: 24px 26px 22px; }
.profile h2 {
  margin: 26px 0 12px;
  font-family: var(--sans);
  font-size: 12.5px; font-weight: 800;
  letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3);
}
.profile-row { display: flex; gap: 20px; align-items: flex-start; }
.profile-avatar { flex: 0 0 auto; }
.profile-photo-tools { flex: 1 1 auto; min-width: 0; }
.profile-photo-btns { display: flex; align-items: center; gap: 10px; }
.profile-hint { margin: 12px 0 8px; font-size: 12.5px; color: var(--ink-3); }
.swatches { display: flex; flex-wrap: wrap; gap: 8px; }
.swatch { width: 26px; height: 26px; padding: 0; border: 0; border-radius: 50%; cursor: pointer; transition: transform .15s var(--spring); }
.swatch:hover { outline: 2px solid var(--ink-3); outline-offset: 2px; transform: scale(1.1); }

.profile input[type=text], .profile input[type=number], .profile select { max-width: 100%; }
.profile-goal { display: flex; flex-wrap: wrap; gap: 14px; }
.profile-goal .field-label { flex: 0 0 150px; }
.profile-goal .field-label.wide { flex: 1 1 260px; }
.profile-foot {
  display: flex; align-items: center; flex-wrap: wrap; gap: 14px;
  margin-top: 26px; padding-top: 18px; border-top: 1px solid var(--line-soft);
}
.profile-said { font-size: 13.5px; font-weight: 600; color: var(--ok); }
.field-with { display: flex; gap: 8px; align-items: center; }
.field-with input { flex: 1 1 auto; }

/* --------------------------------------------------------- cette semaine */

.week-card {
  margin: 22px 0 8px; padding: 18px 20px;
  background: var(--surface); border-radius: var(--r-lg);
  border: 1px solid var(--line-soft);
  box-shadow: var(--shadow-1);
}
.week-card.quiet { color: var(--ink-3); font-size: 14px; }
.week-card.quiet p { margin: 0; }
.week-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.week-title {
  font-size: 11.5px; font-weight: 800; letter-spacing: .08em;
  text-transform: uppercase; color: var(--ink-3);
}
.week-head b { font-family: var(--display); font-size: 21px; font-weight: 700; font-variant-numeric: tabular-nums; }
.week-goal { font-size: 13.5px; color: var(--ink-3); }
.week-bars { display: flex; align-items: flex-end; gap: 6px; height: 48px; margin-top: 12px; }
.week-bar { flex: 1 1 0; height: 100%; display: flex; align-items: flex-end; }
.week-bar i {
  display: block; width: 100%; min-height: 4px;
  background: rgba(27, 26, 46, .08); border-radius: 5px;
  transition: height .5s var(--ease);
}
.week-bar i.on { background: var(--grad-brand); }
.week-card.reached .week-bar i.on { background: var(--ok); }
.week-foot { margin: 10px 0 0; font-size: 13px; color: var(--ink-3); }

/* -------------------------------------------------------- tableau de bord */

.dash-wait { padding: 40px 0; text-align: center; color: var(--ink-3); }
.dash-tabs { margin: -6px 0 22px; }
.dash-classes { margin: -8px 0 18px; }
.dash-tabs + .dash-classes { margin-top: -10px; }
.crumbs + .gate-card { margin-top: 18px; }

.dash-table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 14px; background: #fff; border-radius: var(--r); border: 1px solid var(--line-soft); overflow: hidden; }
.dash-table th {
  padding: 10px 14px; text-align: left; white-space: nowrap;
  font-size: 11.5px; font-weight: 800; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-3);
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
}
.dash-table td { padding: 12px 14px; border-bottom: 1px solid var(--line-soft); vertical-align: middle; }
.dash-table tr:last-child td { border-bottom: 0; }
.dash-table tbody tr { cursor: pointer; transition: background .12s var(--ease); }
.dash-table tbody tr:hover { background: var(--accent-wash); }
.dash-table td.dim { color: var(--ink-3); }
.dash-table td.met { color: var(--ok); font-weight: 700; }
.dash-who { display: flex; align-items: center; gap: 10px; }
.dash-username { display: block; font-size: 12px; color: var(--ink-3); }
.dash-flags { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 4px; }
.flag {
  padding: 2px 8px; font-size: 11px; font-weight: 700;
  border-radius: 999px; background: rgba(27, 26, 46, .06); color: var(--ink-2);
}
.flag.low { background: var(--no-wash); color: var(--no); }
.flag.quiet { background: var(--sun-wash); color: #A06A00; }
.goal-bar { height: 4px; margin-top: 5px; background: rgba(27, 26, 46, .08); border-radius: 2px; }
.goal-bar i { display: block; height: 100%; background: var(--u); border-radius: 2px; }
.row-tools { white-space: nowrap; text-align: right; }
.row-tools .link-btn { margin: 0 0 0 12px; font-size: 12.5px; }

/* The class an account is in, set on its own row: a box the size of the text
   it replaces, with the word that says it was saved beside it. */
.dash-class { display: flex; align-items: center; gap: 8px; }
.dash-class select {
  padding: 6px 9px;
  font: inherit; font-size: 13.5px; color: var(--ink);
  background: #FDFCFA;
  border: 1.5px solid var(--line); border-radius: 10px;
}
.dash-class .profile-said.failed { color: var(--no); }

.student-head { display: flex; align-items: center; gap: 16px; margin: 14px 0 22px; }
.student-head h1 { margin: 0; font-size: 30px; font-weight: 800; letter-spacing: -.02em; }
.student-goal { margin: 6px 0 0; font-style: italic; color: var(--ink-2); }

.day-bars { display: flex; align-items: flex-end; gap: 3px; height: 72px; margin-bottom: 8px; padding: 12px 14px 10px; background: #fff; border-radius: var(--r); border: 1px solid var(--line-soft); }
.day-bar { flex: 1 1 0; height: 100%; display: flex; align-items: flex-end; }
.day-bar i { display: block; width: 100%; background: rgba(27, 26, 46, .08); border-radius: 3px; }
.day-bar.on i { background: var(--grad-brand); }

.wrong-list { display: grid; gap: 10px; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); }
.wrong-row { padding: 13px 15px; background: var(--surface); border-radius: var(--r); border: 1px solid var(--line-soft); box-shadow: var(--shadow-1); }
.wrong-row p { margin: 0 0 5px; font-size: 14px; line-height: 1.4; }
.wrong-where { font-size: 11.5px !important; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.wrong-prompt { color: var(--ink-2); }
.wrong-pair span { font-size: 12px; color: var(--ink-3); }
.wrong-pair s { color: var(--no); }
.wrong-pair b { color: var(--ok); }

.admin-form { display: flex; flex-wrap: wrap; gap: 14px; align-items: flex-end; padding: 0 22px 22px; }
.card > h2 + .admin-form { padding-top: 14px; }
.admin-form .field-label { flex: 1 1 170px; }
.admin-form .field-label.wide { flex: 1 1 100%; }
.admin-form textarea { resize: vertical; min-height: 120px; line-height: 1.5; }
.admin-form .gate-problem { flex: 1 1 100%; }
.card > h2 ~ p { margin-left: 22px; margin-right: 22px; }
.card > h2 ~ .handover { margin: 0 22px 18px; }
.card > .btn { margin: 0 22px 22px; }
.handover {
  margin-top: 12px; padding: 14px 16px;
  background: var(--sun-wash); border-radius: var(--r);
  font-size: 15px; line-height: 1.6;
}
.handover p { margin: 0; }
.handover b { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 15px; }
.handover.inline { display: inline-block; margin: 0; padding: 3px 9px; font-size: 13px; }

/* ------------------------------------------------------------- gradients */

/* Warm-to-cool washes with a grain over them, for the surfaces that are about
   a person or a number: the profile, and the stat cards. */
:root {
  --grad-0: linear-gradient(160deg, #FFE4C4 0%, #FFC8AE 46%, #F3B49A 100%);
  --grad-1: linear-gradient(160deg, #FFC8E0 0%, #B9AFDD 52%, #678EC9 100%);
  --grad-2: linear-gradient(160deg, #D2E8FF 0%, #A8C8F5 48%, #6EBFE4 100%);
  --grad-3: linear-gradient(160deg, #F9ECBA 0%, #F5D198 50%, #E3B482 100%);
  --grad-4: linear-gradient(160deg, #E1AA7B 0%, #F1DCBE 48%, #A8D4CC 100%);
  --grad-5: linear-gradient(160deg, #F0B246 0%, #F4F0A7 50%, #BFC9E4 100%);
  --grad-6: linear-gradient(160deg, #E8CBA2 0%, #FFB89A 50%, #C9A0C0 100%);
  --grad-7: linear-gradient(160deg, #CFE3F7 0%, #9FC0E8 50%, #7D92CB 100%);
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='.42'/%3E%3C/svg%3E");
}

.wash {
  position: relative; overflow: hidden;
  border-radius: var(--r-xl);
  background: var(--grad-0);
}
.wash::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background-image: var(--grain);
  opacity: .5; mix-blend-mode: soft-light;
}
.wash > * { position: relative; z-index: 1; }
.wash.g0 { background: var(--grad-0); } .wash.g1 { background: var(--grad-1); }
.wash.g2 { background: var(--grad-2); } .wash.g3 { background: var(--grad-3); }
.wash.g4 { background: var(--grad-4); } .wash.g5 { background: var(--grad-5); }
.wash.g6 { background: var(--grad-6); } .wash.g7 { background: var(--grad-7); }

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

.hero-card { padding: 32px 24px 24px; text-align: center; margin: 24px 0 18px; }
.hero-avatar { position: relative; display: inline-block; }
.hero-avatar .avatar {
  border: 4px solid rgba(255, 255, 255, .85);
  box-shadow: 0 8px 24px rgba(0, 0, 0, .12);
}
.hero-dot {
  position: absolute; right: 4px; bottom: 4px;
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--ink-3); border: 3px solid #fff;
}
.hero-dot.live { background: #30C158; }
.hero-card h1 {
  margin: 14px 0 2px; font-size: 30px; font-weight: 800;
  letter-spacing: -.02em; color: #1B1B1F;
}
.hero-sub { margin: 0; font-size: 14px; font-weight: 500; color: rgba(27, 27, 31, .6); }

.pill-actions {
  display: flex; justify-content: center; flex-wrap: wrap;
  gap: 10px; margin-top: 22px;
}
.pill-action {
  display: flex; flex-direction: column; align-items: center; gap: 7px;
  width: 76px; padding: 0; border: 0; background: none; cursor: pointer;
  font: inherit; color: #1B1B1F; text-decoration: none;
}
.pill-action i {
  display: flex; align-items: center; justify-content: center;
  width: 56px; height: 56px; border-radius: 20px;
  background: rgba(255, 255, 255, .76);
  box-shadow: 0 1px 2px rgba(0, 0, 0, .05), 0 6px 16px rgba(0, 0, 0, .06);
  transition: transform .18s var(--spring), background .16s var(--ease);
}
.pill-action i svg {
  width: 23px; height: 23px;
  fill: none; stroke: #1B1B1F; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round;
}
.pill-action:hover i { background: #fff; transform: translateY(-3px); }
.pill-action:active i { transform: scale(.94); }
.pill-action span { font-size: 12.5px; font-weight: 600; letter-spacing: -.01em; }

.hero-note {
  margin-top: 20px; padding: 14px 16px; text-align: left;
  background: rgba(255, 255, 255, .74); border-radius: 18px;
}
.hero-note b {
  display: block; margin-bottom: 3px;
  font-size: 11px; font-weight: 800; letter-spacing: .07em;
  text-transform: lowercase; color: rgba(27, 27, 31, .45);
}
.hero-note p { margin: 0; font-size: 16px; line-height: 1.4; color: #1B1B1F; }
.hero-note p.empty { color: rgba(27, 27, 31, .4); }

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

.data-card { padding: 22px 24px 20px; margin-bottom: 18px; }
.data-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.data-head .who { display: flex; align-items: center; gap: 9px; font-size: 14px; font-weight: 700; color: #1B1B1F; }
.data-date { margin: 6px 0 0; font-family: var(--display); font-size: 20px; font-weight: 700; letter-spacing: -.02em; color: #1B1B1F; }

.data-body {
  display: flex; align-items: center; justify-content: space-between; gap: 18px;
  margin-top: 16px; padding: 18px 20px;
  background: rgba(255, 255, 255, .68); border-radius: 22px;
}
.data-label { margin: 0 0 4px; font-size: 12.5px; color: rgba(27, 27, 31, .5); }
.data-big {
  margin: 0; font-family: var(--display); font-size: 40px; font-weight: 800; letter-spacing: -.03em;
  color: #1B1B1F; font-variant-numeric: tabular-nums; line-height: 1;
}
.data-delta {
  display: inline-flex; align-items: center; gap: 5px; margin-top: 9px;
  padding: 4px 10px; border-radius: 999px;
  background: #fff; font-size: 12.5px; font-weight: 700; color: var(--ok);
}
.data-delta.down { color: var(--no); }
.data-aside { margin: 9px 0 0; font-size: 12.5px; color: rgba(27, 27, 31, .5); }

.donut { flex: 0 0 auto; position: relative; width: 106px; height: 106px; }
.donut svg { width: 100%; height: 100%; transform: rotate(-90deg); }
.donut circle { fill: none; stroke-width: 11; stroke-linecap: round; }
.donut .track { stroke: rgba(27, 27, 31, .09); }
.donut .fill { stroke: url(#donutStroke); transition: stroke-dashoffset .5s var(--ease); }
.donut-mid {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
}
.donut-mid b { font-family: var(--display); font-size: 22px; font-weight: 800; letter-spacing: -.02em; color: #1B1B1F; }
.donut-mid span { font-size: 10.5px; color: rgba(27, 27, 31, .5); }

.tile-row { display: flex; gap: 10px; margin-top: 12px; overflow-x: auto; padding-bottom: 2px; }
.tile {
  flex: 1 0 132px; display: flex; align-items: center; gap: 11px;
  padding: 13px 15px; border-radius: 20px;
  background: rgba(255, 255, 255, .68);
}
.tile i {
  display: flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; flex: 0 0 auto; border-radius: 12px;
  background: rgba(255, 255, 255, .9);
}
.tile i svg { width: 16px; height: 16px; fill: #1B1B1F; }
.tile b { display: block; font-size: 15px; font-weight: 700; color: #1B1B1F; letter-spacing: -.01em; }
.tile span { font-size: 12px; color: rgba(27, 27, 31, .5); }

/* ------------------------------------------------------------ responsive */

@media (max-width: 860px) {
  .hub-hero { padding: 30px 28px; }
  .hub-hero-bird { width: 160px; height: 160px; }
}

@media (max-width: 760px) {
  .ex-head { grid-template-columns: 1fr; gap: 0; }
  .ex-head .ex-title { padding-bottom: 14px; order: 1; }
  .ex-photo { width: 100%; height: 180px; order: 2; margin-bottom: 20px; transform: none; }
}

@media (max-width: 640px) {
  body { font-size: 16px; }
  :root { --bar-h: 58px; }
  .topbar { gap: 8px; padding-left: 14px; padding-right: 14px; }
  .brand-mark { width: 30px; height: 30px; }
  .brand-text b { font-size: 18px; }
  .progress-chip { padding-right: 10px; }
  .wrap { padding-left: 18px; padding-right: 18px; }

  /* The bird moves to the corner so the greeting and the line under it keep
     the full width; only the title has to stay clear of it. */
  .hub-hero { display: block; padding: 26px 22px 26px; }
  .hub-hero-bird {
    position: absolute; right: 12px; top: 10px; z-index: 0;
    width: 104px; height: 104px;
  }
  .hub-hero .kicker, .hub-hero h1 { max-width: calc(100% - 100px); }
  .hub-hero .sub { font-size: 15.5px; margin-top: 12px; }
  .resume-card { padding: 18px 20px; }
  .resume-title { font-size: 19px; }

  .checkbar { padding-left: 16px; gap: 4px; }
  .checkbar .btn { height: 42px; padding: 0 17px; font-size: 15px; }
  .checkbar .btn.ghost { padding: 0 11px; }
  .checkbar .score { font-size: 15px; }
  .page-head { padding: 20px 0 16px; }
  .step { grid-template-columns: 78px 1fr auto; gap: 12px; padding: 10px 14px 10px 10px; }
  .step-mark { width: 78px; height: 56px; font-size: 20px; }
  .step-mark.lvl { font-size: 13px; }
  .step-body h3 { font-size: 16.5px; }
  .card-body, .player, .stage-head, .q, .actions, .transcript, .page-wrap, .fold summary, .lesson, .kbd-tip, .admin-form { padding-left: 16px; padding-right: 16px; }
  .card > h2 { padding-left: 16px; padding-right: 16px; }
  .transport { grid-template-columns: 1fr; gap: 14px; }
  .transport .mid { grid-column: 1; justify-content: center; }
  .transport .right { grid-column: 1; justify-self: center; }
  .wave { height: 56px; }
  .stage-hint { margin-left: 0; }
  .pager { flex-direction: column; }
  .unit-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  .unit-card { min-height: 168px; padding: 16px 16px 14px; }
  .unit-card h3 { font-size: 18.5px; }
}

@media (max-width: 900px) {
  .topnav { display: none; }
}

@media (max-width: 480px) {
  .brand-text small { display: none; }
  .brand-text b { font-size: 17px; }
  .crumb.here, .crumb-sep:has(+ .crumb.here) { display: none; }
  .accent-toggle { padding: 0 9px; }
  .topbar { gap: 6px; }
  .accent-toggle, .progress-chip, .streak-chip, .account-chip { white-space: nowrap; }
}

@media (max-width: 420px) {
  .unit-grid { grid-template-columns: 1fr; }
}

@media (max-width: 620px) {
  .act-stat { flex-basis: calc(50% - 5px); }
  .q-gloss { flex-basis: 100%; margin: 4px 0 0; padding-left: 0; }
  .word-grid { grid-template-columns: 1fr; }
  .word-bar .btn { margin-left: 0; width: 100%; }
  .review-prompt h2 { font-size: 27px; }
  .profile-row { flex-direction: column; }
  .dash-table { font-size: 13px; }
  .dash-table th:nth-child(4), .dash-table td:nth-child(4),
  .dash-table th:nth-child(7), .dash-table td:nth-child(7) { display: none; }
  .wrong-list { grid-template-columns: 1fr; }
  .hero-card { padding: 24px 16px 20px; }
  .pill-action { width: 68px; }
  .pill-action i { width: 50px; height: 50px; border-radius: 17px; }
  .data-body { flex-direction: column; align-items: flex-start; }
  .donut { align-self: center; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
  html { scroll-behavior: auto; }
  .hub-hero-bird { animation: none; }
}

/* --------------------------------------------------------------- parcours */

/* The lesson as a path: a bar along the top that fills a step at a time,
   one card, and the pill at the foot that is the one button. */
.pc { padding-top: 10px; }
.pc-top {
  position: sticky;
  top: calc(var(--bar-h) + 10px);
  z-index: 21;
  display: flex; align-items: center; gap: 10px;
  margin: 0 0 16px;
  padding: 8px 12px 8px 8px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .82);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  backdrop-filter: saturate(180%) blur(20px);
  border: 1px solid rgba(27, 26, 46, .07);
  box-shadow: 0 1px 2px rgba(27, 26, 46, .04), 0 10px 30px rgba(27, 26, 46, .10);
  animation: head-in .45s var(--ease) backwards;
}
.pc-exit {
  width: 34px; height: 34px; flex: none;
  display: grid; place-items: center;
  border-radius: 50%;
  background: rgba(27, 26, 46, .06);
  color: var(--ink-2);
  transition: background .15s var(--ease), transform .15s var(--spring);
}
.pc-exit:hover { background: rgba(27, 26, 46, .1); color: var(--ink); }
.pc-exit:active { transform: scale(.92); }
.pc-exit svg { width: 13px; height: 13px; fill: currentColor; }

.pc-segs { flex: 1; display: flex; gap: 4px; min-width: 0; }
.pc-seg {
  position: relative; flex: 1;
  height: 9px; padding: 0; border: 0; border-radius: 999px;
  background: rgba(27, 26, 46, .08);
  overflow: hidden;
  cursor: default;
  transition: transform .15s var(--spring);
}
.pc-seg:not(:disabled) { cursor: pointer; }
.pc-seg:not(:disabled):hover { transform: scaleY(1.5); }
.pc-seg.ahead::before { opacity: .45; }
.pc-seg::before {
  content: '';
  position: absolute; inset: 0;
  width: calc(var(--fill, 0) * 100%);
  border-radius: inherit;
  background: var(--u);
  transition: width .5s var(--ease);
}
.pc-seg.practice::before { background: var(--grad-brand); }
.pc-seg.now { box-shadow: 0 0 0 2px color-mix(in srgb, var(--u) 35%, transparent); }

.pc-count {
  flex: none;
  min-width: 3.4em; text-align: center;
  font-family: var(--display);
  font-size: 14px; font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--ink-3);
}
.pc-combo, .pc-xp {
  flex: none;
  display: inline-flex; align-items: center; gap: 5px;
  height: 32px; padding: 0 11px;
  border-radius: 999px;
  font-family: var(--display);
  font-size: 14px; font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.pc-combo { background: var(--coral-wash); color: #D8452F; animation: pop-in .3s var(--spring); }
.pc-combo svg { width: 14px; height: 14px; fill: currentColor; }
.pc-combo.hot { background: var(--grad-warm); color: #fff; box-shadow: 0 6px 16px rgba(255, 107, 92, .35); animation: pc-hot 1.2s var(--ease) infinite; }
@keyframes pc-hot { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.06); } }
.pc-xp { position: relative; background: var(--sun-wash); color: #8A5A00; }
.pc-xp i { font-style: normal; color: #E39B00; }
.pc-xp.bump { animation: pc-bump .45s var(--spring); }
@keyframes pc-bump { 0% { transform: scale(1); } 40% { transform: scale(1.14); } 100% { transform: scale(1); } }
.pc-float {
  position: absolute; left: 50%; top: -4px;
  transform: translateX(-50%);
  padding: 2px 8px; border-radius: 999px;
  background: var(--sun); color: #3D2A00;
  font-size: 12.5px; font-weight: 800;
  white-space: nowrap;
  pointer-events: none;
  animation: pc-float 1.1s var(--ease) forwards;
}
@keyframes pc-float {
  0% { opacity: 0; transform: translate(-50%, 6px) scale(.8); }
  20% { opacity: 1; transform: translate(-50%, -14px) scale(1.05); }
  100% { opacity: 0; transform: translate(-50%, -40px) scale(1); }
}

/* One card. Each step slides in; the sheet's own pieces, rule, examples,
   table, note, keep their look from .lesson. */
.pc-card { min-height: 300px; margin-bottom: 0; }
.pc-card.flip > .pc-step { animation: pc-step-in .38s var(--ease) backwards; }
@keyframes pc-step-in { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
.pc-step, .pc-step.lesson { padding: 24px 30px 30px; }
.pc-step h2 { margin: 6px 0 10px; font-size: 26px; font-weight: 800; letter-spacing: -.02em; line-height: 1.15; color: var(--ink); }
.pc-step.lesson h2 { color: var(--u); }
.pc-kicker {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  margin: 0 0 4px;
  font-size: 12px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink-3);
}
.pc-kind {
  display: inline-flex; align-items: center;
  height: 24px; padding: 0 10px;
  border-radius: 999px;
  background: var(--u-wash); color: var(--u);
  letter-spacing: .06em;
}
.pc-counter { text-transform: none; letter-spacing: 0; font-size: 13px; font-weight: 600; }
.pc-counter b { color: var(--u); font-weight: 800; }
.pc-again { display: inline-flex; align-items: center; height: 22px; padding: 0 9px; border-radius: 999px; background: var(--sun-wash); color: #8A5A00; letter-spacing: .04em; font-size: 11px; }
.pc-pips { display: inline-flex; gap: 5px; margin-left: 2px; }
.pc-pips i { width: 7px; height: 7px; border-radius: 50%; background: rgba(27, 26, 46, .14); }
.pc-pips i.past { background: color-mix(in srgb, var(--u) 45%, #fff); }
.pc-pips i.on { background: var(--u); }
.pc-hint { margin: -2px 0 12px; font-size: 15px; color: var(--ink-2); }

/* Hear an example. */
.ex-hear, .pc-hear {
  display: inline-grid; place-items: center;
  width: 28px; height: 28px; flex: none;
  border: 0; border-radius: 50%;
  background: var(--u-wash); color: var(--u);
  cursor: pointer;
  transition: background .15s var(--ease), transform .15s var(--spring);
}
.ex-hear svg, .pc-hear svg { width: 14px; height: 14px; fill: currentColor; }
.ex-hear:hover, .pc-hear:hover { background: var(--u); color: #fff; }
.ex-hear:active, .pc-hear:active { transform: scale(.9); }
.lesson .examples p.with-hear { display: flex; align-items: flex-start; gap: 9px; }
.lesson .examples p.with-hear .ex-hear { margin-top: 0; }

/* The question, alone on the card: its number is in the kicker, the field
   is wide, the options are big enough to press. */
.pc-practice .q { padding: 10px 0 0; }
.pc-practice .q-num { display: none; }
.pc-practice .q-text { font-size: 21px; font-weight: 600; line-height: 1.4; letter-spacing: -.01em; }
.pc-practice .q-prompt { margin-bottom: 16px; }
.pc-practice .q input[type=text] { font-size: 18px; padding: 15px 17px; }
.pc-practice .q textarea { font-size: 17px; }
.pc-practice .choice { min-height: 54px; font-size: 17px; padding: 12px 16px; }
.pc-practice .choice:disabled { cursor: default; }
.pc-practice .choices.inline .choice { min-width: 140px; }
.pc-practice .q.correct, .pc-practice .q.wrong { background: transparent; }
.pc-model { margin-top: 16px; padding: 12px 16px; border-radius: var(--r); background: var(--surface-2); font-size: 15px; color: var(--ink-2); }
.pc-model b { display: block; margin-bottom: 3px; font-size: 11.5px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3); }

/* The pill at the foot: neutral while a question waits, green or rose once
   it is marked, with the verdict inside it. */
.pc-foot { justify-content: flex-end; margin-top: 16px; padding-left: 18px; transition: background .25s var(--ease), border-color .25s var(--ease); }
.pc-foot .pc-foot-text { margin-right: auto; font-size: 13.5px; color: var(--ink-3); }
.pc-foot.nudge { animation: shake .34s var(--ease); }
.pc-foot.nudge .pc-foot-text { color: var(--no); font-weight: 700; }
.pc-foot.ok { background: rgba(227, 248, 238, .94); border-color: var(--ok-line); }
.pc-foot.no { background: rgba(255, 233, 234, .94); border-color: var(--no-line); }
.pc-foot.ok, .pc-foot.no, .pc-foot.done { border-radius: 26px; }
.pc-foot .btn svg.chev { width: 8px; height: 13px; fill: currentColor; opacity: .9; }
.pc-back { padding: 0 14px 0 10px; }
.pc-back svg { width: 8px; height: 13px; fill: currentColor; }
.pc-back:disabled { opacity: .35; background: transparent; color: var(--ink-3); }

.pc-verdict { display: flex; align-items: flex-start; gap: 11px; margin-right: auto; min-width: 0; padding: 4px 0; }
.pc-verdict > svg { width: 26px; height: 26px; flex: none; padding: 6px; border-radius: 50%; fill: #fff; margin-top: 1px; }
.pc-verdict.yes > svg { background: var(--ok); }
.pc-verdict.no > svg { background: var(--no); }
.pc-verdict-text { display: flex; flex-direction: column; gap: 2px; font-size: 14.5px; line-height: 1.4; min-width: 0; }
.pc-verdict-text > b { font-size: 16px; font-weight: 800; }
.pc-verdict.yes > .pc-verdict-text > b { color: #0F7A4C; }
.pc-verdict.no > .pc-verdict-text > b { color: #C13A3F; }
.pc-right { color: var(--ink-2); }
.pc-right b { color: var(--ink); font-weight: 800; }
.pc-fix { color: var(--ink-2); font-size: 13.5px; }
.pc-fix b { color: var(--ink); }
.pc-note { color: var(--ink-2); font-size: 13.5px; }
.pc-note.soft { color: var(--ink-3); font-style: italic; }
.pc-verdict .link-btn { margin-top: 3px; align-self: flex-start; }
.pc-earned {
  flex: none; align-self: center;
  display: inline-flex; align-items: center; gap: 4px;
  height: 32px; padding: 0 12px;
  border-radius: 999px;
  background: var(--sun-wash); color: #8A5A00;
  font-family: var(--display); font-size: 15px; font-weight: 800;
  animation: pop-in .35s var(--spring);
}
.pc-earned em { font-style: normal; color: #D8452F; }

/* Stars. */
.pc-stars { display: inline-flex; gap: 4px; }
.pc-stars svg { width: 20px; height: 20px; fill: rgba(27, 26, 46, .12); }
.pc-stars svg.on { fill: var(--sun); filter: drop-shadow(0 2px 4px rgba(227, 155, 0, .35)); }
.pc-stars.small svg { width: 14px; height: 14px; }
.pc-stars.big { gap: 8px; justify-content: center; margin: 6px 0 4px; }
.pc-stars.big svg { width: 46px; height: 46px; }
.pc-stars.big svg.on { animation: pc-star .5s var(--spring) backwards; animation-delay: calc(var(--k, 0) * 160ms + 120ms); }
@keyframes pc-star { 0% { transform: scale(0) rotate(-30deg); opacity: 0; } 70% { transform: scale(1.18) rotate(4deg); opacity: 1; } 100% { transform: scale(1) rotate(0); } }

/* The end of a step, and the end of the lesson. */
.pc-stage-done, .pc-done { text-align: center; padding: 38px 30px 34px; }
.pc-stage-done .pc-kicker, .pc-done .pc-kicker { justify-content: center; }
.pc-stage-done h2, .pc-done h2 { margin: 10px 0 6px; }
.pc-sub { margin: 0 auto; max-width: 42ch; font-size: 16px; color: var(--ink-2); }
.pc-tick { display: inline-grid; place-items: center; width: 56px; height: 56px; margin: 8px 0; border-radius: 50%; background: var(--ok); color: #fff; box-shadow: 0 8px 22px rgba(23, 168, 107, .35); }
.pc-tick svg { width: 24px; height: 24px; fill: currentColor; }
.pc-facts { display: flex; flex-wrap: wrap; gap: 8px 22px; margin-top: 18px; font-size: 13.5px; color: var(--ink-3); }
.pc-stage-done .pc-facts, .pc-done .pc-facts { justify-content: center; }
.pc-facts b { font-family: var(--display); font-size: 17px; font-weight: 800; color: var(--ink); margin-right: 3px; letter-spacing: -.01em; }

/* The intro: what the path holds. */
.pc-outline { list-style: none; margin: 14px 0 0; padding: 0; counter-reset: pc; display: flex; flex-direction: column; gap: 8px; }
.pc-outline li { counter-increment: pc; display: flex; align-items: center; gap: 12px; }
.pc-outline li::before {
  content: counter(pc);
  width: 28px; height: 28px; flex: none;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--u);
  background-image: linear-gradient(160deg, rgba(255, 255, 255, .3), rgba(255, 255, 255, 0) 60%);
  color: #fff;
  font-family: var(--display); font-size: 13px; font-weight: 800;
  box-shadow: 0 3px 8px color-mix(in srgb, var(--u) 35%, transparent);
}
.pc-outline b { font-size: 16.5px; font-weight: 700; }
.pc-outline span { margin-left: auto; font-size: 13px; color: var(--ink-3); white-space: nowrap; }
.pc-last { display: flex; align-items: center; gap: 10px; margin-top: 18px; padding: 10px 14px; border-radius: var(--r); background: var(--surface-2); font-size: 13.5px; color: var(--ink-2); }

/* Words, five at a time. */
.pc-words { display: flex; flex-direction: column; margin-top: 8px; }
.pc-word { display: flex; align-items: flex-start; gap: 10px; padding: 10px 0; border-top: 1px solid var(--line-soft); }
.pc-word:first-child { border-top: 0; }
.pc-word .pc-hear { margin-top: 2px; }
.pc-word-fr { display: block; font-size: 17px; font-weight: 700; }
.pc-word .word-gram { font-size: 12.5px; font-weight: 500; color: var(--ink-3); font-style: italic; }
.pc-word-en { display: block; color: var(--ink-2); font-size: 14.5px; }
.pc-word-ex { display: block; margin-top: 2px; color: var(--ink-3); font-size: 14px; font-style: italic; }

/* The finish. */
.pc-done { background: linear-gradient(180deg, var(--u-wash), #fff 62%); }
.pc-bird { width: 120px; height: 120px; margin: 0 auto 8px; object-fit: contain; filter: drop-shadow(0 16px 24px rgba(31, 79, 214, .2)); animation: float 6s ease-in-out infinite; }
.pc-done h2 { font-size: 32px; }
.pc-tiles { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; margin: 22px 0 18px; }
.pc-tile { padding: 14px 10px 12px; border-radius: var(--r); background: #fff; border: 1px solid var(--line-soft); box-shadow: var(--shadow-1); }
.pc-tile b { display: block; font-family: var(--display); font-size: 24px; font-weight: 800; letter-spacing: -.02em; }
.pc-tile span { font-size: 12.5px; color: var(--ink-3); }
.pc-addwords { margin-top: 16px; }
.pc-foot.done { flex-wrap: wrap; }

.pc-level { text-align: left; margin: 0 auto; max-width: 420px; }
.pc-level-head { display: flex; justify-content: space-between; align-items: baseline; font-size: 14px; color: var(--ink-2); }
.pc-level-head b { font-family: var(--display); font-size: 16px; color: var(--ink); }
.pc-level-xp { font-family: var(--display); font-weight: 800; color: #8A5A00; }
.pc-level-bar { height: 10px; margin: 8px 0 6px; border-radius: 999px; background: rgba(27, 26, 46, .08); overflow: hidden; }
.pc-level-bar i { display: block; height: 100%; border-radius: inherit; background: var(--grad-brand); transition: width 1s var(--ease); }
.pc-level-foot { font-size: 12.5px; color: var(--ink-3); }
.pc-level.compact { max-width: 360px; margin: 14px 0 0; }
.pc-level.compact .pc-level-bar { height: 8px; margin: 6px 0 4px; }

/* On the list: stars for a finished lesson, the step for one under way;
   on the hub, the level. */
.step-end .pc-stars { margin-right: 2px; }
.step-body .meta .going { color: var(--u); font-weight: 700; }

/* The band, on the hub and at the top of a section page. Four segments, one
   per band, each in that band's own hue from LEVEL_HUES, so the bar reads
   warm to cool the way every list of lessons does. The segment being worked
   on is filled to how far through it the learner is; the ones after it are
   the empty track. */
.band-block { margin: 14px 0 0; max-width: 430px; }
.band-head { display: flex; align-items: center; gap: 2px; margin: 0 0 9px; font-family: var(--display); font-size: 17px; font-weight: 700; letter-spacing: -.01em; }
.band-bar { display: grid; grid-template-columns: repeat(4, 1fr); gap: 4px; }
.band-seg { height: 10px; border-radius: 999px; background: rgba(27, 26, 46, .08); overflow: hidden; }
.band-seg i { display: block; height: 100%; border-radius: inherit; transition: width 1s var(--ease); }
.band-line { margin: 9px 0 0; font-size: 14px; line-height: 1.45; color: var(--ink-2); }
.band-block .hub-actions { margin-top: 12px; }
.band-bar.compact { max-width: 360px; margin: 14px 0 0; }
.band-bar.compact .band-seg { height: 8px; }
.fiche-actions { margin: 14px 0 0; }
.pc-crumbs { padding-top: 12px; padding-bottom: 0; }

.pc-confetti { position: fixed; inset: 0; z-index: 60; width: 100vw; height: 100vh; pointer-events: none; }

@media (max-width: 640px) {
  .pc-top { top: calc(var(--bar-h) + 6px); gap: 7px; padding: 6px 8px 6px 6px; }
  .pc-count { display: none; }
  .pc-combo, .pc-xp { height: 28px; padding: 0 9px; font-size: 13px; }
  .pc-step, .pc-step.lesson { padding: 18px 16px 22px; }
  .pc-step h2, .pc-step.lesson h2 { font-size: 22px; }
  .pc-practice .q-text { font-size: 19px; }
  .pc-back span { display: none; }
  .pc-back { padding: 0 12px; }
  .pc-foot { padding-left: 14px; }
  .pc-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .pc-done h2 { font-size: 26px; }
  .pc-stage-done, .pc-done { padding: 28px 18px 26px; }
  .pc-outline span { white-space: normal; }
}

@media (prefers-reduced-motion: reduce) {
  .pc-card.flip > .pc-step, .pc-stars.big svg.on, .pc-combo, .pc-combo.hot, .pc-xp.bump, .pc-earned, .pc-bird, .pc-foot.nudge, .pc-top { animation: none; }
  .pc-seg::before, .pc-level-bar i, .band-seg i { transition: none; }
}

/* ------------------------------------------------------------- bilingual */

/* The English line under a French one, I18N.TT's "both" mode: stacked by
   default, the shape a title or a note wants. */
.bi { display: inline-flex; flex-direction: column; line-height: 1.2; }
.bi-en { color: var(--ink-3); font-size: .82em; font-weight: 500; }
/* In a one-line control the stack would wrap the row; the English goes
   inline instead, after a middle dot. */
.btn .bi, .tag .bi, .seg-btn .bi, .level-tab .bi, .topnav-link .bi, .kicker .bi {
  flex-direction: row; gap: .45em; align-items: baseline;
}
.btn .bi-en::before, .tag .bi-en::before, .seg-btn .bi-en::before,
.level-tab .bi-en::before, .topnav-link .bi-en::before, .kicker .bi-en::before {
  content: '·'; margin-right: .45em;
}

/* ------------------------------------------------------------------ voice */

.voice-pick {
  margin-left: 6px; max-width: 280px;
  padding: 3px 8px;
  font: inherit; font-size: 12.5px; color: var(--ink-2);
  background: #fff; border: 1px solid var(--line); border-radius: 8px;
}

/* ------------------------------------------------------------ récompenses */

/* The flame in the top bar: days in a row. Warm from seven. */
.streak-chip {
  display: inline-flex; align-items: center; gap: 5px;
  height: 36px; padding: 0 12px 0 9px;
  border-radius: 999px;
  background: var(--coral-wash); color: #D8452F;
  border: 1px solid rgba(255, 107, 92, .28);
  font-family: var(--display); font-size: 14px; font-weight: 800;
  font-variant-numeric: tabular-nums;
  transition: transform .15s var(--spring);
}
.streak-chip:hover { transform: translateY(-1px); }
.streak-chip svg { width: 15px; height: 15px; fill: currentColor; }
.streak-chip.hot { background: var(--grad-warm); color: #fff; border-color: transparent; box-shadow: 0 6px 16px rgba(255, 107, 92, .3); }

/* A toast: one card at the foot of the page, said and gone. */
.toasts {
  position: fixed; left: 0; right: 0; bottom: calc(var(--tab-h) + 18px + var(--tab-safe));
  z-index: 70;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  pointer-events: none;
}
.toast {
  pointer-events: auto;
  display: flex; align-items: center; gap: 12px;
  width: max-content; max-width: min(380px, calc(100vw - 32px));
  padding: 10px 18px 10px 10px;
  border-radius: 20px;
  background: rgba(255, 255, 255, .93);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  backdrop-filter: saturate(180%) blur(20px);
  border: 1px solid rgba(27, 26, 46, .08);
  box-shadow: var(--shadow-3);
  color: var(--ink);
  cursor: pointer;
  animation: toast-in .45s var(--spring) backwards;
}
.toast.out { animation: toast-out .32s var(--ease) forwards; }
@keyframes toast-in { from { opacity: 0; transform: translateY(18px) scale(.94); } to { opacity: 1; transform: none; } }
@keyframes toast-out { to { opacity: 0; transform: translateY(12px) scale(.96); } }
.toast-mark { display: grid; place-items: center; width: 40px; height: 40px; flex: none; border-radius: 13px; background: var(--grad-brand); color: #fff; }
.toast-mark svg { width: 18px; height: 18px; fill: currentColor; }
.toast-mark .trophy-glyph { font-family: var(--display); font-size: 13px; font-weight: 800; color: #fff; letter-spacing: -.02em; }
.toast.goal .toast-mark { background: var(--ok); }
.toast.day .toast-mark { background: var(--grad-warm); }
.toast.trophy .toast-mark { background: linear-gradient(135deg, #FFC43D, #FF6B5C); }
.toast-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; line-height: 1.3; }
.toast-kicker { font-size: 10.5px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3); }
.toast-text b { font-family: var(--display); font-size: 15px; font-weight: 800; letter-spacing: -.01em; line-height: 1.25; }
.toast-sub { font-size: 12.5px; line-height: 1.35; color: var(--ink-2); }

/* Objectifs du jour: three rows, a ring each, a tick once it is done. */
.goal-rows { display: flex; flex-direction: column; gap: 9px; margin-top: 12px; }
.goal-row { display: flex; align-items: center; gap: 12px; font-size: 14.5px; font-weight: 600; }
.goal-ring { position: relative; width: 30px; height: 30px; flex: none; }
.goal-ring > svg:first-child { width: 100%; height: 100%; transform: rotate(-90deg); }
.goal-ring .ring-bg, .goal-ring .ring-fg { stroke-width: 4.2; }
.goal-ring > svg:last-child {
  position: absolute; inset: 0; margin: auto;
  width: 14px; height: 14px; fill: #fff;
  opacity: 0; transform: scale(.4);
  transition: opacity .2s var(--ease), transform .3s var(--spring);
}
.goal-row.done .goal-ring::before { content: ''; position: absolute; inset: 2px; border-radius: 50%; background: var(--ok); }
.goal-row.done .goal-ring > svg:first-child { opacity: 0; }
.goal-row.done .goal-ring > svg:last-child { opacity: 1; transform: none; }
.goal-text { flex: 1; min-width: 0; }
.goal-row.done .goal-text { color: var(--ink-3); text-decoration: line-through; text-decoration-color: rgba(27, 26, 46, .3); }
.goal-count { font-family: var(--display); font-size: 13px; font-weight: 800; color: var(--ink-3); font-variant-numeric: tabular-nums; white-space: nowrap; }
.goal-row.done .goal-count { color: var(--ok); }
.bento-tile.b-goals.reached { background: linear-gradient(160deg, #E3F8EE, #fff 70%); }

/* Aujourd'hui: the day's four rows, at the top of the hub where the way back
   to the last page used to sit. A white card at the wide radius carrying the
   band's hue, with the same rings as the goals tile it replaces; once the
   four are done it sits on the green wash that tile sat on. */
.today-card {
  margin: 18px 0 8px;
  padding: 20px 24px 18px;
  border-radius: var(--r-xl);
  background: var(--surface);
  border: 1px solid var(--line-soft);
  box-shadow: var(--shadow-1);
  animation: head-in .45s var(--ease) .08s backwards;
}
.today-card.done { background: linear-gradient(160deg, #E3F8EE, #fff 70%); }
.today-kicker {
  margin: 0;
  font-size: 11.5px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-3);
}
.today-title {
  margin: 5px 0 0;
  font-family: var(--display);
  font-size: 25px; font-weight: 700; letter-spacing: -.015em; line-height: 1.2;
  color: var(--ink);
}
.today-card .goal-rows { gap: 2px; margin-top: 13px; }
.today-card .goal-row {
  gap: 14px;
  margin: 0 -10px;
  padding: 9px 10px;
  border-radius: var(--r);
  color: inherit;
  transition: background .16s var(--ease);
}
.today-card .goal-row:hover { background: var(--u-wash); }
.today-card .goal-text { display: flex; flex-direction: column; gap: 1px; font-weight: 400; }
.today-kind { font-size: 10.5px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--u); }
.today-what { font-family: var(--display); font-size: 16.5px; font-weight: 700; letter-spacing: -.01em; line-height: 1.25; }
.today-sub { font-size: 13px; line-height: 1.35; color: var(--ink-3); }
.today-card .goal-row.done .goal-text { color: inherit; text-decoration: none; }
.today-card .goal-row.done .today-what {
  color: var(--ink-3);
  text-decoration: line-through; text-decoration-color: rgba(27, 26, 46, .3);
}
.today-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap;
  margin: 14px 0 0; padding-top: 13px;
  border-top: 1px solid var(--line-soft);
  font-size: 13px; color: var(--ink-2);
}
.today-band { display: flex; align-items: center; font-weight: 700; color: var(--ink); }
.today-band .level-chip { margin-right: 8px; }
.today-resume {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin-top: 12px; padding-top: 12px;
  border-top: 1px solid var(--line-soft);
  font-size: 13.5px; color: var(--ink-2);
}
.today-resume:hover { color: var(--ink); }
@media (max-width: 640px) {
  .today-card { padding: 18px 18px 16px; }
  .today-title { font-size: 22px; }
  .today-what { font-size: 15.5px; }
}

/* Trophées: a tile with a glyph or an icon, textured like the row tiles once
   it is had, quiet until then. */
.trophy-row { display: flex; gap: 10px; margin-top: 12px; }
.trophy { display: flex; flex-direction: column; align-items: center; gap: 6px; min-width: 0; text-align: center; }
.trophy-mark {
  --pc: color-mix(in srgb, var(--u) 26%, transparent);
  position: relative; display: grid; place-items: center; flex: none;
  width: 62px; height: 62px; border-radius: 20px;
  background-color: color-mix(in srgb, var(--u) 9%, #fff);
  background-image: var(--pattern, none),
    linear-gradient(135deg, color-mix(in srgb, var(--u) 15%, #fff), color-mix(in srgb, var(--u) 3%, #fff));
  background-size: var(--pattern-size, auto), auto;
  background-position: var(--pattern-pos, 0 0), 0 0;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--u) 16%, transparent);
  color: var(--u);
  transition: transform .18s var(--spring);
}
.trophy-glyph { font-family: var(--display); font-weight: 800; font-size: 20px; letter-spacing: -.02em; }
.trophy-icon { width: 26px; height: 26px; fill: currentColor; }
.trophy-name { font-size: 12.5px; font-weight: 700; line-height: 1.2; }
.trophy-how { font-size: 12px; line-height: 1.3; color: var(--ink-3); }
.trophy.locked .trophy-mark { background: var(--surface-2); box-shadow: inset 0 0 0 1px var(--line); color: var(--ink-3); }
.trophy.locked .trophy-name { color: var(--ink-3); }
.trophy.mini { flex: 1; }
.trophy.mini:hover .trophy-mark { transform: translateY(-2px); }
.trophy.mini .trophy-mark { width: 54px; height: 54px; border-radius: 17px; }
.trophy.mini .trophy-glyph { font-size: 17px; }
.trophy.mini .trophy-icon { width: 22px; height: 22px; }
.trophy.mini .trophy-name { font-size: 11.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
.b-trophies .bento-sub { margin-top: 10px; }
.b-trophies .bento-link { padding-top: 6px; }

.trophy-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 14px; margin-top: 22px; }
.trophy-grid .trophy {
  padding: 18px 12px 16px;
  border-radius: var(--r-lg);
  background: var(--surface);
  border: 1px solid var(--line-soft);
  box-shadow: var(--shadow-1);
}
.trophy-grid .trophy.earned { border-color: color-mix(in srgb, var(--u) 30%, transparent); }
.trophy-grid .trophy.locked { box-shadow: none; background: rgba(255, 255, 255, .55); }
.trophy-grid .trophy-mark { width: 74px; height: 74px; border-radius: 24px; }
.trophy-grid .trophy-glyph { font-size: 24px; }
.trophy-grid .trophy-name { font-size: 14px; margin-top: 4px; }

/* The finish: a band crossed, and the days in a row. */
.pc-band {
  display: flex; flex-direction: column; align-items: center; gap: 1px;
  margin: 4px auto 18px; padding: 14px 28px;
  max-width: 320px;
  border-radius: var(--r-lg);
  background: var(--grad-warm); color: #fff;
  box-shadow: 0 12px 30px rgba(255, 63, 142, .28);
  animation: pop-in .5s var(--spring) .35s backwards;
}
.pc-band-kicker { font-size: 11.5px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; opacity: .85; }
.pc-band b { font-family: var(--display); font-size: 30px; font-weight: 800; letter-spacing: -.02em; line-height: 1.1; }
.pc-band-name { font-size: 15px; font-weight: 700; opacity: .95; }
.pc-done.up { background: linear-gradient(180deg, #FFE9E5, #fff 62%); }
.pc-streak {
  display: inline-flex; align-items: center; gap: 7px;
  margin: 16px auto 0; padding: 7px 14px;
  border-radius: 999px;
  background: var(--coral-wash); color: #D8452F;
  font-size: 14px;
}
.pc-streak svg { width: 15px; height: 15px; fill: currentColor; }
.pc-streak b { font-family: var(--display); font-weight: 800; }

/* A drill's path sits under its scoreboard. */
.pc.drill { padding-top: 0; }
.act-stats + .pc.drill .pc-top, .pc.drill .pc-top { margin-top: 14px; }

/* The review row on the grammar page. */
.step.review { --u: #D8452F; --u-wash: var(--coral-wash); }

@media (max-width: 900px) {
  .b-3.b-goals, .b-3.b-trophies { grid-column: span 2; }
}
@media (max-width: 640px) {
  .b-3.b-goals, .b-3.b-trophies { grid-column: span 1; }
  .streak-chip { height: 32px; padding: 0 10px 0 8px; font-size: 13px; }
  .trophy-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .toast { border-radius: 18px; }
}
@media (prefers-reduced-motion: reduce) {
  .toast, .toast.out, .pc-band { animation: none; }
}

/* ---------------------------------------------------------------- réglages */

.accent-toggle.icon { display: inline-flex; align-items: center; justify-content: center; width: 44px; padding: 0; color: var(--ink-2); }
.accent-toggle.icon svg { width: 16px; height: 16px; fill: currentColor; display: block; }
.settings { display: flex; flex-direction: column; gap: 16px; }
.settings-card { padding: 4px 0 4px; }
.settings-card > h2 { margin: 16px 22px 4px; font-size: 12px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3); }
.setting { display: flex; align-items: center; gap: 20px; padding: 15px 22px; border-top: 1px solid var(--line-soft); }
.settings-card > h2 + .setting { border-top: 0; }
.setting-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.setting-text b { font-size: 16px; font-weight: 700; }
.setting-text span { font-size: 13.5px; line-height: 1.45; color: var(--ink-2); }
.setting-control { flex: none; display: flex; align-items: center; gap: 10px; }
.setting-control .btn.small { margin-top: 0; }
.setting-control .voice-pick { margin: 0; max-width: 220px; padding: 8px 10px; font-size: 13.5px; border-radius: 10px; }
.switch {
  position: relative; flex: none;
  width: 50px; height: 30px; padding: 0;
  border: 0; border-radius: 999px;
  background: rgba(27, 26, 46, .16);
  cursor: pointer;
  transition: background .2s var(--ease);
}
.switch i {
  position: absolute; top: 3px; left: 3px;
  width: 24px; height: 24px; border-radius: 50%;
  background: #fff;
  box-shadow: 0 2px 6px rgba(27, 26, 46, .25);
  transition: transform .22s var(--spring);
}
.switch[aria-checked="true"] { background: var(--ok); }
.switch[aria-checked="true"] i { transform: translateX(20px); }
@media (max-width: 640px) {
  .setting { flex-direction: column; align-items: stretch; gap: 10px; padding: 14px 18px; }
  .setting-control { flex: 1 1 auto; min-width: 0; justify-content: flex-end; }
  .setting-control .btn { flex: none; }
  .setting-control .voice-pick { max-width: none; flex: 1 1 0; min-width: 0; }
}
@media (max-width: 480px) { #settingsLink { display: none; } }

/* Review: a sentence with the word blanked, as a recall prompt. */
.review-cloze { margin: 8px 0 0; font-family: var(--display); font-size: 22px; font-weight: 700; line-height: 1.3; letter-spacing: -.01em; text-wrap: balance; }

/* What a thing pays, on its row and on its page. */
.tag.xp { background: var(--sun-wash); color: #8A5A00; border-color: transparent; font-variant-numeric: tabular-nums; }
.step-body .meta .xp { color: #8A5A00; font-weight: 700; }

/* ------------------------------------------------------------- ParleyTV */

/* The feed. Player at the top, the French line under it, controls under that,
   and nothing at all in front of the video, the YouTube terms forbid drawing
   over an embedded player or its controls, and it is the better layout anyway:
   a line under the picture is a line you can read without the picture moving
   behind it.

   This is the one place in Parley where colour sits on French text. It earns
   it by being grammar rather than decoration: blue is a masculine noun, pink a
   feminine one, teal a verb, lilac an adjective, and the sun marks a word you
   do not know yet. Somebody who has seen le and la in two colours for a month
   has had the only gender drill that never felt like one. docs/DESIGN.md says
   the same at more length. */

/* A phone screen even on a desktop: a 16:9 video at 1180 px is a television,
   and the line under it would be a paragraph. */
.tv-wrap { width: min(940px, 100%); padding-bottom: 40px; }
/* ParleyTV's hue is the toucan's teal, as on its hub card, and it keeps it
   whatever page was open before: the kicker reads --u, and without this the
   feed's name would turn A1 red beside a grammar lesson. Deepened so it
   carries a label on white. */
.tv-wrap { --u: #0A6B65; --u-wash: var(--teal-wash); }
.tv-head { padding-bottom: 10px; }

.tv-top { margin: 18px 0 14px; }
.tv-top-row { display: flex; align-items: center; gap: 12px; margin: 18px 0 0; min-height: 34px; }
.tv-top-row .crumbs { margin: 0; min-height: 0; }
.tv-kicker { margin: 0; }
.tv-spacer { flex: 1 1 auto; }
.tv-links { display: flex; gap: 14px; flex: 0 0 auto; }

.tv-seg { flex: 0 0 auto; }
.tv-link { font-size: 14px; font-weight: 700; color: var(--accent); }
.tv-link:hover { color: var(--accent-dark); text-decoration: underline; text-underline-offset: 3px; }

/* the player */

/* The player is one card, like the exercises' own player card: the video,
   the line under it, the controls under the line. The card is sized so the
   whole of it is on screen with the top bar and the trail: 330 px is what
   the line, the controls and the hint need under a 16:9 video. A 9:16 clip
   is sized by height on a dark stage, a phone-shaped video given a phone's
   full width is taller than the phone. */
.tv-player {
  margin: 12px auto 0;
  background: var(--surface);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-2);
  overflow: hidden;
}
.tv-player.is-long { width: clamp(300px, calc((100vh - var(--bar-h) - 330px) * 16 / 9), 100%); }
.tv-player.is-short { width: 100%; }
.tv-stage { background: #0F0E1A; }
.tv-frame { position: relative; overflow: hidden; background: #000; }
.tv-frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.tv-long { aspect-ratio: 16 / 9; width: 100%; }
.tv-short {
  aspect-ratio: 9 / 16;
  height: clamp(280px, calc(100vh - var(--bar-h) - 330px), 600px);
  width: auto; max-width: 100%;
  margin: 0 auto;
}
.tv-noplayer { position: absolute; inset: 0; margin: 0; border-radius: 0; display: grid; place-content: center; }

.tv-meta {
  display: flex; align-items: center; gap: 8px;
  flex: 1 1 240px; min-width: 0; margin: 0;
  font-size: 13.5px; color: var(--ink-2);
}
.tv-meta-title { flex: 1 1 auto; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tv-meta b { color: var(--ink); font-weight: 700; }
.tv-cov {
  flex: none; padding: 3px 9px; border-radius: 999px;
  background: var(--ok-wash); color: var(--ok);
  font-size: 12.5px; font-weight: 800; font-variant-numeric: tabular-nums; white-space: nowrap;
}

/* the line */

.tv-rail {
  padding: 14px 20px 16px;
  border-top: 1px solid var(--line-soft);
  /* Held open for a two-line cue so the controls do not jump under the
     reader's thumb. */
  min-height: 96px;
  touch-action: pan-y;
}
.tv-before {
  margin: 0 0 6px;
  font-family: var(--sans);
  font-size: 13.5px; font-weight: 600; line-height: 1.4;
  color: var(--ink-3);
  min-height: 19px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.tv-line {
  margin: 0;
  font-family: var(--display);
  font-size: clamp(20px, 3.6vw, 26px);
  font-weight: 700;
  line-height: 1.4;
  letter-spacing: -.012em;
  color: var(--ink);
  text-wrap: pretty;
}

/* A word is a button: that is what makes it reachable from a keyboard, and it
   is also what keeps the dictionary's press-and-hold out of the line, since a
   button is already on its list of things to leave alone. */
.tv-w {
  display: inline;
  margin: 0; padding: 0 .05em;
  border: 0; border-radius: 8px;
  background: none;
  font: inherit; color: inherit;
  letter-spacing: inherit;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background .14s var(--ease);
}
.tv-w:hover { background: rgba(27, 26, 46, .06); }
.tv-w:active { background: rgba(27, 26, 46, .11); }

.tv-m { color: var(--tv-m); }
.tv-f { color: var(--tv-f); }
.tv-v { color: var(--tv-v); }
.tv-a { color: var(--tv-a); }

/* The two or three words the clip was chosen for. Not part of the grammar
   colours and does not turn off with them: without it the line is pretty and
   says nothing about what there is to learn in it. */
.tv-new { box-shadow: inset 0 -3px 0 rgba(143, 98, 0, .45); border-radius: 4px; }
.tv-new:hover { background: var(--tv-new-wash); }

.tv-tok { color: var(--tv-name); }
.tv-name { text-decoration: underline dotted rgba(111, 109, 133, .45); text-underline-offset: 5px; }
.tv-num { font-variant-numeric: tabular-nums; }

.tv-nosync { margin: 16px 0 8px; }
.tv-turn { display: flex; gap: 10px; }

.tv-controls {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 10px 14px 12px 20px;
  border-top: 1px solid var(--line-soft);
}
.tv-controls .btn.small { margin-top: 0; align-self: center; flex: 0 0 auto; }
.tv-next svg { width: 9px; height: 13px; fill: currentColor; }
.tv-redo svg { width: 13px; height: 13px; fill: currentColor; }
.tv-hint { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 4px 14px; margin: 10px 4px 0; font-size: 13px; }
.tv-hint-right { font-variant-numeric: tabular-nums; }
.tv-hint-left { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; }
/* The key to the colours: a dot in each, and the mark for a word to learn. */
.tv-legend { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; }
.tv-key { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; font-weight: 600; }
.tv-key i { width: 9px; height: 9px; border-radius: 50%; background: currentColor; display: inline-block; }
.tv-key-new { color: var(--tv-new-ink); }
.tv-key-new i { border-radius: 2px; background: var(--tv-new-wash); box-shadow: inset 0 -2px 0 rgba(143, 98, 0, .6); }
.tv-card-gram.tv-m { color: var(--tv-m); }
.tv-card-gram.tv-f { color: var(--tv-f); }
.tv-card-gram.tv-v { color: var(--tv-v); }
.tv-card-gram.tv-a { color: var(--tv-a); }
/* Regarder, on the settings page: the site's button, with room around it. */
.tv-actions { margin: 14px 0 0; }
.tv-actions .btn svg { width: 9px; height: 13px; fill: currentColor; }
@media (min-width: 901px) { .hub-actions.tv-actions { display: flex; } }
.settings + .tv-actions { margin-top: 22px; }
.tv-wrap.tv-feed { padding-bottom: 28px; }
body.tv-page .foot { display: none; }

.tv-allcues { display: flex; flex-direction: column; gap: 2px; margin-top: 16px; }
.tv-cue-jump {
  text-align: left; border: 0; background: none;
  padding: 8px 11px; border-radius: var(--r-sm);
  font: inherit; font-size: 15px; color: var(--ink-2); cursor: pointer;
}
.tv-cue-jump:hover { background: var(--surface-2); color: var(--ink); }


/* the page: a theatre */

/* On its own page the feed covers the whole thing. The video sits on a band
   of near-black across the full width, like a cinema wall, as large as the
   screen's height allows with the line still in view under it: a video
   that pushes its own subtitle below the fold is the one layout this screen
   cannot have. 330 px is the room the line, the controls and the legend
   need. The band is outside .wrap; the line under it keeps the reading
   column, because a subtitle across 1180 px is a paragraph. The footer goes
   with the rest: there is nothing under the line but the line. */

/* the word card */

/* A sheet at the bottom of the screen. Never a popover beside the word: a
   popover near the top of a phone would sit over the player, which is the one
   thing the terms forbid. */
.tv-veil {
  position: fixed; inset: 0; z-index: 55;
  background: rgba(27, 26, 46, .14);
  animation: tv-fade .2s var(--ease);
}
@keyframes tv-fade { from { opacity: 0; } }

.tv-card {
  position: fixed;
  left: 50%; bottom: 0;
  transform: translateX(-50%);
  width: min(560px, 100%);
  z-index: 60;
  padding: 22px 24px calc(24px + env(safe-area-inset-bottom));
  background: rgba(255, 255, 255, .94);
  -webkit-backdrop-filter: saturate(180%) blur(24px);
  backdrop-filter: saturate(180%) blur(24px);
  border: 1px solid rgba(27, 26, 46, .07);
  border-bottom: 0;
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  box-shadow: var(--shadow-3);
  animation: tv-rise .24s var(--spring);
}
@keyframes tv-rise { from { transform: translate(-50%, 18px); opacity: 0; } }

.tv-card-head { display: flex; align-items: center; gap: 8px; }
.tv-card-title { flex: 1 1 auto; min-width: 0; display: inline-flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.tv-card:focus { outline: none; }
.tv-card-word {
  font-family: var(--display);
  font-size: 28px; font-weight: 800; letter-spacing: -.02em;
}
.tv-card-gram { font-size: 13px; color: var(--ink-3); font-weight: 600; }
.tv-say {
  margin-left: auto;
  width: 34px; height: 34px; flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  border: 0; border-radius: 50%;
  background: var(--accent-wash); cursor: pointer;
  transition: transform .18s var(--spring), background .15s var(--ease);
}
.tv-say:hover { background: #D8E5FF; transform: scale(1.06); }
.tv-say svg { width: 15px; height: 15px; fill: var(--accent-dark); }
.tv-card-close {
  width: 34px; height: 34px; flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  border: 0; border-radius: 50%;
  background: rgba(27, 26, 46, .06);
  font: inherit; font-size: 18px; line-height: 1; color: var(--ink-2); cursor: pointer;
  transition: background .15s var(--ease);
}
.tv-card-close:hover { background: rgba(27, 26, 46, .11); color: var(--ink); }
.tv-card-body { margin: 13px 0 4px; }
.tv-card-body p { margin: 0 0 8px; }
.tv-en { font-size: 18px; font-weight: 700; }
.tv-fr { font-size: 15px; color: var(--ink-2); }
.tv-ex { font-size: 15px; color: var(--ink-2); font-style: italic; }
.tv-ctx {
  font-size: 14px; color: var(--ink-3);
  padding-left: 12px; border-left: 3px solid var(--line);
}
.tv-card-foot { display: flex; gap: 16px; padding-top: 10px; border-top: 1px solid var(--line-soft); }

/* panels, the check, the form */

/* The same surface as .card everywhere else: one radius, one border, one
   shadow, so a ParleyTV panel beside a lesson card reads as the same app. */
.tv-panel {
  margin: 0 0 18px;
  padding: 26px 24px;
  background: var(--surface);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-1);
}
.tv-panel h2 {
  margin: 0 0 8px;
  font-family: var(--display);
  font-size: 22px; font-weight: 700; letter-spacing: -.02em;
}
.tv-panel p { margin: 0 0 10px; color: var(--ink-2); }
.tv-quiet { color: var(--ink-3); font-size: 14px; }
.tv-label { font-size: 12px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3); }
.tv-bad { color: var(--no); font-weight: 700; }
.tv-good { color: var(--ok); font-weight: 700; }
.tv-wait { padding: 70px 0; text-align: center; color: var(--ink-3); }
.tv-done { text-align: center; }

.tv-near, .tv-mine { margin: 6px 0 14px; padding: 0; list-style: none; }
.tv-near li, .tv-mine li { padding: 9px 0; border-bottom: 1px solid var(--line-soft); font-size: 15px; }

.tv-check { text-align: center; }
.tv-progress { height: 5px; border-radius: 999px; background: var(--line-soft); overflow: hidden; margin-bottom: 20px; }
.tv-progress span { display: block; height: 100%; background: var(--grad-brand); transition: width .2s var(--ease); }
.tv-big {
  font-family: var(--display);
  font-size: clamp(34px, 9vw, 54px);
  font-weight: 800; letter-spacing: -.03em;
  margin: 28px 0 32px;
  color: var(--ink);
}
.tv-number {
  margin: 4px 0 2px;
  font-variant-numeric: tabular-nums;
  background: var(--grad-brand); -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}
.tv-check-btns { display: flex; gap: 10px; justify-content: center; }
.tv-check-btns .btn { min-width: 148px; }
.tv-keys { margin: 16px 0 0; font-size: 12.5px; color: var(--ink-3); }
@media (hover: none) { .tv-keys { display: none; } }

.tv-bands { width: 100%; border-collapse: collapse; margin: 16px 0 4px; font-size: 14px; }
.tv-bands th { text-align: left; padding: 7px 0; color: var(--ink-3); font-weight: 700; border-bottom: 1px solid var(--line); }
.tv-bands td { padding: 7px 0; border-bottom: 1px solid var(--line-soft); font-variant-numeric: tabular-nums; }
.tv-bands td:last-child, .tv-bands th:last-child { text-align: right; }

.tv-rule { margin-bottom: 18px; }
.tv-rule p { margin: 7px 0 0; font-size: 14px; }
.tv-field { display: block; margin: 0 0 14px; }
.tv-field > span { display: block; margin-bottom: 7px; font-size: 13px; font-weight: 700; color: var(--ink-2); }
/* The answer fields' own look (.q input), so the form matches the exercises. */
.tv-input {
  width: 100%;
  padding: 13px 15px;
  border: 1.5px solid var(--line); border-radius: var(--r);
  background: #FDFCFA;
  font: inherit; font-size: 16.5px; color: var(--ink);
  resize: vertical; line-height: 1.5;
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease), background .15s var(--ease);
}
.tv-input::placeholder { color: var(--ink-3); }
.tv-input:focus { outline: none; border-color: var(--accent); background: #fff; box-shadow: 0 0 0 4px rgba(47, 107, 255, .14); }

/* the way in: a level, one tap */

.tv-levels {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px; margin: 16px 0 14px;
}
.tv-level {
  padding: 14px 8px 12px;
  border: 1px solid var(--line); border-radius: var(--r);
  background: var(--surface-2);
  font: inherit; text-align: center; cursor: pointer;
  transition: transform .18s var(--spring), border-color .15s var(--ease), background .15s var(--ease), box-shadow .18s var(--ease);
}
.tv-level:hover { transform: translateY(-2px); border-color: var(--u); background: var(--u-wash); box-shadow: var(--shadow-1); }
.tv-level:active { transform: scale(.97); }
.tv-level b { display: block; font-family: var(--display); font-size: 24px; font-weight: 800; letter-spacing: -.02em; color: var(--u); }
.tv-level span { display: block; margin-top: 2px; font-size: 13.5px; font-weight: 700; color: var(--ink); }
.tv-level small { display: block; margin-top: 3px; font-size: 12px; color: var(--ink-3); font-variant-numeric: tabular-nums; }

/* on the meta line: the clip's level, and a word about automatic captions */
.tv-lvl {
  flex: none; padding: 3px 9px; border-radius: 8px;
  background: var(--u-wash); color: var(--u);
  font-size: 12.5px; font-weight: 800; letter-spacing: .04em;
}

/* the way in, on the hub */

.tv-way { grid-column: 1 / -1; }

@media (max-width: 620px) {
  .tv-levels { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .tv-rail { padding: 17px 16px 20px; border-radius: var(--r-lg); min-height: 154px; }
  .tv-panel { padding: 22px 17px; }
  .tv-card { padding: 19px 18px calc(20px + env(safe-area-inset-bottom)); }
  .tv-check-btns { flex-direction: column; }
  .tv-check-btns .btn { width: 100%; }
}

/* ---------------------------------------------------------------- devoirs */

/* What is waiting, on the « Devoirs » link in the top bar. A chip, so the
   radius is the chip's 11 px, in the coral wash: the one warm colour that is
   neither the blue of a control nor the red of a wrong answer. */
.nav-badge {
  margin-left: 6px; min-width: 18px; padding: 0 6px;
  border-radius: var(--r-sm);
  background: var(--coral-wash); color: #C23A2C;
  font-size: 11px; font-weight: 800; line-height: 18px;
  text-align: center; font-variant-numeric: tabular-nums;
}

/* The thread: rows, in the order they were written, not bubbles. Two people
   writing about one piece of work are not chatting. */
/* A devoir's cards keep their row of actions whether or not there is anything
   to put in it, because what belongs there changes as the work goes out and
   comes back; an empty one must not leave a band of padding behind. */
.actions:empty { display: none; }

.thread { display: flex; flex-direction: column; gap: 14px; margin-bottom: 18px; }
.thread:empty { display: none; }
.thread-msg { display: flex; align-items: flex-start; gap: 11px; }
.thread-msg > div { min-width: 0; }
.thread-who {
  margin: 0 0 3px;
  font-size: 12.5px; font-weight: 700; color: var(--ink-3);
}
.thread-body {
  margin: 0;
  font-size: 15px; line-height: 1.55; color: var(--ink);
  white-space: pre-wrap; overflow-wrap: anywhere;
}

/* The work as it was written, the learner's own line breaks kept, on white,
   because it is French meant to be read. */
.devoir-text {
  padding: 15px 17px;
  border-radius: var(--r);
  background: #fff;
  border: 1px solid var(--line-soft);
  font-size: 16px; line-height: 1.6;
  white-space: pre-wrap; overflow-wrap: anywhere;
}
.devoir-audio { width: 100%; max-width: 420px; height: 38px; }

/* Not started, with the professor, back with the learner. */
.devoir-status { box-shadow: none; }
.devoir-status.draft { background: rgba(27, 26, 46, .07); color: var(--ink-2); }
.devoir-status.sent { background: var(--accent-wash); color: var(--accent-dark); }
.devoir-status.returned { background: var(--ok-wash); color: var(--ok); }

/* --------------------------------------------------------- bar at the foot */

/* Under 700 px the top bar's row of sections is gone and the trail carries
   the orientation. The same links sit at the foot instead, where a thumb is:
   an icon over a small label, the page you are on lit in the accent, frosted
   like the bar at the top. Accueil and TV stand with the three sections
   because the brand and the TV switch in the corner are too small to be the
   way in on a phone. Painted by paintNav() in app.js, beside the top links.

   Two screens own the bottom edge themselves and hide it: the feed's theatre,
   where the video is the page, and a lesson's path, where the pill at the
   foot is the one button. */
.tabbar { display: none; }

@media (max-width: 700px) {
  /* The bar's own height: a 1 px rule, 6 px of air, a 48 px item, 6 px of
     air, and the home indicator's room under it. */
  body { --tab-h: calc(61px + env(safe-area-inset-bottom)); --tab-safe: 0px; padding-bottom: var(--tab-h); }
  body.tv-page, body.pc-open { --tab-h: 0px; --tab-safe: env(safe-area-inset-bottom); padding-bottom: 0; }

  .tabbar {
    position: fixed;
    gap: 2px;
    left: 0; right: 0; bottom: 0;
    z-index: 35;
    display: flex;
    padding: 6px max(6px, env(safe-area-inset-right)) calc(6px + env(safe-area-inset-bottom)) max(6px, env(safe-area-inset-left));
    background: rgba(255, 255, 255, .84);
    -webkit-backdrop-filter: saturate(180%) blur(20px);
    backdrop-filter: saturate(180%) blur(20px);
    border-top: 1px solid rgba(27, 26, 46, .07);
  }
  body.tv-page .tabbar, body.pc-open .tabbar { display: none; }
  /* Behind the sign-in there are no sections at all: paintNav() empties the
     bar, and an empty frosted strip along the foot is worse than none. */
  .tabbar:empty { display: none; }
  body:has(.tabbar:empty) { --tab-h: 0px; --tab-safe: env(safe-area-inset-bottom); padding-bottom: 0; }

  .tab {
    flex: 1 1 0; min-width: 0;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
    min-height: 48px; padding: 3px 2px;
    border-radius: var(--r-sm);
    color: var(--ink-3);
    text-align: center;
  }
  .tab.on { color: var(--accent-dark); }
  .tab:active { background: rgba(27, 26, 46, .05); }
  .tab-icon { width: 18px; height: 18px; flex: none; fill: currentColor; }
  .tab-label { max-width: 100%; font-size: 10.5px; font-weight: 700; line-height: 1.1; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
  /* At A2 the label carries its English line: the bar keeps its height and
     the two lines sit inside it. */
  .tab .bi { max-width: 100%; min-width: 0; align-items: center; line-height: 1.05; }
  /* text-overflow does not reach inside the .bi flex, so the two lines carry
     it themselves. */
  .tab .bi-fr, .tab .bi-en { display: block; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .tab .bi-en { font-size: .85em; }
}

/* --------------------------------------------------- the pass at 375 pixels */

/* Found by walking the app at phone width. Every field a learner types into
   is 16 px, because iOS zooms the page in on anything smaller and never zooms
   back out; the switches in the top bar, pressed on every page, are 44 px,
   which is what a thumb asks for; and the top bar itself has to fit, which at
   375 px it did not. Each rule is the smallest that fixed what the walk
   found. */
@media (max-width: 700px) {
  .gate-form input, .field-label input, .field-label select, .field-label textarea,
  .card.review input[type=text], .voice-pick, .setting-control .voice-pick { font-size: 16px; min-height: 44px; }

  .accent-toggle, .account-chip { height: 44px; }
  .brand { min-height: 44px; }
  .level-tab { height: 44px; }
  a.crumb { min-height: 44px; }
  .icon-btn, .mic, .pc-exit { width: 44px; height: 44px; }
  .checkbar .btn, .btn.small, .wordlist-head .btn { height: 44px; }
  .words-know { min-height: 44px; }
  /* Two buttons with their English line under them are wider than the row
     on Réglages: they take a line each rather than being cut off. */
  .setting-control { flex-wrap: wrap; }
  .seg > button { min-height: 44px; }
  .accent-key { min-width: 44px; height: 44px; }
  /* Under 480 px the settings icon leaves the top bar and this line is the
     only way to Réglages. The padding gives it a button's height and the
     margin takes that back out of the layout, so the footer reads as it did. */
  .foot-links a { display: inline-block; padding: 14px 8px; margin: -14px -8px; }

  /* What made the bar overflow on any page carrying a tally: six pills where
     there is room for four. TV is one of the five at the foot now, so the
     switch in the corner is a second way in to the same place; and the avatar
     says who is signed in without the name beside it. */
  #tvLink { display: none; }
  .chip-name { display: none; }
  /* Without a name beside it the chip is a round button, not a label, so its
     padding is even on both sides, not the wider hand it kept for the word
     that used to sit there. */
  .account-chip { padding: 0 6px; }
  /* And on a page that carries both chips, the run of days as well: it is on
     the hub, on the day's card and on its own tile, and the ring beside it is
     about the page the learner is on. */
  .streak-chip { display: none; }
}

/* Above 480 px the settings icon is back in the top bar (`#settingsLink`,
   above), which makes this line say twice what one tap already offers. It
   keeps its place under 480 px, where the icon has left and it is the only
   way to Réglages. */
@media (max-width: 700px) and (min-width: 481px) {
  .foot-links { display: none; }
}

/* At 360 px and under, an older phone or a large display-zoom setting, the
   count beside the ring is what has to go for the top bar to fit. The ring
   still says how far along the section is. On a page that also carries the
   ring (a lesson, a document, a list), the row was a hair too wide even
   after that and one of the round buttons was quietly squashed into an
   oval to make room: the fix is a little less air around the pills, not a
   shrinking button, so every pill stays a true circle. */
@media (max-width: 360px) {
  #progressLabel { display: none; }
  .progress-chip { padding: 0 8px; }
  .topbar { gap: 5px; padding-left: 10px; padding-right: 10px; }
  .accent-toggle, .progress-chip, #accountSlot { flex: none; }
}
