/* ============================================================
 * IntimPath app — consolidated global stylesheet
 * Source: frontend/intimpath_app/src/app/globals.css + all src/**/*.module.css
 * Assets resolved under /app (BASE_PATH). Plain global CSS (no Tailwind).
 * ============================================================ */

/* from app/globals.css */
/* Self-hosted Google Fonts (latin + latin-ext), downloaded from fonts.gstatic.com */
/* latin-ext */
@font-face {
  font-family: 'Faculty Glyphic';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/app/fonts/faculty-glyphic-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;
}
/* latin */
@font-face {
  font-family: 'Faculty Glyphic';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/app/fonts/faculty-glyphic-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;
}
/* latin-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/app/fonts/inter-latin-ext-367ba69a.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;
}
/* latin */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/app/fonts/inter-latin-bec94a4d.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;
}
/* latin-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/app/fonts/inter-latin-ext-367ba69a.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;
}
/* latin */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/app/fonts/inter-latin-bec94a4d.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;
}
/* latin-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/app/fonts/inter-latin-ext-367ba69a.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;
}
/* latin */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/app/fonts/inter-latin-bec94a4d.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;
}
/* latin-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/app/fonts/inter-latin-ext-367ba69a.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;
}
/* latin */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/app/fonts/inter-latin-bec94a4d.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;
}
/* latin-ext */
@font-face {
  font-family: 'Lora';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/app/fonts/lora-latin-ext-b74390d4.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;
}
/* latin */
@font-face {
  font-family: 'Lora';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/app/fonts/lora-latin-ba465564.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;
}
/* latin-ext */
@font-face {
  font-family: 'Lora';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/app/fonts/lora-latin-ext-b74390d4.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;
}
/* latin */
@font-face {
  font-family: 'Lora';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/app/fonts/lora-latin-ba465564.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;
}
/* latin-ext */
@font-face {
  font-family: 'Lora';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/app/fonts/lora-latin-ext-b74390d4.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;
}
/* latin */
@font-face {
  font-family: 'Lora';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/app/fonts/lora-latin-ba465564.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;
}
/* latin-ext */
@font-face {
  font-family: 'Lora';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/app/fonts/lora-latin-ext-b74390d4.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;
}
/* latin */
@font-face {
  font-family: 'Lora';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/app/fonts/lora-latin-ba465564.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;
}
/* latin-ext */
@font-face {
  font-family: 'Oswald';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/app/fonts/oswald-latin-ext-5930b85b.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;
}
/* latin */
@font-face {
  font-family: 'Oswald';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/app/fonts/oswald-latin-c27e7c11.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;
}
/* latin-ext */
@font-face {
  font-family: 'Oswald';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/app/fonts/oswald-latin-ext-5930b85b.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;
}
/* latin */
@font-face {
  font-family: 'Oswald';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/app/fonts/oswald-latin-c27e7c11.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;
}
/* latin-ext */
@font-face {
  font-family: 'Oswald';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/app/fonts/oswald-latin-ext-5930b85b.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;
}
/* latin */
@font-face {
  font-family: 'Oswald';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/app/fonts/oswald-latin-c27e7c11.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;
}

/* Space Grotesk — variable 400–700, self-hosted. Distinctive geometric
   grotesque used for headings, buttons, and big numbers. */
/* latin-ext */
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(/app/fonts/spacegrotesk-latinext.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;
}
/* latin */
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(/app/fonts/spacegrotesk-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;
}

/* Lato — brand font (self-hosted, latin + latin-ext, weights 400/700/900).
   CSS weight-matching maps Medium 500 -> 400, SemiBold 600 -> 700, ExtraBold 800 -> 900. */
@font-face {
  font-family: 'Lato'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(/app/fonts/lato-400-latinext.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;
}
@font-face {
  font-family: 'Lato'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(/app/fonts/lato-400-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: 'Lato'; font-style: normal; font-weight: 700; font-display: swap;
  src: url(/app/fonts/lato-700-latinext.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;
}
@font-face {
  font-family: 'Lato'; font-style: normal; font-weight: 700; font-display: swap;
  src: url(/app/fonts/lato-700-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: 'Lato'; font-style: normal; font-weight: 900; font-display: swap;
  src: url(/app/fonts/lato-900-latinext.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;
}
@font-face {
  font-family: 'Lato'; font-style: normal; font-weight: 900; font-display: swap;
  src: url(/app/fonts/lato-900-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;
}

:root {
  /* Dark theme */
  --bg-dark: #0E1011;
  --surface-dark: #1E2122;
  --surface-dark-2: #2A2D2E;
  --text-dark: #FFFFFF;
  --text-dark-muted: #B5B5B5;
  /* ================= BRAND PALETTE (Fonts_and_Colors style guide) =================
     PRIMARY:   Lime #BBF246 · Dark #192126
     GREYS:     #8B8F92 · #5E6468 · #384046 (text/icon scale) + #E0E1DE surface/frame
     SECONDARY: Purple #A48AED · Red #ED4747 */

  /* ============================ ПРОГРАММНЫЙ ЦВЕТ ============================
     Один токен на цвет активной программы: значения на каждую программу
     подставляет programThemeCssVars() (src/product/program-themes.js) из
     палитры редизайна — той же, что красит hero. Здесь — дефолт для экранов
     без программы (Explore, логин): лаймовый акцент бренда.

     Раньше на эту роль было ПЯТЬ имён: --accent-orange (со значением лайма),
     --accent-orange-hover, --shader-accent, --green-frame и
     --callout-green-frame; часть красилась из доредизайнового набора цветов,
     часть — из редизайнового, и у половины программ они расходились по тону
     (ромбы пунктов читалки Stay Firm были зелёными на оранжевой программе).
     Имена, которые врали о значении, убраны. */
  --program: #BBF246;              /* цвет активной программы (дефолт — лайм) */
  --program-hover: #ACE22F;        /* он же чуть темнее — hover у кнопок */
  --program-rgb: 187, 242, 70;     /* он же как r,g,b — для rgba() в градиентах колец */
  --program-tint: rgba(187, 242, 70, 0.20);  /* он же прозрачной подложкой: выноски, чипы */
  --program-ink: #192126;          /* текст, который лежит НА программном цвете */

  /* Secondary palette (available app-wide) */
  --color-purple: #A48AED;
  --color-red: #ED4747;
  --grey-mid: #8B8F92;
  --grey-dark: #5E6468;
  --grey-darker: #384046;

  /* Light theme — WHITE page. Flat design: cards/tiles are defined by a thin
     light-grey frame (--border-card), never by shadow. */
  --bg-light: #FFFFFF;
  --surface-light: #FFFFFF;
  --surface-beige: #E0E1DE;       /* light grey: secondary surfaces, chips, tracks, frames */
  --surface-tile: #F2F3F5;        /* подложка плиток на белом: иллюстрации упражнений, капсула MARK AS COMPLETE */
  --btn-dark: #192126;            /* тёмные капсульные кнопки: START WORKOUT, CONTINUE, SAVE */
  --text-light: #192126;          /* primary dark text */
  --text-light-muted: #5E6468;    /* grey for muted/secondary text */
  --border-light: #E0E1DE;
  --divider: #DADDE3;             /* волосяные линии-разделители строк и секций */
  /* Успех/ошибка — значения из иконок кружков читалки (circle-true.svg /
     circle-false.svg), теперь одни для всего приложения. */
  --success: #28840F;
  --error: #C51013;
  --border-card: #E0E1DE;         /* thin light-grey frame around flat cards/tiles */

  /* Badges / tags */
  --badge-burgundy: #ED4747;      /* SEXUAL HEALTH tags — red */
  --badge-gray: #E0E1DE;
  --badge-lime: #BBF246;          /* PREMIUM pill — лайм бренда, не цвет программы */

  /* CTAs / accents on light */
  --cta-dark: #192126;            /* dark CTA */

  /* Modern shape tokens (reference) */
  --radius-pill: 999px;
  --radius-card: 22px;
  /* Flat design — no depth. Kept as tokens so any consumer stays shadowless. */
  --shadow-soft: 0 4px 14px -8px rgba(20, 18, 14, 0.10);
  --shadow-card: 0 10px 26px -14px rgba(20, 18, 14, 0.12);

  /* Type families — reference is all clean sans, contrast via weight not serif.
     --font-serif kept as a token name (many modules reference it) but now maps
     to Inter so headings + lesson body read modern like the reference. */
  /* No 'Lato' in these stacks: it is a web font of its own, also declared
     font-display: swap, so as a fallback it added a second swap step (system →
     Lato → Faculty Glyphic), each one re-measuring the centred hero lines. App
     screens are Faculty Glyphic by design, so the fallback drops straight to
     the platform UI font. Nothing else references 'Lato', so its four files are
     no longer fetched on app screens at all. */
  --font-display: var(--font-display-nire), system-ui, -apple-system, sans-serif;
  --font-serif: var(--font-display-nire), system-ui, -apple-system, sans-serif;
  --font-sans: 'Faculty Glyphic', system-ui, -apple-system, sans-serif;
}

* {
  box-sizing: border-box;
  /* Системная тап-подсветка мобильных браузеров выключена везде разом:
     отклик нажатий у продукта свой (.is-pressed, app-press.ejs). */
  -webkit-tap-highlight-color: transparent;
}
html, body { margin: 0; padding: 0; }
body {
  background: var(--bg-light);
  color: var(--text-light);
  font-family: var(--font-sans);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
button { font-family: inherit; cursor: pointer; }
input { font-family: inherit; }
a { color: inherit; text-decoration: none; }

/* Mobile viewport frame */
.viewport {
  width: 100%;
  max-width: 375px;
  min-height: 100dvh;
  margin: 0 auto;
  position: relative;
  overflow-x: hidden;
}

/* Screens that run at the app's own content column instead of the player's
   375px: the lesson reader, matching Today and the program picker. */
.viewport.viewport-wide { max-width: 480px; }

/* ---------------------------------------------------------------------------
   Shared app controls. These are used by screens whose DOM is built in
   app-player.js, which cannot express :hover / :active in inline styles.
   --------------------------------------------------------------------------- */

/* Round top-bar button, measured off the reader toolbar in Figma (node
   170:6031): 44px white circle, glyph #192126, drop shadow y+8 blur 40 at 12%
   black. padding:0 because the UA's own button padding would shrink the content
   box and pull the glyph off centre. */
.appRoundBtn {
  /* No system grey tap plate — the .pressShrink scale is the press feedback.
     `manipulation` drops the double-tap-to-zoom wait so the press lands on the
     first frame (same treatment as the cards and the pill's arrows). */
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: #FFFFFF;
  color: #192126;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: 0 8px 40px rgba(0, 0, 0, 0.12);
}

/* Press feedback for round top-bar controls — the lesson cards' idea, rescaled:
   0.97 moves a 350px card ~5px per side, so a 44px control needs 0.92 to read
   as the same nudge. Fast in, slow out, because a tap holds for a few dozen ms
   (see the driver in partials/app-press.ejs). */
.pressShrink { transition: transform 260ms ease-out; }
.pressShrink:active,
.pressShrink.is-pressed {
  transform: scale(0.92);
  transition-duration: 90ms;
}

/* Primary CTA — #192126, the same near-black as the completed-lesson check on a
   Today card. Hover lifts it a shade; the press shrink matches the cards. */
.appCta {
  width: 100%;
  border: 0;
  border-radius: 999px;
  padding: 15px;
  background: var(--btn-dark);
  color: #FFFFFF;
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 15px;
  letter-spacing: 0.5px;
  cursor: pointer;
  transition: background-color 160ms ease, transform 260ms ease-out;
}
/* Gated on a real cursor. Touch engines leave :hover on the last element a
   finger landed on until the next tap lands elsewhere, so an ungated rule reads
   as "the button stayed lit after I pressed it" — and it survives a step change,
   because WebKit re-resolves hover against the last touch point and the new
   step's CTA sits under it. The press shrink is the touch feedback. */
@media (hover: hover) and (pointer: fine) {
  .appCta:hover { background: #2C363D; }
  .appCta[disabled]:hover { background: var(--btn-dark); }
}
.appCta:active,
.appCta.is-pressed {
  transform: scale(0.97);
  transition-duration: 160ms, 90ms;
}
.appCta[disabled] { opacity: 0.25; cursor: default; }

/* Reader entry: rises into place, the mirror of the program picker sliding down
   (same 437ms and easing). `backwards` and not `both` — a forwards fill would
   keep asserting transform:none afterwards and kill the CTA's press shrink. */
@keyframes appRiseIn {
  from { transform: translateY(100%); }
  to { transform: none; }
}
/* 360ms cubic-bezier(0.23, 0.84, 0.35, 0.97): fitted frame-by-frame to the
   Apple Fitness sheet presentation (60fps screen recording, two openings,
   max fit error <1% of travel) — near-4x speed off the line, long soft brake. */
.appRiseIn { animation: appRiseIn 360ms cubic-bezier(0.23, 0.84, 0.35, 0.97) backwards; }

/* Reader toolbar. Sticky inside the reader's scroll container, so content
   scrolls underneath; the background is solid white only down to the buttons'
   midline (32px = 10px padding + half of the 44px control), then dissolves to
   transparent over the remaining ~94px of the plate — the native-iOS bar
   treatment, with the fade reaching up under the controls themselves.
   The negative bottom margin gives back most of the fade tail, so at rest the
   content sits where it did with the shorter fade instead of dropping lower;
   scrolled content still dissolves through the full tail. pointer-events pass
   through everywhere but the two buttons, so the fade never eats a tap. */
.readerTopBar {
  --bar-solid: calc(32px + env(safe-area-inset-top, 0px));
  position: sticky;
  top: 0;
  z-index: 4;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  /* span the body's 24px side padding so the plate runs edge to edge */
  margin: 0 -24px -36px;
  padding: calc(10px + env(safe-area-inset-top, 0px)) 16px 48px;
  /* Solid to the buttons' midline (--bar-solid), then alpha falls along a
     smoothstep: the two-stop version had a slope discontinuity right where the
     fade began, which read as a hard line. */
  background: linear-gradient(to bottom,
    #FFFFFF var(--bar-solid),
    rgba(255, 255, 255, 0.94) calc(var(--bar-solid) + (100% - var(--bar-solid)) * 0.15),
    rgba(255, 255, 255, 0.78) calc(var(--bar-solid) + (100% - var(--bar-solid)) * 0.3),
    rgba(255, 255, 255, 0.57) calc(var(--bar-solid) + (100% - var(--bar-solid)) * 0.45),
    rgba(255, 255, 255, 0.35) calc(var(--bar-solid) + (100% - var(--bar-solid)) * 0.6),
    rgba(255, 255, 255, 0.16) calc(var(--bar-solid) + (100% - var(--bar-solid)) * 0.75),
    rgba(255, 255, 255, 0.03) calc(var(--bar-solid) + (100% - var(--bar-solid)) * 0.9),
    rgba(255, 255, 255, 0) 100%);
  pointer-events: none;
}
.readerTopBar .appRoundBtn { pointer-events: auto; }

/* The reader's pinned CTA bar. Solid background-color on the fixed element, not
   a transparent-to-white gradient: iOS Safari tints its bottom chrome from the
   fixed element at the bottom edge, and with only a gradient image there it
   picked the dark CTA button instead — the browser's bottom bar went black. The
   scroll-under dissolve the gradient used to provide is the ::before tail. */
.readerCtaBar {
  position: relative;   /* the overlay-guide (non-fixed) case; inline fixed wins otherwise */
  /* No top padding: the solid plate begins at the button's own top edge, which
     is as low as the plate can start while staying a solid background-color
     (the thing iOS samples for its bottom chrome) — a plate that started lower
     would clip the scroll-under dissolve against the button row. */
  padding: 0 24px 20px;
  background: #FFFFFF;
}
.readerCtaBar::before {
  content: '';
  position: absolute;
  bottom: 100%;
  left: 0;
  right: 0;
  height: 34px;
  background: linear-gradient(to bottom,
    rgba(255, 255, 255, 0),
    rgba(255, 255, 255, 0.57) 45%,
    rgba(255, 255, 255, 0.94) 85%,
    #FFFFFF);
  pointer-events: none;
}

/* Step-change wave inside the reader: the stage hop's animation verbatim (same
   keyframes, 20px offset, 300ms, 36ms stagger). --stage-dx and per-child --i are
   set by the renderer; `backwards` for the same reason as everywhere else. */
.readerStepIn > * {
  animation: stageCardEnter 300ms cubic-bezier(0.4, 0, 0.6, 1) backwards;
  animation-delay: calc(var(--i, 0) * 36ms);
}
/* Блок, который открывается после выбора ответа (revealAfter). Своя анимация,
   а не наследование волны шага: волна висит на .readerStepIn, а этот класс есть
   только если на шаг пришли переходом. Если читалка открылась СРАЗУ на шаге с
   выбором (первый шаг потока — так в Stay Firm), волны нет, и подсказка
   появлялась рывком, тогда как в Lasting Longer выезжала. Теперь одинаково
   везде: та же кривая, длительность и сдвиг, что у элементов волны, без
   ступенчатой задержки — блок один. */
.readerReveal,
.readerStepIn > .readerReveal {
  /* Своя кривая и сдвиг: приезжает СНИЗУ вверх (у волны шага сдвиг
     горизонтальный), фейд тот же. */
  animation: readerRevealIn 300ms cubic-bezier(0.4, 0, 0.6, 1) backwards;
  animation-delay: 0ms;
}
@keyframes readerRevealIn {
  from { opacity: 0; transform: translateY(20px); }
  to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .readerStepIn > * { animation: none; }
  .readerReveal, .readerStepIn > .readerReveal { animation: none; }
}

/* The reader opened over Today rather than navigated to (see
   public/js/app-reader-overlay.js). The host is what slides, so the ground it
   rises over — the Today screen — stays visible underneath, which is the whole
   point: on a real navigation there is no previous page left to rise over. */
.readerOverlay {
  position: fixed;
  inset: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 100%;
  max-width: 480px;
  background: #FFFFFF;
  overflow: hidden;
  z-index: 60;
}
/* Its own keyframes, not .appRiseIn: this element is centred with
   translateX(-50%), and a keyframe that animates plain translateY would drop the
   centring for the length of the slide. */
@keyframes readerOverlayIn {
  from { transform: translate(-50%, 100%); }
  to { transform: translate(-50%, 0); }
}
@keyframes readerOverlayOut {
  from { transform: translate(-50%, 0); }
  to { transform: translate(-50%, 100%); }
}
/* Entry curve измерена покадрово с плеера Apple TV (эталон —
   ScreenRecording_08-16-2026 06-26-48, где низ экрана светлый и кромка листа
   читается без искажений). Полный ход 258мс; хвост короткий — последние 5%
   пути за ~16мс против ~100мс у прежней кривой (360мс, cubic-bezier). Это
   важно не только для ощущения: при входе снизу верхняя кромка листа доезжает
   до статус-бара последней, и Safari может перекрасить бар только в конце пути
   (сам он срабатывает за один кадр — замерено). Чем короче хвост, тем раньше
   меняется цвет. cubic-bezier в шорткате — запасной вариант для движков без
   linear(). */
.readerOverlay.readerOverlayIn {
  animation: readerOverlayIn 258ms cubic-bezier(0.32, 0.74, 0.35, 1) backwards;
  animation-timing-function: linear(0, 0.0416, 0.1325, 0.2437, 0.3633, 0.4998,
    0.5714, 0.6575, 0.7319, 0.7939, 0.8451, 0.8884, 0.9208, 0.9476, 0.9692,
    0.9864, 1);
}
.readerOverlay.readerOverlayOut { animation: readerOverlayOut 437ms cubic-bezier(0.4, 0, 0.6, 1) forwards; }

/* Контент приезжающего листа проявляется своей анимацией, а не едет вместе с
   ним. Замерено покадрово со Spotify (ScreenRecording_08-16-2026 06-35-59):
   контент держит нулевую непрозрачность, пока лист проходит ~72% пути, затем
   набирает её и доходит до единицы примерно в момент приземления. Движения у
   контента нет вовсе — сверка положения с финальным кадром даёт сдвиг 0 при
   корреляции 1.000, то есть чистая прозрачность. Кривая набора — с ускорением:
   за первую половину времени только 38%.

   Класс вешается ОДИН раз на внутренний лист при монтировании (см.
   app-reader-overlay.js), а не селектором от хоста: читалка пересоздаёт свой
   <main> на каждом шаге, и правило от класса хоста переигрывало бы фейд при
   каждом листании. Хост при этом остаётся сплошным — именно его Safari
   сэмплирует в статус-бар.

   Тайминги задаются переменными. Пауза пропорциональна ходу листа: снизу вверх
   он едет 258мс, и 125мс — это те же ~72% пути, что в референсе. Длительность
   же взята одинаковой для обоих направлений (234мс, число из референса) —
   решение Игоря от 2026-08-16: пропорциональный пересчёт давал 155мс, и фейд
   читался как более резкий, чем в горизонтальном варианте. Горизонтальный пуш
   длится те же 517мс, что и референс, и берёт его числа как есть (переменные
   переопределяются на его странице). */
@keyframes readerContentIn {
  from { opacity: 0; }
  to { opacity: 1; }
}
.readerContentIn {
  animation: readerContentIn var(--content-fade-dur, 234ms) var(--content-fade-delay, 125ms) backwards;
  animation-timing-function: linear(0, 0.051, 0.113, 0.192, 0.258, 0.383, 0.45,
    0.571, 0.708, 0.808, 1);
}

@media (prefers-reduced-motion: reduce) {
  .readerContentIn { animation: none; }
  .readerOverlay.readerOverlayIn, .readerOverlay.readerOverlayOut { animation: none; }
}

/* ---------------------------------------------------------------------------
   Блоки контента читалки.

   Разметку строит renderBlock() в app-player.js по данным (kind: text, dashRow,
   illustration …), поэтому одна правка здесь меняет верстку ВО ВСЕХ читалках —
   и на отдельных страницах, и в оверлее поверх Today, и в гайде внутри
   тренировки. Классы намеренно НЕ привязаны к body-классу: у этих трёх мест
   body разный (m-lessonflowscreen / m-todayscreen / экран плеера). Тот же
   приём, что у .readerTopBar, .readerCtaBar и .appCta выше.

   Стили держим здесь, а не в инлайнах JS: правки верстки перестают трогать
   app-player.js — файл общий и активно правится, и чем меньше мы в нём
   двигаем, тем дешевле слияния.
   --------------------------------------------------------------------------- */
.readerH2 {
  font-size: 28px;
  font-weight: 400;
  margin-bottom: 16px;
}
.readerText {
  font-size: 16px;
  line-height: 1.55;
  color: var(--text-light-muted);
  margin-bottom: 20px;
}

/* Элемент списка: ромбовидная точка + подпись, под ними пояснение. */
.readerBullet {
  display: flex;
  gap: 10px;
  margin-bottom: 16px;
}
.readerBulletHead {
  display: flex;
  gap: 10px;
  /* Ромб стоит в первую строку подписи, как если бы строка была одна:
     центрирование по высоте уводило его в середину многострочного пункта. */
  align-items: flex-start;
  line-height: 1.55;
}
/* Ромб 6×6 из Figma (dot-romb, node 74:13010). Через mask, а не <img>: файл
   остаётся единственным источником формы, но цвет берётся из темы программы —
   тот же токен, которым красилась прежняя черточка. */
.readerBulletDot {
  flex: 0 0 auto;
  width: 6px;
  height: 6px;
  background-color: var(--program, #BBF246);
  -webkit-mask: url('/app/images/dot-romb.svg') center / 6px 6px no-repeat;
  mask: url('/app/images/dot-romb.svg') center / 6px 6px no-repeat;
}
/* Вариант без подписи: точка стоит в строку с первой строкой абзаца, поэтому
   опускается на половину строки минус половина ромба — одинаково в пункте без
   подписи и в подписи с переносами. Число считается от РЕДИЗАЙНОВОЙ типографики
   читалки (16px × 1.55 = 24.8 ⇒ 12.4 − 3 = 9.4); прежние 8px в dev посчитаны от
   старых 15px × 1.5, которых здесь больше нет. */
.readerBullet > .readerBulletDot,
.readerBulletHead > .readerBulletDot { margin-top: 9.4px; }
/* Из dev (fix/app-reader-bullet-alignment): браузерный 1em у абзаца сдвигал
   текст на целую строку ниже точки, и margin-top у точки это не компенсировал.
   Обнуляем только абзац БЕЗ подписи — селектор `.readerBullet > p` бил и по
   .readerBulletText (он тоже прямой ребёнок, но специфичнее на тип) и съедал её
   margin-top: 4px, то есть зазор между подписью и пояснением. */
.readerBullet > p:not(.readerBulletText) { margin: 0; }
/* Отступ пояснения равен ширине точки плюс зазор — текст встаёт ровно под
   подписью. */
.readerBulletText {
  font-size: 16px;
  line-height: 1.55;
  color: var(--text-light-muted);
  margin-top: 4px;
  padding-left: 16px;
}

.readerFigure {
  /* 26 — общий радиус карточек редизайна (Explore, пикер, аудиокарточка);
     правка Игоря 29.08, было 20. */
  border-radius: 26px;
  margin-top: 32px;
  margin-bottom: 32px;
}

/* Подсказка на плашке. Тон тот же, что у пилюли Optional на карточке Today:
   цвет программы на 12%, без обводки. Абзацы внутри не имеют своих отступов —
   padding плашки должен читаться одинаково со всех четырёх сторон, — поэтому
   многоабзацные подсказки разделяются gap'ом колонки. */
.readerCallout {
  background: color-mix(in srgb, var(--program, #0365BB) 12%, transparent);
  border: 0;
  border-radius: 20px;
  padding: 16px 20px;
  margin-bottom: 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.readerCalloutText {
  font-size: 16px;
  line-height: 1.55;
  margin: 0;
  color: var(--program, #192126);
}

/* Надзаголовок капсом над списком. Цвет — программный: тот же токен, что у
   плашки подсказки и ромба в списке. Прежний #D98032 остаётся запасным на
   случай, если экран отрисован вне программы (токен не задан). */
.readerSectionLabel {
  font-size: 14px;
  line-height: 1.5;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  color: var(--program, #D98032);
  margin-bottom: 16px;
}

/* Строка «делай / не делай»: иконка + подпись, под ней необязательное
   пояснение. Иконки двухцветные, поэтому картинкой, а не маской. */
.readerCheckRow {
  display: flex;
  gap: 10px;
  margin-bottom: 16px;
  font-size: 16px;
  line-height: 1.55;
}
.readerCheckIcon {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  /* центрируем по первой строке: (16 × 1.55 − 16) / 2 */
  margin-top: 4.4px;
  background: center / 16px 16px no-repeat;
}
.readerCheckIcon.is-no { background-image: url('/app/images/circle-false.svg'); }
.readerCheckIcon.is-yes { background-image: url('/app/images/circle-true.svg'); }
.readerCheckNote {
  font-size: 16px;
  line-height: 1.55;
  margin-top: 4px;
  color: var(--text-light-muted);
}
/* Зазор между пунктами держит САМ РЯД (.readerBullet и .readerCheckRow, у обоих
   margin-bottom: 16px). Абзацы внутри ряда своего нижнего отступа иметь не
   должны: браузерный дефолт 1em никто не объявлял, и у пунктов с пояснением
   зазор удваивался — 16 от ряда плюс 16 от абзаца (замер: .readerCheckNote и
   .readerBulletText отдавали computed 4px/16px). Правило общее, а не точечное
   по классам: пункты БЕЗ пояснения от него не меняются (у них зазор и раньше
   приходил только от ряда), поэтому одна страница не может «починиться» за счёт
   другой. По контенту всех программ это 86 пунктов-галочек и 104 пункта-ромба
   с пояснением на 48 шагах из 3243. */
.readerBullet p,
.readerCheckRow p {
  margin-bottom: 0;
}

/* Круглая кнопка поверх кадра: та же геометрия, но подложка — белый на 12%,
   глиф белый, тени нет (на видео она читалась бы грязным пятном). */
/* Кнопки поверх кадра — в тулбаре и в транспорте — выглядят одинаково: белая
   подложка на 12% и размытие кадра под ней, иначе на пёстром месте ролика глиф
   теряется. */
.appRoundBtn.onMedia,
.playerPlay,
.playerSkip {
  position: relative;
  background: rgba(255, 255, 255, 0.12);
  color: #FFFFFF;
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
}
/* Плашка светлее кадра ровно на свой белый 12%, поэтому на светлом кадре её
   край и белое кольцо пропадают вместе. Мягкая внешняя тень обозначает край
   именно там, где кольцо перестаёт работать: кольцо держит тёмный кадр,
   тень — светлый. */
.appRoundBtn.onMedia,
.playerPlay,
.playerSkip {
  box-shadow: 0 2px 24px rgba(0, 0, 0, 0.10);
}

/* Тот же расчёт, но для самого глифа: он чисто белый, а подложка под ним —
   осветлённый кадр, так что затемнять кадр бесполезно (плашка светлеет вместе
   с ним). Читаемость на любом кадре даёт только собственный тёмный ореол по
   контуру формы. У перемотки фильтр висит на обёртке — накрывает и стрелку,
   и цифру одним проходом. */
.appRoundBtn.onMedia svg,
.playerPlay svg,
.playerPlay img,
.playerSkipArt {
  filter: drop-shadow(0 1px 8px rgba(0, 0, 0, 0.20));
}

/* Кнопка Play/Pause медиакарточки читалки — одна на аудио и видео. Плашка
   ЗЕРКАЛЬНА плеерной: там белый 12% поверх тёмного ролика, здесь тёмный поверх
   светлой картинки (аудиокарточки показывают волну на белом), иначе белый глиф
   не читался бы; на кадре видео тёмная плашка работает тем же образом. Кольцо, размытие и отклик нажатия — общие с транспортом плеера:
   селектор добавлен в правило кольца выше, глиф — те же play.svg / pause.svg. */
.readerMediaBtn {
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  position: relative;
  /* 80 с глифом 50 — выбор Игоря 30.08. Подложка, размытие, кольцо и тень те
     же, что у кнопки Play в плеере: обложка теперь тёмная (волна на чёрном),
     и прежняя тёмная плашка на ней не читалась. */
  width: 80px;
  height: 80px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.12);
  color: #FFFFFF;
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  box-shadow: 0 2px 24px rgba(0, 0, 0, 0.10);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.readerMediaBtn img { filter: drop-shadow(0 1px 8px rgba(0, 0, 0, 0.20)); }
.readerMediaBtn:active, .readerMediaBtn.is-pressed {
  background-color: rgba(255, 255, 255, 0.22);
}

/* Отклик медиакарточки: БЕЗ сжатия (правка Игоря 30.08) — темнеет только
   подложка нижнего текстового блока. */
.readerMediaCap {
  background: #FFFFFF;
  transition: background-color 220ms ease-out;
}
.readerMediaCard.is-pressed .readerMediaCap,
.readerMediaCard:active .readerMediaCap {
  background-color: var(--surface-tile, #F2F3F5);
  transition-duration: 90ms;
}

/* Тот же приём, что у пилюли стейджей на Today (.m-todayscreen .dayPill::before):
   1px-кольцо рисует псевдоэлемент — градиентная заливка, замаскированная в
   область рамки, потому что border-image не умеет следовать border-radius.
   Стопы приглушены до 0.40/0.10/0.40: поверх кадра ролика кольцо должно
   обозначать край плашки, а не спорить с ней. */
.appRoundBtn.onMedia::before,
.playerPlay::before,
.playerSkip::before,
.readerMediaBtn::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  padding: 1px;
  background: linear-gradient(135deg,
    rgba(255, 255, 255, 0.35) 0%,
    rgba(255, 255, 255, 0.05) 55%,
    rgba(255, 255, 255, 0.25) 100%);
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  mask-composite: exclude;
  pointer-events: none;
}

/* Транспорт по центру кадра: перемотка −15, play, перемотка +15. */
.playerTransport {
  position: absolute;
  top: 50%;
  left: 0;
  right: 0;
  transform: translateY(-50%);
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 24px;
  pointer-events: none;
}
.playerTransport > * { pointer-events: auto; }
.playerPlay {
  width: 92px;
  height: 92px;
  border: 0;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
.playerSkip {
  width: 64px;
  height: 64px;
  border: 0;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
/* Перемотка ±15: цифра и направление вшиты в сам арт (seconds-back/forward.svg
   из сета Faculty) — ни отдельного номера, ни зеркала больше нет. */
.playerSkipArt {
  position: relative;
  width: 38px;
  height: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Подпись у нижней кромки: подзаголовок над заголовком. Отступ снизу тот же,
   что по бокам, плюс safe-area — иначе текст уезжает под системную полоску. */
.playerCaption {
  position: relative;
  margin-top: auto;
  z-index: 2;
  /* Снизу 32, а не 24: под подписью теперь полоса прокрутки и счётчики
     времени, и прежний отступ прижимал их к кромке (правка Игоря 29.08). */
  padding: 24px 24px calc(32px + env(safe-area-inset-bottom, 0px));
}
.playerSubtitle {
  font-size: 14px;
  opacity: 0.8;
  margin: 0 0 4px;
}
.playerTitle {
  font-size: 24px;
  font-weight: 400;
  margin: 0;
}

/* Интерфейс плеера поверх кадра: прячется и возвращается по тапу (обработчик
   в unlockGuide). pointer-events снимаются, чтобы скрытые кнопки не ловили
   нажатия. */
.playerChrome {
  transition: opacity 200ms ease;
}
.chromeHidden .playerChrome {
  opacity: 0;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .playerChrome { transition: none; }
}

/* Шапка поверх видео (гайд «Unlock Your Pelvic Floor»): те же круглые кнопки,
   что в читалке, но без белого растворения — под ними кадр, а не текст, — и без
   блока с названием: слева выход, справа звук. */
.playerTopBar {
  /* fixed, а не relative — и это не косметика. Замерено стендом /probe/
     (раунд 3, iOS 18.7): статус-бар красит ТОЛЬКО короткая фиксированная
     полоса, прижатая к верхней кромке. Чёрный fixed-экран во весь экран его не
     красит, полоса position: relative внутри экрана — тоже, и sticky (как в
     тулбаре читалки) — тоже. Рабочий вариант сработал за 66мс.
     Поэтому полоса живёт отдельно от кнопок: кнопки прячутся по тапу, а она
     остаётся, иначе бар вернулся бы к цвету страницы посреди ролика.
     left/right/margin держат её внутри 480-колонки на десктопе — fixed иначе
     растянулся бы на всё окно. */
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  margin: 0 auto;
  max-width: 480px;
  z-index: 3;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  padding: calc(10px + env(safe-area-inset-top, 0px)) 16px 40px;
  /* Сплошного участка ровно столько, сколько нужно статус-бару — 4px у самой
     кромки; дальше сход по квадратичному ease-out ((1−t)²). Smoothstep, взятый
     было с пикера, здесь не подошёл: на высокой плашке его крутая середина
     давала видимую ступень на ~2/3 от низа поверх видео. У ease-out крутизна
     сосредоточена у верха (прячется на сплошном чёрном), а хвост длинный и
     сходит в ноль без перелома. Двухстоповый вариант не годился ещё раньше —
     перелом в начале растворения читался как резкая кромка (как в
     .readerTopBar). Плашки до середины кнопок, как в читалке, тут нет —
     под градиентом кадр, а не текст. */
  background: linear-gradient(to bottom,
    #000000 calc(4px + env(safe-area-inset-top, 0px)),
    rgba(0, 0, 0, 0.77) 16%,
    rgba(0, 0, 0, 0.56) 28%,
    rgba(0, 0, 0, 0.39) 40%,
    rgba(0, 0, 0, 0.25) 52%,
    rgba(0, 0, 0, 0.14) 64%,
    rgba(0, 0, 0, 0.06) 76%,
    rgba(0, 0, 0, 0.02) 88%,
    rgba(0, 0, 0, 0) 100%);
  pointer-events: none;
}

/* Полоса — fixed и потому вне потока своей колонки: в 375-м экране её надо
   сузить руками, иначе встанет по 480-й и уведёт кнопки за край.
   Комбинатор строго дочерний: класс .viewport висит и на <body> сессий, и
   потомковый селектор ловил бы через него даже 480-е экраны. */
.viewport:not(.viewport-wide) > .playerTopBar { max-width: 375px; }
/* В настоящем fullscreen колонки нет: UA-стиль снимает max-width с самого
   экрана через !important, а полоса — fixed, её содержащий блок остаётся окном.
   Она бы осталась в 480-й колонке по центру, пока кадр занимает весь экран, —
   поэтому ограничение снимаем и с неё. Стандартный и -webkit- варианты разнесены
   намеренно: незнакомый псевдокласс в общем списке селекторов уронил бы правило
   целиком. */
.viewport:fullscreen > .playerTopBar { max-width: none; }
.viewport:-webkit-full-screen > .playerTopBar { max-width: none; }
.playerTopBar > * { pointer-events: auto; }
/* Левая группа тулбара: динамик и (у видео) фуллскрин. Figma 500:7897 — две
   круглые кнопки 44 с зазором 12. */
.playerTopLeft {
  display: flex;
  align-items: center;
  gap: 12px;
}

/* ===========================================================================
   Транспорт плеера: отклик нажатия, оборот стрелки, смена глифа play/pause.
   Всё замерено покадрово с референса Игоря (ScreenRecording 08-29 18-40-42,
   120 к/с — 8.3мс на кадр): подложка светлеет 19→45 из 255 за ~50мс и
   возвращается к ~275мс; стрелка делает ПОЛНЫЙ оборот за ~170мс с сильным
   ease-out, цифра при этом неподвижна; старый глиф уходит сжимаясь (провал на
   +50мс), новый приходит с перелётом до 1.09 на +200мс и садится к +300мс.
   Единственное, что из референса НЕ берём — там кнопка на нажатии растёт,
   у нас она по-прежнему уменьшается (решение Игоря 29.08).
   =========================================================================== */

/* Отклик у транспорта глубже общих 0.92: кнопки крупные, и на них мелкий вжим
   почти не читается. Заодно на время нажатия светлеет подложка. */
.playerPlay,
.playerSkip {
  transition: transform 260ms ease-out, background-color 220ms ease-out;
}
/* Глифы — это <img>, и долгое нажатие поднимало системное меню картинки
   («Share… / Save to Photos», скриншот Игоря 30.08). Гасим и меню, и
   выделение, и нативный драг — тем же набором, что у иконки самопроверки. */
.playerPlay,
.playerSkip,
.playerTopBar button,
.playerGlyph,
.playerSkipArt,
.playerSkipArc,
.playerSkipNum {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}
.playerGlyph,
.playerSkipArc,
.playerSkipNum {
  -webkit-user-drag: none;
  pointer-events: none;
}
.playerPlay:active, .playerPlay.is-pressed,
.playerSkip:active, .playerSkip.is-pressed {
  transform: scale(0.86);
  background-color: rgba(255, 255, 255, 0.22);
  transition-duration: 90ms;
}

/* Та же подсветка подложки — у ВСЕХ кнопок поверх кадра во всех плеерах
   (правка Игоря 30.08): круглые кнопки тулбара, пилюля GUIDE, пилюля
   плейлиста, тёмная пилюля Play/Pause таймерного плеера. Глубина вжима у них
   своя — здесь меняется только фон. */
.appRoundBtn.onMedia,
.ktPill,
.ktListBtn,
.tpPill:not(.tpPillSolid) {
  transition: transform 260ms ease-out, background-color 220ms ease-out;
}
.appRoundBtn.onMedia:active, .appRoundBtn.onMedia.is-pressed,
.ktPill:active, .ktPill.is-pressed,
.ktListBtn:active, .ktListBtn.is-pressed,
.tpPill:not(.tpPillSolid):active, .tpPill:not(.tpPillSolid).is-pressed {
  background-color: rgba(255, 255, 255, 0.22);
  transition-duration: 90ms;
}
/* Белые кнопки плеера (Done / Ready, CONTINUE на тёмном) светлеть не могут —
   их подложку на нажатии, наоборот, слегка притемняем. */
.tpPill.tpPillSolid,
.appCta.ctaOnDark {
  transition: transform 260ms ease-out, background-color 220ms ease-out;
}
.tpPill.tpPillSolid:active, .tpPill.tpPillSolid.is-pressed,
.appCta.ctaOnDark:active, .appCta.ctaOnDark.is-pressed {
  background-color: #E2E2E2;
  transition-duration: 90ms;
}

/* Дуга и цифра — два слоя друг над другом: крутится только дуга. Поворот идёт
   трансформом по своему слою (GPU), вектор при этом не перерисовывается. */
.playerSkipArc,
.playerSkipNum {
  position: absolute;
  left: 0;
  top: 0;
}
/* will-change держим только на время оборота — постоянный слой ради 170мс
   анимации не нужен. */
.playerSkipArc.spinBack,
.playerSkipArc.spinFwd { will-change: transform; }
@keyframes playerSpinBack { from { transform: rotate(0deg); } to { transform: rotate(-360deg); } }
@keyframes playerSpinFwd  { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
/* 320мс вместо замеренных с референса 170: дуга почти симметрична, видно
   только стрелку, и на 60Гц короткий оборот читался дрожью. Кривая —
   НЕсимметричная ease-in-out: разгон занимает примерно треть времени,
   торможение — две трети (то же соотношение, что у волны на экране
   результата самопроверки). Чистый ease-out не годился: старт был мгновенным
   и глазом не читался вовсе, видна была только вторая половина пути. */
.playerSkipArc.spinBack { animation: playerSpinBack 320ms cubic-bezier(0.25, 0, 0.5, 1); }
.playerSkipArc.spinFwd  { animation: playerSpinFwd  320ms cubic-bezier(0.25, 0, 0.5, 1); }

/* Глифы play/pause лежат стопкой, чтобы смена шла кроссфейдом без «моргания»
   пустой кнопки. Уход — быстрый и сжимающийся, приход — с пружиной. */
.playerGlyph {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}
@keyframes playerGlyphIn {
  from { opacity: 0; transform: translate(-50%, -50%) scale(0.4); }
  55%  { opacity: 1; }
  to   { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}
@keyframes playerGlyphOut {
  from { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  to   { opacity: 0; transform: translate(-50%, -50%) scale(0.3); }
}
/* backwards, а не both: завершённая анимация с both держала бы конечное
   значение сильнее обычных правил (грабля из part2). */
.playerGlyphIn  { animation: playerGlyphIn 200ms cubic-bezier(0.34, 1.56, 0.64, 1) 25ms backwards; }
.playerGlyphOut { animation: playerGlyphOut 90ms ease-in forwards; }

@media (prefers-reduced-motion: reduce) {
  .playerSkipArc.spinBack, .playerSkipArc.spinFwd,
  .playerGlyphIn, .playerGlyphOut { animation: none; }
}

/* Полоса прокрутки и счётчики времени под подписью плеера (Figma 500:7897:
   полоса 6px через 20 после заголовка, время 11px/1.1 через 8 после полосы).
   Радиус не 20, а 999 — полоса должна оставаться полностью скруглённой при
   любой высоте. Зона нажатия шире полосы: в 6px пальцем не попасть, поэтому
   тянут за обёртку с вертикальным паддингом, а отступы пересчитаны с его
   учётом (8 + 12 = 20 сверху; 12 − 4 = 8 снизу). */
.playerScrubHit {
  padding: 12px 0;
  margin-top: 8px;
  cursor: pointer;
  touch-action: none;
}
.playerScrub {
  position: relative;
  height: 6px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.3);
}
.playerScrubFill {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 0;
  border-radius: 999px;
  background: #FFFFFF;
}
.playerTimes {
  display: flex;
  justify-content: space-between;
  margin-top: -4px;
}
.playerTime {
  font-size: 11px;
  line-height: 1.1;
  color: #FFFFFF;
}

/* Ячейка одиночного выбора в читалке (блок option). Обводка — волосяная в
   цвете разделителей; выбор помечается ТОЛЬКО галочкой и обводкой в цвете
   программы: фон и цвет текста не меняются (решение Игоря 22.08). */
.readerOpt {
  /* relative — под градиентную обводку выбранного состояния (::before ниже). */
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  text-align: left;
  padding: 16px;
  margin-bottom: 10px;
  border-radius: 16px;
  border: 1px solid var(--divider, #DADDE3);
  background: #FFFFFF;
  color: var(--text-light, #192126);
  font-size: 16px;
  line-height: 1.55;
  font-weight: 400;
  cursor: pointer;
  /* Отклик нажатия той же глубины, что у карточек Today (0.97), но НЕ их
     таймингами: рядом с пружинистой галочкой возврат за 260мс плавным ease-out
     читался заторможенным (замер по видео: вжим 83мс, возврат ~200мс ровным
     спадом). Возврат отдан той же кривой, что и bounce галочки — easeOutBack с
     перелётом ≈12% хода: у иконки в референсе нормированный ход даёт 0.86 к
     50мс, пик 1.14 к 100мс и оседание к 283мс. Длительности подрезаны против
     референса (возврат 220мс вместо 283) — ход у ячейки короче иконного, и на
     нём та же кривая читается бодрее. Вжим глубже карточек Today (0.955 против
     0.97) и быстрее: на трёх процентах хода движение не успевало прочитаться и
     выглядело вялым, сколько бы миллисекунд ему ни давали. */
  transition: transform 220ms cubic-bezier(0.34, 1.56, 0.64, 1);
  touch-action: manipulation;
}
.readerOpt:active,
.readerOpt.is-pressed {
  transform: scale(0.955);
  /* 30мс: удержания у этих ячеек нет, поэтому вжим должен успеть дойти до дна
     заведомо раньше, чем палец отпущен (тап — 60мс и больше). */
  transition: transform 30ms cubic-bezier(0.3, 0, 0.2, 1);
}
/* Выбранная ячейка: обводка тем же градиентом, что на экране «YOU'RE GREAT!»
   (.finOpt.is-picked) — решение Игоря 30.08; до этого стоял плоский цвет
   программы. Рисует псевдоэлемент: border-image не следует border-radius.
   Ячейке добавлен position: relative — без него обводка считалась бы от
   ближайшего позиционированного предка. */
.readerOpt.is-picked { border-color: transparent; }
.readerOpt.is-picked::before {
  content: '';
  position: absolute;
  inset: -1px;
  border-radius: 16px;
  padding: 1px;
  background: linear-gradient(90deg, #03AFEC 0%, #057CD6 12%, #5987F3 25%,
    #9D7CEE 40%, #BA71D9 52%, #CB6AC4 64%, #DC64A2 80%, #E8645F 100%);
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  mask-composite: exclude;
  pointer-events: none;
}
.readerOpt[disabled] { cursor: default; }
/* Кружок: обводка того же цвета, что у ячейки. В выбранном состоянии на его
   месте — тёмная галочка карточек Today (.circleCheck), уменьшенная 28 → 24,
   глиф масштабирован в той же пропорции (16 / 28). */
.readerOptMark {
  flex: 0 0 auto;
  /* Слой постоянный — см. пояснение у иконок таббара. */
  will-change: transform;
  backface-visibility: hidden;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  border: 2px solid var(--divider, #DADDE3);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #FFFFFF;
}
/* Тёмный кружок с галочкой включается СВОИМ классом, а не через .is-picked:
   обводка ячейки перекрашивается сразу по нажатию, а галочка выходит чуть
   позже — плашка успевает начать возврат (задержка в app-player.js). */
.readerOptMark.is-on {
  border-color: transparent;
  background: var(--btn-dark, #192126);
}
/* Галочка отыгрывает bounce в момент отпускания пальца. Точки сняты покадрово
   с иконок таббара (видео Игоря ScreenRecording 08-22 15-59-54, 60 к/с; там
   иконки 68–73px при DPR 3, т.е. те же ~23 CSS px, что и наш кружок): от 0.80
   быстрый подъём, перелёт +2.8% к 100мс, оседание к 283мс. Между точками
   linear — кривая уже в самих точках. */
@keyframes springPop {
  0% { transform: scale(0.80); }
  8% { transform: scale(0.88); }
  20% { transform: scale(1.006); }
  30% { transform: scale(1.039); }
  38% { transform: scale(1.06); }
  55% { transform: scale(1.039); }
  70% { transform: scale(1.009); }
  85% { transform: scale(0.997); }
  100% { transform: scale(1); }
}
.readerOptMark.pop { animation: springPop 260ms linear; }

/* Подзаголовок внутри шага («Question 1», «1. Physiological aspects»). */
.readerSubhead {
  font-size: 20px;
  font-weight: 400;
  margin: 24px 0 12px;
}

/* Квиз. Ячейки — как ячейки выбора: белый фон, волосяная обводка в цвете
   разделителей, радиус 16. После ответа меняется только цвет обводки; ширина
   остаётся 1px, чтобы содержимое не дёргалось. */
.readerQuiz { margin-bottom: 16px; }
.readerQuizPrompt {
  font-size: 16px;
  line-height: 1.55;
  margin: 0 0 16px;
  color: var(--text-light-muted);
}
.readerQuizOpt {
  display: block;
  width: 100%;
  text-align: left;
  padding: 16px;
  margin-bottom: 10px;
  border-radius: 16px;
  border: 1px solid var(--divider, #DADDE3);
  background: #FFFFFF;
  color: var(--text-light, #192126);
  font-family: inherit;
  font-weight: 400;
  font-size: 16px;
  line-height: 1.55;
  cursor: pointer;
  /* Обводка перекрашивается плавно — вместе с раскрытием ячейки. */
  transition: border-color 180ms ease-out;
}
/* Раскрытие правильной ячейки: высоту ведёт JS от замеренной «до» к «после»
   (от auto анимировать нельзя), здесь только кривая и длительность. */
.readerQuizOpt.is-opening {
  transition: height 258ms cubic-bezier(0.2, 0, 0.2, 1), border-color 180ms ease-out;
}
.readerQuizOpt[disabled] { cursor: default; }
.readerQuizOpt.is-correct { border-color: var(--success, #28840F); }
.readerQuizOpt.is-wrong { border-color: var(--error, #C51013); }
.readerQuizNote {
  display: block;
  font-size: 14px;
  line-height: 1.55;
  margin-top: 6px;
  /* Приглушён только сам ответ; подпись варианта остаётся тёмной. */
  color: var(--text-light-muted);
  /* Текст не едет вместе с высотой, а проявляется — как контент листов
     читалки: пауза, пока ячейка почти раскрылась, затем набор непрозрачности. */
  animation: readerQuizNoteIn 170ms ease-out 100ms backwards;
}
@keyframes readerQuizNoteIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* Текстовое поле шага читалки. Фокус-обводку рисует браузер своим синим —
   перекрываем её программным цветом. */
.readerTextInput {
  width: 100%;
  border: 1px solid var(--divider, #DADDE3);
  border-radius: 12px;
  padding: 12px;
  margin-bottom: 14px;
  font-family: inherit;
  font-size: 16px;
  line-height: 1.55;
  color: var(--text-light, #192126);
}
.readerTextInput:focus-visible,
.readerTextInput:focus {
  outline: 1px solid var(--program, #0365BB);
  outline-offset: 0;
  border-color: var(--program, #0365BB);
}

@media (prefers-reduced-motion: reduce) {
  .readerQuizOpt.is-opening { transition: none; }
  .readerQuizNote { animation: none; }
}

/* Шапка читалки: название урока капсом и счётчик шагов. */
.readerTopBarTitle {
  max-width: 100%;
  font-size: 14px;
  line-height: 18px;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  color: #192126;
  text-align: center;
}
.readerTopBarCount {
  font-size: 12px;
  line-height: 14px;
  color: #5E6468;
}

@media (prefers-reduced-motion: reduce) {
  .appRiseIn { animation: none; }
  .pressShrink, .appCta { transition: none; }
}

.viewport-dark {
  background: var(--bg-dark);
  color: var(--text-dark);
}

.viewport-light {
  background: var(--bg-light);
  color: var(--text-light);
}

/* Reusable bottom spacer so scrollable content clears the fixed BottomNav
   (~63px + the device safe-area inset). */
/* Tail clearance under the fixed nav. Deliberately 60px — less than the bar's
   own 66px — because the bar now hides on the way down and stays hidden at the
   end of the page: a full-height reservation read as an empty band there, while
   60px reads as breathing room after the last card. */
.tab-bottom-pad {
  padding-bottom: calc(60px + env(safe-area-inset-bottom));
}

/* from app/(tabs)/layout.module.css */
/* Tabs layout: a min-height flex column so BottomNav can sit naturally
   at the bottom of the document. Width is locked to the mobile frame so
   the nav stretches edge-to-edge of the 375px viewport. */

.m-layout .frame {
  width: 100%;
  max-width: 375px;
  min-height: 100dvh;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  background: var(--bg-light);
}

.m-layout .content {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* Inside the tabs frame, the page <main.viewport> shouldn't enforce its
   own 100dvh min-height — the frame already guarantees vertical fill,
   and the nav lives below the content. */
.m-layout .content :global(.viewport) {
  min-height: 0;
  margin: 0;
}

/* from components/chrome/BottomNav.module.css */
/* Fixed to the bottom of the mobile column so the nav is pinned to the screen
   bottom identically on every page — regardless of whether it's rendered inside
   the (tabs) frame or a screen's own <main>. Pages that show it add
   `tab-bottom-pad` so content clears the bar. */
/* Redesigned bar (Figma today-program-*): white sheet with rounded top
   corners, hairline top border and a soft upward shadow. Opaque all the way
   down so the translucent iOS Safari toolbar sits on solid white. */
.m-bottomnav .nav {
  position: fixed;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  /* Slides away while reading down the page, comes back on the way up — see the
     script in partials/app-bottom-nav.ejs. */
  transition: transform 280ms cubic-bezier(0.4, 0, 0.6, 1);
  width: 100%;
  max-width: 480px;
  background: var(--surface-light);
  border-top: 1px solid var(--divider);
  border-radius: 32px 32px 0 0;
  box-shadow: 0 -5px 13px rgba(14, 14, 20, 0.04);
  padding-bottom: env(safe-area-inset-bottom);
  z-index: 20;
}

/* Hidden state. translateX(-50%) has to be carried along or the bar jumps to
   the right half of the screen on its way down, and the extra 16px take the
   upward box-shadow off-screen with it instead of leaving a grey line resting
   on the bottom edge. */
.m-bottomnav.navHidden .nav {
  transform: translate(-50%, calc(100% + 16px));
}

@media (prefers-reduced-motion: reduce) {
  .m-bottomnav .nav { transition: none; }
}

.m-bottomnav .pill {
  display: flex;
  align-items: stretch;
  justify-content: center;
  gap: 4px;
  padding: 9px 12px;
}

/* Icon + 10px label; inactive grey, active near-black. Explicit greys so the
   per-program accent theme doesn't tint the nav. */
.m-bottomnav .tab {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  height: 44px;
  color: #969FA6;
  transition: color 0.15s ease;
}

.m-bottomnav .tabLabel {
  font-family: var(--font-sans);
  font-size: 10px;
  line-height: 1.2;
}

/* Иконка вжимается под пальцем и выходит обратно той же пружиной, что галочка
   в ячейках выбора (springPop, cubic-bezier(0.34,1.56,0.64,1) на возврате).
   Прежнее гашение прозрачностью снято: два эффекта разом читались мутно.
   Вжим глубже, чем у плашек, — так в референсе (иконка таббара уходит к 0.8);
   на 26px мельче уже не прочитать. */
.m-bottomnav .tab > svg {
  transition: transform 220ms cubic-bezier(0.34, 1.56, 0.64, 1);
  /* Слой держим постоянно. Бокс иконки стоит на дробном пикселе (таб шириной
     119.33 при трёх табах), и слой, который браузер создаёт под анимацию и
     убирает после неё, привязывает растр к целым пикселям устройства — отсюда
     сдвиг на ~1px в полёте и щелчок обратно в конце (замер: геометрический
     центр при этом неподвижен, дело только в растре). */
  will-change: transform;
  backface-visibility: hidden;
}
.m-bottomnav .tab:active > svg,
.m-bottomnav .tab.is-pressed > svg {
  transform: scale(0.85);
  transition: transform 60ms cubic-bezier(0.3, 0, 0.2, 1);
}
/* Всплытие новой активной иконки на пришедшем экране: таббар — это переходы
   между документами, анимацию нажатия навигация срезает. Класс ставит скрипт
   в partials/app-bottom-nav.ejs и только если переход был тапом по табу. */
.m-bottomnav .tab > svg.pop {
  animation: springPop 260ms linear;
}
@media (prefers-reduced-motion: reduce) {
  .m-bottomnav .tab > svg,
  .m-bottomnav .tab > svg.pop { transition: none; animation: none; }
}

.m-bottomnav .active {
  color: #192126;
}

/* from components/chrome/ScreenHeader.module.css */
.m-screenheader .header {
  padding: 14px 16px 12px;
}

.m-screenheader .row {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
}

.m-screenheader .iconBtn {
  background: transparent;
  border: 0;
  padding: 6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: inherit;
}

.m-screenheader .dark .iconBtn { color: var(--text-dark); }
.m-screenheader .light .iconBtn { color: var(--text-light); }

.m-screenheader .center {
  flex: 1;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}

.m-screenheader .centerStepper {
  flex: 1;
  text-align: center;
}

.m-screenheader .section {
  font-family: var(--font-sans);
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--text-light-muted);
  text-transform: uppercase;
}

.m-screenheader .dark .section { color: var(--text-dark-muted); }

.m-screenheader .titleQuiz {
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 400; /* Faculty ships 400 only */
  letter-spacing: 0.05em;
}

.m-screenheader .titleStepper {
  font-family: var(--font-serif);
  font-size: 15px;
  font-weight: 400; /* Faculty ships 400 only */
}

.m-screenheader .avatar {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: #E0E1DE;
  overflow: hidden;
  flex-shrink: 0;
}

.m-screenheader .avatarInner {
  width: 100%;
  height: 100%;
  background: #E0E1DE;
}

/* from components/MembershipGate.module.css */
.m-membershipgate .scrim {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(25, 33, 38, 0.55);
  backdrop-filter: blur(4px);
}

.m-membershipgate .card {
  width: 100%;
  max-width: 340px;
  background: var(--surface-light);
  border: 1px solid var(--border-card);
  border-radius: var(--radius-card);
  padding: 28px 22px 22px;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.m-membershipgate .lockBadge {
  width: 60px;
  height: 60px;
  border-radius: 50%;
  background: var(--cta-dark);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 16px;
}

.m-membershipgate .eyebrow {
  font-family: var(--font-sans);
  font-size: 11px;
  font-weight: 400; /* Faculty ships 400 only */
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-light);
}

.m-membershipgate .title {
  font-size: 22px;
  font-weight: 400; /* Faculty ships 400 only */
  color: var(--text-light);
  margin: 6px 0 8px;
  line-height: 1.2;
}

.m-membershipgate .body {
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.5;
  color: var(--text-light-muted);
  margin: 0 0 20px;
}

.m-membershipgate .cta {
  width: 100%;
  border: none;
  border-radius: var(--radius-pill);
  background: var(--program);
  color: var(--program-ink);
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 400; /* Faculty ships 400 only */
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 16px;
  cursor: pointer;
}

.m-membershipgate .cta:active {
  opacity: 0.85;
}

.m-membershipgate .secondary {
  width: 100%;
  border: none;
  background: transparent;
  color: var(--text-light-muted);
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 400; /* Faculty ships 400 only */
  padding: 12px 10px 2px;
  cursor: pointer;
}

/* from components/PremiumBanner.module.css */
.m-premiumbanner .banner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  padding: 16px;
  border-radius: 18px;
  border: 1px solid var(--border-card);
  text-decoration: none;
  margin-bottom: 16px;
}

.m-premiumbanner .grace {
  background: var(--program-tint);
  border-color: var(--program);
}

.m-premiumbanner .expired {
  background: rgba(237, 71, 71, 0.1);
  border-color: var(--color-red);
}

.m-premiumbanner .icon {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.m-premiumbanner .grace .icon {
  background: var(--program);
  color: var(--program-ink);
}

.m-premiumbanner .expired .icon {
  background: var(--color-red);
  color: #fff;
}

.m-premiumbanner .text {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.m-premiumbanner .eyebrow {
  font-family: var(--font-sans);
  font-size: 10px;
  font-weight: 400; /* Faculty ships 400 only */
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-light-muted);
}

.m-premiumbanner .title {
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 400; /* Faculty ships 400 only */
  color: var(--text-light);
  line-height: 1.2;
}

.m-premiumbanner .body {
  font-family: var(--font-sans);
  font-size: 13px;
  line-height: 1.4;
  color: var(--text-light-muted);
}

.m-premiumbanner .cta {
  flex: 1 1 100%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  border-radius: var(--radius-pill);
  padding: 12px 16px;
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 400; /* Faculty ships 400 only */
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.m-premiumbanner .grace .cta {
  background: var(--program);
  color: var(--program-ink);
}

.m-premiumbanner .expired .cta {
  background: var(--color-red);
  color: #fff;
}

/* from components/screens/AccountSettingsScreen.module.css */
.m-accountsettingsscreen .root {
  min-height: 100dvh;
  background: #FFFFFF;
  display: flex;
  flex-direction: column;
}

.m-accountsettingsscreen .topBar {
  padding: 14px 16px 4px;
}

.m-accountsettingsscreen .backChip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 6px 14px 6px 10px;
  border: 1px solid var(--border-card);
  border-radius: 999px;
  background: #FFFFFF;
  color: var(--text-light);
  font-family: var(--font-sans);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 15px;
  box-shadow: none;
}

.m-accountsettingsscreen .bodyPad {
  flex: 1;
  padding: 14px 18px 24px;
}

.m-accountsettingsscreen .heading {
  margin: 14px 0 12px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 20px;
  line-height: 1.3;
  color: var(--text-light);
}

.m-accountsettingsscreen .emailInline {
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
}

.m-accountsettingsscreen .notYou {
  background: transparent;
  border: 0;
  padding: 0;
  color: var(--text-light);
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 20px;
  text-decoration: underline;
}

.m-accountsettingsscreen .subtle {
  margin: 0 0 18px;
  color: var(--text-light-muted);
  font-family: var(--font-serif);
  font-size: 15px;
  line-height: 1.4;
}

.m-accountsettingsscreen .input {
  width: 100%;
  height: 56px;
  padding: 0 14px;
  border: 0;
  border-radius: 12px;
  background: #E0E1DE;
  font-family: var(--font-sans);
  font-size: 16px;
  color: var(--text-light);
  margin-bottom: 16px;
  outline: none;
}

.m-accountsettingsscreen .input:focus {
  box-shadow: none;
  border: 1px solid var(--program);
}

.m-accountsettingsscreen .cta {
  width: 100%;
  height: 56px;
  border: 0;
  border-radius: 12px;
  background: #E0E1DE;
  color: var(--text-light-muted);
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 14px;
  letter-spacing: 0.18em;
}

.m-accountsettingsscreen .ctaActive {
  background: var(--cta-dark);
  color: #FFFFFF;
}

.m-accountsettingsscreen .codeRow {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 8px;
  margin-bottom: 16px;
}

.m-accountsettingsscreen .codeBox {
  width: 100%;
  min-width: 0;
  height: 56px;
  padding: 0;
  border: 0;
  border-radius: 12px;
  background: #E0E1DE;
  text-align: center;
  font-family: var(--font-serif);
  font-size: 22px;
  font-weight: 400; /* Faculty ships 400 only */
  color: var(--text-light);
  outline: none;
}

.m-accountsettingsscreen .codeBox:focus {
  box-shadow: none;
  border: 1px solid var(--program);
}

.m-accountsettingsscreen .storeNotice {
  background: #E0E1DE;
  padding: 18px 24px 22px;
  text-align: center;
}

.m-accountsettingsscreen .storeNoticeTitle {
  margin: 0 0 6px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 16px;
  color: var(--text-light);
}

.m-accountsettingsscreen .storeNoticeLink {
  font-family: var(--font-serif);
  font-size: 15px;
  text-decoration: underline;
  color: var(--text-light);
}

.m-accountsettingsscreen .detailHeader {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 4px 0 14px;
}

.m-accountsettingsscreen .detailTitle {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 24px;
  color: var(--text-light);
}

.m-accountsettingsscreen .coachTag {
  background: #192126;
  color: #FFFFFF;
  padding: 6px 12px;
  border-radius: 999px;
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 400; /* Faculty ships 400 only */
  letter-spacing: 0.08em;
}

.m-accountsettingsscreen .detailCard {
  border: 1px solid var(--border-card);
  border-radius: 16px;
  padding: 18px 18px 12px;
  background: #FFFFFF;
}

.m-accountsettingsscreen .planName {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 16px;
  color: var(--text-light);
}

.m-accountsettingsscreen .divider {
  height: 1px;
  background: var(--divider);
  margin: 14px 0;
}

.m-accountsettingsscreen .detailRow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.m-accountsettingsscreen .detailLabel {
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 15px;
  color: var(--text-light);
}

.m-accountsettingsscreen .detailValue {
  font-family: var(--font-serif);
  font-size: 15px;
  color: var(--text-light);
  text-align: right;
  word-break: break-word;
}

.m-accountsettingsscreen .cancelRow {
  display: flex;
  justify-content: flex-end;
  padding: 4px 0 8px;
}

.m-accountsettingsscreen .cancelLink {
  background: transparent;
  border: 0;
  padding: 4px 0;
  color: var(--text-light);
  font-family: var(--font-serif);
  font-size: 15px;
  text-decoration: underline;
}

.m-accountsettingsscreen .cancelOff {
  color: var(--text-light-muted);
  font-family: var(--font-serif);
  font-size: 15px;
  font-style: italic;
}

/* Delete account — moved here from the profile page. Grey (not red) per design. */
.m-accountsettingsscreen .deleteAccountBtn {
  display: block;
  margin: 24px auto 8px;
  background: transparent;
  border: 0;
  padding: 8px;
  color: var(--text-light-muted);
  font-family: var(--font-serif);
  font-size: 16px;
  font-weight: 400; /* Faculty ships 400 only */
  cursor: pointer;
}

/* from components/screens/ActivatePremiumScreen.module.css */
.m-activatepremiumscreen .root {
  display: flex;
  flex-direction: column;
  min-height: 100%;
  background: var(--bg-light);
  padding: 0 20px 24px;
}

.m-activatepremiumscreen .close {
  position: sticky;
  top: 0;
  align-self: flex-start;
  margin: 10px 0 0 -4px;
  width: 40px;
  height: 40px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: transparent;
  color: var(--text-light);
  cursor: pointer;
  z-index: 2;
}

.m-activatepremiumscreen .body {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.m-activatepremiumscreen .badgeIcon {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: var(--program);
  color: var(--program-ink);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin: 6px 0 18px;
}

.m-activatepremiumscreen .eyebrow {
  font-family: var(--font-sans);
  font-size: 11px;
  font-weight: 400; /* Faculty ships 400 only */
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-light);
}

.m-activatepremiumscreen .title {
  font-size: 26px;
  font-weight: 400; /* Faculty ships 400 only */
  color: var(--text-light);
  margin: 6px 0 8px;
  line-height: 1.15;
}

.m-activatepremiumscreen .subtitle {
  font-family: var(--font-sans);
  font-size: 15px;
  color: var(--text-light-muted);
  max-width: 300px;
  line-height: 1.4;
}

.m-activatepremiumscreen .priceRow {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 22px;
}

.m-activatepremiumscreen .price {
  font-size: 32px;
  font-weight: 400; /* Faculty ships 400 only */
  color: var(--text-light);
}

.m-activatepremiumscreen .normal {
  font-size: 18px;
  color: var(--text-light-muted);
  text-decoration: line-through;
}

.m-activatepremiumscreen .badge {
  font-family: var(--font-sans);
  font-size: 10px;
  font-weight: 400; /* Faculty ships 400 only */
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--program-ink);
  background: var(--program);
  padding: 4px 8px;
  border-radius: 6px;
}

.m-activatepremiumscreen .priceNote {
  font-family: var(--font-sans);
  font-size: 12px;
  color: var(--text-light-muted);
  margin: 6px 0 0;
}

.m-activatepremiumscreen .features {
  list-style: none;
  margin: 26px 0 0;
  padding: 0;
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 14px;
  text-align: left;
}

.m-activatepremiumscreen .feature {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.4;
  color: var(--text-light);
}

.m-activatepremiumscreen .featureCheck {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--program);
  color: var(--program-ink);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-top: 1px;
}

.m-activatepremiumscreen .note {
  margin: 20px 0 0;
  width: 100%;
  font-family: var(--font-sans);
  font-size: 13px;
  line-height: 1.45;
  color: var(--text-light-muted);
  background: var(--program-tint);
  border: 1px solid var(--program);
  border-radius: 12px;
  padding: 12px 14px;
  text-align: left;
}

.m-activatepremiumscreen .footer {
  margin-top: 24px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.m-activatepremiumscreen .cta {
  width: 100%;
  border: none;
  border-radius: var(--radius-pill);
  background: var(--program);
  color: var(--program-ink);
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 400; /* Faculty ships 400 only */
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 18px;
  cursor: pointer;
}

.m-activatepremiumscreen .cta:active {
  opacity: 0.85;
}

.m-activatepremiumscreen .decline {
  width: 100%;
  border: none;
  background: transparent;
  color: var(--text-light-muted);
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 400; /* Faculty ships 400 only */
  padding: 10px;
  cursor: pointer;
}

/* from components/screens/BackedByScienceScreen.module.css */
.m-backedbysciencescreen .root {
  min-height: 100dvh;
  background: var(--bg-light);
  padding-bottom: 32px;
}

.m-backedbysciencescreen .topBar {
  padding: 14px 16px 6px;
}

.m-backedbysciencescreen .backChip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 6px 14px 6px 10px;
  border-radius: 999px;
  background: #FFFFFF;
  color: var(--text-light);
  font-family: var(--font-sans);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 15px;
  border: 1px solid var(--border-card);
  box-shadow: none;
}

.m-backedbysciencescreen .heroCard {
  margin: 12px 16px 14px;
  background: var(--surface-beige);
  border-radius: 14px;
  padding: 28px 24px;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
}

.m-backedbysciencescreen .coachTag {
  background: #192126;
  color: #FFFFFF;
  padding: 8px 14px;
  border-radius: 4px;
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 400; /* Faculty ships 400 only */
  letter-spacing: 0.1em;
}

.m-backedbysciencescreen .heading {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 22px;
  color: var(--text-light);
}

.m-backedbysciencescreen .section {
  padding: 14px 22px 8px;
}

.m-backedbysciencescreen .lead {
  margin: 0 0 14px;
  font-family: var(--font-serif);
  font-size: 15px;
  line-height: 1.45;
  color: var(--text-light);
  text-align: center;
}

.m-backedbysciencescreen .subhead {
  margin: 18px 0 12px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 18px;
  color: var(--text-light);
  text-align: center;
}

.m-backedbysciencescreen .bullets {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.m-backedbysciencescreen .bullet {
  display: flex;
  gap: 10px;
  align-items: flex-start;
}

.m-backedbysciencescreen .dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--program);
  margin-top: 9px;
  flex-shrink: 0;
}

.m-backedbysciencescreen .bulletText {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 15px;
  line-height: 1.45;
  color: var(--text-light);
}

.m-backedbysciencescreen .cite {
  margin: 4px 0 0;
  font-family: var(--font-sans);
  font-size: 12px;
  color: var(--text-light);
  line-height: 1.35;
}

.m-backedbysciencescreen .callout {
  margin: 18px 16px;
  padding: 22px 22px 24px;
  background: #192126;
  color: #FFFFFF;
  border-radius: 14px;
}

.m-backedbysciencescreen .calloutPreface {
  margin: 0 0 14px;
  font-family: var(--font-serif);
  font-size: 14px;
  line-height: 1.5;
  color: #E0E1DE;
  text-align: center;
}

.m-backedbysciencescreen .calloutAttribution {
  margin: 0 0 16px;
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 13px;
  line-height: 1.4;
  color: #E0E1DE;
  text-align: center;
}

.m-backedbysciencescreen .statRow {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.m-backedbysciencescreen .statBlock {
  display: flex;
  align-items: center;
  gap: 14px;
}

.m-backedbysciencescreen .statValue {
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 30px;
  color: var(--program);
  min-width: 70px;
}

.m-backedbysciencescreen .statText {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 13px;
  line-height: 1.35;
  color: #E0E1DE;
}

.m-backedbysciencescreen .bigStats {
  padding: 8px 22px 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
}

.m-backedbysciencescreen .bigStat {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
}

.m-backedbysciencescreen .bigCircle {
  width: 150px;
  height: 150px;
  border-radius: 50%;
  border: 2px solid var(--program);
  display: flex;
  align-items: center;
  justify-content: center;
}

.m-backedbysciencescreen .bigCircleValue {
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 34px;
  color: var(--program);
  letter-spacing: 0.02em;
}

.m-backedbysciencescreen .bigStatText {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 15px;
  line-height: 1.35;
  text-align: center;
  color: var(--text-light);
  max-width: 240px;
}

.m-backedbysciencescreen .footnote {
  margin: 10px 0 0;
  font-family: var(--font-serif);
  font-size: 13px;
  font-style: italic;
  color: var(--text-light-muted);
  text-align: center;
}

/* from components/screens/CancelSubscriptionScreen.module.css */
.m-cancelsubscriptionscreen .root {
  min-height: 100dvh;
  background: var(--bg-light);
  display: flex;
  flex-direction: column;
}

.m-cancelsubscriptionscreen .topBar {
  padding: 14px 16px 0;
}

.m-cancelsubscriptionscreen .backChip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: var(--text-light);
  box-shadow: 0 0 0 1px var(--border-light);
  cursor: pointer;
}

.m-cancelsubscriptionscreen .titleBar {
  text-align: center;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 17px;
  color: var(--text-light);
  padding: 8px 0 14px;
  border-bottom: 1px solid var(--divider);
}

.m-cancelsubscriptionscreen .body {
  flex: 1;
  padding: 20px 18px 28px;
  display: flex;
  flex-direction: column;
}

.m-cancelsubscriptionscreen .bodyCenter {
  justify-content: center;
}

.m-cancelsubscriptionscreen .h1 {
  margin: 0 0 8px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 22px;
  line-height: 1.25;
  color: var(--text-light);
}

.m-cancelsubscriptionscreen .h1center {
  margin: 0 0 8px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 22px;
  line-height: 1.25;
  color: var(--text-light);
  text-align: center;
}

.m-cancelsubscriptionscreen .sub {
  margin: 0 0 18px;
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.5;
  color: var(--text-light-muted);
}

.m-cancelsubscriptionscreen .subCenter {
  margin: 0 0 20px;
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.5;
  color: var(--text-light-muted);
  text-align: center;
}

/* reasons */
.m-cancelsubscriptionscreen .reasons {
  list-style: none;
  margin: 0 0 16px;
  padding: 0;
}

.m-cancelsubscriptionscreen .reason {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 2px;
  border-bottom: 1px solid var(--divider);
  font-family: var(--font-sans);
  font-size: 15px;
  color: var(--text-light);
  cursor: pointer;
}

.m-cancelsubscriptionscreen .reason input {
  accent-color: var(--program);
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
}

/* buttons — pill CTAs matching the app design system (flat, Lato) */
.m-cancelsubscriptionscreen .btnPrimary,
.m-cancelsubscriptionscreen .btnGhost,
.m-cancelsubscriptionscreen .btnDanger {
  width: 100%;
  height: 54px;
  border-radius: var(--radius-pill);
  cursor: pointer;
  font-family: var(--font-sans);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 16px;
  margin-top: 12px;
}

.m-cancelsubscriptionscreen .btnPrimary {
  border: 0;
  background: var(--program);
  color: var(--program-ink);
}

.m-cancelsubscriptionscreen .btnPrimary:hover:not(:disabled) {
  background: var(--program-hover);
}

.m-cancelsubscriptionscreen .btnPrimary:disabled {
  background: var(--surface-beige);
  color: var(--text-light-muted);
  cursor: not-allowed;
}

.m-cancelsubscriptionscreen .btnGhost {
  background: #ffffff;
  color: var(--text-light);
  border: 1px solid var(--border-card);
}

/* Destructive confirm — genuine danger (cancel), so it's red. */
.m-cancelsubscriptionscreen .btnDanger {
  border: 0;
  background: var(--color-red);
  color: #ffffff;
}

.m-cancelsubscriptionscreen .btnDanger:active {
  opacity: 0.9;
}

.m-cancelsubscriptionscreen .noThanks {
  display: block;
  margin: 6px auto 0;
  background: transparent;
  border: 0;
  color: var(--text-light-muted);
  font-family: var(--font-sans);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 14px;
  text-decoration: underline;
  cursor: pointer;
}

/* save offer */
.m-cancelsubscriptionscreen .offerIcon {
  position: relative;
  width: 92px;
  height: 92px;
  margin: 6px auto 20px;
  background: var(--surface-beige);
  border-radius: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-light);
}

.m-cancelsubscriptionscreen .offerBadge {
  position: absolute;
  bottom: -8px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--program);
  color: var(--program-ink);
  font-family: var(--font-display);
  font-size: 11px;
  font-weight: 400; /* Faculty ships 400 only */
  letter-spacing: 0.04em;
  padding: 4px 10px;
  border-radius: 999px;
  white-space: nowrap;
}

.m-cancelsubscriptionscreen .subBox {
  background: var(--surface-light);
  border: 1px solid var(--border-card);
  border-radius: 18px;
  padding: 18px;
  margin: 0 0 14px;
  text-align: center;
}

.m-cancelsubscriptionscreen .subBoxTitle {
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 15px;
  color: var(--text-light);
  margin-bottom: 8px;
}

.m-cancelsubscriptionscreen .expires {
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--text-light);
}

.m-cancelsubscriptionscreen .expires s {
  color: var(--badge-burgundy);
}

.m-cancelsubscriptionscreen .expires strong {
  color: var(--error);
  font-weight: 400; /* Faculty ships 400 only */
}

.m-cancelsubscriptionscreen .added {
  display: inline-block;
  margin: 8px 0 4px;
  background: var(--program-tint);
  color: var(--error);
  font-family: var(--font-display);
  font-size: 11px;
  font-weight: 400; /* Faculty ships 400 only */
  letter-spacing: 0.04em;
  padding: 4px 10px;
  border-radius: 999px;
}

.m-cancelsubscriptionscreen .features {
  list-style: none;
  margin: 12px 0 0;
  padding: 14px 0 0;
  border-top: 1px solid var(--divider);
  display: grid;
  gap: 10px;
  text-align: left;
}

.m-cancelsubscriptionscreen .features li {
  display: flex;
  align-items: center;
  gap: 9px;
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--text-light);
}

.m-cancelsubscriptionscreen .featCheck {
  color: var(--error);
  flex: 0 0 auto;
}

.m-cancelsubscriptionscreen .fineprint {
  font-family: var(--font-sans);
  font-size: 12px;
  color: var(--text-light-muted);
  text-align: center;
  margin: 0 0 8px;
}

/* accepted */
.m-cancelsubscriptionscreen .checkBadge {
  width: 84px;
  height: 84px;
  margin: 0 auto 18px;
  border-radius: 50%;
  background: var(--program);
  color: var(--program-ink);
  display: flex;
  align-items: center;
  justify-content: center;
}

/* help */
.m-cancelsubscriptionscreen .helpList {
  list-style: none;
  margin: 4px 0 12px;
  padding: 0;
  display: grid;
  gap: 18px;
}

.m-cancelsubscriptionscreen .helpList li {
  display: flex;
  gap: 12px;
}

.m-cancelsubscriptionscreen .helpIcon {
  color: var(--text-light);
  flex: 0 0 auto;
  margin-top: 2px;
}

.m-cancelsubscriptionscreen .helpH {
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 15px;
  color: var(--text-light);
}

.m-cancelsubscriptionscreen .helpT {
  font-family: var(--font-sans);
  font-size: 13px;
  line-height: 1.45;
  color: var(--text-light-muted);
  margin-top: 2px;
}

/* canceled */
.m-cancelsubscriptionscreen .finalCard {
  background: var(--surface-light);
  border: 1px solid var(--border-card);
  border-radius: 18px;
  padding: 26px 20px;
  margin: 8px 0 4px;
}

.m-cancelsubscriptionscreen .legal {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 20px;
  margin-top: 16px;
}

.m-cancelsubscriptionscreen .legalLink {
  background: transparent;
  border: 0;
  color: var(--text-light-muted);
  font-family: var(--font-sans);
  font-size: 13px;
  text-decoration: underline;
  cursor: pointer;
}


/* from components/screens/CourseComingSoonScreen.module.css */
.m-coursecomingsoonscreen .page {
  display: flex;
  flex-direction: column;
  background: var(--bg-light);
  overflow: hidden;
}

/* ----- Hero image ----- */
.m-coursecomingsoonscreen .hero {
  position: relative;
  flex: 0 0 auto;
  height: 250px;
  background-color: #E0E1DE;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

.m-coursecomingsoonscreen .closeBtn {
  position: absolute;
  top: 18px;
  left: 16px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border: none;
  border-radius: 50%;
  background: var(--surface-light);
  color: var(--text-light);
  cursor: pointer;
  box-shadow: none;
}

.m-coursecomingsoonscreen .videoTag {
  position: absolute;
  left: 16px;
  bottom: 34px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  border-radius: 14px;
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 11px;
  letter-spacing: 0.06em;
}

/* ----- Content sheet ----- */
.m-coursecomingsoonscreen .sheet {
  position: relative;
  z-index: 1;
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 24px 22px 20px;
  background: var(--surface-light);
}

.m-coursecomingsoonscreen .title {
  margin: 0 0 10px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 26px;
  line-height: 1.15;
  letter-spacing: -0.01em;
  color: var(--text-light);
}

.m-coursecomingsoonscreen .meta {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--text-light-muted);
}

.m-coursecomingsoonscreen .dot {
  color: var(--text-light-muted);
}

/* ----- Coming-soon note ----- */
.m-coursecomingsoonscreen .soon {
  margin-top: 28px;
  padding: 20px;
  border-radius: 14px;
  background: var(--surface-beige);
}

.m-coursecomingsoonscreen .soonTag {
  display: inline-block;
  font-family: var(--font-sans);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-light);
  background: rgba(0, 0, 0, 0.06);
  padding: 2px 8px;
  border-radius: 4px;
}

.m-coursecomingsoonscreen .soonText {
  margin: 12px 0 0;
  font-family: var(--font-serif);
  font-size: 16px;
  line-height: 1.5;
  color: var(--text-light);
}

/* from components/screens/CustomKegelWorkoutScreen.module.css */
/* "+ ADD EXERCISE" button under the exercise list (intro stage). */
.m-customkegelworkoutscreen .addBtn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  margin: 6px 0 4px;
  padding: 16px;
  border: none;
  border-radius: 12px;
  background: var(--surface-beige);
  color: var(--text-light);
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 14px;
  letter-spacing: 0.04em;
  cursor: pointer;
}

.m-customkegelworkoutscreen .addBtn:hover {
  background: #E0E1DE;
}

/* ----- Add-exercises bottom sheet ----- */
.m-customkegelworkoutscreen .addScrim {
  position: absolute;
  inset: 0;
  z-index: 40;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  background: rgba(0, 0, 0, 0.45);
}

.m-customkegelworkoutscreen .addSheet {
  display: flex;
  flex-direction: column;
  max-height: 86%;
  padding: 8px 20px calc(16px + env(safe-area-inset-bottom));
  border-radius: 22px 22px 0 0;
  background: var(--surface-light);
}

.m-customkegelworkoutscreen .addHeader {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 14px 0 12px;
  border-bottom: 1px solid var(--divider);
}

.m-customkegelworkoutscreen .addTitle {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 19px;
  color: var(--text-light);
}

.m-customkegelworkoutscreen .addClose {
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border: none;
  border-radius: 50%;
  background: var(--surface-beige);
  color: var(--text-light);
  cursor: pointer;
}

.m-customkegelworkoutscreen .addList {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 4px 0;
}

.m-customkegelworkoutscreen .addRow {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  padding: 12px 2px;
  border: none;
  background: transparent;
  text-align: left;
  cursor: pointer;
}

.m-customkegelworkoutscreen .addThumb {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: 8px;
  background: #E0E1DE;
  color: var(--text-light);
}

.m-customkegelworkoutscreen .addBody {
  flex: 1 1 auto;
  min-width: 0;
}

.m-customkegelworkoutscreen .addExTitle {
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 17px;
  color: var(--text-light);
}

.m-customkegelworkoutscreen .addExMeta {
  margin-top: 2px;
  font-family: var(--font-display);
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--text-light-muted);
}

.m-customkegelworkoutscreen .addRadio {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  border: 2px solid #E0E1DE;
  border-radius: 50%;
  background: transparent;
}

.m-customkegelworkoutscreen .addRadioOn {
  border-color: var(--text-light);
  background:
    radial-gradient(circle, var(--program) 0 6px, transparent 7px);
}

.m-customkegelworkoutscreen .addSaveBtn {
  flex: 0 0 auto;
  width: 100%;
  height: 52px;
  margin-top: 8px;
  border: none;
  border-radius: 12px;
  background: #E0E1DE;
  color: var(--text-light-muted);
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 14px;
  letter-spacing: 0.08em;
  cursor: not-allowed;
}

.m-customkegelworkoutscreen .addSaveBtnActive {
  background: var(--program);
  color: var(--program-ink);
  cursor: pointer;
  box-shadow: none;
}

.m-customkegelworkoutscreen .addSaveBtnActive:active {
  transform: scale(0.99);
}

/* from components/screens/ExerciseInstructionModal.module.css */
.m-exerciseinstructionmodal .modal {
  height: 100dvh;
  background: #FFFFFF;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.m-exerciseinstructionmodal .header {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 18px 20px 12px;
}

.m-exerciseinstructionmodal .title {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 18px;
  line-height: 1.2;
  color: var(--text-light);
  text-align: center;
}

.m-exerciseinstructionmodal .closeButton {
  position: absolute;
  top: 14px;
  right: 16px;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: none;
  background: var(--surface-beige);
  color: var(--text-light);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}

.m-exerciseinstructionmodal .body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 4px 20px 24px;
}

.m-exerciseinstructionmodal .diagram {
  background: var(--surface-beige);
  border-radius: 12px;
  padding: 18px 16px;
  margin: 8px 0 20px;
  min-height: 160px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.m-exerciseinstructionmodal .diagramSlot {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.m-exerciseinstructionmodal .diagramCaption {
  font-family: var(--font-sans);
  font-size: 13px;
  color: var(--text-light-muted);
  text-align: center;
}

.m-exerciseinstructionmodal .sectionLabel {
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 13px;
  letter-spacing: 0.08em;
  color: var(--text-light);
  margin: 4px 0 12px;
}

.m-exerciseinstructionmodal .steps {
  list-style: none;
  padding: 0;
  margin: 0 0 20px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.m-exerciseinstructionmodal .step {
  display: flex;
  align-items: flex-start;
  gap: 12px;
}

.m-exerciseinstructionmodal .stepNumber {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--program);
  color: var(--program-ink);
  font-family: var(--font-sans);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 12px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-top: 1px;
}

.m-exerciseinstructionmodal .stepText {
  flex: 1;
  font-family: var(--font-serif);
  font-size: 15px;
  line-height: 1.45;
  color: var(--text-light);
  margin: 0;
}

.m-exerciseinstructionmodal .adjust {
  margin-top: 8px;
}

.m-exerciseinstructionmodal .adjustRow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: var(--surface-beige);
  border-radius: 8px;
  padding: 14px 16px;
  margin-top: 4px;
}

.m-exerciseinstructionmodal .adjustLabel {
  font-family: var(--font-sans);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 15px;
  color: var(--text-light);
}

.m-exerciseinstructionmodal .adjustValue {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 13px;
  letter-spacing: 0.06em;
  color: var(--text-light);
}

/* Naturally pinned by the flex layout — `.body` scrolls internally above. */
.m-exerciseinstructionmodal .footer {
  flex-shrink: 0;
  padding: 12px 20px 24px;
  background: var(--surface-light);
}

.m-exerciseinstructionmodal .saveButton {
  width: 100%;
  padding: 16px 20px;
  border: none;
  border-radius: 999px;
  background: var(--border-light);
  color: var(--text-light-muted);
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 15px;
  letter-spacing: 0.08em;
  cursor: not-allowed;
}

/* from components/screens/ExploreScreen.module.css */
.m-explorescreen .page {
  min-height: 100dvh;
  background: var(--bg-light);
  color: var(--text-light);
  padding: 12px 0 calc(84px + env(safe-area-inset-bottom));
}

.m-explorescreen .topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 4px 16px 0;
}

.m-explorescreen .title {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 22px;
}

.m-explorescreen .avatar {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: #E0E1DE;
  overflow: hidden;
  flex-shrink: 0;
}

.m-explorescreen .avatarInner {
  width: 100%;
  height: 100%;
  background: #E0E1DE;
}

.m-explorescreen .mainProgramsLabel {
  margin: 18px 16px 12px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 22px;
}

.m-explorescreen .hero {
  margin: 0 16px;
  display: flex;
  align-items: stretch;
  background: var(--surface-light);
  border: 1px solid var(--border-card);
  box-shadow: var(--shadow-card);
  border-radius: 22px;
  overflow: hidden;
  height: 140px;
  text-decoration: none;
  color: inherit;
}

.m-explorescreen .heroLeft {
  flex: 1;
  padding: 14px 12px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

.m-explorescreen .heroTitle {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 22px;
  line-height: 1.15;
}

.m-explorescreen .heroImg {
  width: 50%;
  background-color: #E0E1DE;
  background-size: cover;
  background-position: center;
}

.m-explorescreen .heroBlurb {
  margin: 12px 16px 6px;
  font-family: var(--font-serif);
  font-size: 14px;
  line-height: 1.45;
  color: var(--text-light);
}

.m-explorescreen .heroMeta {
  display: flex;
  align-items: center;
  gap: 16px;
  margin: 0 16px 18px;
  border-bottom: 1px solid var(--divider);
  padding-bottom: 14px;
}

.m-explorescreen .metaItem {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: var(--font-sans);
  font-size: 12px;
  color: var(--text-light-muted);
}

/* Render the 📅/💪 meta icons as solid black (monochrome emoji theme). */
.m-explorescreen .metaItem [aria-hidden] {
}

.m-explorescreen .sectionLabel {
  margin: 18px 16px 12px;
  font-family: var(--font-sans);
  font-size: 11px;
  letter-spacing: 0.1em;
  color: var(--text-light-muted);
  text-transform: uppercase;
  font-weight: 400; /* Faculty ships 400 only */
}

/* Horizontal scroll carousels */
.m-explorescreen .carousel,
.m-explorescreen .coursesRow {
  display: flex;
  gap: 10px;
  /* Inset the whole row to the hero's 16px gutters so it occupies the same
     on-screen width as the Last Longer card. Cards keep their own size and
     scroll within this region; the right peek clips at the gutter instead of
     bleeding to the screen edge. (margin, not padding, so the scroll viewport
     itself is inset — no scroll-padding/auto-scroll quirk.) */
  margin: 0 16px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}

.m-explorescreen .carousel::-webkit-scrollbar,
.m-explorescreen .coursesRow::-webkit-scrollbar { display: none; }

.m-explorescreen .recCard {
  flex: 0 0 280px;
  scroll-snap-align: start;
  background: var(--surface-light);
  border: 1px solid var(--border-card);
  box-shadow: var(--shadow-card);
  border-radius: 22px;
  padding: 12px;
  display: flex;
  flex-direction: column;
  text-decoration: none;
  color: inherit;
}

/* Coming-soon programs: dimmed + inert, mirroring ProgramPickerSheet. */
.m-explorescreen .cardDisabled {
  opacity: 0.55;
  cursor: not-allowed;
}

.m-explorescreen .comingSoonTag {
  font-family: var(--font-sans);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-light);
  background: rgba(0, 0, 0, 0.06);
  padding: 2px 8px;
  border-radius: 4px;
  margin-left: auto;
}

.m-explorescreen .recHeader {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
}

.m-explorescreen .recImg {
  width: 100px;
  height: 80px;
  background-color: #E0E1DE;
  background-size: cover;
  background-position: center;
  border-radius: 8px;
  flex-shrink: 0;
}

.m-explorescreen .recTitle {
  margin: 10px 0 4px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 20px;
  line-height: 1.15;
}

.m-explorescreen .recBlurb {
  margin: 0 0 10px;
  font-family: var(--font-serif);
  font-size: 13px;
  line-height: 1.4;
  color: var(--text-light);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.m-explorescreen .recMeta {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-top: auto;
}

/* Courses */
.m-explorescreen .courseCard {
  flex: 0 0 175px;
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  gap: 6px;
  text-decoration: none;
  color: inherit;
}

.m-explorescreen .courseImg {
  width: 100%;
  height: 100px;
  background-color: #E0E1DE;
  background-size: cover;
  background-position: center;
  border-radius: 8px;
  position: relative;
}

.m-explorescreen .courseTag {
  position: absolute;
  bottom: 8px;
  left: 8px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: var(--color-red);
  color: #FFFFFF;
  padding: 4px 8px;
  border-radius: 999px;
  font-family: var(--font-sans);
  font-size: 10px;
  font-weight: 400; /* Faculty ships 400 only */
  letter-spacing: 0.05em;
}

.m-explorescreen .courseTitle {
  margin: 4px 0 0;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 15px;
  line-height: 1.2;
}

.m-explorescreen .courseMeta {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: var(--font-sans);
  font-size: 12px;
  color: var(--text-light-muted);
}

.m-explorescreen .courseTagText {
  font-weight: 400; /* Faculty ships 400 only */
}

.m-explorescreen .tag_burgundy { color: var(--badge-burgundy); }
.m-explorescreen .tag_orange { color: var(--text-light); }

.m-explorescreen .dot { color: var(--text-light-muted); }

/* Practices */
.m-explorescreen .practicesRow {
  display: flex;
  gap: 10px;
  margin: 0 16px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}

.m-explorescreen .practicesRow::-webkit-scrollbar { display: none; }

.m-explorescreen .practiceTile {
  flex: 0 0 175px;
  height: 96px;
  scroll-snap-align: start;
  border-radius: 16px;
  background-color: #E0E1DE;
  background-size: cover;
  background-position: center;
  position: relative;
  padding: 10px;
  display: flex;
  align-items: flex-end;
  text-decoration: none;
  border: 1px solid var(--border-card);
  box-shadow: var(--shadow-card);
}

.m-explorescreen .practiceTile::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(0,0,0,0) 40%, rgba(0,0,0,0.05) 100%);
  border-radius: 10px;
}

.m-explorescreen .practiceTitle {
  position: relative;
  z-index: 1;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 16px;
  color: var(--text-light);
  line-height: 1.2;
}

/* ---- Female Explore --------------------------------------------------- */
/* Section headers ("All programs", "Self-Exploration", …) — dark serif,
   mixed-case, matching the reference. */
.m-explorescreen .fSectionHead {
  margin: 22px 16px 12px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 20px;
  line-height: 1.15;
  color: var(--text-light);
}

/* "All programs" carousel — landscape program cards (image with badge + title
   baked in) over a live blurb + meta line. */
.m-explorescreen .fProgRow {
  display: flex;
  gap: 14px;
  margin: 0 16px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.m-explorescreen .fProgRow::-webkit-scrollbar { display: none; }

.m-explorescreen .fProgCard {
  flex: 0 0 266px;
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  text-decoration: none;
  color: inherit;
}
.m-explorescreen .fProgCardInert { cursor: default; }

/* Themed program-card art — filled with the programme's own colour theme
   (original palette), with a live day-badge, optional Completed pill, and
   title over it. No reference imagery. */
.m-explorescreen .fProgArt {
  position: relative;
  width: 100%;
  height: 150px;
  border-radius: 16px;
  padding: 14px;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  overflow: hidden;
}

.m-explorescreen .fProgBadge {
  align-self: flex-start;
  background: rgba(255, 255, 255, 0.92);
  color: var(--text-light, #C6395E);
  font-family: var(--font-sans);
  font-size: 10px;
  font-weight: 400; /* Faculty ships 400 only */
  letter-spacing: 0.07em;
  padding: 5px 10px;
  border-radius: 999px;
}

.m-explorescreen .fProgDone {
  align-self: flex-start;
  margin-top: 6px;
  background: rgba(255, 255, 255, 0.92);
  color: #2E7D46;
  font-family: var(--font-sans);
  font-size: 10px;
  font-weight: 400; /* Faculty ships 400 only */
  letter-spacing: 0.05em;
  padding: 4px 9px;
  border-radius: 999px;
}

.m-explorescreen .fProgTitle {
  margin: auto 0 0;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 21px;
  line-height: 1.12;
  color: #FFFFFF;
}

.m-explorescreen .fProgBlurb {
  margin: 11px 2px 6px;
  font-family: var(--font-serif);
  font-size: 14px;
  line-height: 1.4;
  color: var(--text-light);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.m-explorescreen .fProgMeta {
  margin: 0 2px;
  font-family: var(--font-sans);
  font-size: 12px;
  color: var(--text-light-muted);
}

/* Content-card carousels — portrait cards. Badge and title are LIVE markup over
   a clean crop (they used to be baked into the JPEG, which made them
   untranslatable and the card unclickable). */
.m-explorescreen .fCardRow {
  display: flex;
  gap: 12px;
  margin: 0 16px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.m-explorescreen .fCardRow::-webkit-scrollbar { display: none; }

.m-explorescreen .fCard {
  flex: 0 0 152px;
  scroll-snap-align: start;
  display: block;
  text-decoration: none;
  color: inherit;
}

.m-explorescreen .fCardArt {
  position: relative;
  border-radius: 16px;
  overflow: hidden;
  background: var(--surface-beige);
}

.m-explorescreen .fCardImg {
  width: 100%;
  aspect-ratio: 152 / 196;
  object-fit: cover;
  display: block;
}

/* Type chip (Article / Practice) — frosted pill, top-left. */
.m-explorescreen .fCardBadge {
  position: absolute;
  top: 8px;
  left: 8px;
  display: inline-flex;
  align-items: center;
  padding: 4px 10px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.82);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: 11px;
  line-height: 1.2;
  color: var(--text-light);
}

/* "New" dot-chip sits under the type chip so the two never overlap. */
.m-explorescreen .fCardNew {
  position: absolute;
  top: 34px;
  left: 8px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 9px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.92);
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: 10px;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--text-light);
}
.m-explorescreen .fCardNew::before {
  content: '';
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: #C96A5E;
}

.m-explorescreen .fCardLock {
  position: absolute;
  top: 8px;
  right: 8px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.9);
  color: var(--text-light);
}

/* Locked cards stay legible — dimmed, not hidden, so the section keeps its
   shape and the lock reads as an upsell rather than a broken tile. */
.m-explorescreen .fCardLocked .fCardImg { opacity: 0.62; }

.m-explorescreen .fCardTitle {
  margin: 8px 2px 0;
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: 14px;
  line-height: 1.3;
  color: var(--text-light);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.m-explorescreen .fCardMeta {
  margin: 3px 2px 0;
  font-family: var(--font-sans);
  font-size: 11px;
  line-height: 1.3;
  color: var(--text-light-muted);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.m-explorescreen .srOnly {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* from components/screens/FaqScreen.module.css */
.m-faqscreen .root {
  min-height: 100dvh;
  background: var(--bg-light);
  padding-bottom: 40px;
}

.m-faqscreen .topBar {
  padding: 14px 16px 6px;
}

.m-faqscreen .backChip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 6px 14px 6px 10px;
  border-radius: 999px;
  background: #FFFFFF;
  color: var(--text-light);
  font-family: var(--font-sans);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 15px;
  border: 1px solid var(--border-card);
  box-shadow: none;
}

.m-faqscreen .title {
  margin: 14px 18px 8px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 24px;
  color: var(--text-light);
}

.m-faqscreen .list {
  list-style: none;
  padding: 0;
  margin: 8px 16px 0;
  background: #FFFFFF;
  border-radius: 14px;
  border: 1px solid var(--border-card);
  box-shadow: none;
  overflow: hidden;
}

.m-faqscreen .row {
  border-top: 1px solid var(--divider);
}

.m-faqscreen .row:first-child { border-top: 0; }

.m-faqscreen .rowButton {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  padding: 16px 16px;
  background: transparent;
  border: 0;
  text-align: left;
  color: var(--text-light);
}

.m-faqscreen .question {
  flex: 1;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 15px;
  line-height: 1.35;
}

.m-faqscreen .toggleIcon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-light);
}

.m-faqscreen .answer {
  padding: 0 16px 16px;
}

.m-faqscreen .answerText {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 14px;
  line-height: 1.5;
  color: var(--text-light);
}

.m-faqscreen .group {
  margin-top: 12px;
}

.m-faqscreen .groupTitle {
  margin: 0 0 6px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 14px;
  color: var(--text-light);
}

.m-faqscreen .groupSteps {
  padding-left: 22px;
  margin: 4px 0 0;
  font-family: var(--font-serif);
  font-size: 14px;
  line-height: 1.5;
  color: var(--text-light);
}

/* from components/screens/FirstKegelWorkoutScreen.module.css */
/* ============================================================ */
/*  Intro stage                                                   */
/* ============================================================ */

.m-firstkegelworkoutscreen .intro {
  min-height: 100dvh;
  background: var(--surface-light);
  display: flex;
  flex-direction: column;
  padding-bottom: 100px;
}

/* ===== Exercise-details layout (reference "31_Exercise Details") ===== */

/* Full-bleed hero image with a back arrow overlaid top-left. */
.m-firstkegelworkoutscreen .heroFull {
  position: relative;
  width: 100%;
}

.m-firstkegelworkoutscreen .heroImage {
  width: 100%;
  height: 200px;
  background-color: #E0E1DE;
  background-size: cover;
  background-position: center;
}

.m-firstkegelworkoutscreen .backBtn {
  position: absolute;
  top: 16px;
  left: 14px;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 0;
  background: rgba(255, 255, 255, 0.9);
  color: #192126;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 2;
}

/* White stats card floating over the bottom of the hero image. */
.m-firstkegelworkoutscreen .statsCard {
  position: relative;
  z-index: 1;
  margin: -34px 20px 0;
  background: #FFFFFF;
  border-radius: 20px;
  padding: 16px 12px;
  display: flex;
  align-items: center;
}

.m-firstkegelworkoutscreen .statCell {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-width: 0;
}

.m-firstkegelworkoutscreen .statCellIcon {
  font-size: 22px;
  line-height: 1;
  /* render the ⏱️/💪 stat icons as solid black to match the monochrome emoji theme */
}

.m-firstkegelworkoutscreen .statCellValue {
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 16px;
  color: var(--text-light);
  white-space: nowrap;
}

.m-firstkegelworkoutscreen .statCellSep {
  width: 1px;
  align-self: stretch;
  background: var(--border-card);
  margin: 2px 4px;
}

/* ----- Chips row (Level / Type / Focus) ----- */
.m-firstkegelworkoutscreen .chipsRow {
  display: flex;
  gap: 10px;
  padding: 18px 20px 0;
}

.m-firstkegelworkoutscreen .chip {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.m-firstkegelworkoutscreen .chipLabel {
  font-family: var(--font-sans);
  font-size: 10px;
  letter-spacing: 0.04em;
  color: var(--text-light-muted);
  text-align: center;
}

.m-firstkegelworkoutscreen .chipValue {
  background: var(--cta-dark);
  border-radius: 8px;
  padding: 10px 6px;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 13px;
  color: #FFFFFF;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ----- Detail title + description ----- */
.m-firstkegelworkoutscreen .detail {
  padding: 18px 20px 4px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.m-firstkegelworkoutscreen .overviewTitle {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 26px;
  line-height: 1.12;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  color: var(--text-light);
}

.m-firstkegelworkoutscreen .overviewDesc {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 14px;
  line-height: 1.55;
  color: var(--text-light-muted);
}

.m-firstkegelworkoutscreen .overviewNote {
  margin: 0;
  font-family: var(--font-sans);
  font-size: 13px;
  line-height: 1.4;
  color: var(--text-light-muted);
}

/* ----- Content sections ----- */
.m-firstkegelworkoutscreen .content {
  padding: 22px 20px 8px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.m-firstkegelworkoutscreen .sectionLabel {
  margin: 12px 0 4px;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 14px;
  letter-spacing: 0.08em;
  color: var(--text-light);
}

.m-firstkegelworkoutscreen .goalText {
  margin: 0 0 8px;
  font-family: var(--font-serif);
  font-size: 15px;
  line-height: 1.5;
  color: var(--text-light);
}

/* ----- Stretching toggle card ----- */
.m-firstkegelworkoutscreen .toggleCard {
  background: #fff;
  border: 1px solid var(--border-light);
  border-radius: 12px;
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.m-firstkegelworkoutscreen .toggleRow {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.m-firstkegelworkoutscreen .toggleTitle {
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 16px;
  color: var(--text-light);
}

.m-firstkegelworkoutscreen .toggleExtra {
  color: var(--text-light-muted);
  font-weight: 400; /* Faculty ships 400 only */
}

.m-firstkegelworkoutscreen .toggle {
  width: 50px;
  height: 28px;
  border-radius: 999px;
  background: #E0E1DE;
  border: 0;
  position: relative;
  padding: 0;
  cursor: pointer;
  transition: background 200ms ease;
}

.m-firstkegelworkoutscreen .toggle.toggleOn {
  background: var(--program);
}

.m-firstkegelworkoutscreen .toggleKnob {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: #fff;
  box-shadow: none;
  transition: left 200ms ease;
}

.m-firstkegelworkoutscreen .toggle.toggleOn .toggleKnob {
  left: 25px;
}

.m-firstkegelworkoutscreen .toggleHelp,
.m-firstkegelworkoutscreen .tipHelp {
  display: flex;
  gap: 8px;
  background: #E0E1DE;
  border-radius: 10px;
  padding: 10px 12px;
  align-items: flex-start;
  font-family: var(--font-sans);
  font-size: 13px;
  line-height: 1.4;
  color: var(--text-light);
}

.m-firstkegelworkoutscreen .toggleHelpIcon {
  color: var(--text-light-muted);
  flex-shrink: 0;
  margin-top: 2px;
}

/* ----- Exercise rows ----- */
.m-firstkegelworkoutscreen .exList {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.m-firstkegelworkoutscreen .exRow {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 2px;
  border: 0;
  background: transparent;
  width: 100%;
  text-align: left;
  cursor: pointer;
}

/* Leading completion indicator — empty outline circle by default, filled
   lime with a check when the exercise is done (matches Today's lime checks). */
.m-firstkegelworkoutscreen .exCheck {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 2px solid var(--border-card);
  background: transparent;
  color: transparent;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.m-firstkegelworkoutscreen .exCheckDone {
  border: 0;
  background: var(--program);
  color: var(--program-ink);
}

.m-firstkegelworkoutscreen .exThumb {
  width: 56px;
  height: 56px;
  border-radius: 10px;
  background: #E0E1DE;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  overflow: hidden;
}

.m-firstkegelworkoutscreen .exBody {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.m-firstkegelworkoutscreen .exTitle {
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 17px;
  color: var(--text-light);
}

.m-firstkegelworkoutscreen .exMeta {
  font-family: var(--font-sans);
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--text-light-muted);
  text-transform: uppercase;
}

.m-firstkegelworkoutscreen .exChev {
  color: var(--text-light-muted);
}

/* ----- Tips section ----- */
.m-firstkegelworkoutscreen .tipRow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 2px;
}

.m-firstkegelworkoutscreen .tipTitle {
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 16px;
  color: var(--text-light);
}

.m-firstkegelworkoutscreen .guideLink {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: transparent;
  border: 0;
  color: var(--text-light);
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 13px;
  letter-spacing: 0.05em;
  cursor: pointer;
}

.m-firstkegelworkoutscreen .markCompleteBtn {
  margin-top: 14px;
  width: 100%;
  height: 50px;
  background: #E0E1DE;
  color: var(--text-light);
  border: 0;
  border-radius: 10px;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 14px;
  letter-spacing: 0.08em;
  cursor: pointer;
}

/* ----- Bottom START WORKOUT ----- */
.m-firstkegelworkoutscreen .footer {
  position: fixed;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 100%;
  max-width: 375px;
  padding: 14px 20px 22px;
  background: linear-gradient(180deg, rgba(255,255,255,0.0) 0%, #fff 30%);
  z-index: 10;
}

.m-firstkegelworkoutscreen .startBtn {
  width: 100%;
  height: 56px;
  background: var(--program);
  color: var(--program-ink);
  border: 0;
  border-radius: 12px;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 16px;
  letter-spacing: 0.1em;
  cursor: pointer;
  box-shadow: none;
}

.m-firstkegelworkoutscreen .startBtn:active {
  transform: scale(0.99);
}

/* ============================================================ */
/*  Warm-up video stage                                           */
/* ============================================================ */

.m-firstkegelworkoutscreen .warmup {
  position: relative;
  min-height: 100dvh;
  height: 100dvh;
  background: #000;
  color: #fff;
  overflow: hidden;
}

.m-firstkegelworkoutscreen .video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  cursor: pointer;
  background: #000;
}

.m-firstkegelworkoutscreen .scrim {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(180deg, rgba(0,0,0,0.45) 0%, rgba(0,0,0,0) 18%),
    linear-gradient(0deg, rgba(0,0,0,0.6) 0%, rgba(0,0,0,0) 40%);
}

.m-firstkegelworkoutscreen .warmupTop {
  position: absolute;
  top: 14px;
  left: 12px;
  right: 12px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  z-index: 2;
}

.m-firstkegelworkoutscreen .warmupRoundBtn {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 0;
  background: rgba(0, 0, 0, 0.4);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.m-firstkegelworkoutscreen .warmupBottom {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 14px 20px 22px;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.m-firstkegelworkoutscreen .warmupTitle {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 22px;
  line-height: 1.2;
}

.m-firstkegelworkoutscreen .warmupSubtitle {
  margin: 0;
  font-family: var(--font-sans);
  font-size: 13px;
  color: rgba(255,255,255,0.75);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.m-firstkegelworkoutscreen .warmupSeek {
  position: relative;
  width: 100%;
  height: 4px;
  border: 0;
  padding: 0;
  background: rgba(255,255,255,0.25);
  border-radius: 2px;
  cursor: pointer;
  margin-top: 6px;
}

.m-firstkegelworkoutscreen .warmupSeekFill {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  background: var(--program);
  border-radius: 2px;
}

.m-firstkegelworkoutscreen .warmupSeekTimes {
  display: flex;
  justify-content: space-between;
  font-family: var(--font-sans);
  font-size: 12px;
  color: rgba(255,255,255,0.85);
}

.m-firstkegelworkoutscreen .warmupControls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 32px;
  margin-top: 8px;
}

.m-firstkegelworkoutscreen .warmupSkipBtn {
  position: relative;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: 0;
  background: rgba(0,0,0,0.4);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.m-firstkegelworkoutscreen .warmupSkipBtn span {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -42%);
  font-family: var(--font-sans);
  font-size: 11px;
  font-weight: 400; /* Faculty ships 400 only */
}

.m-firstkegelworkoutscreen .warmupBigBtn {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  border: 0;
  background: #fff;
  color: #192126;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.m-firstkegelworkoutscreen .warmupSkip {
  margin-top: 10px;
  align-self: center;
  background: transparent;
  border: 1px solid rgba(255,255,255,0.5);
  color: #fff;
  padding: 8px 18px;
  border-radius: 999px;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 11px;
  letter-spacing: 0.1em;
  cursor: pointer;
}

/* ============================================================ */
/*  Congrats modal over player                                    */
/* ============================================================ */

.m-firstkegelworkoutscreen .playerHost {
  position: relative;
  width: 100%;
  min-height: 100dvh;
}

.m-firstkegelworkoutscreen .modalScrim {
  position: absolute;
  inset: 0;
  background: rgba(0,0,0,0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px 18px;
  z-index: 50;
  pointer-events: auto;
}

.m-firstkegelworkoutscreen .modalCard {
  width: 100%;
  max-width: 340px;
  background: #fff;
  border: 1px solid var(--border-card);
  border-radius: 18px;
  padding: 18px 18px 18px;
  box-shadow: none;
  display: flex;
  flex-direction: column;
  align-items: stretch;
}

.m-firstkegelworkoutscreen .modalIllustration {
  background: #E0E1DE;
  border-radius: 14px;
  height: 230px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 8px;
  margin-bottom: 14px;
}

.m-firstkegelworkoutscreen .stretchSvg {
  max-width: 220px;
  max-height: 220px;
}

.m-firstkegelworkoutscreen .modalTitle {
  margin: 0 0 10px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 26px;
  line-height: 1.15;
  color: var(--text-light);
}

.m-firstkegelworkoutscreen .modalBody {
  margin: 0 0 18px;
  font-family: var(--font-serif);
  font-size: 16px;
  line-height: 1.45;
  color: var(--text-light);
}

.m-firstkegelworkoutscreen .letsGoBtn {
  width: 100%;
  height: 52px;
  background: var(--program);
  color: var(--program-ink);
  border: 0;
  border-radius: 8px;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 16px;
  letter-spacing: 0.1em;
  cursor: pointer;
  box-shadow: none;
}

.m-firstkegelworkoutscreen .letsGoBtn:active {
  transform: scale(0.99);
}

.m-firstkegelworkoutscreen .playerStub {
  width: 100%;
  min-height: 100dvh;
  background: var(--surface-light);
}

.m-firstkegelworkoutscreen .markCompleteBtnDone {
  background: #192126;
  color: #FFFFFF;
}

/* ============================================================ */
/*  Exercise detail sheet                                         */
/* ============================================================ */

/* Scrim is `position: fixed` so the sheet's bottom always meets the bottom
 * of the visible window — no matter where the user has scrolled. Constrained
 * to the 375px phone-frame width and centered, so on wide desktop previews
 * the dim doesn't spill past the simulated phone. */
.m-firstkegelworkoutscreen .detailScrim {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 100%;
  max-width: 375px;
  background: rgba(0, 0, 0, 0.42);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  z-index: 60;
  animation: detailScrimFadeIn 220ms ease-out both;
}

/* Sheet slides up from the bottom and leaves ~70px of the underlying
 * screen visible at the top — matches the iOS reference. Height is sized
 * relative to the scrim (which now matches the phone viewport), so the
 * sheet can never grow taller than the page itself. Width is capped at
 * the phone viewport's 375px so the popup never exceeds the page on wider
 * previews. `overscroll-behavior: contain` keeps swipes inside the sheet
 * from chaining into the page underneath. */
.m-firstkegelworkoutscreen .detailSheet {
  width: 100%;
  max-width: 375px;
  height: calc(100% - 70px);
  max-height: calc(100% - 70px);
  background: #fff;
  border-radius: 20px 20px 0 0;
  padding: 18px 20px 22px;
  overflow-y: auto;
  overscroll-behavior: contain;
  position: relative;
  animation: detailSheetSlideUp 320ms cubic-bezier(0.22, 1, 0.36, 1) both;
}

@keyframes detailScrimFadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes detailSheetSlideUp {
  from { transform: translateY(100%); }
  to   { transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .m-firstkegelworkoutscreen .detailScrim,
  .m-firstkegelworkoutscreen .detailSheet { animation: none; }
}

.m-firstkegelworkoutscreen .detailHeader {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 14px;
}

.m-firstkegelworkoutscreen .detailTitle {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 22px;
  color: var(--text-light);
}

.m-firstkegelworkoutscreen .detailClose {
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 0;
  background: #E0E1DE;
  color: var(--text-light);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.m-firstkegelworkoutscreen .detailIllustration {
  background: var(--program-tint);
  border-radius: 14px;
  padding: 18px 14px;
  margin-bottom: 18px;
}

.m-firstkegelworkoutscreen .diagramSvg {
  width: 100%;
  height: auto;
  display: block;
}

.m-firstkegelworkoutscreen .diagramText {
  font-family: var(--font-serif);
  font-size: 12px;
  fill: var(--text-light);
}

.m-firstkegelworkoutscreen .detailSection {
  margin: 12px 0 8px;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 13px;
  letter-spacing: 0.08em;
  color: var(--text-light);
}

.m-firstkegelworkoutscreen .detailSteps {
  list-style: none;
  margin: 0 0 14px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.m-firstkegelworkoutscreen .detailStep {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-family: var(--font-serif);
  font-size: 15px;
  line-height: 1.45;
  color: var(--text-light);
}

.m-firstkegelworkoutscreen .detailStepNum {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--program);
  color: var(--program-ink);
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 12px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.m-firstkegelworkoutscreen .detailIntensity {
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  background: #E0E1DE;
  border: 0;
  border-radius: 10px;
  padding: 14px 16px;
  cursor: pointer;
  margin-bottom: 14px;
}

.m-firstkegelworkoutscreen .detailIntensityLabel {
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 16px;
  color: var(--text-light);
}

/* Inline intensity "dial" (slider) — replaces the old pop-up picker. */
.m-firstkegelworkoutscreen .intensityDial {
  margin-top: 6px;
  padding: 4px 6px 2px;
}

.m-firstkegelworkoutscreen .intensityDialTop {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 14px;
}

.m-firstkegelworkoutscreen .intensityDialValue {
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 14px;
  letter-spacing: 0.06em;
  color: var(--text-light);
}

.m-firstkegelworkoutscreen .intensitySlider {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 6px;
  border-radius: 999px;
  background: #E0E1DE;
  outline: none;
  margin: 0;
}

.m-firstkegelworkoutscreen .intensitySlider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--program);
  border: 3px solid #fff;
  box-shadow: none;
  cursor: pointer;
}

.m-firstkegelworkoutscreen .intensitySlider::-moz-range-thumb {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--program);
  border: 3px solid #fff;
  box-shadow: none;
  cursor: pointer;
}

.m-firstkegelworkoutscreen .intensityTicks {
  display: flex;
  justify-content: space-between;
  margin-top: 10px;
  gap: 4px;
}

.m-firstkegelworkoutscreen .intensityTick {
  flex: 1;
  text-align: center;
  font-family: var(--font-sans);
  font-size: 9.5px;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--text-light-muted);
  line-height: 1.2;
}

.m-firstkegelworkoutscreen .intensityTick:first-child { text-align: left; }
.m-firstkegelworkoutscreen .intensityTick:last-child { text-align: right; }

.m-firstkegelworkoutscreen .detailIntensityValue {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 13px;
  letter-spacing: 0.06em;
  color: var(--text-light);
}

.m-firstkegelworkoutscreen .detailSaveBtn {
  width: 100%;
  height: 50px;
  border: 0;
  border-radius: 10px;
  background: #E0E1DE;
  color: var(--text-light-muted);
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 14px;
  letter-spacing: 0.08em;
  cursor: not-allowed;
}

.m-firstkegelworkoutscreen .detailSaveBtnActive {
  background: var(--program);
  color: var(--program-ink);
  cursor: pointer;
  box-shadow: none;
}

.m-firstkegelworkoutscreen .detailSaveBtnActive:active {
  transform: scale(0.99);
}

/* Custom Kegel builder — remove-exercise affordance under SAVE. */
.m-firstkegelworkoutscreen .detailRemoveBtn {
  width: 100%;
  height: 46px;
  margin-top: 10px;
  border: 0;
  border-radius: 10px;
  background: transparent;
  color: #ED4747;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 13px;
  letter-spacing: 0.08em;
  cursor: pointer;
}

/* ----- Level picker sheet (nested) ----- */
.m-firstkegelworkoutscreen .pickerScrim {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.38);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  z-index: 70;
}

.m-firstkegelworkoutscreen .pickerSheet {
  width: 100%;
  max-width: 420px;
  background: #fff;
  border-radius: 20px 20px 0 0;
  padding: 14px 18px 22px;
}

.m-firstkegelworkoutscreen .pickerList {
  list-style: none;
  margin: 0 0 12px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.m-firstkegelworkoutscreen .pickerItem {
  display: flex;
  justify-content: center;
}

.m-firstkegelworkoutscreen .pickerBtn {
  width: 100%;
  background: transparent;
  border: 0;
  padding: 12px 16px;
  border-radius: 999px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 16px;
  color: var(--text-light-muted);
  cursor: pointer;
}

.m-firstkegelworkoutscreen .pickerBtnActive {
  background: #E0E1DE;
  color: var(--text-light);
  font-weight: 400; /* Faculty ships 400 only */
}

.m-firstkegelworkoutscreen .pickerSelectBtn {
  width: 100%;
  height: 48px;
  border: 0;
  border-radius: 10px;
  background: #E0E1DE;
  color: var(--text-light);
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 13px;
  letter-spacing: 0.08em;
  cursor: pointer;
}

/* ============================================================ */
/*  Practice complete (feedback)                                  */
/* ============================================================ */

.m-firstkegelworkoutscreen .complete {
  min-height: 100dvh;
  background: var(--surface-light);
  display: flex;
  flex-direction: column;
  padding: 14px 20px 22px;
}

.m-firstkegelworkoutscreen .completeTop {
  display: flex;
  justify-content: flex-end;
}

.m-firstkegelworkoutscreen .completeClose {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 0;
  background: transparent;
  color: var(--text-light);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.m-firstkegelworkoutscreen .completeBody {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 8px 0 14px;
}

.m-firstkegelworkoutscreen .completeRing {
  margin-top: 18px;
  margin-bottom: 24px;
}

.m-firstkegelworkoutscreen .completeTitle {
  margin: 0 0 6px;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 36px;
  letter-spacing: 0.02em;
  color: var(--text-light);
  text-align: center;
}

.m-firstkegelworkoutscreen .completeSubtitle {
  margin: 0 0 26px;
  font-family: var(--font-serif);
  font-size: 18px;
  color: var(--text-light-muted);
  text-align: center;
}

.m-firstkegelworkoutscreen .completeOptions {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.m-firstkegelworkoutscreen .completeOption {
  width: 100%;
  background: #E0E1DE;
  border: 2px solid transparent;
  border-radius: 12px;
  padding: 14px 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  cursor: pointer;
  color: var(--text-light);
  transition: border-color 150ms ease, background 150ms ease;
}

.m-firstkegelworkoutscreen .completeOption:hover {
  background: #D7D9D4;
}

.m-firstkegelworkoutscreen .completeOptionActive {
  /* Selected = themed frame only (no fill): keep the unselected card
     background and just show the accent-coloured border. */
  border-color: var(--program);
  background: #E0E1DE;
  color: var(--text-light);
}

.m-firstkegelworkoutscreen .completeOptionLabel {
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 16px;
  text-align: left;
}

.m-firstkegelworkoutscreen .completeFooter {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding-top: 14px;
}

.m-firstkegelworkoutscreen .completeContinue {
  width: 100%;
  height: 54px;
  border: 0;
  border-radius: 12px;
  background: #E0E1DE;
  color: var(--text-light-muted);
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 16px;
  letter-spacing: 0.1em;
  cursor: not-allowed;
}

.m-firstkegelworkoutscreen .completeContinue:not(:disabled) {
  background: var(--program);
  color: var(--program-ink);
  cursor: pointer;
  box-shadow: none;
}

.m-firstkegelworkoutscreen .completeContinue:not(:disabled):active {
  transform: scale(0.99);
}

.m-firstkegelworkoutscreen .completeExit {
  width: 100%;
  height: 50px;
  border: 0;
  background: transparent;
  color: var(--text-light);
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 14px;
  letter-spacing: 0.08em;
  cursor: pointer;
}

/* ----- Dark variant (Resistance Kegel completion) -----
 * Compound selectors keep the layout shared with the light variant and only
 * recolor the surfaces / text. Toggle by adding `.completeDark` next to
 * `.complete` on the root <main>. */
.m-firstkegelworkoutscreen .completeDark {
  background: #192126;
  color: #fff;
}

.m-firstkegelworkoutscreen .completeDark .completeClose {
  color: var(--text-light-muted);
}

.m-firstkegelworkoutscreen .completeDark .completeTitle {
  color: var(--program);
}

.m-firstkegelworkoutscreen .completeDark .completeSubtitle {
  color: var(--text-light-muted);
}

.m-firstkegelworkoutscreen .completeDark .completeOption {
  background: #384046;
  color: #FFFFFF;
  border-color: transparent;
}

.m-firstkegelworkoutscreen .completeDark .completeOption:hover {
  background: #384046;
}

.m-firstkegelworkoutscreen .completeDark .completeOptionActive {
  /* Selected = themed frame only (no fill): keep the unselected card
     background and just show the accent-coloured border. */
  background: #384046;
  border-color: var(--program);
  color: #fff;
}

.m-firstkegelworkoutscreen .completeDark .completeContinue {
  background: #192126;
  color: var(--text-light-muted);
}

.m-firstkegelworkoutscreen .completeDark .completeContinue:not(:disabled) {
  background: var(--program);
  color: var(--program-ink);
}

.m-firstkegelworkoutscreen .completeDark .completeExit {
  color: #FFFFFF;
}

/* ============================================================ */
/*  Unsaved-changes confirmation (inside detail sheet)            */
/* ============================================================ */

.m-firstkegelworkoutscreen .unsavedScrim {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.35);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  z-index: 90;
}

.m-firstkegelworkoutscreen .unsavedCard {
  width: 100%;
  max-width: 320px;
  background: #fff;
  border: 1px solid var(--border-card);
  border-radius: 18px;
  padding: 24px 20px 20px;
  box-shadow: none;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.m-firstkegelworkoutscreen .unsavedTitle {
  margin: 0 0 4px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 19px;
  line-height: 1.25;
  color: var(--text-light);
  text-align: left;
}

.m-firstkegelworkoutscreen .unsavedCancel {
  width: 100%;
  height: 52px;
  border: 0;
  border-radius: 10px;
  background: #E0E1DE;
  color: var(--text-light-muted);
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 14px;
  letter-spacing: 0.12em;
  cursor: pointer;
}

.m-firstkegelworkoutscreen .unsavedDiscard {
  width: 100%;
  height: 52px;
  border: 0;
  border-radius: 10px;
  background: var(--cta-dark);
  color: #fff;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 14px;
  letter-spacing: 0.12em;
  cursor: pointer;
}

/* ============================================================ */
/*  Quit confirmation modal                                       */
/* ============================================================ */

.m-firstkegelworkoutscreen .quitScrim {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 22px;
  z-index: 80;
}

.m-firstkegelworkoutscreen .quitCard {
  width: 100%;
  max-width: 340px;
  background: #fff;
  border: 1px solid var(--border-card);
  border-radius: 18px;
  padding: 22px 22px 18px;
  box-shadow: none;
}

.m-firstkegelworkoutscreen .quitTitle {
  margin: 0 0 8px;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 22px;
  color: var(--text-light);
  text-align: center;
}

.m-firstkegelworkoutscreen .quitBody {
  margin: 0 0 18px;
  font-family: var(--font-serif);
  font-size: 15px;
  line-height: 1.45;
  color: var(--text-light);
  text-align: center;
}

.m-firstkegelworkoutscreen .quitContinueBtn {
  width: 100%;
  height: 50px;
  border: 0;
  border-radius: 10px;
  background: var(--program);
  color: var(--program-ink);
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 14px;
  letter-spacing: 0.08em;
  cursor: pointer;
  margin-bottom: 10px;
  box-shadow: none;
}

.m-firstkegelworkoutscreen .quitContinueBtn:active {
  transform: scale(0.99);
}

.m-firstkegelworkoutscreen .quitLeaveBtn {
  width: 100%;
  height: 44px;
  border: 0;
  background: transparent;
  color: var(--text-light-muted);
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 13px;
  letter-spacing: 0.08em;
  cursor: pointer;
}

/* from components/screens/KegelUltimatePaywallScreen.module.css */
.m-kegelultimatepaywallscreen .root {
  display: flex;
  flex-direction: column;
  min-height: 100%;
  background: var(--bg-light);
  padding: 0 20px 24px;
}

.m-kegelultimatepaywallscreen .close {
  position: sticky;
  top: 0;
  align-self: flex-start;
  margin: 10px 0 0 -4px;
  width: 40px;
  height: 40px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: transparent;
  color: var(--text-light);
  cursor: pointer;
  z-index: 2;
}

.m-kegelultimatepaywallscreen .body {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.m-kegelultimatepaywallscreen .lockBadge {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: #192126;
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin: 6px 0 18px;
}

.m-kegelultimatepaywallscreen .eyebrow {
  font-family: var(--font-sans);
  font-size: 11px;
  font-weight: 400; /* Faculty ships 400 only */
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #BBF246;
}

.m-kegelultimatepaywallscreen .title {
  font-size: 26px;
  font-weight: 400; /* Faculty ships 400 only */
  color: var(--text-light);
  margin: 6px 0 8px;
  line-height: 1.15;
}

.m-kegelultimatepaywallscreen .subtitle {
  font-family: var(--font-sans);
  font-size: 15px;
  color: var(--text-light-muted);
  max-width: 300px;
  line-height: 1.4;
}

.m-kegelultimatepaywallscreen .priceRow {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 22px;
}

.m-kegelultimatepaywallscreen .price {
  font-size: 32px;
  font-weight: 400; /* Faculty ships 400 only */
  color: #192126;
}

.m-kegelultimatepaywallscreen .normal {
  font-size: 18px;
  color: var(--text-light-muted);
  text-decoration: line-through;
}

.m-kegelultimatepaywallscreen .badge {
  font-family: var(--font-sans);
  font-size: 10px;
  font-weight: 400; /* Faculty ships 400 only */
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--program-ink);
  background: var(--program);
  padding: 4px 8px;
  border-radius: 6px;
}

.m-kegelultimatepaywallscreen .priceNote {
  font-family: var(--font-sans);
  font-size: 12px;
  color: var(--text-light-muted);
  margin: 6px 0 0;
}

.m-kegelultimatepaywallscreen .features {
  list-style: none;
  margin: 26px 0 0;
  padding: 0;
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 14px;
  text-align: left;
}

.m-kegelultimatepaywallscreen .feature {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.4;
  color: var(--text-light);
}

.m-kegelultimatepaywallscreen .featureCheck {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: #BBF246;
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-top: 1px;
}

.m-kegelultimatepaywallscreen .footer {
  margin-top: 28px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.m-kegelultimatepaywallscreen .cta {
  width: 100%;
  border: none;
  border-radius: 14px;
  background: #192126;
  color: #fff;
  font-family: var(--font-sans);
  font-size: 16px;
  font-weight: 400; /* Faculty ships 400 only */
  padding: 16px;
  cursor: pointer;
}

.m-kegelultimatepaywallscreen .cta:active {
  opacity: 0.9;
}

.m-kegelultimatepaywallscreen .decline {
  width: 100%;
  border: none;
  background: transparent;
  color: var(--text-light-muted);
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 400; /* Faculty ships 400 only */
  padding: 10px;
  cursor: pointer;
}

/* from components/screens/KegelWorkoutPlayer.module.css */
.m-kegelworkoutplayer .page {
  position: relative;
  min-height: 100dvh;
  height: 100dvh;
  background: var(--surface-light);
  color: var(--text-light);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* ----- Top bar (X close) ----- */
.m-kegelworkoutplayer .topBar {
  display: flex;
  justify-content: flex-end;
  padding: 14px 14px 0;
}

.m-kegelworkoutplayer .roundBtn {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 0;
  background: rgba(0, 0, 0, 0.08);
  color: var(--text-light);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

/* ----- "Guide" pill ----- */
.m-kegelworkoutplayer .guidePill {
  margin: -34px 14px 0;
  align-self: flex-start;
  background: #FFFFFF;
  border: 1.5px solid var(--program);
  border-radius: 12px;
  padding: 6px 12px;
  max-width: 220px;
  text-align: left;
  cursor: pointer;
}

.m-kegelworkoutplayer .guideLabel {
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 10px;
  letter-spacing: 0.12em;
  color: var(--text-light-muted);
  line-height: 1;
}

.m-kegelworkoutplayer .guideRow {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 2px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 13px;
  color: var(--text-light);
}

/* ----- Center: number, label, ring ----- */
.m-kegelworkoutplayer .center {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 4px 24px 4px;
  text-align: center;
}

.m-kegelworkoutplayer .bigNumber {
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 64px;
  line-height: 1;
  color: var(--program);
  letter-spacing: 0.01em;
}

.m-kegelworkoutplayer .label {
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 18px;
  color: var(--text-light);
  margin-bottom: 8px;
}

/* ----- Ring ----- */
/* Outer wrap is fixed size (large enough to contain the contracted backdrop).
   Both the backdrop and the progress arc are absolutely positioned inside,
   centered. Only the backdrop changes size between states; the arc stays put. */
.m-kegelworkoutplayer .ringWrap {
  position: relative;
  width: 320px;
  height: 320px;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Breathing concentric rings — nested translucent lime bands that grow on
   contract (inhale) and slowly collapse toward the progress-ring size on
   release (exhale). The banded radial gradient scales with the element so the
   rings expand/collapse together. Sits behind the SVG progress arc + disc. */
.m-kegelworkoutplayer .ringBackdrop {
  position: absolute;
  top: 50%;
  left: 50%;
  border-radius: 50%;
  border: 0;
  background:
    /* concentric rings — the SAME shade as the progress bar (lime rgb 205,230,104)
       but lighter: inner band densest, fading lighter outward. Thin white
       frames between bands. */
    radial-gradient(
      circle at center,
      rgba(var(--program-rgb), 0.55) 0%,
      rgba(var(--program-rgb), 0.55) 18.6%,
      rgba(255, 255, 255, 0.85) 18.6%,
      rgba(255, 255, 255, 0.85) 19.2%,
      rgba(var(--program-rgb), 0.42) 19.2%,
      rgba(var(--program-rgb), 0.42) 38.6%,
      rgba(255, 255, 255, 0.75) 38.6%,
      rgba(255, 255, 255, 0.75) 39.2%,
      rgba(var(--program-rgb), 0.30) 39.2%,
      rgba(var(--program-rgb), 0.30) 58.6%,
      rgba(255, 255, 255, 0.62) 58.6%,
      rgba(255, 255, 255, 0.62) 59.2%,
      rgba(var(--program-rgb), 0.19) 59.2%,
      rgba(var(--program-rgb), 0.19) 78.6%,
      rgba(255, 255, 255, 0.5) 78.6%,
      rgba(255, 255, 255, 0.5) 79.2%,
      rgba(var(--program-rgb), 0.09) 79.2%,
      rgba(var(--program-rgb), 0.09) 100%
    );
  filter: blur(0.4px);
  box-shadow: none;
  transform: translate(-50%, -50%);
  /* Gradual, eased breathing: a smooth ease-in-out (slow start + slow end) a
     touch longer than a breath, so the ring keeps gliding — never snaps on. */
  transition: width 2600ms cubic-bezier(0.5, 0, 0.5, 1),
    height 2600ms cubic-bezier(0.5, 0, 0.5, 1);
}

.m-kegelworkoutplayer .backdropReady {
  width: 40px;
  height: 40px;
}

.m-kegelworkoutplayer .backdropRest {
  width: 40px;
  height: 40px;
}

/* Released: gradient shrinks down to match the 240px progress ring. */
.m-kegelworkoutplayer .backdropRelaxed {
  width: 40px;
  height: 40px;
}

/* Contracted: gradient gently blooms past the progress ring. */
.m-kegelworkoutplayer .backdropContracted {
  width: 280px;
  height: 280px;
}

/* Flicker (quick contract/relax): FULL amplitude — collapses fully on relax
   and blooms to the maximum ring size on contract, so the rapid beat reads as
   a strong pulse. Paired with `.backdropFast` for the quick 1-second beat. */
.m-kegelworkoutplayer .backdropFlickerRelaxed {
  width: 40px;
  height: 40px;
}

.m-kegelworkoutplayer .backdropFlickerContracted {
  width: 320px;
  height: 320px;
}

/* Speed override — drops the 1.8s Waves transition to 600ms so the bloom
   plays cleanly inside each 1-second flicker beat (1s contract / 1s relax).
   Layered on top of `.ringBackdrop` so non-flicker phases keep their slow
   ease. */
.m-kegelworkoutplayer .backdropFast {
  transition: width 600ms cubic-bezier(0.45, 0, 0.55, 1),
    height 600ms cubic-bezier(0.45, 0, 0.55, 1);
}

/* Clasp — asymmetric grow/shrink that mirrors "contract slowly, release
   quickly". The transition lives on the *destination* state so each
   direction uses its own timing:
   • Going INTO contracted: the contracted class applies, browser reads its
     3s ease-in transition, and the backdrop slowly blooms to the larger
     size over the full 3-second hold.
   • Going BACK to relaxed: the relaxed class applies, browser reads its
     150ms snap, and the ring instantly shrinks back to the progress-ring
     size.
*/
.m-kegelworkoutplayer .backdropClaspRelaxed {
  width: 40px;
  height: 40px;
  transition: width 150ms cubic-bezier(0.4, 0, 0.6, 1),
    height 150ms cubic-bezier(0.4, 0, 0.6, 1);
}

.m-kegelworkoutplayer .backdropClaspContracted {
  width: 280px;
  height: 280px;
  transition: width 3000ms cubic-bezier(0.4, 0, 0.4, 1),
    height 3000ms cubic-bezier(0.4, 0, 0.4, 1);
}

/* Inverted Clasp — mirror of Clasp. "Quickly contract, gradually relax over
   3 seconds": the contracted class snaps in fast, the relaxed class drifts
   back over the full 3-second descent. Transition lives on each destination
   so the direction of travel picks up the right timing. */
.m-kegelworkoutplayer .backdropInvertedClaspContracted {
  width: 280px;
  height: 280px;
  transition: width 150ms cubic-bezier(0.4, 0, 0.6, 1),
    height 150ms cubic-bezier(0.4, 0, 0.6, 1);
}

.m-kegelworkoutplayer .backdropInvertedClaspRelaxed {
  width: 40px;
  height: 40px;
  transition: width 3000ms cubic-bezier(0.6, 0, 0.6, 1),
    height 3000ms cubic-bezier(0.6, 0, 0.6, 1);
}

/* Box Breathing — symmetric 4-second grow / 4-second shrink with natural
   plateaus during the two holds. Both destination states use the same 4 s
   ease-in-out so inhale (relaxed → contracted) and exhale (contracted →
   relaxed) feel identical. When the sub-phase advances from inhale to
   hold-full or from exhale to hold-empty the class doesn't change, so no
   transition fires and the backdrop holds its size. */
.m-kegelworkoutplayer .backdropBoxRelaxed {
  width: 40px;
  height: 40px;
  transition: width 4000ms cubic-bezier(0.45, 0, 0.55, 1),
    height 4000ms cubic-bezier(0.45, 0, 0.55, 1);
}

.m-kegelworkoutplayer .backdropBoxContracted {
  width: 280px;
  height: 280px;
  transition: width 4000ms cubic-bezier(0.45, 0, 0.55, 1),
    height 4000ms cubic-bezier(0.45, 0, 0.55, 1);
}

/* Progress arc — fixed 240×240 box, centered over the backdrop. */
.m-kegelworkoutplayer .ringSvg {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 240px;
  height: 240px;
  pointer-events: none;
  transform: translate(-50%, -50%) rotate(-90deg);
  overflow: visible;
  z-index: 2;
}

.m-kegelworkoutplayer .ringTrack {
  stroke: rgba(20, 20, 20, 0.10);
  stroke-width: 8;
}

/* No `stroke` here on purpose — the SVG attribute on the <circle> drives
   colour (solid vs. gradient) and CSS would otherwise override it. */
.m-kegelworkoutplayer .ringFill {
  stroke-width: 10;
  stroke-linecap: round;
}

.m-kegelworkoutplayer .ringPip {
  fill: #E0E1DE;
  transform-origin: 115px 115px;
}

.m-kegelworkoutplayer .ringInnerDisc {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 110px;
  height: 110px;
  border-radius: 50%;
  background: #fff;
  color: var(--text-light);
  border: 1px solid var(--border-card);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: none;
}

/* ----- Complete CTA ----- */
.m-kegelworkoutplayer .completeBtn {
  margin-top: 16px;
  width: 100%;
  max-width: 280px;
  height: 50px;
  border: 0;
  border-radius: 10px;
  background: var(--cta-dark);
  color: #fff;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 14px;
  letter-spacing: 0.08em;
  cursor: pointer;
}

/* ----- Bottom card ----- */
.m-kegelworkoutplayer .bottomCard {
  padding: 12px 16px 22px;
  background: #fff;
  border-top: 1px solid var(--divider);
}

.m-kegelworkoutplayer .iconRow {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 8px 12px;
}

.m-kegelworkoutplayer .iconBtn {
  background: transparent;
  border: 0;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-light);
  cursor: pointer;
}

.m-kegelworkoutplayer .iconBtnOn {
  color: var(--text-light);
}

/* ----- Header (Exercise N of M + title) ----- */
.m-kegelworkoutplayer .kHead {
  padding: 4px 20px 0;
  text-align: center;
}

.m-kegelworkoutplayer .counter {
  margin: 0;
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--text-light);
}

.m-kegelworkoutplayer .counterChip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  margin: 0 2px;
  border-radius: 6px;
  background: var(--program);
  color: var(--program-ink);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 13px;
}

.m-kegelworkoutplayer .kTitle {
  margin: 3px 0 0;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 20px;
  line-height: 1.15;
  color: var(--text-light);
  text-transform: capitalize;
}

/* ----- Exercise timeline (replaces phase tabs) ----- */
.m-kegelworkoutplayer .timeline {
  position: relative;
  max-height: 128px;
  overflow-y: auto;
  scrollbar-width: none;
  padding: 2px 2px 0;
}

.m-kegelworkoutplayer .timeline::-webkit-scrollbar { display: none; }

.m-kegelworkoutplayer .tlRow {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  width: 100%;
  background: transparent;
  border: 0;
  padding: 0;
  text-align: left;
  cursor: pointer;
}

.m-kegelworkoutplayer .tlMarker {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  align-self: stretch;
}

.m-kegelworkoutplayer .tlNum {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-sans);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 15px;
  flex-shrink: 0;
  z-index: 1;
}

.m-kegelworkoutplayer .num_upcoming {
  background: #E0E1DE;
  color: var(--text-light);
  box-shadow: none;
}
.m-kegelworkoutplayer .num_done {
  background: var(--program);
  color: var(--program-ink);
  box-shadow: none;
}
.m-kegelworkoutplayer .num_current {
  background: var(--program-tint);
  color: var(--text-light);
  border: 1px solid var(--program);
  box-shadow: none;
}

.m-kegelworkoutplayer .tlLine {
  flex: 1 1 auto;
  width: 2px;
  min-height: 12px;
  background: var(--border-light);
  margin: 2px 0;
}

.m-kegelworkoutplayer .tlBody {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 2px 0 12px;
  min-width: 0;
}

.m-kegelworkoutplayer .tlTitle {
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 15px;
  color: var(--text-light);
  text-transform: capitalize;
  line-height: 1.2;
  letter-spacing: -0.01em;
}

.m-kegelworkoutplayer .tlTitleCurrent { color: var(--text-light); }

.m-kegelworkoutplayer .tlMeta {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-sans);
  font-size: 12px;
  color: var(--text-light-muted);
}

/* ----- Info modal (bottom sheet) ----- */
.m-kegelworkoutplayer .modalBackdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  z-index: 50;
}

.m-kegelworkoutplayer .modalSheet {
  position: relative;
  width: 100%;
  max-height: 78%;
  background: #fff;
  border-radius: 20px 20px 0 0;
  padding: 18px 20px 24px;
  overflow-y: auto;
}

.m-kegelworkoutplayer .modalClose {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 0;
  background: transparent;
  color: var(--text-light);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.m-kegelworkoutplayer .modalTitle {
  margin: 0 0 12px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 22px;
  color: var(--text-light);
}

.m-kegelworkoutplayer .modalIntro {
  margin: 0 0 12px;
  font-family: var(--font-serif);
  font-size: 15px;
  line-height: 1.5;
  color: var(--text-light);
}

.m-kegelworkoutplayer .modalSteps,
.m-kegelworkoutplayer .modalDashList {
  list-style: none;
  margin: 0 0 14px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.m-kegelworkoutplayer .modalStep,
.m-kegelworkoutplayer .modalDashRow {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  font-family: var(--font-serif);
  font-size: 15px;
  line-height: 1.45;
  color: var(--text-light);
}

.m-kegelworkoutplayer .modalDash {
  display: inline-block;
  width: 14px;
  height: 3px;
  margin-top: 10px;
  background: var(--program);
  border-radius: 2px;
  flex-shrink: 0;
}

.m-kegelworkoutplayer .modalCallout {
  background: var(--program-tint);
  border: 1.5px solid var(--program);
  border-radius: 10px;
  padding: 12px 14px;
  font-family: var(--font-serif);
  font-size: 14px;
  line-height: 1.5;
  color: #192126;
}

.m-kegelworkoutplayer .modalCallout p {
  margin: 0 0 8px;
}

.m-kegelworkoutplayer .modalCallout p:last-child {
  margin-bottom: 0;
}

/* from components/screens/LessonFlowScreen.module.css */
/* Bounded to exactly one viewport height with overflow clipped, so the
   document itself never scrolls. The inner .body is the scroll container;
   header + footer stay pinned by the flex layout. This is more reliable than
   `position: sticky` on the footer — sticky can fail when an ancestor has
   non-visible overflow or when the flex child won't shrink (the default
   `min-height: auto` on flex children prevents overflow:auto from engaging).
*/
.m-lessonflowscreen .page {
  height: 100dvh;
  background: var(--surface-light);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* ----- Header ----- */
.m-lessonflowscreen .header {
  padding: 10px 16px 12px;
  background: var(--surface-light);
  border-bottom: 1px solid var(--divider);
}

.m-lessonflowscreen .breadcrumbRow {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 24px;
  margin-bottom: 8px;
}

.m-lessonflowscreen .breadcrumb {
  font-family: var(--font-serif);
  font-size: 15px;
  font-weight: 400; /* Faculty ships 400 only */
  color: var(--text-light);
}

.m-lessonflowscreen .controlRow {
  display: flex;
  align-items: center;
  gap: 10px;
}

.m-lessonflowscreen .iconBtn {
  background: transparent;
  border: 0;
  width: 32px;
  height: 32px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-light);
  flex-shrink: 0;
  border-radius: 50%;
}

/* Cursor-only, for the reason spelled out at .appCta:hover — on touch this grey
   plate would stay behind after the tap. */
@media (hover: hover) and (pointer: fine) {
  .m-lessonflowscreen .iconBtn:hover {
    background: rgba(0, 0, 0, 0.04);
  }
}

.m-lessonflowscreen .progress {
  flex: 1;
  display: flex;
  gap: 6px;
}

.m-lessonflowscreen .seg {
  flex: 1;
  height: 4px;
  border-radius: 3px;
  background: rgba(0, 0, 0, 0.08);
  transition: background 0.3s ease;
}

.m-lessonflowscreen .segDone {
  background: var(--program);
}

/* ----- Body ----- */
/* `min-height: 0` is the critical bit: flex children default to
   `min-height: auto` which prevents them shrinking below their content size.
   Without it, `overflow-y: auto` never engages and the parent grows to fit
   content — breaking the bounded-page layout. */
.m-lessonflowscreen .body {
  flex: 1;
  min-height: 0;
  padding: 18px 20px 24px;
  overflow-y: auto;
}

.m-lessonflowscreen .heading {
  margin: 0 0 16px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 28px;
  line-height: 1.2;
  color: var(--text-light);
  letter-spacing: -0.01em;
}

.m-lessonflowscreen .blocks {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.m-lessonflowscreen .text {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 16px;
  line-height: 1.5;
  color: var(--text-light);
}

/* ----- Dash row ----- */
.m-lessonflowscreen .dashRow {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 4px;
}

/* Single-line dash bullet: orange dash sits inline with text, paragraph wraps
   under itself without any bold label heading. */
.m-lessonflowscreen .dashItem {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin-top: 4px;
}

.m-lessonflowscreen .dashItem .dash {
  margin-top: 11px; /* visually align with first text baseline */
}

.m-lessonflowscreen .dashItem .dashText {
  flex: 1;
}

.m-lessonflowscreen .dashRowHead {
  display: flex;
  align-items: center;
  gap: 10px;
}

.m-lessonflowscreen .dash {
  display: inline-block;
  width: 18px;
  height: 3px;
  background: var(--program);
  border-radius: 2px;
  flex-shrink: 0;
}

.m-lessonflowscreen .dashLabel {
  font-family: var(--font-serif);
  font-size: 16px;
  font-weight: 400; /* Faculty ships 400 only */
  color: var(--text-light);
}

.m-lessonflowscreen .dashText {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 16px;
  line-height: 1.5;
  color: var(--text-light);
}

/* ----- Illustration ----- */
.m-lessonflowscreen .illustration {
  width: 100%;
  min-height: 200px;
  height: 240px;
  background: #E0E1DE;
  border: 1px solid var(--border-card);
  border-radius: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  text-align: center;
  margin: 6px 0 4px;
}

.m-lessonflowscreen .illustrationImage {
  background: #E0E1DE;
}

.m-lessonflowscreen .illustrationLabel {
  font-family: var(--font-sans);
  font-size: 12px;
  font-weight: 400; /* Faculty ships 400 only */
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-light-muted);
  max-width: 240px;
  line-height: 1.4;
}

/* ----- Callout (green note) ----- */
.m-lessonflowscreen .callout {
  position: relative;
  background: var(--program-tint);
  border: 1.5px solid var(--program);
  border-radius: 16px;
  padding: 14px 16px;
  margin: 4px 0;
  overflow: hidden;
}

.m-lessonflowscreen .calloutText {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 16px;
  line-height: 1.45;
  color: #192126;
}

/* Stack multiple paragraphs inside a single callout (e.g. the 10
 * distorted-thinking patterns) with a clear visible break between
 * each line — matches the iOS reference where each numbered item
 * sits on its own line inside the same green box. */
.m-lessonflowscreen .calloutText + .calloutText {
  margin-top: 12px;
}

/* ----- Free-form text answer box -----
 *
 * Matches the iOS reference for the Triple Column Exercise: soft beige-grey
 * rounded box, serif body text, no border, just enough internal padding so
 * the entered answer breathes. Lives inline with the other lesson blocks. */
.m-lessonflowscreen .textInput {
  width: 100%;
  background: #E0E1DE;
  border: none;
  border-radius: 14px;
  padding: 14px 16px;
  margin: 4px 0;
  font-family: var(--font-serif);
  font-size: 16px;
  line-height: 1.45;
  color: var(--text-light);
  resize: vertical;
  min-height: 96px;
  box-sizing: border-box;
}

.m-lessonflowscreen .textInput::placeholder {
  color: var(--text-light-muted);
  opacity: 0.7;
}

.m-lessonflowscreen .textInput:focus {
  outline: 2px solid var(--program);
  outline-offset: 2px;
}

/* Locked state — after the user hits CONTINUE the textarea becomes
 * read-only. Muted background, dimmer text, no caret, no focus ring. */
.m-lessonflowscreen .textInputLocked {
  background: #E0E1DE;
  color: var(--text-light);
  cursor: not-allowed;
  caret-color: transparent;
}

.m-lessonflowscreen .textInputLocked:focus {
  outline: none;
}

/* ----- Section label (orange caps) ----- */
.m-lessonflowscreen .sectionLabel {
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 400; /* Faculty ships 400 only */
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-light);
  line-height: 1.3;
  margin-top: 4px;
}

/* Coral bold sub-heading / lead-in that keeps the authored case (no uppercase
   transform). Used by the menopause lessons for salmon title/sentence-case
   labels such as "Vaginal Moisturizers" and "As estrogen declines…:". */
.m-lessonflowscreen .coralLead {
  font-family: var(--font-sans);
  font-size: 15px;
  font-weight: 400; /* Faculty ships 400 only */
  color: var(--program);
  line-height: 1.35;
  margin: 4px 0 0;
}

/* ----- Bullet rows (✅ / ❌) ----- */
.m-lessonflowscreen .bullet {
  display: flex;
  gap: 10px;
  align-items: flex-start;
}

.m-lessonflowscreen .bulletIcon {
  font-size: 18px;
  line-height: 1.2;
  flex-shrink: 0;
  margin-top: 1px;
}

.m-lessonflowscreen .bulletBody {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.m-lessonflowscreen .bulletLabel {
  font-family: var(--font-serif);
  font-size: 16px;
  line-height: 1.5;
  color: var(--text-light);
  font-weight: 400; /* Faculty ships 400 only */
}

.m-lessonflowscreen .bulletText {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 16px;
  line-height: 1.5;
  color: var(--text-light);
}

/* ----- Option (selectable multiple-choice row) -----
   Rendered as a <button> so it's clickable + keyboard-accessible. Reset
   the native button styling so the row looks identical to the prior
   non-interactive markup, then add a selected variant. */
.m-lessonflowscreen .option {
  display: flex;
  align-items: center;
  gap: 12px;
  background: #FFFFFF;
  border: 1.5px solid var(--program);
  border-radius: 16px;
  padding: 14px 16px;
  width: 100%;
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
  transition: background 120ms ease, border-color 120ms ease;
}

.m-lessonflowscreen .option:hover:not(:disabled) {
  background: var(--program-tint);
}

.m-lessonflowscreen .optionSelected {
  background: var(--program-tint);
  border-color: var(--program);
}

/* Locked siblings keep their beige pill so the list still reads as a set of
   answers — only the hover affordance is suppressed (the group is single-
   shot, so hovering an unselected option shouldn't suggest it's clickable). */
.m-lessonflowscreen .option:disabled {
  cursor: default;
  opacity: 1;
}

.m-lessonflowscreen .optionDot {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: 1.5px solid var(--text-light);
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: border-color 120ms ease, background 120ms ease;
}

/* Selected dot: theme-coloured ring with a smaller filled dot in the centre. */
.m-lessonflowscreen .optionDotSelected {
  border-color: var(--program);
}

.m-lessonflowscreen .optionDotSelected::after {
  content: '';
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--program);
}

.m-lessonflowscreen .optionLabel {
  font-family: var(--font-serif);
  font-size: 16px;
  line-height: 1.4;
  color: var(--text-light);
}

/* ----- Subheading ----- */
.m-lessonflowscreen .subheading {
  margin: 4px 0 0;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 20px;
  line-height: 1.25;
  color: var(--text-light);
}

/* Inline serif heading rendered between blocks (Explore practice flows). */
.m-lessonflowscreen .blockHeading {
  margin: 2px 0 0;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 26px;
  line-height: 1.2;
  color: var(--text-light);
  letter-spacing: -0.01em;
}

/* ----- Table (Triple Column explore) ----- */
.m-lessonflowscreen .tableWrap {
  width: 100%;
  overflow-x: auto;
}
.m-lessonflowscreen .table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--font-sans);
  font-size: 12px;
  line-height: 1.35;
}
.m-lessonflowscreen .table th,
.m-lessonflowscreen .table td {
  border: 1px solid var(--border-light);
  padding: 8px;
  text-align: left;
  vertical-align: top;
  color: var(--text-light);
}
.m-lessonflowscreen .tableHeadCell {
  background: var(--surface-beige);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 11px;
  color: var(--text-light-muted);
}

/* ----- Numbered list item ----- */
.m-lessonflowscreen .numberedItem {
  display: flex;
  align-items: flex-start;
  gap: 10px;
}

.m-lessonflowscreen .numberedItemNum {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  margin-top: 2px;
  border-radius: 50%;
  background: var(--program);
  color: var(--program-ink);
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 12px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.m-lessonflowscreen .numberedItemText {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 16px;
  line-height: 1.45;
  color: var(--text-light);
}

/* ----- Media card (video / audio with snippet) ----- */
.m-lessonflowscreen .mediaCard {
  display: flex;
  flex-direction: column;
  background: #fff;
  border: 1px solid var(--border-light);
  border-radius: 18px;
  overflow: hidden;
  margin: 4px 0;
}

.m-lessonflowscreen .mediaPoster {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  background-size: cover;
  background-position: center;
  background-color: #192126;
  background-repeat: no-repeat;
  display: flex;
  align-items: center;
  justify-content: center;
}

.m-lessonflowscreen .mediaScrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(0,0,0,0.15) 0%, rgba(0,0,0,0.45) 100%);
}

.m-lessonflowscreen .mediaWaveform {
  position: absolute;
  left: 10%;
  right: 10%;
  bottom: 14px;
  width: 80%;
  height: 36px;
  opacity: 0.85;
  pointer-events: none;
}

.m-lessonflowscreen .mediaPlay {
  position: relative;
  z-index: 1;
  width: 54px;
  height: 54px;
  border-radius: 50%;
  background: rgba(255,255,255,0.92);
  color: var(--text-light);
  border: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: none;
}

.m-lessonflowscreen .mediaCaption {
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: var(--surface-light);
}

.m-lessonflowscreen .mediaCaptionTitle {
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 16px;
  color: var(--text-light);
}

.m-lessonflowscreen .mediaCaptionSubtitle {
  font-family: var(--font-sans);
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--text-light-muted);
}

/* ----- Footer -----
   Naturally pinned at the bottom of `.page` by the flex layout — `.body`
   takes flex:1 and scrolls internally, this footer is the last flex item.
   `flex-shrink: 0` guards against compression when content is tiny + the
   footer would otherwise be squeezed by `min-height` interactions. */
.m-lessonflowscreen .footer {
  flex-shrink: 0;
  padding: 12px 20px 20px;
  background: var(--surface-light);
  border-top: 1px solid transparent;
}

/* ----- Quiz block (interactive multiple choice) -----
 *
 * Idle: beige pill, hollow dark circle indicator, dark serif label.
 * Revealed-correct: same beige bg, green filled-circle indicator, green
 *   label, and the explanation rendered underneath the label as bold dark
 *   serif text — all inside the same pill (so the correct option grows
 *   vertically to fit its explanation).
 * Revealed-wrong: light coral bg, red hollow circle, red label.
 *
 * Buttons are `display: flex; align-items: flex-start;` so that when the
 * correct option expands with an explanation, the radio dot stays pinned to
 * the top of the pill next to the label rather than floating in the middle.
 */
.m-lessonflowscreen .quiz {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin: 8px 0 4px;
}

.m-lessonflowscreen .quizPrompt {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 16px;
  line-height: 1.5;
  color: var(--text-light);
}

.m-lessonflowscreen .quizOptions {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.m-lessonflowscreen .quizOption {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  width: 100%;
  padding: 16px 20px;
  border: 0;
  border-radius: 14px;
  background: var(--surface-beige);
  color: var(--text-light);
  font-family: var(--font-serif);
  font-size: 17px;
  font-weight: 400; /* Faculty ships 400 only */
  text-align: left;
  cursor: pointer;
  transition: background 160ms ease, color 160ms ease, transform 80ms ease;
}

.m-lessonflowscreen .quizOption:active:not(:disabled) {
  transform: scale(0.99);
}

.m-lessonflowscreen .quizOption:disabled {
  cursor: default;
}

.m-lessonflowscreen .quizDot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 2px solid var(--text-light);
  background: transparent;
  margin-top: 2px;
  flex-shrink: 0;
  transition: background 160ms ease, border-color 160ms ease;
}

.m-lessonflowscreen .quizDotInner {
  display: block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: transparent;
  transition: background 160ms ease;
}

.m-lessonflowscreen .quizOptionBody {
  display: flex;
  flex-direction: column;
  gap: 14px;
  flex: 1;
  min-width: 0;
}

.m-lessonflowscreen .quizOptionLabel {
  font-family: var(--font-serif);
  font-size: 17px;
  font-weight: 400; /* Faculty ships 400 only */
  line-height: 1.3;
}

.m-lessonflowscreen .quizOptionExplanation {
  display: block;
  margin: 0;
  font-family: var(--font-serif);
  font-size: 15px;
  font-weight: 400; /* Faculty ships 400 only */
  line-height: 1.5;
  color: var(--text-light);
}

/* Correct state — light lime wash + lime filled indicator, black label. */
.m-lessonflowscreen .quizOptionCorrect {
  background: var(--program-tint);
  color: #192126;
}

.m-lessonflowscreen .quizOptionCorrect .quizDot {
  background: var(--program);
  border-color: var(--program);
}

.m-lessonflowscreen .quizOptionCorrect .quizDot .quizDotInner {
  background: #FFFFFF;
}

.m-lessonflowscreen .quizOptionCorrect .quizOptionLabel {
  color: #192126;
}

/* Wrong state — light coral wash + coral hollow circle, black label. */
.m-lessonflowscreen .quizOptionWrong {
  background: rgba(237, 71, 71, 0.16);
  color: #192126;
}

.m-lessonflowscreen .quizOptionWrong .quizDot {
  border-color: #ED4747;
  background: transparent;
}

.m-lessonflowscreen .quizOptionWrong .quizOptionLabel {
  color: #192126;
}

/* ----- Comparison card -----
 *
 * Used by the `compareCard` block kind — a rounded card with a bold title
 * and a small bulleted list. Two variants (`neutral` = gray, `accent` =
 * orange-tinted) stack to produce the iOS-reference comparison block.
 */
.m-lessonflowscreen .compareCard {
  border-radius: 14px;
  padding: 18px 20px 16px;
  margin: 6px 0;
}

.m-lessonflowscreen .compareCardNeutral {
  background: #E0E1DE;
  color: var(--text-light);
}

.m-lessonflowscreen .compareCardAccent {
  background: var(--program-tint);
  color: var(--text-light);
}

.m-lessonflowscreen .compareCardTitle {
  margin: 0 0 10px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 19px;
  line-height: 1.2;
}

.m-lessonflowscreen .compareCardAccent .compareCardTitle {
  color: var(--text-light);
}

.m-lessonflowscreen .compareCardList {
  list-style: none;
  margin: 0;
  padding: 0;
}

.m-lessonflowscreen .compareCardItem {
  position: relative;
  padding: 4px 0 4px 18px;
  font-family: var(--font-serif);
  font-size: 16px;
  line-height: 1.35;
}

.m-lessonflowscreen .compareCardItem::before {
  content: '';
  position: absolute;
  left: 4px;
  top: 14px;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: currentColor;
}

/* from components/screens/LessonScreen.module.css */
/* Bounded viewport with internal scroll — see LessonFlowScreen for why. */
.m-lessonscreen .page {
  height: 100dvh;
  background: #FFFFFF;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.m-lessonscreen .body {
  flex: 1;
  min-height: 0;
  padding: 16px 20px 24px;
  overflow-y: auto;
}

.m-lessonscreen .heading {
  margin: 4px 0 16px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 26px;
  line-height: 1.2;
  color: var(--text-light);
}

.m-lessonscreen .bodyText {
  margin: 0 0 18px;
  font-family: var(--font-serif);
  font-size: 16px;
  line-height: 1.5;
  color: var(--text-light);
}

.m-lessonscreen .callout {
  display: flex;
  background: var(--program-tint);
  border: 1.5px solid var(--program);
  border-radius: 16px;
  overflow: hidden;
  padding: 14px 16px;
  position: relative;
}

.m-lessonscreen .calloutBar {
  display: none;
}

.m-lessonscreen .calloutText {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 15px;
  line-height: 1.4;
  color: var(--text-light);
}

/* Naturally pinned by the flex layout — `.body` scrolls internally above. */
.m-lessonscreen .footer {
  flex-shrink: 0;
  padding: 12px 20px 24px;
  background: #FFFFFF;
}

/* from components/screens/LoginScreen.module.css */
.m-loginscreen .page {
  min-height: 100dvh;
  position: relative;
  overflow: hidden;
  color: var(--text-light);
  /* Porcelain with a soft green/violet pastel wash up top — homepage palette. */
  background:
    radial-gradient(92% 42% at 8% 0%, var(--program-tint) 0%, transparent 60%),
    radial-gradient(85% 42% at 100% 6%, rgba(164, 138, 237, 0.14) 0%, transparent 60%),
    var(--bg-light);
}

.m-loginscreen .content {
  position: relative;
  z-index: 1;
  padding: 20px 24px 32px;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}

.m-loginscreen .header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 44px;
}

.m-loginscreen .brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
}

.m-loginscreen .brandMark {
  width: 34px;
  height: 34px;
  border-radius: 10px;
  background: var(--program);
  color: var(--program-ink);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-sans);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 14px;
  letter-spacing: 0.01em;
}

.m-loginscreen .brandName {
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 17px;
  letter-spacing: 0.02em;
  color: var(--text-light);
}

.m-loginscreen .closeBtn {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: #fff;
  border: 1px solid var(--border-light, #e4e9e6);
  color: var(--text-light);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.m-loginscreen .title {
  margin: 0 0 8px;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 30px;
  line-height: 1.12;
  letter-spacing: -0.02em;
  color: var(--text-light);
}

.m-loginscreen .subtitle {
  margin: 0 0 28px;
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 1.5;
  color: var(--text-light-muted);
  max-width: 320px;
}

.m-loginscreen .emailStrong {
  color: var(--text-light);
  font-weight: 400; /* Faculty ships 400 only */
}

.m-loginscreen .form {
  display: flex;
  flex-direction: column;
}

.m-loginscreen .fieldLabel {
  font-family: var(--font-sans);
  font-size: 12px;
  font-weight: 400; /* Faculty ships 400 only */
  letter-spacing: 0.01em;
  color: var(--text-light-muted);
  margin: 0 0 8px 2px;
}

.m-loginscreen .fieldWrap {
  position: relative;
}

.m-loginscreen .input {
  width: 100%;
  height: 54px;
  background: #fff;
  border: 1px solid var(--border-light, #e4e9e6);
  border-radius: 14px;
  padding: 0 46px 0 16px;
  font-size: 16px;
  color: var(--text-light);
  outline: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.m-loginscreen .input::placeholder {
  color: #9aa39d;
}

.m-loginscreen .input:focus {
  border-color: var(--program);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--program) 22%, transparent);
}

.m-loginscreen .fieldIcon {
  position: absolute;
  right: 16px;
  top: 50%;
  transform: translateY(-50%);
  color: #9aa39d;
}

.m-loginscreen .submit {
  margin-top: 16px;
  height: 54px;
  background: #e4e9e6;
  color: #9aa39d;
  border: 0;
  border-radius: 999px;
  font-family: var(--font-sans);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 15px;
  letter-spacing: 0.01em;
  cursor: not-allowed;
  transition: background 0.15s ease;
}

.m-loginscreen .submitOn {
  background: var(--program);
  color: var(--program-ink);
  cursor: pointer;
}

.m-loginscreen .submitOn:hover {
  background: var(--program-hover);
}

.m-loginscreen .help {
  margin: 22px 0 0;
  text-align: center;
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.6;
  color: var(--text-light-muted);
}

.m-loginscreen .link {
  color: var(--program);
  font-weight: 400; /* Faculty ships 400 only */
  text-decoration: none;
}

.m-loginscreen .link:hover {
  text-decoration: underline;
}

.m-loginscreen .resend {
  margin: 24px 0 0;
  text-align: center;
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--text-light-muted);
}

.m-loginscreen .resendLink {
  display: inline-block;
  margin-top: 4px;
  font-family: var(--font-sans);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 14px;
  color: var(--program);
  background: transparent;
  border: 0;
  cursor: pointer;
}


/* Naturally pinned by the flex layout — `.body` scrolls internally above. */


/* from components/screens/PelvicAssessmentScreen.module.css */
.m-pelvicassessmentscreen .page {
  height: 100dvh;
  background: var(--surface-light);
  display: flex;
  flex-direction: column;
  position: relative;
  overflow: hidden;
}

/* ----- Top bar ----- */
.m-pelvicassessmentscreen .topBar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 16px 6px;
  min-height: 56px;
}

.m-pelvicassessmentscreen .closeBtn,
.m-pelvicassessmentscreen .retryBtn {
  background: transparent;
  border: 0;
  padding: 4px 6px;
  color: var(--text-light);
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 14px;
  letter-spacing: 0.04em;
  cursor: pointer;
}

.m-pelvicassessmentscreen .closeBtn {
  margin-left: auto;
}

.m-pelvicassessmentscreen .retryBtn {
  margin-left: auto;
}

/* ----- Guide pill ----- */
.m-pelvicassessmentscreen .guidePill {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  background: #E0E1DE;
  border: 0;
  border-radius: 10px;
  padding: 8px 14px 8px 12px;
  cursor: pointer;
  text-align: left;
}

.m-pelvicassessmentscreen .guideKicker {
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--text-light);
  display: block;
  line-height: 1.1;
}

.m-pelvicassessmentscreen .guideTitle {
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 14px;
  color: var(--text-light);
  display: block;
  line-height: 1.15;
}

.m-pelvicassessmentscreen .guidePlay {
  color: var(--text-light);
  margin-left: 4px;
}

/* ----- Big timer ----- */
.m-pelvicassessmentscreen .timerBlock {
  text-align: center;
  padding: 8px 0 0;
}

.m-pelvicassessmentscreen .bigTime {
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 64px;
  letter-spacing: 0.02em;
  color: var(--text-light);
  line-height: 1;
}

.m-pelvicassessmentscreen .holdLabel {
  margin-top: 14px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 20px;
  color: var(--text-light-muted);
}

/* ----- Hold area ----- */
.m-pelvicassessmentscreen .holdArea {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 12px 0 40px;
}

.m-pelvicassessmentscreen .holdTarget {
  position: relative;
  width: 260px;
  height: 260px;
  border-radius: 50%;
  border: 12px solid var(--program-tint);
  background: #FFFFFF;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  outline: none;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
  transition: border-color 240ms ease, transform 240ms ease, width 320ms ease,
    height 320ms ease;
}

.m-pelvicassessmentscreen .fingerIcon {
  color: var(--text-light);
}

/* Pulsating hold ring — same concentric lime bands as the Kegel exercises. */
.m-pelvicassessmentscreen .holdTargetActive {
  width: 320px;
  height: 320px;
  border-width: 0;
  background:
    radial-gradient(
      circle at center,
      rgba(var(--program-rgb), 0.55) 0%,
      rgba(var(--program-rgb), 0.55) 18.6%,
      rgba(255, 255, 255, 0.85) 18.6%,
      rgba(255, 255, 255, 0.85) 19.2%,
      rgba(var(--program-rgb), 0.42) 19.2%,
      rgba(var(--program-rgb), 0.42) 38.6%,
      rgba(255, 255, 255, 0.75) 38.6%,
      rgba(255, 255, 255, 0.75) 39.2%,
      rgba(var(--program-rgb), 0.30) 39.2%,
      rgba(var(--program-rgb), 0.30) 58.6%,
      rgba(255, 255, 255, 0.62) 58.6%,
      rgba(255, 255, 255, 0.62) 59.2%,
      rgba(var(--program-rgb), 0.19) 59.2%,
      rgba(var(--program-rgb), 0.19) 78.6%,
      rgba(255, 255, 255, 0.5) 78.6%,
      rgba(255, 255, 255, 0.5) 79.2%,
      rgba(var(--program-rgb), 0.09) 79.2%,
      rgba(var(--program-rgb), 0.09) 100%
    );
  filter: blur(0.4px);
  box-shadow: none;
  animation: pulse 1.2s ease-in-out infinite;
}

@keyframes pulse {
  0%, 100% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.04);
  }
}

/* ----- Result stage ----- */
.m-pelvicassessmentscreen .resultBlock {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
}

.m-pelvicassessmentscreen .yourResult {
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 22px;
  color: var(--text-light);
}

/* ----- Loading stage ----- */
.m-pelvicassessmentscreen .loadingCenter {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
}

.m-pelvicassessmentscreen .loadingRingWrap {
  position: relative;
  display: inline-flex;
  width: 240px;
  height: 240px;
  align-items: center;
  justify-content: center;
}

.m-pelvicassessmentscreen .loadingRingSvg {
  display: block;
}

.m-pelvicassessmentscreen .loadingPct,
.m-pelvicassessmentscreen .loadingPctCenter {
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 44px;
  color: var(--text-light);
  letter-spacing: 0.02em;
  line-height: 1;
}

.m-pelvicassessmentscreen .loadingPctCenter {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

/* ----- Algorithm updated stage ----- */
.m-pelvicassessmentscreen .updatedCenter {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 0 32px;
  gap: 36px;
}

.m-pelvicassessmentscreen .updatedTitle {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 28px;
  color: var(--text-light);
  text-align: center;
}

.m-pelvicassessmentscreen .hidden {
  opacity: 0;
  pointer-events: none;
  transition: opacity 240ms ease;
}

.m-pelvicassessmentscreen .fadeIn {
  opacity: 1;
  transition: opacity 320ms ease 80ms;
}

/* ----- Percentile stage ----- */
.m-pelvicassessmentscreen .percentileBlock {
  flex: 1;
  padding: 4px 24px 24px;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.m-pelvicassessmentscreen .chart {
  position: relative;
  width: 100%;
  height: 240px;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 14px;
  padding: 56px 4px 0;
}

.m-pelvicassessmentscreen .chartCol {
  position: relative;
  flex: 1;
  height: 100%;
}

.m-pelvicassessmentscreen .chartColActive {
  z-index: 10;
}

.m-pelvicassessmentscreen .chartTrack {
  position: relative;
  width: 100%;
  height: 100%;
  background: #E0E1DE;
  border-radius: 10px;
  overflow: hidden;
}

.m-pelvicassessmentscreen .chartFill {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  border-radius: 10px 10px 0 0;
  transition: height 320ms ease;
}

.m-pelvicassessmentscreen .chartTag {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  background: #192126;
  color: #FFFFFF;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 13px;
  line-height: 1.2;
  text-align: center;
  border-radius: 10px;
  padding: 8px 14px;
  min-width: 84px;
  white-space: nowrap;
  z-index: 11;
  box-shadow: none;
}

.m-pelvicassessmentscreen .chartTagArrow {
  position: absolute;
  left: 50%;
  bottom: -7px;
  transform: translateX(-50%);
  width: 0;
  height: 0;
  border-left: 7px solid transparent;
  border-right: 7px solid transparent;
  border-top: 7px solid #192126;
}

.m-pelvicassessmentscreen .startingPoint {
  margin: 28px 0 14px;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 28px;
  color: var(--text-light);
  letter-spacing: 0.02em;
  text-align: center;
}

.m-pelvicassessmentscreen .percentileBody {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 16px;
  line-height: 1.55;
  color: var(--text-light);
  text-align: center;
  max-width: 320px;
}

/* ----- Footer CTA -----
   `.page` is `overflow: hidden` and `flex column`. For the footer to stay
   pinned at the viewport bottom, the result-stage content above it has to
   live inside a `flex: 1; min-height: 0; overflow-y: auto` container so it
   scrolls internally rather than pushing the footer off-screen. */
.m-pelvicassessmentscreen .footer {
  flex-shrink: 0;
  padding: 12px 16px 24px;
  background: var(--surface-light);
}

.m-pelvicassessmentscreen .darkCta {
  width: 100%;
  height: 56px;
  background: var(--cta-dark);
  color: #FFFFFF;
  border: 0;
  border-radius: 4px;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 16px;
  letter-spacing: 0.08em;
  cursor: pointer;
}

/* from components/screens/PelvicFloorGuideModal.module.css */
.m-pelvicfloorguidemodal .scrim {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: var(--surface-light);
  /* The child LessonFlowScreen already renders a full-bleed `.viewport` so we
     just need to sit on top of whatever is behind us. */
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* from components/screens/PersonalizationScreen.module.css */
.m-personalizationscreen .root {
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
  background: #FFFFFF;
}

.m-personalizationscreen .header {
  padding: 14px 0 10px;
  border-bottom: 1px solid var(--divider);
}

.m-personalizationscreen .titleRow {
  display: flex;
  justify-content: center;
  padding-bottom: 8px;
}

.m-personalizationscreen .title {
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 15px;
}

.m-personalizationscreen .barRow {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 12px;
}

.m-personalizationscreen .iconBtn {
  background: transparent;
  border: 0;
  padding: 6px;
  color: var(--text-light-muted);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.m-personalizationscreen .track {
  flex: 1;
  height: 4px;
  border-radius: 999px;
  background: var(--surface-beige);
  overflow: hidden;
}

.m-personalizationscreen .fill {
  height: 100%;
  background: var(--program);
  border-radius: 999px;
  transition: width 0.25s ease;
}

.m-personalizationscreen .body {
  flex: 1;
  padding: 18px 18px 24px;
}

.m-personalizationscreen .heading {
  margin: 6px 0 16px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 24px;
  line-height: 1.2;
  color: var(--text-light);
}

.m-personalizationscreen .optionList {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.m-personalizationscreen .option {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 14px 14px;
  border: 1px solid var(--border-card);
  border-radius: 10px;
  background: #FFFFFF;
  color: var(--text-light);
  text-align: left;
  font-family: var(--font-serif);
  font-size: 16px;
}

.m-personalizationscreen .optionSelected {
  background: var(--program-tint);
  border-color: var(--program);
}

.m-personalizationscreen .radio {
  color: var(--text-light);
}

.m-personalizationscreen .radioOn {
  color: var(--text-light);
}

.m-personalizationscreen .yesNoWrap {
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.m-personalizationscreen .yesNoBlock {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.m-personalizationscreen .yesNoQuestion {
  margin: 0 0 2px;
  font-family: var(--font-serif);
  font-size: 16px;
  color: var(--text-light);
}

.m-personalizationscreen .footer {
  position: sticky;
  bottom: 0;
  padding: 16px;
  background: linear-gradient(to top, #FFFFFF 70%, rgba(255, 255, 255, 0));
}

.m-personalizationscreen .cta {
  width: 100%;
  height: 56px;
  border: 0;
  border-radius: 4px;
  background: var(--surface-beige);
  color: var(--text-light-muted);
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 14px;
  letter-spacing: 0.18em;
}

.m-personalizationscreen .cta:not(:disabled) {
  background: var(--cta-dark);
  color: #FFFFFF;
}

/* from components/screens/PracticeIntroScreen.module.css */
.m-practiceintroscreen .page {
  display: flex;
  flex-direction: column;
  background: var(--bg-light);
  overflow: hidden;
}

/* ----- Hero image ----- */
.m-practiceintroscreen .hero {
  position: relative;
  flex: 0 0 auto;
  height: 250px;
  background-color: #E0E1DE;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

.m-practiceintroscreen .closeBtn {
  position: absolute;
  top: 18px;
  left: 16px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border: none;
  border-radius: 50%;
  background: var(--surface-light);
  color: var(--text-light);
  cursor: pointer;
  box-shadow: none;
}

/* ----- Content sheet ----- */
.m-practiceintroscreen .sheet {
  position: relative;
  z-index: 1;
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 24px 22px 20px;
  background: var(--surface-light);
}

.m-practiceintroscreen .title {
  margin: 0 0 18px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 26px;
  line-height: 1.15;
  letter-spacing: -0.01em;
  color: var(--text-light);
}

.m-practiceintroscreen .label {
  margin: 18px 0 8px;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 13px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-light-muted);
}

.m-practiceintroscreen .body {
  margin: 0 0 10px;
  font-family: var(--font-serif);
  font-size: 16px;
  line-height: 1.5;
  color: var(--text-light);
}

.m-practiceintroscreen .frequency {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin: 18px 0 0;
  font-family: var(--font-serif);
  font-size: 16px;
  line-height: 1.4;
  color: var(--text-light);
}

.m-practiceintroscreen .frequencyIcon {
  flex: 0 0 auto;
  margin-top: 2px;
  color: var(--text-light-muted);
}

/* ----- Footer CTA ----- */
.m-practiceintroscreen .footer {
  flex: 0 0 auto;
  padding: 12px 22px calc(16px + env(safe-area-inset-bottom));
  background: var(--surface-light);
  border-top: 1px solid var(--divider);
}

.m-practiceintroscreen .startBtn {
  width: 100%;
  padding: 16px;
  border: none;
  border-radius: 14px;
  background: var(--program);
  color: var(--program-ink);
  box-shadow: none;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 15px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
}

.m-practiceintroscreen .startBtn:active {
  transform: scale(0.99);
}

/* from components/screens/profile/ConfirmModal.module.css */
.m-confirmmodal .scrim {
  position: fixed;
  inset: 0;
  background: rgba(20, 20, 20, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 28px;
  z-index: 80;
}

.m-confirmmodal .card {
  position: relative;
  width: 100%;
  max-width: 320px;
  border-radius: 6px;
  padding: 26px 24px 22px;
  color: #FFFFFF;
  text-align: center;
  box-shadow: none;
}

.m-confirmmodal .red { background: var(--error, #C51013); }
.m-confirmmodal .dark { background: #192126; }

.m-confirmmodal .close {
  position: absolute;
  top: 12px;
  right: 12px;
  background: transparent;
  border: 0;
  color: #FFFFFF;
  padding: 4px;
  opacity: 0.85;
}

.m-confirmmodal .title {
  margin: 4px 0 12px;
  font-family: var(--font-serif);
  font-size: 18px;
  font-weight: 400; /* Faculty ships 400 only */
  line-height: 1.25;
}

.m-confirmmodal .body {
  margin: 0 0 20px;
  font-family: var(--font-serif);
  font-size: 17px;
  line-height: 1.3;
}

.m-confirmmodal .cancel {
  display: block;
  width: 100%;
  padding: 14px 16px;
  margin-top: 4px;
  border: 0;
  border-radius: 4px;
  background: #FFFFFF;
  color: var(--text-light);
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 14px;
  letter-spacing: 0.12em;
}

.m-confirmmodal .confirm {
  display: block;
  width: 100%;
  padding: 14px 16px;
  margin-top: 12px;
  border: 0;
  background: transparent;
  color: #FFFFFF;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 14px;
  letter-spacing: 0.12em;
}

/* ===========================================================================
   Вкладка Profile — редизайн 30.08.2026 в духе профиля Airbnb (референс:
   фрейм Figma 505:7978 = скриншоты приложения + живая страница
   airbnb.com/users/profile, снятая через браузер: строка 56px, иконка 24 у
   поля 24, подпись 16/20, шеврон 16 у правого поля, разделитель 1px в тех же
   полях, внутри группы линий нет). Наши значения: фон и радиусы взяты с Today
   (#F2F1F6 и 26), навбар — как на Explore, шеврон — наш, из карточек Today.
   =========================================================================== */
.m-profilescreen.viewport { max-width: 480px; }
.m-profilescreen.viewport-light { background: #F2F1F6; }

/* Отступы страницы — один в один с .exPage на Explore: сверху 10 + safe,
   по бокам 0 (боковые поля живут на самих блоках), снизу место под таббар. */
.prPage {
  min-height: 100dvh;
  background: #F2F1F6;
  color: var(--text-light);
  padding: calc(10px + env(safe-area-inset-top, 0px)) 0
           calc(110px + env(safe-area-inset-bottom, 0px));
}
/* Навбар — ТОТ ЖЕ .exTop, что на Explore, без собственных вертикальных
   отступов: с ними заголовок стоял ниже, чем на Explore (замечание Игоря
   30.08). Не липкий — едет со страницей. */
.m-profilescreen .exTop {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 20px;
}
.m-profilescreen .exTitle {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 400;
  font-size: 20px;
  line-height: 1.2;
  color: var(--text-light, #192126);
}

/* Карточка профиля: аватар, имя, пилюля и ачивменты одним блоком (правка
   Игоря 30.08 — раньше ачивменты жили отдельной плашкой). */
.m-profilescreen .prCard {
  background: #FFFFFF;
  border-radius: 26px;
  padding: 28px 20px 20px;
  margin: 16px 20px 12px;
}
.m-profilescreen .prHead {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
}
.m-profilescreen .avatar {
  position: relative;
  width: 96px;
  height: 96px;
  border-radius: 50%;
  background: var(--surface-tile, #F2F3F5);
  overflow: hidden;
  flex: 0 0 auto;
}
.m-profilescreen .avatarHair {
  position: absolute;
  left: 22px;
  top: 16px;
  width: 52px;
  height: 34px;
  border-radius: 26px 26px 0 0;
  background: #C3C7CE;
}
.m-profilescreen .avatarFace {
  position: absolute;
  left: 28px;
  top: 30px;
  width: 40px;
  height: 44px;
  border-radius: 20px;
  background: #DDE0E5;
}
.m-profilescreen .prName {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 400;
  font-size: 24px;
  line-height: 1.2;
  color: var(--text-light, #192126);
  text-align: center;
}
.m-profilescreen .badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 27px;
  padding: 0 12px;
  border-radius: 40px;
  background: var(--surface-tile, #F2F3F5);
  color: var(--text-light, #192126);
  font-size: 12px;
  line-height: 1;
}
.m-profilescreen .badgeStar { font-size: 12px; }

/* Ачивменты: три колонки в подвале карточки, отделены волосяной линией. */
.m-profilescreen .prStats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  margin-top: 22px;
  padding-top: 20px;
  border-top: 1px solid var(--divider, #DADDE3);
}
.m-profilescreen .prStat { text-align: center; }
.m-profilescreen .prStatTop {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}
.m-profilescreen .prStatEmoji { font-size: 15px; line-height: 1; }
.m-profilescreen .prStatValue {
  font-family: var(--font-serif);
  font-weight: 400;
  font-size: 22px;
  line-height: 1.2;
  color: var(--text-light, #192126);
}
.m-profilescreen .prStatLabel {
  margin-top: 4px;
  font-size: 12px;
  line-height: 1.35;
  color: var(--text-light-muted, #5E6468);
  white-space: pre-line;
}

/* Get Premium — прежний блок .banner из .m-premiumbanner, ничего в его
   структуре и цвете не меняется: правка Игоря 30.08 касалась ТОЛЬКО радиуса
   подложки (18 → 26, как у карточек Today). */
.m-profilescreen .bannerWrap { padding: 0 20px; }
.m-profilescreen .bannerWrap:empty { display: none; }
.m-profilescreen .banner { border-radius: 26px; }

/* Список настроек: без подложек, ровно как у Airbnb. Строка 56, иконка 24 у
   левого поля, подпись через 16, шеврон у правого поля. Разделитель делит
   список на две группы; внутри группы линий нет. */
.m-profilescreen .prList { margin: 20px; }
.m-profilescreen .prRow {
  display: flex;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 56px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--text-light, #192126);
  text-decoration: none;
  text-align: left;
  font-family: inherit;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
.m-profilescreen .prIcon {
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  color: var(--text-light, #192126);
}
.m-profilescreen .prIcon svg { display: block; width: 24px; height: 24px; }
.m-profilescreen .prRowLabel {
  flex: 1;
  min-width: 0;
  font-size: 16px;
  line-height: 20px;
}
.m-profilescreen .prChev {
  flex: 0 0 auto;
  color: var(--text-light-muted, #5E6468);
}
.m-profilescreen .prDiv {
  height: 1px;
  margin: 12px 0;
  background: var(--divider, #DADDE3);
}
.m-profilescreen .prLangSelect {
  border: 0;
  background: none;
  font: inherit;
  font-size: 15px;
  color: var(--text-light-muted, #5E6468);
  cursor: pointer;
}
/* Отклик строки — подсветка подложки, без сжатия: строки во всю ширину, и
   масштаб на них читался бы рывком. */
.m-profilescreen .prRow.is-pressed,
.m-profilescreen .prRow:active {
  background: rgba(25, 33, 38, 0.05);
  border-radius: 14px;
  box-shadow: 0 0 0 8px rgba(25, 33, 38, 0.05);
}


/* from components/screens/ProgramPickerSheet.module.css */
/* Redesigned program picker (Figma "select a program"): a full-screen panel
   that slides down from the top edge, over everything including the bottom
   nav. Cards scroll; the close button stays fixed above them. */
.m-programpickersheet .programPicker {
  position: fixed;
  inset: 0;
  /* Та же 480-колонка, что у .readerOverlay: на десктопе панель не тянется на
     весь вьюпорт. Центрирование живёт в transform, поэтому оба состояния ниже
     несут translateX(-50%) — одиночный translateY его затирал бы. */
  left: 50%;
  right: auto;
  width: 100%;
  max-width: 480px;
  z-index: 100;
  background: #FFFFFF;
  /* bottom-edge shadow reads while the panel slides over the page */
  box-shadow: 0 5px 26px rgba(14, 14, 20, 0.08);
  transform: translate(-50%, -100%);
  visibility: hidden;
  /* Лонг-тап по карточке не должен включать выделение текста (iOS выделял
     текст даже соседней карточки) — весь текст панели декоративный. */
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  /* Timing lifted from apple.com's mobile hamburger menu: its container
     expands over 437ms on cubic-bezier(0.4, 0, 0.6, 1), the same curve the
     cards inside use — see .pickItem. */
  transition: transform 437ms cubic-bezier(0.4, 0, 0.6, 1), visibility 0s linear 437ms;
}

.m-programpickersheet .programPicker.open {
  transform: translate(-50%, 0);
  visibility: visible;
  transition: transform 437ms cubic-bezier(0.4, 0, 0.6, 1);
}

/* Пикер, «перенесённый» через перезагрузку (переход на другую программу):
   новая страница рендерит его сразу открытым, статично — без анимации панели
   и без каскада карточек. Класс снимается перед стартом закрытия. */
.m-programpickersheet .programPicker.pickerInstant,
.m-programpickersheet .programPicker.pickerInstant .pickItem,
.m-programpickersheet .programPicker.pickerInstant .pickCard,
.m-programpickersheet .programPicker.pickerInstant .pickItem::before { transition: none !important; }

/* Белый растворяющий верх пикера. Рецепт и кривая — дословно .playerTopBar
   (та полоса замерена стендом /probe/, раунд 3, и красит статус-бар в проде):
   сплошных ровно 4px у кромки — заголовка тут нет, длинная плашка как в
   читалке не нужна, — дальше мягкий сход по восьми стопам. Высота 64px — до
   верха первой карточки (padding-top списка), чтобы в покое оверлей её не
   перекрывал; карточки уходят под него только при скролле.
   Два элемента с одной внешностью: .pickerTopBar живёт ВНУТРИ пикера (z 4 —
   под кнопкой закрытия, над скроллом) и приезжает вместе с ним;
   .pickerChromeTop красит статус-бар: пикер всегда смонтирован и лишь меняет
   transform, а пересэмплирование запускает только МОНТИРОВАНИЕ элемента у
   кромки — JS открытия подкладывает свежую полосу ПОД пикер (z 99 < 100) и
   снимает её по окончании закрытия, возвращая бару цвет hero ровно в момент
   ухода панели. ВАЖНО: полоса-краситель без transform и короткая — стенд
   показал, что красит только короткая fixed-полоса у кромки, а первая версия
   с центрированием через translateX(-50%) давала дефолтный серый #F6F6F6;
   центрирование — как у плеера: left/right:0 + margin:auto + max-width. */
.m-programpickersheet .pickerTopBar,
.m-programpickersheet .pickerChromeTop {
  height: calc(64px + env(safe-area-inset-top, 0px));
  pointer-events: none;
  /* Спад — smoothstep (1−(3t²−2t³)) по восьми стопам в той же высоте 64px:
     плеерные веса (.82 уже на 16%) роняли непрозрачность слишком быстро у
     верха, и скроллящиеся карточки резко обрезались на стыке со статус-баром.
     Smoothstep держит плотное белое дольше и сходит на нет без перелома. */
  background: linear-gradient(to bottom,
    #FFFFFF calc(4px + env(safe-area-inset-top, 0px)),
    rgba(255, 255, 255, 0.96) 18%,
    rgba(255, 255, 255, 0.84) 30%,
    rgba(255, 255, 255, 0.68) 41%,
    rgba(255, 255, 255, 0.50) 53%,
    rgba(255, 255, 255, 0.32) 65%,
    rgba(255, 255, 255, 0.16) 77%,
    rgba(255, 255, 255, 0.04) 88%,
    rgba(255, 255, 255, 0) 100%);
}
.m-programpickersheet .pickerTopBar {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 4;
}
.m-programpickersheet .pickerChromeTop {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  margin: 0 auto;
  max-width: 480px;
  z-index: 99;
}

@media (prefers-reduced-motion: reduce) {
  .m-programpickersheet .programPicker { transition: none; }
}

.m-programpickersheet .pickerClose {
  position: absolute;
  /* Plain px in a browser tab — the page never extends under the iOS status
     bar there, so env(safe-area-inset-top) is 0 anyway. The inset is added
     back only for an installed PWA, where the page really is edge-to-edge. */
  top: 10px;
  /* 16px inside the 480px content column (Figma), not the viewport edge */
  right: max(16px, calc(50% - 224px));
  width: 44px;
  height: 44px;
  /* the UA's default button padding (2px/6px/3px/6px in Chrome) would shrink
     the content box to 32x39 and push the glyph off-centre vertically */
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: #FFFFFF;
  color: #192126;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  z-index: 5;
  box-shadow: 0 2px 10px rgba(14, 14, 20, 0.10);
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.m-programpickersheet .pickerScroll {
  height: 100%;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

.m-programpickersheet .pickerList {
  max-width: 480px;
  margin: 0 auto;
  /* Figma: active plate at x=16, card at x=20 (the plate adds its own 4px), and
     the first card at y=122 in the 402x874 frame — minus the 59pt status bar
     the frame includes, since the browser viewport starts below it. */
  padding: 64px 16px calc(32px + env(safe-area-inset-bottom, 0px));
  display: flex;
  flex-direction: column;
  /* 4px here + 4px plate padding on each side = the 12px card gap from Figma */
  gap: 4px;
}

/* Installed PWA only: there the page IS edge-to-edge, so the safe-area inset
   has to be added on top of the designed offsets. */
@media (display-mode: standalone) {
  .m-programpickersheet .pickerClose { top: calc(10px + env(safe-area-inset-top, 0px)); }
  .m-programpickersheet .pickerList { padding-top: calc(64px + env(safe-area-inset-top, 0px)); }
}

/* Card shell: carries the 4px gap ring that becomes the white plate with a
   1.4px #192126 border on the active programme (Figma "highlight"). */
.m-programpickersheet .pickItem {
  position: relative;
  display: block;
  width: 100%;
  padding: 4px;
  background: transparent;
  border: 0;
  border-radius: 30px;
  cursor: pointer;
  text-align: inherit;
  /* Staggered reveal, retuned from apple.com's mobile menu for three 208px
     cards instead of eleven 44px rows. Apple's curve and total envelope are
     kept (~640ms end-to-end); what changes is the distribution:
       · rise 24px, not 8 — 8px on a 208px card is 4% of it and reads as no
         movement at all (Apple's 8px on a 44px row is ~18%);
       · step 90ms, not 20 — with only three items a 20ms step is 8% of the
         duration, so all three effectively start at once. ~⅓ of the duration
         gives a clear phase shift while still overlapping, which is what makes
         it read as one wave rather than three separate animations;
       · 300ms, not 240 — the longer travel needs the extra time to stay soft.
     Closing runs with no delay so they fade out together. */
  opacity: 0;
  transform: translateY(-40px);
  transition: opacity 300ms cubic-bezier(0.4, 0, 0.6, 1),
              transform 300ms cubic-bezier(0.4, 0, 0.6, 1);
  transition-delay: 0s;
  /* Серый нативный оверлей тапа Safari — долой; отклик даёт скейл .pickCard. */
  -webkit-tap-highlight-color: transparent;
}

/* Пресс — как у карточек Today (0.97, быстрый вход / плавный выход), но на
   внутреннем .pickCard: transform самого .pickItem занят каскадом появления,
   и его transition-delay (160мс + шаг) съедал бы мгновенность отклика. */
.m-programpickersheet .pickItem:active .pickCard,
.m-programpickersheet .pickItem.is-pressed .pickCard {
  transform: scale(0.97);
  transition-duration: 90ms;
}

/* У активной карточки вместе с .pickCard сжимается и кольцо (::before) — сам
   .pickItem масштабировать нельзя (см. выше). Белая плашка (фон .pickItem)
   не сжимается, но её выступ за кольцом — белое на белом фоне пикера, не
   виден. Разница хода (кольцо на 8px шире карточки) — доли пикселя. */
.m-programpickersheet .pickItem.pickActive::before { transition: transform 260ms ease-out; }
.m-programpickersheet .pickItem.pickActive:active::before,
.m-programpickersheet .pickItem.pickActive.is-pressed::before {
  transform: scale(0.97);
  transition-duration: 90ms;
}

.m-programpickersheet .programPicker.open .pickItem {
  opacity: 1;
  transform: translateY(0);
  transition-delay: calc(160ms + var(--i, 0) * 60ms);
}

@media (prefers-reduced-motion: reduce) {
  .m-programpickersheet .pickItem { transition: none; }
}

.m-programpickersheet .pickItem.pickActive { background: #FFFFFF; }

/* Active ring: a 1.4px gradient stroke drawn inside the plate's own box, so
   the card keeps its full 362px (a border would shrink it). Gradient runs
   top→bottom; the first stop is #192126 for every programme, the other two
   come from its palette (Figma "program N highlight" stroke). */
.m-programpickersheet .pickItem.pickActive::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 30px;
  padding: 1.4px;
  background: linear-gradient(180deg,
    #192126 0%,
    var(--ring-mid, #054FA9) 50.2%,
    var(--ring-end, #A6C5EC) 100%);
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  mask-composite: exclude;
  pointer-events: none;
}

.m-programpickersheet .pickItem.pickDisabled {
  opacity: 0.55;
  cursor: not-allowed;
}

/* Card: the bottom half is the supplied ribbed-band PNG (set inline per
   programme in today.ejs), the top half the photo. The band is exactly the
   card's lower half — 440×100pt, so `100% 50%` never distorts its rib pitch
   vertically; horizontally it stretches to whatever the card is, which is
   harmless because the band is constant along X. */
.m-programpickersheet .pickCard {
  display: block;
  position: relative;
  height: 200px;
  border-radius: 26px;
  overflow: hidden;
  /* Выход из пресса — медленный (260мс), вход задаёт правило .is-pressed. */
  transition: transform 260ms ease-out;
}

/* Photo fills the card's top half (the PNGs ship pre-cropped to exactly this
   362×100 framing), with the mock's slight backdrop-blur softness. */
.m-programpickersheet .pickPhotoBox {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 50%;
  overflow: hidden;
  pointer-events: none;
}
/* Лента — зеркально фото: тот же <img> в таком же боксе, только у нижней
   кромки. Раньше она была background-image карточки, и это давало вечную
   разницу с фото: у <img> приоритет загрузки выше, чем у фонов (фон грузится
   только после расчёта стиля элемента), плюс подложке-миниатюре был нужен
   JS-свап. Теперь оба слоя живут одинаково: миниатюра — фоном бокса,
   настоящий файл — <img> поверх, без свапов. */
.m-programpickersheet .pickBandBox {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 50%;
  overflow: hidden;
  pointer-events: none;
}
/* Лента НЕ масштабируется в бокс (правка Игоря 28.08): она рисуется в
   натуральную величину — арты @3x, 1320px по ширине = 440 CSS, — прилегает к
   НИЖНЕЙ кромке бокса и центрируется по горизонтали; всё, что выходит сверху и
   по бокам, срезает overflow бокса. Так у всех палитр одинаковый шаг рёбер:
   мужские ленты (1320×300) прежде сжимались по ширине до 362, а женские
   (1320×396) сжались бы ещё и по высоте. */
.m-programpickersheet .pickBand {
  position: absolute;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 440px;
  height: auto;
  max-width: none;
  display: block;
}

/* Фото — во всю ширину карточки и по центру по вертикали своего бокса
   (правка Игоря 27.08): арты пересохранены под карточку Explore (1086×444 =
   362×148 @3x), а бокс пикера — 362×100, поэтому лишнее сверху и снизу
   срезается симметрично. height:auto, а не cover: масштаб всегда считается по
   ШИРИНЕ и не зависит от того, окажется ли арт выше или ниже бокса. */
.m-programpickersheet .pickPhoto {
  position: absolute;
  top: 50%;
  left: 0;
  width: 100%;
  height: auto;
  transform: translateY(-50%);
  display: block;
}

/* No separate whitewash layer: the band PNG already dissolves toward the page
   background at its own bottom edge, which is Figma's ¾→#F2F1F6 overlay. A
   second wash on top would bleach it. */

/* Заголовок карточки прижат НИЗОМ (правка Игоря 28.08 — как «align bottom» в
   Figma): низ последней строки всегда на 116px от верха карточки (карточка
   200px ⇒ bottom: 84), поэтому зазор до блерба не меняется, а вторая строка
   при переносе не толкает контент вниз — блок растёт ВВЕРХ, на фото.
   Обрезание эллипсисом снято: длинные названия переносятся.
   left/right вместо left:50% + translateX — обязательны: у absolute-элемента
   с одной горизонтальной координатой ширина считается shrink-to-fit от неё до
   края контейнера (то есть от 181px), и перенос шёл по ПОЛОВИНЕ карточки —
   «THE MENOPAUSE RESET» ломался на три строки вместо двух. */
.m-programpickersheet .pickTitle {
  position: absolute;
  bottom: 84px;
  left: 20px;
  right: 20px;
  font-family: var(--font-serif);
  font-size: 30px;
  line-height: 1.2;
  text-transform: uppercase;
  text-align: center;
  color: #FFFFFF;
}
/* 28 — только женский пикер (правка Игоря 28.08): мужские карточки согласованы
   по фигме на 30 и остаются как были. Геометрия (прижатие низом и перенос)
   общая — у мужских названий она ничего не меняет, они в одну строку. */
.m-programpickersheet.m-female .pickTitle { font-size: 28px; }

.m-programpickersheet .pickBlurb {
  position: absolute;
  top: 150px;
  left: 50%;
  transform: translate(-50%, -50%);
  width: calc(100% - 40px);
  max-width: 322px;
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.4;
  text-align: center;
  color: #FFFFFF;
}

/* from components/screens/QuizScreen.module.css */
.m-quizscreen .page {
  min-height: 100dvh;
  background: var(--bg-dark);
  color: var(--text-dark);
  display: flex;
  flex-direction: column;
}

/* Quiz header: the bar blends into the page background (the shared
   `.m-progressbar .dark` tint is meant for the track only), and the category
   label centers on the page rather than on the space left of the back button. */
.m-quizscreen .header.dark { background: var(--bg-dark); }
.m-quizscreen .header .row { position: relative; }
.m-quizscreen .header .center {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  pointer-events: none;
}

.m-quizscreen .body {
  padding: 8px 20px 24px;
  flex: 1;
  display: flex;
  flex-direction: column;
}

.m-quizscreen .title {
  margin: 16px 0 8px;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 28px;
  line-height: 1.1;
  letter-spacing: 0.01em;
  text-align: center;
  text-transform: uppercase;
}

.m-quizscreen .subtitle {
  margin: 0 0 24px;
  text-align: center;
  color: var(--text-dark-muted);
  font-family: var(--font-serif);
  font-size: 15px;
  line-height: 1.4;
}

.m-quizscreen .options {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.m-quizscreen .option {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  background: var(--surface-dark);
  color: var(--text-dark);
  border: 0;
  border-radius: 10px;
  padding: 22px 18px;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 15px;
  letter-spacing: 0.04em;
  text-align: left;
  text-transform: uppercase;
  transition: background 0.15s ease;
}

.m-quizscreen .option:hover { background: var(--surface-dark-2); }

.m-quizscreen .chev { color: var(--text-dark-muted); }

.m-quizscreen .radio {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 1.5px solid var(--text-dark-muted);
  flex-shrink: 0;
  position: relative;
}

.m-quizscreen .radioOn::after {
  content: '';
  position: absolute;
  inset: 3px;
  border-radius: 50%;
  background: var(--program);
}

.m-quizscreen .cta {
  position: sticky;
  bottom: 0;
  padding: 16px 20px 24px;
  background: linear-gradient(180deg, rgba(14,16,17,0) 0%, var(--bg-dark) 30%);
  text-align: center;
}

.m-quizscreen .ctaBtn {
  background: transparent;
  border: 0;
  color: var(--text-dark-muted);
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 14px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 14px 0;
}

.m-quizscreen .ctaBtn.enabled { color: var(--text-dark); }

/* from components/screens/ResistanceKegelPlayer.module.css */
.m-resistancekegelplayer .page {
  height: 100dvh;
  display: flex;
  flex-direction: column;
  background: var(--surface-light);
  color: var(--text-light);
}

/* ---------- Header ---------- */

.m-resistancekegelplayer .header {
  flex: 0 0 auto;
  background: var(--surface-light);
  padding: 10px 18px 16px;
}

.m-resistancekegelplayer .headerTop {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.m-resistancekegelplayer .backBtn {
  width: 40px;
  height: 40px;
  margin-left: -8px;
  border: 0;
  background: transparent;
  color: var(--text-light);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.m-resistancekegelplayer .menuCircle {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: #E0E1DE;
  flex-shrink: 0;
}

.m-resistancekegelplayer .counter {
  margin: 4px 0 0;
  text-align: center;
  font-family: var(--font-sans);
  font-size: 15px;
  color: var(--text-light);
}

.m-resistancekegelplayer .counterChip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 22px;
  padding: 0 6px;
  margin: 0 2px;
  border-radius: 6px;
  background: var(--program);
  color: var(--program-ink);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 14px;
}

.m-resistancekegelplayer .title {
  margin: 6px 0 0;
  text-align: center;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 22px;
  line-height: 1.2;
  color: var(--text-light);
}

/* ---------- Video / visual ---------- */

.m-resistancekegelplayer .videoArea {
  position: relative;
  flex: 0 0 auto;
  height: 38dvh;
  min-height: 250px;
  background: #E0E1DE;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.m-resistancekegelplayer .diagramWrap {
  width: 100%;
  max-width: 320px;
  aspect-ratio: 2.5 / 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 24px;
}

.m-resistancekegelplayer .diagramSvg {
  width: 100%;
  height: 100%;
}

.m-resistancekegelplayer .repsOverlay {
  margin-top: 16px;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 32px;
  color: var(--text-light);
}

.m-resistancekegelplayer .restBadge {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 24px;
  text-align: center;
}

.m-resistancekegelplayer .restBadgeLabel {
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 48px;
  letter-spacing: 0.04em;
  color: var(--text-light);
  line-height: 1;
}

.m-resistancekegelplayer .placeholderLabel {
  font-family: var(--font-sans);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-light-muted);
}

/* Control row — sits UNDER the video: pause, progress bar, volume. */
.m-resistancekegelplayer .videoBar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 20px;
  background: var(--surface-light);
  border-bottom: 1px solid var(--divider);
}

.m-resistancekegelplayer .barBtn {
  border: 0;
  background: transparent;
  color: var(--text-light);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex-shrink: 0;
}

.m-resistancekegelplayer .barTime {
  font-family: var(--font-sans);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--text-light-muted);
  flex-shrink: 0;
}

.m-resistancekegelplayer .scrubTrack {
  flex: 1 1 auto;
  height: 5px;
  border-radius: 3px;
  background: var(--border-light);
  overflow: hidden;
}

.m-resistancekegelplayer .scrubFill {
  height: 100%;
  background: var(--program);
  border-radius: 2px;
  transition: width 0.2s linear;
}

/* ---------- Exercise timeline ---------- */

.m-resistancekegelplayer .timeline {
  flex: 1 1 0;
  min-height: 0;
  overflow-y: auto;
  background: var(--surface-light);
  padding: 20px 20px 8px;
}

.m-resistancekegelplayer .timelineRow {
  display: flex;
  gap: 14px;
  align-items: flex-start;
}

.m-resistancekegelplayer .timelineMarker {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  align-self: stretch;
}

.m-resistancekegelplayer .timelineNum {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-sans);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 16px;
  flex-shrink: 0;
  z-index: 1;
}

.m-resistancekegelplayer .num_upcoming {
  background: #E0E1DE;
  color: var(--text-light);
  box-shadow: none;
}

.m-resistancekegelplayer .num_done {
  background: var(--program);
  color: var(--program-ink);
  box-shadow: none;
}

.m-resistancekegelplayer .num_current {
  background: var(--program-tint);
  color: var(--text-light);
  border: 1px solid var(--program);
  box-shadow: none;
}

.m-resistancekegelplayer .timelineLine {
  flex: 1 1 auto;
  width: 2px;
  min-height: 22px;
  background: var(--border-light);
  margin: 2px 0;
}

.m-resistancekegelplayer .timelineBody {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 4px 0 22px;
  min-width: 0;
}

.m-resistancekegelplayer .timelineTitle {
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 15px;
  color: var(--text-light);
  line-height: 1.25;
  letter-spacing: -0.01em;
}

.m-resistancekegelplayer .timelineTitleCurrent {
  color: var(--text-light);
}

.m-resistancekegelplayer .timelineMeta {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-sans);
  font-size: 13px;
  color: var(--text-light-muted);
}

/* ---------- Footer ---------- */

.m-resistancekegelplayer .footer {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 20px calc(18px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--divider);
  background: var(--surface-light);
}

.m-resistancekegelplayer .timeBlock {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.m-resistancekegelplayer .timeLabel {
  font-family: var(--font-sans);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 15px;
  color: var(--text-light);
}

.m-resistancekegelplayer .timeValue {
  font-family: var(--font-sans);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  color: var(--text-light-muted);
}

.m-resistancekegelplayer .nextBtn {
  min-width: 150px;
  height: 52px;
  padding: 0 32px;
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--program);
  color: var(--program-ink);
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 15px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
  box-shadow: none;
  transition: transform 0.1s ease, box-shadow 0.15s ease;
}

.m-resistancekegelplayer .nextBtn:active {
  transform: scale(0.99);
  box-shadow: none;
}

/* from components/screens/SessionPlayerScreen.module.css */
/* ===== Shared ===== */
.m-sessionplayerscreen .page {
  position: relative;
  min-height: 100dvh;
  max-height: 100dvh;
  overflow: hidden;
  font-family: var(--font-sans);
}

.m-sessionplayerscreen .roundBtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 0;
  background: rgba(0, 0, 0, 0.35);
  color: #fff;
  cursor: pointer;
  padding: 0;
}

.m-sessionplayerscreen .roundBtnLight {
  background: rgba(0, 0, 0, 0.45);
  color: #fff;
}

.m-sessionplayerscreen .roundBtnDark {
  background: #192126;
  color: #fff;
}

/* =====================================================
   COUNTDOWN STATE
   ===================================================== */
.m-sessionplayerscreen .countdownPage {
  background: #E0E1DE;
  color: var(--text-light);
  display: flex;
  flex-direction: column;
}

.m-sessionplayerscreen .topBar {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 14px 0;
}

.m-sessionplayerscreen .guidePill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 14px 0 0 14px;
  padding: 6px 12px;
  background: #E0E1DE;
  border: 0;
  border-radius: 6px;
  font-family: var(--font-serif);
  font-size: 13px;
  color: #192126;
  width: fit-content;
  cursor: pointer;
}

.m-sessionplayerscreen .guidePill svg {
  width: 12px;
  height: 12px;
}

.m-sessionplayerscreen .countdownCenter {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding-top: 6px;
}

.m-sessionplayerscreen .bigNumber {
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 88px;
  line-height: 1;
  color: var(--program);
  letter-spacing: 0.02em;
  margin-top: 4px;
}

.m-sessionplayerscreen .getReady {
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 18px;
  margin-top: 4px;
  color: #192126;
}

.m-sessionplayerscreen .ringWrap {
  position: relative;
  width: 230px;
  height: 230px;
  margin-top: 28px;
}

.m-sessionplayerscreen .ringSvg {
  width: 100%;
  height: 100%;
  transform: rotate(-90deg);
}

.m-sessionplayerscreen .ringTrack {
  fill: none;
  stroke: transparent;
  stroke-width: 18;
}

.m-sessionplayerscreen .ringFill {
  fill: none;
  stroke: var(--program);
  stroke-width: 18;
  stroke-linecap: butt;
}

.m-sessionplayerscreen .ringInterior {
  position: absolute;
  inset: 18px;
  border-radius: 50%;
  background: var(--program-tint);
  display: flex;
  align-items: center;
  justify-content: center;
}

.m-sessionplayerscreen .ringInnerDisc {
  width: 96px;
  height: 96px;
  border-radius: 50%;
  background: #FFFFFF;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #192126;
  border: 0;
  cursor: pointer;
}

.m-sessionplayerscreen .tooltip {
  position: relative;
  margin-top: 14px;
  background: #FFFFFF;
  color: #192126;
  border-radius: 14px;
  padding: 8px 12px;
  font-family: var(--font-serif);
  font-size: 13px;
  box-shadow: none;
}

.m-sessionplayerscreen .tooltip::after {
  content: '';
  position: absolute;
  top: -6px;
  left: 50%;
  transform: translateX(-50%) rotate(45deg);
  width: 10px;
  height: 10px;
  background: #FFFFFF;
}

/* Bottom card on countdown */
.m-sessionplayerscreen .bottomCard {
  margin-top: auto;
  background: #FFFFFF;
  border-radius: 12px 12px 0 0;
  padding: 14px 16px 18px;
  box-shadow: none;
}

.m-sessionplayerscreen .bottomCardTopRow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
  color: #192126;
}

.m-sessionplayerscreen .iconBtn {
  background: transparent;
  border: 0;
  padding: 6px;
  color: #192126;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.m-sessionplayerscreen .audioRow {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-display);
  font-size: 12px;
  color: var(--text-light-muted);
}

.m-sessionplayerscreen .audioBar {
  position: relative;
  flex: 1;
  height: 3px;
  background: #E0E1DE;
  border-radius: 2px;
  overflow: hidden;
}

.m-sessionplayerscreen .audioBarFill {
  position: absolute;
  inset: 0;
  width: 66%;
  background: var(--program);
}

.m-sessionplayerscreen .tabsRow {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin-top: 14px;
}

.m-sessionplayerscreen .tab {
  background: transparent;
  border: 0;
  padding: 8px 18px;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 13px;
  letter-spacing: 0.1em;
  color: #192126;
  border-radius: 999px;
  cursor: pointer;
}

.m-sessionplayerscreen .tabActive {
  background: #E0E1DE;
}

.m-sessionplayerscreen .dots {
  display: flex;
  justify-content: center;
  gap: 5px;
  margin-top: 8px;
}

.m-sessionplayerscreen .dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: #E0E1DE;
}

.m-sessionplayerscreen .dotActive {
  background: #192126;
}

.m-sessionplayerscreen .controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 28px;
  margin-top: 14px;
}

.m-sessionplayerscreen .skipBtn {
  position: relative;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: transparent;
  border: 0;
  color: #192126;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.m-sessionplayerscreen .skipBtn span {
  position: absolute;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 11px;
  color: #192126;
}

.m-sessionplayerscreen .bigPauseBtn {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: #FFFFFF;
  border: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #192126;
  box-shadow: none;
  cursor: pointer;
}

/* =====================================================
   VIDEO STATE
   ===================================================== */
.m-sessionplayerscreen .videoPage {
  background: #192126;
  color: #fff;
  position: relative;
}

.m-sessionplayerscreen .videoBg {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, #6B5648 0%, #4A3A30 55%, #3D3128 100%);
}

.m-sessionplayerscreen .videoTop {
  position: absolute;
  top: 12px;
  left: 0;
  right: 0;
  display: flex;
  justify-content: space-between;
  padding: 0 14px;
  z-index: 2;
}

.m-sessionplayerscreen .videoBottom {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  padding: 0 18px 22px;
  z-index: 2;
  background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.55) 60%, rgba(0, 0, 0, 0.75) 100%);
  padding-top: 80px;
}

.m-sessionplayerscreen .videoTitle {
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 24px;
  color: #FFFFFF;
  margin: 0;
}

.m-sessionplayerscreen .videoSubtitle {
  font-family: var(--font-sans);
  font-size: 14px;
  color: rgba(255, 255, 255, 0.65);
  margin: 2px 0 14px;
}

.m-sessionplayerscreen .seekBar {
  position: relative;
  width: 100%;
  height: 2px;
  background: rgba(255, 255, 255, 0.25);
  border-radius: 2px;
}

.m-sessionplayerscreen .seekBarFill {
  position: absolute;
  inset: 0;
  width: 92%;
  background: var(--program);
}

.m-sessionplayerscreen .seekTimes {
  display: flex;
  justify-content: space-between;
  font-family: var(--font-display);
  font-size: 12px;
  color: rgba(255, 255, 255, 0.7);
  margin-top: 8px;
}

.m-sessionplayerscreen .videoControls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 28px;
  margin-top: 18px;
}

.m-sessionplayerscreen .videoSkipBtn {
  position: relative;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.35);
  border: 0;
  color: #FFFFFF;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.m-sessionplayerscreen .videoSkipBtn span {
  position: absolute;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 11px;
  color: #FFFFFF;
}

/* =====================================================
   LOADING STATE
   ===================================================== */
.m-sessionplayerscreen .loadingPage {
  background: #FFFFFF;
  color: var(--text-light);
  display: flex;
  flex-direction: column;
}

.m-sessionplayerscreen .loadingTop {
  position: relative;
  flex: 1;
  display: flex;
  flex-direction: column;
}

.m-sessionplayerscreen .loadingTopBar {
  display: flex;
  justify-content: space-between;
  padding: 12px 14px 0;
}

.m-sessionplayerscreen .closeBtn {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: #E0E1DE;
  border: 0;
  color: #FFFFFF;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.m-sessionplayerscreen .loadingCenter {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
}

.m-sessionplayerscreen .kettlebellWrap {
  color: #192126;
}

.m-sessionplayerscreen .loadingText {
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 64px;
  letter-spacing: 0.02em;
  color: #E0E1DE;
  line-height: 1;
}

.m-sessionplayerscreen .loadingSpeaker {
  position: absolute;
  right: 18px;
  bottom: 14px;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: #192126;
  color: #FFFFFF;
  border: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.m-sessionplayerscreen .loadingPanel {
  background: #192126;
  color: #FFFFFF;
  padding: 22px 18px 22px;
  border-radius: 14px 14px 0 0;
  position: relative;
}

.m-sessionplayerscreen .loadingPanelStripe {
  position: absolute;
  top: -2px;
  left: 0;
  width: 18%;
  height: 2px;
  background: var(--program);
}

.m-sessionplayerscreen .loadingTitle {
  text-align: center;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 18px;
  margin: 0;
  color: #FFFFFF;
}

.m-sessionplayerscreen .loadingDuration {
  text-align: center;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 44px;
  color: var(--program);
  margin: 10px 0 18px;
  letter-spacing: 0.02em;
  line-height: 1;
}

.m-sessionplayerscreen .loadingControls {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.m-sessionplayerscreen .chevBtn {
  background: transparent;
  border: 0;
  color: #FFFFFF;
  padding: 8px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.m-sessionplayerscreen .squarePauseBtn {
  width: 52px;
  height: 52px;
  border-radius: 14px;
  background: transparent;
  border: 1.5px solid #FFFFFF;
  color: #FFFFFF;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.m-sessionplayerscreen .doneBtn {
  flex: 1;
  height: 52px;
  border-radius: 14px;
  background: #FFFFFF;
  color: #192126;
  border: 0;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 15px;
  letter-spacing: 0.18em;
  cursor: pointer;
}

/* from components/screens/SplashScreen.module.css */
.m-splashscreen .splash {
  min-height: 100dvh;
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  /* Soft pastel wash in the app's own accent + violet, over a light base. */
  background:
    radial-gradient(90% 55% at 12% 10%, color-mix(in srgb, #3877C4 34%, transparent) 0%, transparent 55%),
    radial-gradient(85% 60% at 95% 42%, rgba(164, 138, 237, 0.30) 0%, transparent 60%),
    linear-gradient(158deg, color-mix(in srgb, #3877C4 12%, #fff) 0%, #fff 50%, rgba(164, 138, 237, 0.12) 100%);
}

/* Oversized translucent wordmark behind the hero (echoes the homepage). */
.m-splashscreen .watermark {
  position: absolute;
  top: 46px;
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: clamp(38px, 14.5vw, 66px);
  letter-spacing: -0.01em;
  line-height: 1;
  color: rgba(255, 255, 255, 0.66);
  white-space: nowrap;
  pointer-events: none;
  z-index: 0;
}

.m-splashscreen .copy {
  position: relative;
  z-index: 2;
  padding: 150px 28px 0;
}

.m-splashscreen .title {
  margin: 0;
  display: flex;
  flex-direction: column;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 40px;
  line-height: 1.04;
  letter-spacing: -0.02em;
}

.m-splashscreen .titleTop {
  color: var(--text-light);
}

.m-splashscreen .titleAccent {
  background: linear-gradient(90deg, #3877C4 0%, var(--color-purple) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}

.m-splashscreen .subtitle {
  margin: 16px 0 0;
  max-width: 300px;
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.45;
  color: var(--text-light-muted);
}

/* Couple photography, bleeding off the bottom and fading up into the wash. */
.m-splashscreen .hero {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 54%;
  background-repeat: no-repeat;
  background-position: center bottom;
  background-size: cover;
  z-index: 1;
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 24%);
  mask-image: linear-gradient(180deg, transparent 0%, #000 24%);
}

/* from components/screens/SupportCategoryScreen.module.css */
.m-supportcategoryscreen .root {
  min-height: 100dvh;
  background: #FFFFFF;
  display: flex;
  flex-direction: column;
  padding-bottom: 24px;
}

.m-supportcategoryscreen .topBar {
  padding: 14px 16px 6px;
}

.m-supportcategoryscreen .backBtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: #FFFFFF;
  color: var(--text-light);
  border: 1px solid var(--border-card);
  box-shadow: none;
}

.m-supportcategoryscreen .bodyPad {
  padding: 8px 18px 14px;
  flex: 1;
}

.m-supportcategoryscreen .categoryLabel {
  margin: 12px 0 4px;
  color: var(--text-light-muted);
  font-family: var(--font-serif);
  font-size: 15px;
}

.m-supportcategoryscreen .categoryName {
  margin: 0 0 14px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 22px;
  color: var(--text-light);
}

.m-supportcategoryscreen .hairline {
  height: 1px;
  background: var(--divider);
  margin: 10px 0 14px;
}

.m-supportcategoryscreen .fieldLabel {
  display: block;
  color: var(--text-light-muted);
  font-family: var(--font-serif);
  font-size: 14px;
  margin-bottom: 4px;
}

.m-supportcategoryscreen .emailInput {
  width: 100%;
  border: 0;
  border-bottom: 1.5px solid #BBF246;
  background: var(--surface-beige);
  padding: 12px 12px;
  font-family: var(--font-sans);
  font-size: 16px;
  color: var(--text-light);
  outline: none;
}

.m-supportcategoryscreen .textarea {
  width: 100%;
  min-height: 130px;
  border: 0;
  background: var(--surface-beige);
  padding: 14px;
  border-radius: 4px;
  font-family: var(--font-sans);
  font-size: 16px;
  color: var(--text-light);
  outline: none;
  resize: vertical;
}

.m-supportcategoryscreen .attachRow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 16px 4px;
  border-top: 1px solid var(--divider);
  border-bottom: 1px solid var(--divider);
  margin-top: 18px;
  cursor: pointer;
  color: var(--text-light);
}

.m-supportcategoryscreen .attachLabel {
  font-family: var(--font-serif);
  font-size: 16px;
}

.m-supportcategoryscreen .fileHidden {
  position: absolute;
  width: 0;
  height: 0;
  opacity: 0;
  pointer-events: none;
}

.m-supportcategoryscreen .attachName {
  margin: 4px 0 0;
  font-family: var(--font-sans);
  font-size: 13px;
  color: var(--text-light-muted);
}

.m-supportcategoryscreen .notice {
  margin: 14px 0 18px;
  font-family: var(--font-serif);
  font-size: 14px;
  color: var(--text-light);
  line-height: 1.4;
}

.m-supportcategoryscreen .noticeBold {
  font-weight: 400; /* Faculty ships 400 only */
}

.m-supportcategoryscreen .darkCta {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 56px;
  border: 0;
  border-radius: 4px;
  background: var(--cta-dark);
  color: #FFFFFF;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 14px;
  letter-spacing: 0.18em;
}

.m-supportcategoryscreen .darkCta:disabled {
  background: #E0E1DE;
  color: var(--text-light-muted);
  cursor: not-allowed;
}

.m-supportcategoryscreen .heading {
  margin: 14px 0 12px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 22px;
  color: var(--text-light);
}

.m-supportcategoryscreen .subtle {
  margin: 0 0 18px;
  color: var(--text-light-muted);
  font-family: var(--font-serif);
  font-size: 15px;
  line-height: 1.4;
}

.m-supportcategoryscreen .cantHeading {
  margin: 14px 0 18px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 20px;
  line-height: 1.35;
  color: var(--text-light);
}

.m-supportcategoryscreen .cantStepsTitle {
  margin: 0 0 10px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 16px;
  color: var(--text-light);
}

.m-supportcategoryscreen .cantSteps {
  padding-left: 22px;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
  font-family: var(--font-serif);
  font-size: 15px;
  line-height: 1.4;
  color: var(--text-light);
}

.m-supportcategoryscreen .cantCtaWrap {
  padding: 0 18px 18px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
}

.m-supportcategoryscreen .anywayLink {
  background: transparent;
  border: 0;
  color: var(--text-light-muted);
  text-decoration: underline;
  font-family: var(--font-serif);
  font-size: 14px;
  padding: 4px;
}

/* from components/screens/SupportLandingScreen.module.css */
.m-supportlandingscreen .root {
  min-height: 100dvh;
  background: var(--bg-light);
  padding-bottom: 40px;
}

.m-supportlandingscreen .topBar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 16px 6px;
}

.m-supportlandingscreen .backChip,
.m-supportlandingscreen .faqChip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border-radius: 999px;
  background: #FFFFFF;
  color: var(--text-light);
  font-family: var(--font-sans);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 15px;
  border: 1px solid var(--border-card);
  box-shadow: none;
}

.m-supportlandingscreen .hero {
  margin: 14px 16px 18px;
  background: var(--surface-beige);
  border-radius: 14px;
  padding: 26px 22px 22px;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
}

.m-supportlandingscreen .headline {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 26px;
  letter-spacing: 0.04em;
}

.m-supportlandingscreen .lead {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 16px;
  color: var(--text-light);
}

.m-supportlandingscreen .avatars {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 44px;
}

.m-supportlandingscreen .face {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 3px solid var(--surface-beige);
  background: #E0E1DE;
  box-shadow: none;
}

.m-supportlandingscreen .faceLeft { background: #E0E1DE; }
.m-supportlandingscreen .faceCenter {
  background: #E0E1DE;
  margin-left: -10px;
  z-index: 1;
}
.m-supportlandingscreen .faceRight {
  background: #E0E1DE;
  margin-left: -10px;
}

.m-supportlandingscreen .list {
  background: #FFFFFF;
  margin: 0 16px;
  border-radius: 14px;
  padding: 18px 0 4px;
  border: 1px solid var(--border-card);
  box-shadow: none;
}

.m-supportlandingscreen .sectionTitle {
  margin: 0 0 4px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 18px;
  text-align: center;
}

.m-supportlandingscreen .sectionSub {
  margin: 0 0 14px;
  font-family: var(--font-serif);
  font-size: 14px;
  color: var(--text-light-muted);
  text-align: center;
}

.m-supportlandingscreen .rows {
  list-style: none;
  padding: 0;
  margin: 0;
}

.m-supportlandingscreen .row {
  border-top: 1px solid var(--divider);
}

.m-supportlandingscreen .rowLink {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 16px 18px;
  color: var(--text-light);
}

.m-supportlandingscreen .rowLabel {
  font-family: var(--font-serif);
  font-size: 16px;
}

.m-supportlandingscreen .rowChevron { color: var(--text-light-muted); }

/* from components/screens/TermsPrivacyScreen.module.css */
.m-termsprivacyscreen .root {
  min-height: 100dvh;
  background: var(--bg-light);
  padding-bottom: 40px;
}

.m-termsprivacyscreen .topBar {
  padding: 14px 16px 6px;
}

.m-termsprivacyscreen .backChip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 6px 14px 6px 10px;
  border-radius: 999px;
  background: #FFFFFF;
  color: var(--text-light);
  font-family: var(--font-sans);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 15px;
  border: 1px solid var(--border-card);
  box-shadow: none;
}

.m-termsprivacyscreen .title {
  margin: 14px 18px 12px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 24px;
}

.m-termsprivacyscreen .body {
  background: #FFFFFF;
  margin: 4px 16px;
  border-radius: 14px;
  border: 1px solid var(--border-card);
  box-shadow: none;
  padding: 6px 18px;
}

.m-termsprivacyscreen .section {
  padding: 16px 0;
  border-top: 1px solid var(--divider);
}

.m-termsprivacyscreen .section:first-child { border-top: 0; }

.m-termsprivacyscreen .heading {
  margin: 0 0 8px;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 17px;
  color: var(--text-light);
}

.m-termsprivacyscreen .copy {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 14px;
  line-height: 1.5;
  color: var(--text-light);
}

/* Highlighted in-copy link out to the homepage's canonical legal page.
   Text stays black; the lime underline + weight is the "highlight". */
.m-termsprivacyscreen .legalLink {
  color: var(--text-light);
  font-weight: 400; /* Faculty ships 400 only */
  text-decoration: underline;
  text-decoration-color: var(--program);
  text-decoration-thickness: 2px;
  text-underline-offset: 2px;
}

.m-termsprivacyscreen .legalLink:hover {
  text-decoration-color: var(--program-hover);
}

/* from components/screens/TodayScreen.module.css */
/* Redesigned Today (Figma today-program-*): full-bleed shader hero flowing
   from the very top of the page, content cards on a #F2F1F6 canvas. */
/* The redesign is drawn full-bleed at 402pt — let it stretch to 480px
   instead of the default 375px app column. (Redesigned screens move to 480
   one by one; legacy screens keep 375 until they are reworked.) */
.m-todayscreen.viewport { max-width: 480px; }

/* Body must match the page canvas — .tab-bottom-pad pads the body
   below main.page, and that strip showed the default white as a "hole" above
   the bottom nav when scrolled to the end. */
.m-todayscreen.viewport-light { background: #F2F1F6; }

.m-todayscreen .page {
  min-height: 100dvh;
  background: #F2F1F6;
  color: var(--text-light);
  /* bottom clearance for the fixed nav comes from body's .tab-bottom-pad —
     padding here too would double the empty space above the nav */
  padding: 0;
}

/* Hero — ribbed-glass shader panel. The CSS gradient (inline, per program) is
   the static fallback; the WebGL canvas fades in over it once it has drawn. */
/* Wrapper is exactly as tall as the hero, which leaves the sticky hero no
   room to travel — visually identical to a static block, but `sticky` makes
   iOS Safari sample the hero's colour for the status bar (see today.ejs). */
.m-todayscreen .heroSticky {
  /* Lesson cards start at y=432 in the frame — they overlap the fade zone. */
  margin-bottom: -28px;
}

.m-todayscreen .hero {
  position: sticky;
  top: 0;
  display: block;
  /* The 460pt Figma frame includes the 59pt iOS status bar; in-browser the
     viewport starts below it. Standalone/PWA gets it back via the inset.
     min-height, а не height (правка Игоря 28.08): длинное название программы
     переносится на вторую строку, и hero обязан вырасти на её высоту — вместе
     с ним вниз уезжают дуга прогресса, пилюля дня и весь контент под hero. */
  min-height: calc(401px + env(safe-area-inset-top, 0px));
  color: #FFFFFF;
}

.m-todayscreen .heroShader {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  transition: opacity 0.6s ease;
}

.m-todayscreen .heroShader.is-ready { opacity: 1; }

/* Top fade into the hero's own colour — the counterpart of the shader's fade
   into the page background at the bottom. Keeps the very top edge exactly equal
   to the colour iOS Safari froze into the status bar, whatever phase the shader
   animation is in. Eased stops (not a plain two-stop ramp) so the end of the
   fade has no visible edge of its own. */
.m-todayscreen .heroTopFade {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: calc(80px + env(safe-area-inset-top, 0px));
  pointer-events: none;
  background: linear-gradient(180deg,
    var(--tint) 0%,
    rgba(var(--tint-rgb), 0.92) 18%,
    rgba(var(--tint-rgb), 0.68) 40%,
    rgba(var(--tint-rgb), 0.36) 64%,
    rgba(var(--tint-rgb), 0.12) 84%,
    rgba(var(--tint-rgb), 0) 100%);
}

.m-todayscreen .heroContent {
  position: relative;
  z-index: 1;
  /* min-height вместо height: у hero теперь min-height, и height:100% ребёнка
     от auto-высоты не считался бы — колонка просто держит ту же базу. */
  min-height: calc(401px + env(safe-area-inset-top, 0px));
  display: flex;
  flex-direction: column;
  align-items: center;
  padding-top: calc(13px + env(safe-area-inset-top, 0px));
}

/* Program name — tapping opens the program picker sheet. */
.m-todayscreen .heroTitle {
  background: transparent;
  border: 0;
  padding: 0;
  /* Серую нативную подсветку тапа Safari — долой (как у карточек). */
  -webkit-tap-highlight-color: transparent;
  /* Блочная кнопка с ОБЫЧНЫМ текстовым потоком внутри: только так шеврон идёт
     за последним словом и переносится вместе с ним. inline-flex этого не умеет
     — его содержимое не разбивается на строки. */
  display: block;
  max-width: calc(100% - 32px);
  font-family: var(--font-serif);
  font-weight: 400;
  font-size: 30px;
  line-height: 1.2;
  text-transform: uppercase;
  text-align: center;
  color: #FFFFFF;
}

/* Обрезание эллипсисом снято (правка Игоря 28.08) — длинное название
   переносится на вторую строку. */
.m-todayscreen .heroTitleText {
  display: inline;
}
/* Последнее слово + шеврон — неразрывная связка: иначе иконка уезжает на
   вторую строку одна (её inline-flex бокс — атомарный инлайн, перед которым
   браузер ставит точку переноса даже без пробела). */
.m-todayscreen .heroTitleTail {
  white-space: nowrap;
}

/* 12x18 box holding the 18x12 chevron-up-down glyph rotated 90°. */
.m-todayscreen .heroChevBox {
  width: 12px;
  height: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  /* Отступ от последнего слова — прежний gap инлайн-флекса. Вертикаль: бокс
     ростом в строку и прижат к её верху, а глиф внутри центрируется своим
     flex'ом — так иконка встаёт ровно по центру строки, как при прежнем
     inline-flex + align-items:center, и не зависит от метрик шрифта (у
     vertical-align:middle точка отсчёта — половина x-height, из-за чего иконка
     уехала; замечание Игоря 28.08). */
  margin-left: 6px;
  height: 1.2em;
  vertical-align: top;
}

.m-todayscreen .heroChev {
  color: #FFFFFF;
  flex-shrink: 0;
}

/* Нажатие на название программы: шевроны расходятся. Иконка — один svg,
   повёрнутый на 90°, поэтому «вверх/вниз» на экране — это ±X внутри его
   системы координат: первый путь после поворота оказывается верхним, второй
   нижним. Возврат — пружиной стрелок пилюли.

   Ход 1.8px (зазор 2.4px в покое → ~6px под пальцем): 1.2 показались Игорю
   мелкими, 2.4 — размашистыми; 1.8 — его «на 50% больше» от 1.2. */
.m-todayscreen .heroChev path {
  transition: transform 220ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
.m-todayscreen .heroTitle:active .heroChev path:first-of-type,
.m-todayscreen .heroTitle.is-pressed .heroChev path:first-of-type {
  transform: translateX(-1.8px);
  transition-duration: 90ms;
}
.m-todayscreen .heroTitle:active .heroChev path:last-of-type,
.m-todayscreen .heroTitle.is-pressed .heroChev path:last-of-type {
  transform: translateX(1.8px);
  transition-duration: 90ms;
}

/* Каскад появления страницы программы: элементы ниже числа с процентом
   выезжают СНИЗУ вверх с фейдом и равным шагом. Играет при выборе программы в
   пикере и при его закрытии (класс ставит скрипт в today.ejs).

   Числа — из той же анимации меню apple.com, с которой снят сам пикер: 300мс,
   cubic-bezier(0.4, 0, 0.6, 1), шаг 60мс, ход 24px (см. комментарии у
   .programPicker и .pickItem — там же оговорено, почему ход не 8px). Hero,
   название программы, дуга и число процента не участвуют. */
.m-todayscreen.programEnter .progEnter {
  /* Долгое видимое торможение: элемент медленно доезжает до места, а не
     «прилетает и встаёт». easeOutQuint здесь НЕ работает — он проходит почти
     весь путь в первые 40% времени, и остановка читается резкой, хотя хвост
     математически пологий. easeOutCubic на 450мс держит движение заметным до
     самого конца (замечание Игоря 23.08, вторая итерация). */
  animation: progEnterUp 450ms cubic-bezier(0.215, 0.61, 0.355, 1) backwards;
  animation-delay: calc(var(--pi, 0) * 60ms);
}
/* Пока уезжающая панель пикера ещё закрывает контент, участники волны удержаны
   невидимыми: волна стартует, когда нижняя кромка панели откроет верхний из
   них (rAF-слежение в closeWithWave, today.ejs) — не раньше и не под панелью. */
.m-todayscreen.progHold .progEnter { opacity: 0; }
@keyframes progEnterUp {
  from { opacity: 0; transform: translateY(24px); }
  to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .m-todayscreen.programEnter .progEnter { animation: none; }
  .m-todayscreen .heroChev path { transition: none; }
}

/* Dashed-arc progress gauge. Geometry mirrors the exported Figma asset:
   354x104 box, tick artwork 333.5x93 inset (10.25, 11). The filled layer is
   revealed with a conic-gradient mask (see the inline script). */
.m-todayscreen .heroGauge {
  position: relative;
  width: 354px;
  height: 104px;
  margin-top: 20px;
  flex-shrink: 0;
}

.m-todayscreen .gaugeBase,
.m-todayscreen .gaugeFill img {
  position: absolute;
  left: 10.25px;
  top: 11px;
  width: 333.5px;
  height: 93px;
  display: block;
}

.m-todayscreen .gaugeBase { opacity: 0.3; }

.m-todayscreen .gaugeFill {
  position: absolute;
  inset: 0;
  /* hidden until the reveal script sets the sector clip-path (a conic-gradient
     mask would be simpler, but Safari renders it unreliably) */
  clip-path: polygon(0 0, 0 0, 0 0);
  -webkit-clip-path: polygon(0 0, 0 0, 0 0);
}

.m-todayscreen .gaugeLabel {
  position: absolute;
  font-family: var(--font-sans);
  font-size: 12px;
  line-height: 1;
  color: #FFFFFF;
  opacity: 0.7;
}

.m-todayscreen .gaugeLabelMin {
  left: 2px;
  top: 64px;
  transform: rotate(-45deg);
}

.m-todayscreen .gaugeLabelMax {
  right: 0;
  top: 62px;
  transform: rotate(45deg);
}

.m-todayscreen .gaugeDot {
  position: absolute;
  width: 4px;
  height: 4px;
  background: #FFFFFF;
  opacity: 0.7;
}

.m-todayscreen .heroPct {
  position: absolute;
  left: 0;
  right: 0;
  top: 68px;
  text-align: center;
  font-family: var(--font-serif);
  line-height: 1;
  color: #FFFFFF;
}

.m-todayscreen .pctNum { font-size: 60px; }
.m-todayscreen .pctSign { font-size: 35px; }

/* Slot for eyebrow + module name + stage pill. Sized to the full stack (as in
   the Figma frame); when the MODULE N eyebrow or the whole module header is
   absent, the remaining rows centre vertically instead of hugging the gauge. */
.m-todayscreen .heroMeta {
  margin-top: 52px;
  min-height: 116px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
}

.m-todayscreen .heroModule {
  font-family: var(--font-sans);
  font-size: 12px;
  line-height: 1.2;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  color: #FFFFFF;
}

.m-todayscreen .heroModuleName {
  padding: 0 20px;
  max-width: 380px;
  font-family: var(--font-serif);
  font-size: 20px;
  line-height: 1.2;
  text-align: center;
  color: #FFFFFF;
}

/* Frosted "Stage N of M" pill with prev/next day chevrons. */
.m-todayscreen .dayPill {
  position: relative;
  margin-top: 5px;
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 15px 17px;
  border-radius: 40px;
  background: rgba(0, 0, 0, 0.10);
}

/* Angled gradient border (per Figma): a 1px ring painted by a pseudo-element —
   gradient fill masked to the border area (content-box XOR full box), since
   border-image can't follow a border-radius. */
.m-todayscreen .dayPill::before,
.introHeroPill::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 40px;
  padding: 1px;
  background: linear-gradient(135deg,
    rgba(255, 255, 255, 0.80) 0%,
    rgba(255, 255, 255, 0.25) 55%,
    rgba(255, 255, 255, 0.60) 100%);
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  mask-composite: exclude;
  pointer-events: none;
}

.m-todayscreen .dayNav {
  background: transparent;
  border: 0;
  padding: 0;
  /* Tap target, not artwork: 52×52 is the 20px icon plus 16px of slack on every
     side, which is exactly the pill's own height (15px padding + the 22.4px
     label line box + 15px), so it spans the pill top to bottom and stops 1px
     short of its left/right edge. The negative margins keep the visual layout
     byte-identical — flex `gap` measures margin boxes, and 52 − 16 − 16 is the
     20px the icon occupied before. */
  width: 52px;
  height: 52px;
  margin: -16px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #FFFFFF;
  /* iOS paints a dark rounded plate over a tapped link. On a 52px target that
     reads as the pill being pressed, so it goes — the :active dim below stands
     in as the feedback. */
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: opacity 200ms ease-out;
}

/* Only the live arrows: the disabled and locked ones are spans, so this cannot
   brighten them past their own dimmed opacity. Fast in, slow out, for the same
   reason as the cards — a tap holds the finger down for a few dozen ms. */
/* Отклик стрелок — как у иконок таббара: вжим под пальцем и пружина. Гашение
   прозрачностью снято, два эффекта разом читались мутно. Трансформ идёт по
   САМОЙ ссылке, а не по svg: у одной из стрелок иконка отражена через
   transform, и scale() на ней перебивал отражение — в полёте стрелка
   разворачивалась. Слой держим постоянно: бокс стоит на дробном пикселе, и
   слой, создаваемый под анимацию, привязывал бы растр к целым пикселям
   устройства (тот же сдвиг на ~1px, что был у таббара). */
.m-todayscreen .dayNav {
  will-change: transform;
  backface-visibility: hidden;
}
.m-todayscreen a.dayNav {
  transition: transform 220ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
.m-todayscreen a.dayNav:active,
.m-todayscreen a.dayNav.is-pressed {
  transform: scale(0.85);
  transition: transform 60ms cubic-bezier(0.3, 0, 0.2, 1);
}
/* Всплытие на пришедшем стейдже: переход между стейджами — полная загрузка
   документа, анимацию нажатия навигация срезает. Класс ставит скрипт в
   today.ejs, и только если стейдж сменился именно стрелкой. */
/* Пружина у стрелок с более высоким пиком (1.15 против общих 1.06): та же
   форма, перелёт масштабирован. Правило не на a.dayNav, а на .dayNav — на
   крайних стейджах слот занимает неактивный <span>, и он тоже должен отыграть
   движение, если палец был на нём. */
.m-todayscreen .dayNav.pop { animation: springPopArrow 260ms linear; }
@keyframes springPopArrow {
  0% { transform: scale(0.80); }
  8% { transform: scale(0.88); }
  20% { transform: scale(1.015); }
  30% { transform: scale(1.098); }
  38% { transform: scale(1.15); }
  55% { transform: scale(1.098); }
  70% { transform: scale(1.023); }
  85% { transform: scale(0.993); }
  100% { transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .m-todayscreen a.dayNav,
  .m-todayscreen .dayNav.pop { transition: none; animation: none; }
}

/* No previous/next day to go to: keep the chevron for balance, dimmed. */
.m-todayscreen .dayNavDisabled { opacity: 0.4; }

.m-todayscreen .dayNavLock { opacity: 0.7; }

.m-todayscreen .dayLabel {
  font-family: var(--font-serif);
  font-size: 16px;
  line-height: 1.4;
  color: #FFFFFF;
}

.m-todayscreen .section {
  position: relative;
  z-index: 1;
  margin-top: 24px;
  padding: 0 20px;
}

/* First card section sits directly under the hero (adjacency can't be used —
   inline <script>s sit between them in the markup). */
.m-todayscreen .page > section.section:first-of-type { margin-top: 0; }

.m-todayscreen .sectionLabel {
  margin: 0 0 12px;
  font-family: var(--font-sans);
  font-size: 12px;
  letter-spacing: 1.1px;
  color: var(--text-light-muted);
  text-transform: uppercase;
  font-weight: 400;
}

/* Narrow phones (<390px): the 354px gauge won't fit — scale it around its
   top centre and absorb the leftover height. */
@media (max-width: 389px) {
  .m-todayscreen .heroGauge {
    transform: scale(0.88);
    transform-origin: top center;
    margin-bottom: -12px;
  }
}

.m-todayscreen .cardList {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* Stage-hop wave: on a stage/day hop inside one programme, the labels and cards
   roll in from the side we came from — the inline script in today.ejs adds
   .stageEnter and sets --stage-dx's sign. Keyframes rather than a transition
   because there is no trigger to react to: the page simply arrives, and
   `both` fill keeps every element in its offset first frame through its delay,
   so nothing flashes at its settled position first.
   Numbers derive from apple.com's mobile menu (8px rise, 20ms step, 240ms,
   this same curve): what makes that read as one soft wave is a step that is a
   small fraction of the duration — 8% there. 36ms of 300ms is 12%, so eight
   elements are in flight at once; the picker's 30% suits its three tall cards
   but here would break the wave into separate arrivals.
   20px is deliberate, not eyeballed: .section pads 20px, so at the extreme of
   the travel a card's edge lands exactly on the column edge and never crosses
   it — no horizontal overflow to clip, and the hero's sticky (which the iOS
   status-bar colour depends on) stays untouched. */
@keyframes stageCardEnter {
  from { opacity: 0; transform: translateX(var(--stage-dx, 0px)); }
  to   { opacity: 1; transform: none; }
}

/* `backwards`, not `both`: the offset first frame has to hold through the delay,
   but a forwards fill would keep asserting `transform: none` after the wave is
   over — and a filling animation outranks normal declarations, so the cards'
   :active press would silently stop working for the rest of the page's life. */
.m-todayscreen.stageEnter .sectionLabel,
.m-todayscreen.stageEnter .lessonCard,
.m-todayscreen.stageEnter .practiceCard {
  animation: stageCardEnter 300ms cubic-bezier(0.4, 0, 0.6, 1) backwards;
  animation-delay: calc(var(--i, 0) * 36ms);
}

@media (prefers-reduced-motion: reduce) {
  .m-todayscreen.stageEnter .sectionLabel,
  .m-todayscreen.stageEnter .lessonCard,
  .m-todayscreen.stageEnter .practiceCard { animation: none; }
}

.m-todayscreen .lessonCard,
.m-todayscreen .practiceCard {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  background: #FFFFFF;
  border: 0;
  box-shadow: none;
  border-radius: 26px;
  padding: 4px 12px 4px 4px;
  color: var(--text-light);
  /* transform here is the release; the press is faster, see :active below */
  transition: box-shadow 0.15s ease, transform 260ms ease-out;
  /* Same dark plate iOS paints over a tapped link as on the pill's arrows — the
     scale below is the feedback instead. `manipulation` also drops the legacy
     double-tap-to-zoom wait, so the press lands on the first frame. */
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

/* Locked optional cards (no subscription): blur the content + centred lock. */
.m-todayscreen .locked .lessonThumb,
.m-todayscreen .locked .lessonText,
.m-todayscreen .locked .practiceThumb,
.m-todayscreen .locked .practiceBody {
  filter: blur(3px);
  opacity: 0.5;
}

.m-todayscreen .lockCenter {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 42px;
  height: 42px;
  border-radius: 50%;
  background: #192126;
  color: #FFFFFF;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  z-index: 2;
}

/* Press feedback. On a tap the finger is down for well under 100ms before the
   navigation starts, so the press has to reach full scale fast and ease back
   slowly (the release duration lives in the base rule's transition) — otherwise
   a 0.1s symmetric transition never renders anything on a phone. 0.97 rather
   than 0.99: 1% of an 80px-tall card is under a pixel of movement. */
.m-todayscreen .lessonCard:active,
.m-todayscreen .practiceCard:active,
.m-todayscreen .lessonCard.is-pressed,
.m-todayscreen .practiceCard.is-pressed {
  transform: scale(0.97);
  transition: transform 90ms ease-out;
}

.m-todayscreen .lessonThumb,
.m-todayscreen .practiceThumb {
  width: 104px;
  height: 96px;
  border-radius: 22px;
  /* photo→text is 20px, text→status icon stays at the flex gap of 12px */
  margin-right: 8px;
  background-color: #E0E1DE;
  background-size: cover;
  background-position: center;
  flex-shrink: 0;
  position: relative;
}

.m-todayscreen .bookmark {
  position: absolute;
  top: 4px;
  left: 4px;
  color: var(--text-light);
  fill: var(--program);
}

.m-todayscreen .lessonText,
.m-todayscreen .practiceBody {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}

.m-todayscreen .lessonTitle,
.m-todayscreen .practiceTitle {
  font-family: var(--font-serif);
  font-size: 16px;
  font-weight: 400;
  color: #192126;
  line-height: 1.4;
}

.m-todayscreen .lessonMeta,
.m-todayscreen .practiceMeta {
  font-family: var(--font-sans);
  font-size: 12px;
  line-height: 1.2;
  color: var(--text-light-muted);
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

/* Длинная подпись рядом с бейджем: своей строкой под заголовком, бейдж под
   ней (см. пояснение в today.ejs). Бейдж inline-flex, поэтому по ширине он
   сжимается до текста только с align-items. */
.m-todayscreen .lessonMeta.lessonMetaStack {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  line-height: 1.35;
}

/* "meta · duration" separator dot. */
.m-todayscreen .metaDot {
  width: 2px;
  height: 2px;
  border-radius: 50%;
  background: var(--text-light-muted);
  flex-shrink: 0;
}

/* Soft program-accent chip (was a solid red badge). */
.m-todayscreen .optional {
  font-size: 11px;
  color: var(--program, #E8642C);
  background: rgba(232, 100, 44, 0.12);
  background: color-mix(in srgb, var(--program, #E8642C) 12%, transparent);
  border: 0;
  padding: 2px 8px;
  border-radius: 6px;
}

.m-todayscreen .circleChev {
  width: 32px;
  height: 32px;
  border: 0;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #969FA6;
  flex-shrink: 0;
}

.m-todayscreen .circleCheck {
  width: 28px;
  height: 28px;
  margin-right: 4px;
  border: 0;
  border-radius: 50%;
  background: #192126;
  color: #FFFFFF;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

/* Optional content locked behind the Kegel Ultimate paywall. */
.m-todayscreen .circleLock {
  width: 32px;
  height: 32px;
  border: 0;
  border-radius: 50%;
  background: #192126;
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}


/* from components/screens/UnlockPelvicFloorScreen.module.css */
.m-unlockpelvicfloorscreen .page {
  position: relative;
  min-height: 100dvh;
  height: 100dvh;
  background: #000;
  color: #fff;
  overflow: hidden;
}

.m-unlockpelvicfloorscreen .video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  cursor: pointer;
  background: #000;
}

/* dark gradient over top + bottom so controls read on bright frames */
.m-unlockpelvicfloorscreen .scrim {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(180deg, rgba(0,0,0,0.45) 0%, rgba(0,0,0,0) 18%),
    linear-gradient(0deg, rgba(0,0,0,0.6) 0%, rgba(0,0,0,0) 38%);
}

/* ----- Top bar ----- */
.m-unlockpelvicfloorscreen .topBar {
  position: absolute;
  top: 14px;
  left: 12px;
  right: 12px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  z-index: 2;
}

.m-unlockpelvicfloorscreen .roundBtn {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 0;
  background: rgba(0, 0, 0, 0.4);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

/* ----- Bottom controls ----- */
.m-unlockpelvicfloorscreen .bottom {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 14px 20px 22px;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.m-unlockpelvicfloorscreen .title {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 22px;
  line-height: 1.2;
}

.m-unlockpelvicfloorscreen .subtitle {
  margin: 0;
  font-family: var(--font-sans);
  font-size: 13px;
  color: rgba(255,255,255,0.75);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.m-unlockpelvicfloorscreen .seek {
  position: relative;
  width: 100%;
  height: 4px;
  border: 0;
  padding: 0;
  background: rgba(255,255,255,0.25);
  border-radius: 2px;
  cursor: pointer;
  margin-top: 6px;
}

.m-unlockpelvicfloorscreen .seekFill {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  background: var(--program);
  border-radius: 2px;
}

.m-unlockpelvicfloorscreen .seekTimes {
  display: flex;
  justify-content: space-between;
  font-family: var(--font-sans);
  font-size: 12px;
  color: rgba(255,255,255,0.85);
  letter-spacing: 0.02em;
}

.m-unlockpelvicfloorscreen .controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 32px;
  margin-top: 8px;
}

.m-unlockpelvicfloorscreen .skipBtn {
  position: relative;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: 0;
  background: rgba(0,0,0,0.4);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-sans);
  font-size: 10px;
  font-weight: 400; /* Faculty ships 400 only */
  cursor: pointer;
}

.m-unlockpelvicfloorscreen .skipBtn span {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -42%);
  font-size: 11px;
  font-weight: 400; /* Faculty ships 400 only */
}

.m-unlockpelvicfloorscreen .bigPlayBtn {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  border: 0;
  background: #fff;
  color: #192126;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

/* ----- End-of-video OK overlay ----- */
.m-unlockpelvicfloorscreen .endOverlay {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  top: 0;
  z-index: 3;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: 0 20px 28px;
  background: linear-gradient(0deg, rgba(0,0,0,0.65) 0%, rgba(0,0,0,0) 60%);
}

.m-unlockpelvicfloorscreen .okBtn {
  width: 100%;
  max-width: 340px;
  height: 56px;
  border: 0;
  border-radius: 4px;
  background: var(--cta-dark);
  color: #fff;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 16px;
  letter-spacing: 0.1em;
  cursor: pointer;
}

/* from components/ui/Badge.module.css */
.m-badge .badge {
  display: inline-block;
  padding: 4px 10px;
  font-family: var(--font-sans);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #FFFFFF;
  border-radius: var(--radius-pill);
  white-space: nowrap;
}

.m-badge .burgundy { background: var(--badge-burgundy); }
.m-badge .gray     { background: var(--badge-gray); color: #192126; }
.m-badge .orange   { background: var(--badge-lime); color: var(--program-ink); }

/* from components/ui/OtpInput.module.css */
.m-otpinput .row {
  display: flex;
  justify-content: center;
  gap: 10px;
}

.m-otpinput .box {
  width: 56px;
  height: 56px;
  border-radius: 14px;
  border: 1px solid var(--border-light, #e4e9e6);
  background: #fff;
  text-align: center;
  font-size: 24px;
  font-weight: 400; /* Faculty ships 400 only */
  color: var(--text-light);
  outline: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.m-otpinput .box:focus {
  border-color: #2f7a63;
  box-shadow: 0 0 0 3px rgba(47, 122, 99, 0.12);
}

/* from components/ui/PrimaryButton.module.css */
.m-primarybutton .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 56px;
  border: 0;
  border-radius: var(--radius-pill);
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 15px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  transition: opacity 0.15s ease, background 0.15s ease;
}

/* Flat: no depth. Subtle press feedback via opacity only. */
.m-primarybutton .btn:active:not(:disabled) {
  opacity: 0.85;
}

.m-primarybutton .btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.m-primarybutton .full { width: 100%; }

.m-primarybutton .orange {
  background: var(--program);
  color: var(--program-ink);
}
.m-primarybutton .orange:hover:not(:disabled) {
  background: var(--program-hover);
}

.m-primarybutton .dark {
  background: var(--cta-dark);
  color: #FFFFFF;
}

.m-primarybutton .beige {
  background: var(--surface-beige);
  color: var(--text-light);
}

.m-primarybutton .darkOutline {
  background: transparent;
  color: var(--text-dark);
  border: 1px solid var(--text-dark-muted);
}

/* from components/ui/ProgressBar.module.css */
.m-progressbar .track {
  width: 100%;
  height: 3px;
  border-radius: 2px;
  overflow: hidden;
  position: relative;
}

.m-progressbar .light { background: rgba(0,0,0,0.08); }
.m-progressbar .dark  { background: rgba(255,255,255,0.12); }

.m-progressbar .fill {
  height: 100%;
  background: var(--program);
  transition: width 0.3s ease;
}

.m-progressbar .segmented {
  display: flex;
  gap: 6px;
  width: 100%;
}

.m-progressbar .seg {
  flex: 1;
  height: 3px;
  border-radius: 2px;
  background: rgba(0,0,0,0.08);
}

.m-progressbar .segDone {
  background: var(--cta-dark);
}

/* from components/ui/SuccessAnimation.module.css */
/* Standard completion-screen animation — orange circle draws, checkmark
   fills in, four 4-point sparkles burst outside the circle then fade.
   Color is driven by the `--accent` CSS custom property (set on .scene)
   so each consumer can pass its own brand color. */

.m-successanimation .scene {
  --accent: var(--program, #BBF246);

  position: relative;
  width: 180px;
  height: 180px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: visible;
}

.m-successanimation .svg {
  width: 100%;
  height: 100%;
  overflow: visible;
}

/* Filled flat lime disc — pops in (like the reference sticker icon). */
.m-successanimation .disc {
  fill: var(--accent);
  transform: scale(0);
  transform-origin: 50% 50%;
  animation: discPop 0.55s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

/* White flat checkmark on top of the disc. */
.m-successanimation .check {
  fill: none;
  stroke: #fff;
  stroke-width: 15;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 125;
  stroke-dashoffset: 125;
  animation: drawCheck 0.4s ease-out 0.5s forwards;
}

@keyframes discPop {
  0%   { transform: scale(0); }
  70%  { transform: scale(1.06); }
  100% { transform: scale(1); }
}

@keyframes drawCheck {
  to { stroke-dashoffset: 0; }
}

/* Sparkles */
.m-successanimation .sparkle {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 26px;
  height: 26px;
  margin: -13px 0 0 -13px;
  opacity: 0;
  pointer-events: none;
  animation: sparkle 1.2s ease-out 1.15s forwards;
}

.m-successanimation .sparkle svg {
  width: 100%;
  height: 100%;
  display: block;
  fill: var(--program);
}

/* Pop in and STAY (no fade-out). */
@keyframes sparkle {
  0%   { opacity: 0; transform: translate(var(--x, 0), var(--y, 0)) scale(0) rotate(0deg); }
  60%  { opacity: 1; transform: translate(var(--x, 0), var(--y, 0)) scale(1.15) rotate(95deg); }
  100% { opacity: 1; transform: translate(var(--x, 0), var(--y, 0)) scale(1) rotate(90deg); }
}

.m-successanimation .s1 { --x:  105px; --y:  -85px; animation-delay: 1.15s; }
.m-successanimation .s2 { --x: -110px; --y:  -75px; animation-delay: 1.25s; }
.m-successanimation .s3 { --x:   95px; --y:   95px; animation-delay: 1.20s; width: 20px; height: 20px; margin: -10px 0 0 -10px; }
.m-successanimation .s4 { --x: -100px; --y:   95px; animation-delay: 1.35s; }

/* from components/UltimateGate.module.css */
/* Locked (no-subscription) preview: the gated content renders behind a blur
   with a lock overlay + Unlock CTA on top. */
.m-ultimategate .gate {
  position: relative;
  min-height: 100dvh;
}

.m-ultimategate .blurred {
  filter: blur(7px);
  pointer-events: none;
  user-select: none;
  -webkit-user-select: none;
}

.m-ultimategate .overlay {
  position: fixed;
  inset: 0;
  z-index: 30;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 24px;
  text-align: center;
  background: rgba(255, 255, 255, 0.4);
}

.m-ultimategate .backBtn {
  position: absolute;
  top: 16px;
  left: 14px;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: #FFFFFF;
  border: 1px solid var(--border-card);
  color: var(--text-light);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.m-ultimategate .lockCircle {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: #192126;
  color: #FFFFFF;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 4px;
}

.m-ultimategate .lockTitle {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 24px;
  color: var(--text-light);
}

.m-ultimategate .lockText {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 15px;
  line-height: 1.45;
  color: var(--text-light-muted);
  max-width: 280px;
}

.m-ultimategate .unlockBtn {
  margin-top: 8px;
  background: var(--program);
  color: var(--program-ink);
  border: 0;
  border-radius: 999px;
  padding: 15px 36px;
  font-family: var(--font-display);
  font-weight: 400; /* Faculty ships 400 only */
  font-size: 15px;
  letter-spacing: 0.08em;
  cursor: pointer;
}


/* ===========================================================================
   ИНТРО ТРЕНИРОВКИ — hero с шейдером программы
   Замерено по фрейму hero-header (Figma 168:5212, 402×300, из которых 62 —
   статус-бар): заголовок на 44 от кромки контента, «level» через 8, пилюля
   ещё через 20. В браузере вьюпорт начинается ПОД статус-баром, поэтому
   300 − 62 = 238 плюс инсет для standalone — та же арифметика, что у Today.
   =========================================================================== */
/* Обёртка ровно в высоту hero — тот же приём, что .heroSticky на Today:
   у sticky-элемента внутри родителя собственной высоты нулевой ход, поэтому
   он уезжает вместе со страницей, а не прибивается к верху. Сам sticky нужен
   не ради прилипания: iOS Safari берёт цвет статус-бара с фиксированного или
   липкого элемента у верхней кромки. */
.introHeroWrap {
  flex: 0 0 auto;
  height: calc(238px + env(safe-area-inset-top, 0px));
}

.introHero {
  position: sticky;
  top: 0;
  display: block;
  height: calc(238px + env(safe-area-inset-top, 0px));
  overflow: hidden;
  color: #FFFFFF;
}

/* Прокручивается внутренний слой, а не сам экран: на iOS position: fixed внутри
   прокручиваемого поддерева уезжает вместе с ним, и кнопка START WORKOUT
   переставала быть прибитой к низу. У читалки ровно та же схема. */
.introScroll {
  flex: 1;
  overflow-y: auto;
}

/* Полотно ВЫШЕ секции и прижато к её низу: в макете шейдер — фрейм 402×460,
   заезжающий за верхнюю кромку на 160. Так же сохраняется масштаб рёбер: они
   живут в uv-пространстве полотна, и на 300px были бы на четверть мельче,
   чем на Today (там hero ≈460 вместе с инсетом). */
.introHeroShader {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  width: 100%;
  height: 460px;
  opacity: 0;
  transition: opacity 0.6s ease;
}
.introHeroShader.is-ready { opacity: 1; }

/* Тот же приём, что на Today: верхняя кромка приводится ровно к --tint —
   это цвет, который iOS Safari замораживает в статус-баре, в какой бы фазе
   ни была анимация шейдера. */
.introHeroTopFade {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: calc(80px + env(safe-area-inset-top, 0px));
  pointer-events: none;
  background: linear-gradient(180deg,
    var(--tint) 0%,
    rgba(var(--tint-rgb), 0.92) 18%,
    rgba(var(--tint-rgb), 0.68) 40%,
    rgba(var(--tint-rgb), 0.36) 64%,
    rgba(var(--tint-rgb), 0.12) 84%,
    rgba(var(--tint-rgb), 0) 100%);
}


/* Коробка ровно в однострочную высоту блока: сверху зарезервированы 44 под
   тулбар, снизу — 64, столько же, сколько под пилюлей в макете. Внутри блок
   центрируется, поэтому одна строка встаёт точно по замерам, а перенос на
   вторую растёт симметрично вверх и вниз, а не сдвигает всё вниз. */
.introHeroBody {
  position: absolute;
  z-index: 1;
  left: 0;
  right: 0;
  top: calc(44px + env(safe-area-inset-top, 0px));
  bottom: 64px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.introHeroTitle {
  margin: 0;
  /* 52 по бокам, чтобы длинный заголовок не заезжал под кнопку закрытия. */
  padding: 0 52px;
  font-size: 30px;
  line-height: 1.2;
  font-weight: 400;
  text-align: center;
}

.introHeroLevel {
  margin: 8px 0 0;
  padding: 0 52px;
  font-size: 12px;
  line-height: 1.2;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  text-align: center;
}

/* Кнопка закрытия — та же .appRoundBtn, что в тулбаре читалки и пикера;
   44×44 в 16 от правого края, вплотную под статус-баром (Figma 168:5333). */
.introHeroClose {
  position: absolute;
  z-index: 2;
  top: calc(8px + env(safe-area-inset-top, 0px));
  right: 16px;
}

/* Пилюля длительности и числа упражнений — тот же материал, что у пилюли
   стейджей на Today (кольцо у них общее, см. .dayPill::before выше). */
.introHeroPill {
  position: relative;
  margin-top: 20px;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 15px 24px;
  border-radius: 40px;
  background: rgba(0, 0, 0, 0.10);
}

.introHeroStat {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 16px;
  line-height: 1.4;
  white-space: nowrap;
}

.introHeroStatIcon {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  display: block;
}

/* Ромб-разделитель — тот же ассет, что в элементах списка читалки; красится
   маской, потому что в файле он залит тёмным. */
.introHeroDot {
  flex: 0 0 auto;
  width: 6px;
  height: 6px;
  background-color: currentColor;
  -webkit-mask: url('/app/images/dot-romb.svg') center / contain no-repeat;
  mask: url('/app/images/dot-romb.svg') center / contain no-repeat;
}

/* ---- Список упражнений и подсказки на интро тренировки ---------------------
   Вторая строка ячейки и шеврон повторяют карточки daily practice / lessons
   на Today (.lessonMeta / .metaDot / .circleChev) — те правила заперты в
   .m-todayscreen, поэтому здесь их зеркало, а не селектор через запятую. */
.introExRow {
  display: flex;
  align-items: center;
  gap: 16px;
  width: 100%;
  background: none;
  border: 0;
  padding: 8px 2px;
  margin-bottom: 4px;
  cursor: pointer;
  color: var(--text-light);
  text-align: left;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.introExMeta {
  font-family: var(--font-sans);
  font-size: 12px;
  line-height: 1.2;
  color: var(--text-light-muted);
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-top: 4px;
}

/* Отбивка между карточкой разминки с подсказкой и списком упражнений —
   в ширину карточки и в цвет её рамки. */
.introDivider {
  height: 1px;
  background: var(--divider);
  margin: 0 0 16px;
}

.introExDot {
  width: 2px;
  height: 2px;
  border-radius: 50%;
  background: var(--text-light-muted);
  flex-shrink: 0;
}

.introExChev {
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #969FA6;
  flex-shrink: 0;
}

/* Подсказки (под свитчером разминки и в TIPS) — просто текст, без подложки и
   без иконки; левый край совпадает с блоком над ними. */
.introHint {
  margin: 12px 0 24px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--text-light-muted);
}

/* Карточка со свитчером: в рамке осталась только верхняя часть. */
.introToggleCard {
  border: 1px solid var(--divider);
  border-radius: 16px;
  padding: 14px 16px;
}

.introToggle {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  text-align: left;
  color: #192126;
  /* Без этого iOS кладёт под палец тёмную плашку во всю ширину поля. */
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

/* MARK AS COMPLETE — та же капсула, что у START WORKOUT. */
/* REMOVE EXERCISE в экшн-шите упражнения: капсула размеров MARK AS COMPLETE,
   подложка — её же красный на 15%. Отступ 48px — от ползунка интенсивности. */
.exSheetRemove {
  width: 100%;
  height: 50px;
  border: 0;
  border-radius: 999px;
  margin-top: 48px;
  background: color-mix(in srgb, var(--error, #C51013) 15%, transparent);
  color: var(--error, #C51013);
  font-family: inherit;
  font-weight: 400;
  font-size: 14px;
  letter-spacing: 0.08em;
  cursor: pointer;
}

/* ADD EXERCISE в кастомной тренировке — та же капсула, что MARK AS COMPLETE,
   плюс глиф слева. */
.introAddEx {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

.introMarkDone {
  width: 100%;
  height: 50px;
  border: 0;
  border-radius: 999px;
  background: var(--surface-tile);
  color: var(--text-light);
  margin-top: 14px;
  font-weight: 400;
  font-size: 14px;
  letter-spacing: 0.08em;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}


/* ---------------------------------------------------------------------------
   Action sheet упражнения (тап по элементу списка Exercise Program на интро).
   Выезжает/уезжает как листы читалки (те же кривые, что .readerOverlayIn/Out),
   ширина — общая 480-колонка, верхние углы 38. Кнопка закрытия — та же
   .appRoundBtn, что в читалке/на интро, приколота к углу шита; контент
   скроллится под неё и растворяется верхним градиентом с теми же стопами, что
   у пикера (smoothstep, сплошные 4px). Скруглённые углы обрезают градиент
   через overflow:hidden самого шита. */
.exSheetScrim {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 100%;
  max-width: 480px;
  display: flex;
  align-items: flex-end;
  z-index: 60;
  animation: exScrimIn 258ms ease backwards;
  background: rgba(0, 0, 0, 0.5);
}
@keyframes exScrimIn { from { background: rgba(0, 0, 0, 0); } to { background: rgba(0, 0, 0, 0.5); } }
.exSheetScrim.exSheetScrimOut { animation: exScrimOut 437ms cubic-bezier(0.4, 0, 0.6, 1) forwards; }
@keyframes exScrimOut { from { background: rgba(0, 0, 0, 0.5); } to { background: rgba(0, 0, 0, 0); } }

.exSheet {
  position: relative;
  width: 100%;
  max-height: 88vh;
  display: flex;
  flex-direction: column;
  background: #FFFFFF;
  color: var(--text-light);
  border-radius: 38px 38px 0 0;
  overflow: hidden;
  font-family: var(--font-display-nire, sans-serif);
  /* Кривая входа читалки (Apple TV, 258мс/17 точек) и её же кривая выхода. */
  animation: exSheetIn 258ms cubic-bezier(0.32, 0.74, 0.35, 1) backwards;
  animation-timing-function: linear(0, 0.0416, 0.1325, 0.2437, 0.3633, 0.4998,
    0.5714, 0.6575, 0.7319, 0.7939, 0.8451, 0.8884, 0.9208, 0.9476, 0.9692,
    0.9864, 1);
}
@keyframes exSheetIn { from { transform: translateY(100%); } to { transform: translateY(0); } }
.exSheet.exSheetOut { animation: exSheetOut 437ms cubic-bezier(0.4, 0, 0.6, 1) forwards; }
@keyframes exSheetOut { from { transform: translateY(0); } to { transform: translateY(100%); } }

.exSheetScroll {
  flex: 1 1 auto;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 80px 20px calc(24px + env(safe-area-inset-bottom, 0px));
}

/* Заголовок приколот к верху шита поверх растворяющего градиента, по одной
   оси с кнопкой закрытия (у неё top:16, высота 44). */
.exSheetTitle {
  position: absolute;
  top: 16px;
  /* Симметричные поля (под кнопку закрытия справа и её зеркало слева) — иначе
     центр текста не совпадёт с центром шита. Верх приколот: длинный заголовок
     переносится на вторую строку ВНИЗ, не подъезжая к верхней кромке. */
  left: 76px;
  right: 76px;
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  margin: 0;
  font-size: 20px;
  font-weight: 400;
  z-index: 2;
}

/* Надзаголовки секций шита (INSTRUCTION:, ADJUST:). */
.exSheetLabel {
  margin: 32px 0 12px;
  font-size: 12px;
  letter-spacing: 0.08em;
  /* Капс отдаёт класс, а не строка контента — иначе заголовки секций
     рендерятся строчными и не читаются заголовками. */
  text-transform: uppercase;
  color: var(--text-light-muted);
}

/* Кросс-браузерный слайдер интенсивности: нативный вид разъезжается между
   движками (десктопный Chrome рисует своё, iOS — своё), поэтому
   appearance:none и одинаковые трек/ползунок руками. Заливка пройденной части
   — градиент по --fill, обновляется скриптом на input. Тень ползунка — та же,
   что у кнопки закрытия (.appRoundBtn). */
.exRange {
  -webkit-appearance: none;
  appearance: none;
  display: block;
  width: 100%;
  /* Зона тапа выше видимого ползунка (24px) — легче ухватить пальцем. */
  height: 44px;
  margin: -8px 0 0;
  padding: 0;
  /* Отрицательный margin подводит бокс под строку Adjust Intensity —
     поднимаем инпут в каскаде, чтобы зона захвата не перекрывалась. */
  position: relative;
  z-index: 1;
  background: transparent;
}
.exRange::-webkit-slider-runnable-track {
  height: 6px;
  border-radius: 3px;
  background: linear-gradient(to right,
    var(--program, #0365BB) var(--fill, 0%), var(--divider) var(--fill, 0%));
}
.exRange::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 36px;
  height: 24px;
  border-radius: 12px;
  border: 0;
  background: #FFFFFF;
  /* (6 − 24) / 2 — центровка ползунка по треку */
  margin-top: -9px;
  box-shadow: 0 2px 6px rgba(14, 14, 20, 0.18), 0 6px 16px rgba(14, 14, 20, 0.12);
  cursor: pointer;
}
.exRange::-moz-range-track {
  height: 6px;
  border-radius: 3px;
  background: linear-gradient(to right,
    var(--program, #0365BB) var(--fill, 0%), var(--divider) var(--fill, 0%));
}
.exRange::-moz-range-thumb {
  width: 36px;
  height: 24px;
  border-radius: 12px;
  border: 0;
  background: #FFFFFF;
  box-shadow: 0 2px 6px rgba(14, 14, 20, 0.18), 0 6px 16px rgba(14, 14, 20, 0.12);
  cursor: pointer;
}

/* Футер с SAVE вне скролла: 24px от нижнего края контента до кнопки. */
.exSheetFooter {
  position: relative;
  flex: 0 0 auto;
  background: #FFFFFF;
  /* Как у .readerCtaBar: сплошная плашка начинается от верхней грани кнопки —
     без верхнего паддинга, — а зазор контент-кнопка (40px) живёт в нижнем
     паддинге скролла и уезжает вместе с контентом. Так растворение происходит
     непосредственно у кнопки, а не в 40px над ней. */
  padding: 0 20px calc(20px + env(safe-area-inset-bottom, 0px));
}
/* Контент растворяется над футером — тот же хвост, что у .readerCtaBar::before
   под START WORKOUT. */
.exSheetFooter::before {
  content: '';
  position: absolute;
  bottom: 100%;
  left: 0;
  right: 0;
  height: 34px;
  background: linear-gradient(to bottom,
    rgba(255, 255, 255, 0),
    rgba(255, 255, 255, 0.57) 45%,
    rgba(255, 255, 255, 0.94) 85%,
    #FFFFFF);
  pointer-events: none;
}

.exSheetTopFade {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  /* Та же плашка, что тулбар читалки (.readerTopBar): сплошные 32px под
     заголовок + гладкий спад — пикерного варианта не хватало для читаемости
     заголовка над проскролленным контентом. */
  --bar-solid: 32px;
  height: 102px;
  pointer-events: none;
  background: linear-gradient(to bottom,
    #FFFFFF var(--bar-solid),
    rgba(255, 255, 255, 0.94) calc(var(--bar-solid) + (100% - var(--bar-solid)) * 0.15),
    rgba(255, 255, 255, 0.78) calc(var(--bar-solid) + (100% - var(--bar-solid)) * 0.3),
    rgba(255, 255, 255, 0.57) calc(var(--bar-solid) + (100% - var(--bar-solid)) * 0.45),
    rgba(255, 255, 255, 0.35) calc(var(--bar-solid) + (100% - var(--bar-solid)) * 0.6),
    rgba(255, 255, 255, 0.16) calc(var(--bar-solid) + (100% - var(--bar-solid)) * 0.75),
    rgba(255, 255, 255, 0.03) calc(var(--bar-solid) + (100% - var(--bar-solid)) * 0.9),
    rgba(255, 255, 255, 0) 100%);
}

.exSheetClose {
  position: absolute;
  top: 16px;
  right: 16px;
  z-index: 2;
}

/* Возврат плашки CTA после ухода экшн-шита: встречный выезд снизу (см.
   exerciseDetail.close()); 150% — чтобы за кадром скрылся и градиент-хвост. */
.readerCtaBar.ctaRiseIn { animation: ctaRiseIn 437ms cubic-bezier(0.4, 0, 0.6, 1) backwards; }
@keyframes ctaRiseIn {
  from { transform: translate(-50%, 150%); }
  to { transform: translate(-50%, 0); }
}
/* Уход вниз, пока показан экшн-шит: зеркало ctaRiseIn той же кривой. forwards —
   плашка ДОЛЖНА остаться внизу на всё время показа листа. */
.readerCtaBar.ctaFallOut { animation: ctaFallOut 437ms cubic-bezier(0.4, 0, 0.6, 1) forwards; }
@keyframes ctaFallOut {
  from { transform: translate(-50%, 0); }
  to { transform: translate(-50%, 150%); }
}

@media (prefers-reduced-motion: reduce) {
  .exSheetScrim, .exSheetScrim.exSheetScrimOut,
  .exSheet, .exSheet.exSheetOut,
  .readerCtaBar.ctaRiseIn { animation: none; }
  .readerCtaBar.ctaFallOut { animation: none; transform: translate(-50%, 150%); }
}

/* ===========================================================================
   Кегель-тренажёр (KegelPlayer) — редизайн 25.08.2026.
   Тёмный медиа-каркас: полоса .playerTopBar красит статус-бар, кнопки — общий
   onMedia-рецепт. Два состояния: «плеер» и «плейлист» (класс .ktQueue на
   странице); геометрию между ними возит JS-FLIP трансформами, кривая —
   критически задемпфированная пружина, снятая покадрово с перехода
   плеер⇄очередь Apple Music (τ≈50мс: 50%@80мс, 90%@185мс, хвост до ~500мс).
   =========================================================================== */
/* !important: fullscreen() вешает overflow-y:auto инлайном. */
.ktScreen {
  overflow: hidden !important;
  /* ВЫСОТА ПО ДИНАМИЧЕСКОМУ ВЬЮПОРТУ. fullscreen() задаёт инлайном inset:0, и
     тогда низ экрана оказывается на дне ЛАЙАУТ-вьюпорта — под нижним тулбаром
     Safari: нижний блок с кнопкой плейлиста уходил под тулбар (развёрнутый) или
     обрезался наполовину (свёрнутый) — скриншоты Игоря 26.08. 100dvh — это
     видимая высота, она же меняется при сворачивании тулбара; top+height
     переопределяют инлайновый bottom (over-constrained ⇒ bottom игнорируется).
     Работает и в оверлее, где экран переписан в absolute: dvh считается от
     вьюпорта независимо от позиционирования. */
  height: 100dvh;
}

/* Подъём экрана плеера над интро на START WORKOUT — тот же ход и кривая, что
   у листов (258мс, покадровый замер Apple TV). Транслируется сама страница:
   движущийся элемент обязан быть fixed сам (правило статус-бара), поэтому
   никакой обёртки. */
@keyframes ktRiseIn {
  from { transform: translateY(100%); }
  to { transform: translateY(0); }
}
.ktRiseIn {
  animation: ktRiseIn 258ms cubic-bezier(0.32, 0.74, 0.35, 1) backwards;
  animation-timing-function: linear(0, 0.0416, 0.1325, 0.2437, 0.3633, 0.4998,
    0.5714, 0.6575, 0.7319, 0.7939, 0.8451, 0.8884, 0.9208, 0.9476, 0.9692,
    0.9864, 1);
}

/* Пружина переключения состояний — для transition на transform из FLIP. */
.ktScreen .ktFlip {
  transition: transform 500ms linear(0, 0.090 5%, 0.264 10%, 0.442 15%,
    0.594 20%, 0.713 25%, 0.801 30%, 0.864 35%, 0.908 40%, 0.939 45%,
    0.960 50%, 0.973 55%, 0.983 60%, 0.993 70%, 0.997 80%, 0.999 90%, 1);
}

/* GUIDE-пилюля в тулбаре: тот же onMedia-рецепт, что у круглых кнопок
   (12% белого + blur + мягкая тень + градиентное 1px-кольцо), но в форме
   капсулы — у .appRoundBtn.onMedia::before радиус круга, поэтому кольцо
   повторено здесь со скруглением капсулы. */
.ktPill {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 44px;
  padding: 0 18px;
  border: 0;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.12);
  color: #FFFFFF;
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  box-shadow: 0 2px 24px rgba(0, 0, 0, 0.10);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  min-width: 0;
}
.ktPill::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 999px;
  padding: 1px;
  background: linear-gradient(135deg,
    rgba(255, 255, 255, 0.35) 0%,
    rgba(255, 255, 255, 0.05) 55%,
    rgba(255, 255, 255, 0.25) 100%);
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  mask-composite: exclude;
  pointer-events: none;
}
.ktPillLbl {
  font-size: 10px;
  letter-spacing: 0.12em;
  line-height: 1.2;
  opacity: 0.6;
  white-space: nowrap;
}
.ktPillTitle {
  display: flex;
  align-items: center;
  /* В макете 16-бокс шеврона примыкает к тексту вплотную (Frame 48097887):
     видимый зазор дают поля глифа внутри бокса. */
  gap: 0;
  font-size: 13px;
  line-height: 1.2;
  margin-top: 1px;
  white-space: nowrap;
}
.ktPillTitle img { display: block; }

/* Колонка контента. Отступ сверху — под тулбар (кнопки 44 при паддинге
   10 + safe-area = зона 64, как в макете). */
.ktCol {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
}
/* 52 − 20: блок времени поднят на 20 (правка Игоря 30.08). В
   плейлист-состоянии значение прежнее — 4. */
.ktTime {
  margin-top: calc(64px + env(safe-area-inset-top, 0px) + 32px);
  text-align: center;
  z-index: 1;
}
.ktQueue .ktTime { margin-top: calc(64px + env(safe-area-inset-top, 0px) + 4px); }
.ktBig {
  font-size: 70px;
  line-height: 1.2;
  font-weight: 400;
  color: #FFFFFF;
}
/* fit-content: FLIP меряет ширину ТЕКСТА (масштаб кегля 70→45 и 16→13), а не
   колонки — блочная ширина дала бы масштаб 1 и цифры прыгали бы без пружины. */
.ktBig, .ktSub {
  width: fit-content;
  margin-left: auto;
  margin-right: auto;
}
.ktQueue .ktBig { font-size: 45px; }
.ktSub {
  font-size: 16px;
  line-height: 1.2;
  font-weight: 400;
  color: #FFFFFF;
  margin-top: 8px;
  min-height: 1.2em;
}
.ktQueue .ktSub { font-size: 13px; margin-top: 6px; }

/* Кольцо ромбов + контрол. Бокс фиксированный, в плейлист-состоянии
   масштабируется трансформом (canvas отрисован под полный размер — вниз
   масштабируется чисто). */
.ktRingWrap {
  flex: 1 1 0;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
}
.ktQueue .ktRingWrap { flex: 0 0 auto; height: 224px; }
.ktRingBox {
  position: relative;
  width: 346px;
  height: 346px;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Кольца с ромбами и контрол крупнее на 15% и подняты на 20 (правка Игоря
     30.08). Сдвиг стоит СЛЕВА от scale: так он не умножается на масштаб и
     остаётся ровно 20px. Трансформ не меняет боксы в потоке — соседние блоки
     не сдвигаются. ЭТО ЖЕ значение продублировано как RING_P в setQueue()
     (app-player.js) — оно финал FLIP при закрытии плейлиста; менять парой,
     иначе блок доедет до одной точки, а класс поставит его в другую. */
  transform: translateY(-20px) scale(1.15);
}
/* В плейлист-состоянии — прежние значения: свой transform перекрывает оба
   преобразования разом, сдвиг сюда не переносится. */
.ktQueue .ktRingBox { transform: scale(0.6468); }
.ktDiamonds {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.ktControl {
  position: relative;
  width: 128px;
  height: 128px;
  border: 0;
  border-radius: 50%;
  /* Непрозрачный чёрный: ромбы стартуют/гаснут под контролом (scale 0.5) и
     просвечивали бы в зазоре между треком и иконкой. */
  background: #000000;
  color: #FFFFFF;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  padding: 0;
}
.ktControl svg.ktProgress {
  position: absolute;
  inset: 0;
  transform: rotate(-90deg);
  pointer-events: none;
}
.ktControl img { position: relative; }

/* Нижний блок: слева верхняя строка (часы + длительность) и название,
   справа info и кнопка плейлиста. Divider — нижняя кромка блока, виден
   только при открытом плейлисте. */
.ktBlock {
  flex: 0 0 auto;
  width: 100%;
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px 20px calc(16px + env(safe-area-inset-bottom, 0px));
  z-index: 1;
}
.ktBlock::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: rgba(255, 255, 255, 0.25);
  opacity: 0;
  transition: opacity 150ms ease;
}
.ktQueue .ktBlock { padding-bottom: 16px; }
.ktQueue .ktBlock::after { opacity: 1; }
.ktBlockText { flex: 1 1 auto; min-width: 0; }
.ktBlockMeta {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  line-height: 1.2;
  color: rgba(255, 255, 255, 0.6);
}
/* Часы — файл (белый, своей прозрачности в нём больше нет: Игорь заменил svg
   26.08, до этого 0.6 в файле умножалось на 0.6 здесь и иконка была бледнее
   текста). Глиф repeat приходит инлайновым svg и красится currentColor строки,
   поэтому прозрачность ему не нужна — цвет совпадает с текстом по определению. */
.ktBlockMeta img { display: block; opacity: 0.6; }
/* Прозрачность глифа задаётся НА ЭЛЕМЕНТЕ svg, а не через currentColor: у
   repeat штрихи перекрываются, и два полупрозрачных мазка складывались в 84%
   (замер 214 против 153 у текста). opacity на svg композитит группу целиком —
   получается ровно тот же 60% белого, что у текста и у файла часов. */
.ktBlockMeta svg,
.ktRowMeta svg {
  display: block;
  color: #FFFFFF;
  opacity: 0.6;
}
.ktMetaIc { display: flex; flex: 0 0 auto; }
.ktBlockTitle {
  font-size: 20px;
  line-height: 1.2;
  font-weight: 400;
  color: #FFFFFF;
  margin-top: 4px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Плейлист. Строки 44px с кружком-маркером (галочка у пройденных, номер у
   остальных), вертикальные чёрточки-коннекторы между кружками, подсветка
   текущей строки — белая капсула на 12%. Появление/гашение контента — по
   хореографии референса: fade после ~90% пути геометрии. */
.ktList {
  display: none;
  width: 100%;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 24px 20px calc(20px + env(safe-area-inset-bottom, 0px));
}
.ktQueue .ktList { display: block; }
.ktRow {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  background: none;
  border: 0;
  padding: 0;
  color: #FFFFFF;
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
.ktRow.ktCurrent::before {
  content: '';
  position: absolute;
  left: -10px;
  right: -10px;
  top: 50%;
  height: 64px;
  transform: translateY(-50%);
  border-radius: 40px;
  background: rgba(255, 255, 255, 0.12);
}
/* То же кольцо, что у круглых кнопок и пилюль экрана (правка Игоря 28.08).
   Рисуем на ::after: ::before занят самой плашкой, геометрия повторена
   один-в-один, чтобы кольцо село по её кромке. */
.ktRow.ktCurrent::after {
  content: '';
  position: absolute;
  left: -10px;
  right: -10px;
  top: 50%;
  height: 64px;
  transform: translateY(-50%);
  border-radius: 40px;
  padding: 1px;
  background: linear-gradient(135deg,
    rgba(255, 255, 255, 0.35) 0%,
    rgba(255, 255, 255, 0.05) 55%,
    rgba(255, 255, 255, 0.25) 100%);
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  mask-composite: exclude;
  pointer-events: none;
}
.ktRowMark {
  position: relative;
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: #404040;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  line-height: 1;
  color: #FFFFFF;
}
.ktRowText { position: relative; flex: 1 1 auto; min-width: 0; }
.ktRowMeta {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  line-height: 1.2;
  color: rgba(255, 255, 255, 0.6);
}
.ktRowMeta img { display: block; opacity: 0.6; }
.ktRowTitle {
  /* block, а не инлайновый span: у инлайна вертикальные margin'ы игнорируются
     (зазор до верхней строки не работал вовсе), а overflow/ellipsis — тоже. */
  display: block;
  font-size: 16px;
  line-height: 1.2;
  /* Замер макета: верхняя строка занимает 0…14, название начинается с 20 ⇒
     зазор 6 от макетного бокса, 5.6 от нашего (12px × 1.2 = 14.4). Прежние 2px
     склеивали строки (правка Игоря 26.08). */
  margin-top: 5.6px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ktRowLink {
  display: block; /* span: без block размеры схлопываются */
  /* НАД капсулой текущей строки: капсула (белая 12%, ::before строки, выступает
     на ±10px за строку) красилась ПОВЕРХ концов коннектора и светлила их —
     смена цвета линии на solid этого не лечила (недосмотр 25.08). Кружки не
     светлеют ровно потому, что .ktRowMark позиционирован; коннектору — тот же
     слой. Геометрически с капсулой не спорит: линия 2px в зазоре между
     кружками. */
  position: relative;
  z-index: 1;
  width: 2px;
  height: 24px;
  background: #404040;
  margin: 0 0 0 21px;
}

/* Плейлист едет вслед за блоком той же пружиной и одновременно фейдится:
   инлайновый transition затирал бы классовый, поэтому комбинированные
   переходы держат отдельные классы (transform-стопы = пружина .ktFlip). */
.ktScreen .ktListIn {
  transition: transform 500ms linear(0, 0.090 5%, 0.264 10%, 0.442 15%,
    0.594 20%, 0.713 25%, 0.801 30%, 0.864 35%, 0.908 40%, 0.939 45%,
    0.960 50%, 0.973 55%, 0.983 60%, 0.993 70%, 0.997 80%, 0.999 90%, 1),
    opacity 320ms ease 100ms;
  will-change: transform;
}
.ktScreen .ktListOut {
  transition: transform 500ms linear(0, 0.090 5%, 0.264 10%, 0.442 15%,
    0.594 20%, 0.713 25%, 0.801 30%, 0.864 35%, 0.908 40%, 0.939 45%,
    0.960 50%, 0.973 55%, 0.983 60%, 0.993 70%, 0.997 80%, 0.999 90%, 1),
    opacity 180ms ease;
  will-change: transform;
}

/* Галочка пройденного пункта: файл check-ic-24 нарисован тёмным (карточки
   Today) — в тёмном плейлисте перекрашивается фильтром в белый (макет). */
.ktRowMark img {
  filter: brightness(0) invert(1);
  display: none;
}
.ktRow.ktDone .ktRowMark img { display: block; }
.ktRow.ktDone .ktRowMark .ktRowNum { display: none; }

/* Открытый плейлист: плашка кнопки — сплошная белая, иконка чёрная (макет
   359:4526); файл list-ic белый, перекрашивается обратным фильтром. */
.ktListBtn,
.ktListBtn img { transition: background-color 150ms ease, filter 150ms ease; }
.ktQueue .ktListBtn { background: #FFFFFF; }
/* В плейлист-состоянии кнопка белая, и осветлять её нечем — притемняем, как
   Done/Ready. Правило стоит ЗДЕСЬ, а не в общем блоке отклика: у `.ktQueue
   .ktListBtn` та же специфичность, и общий блок идёт раньше по файлу. */
.ktQueue .ktListBtn:active, .ktQueue .ktListBtn.is-pressed { background: #E2E2E2; }
.ktQueue .ktListBtn img { filter: invert(1) brightness(0); }

/* Хром-плашка нижнего тулбара Safari: низ красит только fixed-элемент у
   нижней кромки (полноэкранный fixed-хост «баром» не считается). fixed задан
   классом, а не инлайном, — unfixPositions оверлея переписывает в absolute
   только инлайновые позиции, эта остаётся fixed и в оверлее с Today. */
.ktChromeBar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  /* ВЫСОТА ≥20px ОБЯЗАТЕЛЬНА: стенд /probe-bottom/ (видео Игоря 15-11-04,
     полный поэпизодный разбор) — полоса 2px НЕ красит нижний тулбар ни разу
     (0/3), полосы 20/34/90px красят стабильно (3/3 каждая). Прежние 2px
     (env(safe)=0 при развёрнутом тулбаре) и были причиной «лотереи». */
  height: calc(env(safe-area-inset-bottom, 0px) + 20px);
  padding: 0;
  background: #000000;
  /* Живёт в document.body над хостом оверлея (60); при открытом инфо-шите
     sheetShell опускает её на 59, чтобы низ красил белый шит. На чёрных
     экранах плеера чёрная полоса невидима; на светлых экранах флоу полоса
     ПЕРЕМОНТИРУЕТСЯ белой (перекраска смонтированной не сэмплится — 0/3). */
  z-index: 61;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .ktRiseIn { animation: none; }
  .ktScreen .ktFlip,
  .ktScreen .ktListIn,
  .ktScreen .ktListOut { transition: none; }
}


/* ===========================================================================
   Поп-ап подтверждения выхода из тренировки (confirmQuit).
   Замерено с Figma 407:7906 (фрейм 402×812): скрим #000 @55%; карточка
   314×300, radius 44, фон #292929, паддинги 32/20/20; заголовок 24px/120%,
   текст 16px/155% белый @60% с отступом 8 от заголовка; кнопки — общие .appCta
   с зазором 28 от текста и 12 между собой, в поп-апе меняются только цвета.
   =========================================================================== */
.quitScrim {
  position: fixed;
  inset: 0;
  z-index: 70;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(0, 0, 0, 0.55);
}
.quitCard {
  width: 314px;
  max-width: 100%;
  padding: 32px 20px 20px;
  border-radius: 44px;
  background: #292929;
  color: #FFFFFF;
  text-align: center;
  font-family: var(--font-display-nire, sans-serif);
}
.quitTitle {
  margin: 0;
  font-size: 24px;
  line-height: 1.2;
  font-weight: 400;
}
.quitText {
  margin: 8px 0 28px;
  font-size: 16px;
  line-height: 1.55;
  font-weight: 400;
  color: rgba(255, 255, 255, 0.6);
}
/* Кнопки — те же .appCta в тёмной гамме (.ctaOnDark / .ctaGhost, общие для
   поп-апа выхода и экрана завершения); своего здесь только зазор 12. */
.quitBtn.ghost { margin-top: 12px; }

/* Градиентная обводка карточки и кнопки QUIT ANYWAY — тот же рецепт, что у
   круглых кнопок плеера (.appRoundBtn.onMedia::before): заливка-градиент,
   замаскированная в область рамки, потому что border-image не следует
   border-radius. Радиусы свои: 44 у карточки, 999 у кнопки. Обводки нет у
   белой CONTINUE WORKOUT — на белом она не читается, как и у пилюли Done в
   плеере. Правка Игоря 29.08. */
.quitCard,
.quitBtn.ghost { position: relative; }
.quitCard::before,
.quitBtn.ghost::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(135deg,
    rgba(255, 255, 255, 0.35) 0%,
    rgba(255, 255, 255, 0.05) 55%,
    rgba(255, 255, 255, 0.25) 100%);
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  mask-composite: exclude;
  pointer-events: none;
}


/* Кнопка .appCta на тёмном экране: геометрия, кегль, радиус, letter-spacing и
   отклик нажатия — общие, меняется только гамма. Белая — основная (поп-ап
   выхода, CONTINUE на экране завершения), 20%-белая — второстепенная. */
.appCta.ctaOnDark {
  background: #FFFFFF;
  color: #000000;
}
.appCta.ctaGhost {
  background: rgba(255, 255, 255, 0.2);
  color: #FFFFFF;
}
@media (hover: hover) {
  .appCta.ctaOnDark:hover { background: #FFFFFF; }
  .appCta.ctaGhost:hover { background: rgba(255, 255, 255, 0.2); }
}

/* ===========================================================================
   Экран завершения тренировки (completeScreen).
   Замерено с Figma 408:8118 (фрейм 402×812): фон #000; сцена — группа звёзд
   206×157 от y93, кольцо 120 с градиентной обводкой 4px от y119, галочка 80
   от y139; заголовок 40px/130% UPPERCASE с градиентом ПО ШИРИНЕ ТЕКСТА,
   подзаголовок 16px/155% белый. Ячейки ответов — те же .readerOpt, что в
   читалке (форма, размеры, отклик), в тёмной гамме. Кнопка снизу зафиксирована
   и стоит на растворяющем градиенте — зеркало .readerCtaBar в чёрном.
   =========================================================================== */
.finScreen { overflow: hidden !important; }
/* Тот же тулбар, что на экране тренировки (кнопка на том же месте), но без
   растворяющего градиента — на этом экране он только снизу. */
.finTop.playerTopBar {
  background: none;
  justify-content: flex-end;
  padding-bottom: 0;
}
.finBody {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  /* 48px — верх группы звёзд, считая от кромки экрана: тулбар фиксированный и
     места в потоке не занимает. Дальше всё встаёт само (кольцо 74, заголовок
     234, подзаголовок 298). */
  padding: calc(48px + env(safe-area-inset-top, 0px)) 24px 110px;
}
/* Без опроса (Box Breathing, гайды) блок стоит по вертикальному центру между
   тулбаром и кнопкой — решение Игоря: с координатами макета короткий экран
   выглядел прижатым к верху. Верхний паддинг равен высоте тулбара (10 + 44),
   чтобы контенту было куда подниматься и он не наезжал на кнопку закрытия. */
.finBody.finCentered {
  justify-content: center;
  padding-top: calc(54px + env(safe-area-inset-top, 0px));
}

/* --- сцена: кольцо + галочка + звёзды ------------------------------------ */
.finScene {
  position: relative;
  flex: 0 0 auto;
  width: 206px;
  height: 157px;
}
.finRing {
  position: absolute;
  left: 44px;
  top: 26px;
  width: 120px;
  height: 120px;
  border-radius: 50%;
  transform: scale(0);
  animation: ipDiscPop 550ms cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}
/* Обводка градиентом — тем же кольцом на маске, что у кнопок поверх кадра:
   border-image не умеет следовать border-radius. Толщина 4 (в макете INSIDE). */
.finRing::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  padding: 4px;
  background: linear-gradient(90deg, #03AFEC 0%, #057CD6 12%, #5987F3 26%,
    #9D7CEE 40%, #BA71D9 52%, #CB6AC4 60%, #DC64A2 74%, #E8645F 87%, #EE7100 100%);
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  mask-composite: exclude;
}
/* Галочка проявляется прорисовкой — шторкой слева направо: у формы сперва
   короткий нижний штрих, затем длинный верхний, поэтому такой ход читается
   как рисование (прежняя анимация была stroke-dashoffset, к заливке с
   градиентом он неприменим). */
.finCheck {
  position: absolute;
  left: 64px;
  top: 46px;
  width: 80px;
  height: 80px;
  display: block;
  clip-path: inset(0 100% 0 0);
  animation: ipCheckWipe 400ms ease-out 500ms forwards;
}
.finStar {
  position: absolute;
  display: block;
  opacity: 0;
  animation: ipSparkleIn 1200ms ease-out forwards, ipTwinkle 4500ms ease-in-out 3;
}

@keyframes ipDiscPop {
  0% { transform: scale(0); }
  70% { transform: scale(1.06); }
  100% { transform: scale(1); }
}
@keyframes ipCheckWipe {
  from { clip-path: inset(0 100% 0 0); }
  to { clip-path: inset(0 0 0 0); }
}
@keyframes ipSparkleIn {
  0% { opacity: 0; transform: scale(0) rotate(0deg); }
  60% { opacity: 1; transform: scale(1.15) rotate(95deg); }
  100% { opacity: 1; transform: scale(1) rotate(90deg); }
}
/* «Дыхание» занимает первую треть цикла, дальше звезда стоит: интервал между
   вдохами втрое длиннее прежнего (решение Игоря). Волна — разными задержками
   у звёзд, они задаются в app-player.js. */
@keyframes ipTwinkle {
  0% { opacity: 1; transform: scale(1) rotate(90deg); }
  16% { opacity: 0.35; transform: scale(0.78) rotate(90deg); }
  33%, 100% { opacity: 1; transform: scale(1) rotate(90deg); }
}

/* --- заголовок и подзаголовок -------------------------------------------- */
.finTitle {
  flex: 0 0 auto;
  margin: 29px 0 0;
  font-size: 40px;
  line-height: 1.3;
  font-weight: 400;
  text-transform: uppercase;
  color: #FFFFFF;
}
/* Градиент тянется по ШИРИНЕ ТЕКСТА, а не колонки: inline-block ужимает бокс
   под строку. Без background-clip: text текст остаётся белым (иначе он был бы
   прозрачным, то есть невидимым). */
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .finTitle {
    display: inline-block;
    background-image: linear-gradient(90deg, #03AFEC 0%, #057CD6 12%, #5987F3 25%,
      #9D7CEE 40%, #BA71D9 52%, #CB6AC4 64%, #DC64A2 80%, #E8645F 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
}
.finSub {
  flex: 0 0 auto;
  margin: 12px 0 0;
  font-size: 16px;
  line-height: 1.55;
  font-weight: 400;
  color: #FFFFFF;
}

/* --- ячейки ответов: те же .readerOpt в тёмной гамме ---------------------- */
.finList {
  flex: 0 0 auto;
  width: 100%;
  margin-top: 24px;
}
.finOpt.readerOpt {
  position: relative;
  background: transparent;
  color: #FFFFFF;
  border-color: rgba(255, 255, 255, 0.25);
}
/* Кружок — той же обводкой, что ячейка (правило читалки). */
.finOpt .readerOptMark { border-color: rgba(255, 255, 255, 0.25); }
.finOpt .readerOptMark.is-on {
  background: #FFFFFF;
  color: #000000;
  border-color: transparent;
}
/* Выбранная ячейка: обводка тем же градиентом, что заголовок и кольцо. */
.finOpt.readerOpt.is-picked { border-color: transparent; }
.finOpt.readerOpt.is-picked::before {
  content: '';
  position: absolute;
  inset: -1px;
  border-radius: 16px;
  padding: 1px;
  background: linear-gradient(90deg, #03AFEC 0%, #057CD6 12%, #5987F3 25%,
    #9D7CEE 40%, #BA71D9 52%, #CB6AC4 64%, #DC64A2 80%, #E8645F 100%);
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  mask-composite: exclude;
  pointer-events: none;
}

/* --- нижняя плашка: зеркало .readerCtaBar в чёрном ------------------------ */
.finCtaBar {
  position: fixed;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 100%;
  max-width: 480px;
  z-index: 3;
  padding: 0 24px calc(20px + env(safe-area-inset-bottom, 0px));
  background: #000000;
}
.finCtaBar::before {
  content: '';
  position: absolute;
  bottom: 100%;
  left: 0;
  right: 0;
  height: 34px;
  background: linear-gradient(to bottom,
    rgba(0, 0, 0, 0),
    rgba(0, 0, 0, 0.57) 45%,
    rgba(0, 0, 0, 0.94) 85%,
    #000000);
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .finRing, .finCheck, .finStar { animation: none; }
  .finRing { transform: none; }
  .finCheck { clip-path: none; }
  .finStar { opacity: 1; }
}

/* ===========================================================================
   Таймерный плеер тренировки (timedPlayer: Resistance Kegel / Pelvic Pilates) —
   редизайн 26.08.2026. Замеры с Figma, фрейм 402×812: плеер 343:3853,
   состояние reps/пауза 363:5266, плейлист 360:4988.
   Каркас взят у кегель-тренажёра (.ktScreen / .ktCol / .ktBlock / .ktList /
   .ktFlip / .ktRiseIn) — здесь только своё: кадр, таймер и пилюли транспорта.
   Вертикаль плеера: кадр 84…516, таймер 552 (50px/120% ⇒ бокс 60), пилюли 648
   (48), блок 716 (76). Вертикаль плейлиста: кадр 32…227, таймер 243 (34px),
   пилюли 300, блок 368 (divider 443 виден), список с 468.
   =========================================================================== */

/* РАСКЛАДКА КОЛОНКИ (правка Игоря 26.08). Нижний блок обязан быть у нижней
   кромки ВИДИМОЙ области при любом состоянии тулбара Safari, пилюли и таймер —
   на неизменных расстояниях над ним. Поэтому вертикальные отступы здесь не
   margin'ы, а гибкие спейсеры, и порядок уступок задан явно:
     .tpTopGap  — 84 из макета, НЕ растёт, сдаётся ПЕРВЫМ (shrink 1000):
                  на экране короче макета кадр уезжает вверх к статус-бару;
     кадр       — 432 из макета, уступает вторым (shrink 1), уже после того,
                  как верхний отступ схлопнулся в ноль;
     .tpGap ×2  — 36 из макета, НЕ сжимаются и растут поровну: на высоком
                  экране блок и пилюли остаются у кромки, а таймер оказывается
                  по центру между кадром и пилюлями;
     зазор до блока — жёсткие 20 (margin-bottom пилюль).
   Отступ под статус-бар — паддинг колонки (только у этого экрана: у
   кегель-тренажёра свои отступы внутри .ktTime). */
.tpScreen .ktCol { padding-top: env(safe-area-inset-top, 0px); }
.tpTopGap { flex: 0 1000 84px; }
.tpGap { flex: 1 0 36px; }
.tpVideoWrap {
  flex: 0 1 432px;
  /* min-height:0 обязателен: у flex-элемента дефолт min-height:auto, и кадр
     упирался в min-content своего <video> (≈429 при ширине 402) — на коротком
     экране обёртка отказывалась сжиматься и нижний блок уезжал за кромку, а в
     плейлист-состоянии не садилась в свои 195. */
  min-height: 0;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
.tpVideo {
  position: relative;
  width: 100%;
  /* stretch, а не height:100%: высота обёртки приходит из flex-basis, и
     процентная высота ребёнка на таком родителе в WebKit ненадёжна. */
  align-self: stretch;
  overflow: hidden;
  background: #0A0A0A;
}
.tpFrame {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* Плейлист: тот же кадр МАСШТАБОМ (182.3/402 = 0.4535), а не пересборкой в
   маленький бокс — слой остаётся отрисованным в полную ширину, не мылится на
   обратном ходу и не переобрезает кадр. Высота кадра здесь задана в px:
   масштаб должен считаться от макетной высоты, а не от высоты обёртки
   (432 × 0.4535 = 195.9 против обёртки 195 — перелив 0.45px невидим). */
/* Плейлист-состояние — жёсткая макетная вертикаль (кадр 32…227, зазоры 16),
   а свободное место забирает список. */
.ktQueue .tpTopGap { flex: 0 0 32px; }
.ktQueue .tpGap { flex: 0 0 16px; }
.ktQueue .tpVideoWrap { flex: 0 0 195px; }
.ktQueue .tpVideo { align-self: center; height: 432px; transform: scale(0.4535); }

/* Плашка отдыха (остаётся до решения по живому материалу) и диаграмма-фолбэк
   для упражнений без съёмки. */
.tpRest {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 24px;
  text-align: center;
  background: #141414;
}
.tpRestBig {
  font-size: 48px;
  line-height: 1;
  letter-spacing: 0.04em;
  color: #FFFFFF;
}
.tpRestSub {
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.6);
}
/* Линейная диаграмма на чёрном не читается — кладём на светлую плитку. */
.tpDiagram {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 24px;
  background: var(--surface-tile, #F2F3F5);
}

/* Таймер — .ktBig тренажёра в своём кегле (50/34 вместо 70/45). */
.tpScreen .ktBig { font-size: 50px; }
.tpScreen.ktQueue .ktBig { font-size: 34px; }
.tpTime { flex: 0 0 auto; }

/* Пилюли транспорта: в макете 160×48 при колонке 402 (поля 36, зазор 10) —
   тянутся вместе с колонкой, сохраняя пропорцию. Левая — 15% белого с белой
   подписью (Pause/Play), правая — сплошная белая с чёрной (Done, во время
   отдыха Ready). */
.tpPills {
  flex: 0 0 auto;
  display: flex;
  gap: 10px;
  width: 100%;
  padding: 0 36px;
  margin-bottom: 20px; /* зазор до блока, из макета */
}
.tpPill {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  height: 48px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 0 12px;
  border: 0;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.15);
  color: #FFFFFF;
  font-size: 18px;
  line-height: 1.2;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  /* Отклик — как у .appCta (0.97): 0.92 круглых кнопок на плашке 160 читается
     провалом. Флаг .is-pressed ставит общий драйвер (partials/app-press.ejs). */
  transition: transform 260ms ease-out;
}
/* Кольцо Play/Pause — тот же рецепт, что у круглых кнопок экрана (правка Игоря
   28.08): градиент, замаскированный в область рамки. Белую пилюлю Done/Ready
   исключаем — на белом фоне белое кольцо не читается. */
.tpPill:not(.tpPillSolid)::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 999px;
  padding: 1px;
  background: linear-gradient(135deg,
    rgba(255, 255, 255, 0.35) 0%,
    rgba(255, 255, 255, 0.05) 55%,
    rgba(255, 255, 255, 0.25) 100%);
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  mask-composite: exclude;
  pointer-events: none;
}
.tpPill:active,
.tpPill.is-pressed {
  transform: scale(0.97);
  transition-duration: 90ms;
}
.tpPill img { display: block; }
.tpPillSolid { background: #FFFFFF; color: #000000; }

/* Нижний блок ничего не растягивает: его к кромке прижимают растущие .tpGap
   (в плейлисте — растущий список). */
.tpScreen .ktBlock { flex: 0 0 auto; }

@media (prefers-reduced-motion: reduce) {
  .tpPill { transition: none; }
}

/* ===========================================================================
   Самопроверка (assessment) — редизайн 26.08.2026. Замеры с Figma, фрейм
   402×812: покой 412:8996, удержание 412:9143, результат 412:8755.
   Тёмный каркас общий с плеерами (.ktScreen — высота по видимому вьюпорту и
   overflow; .playerTopBar; .ktPill; .ktTime/.ktBig/.ktSub; .appRoundBtn.onMedia;
   diamondRing) — здесь только кнопка удержания и раскладка.
   Вертикаль покоя: таймер 116, подпись 208, кнопка 379…539 (габарит с
   обводкой 375…543). Результат: кольца по центру большой цифры (392), время
   350…461, кнопка 306×48 с y716.
   =========================================================================== */
.paScreen {
  /* Долгое нажатие на кнопку в iOS выделяло ближайший текст — таймер или
     подпись (баг из отчёта Игоря 26.08). user-select на самой кнопке этого не
     закрывает: выделение начинается на СОСЕДНЕМ узле. */
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}
/* Пустой слот 44 слева: кнопки там в макете нет, но полоса раскладывает
   элементы space-between — без слота пилюля уехала бы влево. */
.paSlot {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
}

/* Пропорции вертикали — спейсерами, а не фиксированными отступами: ядро
   экрана «плавает» и держит соотношение при любой высоте окна.
   Числа из макетов 453:6239 / 453:6113 (правка Игоря 27.08: текст и кнопка
   подняты, кольца результата опущены): свободное место делится 137 : 300.

   ВАЖНО — почему на обоих экранах ОДНО правило. Требование Игоря: вертикальный
   центр кнопки на экране покоя и центр колец на экране результата должны
   СОВПАДАТЬ при любой высоте. Это выполняется, только если у обоих экранов
   одинаковы и высота ядра (.paCore = 168), и «занятая» верхняя зона. На покое
   она реальная — тулбар и блок времени (низ на 207.2 от кромки фрейма), на
   результате блок времени лежит ВНУТРИ ядра, поэтому ту же зону подставляем
   базисом верхнего спейсера. Полоса тулбара — fixed и места в потоке не
   занимает, её 64 тоже входят в базис. */
.paGapTop { flex: 137 0 0; min-height: 0; }
.paGapBottom { flex: 300 0 0; min-height: 0; }
.paGapTop.paGapDone { flex: 137 0 calc(env(safe-area-inset-top, 0px) + 207.2px); }

/* Таймер с подписью на экране покоя: цифра с y86 (макет 453:6239 минус 10 —
   правка Игоря 27.08; у кегель-тренажёра своя вертикаль, поэтому правило
   скоупится экраном). Нижний margin возвращает те же 10: занятая блоком зона
   остаётся 207.2, а от неё считаются и доли спейсеров, и совпадение
   вертикальных центров двух экранов. */
.paScreen .ktTime {
  margin-top: calc(env(safe-area-inset-top, 0px) + 86px);
  margin-bottom: 10px;
}

/* Ядро экрана: кнопка (или блок времени) и кольцо ромбов вокруг. Канва
   абсолютная и в раскладке не участвует — на результате она шире колонки и
   обрезается кромкой экрана, ровно как в макете. */
.paCore {
  position: relative;
  /* 168 = габарит кнопки удержания; та же высота у ядра экрана результата —
     см. объяснение у спейсеров. */
  flex: 0 0 168px;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
/* inset ПЕРЕД left/top: у .ktDiamonds задан inset:0 (кегель), и шорткат,
   поставленный после, обнулил бы центрирование. */
.paCore .ktDiamonds {
  inset: auto;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}
/* Кольца центрируются на ядре и на покое, и на результате. На результате
   внутри ядра лежит блок времени, поднятый на половину высоты большой цифры
   (84/2): её центр приходится ровно на центр ядра — как в макете. */
.paCoreDone .paTimeDone {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  /* margin обнуляется явно: у .ktTime он несёт отступ под тулбар экрана покоя
     и иначе утащил бы блок вниз. */
  margin-top: 0;
  margin-bottom: 0;
  transform: translateY(-42px);
}

/* Волна на экране результата (правка Игоря 27.08): кольца всплывают на месте
   кнопки удержания, а когда встали — весь блок уходит вверх ровно на высоту
   кнопки CONTINUE (--pa-lift меряется в JS), и следом, с небольшой задержкой,
   тем же ходом снизу приходит сама кнопка. Кривая — общая кривая подъёма
   листов (.appRiseIn). */
.paCoreDone {
  /* 600мс и НЕсимметричная кривая: мягкий вход короткий, мягкий выход вдвое
     длиннее — в терминах контрольных точек 0.25 на разгон против 0.5 на
     торможение. Путь подбора: 360 рывок → 560 резко → 1120 затянуто → 750 →
     600 (правки Игоря 27.08). */
  transition: transform 600ms cubic-bezier(0.25, 0, 0.5, 1);
}
.paCoreDone.paLift {
  transform: translateY(calc(var(--pa-lift, 50px) * -1));
}

/* Кнопка удержания: круг Ø160 с ЦЕНТРИРОВАННОЙ обводкой 8 (замер: внешний
   габарит 168, внутренний 152); #333 — те же 20% белого, что у трека
   прогресса в кегель-тренажёре. Прогресс-дуги здесь нет. touch-action: none —
   чтобы удержание не перехватывал скролл. */
.paHold {
  position: relative;
  z-index: 1;
  box-sizing: border-box;
  width: 168px;
  height: 168px;
  padding: 0;
  /* Обводку рисует ::before: она «дышит» отдельно от кнопки, а сама кнопка
     вместе с иконкой отвечает на нажатие общим pressShrink. */
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: #FFFFFF;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: none;
}
/* Дыхание обводки в покое: диаметр +10%, толщина при этом с 8 до 4 —
   в пике кольцо шире и тоньше (задача Игоря 27.08). Внешний габарит ::before
   фиксирован (border-box 168), поэтому меняется только видимая толщина. */
.paHold::before {
  content: '';
  position: absolute;
  inset: 0;
  box-sizing: border-box;
  border: 8px solid #333333;
  border-radius: 50%;
  animation: paBreathe 2800ms cubic-bezier(0.4, 0, 0.6, 1) infinite;
  pointer-events: none;
}
@keyframes paBreathe {
  0%, 100% { transform: scale(1); border-width: 8px; }
  50% { transform: scale(1.1); border-width: 4px; }
}
/* В удержании обратная связь своя (кольца ромбов) — пульсация останавливается
   в исходном размере. */
.paHoldOn::before { animation: none; }

/* Иконка не должна перетаскиваться пальцем: в iOS долгое нажатие на <img>
   поднимает нативный драг и глиф уезжает вслед за пальцем (баг из отчёта
   Игоря 27.08). pointer-events снимает её и с пути указателя — целью всегда
   остаётся кнопка. */
.paHold img {
  display: block;
  pointer-events: none;
  -webkit-user-drag: none;
  user-select: none;
  /* На нажатии иконка красится в #4D4D4D (правка Игоря 30.08; до этого была
     прозрачность, потом цвет обводки #333). Глиф чисто белый, поэтому хватает
     brightness: 0.302 × 255 = 77 = 0x4D. */
  transition: filter 220ms ease-out;
}
.paHold:active img,
.paHold.is-pressed img {
  filter: brightness(0.302);
  transition-duration: 90ms;
}

/* Блок времени на результате — тот же .ktTime, но без отступа под тулбар. */
.paTimeDone {
  position: relative;
  z-index: 1;
  margin-top: 0;
}

/* Кнопка результата — тот же прибитый к низу бар, что на экранах завершения
   (.finCtaBar: чёрная плашка с растворяющим градиентом над ней), внутри общая
   .appCta в белой гамме. Появляется фейдом после того, как кольца встали. */
.paCta {
  opacity: 0;
  pointer-events: none;
  transform: translateY(var(--pa-lift, 50px));
  transition: opacity 600ms ease 100ms,
              transform 600ms cubic-bezier(0.25, 0, 0.5, 1) 100ms;
}
.paCta.paCtaIn {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}

/* Пилюля RETRY: тот же onMedia-рецепт, что у круглых кнопок и GUIDE-пилюли
   (12% белого + blur + тень + градиентное кольцо), подпись — по правилам
   общих кнопок (.appCta: 15px, letter-spacing 0.5). */
.paRetry {
  position: relative;
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 44px;
  padding: 0 18px;
  border: 0;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.12);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  box-shadow: 0 2px 24px rgba(0, 0, 0, 0.10);
  color: #FFFFFF;
  font-size: 15px;
  letter-spacing: 0.5px;
  line-height: 1;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
.paRetry::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 999px;
  padding: 1px;
  background: linear-gradient(135deg,
    rgba(255, 255, 255, 0.35) 0%,
    rgba(255, 255, 255, 0.05) 55%,
    rgba(255, 255, 255, 0.25) 100%);
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  mask-composite: exclude;
  pointer-events: none;
}
.paRetry img { display: block; }

@media (prefers-reduced-motion: reduce) {
  .paCta,
  .paCoreDone { transition: none; }
  .paHold::before { animation: none; }
}


/* ===========================================================================
   Самопроверка, экраны 4 и 5: «YOUR STARTING POINT» (Figma 451:5846) и
   «Algorithm updated» (453:6438) — переведены на тёмный каркас .paScreen.
   Гистограмма замерена по рендеру макета (фрейм 390×812): пять колонок 52×184
   с шагом 66 (зазор 14), трек #262626 радиус 10, заливки с пиком 11 сверху;
   подсказка — белая пилюля 31 высотой с остриём 14×7. Кнопка внизу — общий
   .finCtaBar, как на экранах завершения и на экране результата.
   =========================================================================== */
/* Контент этих двух экранов центрируется по вертикали (требование Игоря);
   .finCtaBar — fixed, места в потоке не занимает, поэтому её высота
   компенсируется нижним паддингом колонки. */
.spCol {
  justify-content: center;
  padding: calc(64px + env(safe-area-inset-top, 0px)) 20px
           calc(90px + env(safe-area-inset-bottom, 0px));
}

.spChart {
  flex: 0 0 auto;
  display: flex;
  gap: 14px;
  align-items: flex-end;
}
.spTrack {
  position: relative;
  width: 52px;
  height: 184px;
  border-radius: 10px;
  background: #262626;
}
/* Заливка растёт снизу; высоту ставит JS (от неё же считается положение
   подсказки), поэтому здесь только ноль-старт и кривая. Пик сверху — клипом:
   11 из макета, вершина по центру колонки. */
.spFill {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 0;
  border-radius: 10px;
  clip-path: polygon(0 11px, 50% 0, 100% 11px, 100% 100%, 0 100%);
  transition: height 620ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
/* Подсказка: белая пилюля остриём в вершину своей колонки. Приходит фейдом со
   сдвигом снизу — после того, как налились все колонки. */
.spTip {
  position: absolute;
  /* Выше всех колонок: соседние треки идут позже по DOM и перекрывали бы
     подсказку — она шире своей колонки (баг из отчёта Игоря 27.08). */
  z-index: 2;
  left: 50%;
  transform: translate(-50%, 14px);
  margin-bottom: 7px; /* место под остриё */
  padding: 8px 14px;
  border-radius: 10px;
  background: #FFFFFF;
  color: #192126;
  font-size: 13px;
  line-height: 1.2;
  white-space: nowrap;
  opacity: 0;
  transition: opacity 420ms ease, transform 420ms cubic-bezier(0.22, 0.61, 0.36, 1);
  pointer-events: none;
}
.spTip::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 100%;
  width: 0;
  height: 0;
  border-left: 7px solid transparent;
  border-right: 7px solid transparent;
  border-top: 7px solid #FFFFFF;
  transform: translateX(-50%);
}
.spTip.spTipIn {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* Заголовок и текст — те же .finTitle / .finSub, что на экранах завершения. */
.spTitle {
  margin-top: 36px;
  text-align: center;
}
.spSub {
  margin-top: 12px;
  max-width: 320px;
  text-align: center;
}

/* «Algorithm updated»: кольцо рисует канва (палитра — общая ringLut, трек
   белый 20%), проценты внутри, подпись под ним. */
.spRing {
  position: relative;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
}
.spRing canvas { display: block; }
.spPct {
  position: absolute;
  font-size: 44px;
  line-height: 1.2;
  color: #FFFFFF;
}
.spDone {
  flex: 0 0 auto;
  margin: 36px 0 0;
  font-size: 28px;
  line-height: 1.2;
  font-weight: 400;
  color: #FFFFFF;
  opacity: 0;
  transition: opacity 400ms ease;
}
.spDone.spDoneIn { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .spFill, .spTip, .spDone { transition: none; }
}

/* ===========================================================================
   Вкладка Explore — редизайн 27.08.2026. Значения взяты ИЗ НОД Figma
   (448:3438 и потомки), а не с рендера: карточка программы 448:3553, пилюля
   448:3950, бейдж 458:6519, плитка практики 458:6908, лейблы 458:6900,
   заголовок 456:6509.
   Колонка — общая 480 (класс viewport-wide на body), поля 20.
   =========================================================================== */
.m-explorescreen .exPage {
  /* Низ: 48 до кромки таббара плюс его собственная высота (пилюля 9+44+9 = 62
     и safe-area). Класс tab-bottom-pad на этом экране не нужен — иначе
     отступы складывались и внизу оставалась дыра ~82 (правка Игоря 27.08). */
  padding: calc(10px + env(safe-area-inset-top, 0px)) 0
           calc(110px + env(safe-area-inset-bottom, 0px));
}
.m-explorescreen .exTop {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 20px;
}
.m-explorescreen .exTitle {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 400;
  font-size: 20px;
  line-height: 1.2;
  color: var(--text-light, #192126);
}

/* Лейбл секции: 12px, #5E6468, трекинг 1.1, капсом (нода 458:6900). */
.m-explorescreen .exLabel {
  margin: 32px 20px 12px;
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: 12px;
  line-height: 1.33;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  color: #5E6468;
}
.m-explorescreen .exLabelFirst { margin-top: 30px; }

.m-explorescreen .exMain { padding: 0 20px; }
/* Ряд рекомендованных: карточки той же ширины, что главная, зазор 10;
   поля-«отбивки» дают крайним карточкам те же 20 от кромки. */
.m-explorescreen .exRow {
  display: flex;
  gap: 10px;
  padding: 0 20px;
  /* scroll-padding обязателен вместе со snap: без него Chrome подтягивает
     первый элемент к ПАДДИНГ-боксу, и ряд стартует уже прокрученным на 20 —
     левое поле пропадало. */
  scroll-padding-left: 20px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.m-explorescreen .exRow::-webkit-scrollbar { display: none; }
.m-explorescreen .exCardRow {
  /* 100% контент-бокса ряда = ширина главной карточки (362 при колонке 402,
     440 при 480): в макете рекомендованные той же ширины, что главная. */
  flex: 0 0 100%;
  scroll-snap-align: start;
}

/* Карточка программы: тот же каркас, что у карточки пикера (фото + лента +
   название и блерб поверх), но вертикаль своя — фото 148 из 280. */
.m-explorescreen .exCard {
  position: relative;
  display: block;
  height: 280px;
  border-radius: 26px;
  overflow: hidden;
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
  transition: transform 260ms ease-out;
}
/* Скейла на нажатии у карточек Explore НЕТ (правка Игоря 30.08): ряды
   скроллятся горизонтально, и сжатие под пальцем ещё до начала свайпа дёргало
   соседние карточки — они подтягивались к сжавшейся. */
.m-explorescreen .exCardPhotoBox,
.m-explorescreen .exCardBandBox {
  position: absolute;
  left: 0;
  right: 0;
  overflow: hidden;
  pointer-events: none;
}
.m-explorescreen .exCardPhotoBox { top: 0; height: 148px; }
.m-explorescreen .exCardBandBox { bottom: 0; height: 132px; }
.m-explorescreen .exCardPhoto {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Лента растягивается ровно в свой бокс — как в пикере (fill, не cover). */
.m-explorescreen .exCardBand {
  width: 100%;
  height: 100%;
  object-fit: fill;
  display: block;
}
/* Как заголовок карточки пикера (правка Игоря 28.08): прижат НИЗОМ, эллипсиса
   нет, длинное название переносится и растёт ВВЕРХ, на фото, — блерб и пилюля
   под ним не сдвигаются. Низ последней строки всегда на 163px от верха
   карточки (карточка 280 ⇒ bottom: 117), это ровно то место, где стояла
   единственная строка при top:145 + translateY(-50%).
   Горизонтальные границы — left/right, а не left:50% + transform: у
   absolute-элемента с одной координатой ширина строки считается shrink-to-fit
   от неё до края (то есть от половины карточки), и перенос шёл бы по 161px. */
.m-explorescreen .exCardTitle {
  position: absolute;
  bottom: 117px;
  left: 20px;
  right: 20px;
  font-family: var(--font-serif);
  font-size: 30px;
  line-height: 1.2;
  text-transform: uppercase;
  text-align: center;
  color: #FFFFFF;
}
/* 28 — только женская версия (как заголовок женской карточки пикера); мужские
   карточки согласованы по фигме на 30. */
.m-explorescreen.m-female .exCardTitle { font-size: 28px; }

.m-explorescreen .exCardBlurb {
  position: absolute;
  top: 197px;
  left: 50%;
  transform: translate(-50%, -50%);
  width: calc(100% - 40px);
  max-width: 322px;
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.4;
  text-align: center;
  color: #FFFFFF;
}

/* Бейдж и мета-пилюля — одна форма (ноды 458:6519 и 448:3950): паддинги
   10/4, радиус 40, обводка 1px rgba(255,255,255,0.7), backdrop-blur 2.5,
   текст 12. Разница только в заливке: бейдж — белый 85%, пилюля — чёрный 5%.
   Ширина обеих задаётся контентом. */
.m-explorescreen .exBadge,
.m-explorescreen .exPill {
  position: absolute;
  display: inline-flex;
  align-items: center;
  /* 5/11, а не 4/10: обводка в Figma внутренняя (strokeAlign INSIDE) и в
     габарит не входит — её 1px мы добавляем к паддингу, чтобы высоты
     остались макетными (пилюля 27, бейдж 24). */
  padding: 5px 11px;
  border-radius: 40px;
  -webkit-backdrop-filter: blur(2.5px);
  backdrop-filter: blur(2.5px);
  font-family: var(--font-sans);
  font-size: 12px;
}
/* Стопка бейджей в углу: на карточке программы это один бейдж (плюс
   «Completed» у пройденной), на плитке библиотеки — категория и «New».
   Позиция общая, сами бейджи внутри становятся поточными. */
.m-explorescreen .exBadgeStack {
  position: absolute;
  top: 16px;
  left: 16px;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
}
.m-explorescreen .exBadgeStack .exBadge { position: static; }
/* Галочка в бейдже «Completed»: бокс 14 при чернилах 10.8×8.4 — тот же
   оптический размер, что у прежнего текстового «✓» (8×9). Зазор до слова 3px,
   как был у глифа (2.9). */
.m-explorescreen .exBadgeIcon {
  width: 14px;
  height: 14px;
  margin-right: 3px;
  flex: 0 0 auto;
}

/* На карточке программы бейджей бывает два («30-Day Program» и «Completed») —
   они идут в РЯД (правка Игоря 28.08). На плитке 175px ряд не помещается,
   поэтому там остаётся колонка. */
.m-explorescreen .exCard .exBadgeStack {
  flex-direction: row;
  align-items: center;
}
/* «New» — точка перед словом, как было у женских карточек до переезда. */
.m-explorescreen .exBadgeNew::after {
  content: '';
  position: static;
  width: 6px;
  height: 6px;
  margin-right: 6px;
  border-radius: 50%;
  background: #E0562F;
  padding: 0;
  order: -1;
  -webkit-mask: none;
  mask: none;
}
/* Замок закрытой карточки — тот же кружок, что бейдж, но стоит НАД заголовком
   (правка Игоря 28.08), у той же левой кромки, что бейджи сверху. */
.m-explorescreen .exTileLock {
  position: relative;
  z-index: 2;
  margin-bottom: 6px;
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.85);
  -webkit-backdrop-filter: blur(2.5px);
  backdrop-filter: blur(2.5px);
  color: var(--text-light, #192126);
}
.m-explorescreen .exTileLocked .exTileTitle { opacity: 0.85; }

/* Обводка — ГРАДИЕНТНАЯ, стопы и направление сняты из нод (448:3950 и
   458:6519, stroke GRADIENT_LINEAR): белый 70% → 20% на середине → 70%, ось
   почти горизонтальная (gradientTransform даёт наклон ≈4°). Рисует
   псевдоэлемент с маской — border-image не умеет следовать border-radius. */
.m-explorescreen .exBadge::before,
.m-explorescreen .exPill::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 40px;
  padding: 1px;
  background: linear-gradient(94deg,
    rgba(255, 255, 255, 0.7) 0%,
    rgba(255, 255, 255, 0.2) 50%,
    rgba(255, 255, 255, 0.7) 100%);
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  mask-composite: exclude;
  pointer-events: none;
}
.m-explorescreen .exBadge {
  top: 16px;
  left: 16px;
  background: rgba(255, 255, 255, 0.85);
  /* Тёмный текст — общим токеном, без капса и без трекинга (правка Игоря
     28.08). Сам регистр правится при рендере: в контенте и переводах строка
     лежит капсом, а её же капс — ключ перевода (routes/app-pages.js). */
  color: var(--text-light, #192126);
  line-height: 1.2;
  white-space: nowrap;
}
.m-explorescreen .exPill {
  bottom: 16px;
  left: 50%;
  transform: translateX(-50%);
  gap: 8px;
  background: rgba(0, 0, 0, 0.05);
  color: #FFFFFF;
  line-height: 1.4;
  white-space: nowrap;
}
.m-explorescreen .exPillItem {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.m-explorescreen .exPillIcon {
  display: block;
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
}
/* Разделитель — тот же ромб, что в интро-пилюле: квадрат 2.667 под 45°. */
.m-explorescreen .exDot {
  flex: 0 0 auto;
  width: 2.667px;
  height: 2.667px;
  background: #FFFFFF;
  transform: rotate(45deg);
}

/* Плитки практик: 175×260, радиус 26, зазор 12 (ноды 458:6908 и соседние);
   название 16/1.55 белым в углу с отступом 16, к низу — растворение, чтобы
   подпись читалась на светлых кадрах. */
.m-explorescreen .exTiles {
  display: flex;
  gap: 12px;
  padding: 0 20px;
  scroll-padding-left: 20px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.m-explorescreen .exTiles::-webkit-scrollbar { display: none; }
.m-explorescreen .exTile {
  position: relative;
  flex: 0 0 175px;
  height: 260px;
  border-radius: 26px;
  overflow: hidden;
  scroll-snap-align: start;
  /* Колонка, прижатая к низу: заголовок и замок над ним получают один левый
     отступ от паддинга плитки — тот же, что у бейджей в верхнем углу. */
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: flex-start;
  padding: 16px;
  background-color: #BABABA;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
  transition: transform 260ms ease-out;
}
/* Плитки — то же самое, скейла нет: они тоже живут в горизонтальных рядах. */
.m-explorescreen .exTile::after {
  content: '';
  position: absolute;
  inset: 0;
  /* Затемнение низа ослаблено трижды (правки Игоря 28.08): исходные 0.35/0.55
     умножены на 0.7, затем на 0.8 и ещё раз на 0.8 — итого 0.448 от
     начального. Точки перегиба и сама кривая не менялись. */
  background: linear-gradient(180deg,
    rgba(0, 0, 0, 0) 55%,
    rgba(0, 0, 0, 0.157) 82%,
    rgba(0, 0, 0, 0.246) 100%);
  pointer-events: none;
}
.m-explorescreen .exTileTitle {
  position: relative;
  z-index: 1;
  font-family: var(--font-serif);
  font-size: 16px;
  line-height: 1.55;
  color: #FFFFFF;
}

/* ===========================================================================
   Экран практики (Explore → Body/Mind Practices) — редизайн 27.08.2026.
   Каркас читалки: 480-колонка, её типографика (.readerH2/.readerText) и её же
   прибитый снизу бар (.readerCtaBar + .appCta). Своё — изображение сверху
   прежней высоты (250) и метки блоков.
   =========================================================================== */
.paperScreen .prBody {
  flex: 1;
  overflow-y: auto;
  /* Нижний отступ — под прибитую кнопку, как в читалке. */
  padding: 0 24px 120px;
}
/* Изображение во всю ширину колонки: тело скролла с полями 24, поэтому
   отрицательные margin'ы возвращают его к кромкам. */
.paperScreen .prHero {
  position: relative;
  margin: 0 -24px 20px;
  height: 250px;
  background: #E0E1DE;
  overflow: hidden;
}
.paperScreen .prHeroImg {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.paperScreen .prTitle { margin: 0 0 20px; }
.paperScreen .prLabel {
  margin: 28px 0 12px;
  font-size: 14px;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-light, #192126);
}
.paperScreen .prFreq {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 4px 0 0;
  font-size: 14px;
  line-height: 1.4;
  color: var(--text-light-muted, #5E6468);
}
.paperScreen .prFreq img { display: block; opacity: 0.6; filter: brightness(0) invert(0.4); }
