/* Foundation pattern components (Blueprint waves).
   Source: design-system-v2/handoff/project/Паттерны.dc.html
   Visual values (padding, font-size, etc.) governed by the handoff — on conflicts, handoff is authoritative.
   All colours/radii/shadows via var(--…) from tokens.css — no inline colour literals.
   Class prefixes: rp-ph* (page header), rp-card* (section card),
   rp-chip* (status chip), rp-ctx* (context badge), rp-empty2* (empty state),
   rp-tabs*, rp-tab* (hub tabs; rp-tabs-seg/-seg-tab/-seg-ico/-seg-lbl = the mobile «icon + short label»
     N-column segment control RpHubTabs renders when a RpHubTab carries Icon/Short — Финансы.dc.html),
   rp-fin* (wave 5 Task 2 — /finance hub + «Платежи» tab, Финансы.dc.html: rp-fin-toolbar/-panel shell,
     the summary row (rp-fin-summary/-spacer, the received card rp-fin-sumcard/-sumcard-label/-sumcard-row/
     -sumcard-amount/-sumcard-count, the period segment rp-fin-periods/-period(--active), the status
     dropdown rp-fin-filterbox/-filter-ico/-filter), the desktop payments table (rp-fin-table/-thead/-row/
     -date/-payer/-payer-name/-payer-sub/-item/-amount/-chev) + its ≤640px card view (rp-fin-cards/-card/
     -card-top/-card-payer/-card-amount/-card-mid/-card-item/-card-meta), rp-fin-more/-none/-note; wave 5
     Task 3 — «Прайс» tab: rp-fin-price-section/-sectionhead/-title/-sub/-addbtn, the packages table
     (rp-fin-price-table/-thead/-row/-name/-mix/-term/-vis(--accent), the hand-rolled 36×21 toggle
     rp-fin-price-switch(-thumb) — П-9, no BbSwitch preset matches — and rp-fin-price-edit), the read-only
     courses-products table (rp-fin-price-coursetable/-courserow/-courselink, no header row), their shared
     ≤640px card view (rp-fin-price-cards/-card/-card-top/-card-name/-card-amount/-card-meta/-card-mid),
     and PackageDialog's audience multi-select (rp-fin-pkg-audlist/-audrow(--picked)/-audcheck/-audname —
     everything else reuses rp-covw-dlg* chrome verbatim)); wave 5 Task 4 — «Приём оплат» tab (GatewayPanel):
     rp-gw* (rp-gw-intro, rp-gw-banner(--off)/-banner-ico/-banner-txt/-banner-title/-banner-sub/-banner-btn,
     rp-gw-seg/-seg-tab(--active), rp-gw-reco, rp-gw-fields/-row2/-field(--half)/-label/-input/-hint,
     rp-gw-details/-details-body, rp-gw-actions) and «Подписка» tab (SubscriptionPanel): rp-sub* (rp-sub-status/
     -pill(--ok/--warn/--danger)/-pill-dot/-paid, rp-sub-plans/-plan(--current)/-plan-head/-plan-name/-plan-badge/
     -plan-price/-plan-per, rp-sub-feats/-feat(--off)/-feat-ico, rp-sub-plan-grow, rp-sub-plan-cta(--primary/
     --outline/--free), rp-sub-promo — the promo input reuses rp-gw-field/-label/-input); wave 5 Task 5 —
     «ИИ-кредиты» tab (AiCreditsPanel): rp-ai* (rp-ai-top/-card/-card-label, rp-ai-avail/-avail-num/-avail-meta/
     -avail-note, rp-ai-promo-title/-promo-row/-promo-btn — the redeem input reuses rp-gw-input, rp-ai-discount
     for the percent-off-at-checkout field — reuses rp-gw-field/-label — rp-ai-section-title, the desktop pack
     grid rp-ai-packs/-pack/-pack-name/-pack-credits/-pack-bottom/-pack-price/-pack-buy + its ≤640px row list
     rp-ai-packs-m/-pack-row/-pack-row-info/-pack-row-name/-pack-row-credits/-pack-row-price/-pack-row-buy, and
     the desktop-only history rp-ai-history-section/-history/-history-row/-history-date/-history-kind/
     -history-delta(--plus) — grid 130px 1fr 80px, no header row, LOCKED-12 (no mobile counterpart at all)),
     rp-btn-submit, rp-spin (submit), rp-bal* (balance widget/card/history),
   rp-prod* (product card), rp-seg* (segmented tabs), rp-asg* (assignment list/card),
   rp-sban* (success banner), rp-payrow* (payments list), rp-crs* (course card),
   rp-pay* (Task 6 — /pay page layout: section spacing/labels + the "Купить" grid; wave 6 Task 2 added
     rp-pay-kid* — the parent «За детей» blocks, Оплата.dc.html «Родитель»: the per-(child, tenant) block
     rp-pay-kid, its desktop head rp-pay-kid-head(--self is the «За себя» divider)/-avatar(--warm)/-name/-sub,
     the balance wrapper rp-pay-kid-bal(--warn = zero-balance warning tone over rp-balcard), the ≤768px
     accordion rp-pay-kid-acc/-acc-txt/-acc-name/-acc-bal(--warn)/-chev(--open), the collapsible body
     rp-pay-kid-body(--open) + mobile shop label rp-pay-kid-shoplabel, the mobile compact product rows
     rp-pay-kid-rows/-row/-row-info/-row-name/-row-sub/-row-buy/-row-price/-row-btn, and the honest
     empty-shop note rp-pay-kid-none),
   rp-pmt* (wave 5 Task 6 — /payments/{id} + /receipts/{id} pages, Платёж и чек.dc.html: the page wrapper
     rp-pmt (max-width column), the payment card rp-pmt-card + rp-pmt-crumb (role breadcrumb), the header
     rp-pmt-head/-head-main/-title/-ulid (mono short ULID), the 150px-1fr requisites grid rp-pmt-rows/-row
     (--last)/-k/-v(--strong), the destructive-outline rp-pmt-actions/-refund-btn, the refunds table
     rp-pmt-rf-table/-rf-thead/-rf-row/-rf-amount/-rf-date (grid 90px 90px 1fr 120px) + rp-pmt-refunds-title;
     RefundDialog reuses rp-covw-dlg head/close chrome + rp-sched-dlg-label/-input, adds rp-pmt-rf-dlg/
     -rf-desc/-rf-fields/-rf-hint/-rf-actions/-rf-cancel/-rf-submit (destructive); the receipt card
     rp-pmt-rcpt-card/-rcpt-head/-rcpt-badge (accent 40px)/-rcpt-title/-rcpt-sub, the dashed товарный чек
     rp-pmt-rcpt-table/-rcpt-row/-rcpt-k/-rcpt-leader (dotted)/-rcpt-v(--strong)/-rcpt-total/-rcpt-total-k/
     -rcpt-spacer/-rcpt-total-v, the full-width primary-outline rp-pmt-rcpt-pdf + rp-pmt-rcpt-note),
   rp-wk*, rp-wknav*, rp-book* (Task 7 — /my-lessons week calendar + booking dialog;
     wave 3 Task 5 extended the rp-wk-ev-- kinds with --group/--done/--cancelled + rp-wk-ev-top,
     rp-wk-ev-badge, rp-wk-ev-time--struck and the mobile rp-wkm-card-time/-chip/-sub for the tutor view;
     a later fix-wave added the live/«скоро» treatment — rp-wk-ev--live (desktop tint),
     rp-wkm-card--live/-hit/-actions/-action(--primary/--outline)/-chip--success (mobile border + chip +
     «Войти в занятие»/«Перенести» action row)),
   rp-les* (Task 8 — /lesson/{id} entity page: details/homework/summary cards + cancel dialog),
   rp-hwh* (Task 9 — /homework assignments hub: tabs spacing + section labels),
   rp-hws* (Task 10 — /homework/block/{id} focus-mode submission page: header/autosave indicator,
     answer + feedback cards, file tokens, quiz mini-layout, sticky mobile CTA).
   rp-mycrs* (Task 12 — /my-courses enrolled-only grid + shop footnote; the card itself is rp-crs*).
   rp-quiz* (Task 11 — /tests/take/{id} focus-mode test page: header/progress/question/options/nav +
     the result screen's score ring, ScoreRing.razor's .rp-quiz-ring).
   rp-plr* (Task 13 — /my-courses/{id} desktop two-pane player: structure aside + inline lesson panel,
     incl. AudioPlayerPill's rp-plr-audio* — the audio pill has no separate prefix of its own).
   rp-shome* (Task 14 — /home/student grid + shared card-head/link), rp-nlc* (next-lesson card),
   rp-crw* (course-resume widget), rp-bal-warning (low-balance strip on the RpBalanceWidget full card).
   rp-phome* (wave 6 Task 3 — /home/parent, Главная родителя.dc.html: the 2-col child-card grid
     rp-phome-grid/-card, card head rp-phome-head/-head-text/-name/-tenant + the shared initials avatar
     rp-phome-avatar(--warm alternating child tint, --sm week-row size), the next-lesson box
     rp-phome-next/-next-ico/-next-body/-next-title/-next-when/-next-none/-next-link, the balance box
     rp-phome-bal(--warn zero-balance tone)/-bal-body/-bal-label/-bal-num + the «Пополнить» CTA
     rp-phome-topup(--primary filled at zero), the tasks block rp-phome-tasks (head reuses
     rp-shome-card-head/-label/-link), the desktop-only week card rp-phome-week/-week-list/-week-row/
     -week-when/-week-body/-week-title/-week-child/-week-none, and the no-children rp-phome-empty).
   rp-chw* (wave 6 Task 4 — /children-homework, Задания детей.dc.html: the per-child filter chips
     rp-chw-filters/-chip(--active)/-chip-av(--warm — the 20px initials circle, hidden ≤640px per
     LOCKED-12; one markup) and the status sections rp-chw-sec/-sec-head/-label + the section-tone
     counter badge rp-chw-count(--danger, --info, --success); the rows themselves are rp-asg*, which
     gained the optional child-initials rp-asg-avatar(--warm) rendered on both viewports; wave 6
     Task 6 added the parent read-only submission view chrome rp-chw-sub/-sub-back/-sub-badge —
     the engine cards inside are HomeworkSubmissionDetail's own).
   rp-pbadge* (wave 6 Task 5 — ParentModeBadge, Режим родителя.dc.html, П-14: the inline read-only pill
     rp-pbadge-pill next to the /my-lessons title, the full-width strip rp-pbadge-banner(-banner-text)
     above /lesson/{id} content, and the LOCKED-10 info card rp-pbadge-info/-info-ico/-info-text).
   rp-th* (wave 3 Task 4 — /home/tutor: greeting head/actions, the desktop 1.6fr/1fr grid (today,
     grading queue, new-request, low-balance, week-stats cards) and the mobile hero/compact/link-card
     stream — see this component's own doc comment for the desktop/mobile split rationale).
   rp-sched* (wave 3 Task 5 — /schedule tutor page: the toolbar (title + «+ Занятие»/«+ Слот»),
     the nav row (‹ › + range + «Сегодня» + Неделя/День segment + legend), the desktop «День» single-day
     list wrapper, and the two Bb dialogs' bodies — details (rp-sched-dlg*) + conduct (rp-sched-conduct*)).
   rp-cld*, rp-psd* (wave 3 Task 6 — the /schedule create-lesson dialog (rp-cld*: head/close, segment,
     student picker/list, weekly-repeat switch, balance strip, «Дополнительно» collapse, submit — reused
     by the publish-slots dialog for the shared form chrome) and the publish-slots dialog extras (rp-psd*:
     hint + weekday multiselect)).
   rp-chat* (Task 3, wave 2 — /chat INBOX pane: head/search/tabs/groups/rows/avatars/foot +
     the desktop no-room-selected placeholder), rp-chat-shell (the two-pane/two-screen page shell,
     Task 4 — was chat.css's .chat-shell), rp-convo* (Task 4 — conversation pane: head/kebab/
     search-nav/body/day-separators, was chat.css's .convo-*), rp-msg* (Task 4 — message row/
     bubble/receipt/actions/attachments/delete, was chat.css's .msg-*), rp-composer*
     (Task 4 — composer wrap/field/attach/send/preview/help/disabled-notice, was chat.css's
     .composer-*). chat.css is DELETED — every legacy class above has an rp-* successor.
   rp-anncmp* (Task 5, wave 2, ОВ-2а — announcement compose: the ChatInbox header «Объявление»
     trigger button + the AnnouncementComposeDialog BbDialog content — head/grabber/labels/
     input/textarea/validation/audience-preview/rate-limit/actions — and its ≤600px bottom-sheet
     variant; the standalone /announcements page is gone, replaced by this dialog + a transitional
     redirect, RedirectMap.cs).
   rp-annh* (Task 6, wave 2 — ChatInbox's manager-only «Объявления» tab: AnnouncementHistoryList's
     head/card/preview/chip/audience/revoke), rp-msg-annmeta* (Task 6 — the tutor's per-message
     read/audience/revoke meta line, replacing rp-msg-receipt on the tutor's own announcement
     bubble), rp-convo-newann (Task 6 — the announcement conversation header's «Новое объявление»
     button, tutor-only; rp-convo-chip/rp-composer-disabled are REUSED as-is for the tutor's
     audience chip and daily-budget footer, no new classes needed there).
   rp-notif* (Task 7, wave 2 — /settings/notifications restyle: push status card + the
     Событие/Чат/Email/Push matrix, collapsing to a card-per-event ≤600px; the Email/Push pill
     switch itself is NotifChannelSwitch.razor's .rp-notif-switch, not BbSwitch — see that
     component's doc comment).
   rp-menu (blueprint-pitfalls.md П-20 follow-up — shared BbDropdownMenuContent/Item/Separator
     skin for ALL FIVE dropdown consumers: TopBarUserMenu, TopBarScheduleWidget, TopBarChatButton,
     TopBarRoleSwitcher, ChatConversation's kebab; rp-tbw-chat-menu is a width:320px modifier for
     the messages dropdown only, combined with rp-menu, not folded into it).
   rp-stu* (wave 3 Task 7 — /students hub: the toolbar (title + «+ Пригласить»), the Ученики-tab
     filters (search + status select), the desktop roster table (rp-stu-table/-thead/-row/-user/
     -avatar/-name/-bal(--danger/--warning/--success)/-muted/-chev/-rowact) + its ≤640px card view
     (rp-stu-cards/-card/-card-main/-card-name/-card-sub), the pending-row inline actions
     (rp-stu-pending-actions/-pact(--accept/--decline)), the Группы-tab card grid (rp-stu-groups/
     -gcard/-gcard-head/-gcard-dot/-gcard-name/-gcard-meta/-gedit/-gnew) + paid-plan upsell
     (rp-stu-upsell), the Приглашения-tab list (rp-stu-inv/-inv-row/-inv-icon/-inv-main/-inv-email/
     -inv-meta/-inv-act(--danger)/-inv-foot), and shared bits (rp-stu-panel, rp-stu-field, rp-stu-err,
     rp-stu-hint, rp-stu-check, rp-stu-members/-member/-member-remove, rp-stu-addrow, rp-stu-schedlink).
     Dialog CHROME is REUSED from rp-sched-dlg* (title/sub/label/input/actions/btn) — the same generic
     Bb-dialog primitives SchedulePage's confirm uses; only students-specific layout gets rp-stu-*.)
   rp-scard* (wave 3 Task 8 — /students/{id} student card page (Карточка ученика.dc.html): the
     breadcrumb (rp-scard-crumb/-link/-sep/-cur), the avatar+name+status+actions header
     (rp-scard-head/-avatar/-head-main/-name-row/-name/-sub/-actions, action buttons rp-scard-btn
     with --primary/--ghost), the 1.5fr/1fr desktop grid (rp-scard-grid/-col) of section cards
     (rp-scard-card(--pad)/-card-head/-card-title(--inline)/-card-spacer/-card-foot/-card-link(--danger)),
     the balance card body (rp-scard-topup, rp-scard-bal-row/-bal-num/-bal-cap, rp-scard-hist wrapping
     the reused rp-balhist* rows), the lesson rows (rp-scard-lesson/-lesson-when/-lesson-day/-lesson-time/
     -lesson-topic), the course rows (rp-scard-crs/-crs-top/-crs-name/-crs-count/-crs-foot + the progress
     bar rp-scard-prog/-prog-fill), the works rows (rp-scard-work/-work-main/-work-title/-work-kind), the
     parent rows (rp-scard-parent/-parent-avatar/-parent-main/-parent-name/-parent-email), the muted
     footnote rp-scard-note, the small per-card empty text rp-scard-empty, the «Опасная зона» archive
     footer (rp-scard-danger/-danger-text/-danger-title/-danger-sub/-danger-btn), the loading wrap
     rp-scard-loading, and the «Начислить» dialog body (rp-scard-dlg/-dlg-head/-dlg-title/-dlg-spacer/
     -dlg-x/-dlg-sub/-dlg-fields/-dlg-field/-dlg-preview/-dlg-preview-label/-dlg-preview-val); field/
     label/input/actions/btn chrome is REUSED from rp-sched-dlg*.)
   rp-gq* (wave 3 Task 9 — /grading queue, Домашние задания.dc.html top screen): the toolbar
     (rp-gq-toolbar/-toolbar-spacer, the pill tabs rp-gq-tab(--active), the two BbDropdownMenu filter
     triggers rp-gq-filter — dropdown content itself reuses the shared rp-menu skin), the desktop list
     (rp-gq-list/-row/-avatar/-body/-title/-student/-task/-sub/-files/-age(--warn)/-chev), and the
     ≤768px card stream (rp-gq-mhead/-mtitle/-mbadge/-mtabs/-mtab(--active)/-mempty/-mcard/-mcard-top/
     -mcard-body/-mcard-name/-mcard-task/-mcard-btn) toggled by the same shell breakpoint as rp-th-*.
   rp-grev* (wave 3 Task 10 — /grading/{SubmissionId} review page, Домашние задания.dc.html bottom
     screen): the loading wrap rp-grev-loading, the header (rp-grev-head/-head-spacer, breadcrumb
     rp-grev-crumb/-crumb-link/-crumb-sep/-crumb-cur, the queue position rp-grev-pos + the ‹ › nav
     rp-grev-nav/-navbtn(--disabled)), the 1.5fr/1fr desktop grid (rp-grev-grid/-col), the section cards
     (rp-grev-card(--muted/--pad)/-card-label/-card-title, the muted note rp-grev-muted), the answer card
     (rp-grev-answer-head/-answer-spacer/-answer-text, the «K-я попытка» chip rp-grev-attempt, file chips
     rp-grev-files/-file/-file-name/-file-size, the autotest review rp-grev-score/-quiz-q/-quiz-prompt/
     -quiz-answer/-quiz-correct), the previous-review text rp-grev-prev-text, the decision card
     (the conflict banner rp-grev-conflict, the graded verdict rp-grev-verdict(--success/--warning/
     --danger)/-verdict-label/-verdict-text, the auto-take-in-flight hint rp-grev-hint (pairs with
     rp-grev-muted), the editable form rp-grev-field-label/-textarea/-actions,
     the buttons rp-grev-btn(--accept/--outline) + the destructive text-link rp-grev-reject), and the
     student mini-card (rp-grev-stats/-cardlink); the reject-confirm dialog reuses rp-sched-dlg*.
   rp-tm* (wave 3 Task 11 — /tests gradebook, Тесты.dc.html): the toolbar (rp-tm-toolbar/-toolbar-spacer/
     -filters/-filter/-inactive, buttons rp-tm-btn(--primary/--ghost)), the TRANSPOSED sticky-corner
     matrix (rp-tm-wrap/-tm, sticky rp-tm-corner + rp-tm-rowhead, columns rp-tm-colhead(--inactive)/
     -colhead-inner/-colhead-main/-colhead-name/-colhead-meta, the kebab rp-tm-kebab, the badge
     rp-tm-badge(--muted), the student cell rp-tm-student/-student-name/-avatar, cells rp-tm-cell +
     the state chips rp-tm-chip(--passed/--failed/--scored/--assigned) + rp-tm-assigned/-dash, the footer
     rp-tm-hint), the ≤768px card view (rp-tm-cards/-card(--inactive)/-card-head/-card-name/-card-meta/
     -card-chips/-card-empty), the create dialog (rp-tm-dlg/-dlg-title/-dlg-sub/-dlg-field/-dlg-label/
     -dlg-input/-dlg-thr/-dlg-thr-unit/-dlg-help/-dlg-switchrow/-dlg-switchtext/-dlg-actions/-dlg-spacer,
     the pill switch rp-tm-sw(--on)/-sw-thumb, errors rp-tm-err), and the cell-results popup body
     (rp-tm-res-head/-res-list/-res-row/-res-date). The assign/results/AI dialogs keep the MudDialog shell
     but reuse rp-sched-dlg* for their Blueprint-styled bodies.
   rp-crsl* (wave 4 Task 3 — /courses list, Курсы.dc.html): the toolbar (rp-crsl-toolbar/-toolbar-spacer,
     the primary button rp-crsl-btn(--primary) with its responsive rp-crsl-btn-full/-btn-compact text
     swap ≤768px), the filter chips (rp-crsl-filters/-chip(--active), client-side Все/Черновики/Архив —
     no server round-trip), the card grid (rp-crsl-grid, cards rp-crsl-card(--archived) linking straight
     to the overview /courses/{Id}, cover rp-crsl-cover, body rp-crsl-body/-name/-meta/-row/-students/
     -spacer/-price), the footer note rp-crsl-info, an empty state (RpEmpty, shared — no new classes),
     and the CreateCourseDialog body (rp-crsl-dlg/-dlg-head/-dlg-title/-dlg-spacer/-dlg-close/-dlg-optional/
     -dlg-textarea/-dlg-note/-dlg-submit, field wrapper rp-crsl-field, errors rp-crsl-err/-err-banner);
     label/input chrome is REUSED from rp-sched-dlg*.
   rp-ted* (wave 3 Task 11 — /tests/{Id} editor): the header (rp-ted-head/-head-spacer, breadcrumb
     rp-ted-crumb/-crumb-link/-crumb-sep/-crumb-cur, autosave rp-ted-status(--ok/--pending/--warn),
     buttons rp-ted-btn(--primary)), the 1.5fr/1fr grid (rp-ted-grid), the questions column
     (rp-ted-questions, fields rp-ted-field/-label/-input, the inline alert rp-ted-alert, question cards
     rp-ted-qcard/-qhead/-qnum/-qtype/-qspacer/-qdel/-qtext, options rp-ted-opt/-opt-mark(--on/--radio)/
     -opt-del, add buttons rp-ted-addopt/-addq/-ai), the right column (rp-ted-side, cards
     rp-ted-card/-card-title/-card-spacer/-card-count, the threshold rp-ted-thr/-thr-unit, the display row
     rp-ted-prow/-prow-key/-prow-val, switch rows rp-ted-switchrow/-switchtext reusing rp-tm-sw, the
     assignments list rp-ted-batch/-batch-aud/-batch-meta/-reslabel/-resrow/-resname, empty rp-ted-empty).
     Reuses rp-tm-avatar/-tm-chip for result rows and rp-tm-badge for the «новым ученикам» crumb badge.
   rp-covw* (wave 4 Task 4 — /courses/{Id} course overview, Обзор курса.dc.html — the П-7 product hub):
     the loading wrap rp-covw-loading, the page wrap rp-covw, the breadcrumb (rp-covw-crumb/-crumb-link/
     -crumb-back(≤768 back-arrow)/-crumb-sep/-crumb-cur), the draft banner (rp-covw-banner/-banner-text/
     -banner-btn), the header (rp-covw-head, cover rp-covw-cover(--placeholder), rp-covw-head-main, title
     row rp-covw-title-row/-title, the kebab trigger rp-covw-kebab, description rp-covw-desc, action
     buttons rp-covw-actions/-btn(--primary/--outline)), the card grid rp-covw-grid, the «Продукт» card
     (rp-covw-card/-card-head, rows rp-covw-row(--switch)/-row-label/-row-val(--muted)/-row-edit, the
     section label rp-covw-subhead, module stepper rows rp-covw-mod/-mod-title/-mod-count + the ± buttons
     rp-covw-step, the footer rp-covw-foot, the small empty text rp-covw-empty), and the Bb dialog bodies
     (price + name/description + cover) rp-covw-dlg/-dlg-head/-dlg-title/-dlg-spacer/-dlg-close/-dlg-fields/
     -dlg-textarea/-dlg-hint-inline/-dlg-summary/-dlg-summary-label/-dlg-summary-val/-dlg-note/-dlg-submit,
     field wrapper rp-covw-field, errors rp-covw-err/-err-banner. The confirm dialog reuses rp-sched-dlg*;
     label/input chrome is REUSED from rp-sched-dlg*; the SequentialUnlock toggle reuses NotifChannelSwitch
     (rp-notif-switch); the cover engine is the shared RpImageField. Task 5 extends the same prefix: the
     «Озвучка» card (rp-covw-audio-head/-title, voice chips rp-covw-voice/-voice-label/-voice-chips/
     -voice-chip(--active), the refresh row rp-covw-audio-refresh/-audio-btn/-audio-est, the honest hint
     rp-covw-hint), the «Ученики» card (full-span rp-covw-card--students, header rp-covw-students-head/
     -title/-sub/-enroll-btn, desktop rows rp-covw-students-rows/-student-row/-avatar/-name/-date/-progress(-fill/-pct/
     -none)/-unenroll, mobile compact rp-covw-students-cards/-student-card(-main/-name/-meta) swapped in at
     ≤768px), and the «Записать ученика» dialog (rp-covw-enroll-search(-input)/-list/-row(--disabled)/
     -name/-chip, reusing rp-covw-dlg/-dlg-head* chrome + rp-covw-student-avatar).
   rp-ced* (wave 4 Task 6 — /courses/{Id}/content content-editor shell, Редактор содержания.dc.html, on
     ReaderLayout/no-shell): the full-screen column rp-ced/-loading, the header (rp-ced-head/-head-spacer,
     breadcrumb rp-ced-crumb/-crumb-link/-crumb-sep/-crumb-cur, the AI-credits chip rp-ced-credits), the
     body split rp-ced-body, the left tree pane (rp-ced-tree, desktop course header rp-ced-tree-head/
     -course-row/-course-name/-course-meta/-course-counts/-course-actions/-course-btn(--disabled), the
     scroll rp-ced-tree-scroll/-tree-empty, module rows rp-ced-mod/-modrow/-mod-toggle/-mod-title/-mod-meta,
     lesson rows rp-ced-lesson(--active)/-lesson-title/-lesson-meta, the add-lesson affordance
     rp-ced-addlesson, footer rp-ced-tree-foot/-foot-btn(--accent), shared kebab rp-ced-kebab), the canvas
     host (rp-ced-canvas/-canvas-inner/-canvas-context), and the mobile-only pane headers rp-ced-mhead
     (--lesson)/-mhead-back/-mhead-main/-mhead-title/-mhead-sub/-mhead-ai swapped in by [data-mobile-pane]
     at ≤768px. Kebab dropdown bodies reuse rp-menu.
   rp-lc* (wave 4 Task 7 — the LessonCanvas block document inside rp-ced-canvas, Редактор
     содержания.dc.html): the title bar (rp-lc-titlebar/-title/-title-input/-pencil/-ai), the aggregate
     save-status line rp-lc-status, the compact cover slot rp-lc-cover, block cards (rp-lc-block/-block-icon/
     -block-body/-kebab, destructive kebab item rp-lc-danger), and the «+ Блок» affordance (rp-lc-add/
     -addbtn + the in-canvas popover rp-lc-add-backdrop/-add-pop/-add-grid/-add-tile/-add-ai — NOT a Bb
     portal, so П-15 doesn't apply). Block kebab bodies + the «✦ ИИ» dropdown reuse rp-menu. The autotest
     block card body is a collapsed summary rp-lc-atsum/-atsum-title/-atsum-meta/-atsum-chev (opens the
     in-canvas editor). Task 9 adds the «✦ ИИ» menu header rp-lc-ai-menu/-ai-head/-ai-head-bolt/-ai-head-bal/
     -ai-head-top, inline AI drafts rp-lc-block--draft/-draft-badge/-draft-md/-draft-at, and the sticky
     accept/discard bar rp-lc-draftbar/-draftbar-icon/-draftbar-label/-draftbar-discard/-draftbar-accept.
   rp-gen* (wave 4 Task 9 — the AI generation dialogs «Заполнить урок», «Вопросы автотеста», «План курса»,
     reusing rp-covw-dlg head/close chrome): rp-gen-dlg(--wide)/-dlg-title/-dlg-lead/-dlg-hint/-dlg-fields/
     -dlg-label/-dlg-input/-dlg-row/-dlg-col/-dlg-foot/-dlg-bal/-dlg-btn(--ghost)/-dlg-counts, plus the
     outline preview list rp-gen-out-list/-out-mod/-out-modrow/-out-lesrow/-out-del.
   rp-atc*, rp-atf* (wave 4 Task 8 — the autotest editor IN THE CANVAS, Дизайнер курсов.dc.html «канвас:
     автотест»): the canvas chrome rp-atc/-atc-back/-atc-head/-atc-titlewrap/-atc-title/-atc-meta/
     -atc-head-spacer, and the AutoTestForm's compact settings row rp-atf-settings/-atf-set/-atf-set-label/
     -atf-thr/-atf-thr-unit + the correct-option tag rp-atf-correct-tag/-atf-ansdot, plus the «Описание
     задания» disclosure rp-atf-desc/-desc-toggle/-desc-label/-desc-excerpt/-desc-text (Task 8 fix-wave —
     PromptMarkdown is student-visible + AI-filled, so it needed an editable affordance after all). Question
     cards, options, add buttons + the AI button REUSE the /tests editor's rp-ted-* (qcard/qhead/qnum/qtype/
     qspacer/qdel/qtext/opt/opt-mark/opt-del/addopt/addq/ai/input/alert/status/btn) and the pill switch rp-tm-sw.
   rp-frm* (Формула-мини-волна Task 3 — the `formula` block editor rendered INLINE in its rp-lc-block card,
     Дизайнер курсов.dc.html «формула»): the container rp-frm, monospace textarea rp-frm-input, char counter
     rp-frm-count(--over past 5000), the KaTeX preview wrapper rp-frm-preview (centers the live-typed preview,
     min-height keeps it from collapsing while empty — the rendered .rp-formula[data-latex] node's own card
     chrome is defined separately, see .rp-formula below), and the footer rp-frm-foot/-frm-error/-frm-spacer
     holding the explicit Save button (REUSES rp-ted-btn/-btn--primary + rp-spin from the tests-editor/
     submit-button patterns).
   .rp-formula (Формула-мини-волна Task 4 — the KaTeX display card, katex-render.js's `data-latex` render
     target): centered flex, padding, overflow-x auto for wide formulas, bordered card on var(--card)/
     var(--border). ONE class shared by every surface that shows a rendered formula: the tutor's live
     editor preview (Task 3, nested inside rp-frm-preview above), the student /content page + course
     player (LessonContentBody, wrapped in the usual rp-plr-block spacer), and the /read fullscreen reader
     (ReaderDocument, bare inside its own rp-reader-block — reader.css re-tints background/border per
     reading theme). KaTeX itself renders formula text in currentColor, so no extra color rule is needed
     for contrast across the three reading schemes.
   rp-set* (wave 5 Task 7 — /settings hub tabs, Настройки.dc.html, П-20: the 600px form column rp-set,
     the intro row rp-set-introrow + intro paragraph rp-set-intro + the framed «Открыть мой сайт» link
     rp-set-sitelink, the form card rp-set-card, the switch row rp-set-switchrow(--dim)/-switch(-thumb)/
     -switchtext/-switch-label/-switch-cap — a bespoke 38×22 pill switch, П-9, no BbSwitch/prior preset
     matches the mockup size — the two-column field grid rp-set-grid2 (collapses to one column ≤640px),
     the field rp-set-field(--dim/--minage)/-label/-input/-hint, and the inline error rp-set-err;
     the Save button REUSES rp-btn-submit). Shared by SignupPolicyPanel/CancellationPolicyPanel/
     RoomDefaultsSettings (hosted by VideoPanel). Wave 5 Task 8 adds the «ИИ-функции» + «Площадка» tabs:
     the AI narration card rp-set-aicard + the voice field rp-set-field--voice, the informational
     generation card rp-set-infocard/-infocard-text/-infocard-title/-infocard-cap/-infocard-chip; the
     read-only tenant card rp-set-tenantcard/-tenant-name/-tenant-host; and the destructive close-tenant
     zone rp-set-danger (--destructive-tinted border) + -danger-title (--destructive heading) +
     -danger-warn/-danger-warn-title/-danger-list/-danger-note (the consequences warn block, border and
     background color-mixed with --destructive) + -danger-lead/-danger-row/-danger-field/-danger-fullfield/
     -danger-actions, plus the destructive buttons rp-btn-danger (filled) + rp-btn-danger-outline (outline)
     and the plain link-button rp-btn-textlink used for «Отправить код повторно».
   rp-site* (wave 5 Task 9 — «Мой сайт» hub §Оформление, Мой сайт.dc.html: SitePage top-action links
     rp-site-topbtn(--primary); the appearance tab's 300px/1fr grid rp-site (preview left-column-first
     on mobile via order), rp-site-loading, the controls column rp-site-controls + rp-site-group-title +
     the HEX field wrapper rp-site-hexfield + save button rp-site-save (reuses rp-btn-submit), the template
     cards rp-site-templates/-tpl(--active)/-tpl-thumb/-tpl-bar/-tpl-sub/-tpl-text/-tpl-name/-tpl-desc, the
     colour presets rp-site-colors/-color(--active), and the preview column rp-site-preview/-preview-head/
     -preview-eyebrow/-preview-host/-preview-note + rp-site-spacer. The LIVE PREVIEW itself (SiteLivePreview)
     uses rp-site-pv* — its palette is HARDCODED public-landing colours (#fff/#1c1a17/#6f6a61/#8a857c/
     #faf9f7/#eceae6), deliberately NOT cabinet tokens: rp-site-pv/-pv-head/-pv-logo(-img)/-pv-name/-pv-spacer/
     -pv-menu/-pv-hcta/-pv-hero/-pv-hero-text/-pv-hero-cta/-pv-htitle/-pv-hsub/-pv-photo/-pv-stats/-pv-stat/
     -pv-stat-num/-pv-stat-lbl/-pv-price/-pv-price-name/-pv-price-src/-pv-price-buy. Accent colour +
     template geometry are applied inline by the component, so these classes carry only structure/palette.)
   rp-land* (wave 5 Task 10 — the shared landing-block surface + edit dialog, Мой сайт.dc.html §Содержание +
     Онбординг.dc.html §Превью, both driving LandingPreviewSurface/LandingBlockEditDialog: the intro copy
     rp-land-intro; each block card rp-land-block(--off dims a hidden block), its chrome header row
     rp-land-chrome + the 34px accentSoft icon rp-land-ico (accent applied inline), rp-land-meta/-titlerow/
     -name/-hint, the status pills rp-land-badge(--auto = «заполняется сам» accent, --empty = «не заполнен»
     warning-muted) each carrying a -badge-full (desktop) + -badge-short (≤640 «сам»/«пусто») text span, the
     visible outline rp-land-edit button + the hand-rolled 36×21 rp-land-toggle(-thumb)(--on = primary, П-9
     no BbSwitch preset) + the BbDropdownMenu kebab rp-land-kebab (content reuses rp-menu), and rp-land-preview
     wrapping the schematic Preview/* (hidden ≤640 — chrome only on mobile). The edit dialog reuses BbDialog/
     BbDialogContent (own header/close, ShowClose=false П-8): rp-land-dlg(-handle mobile pill/-head/-title/
     -spacer/-close/-desc/-hint/-platform/-body), the rp-land-dlg-actions row (-tpl «Вставить шаблон»/-cancel/
     -save), and a ≤640 bottom-sheet override (pinned bottom, rounded top, handle shown, П-14 transform+translate
     reset, П-15 nav-clearance padding-bottom).)
   rp-site-dom* (wave 5 Task 11 — «Мой сайт» hub §Домен, Мой сайт.dc.html: the narrow column rp-site-dom +
     intro copy rp-site-dom-intro, each domain card rp-site-dom-card(--primary for the read-only platform
     subdomain row: rp-site-dom-primary-text/-primary-label/-primary-value), the host/status header row
     rp-site-dom-headrow + rp-site-dom-host, the status pill rp-site-dom-badge(--success/--warning) with a
     -badge-full (desktop) + -badge-short (≤640 «Ожидает») text span, the TXT/DNS copy rp-site-dom-step
     («Шаг N») + the muted mono code block rp-site-dom-code (label spans -code-label-full «Имя:»/«Значение:»
     vs -code-label-short «TXT:» ≤640) + the desktop-only caption rp-site-dom-note (hidden ≤640 along with
     rp-site-dom-step — the mobile pending card drops both, code block + actions only), the per-row error
     rp-site-dom-error, the action row rp-site-dom-actions (Проверить primary + Удалить outline-neutral-
     border/destructive-text rp-site-dom-btn/-btn--danger — ≤640 becomes a 1fr/1fr 40px grid) + the single-
     button wrapper rp-site-dom-single (verified-domain «Удалить домен», ≤640 full-width/44px), the add-
     domain row rp-site-dom-form/-input/-add with -add-full/-add-short text («Добавить домен»/«Добавить»),
     and the Pro-gate upsell card rp-site-dom-upsell (reuses rp-site-dom-card + the rp-site-topbtn--primary
     CTA link to /finance?tab=subscription — Pro-gate logic unchanged from the MudBlazor-era panel).)
   rp-onb* (wave 5 Task 12 — /onboarding «сайт за минуту», Онбординг.dc.html: the focus-mode page shell
     rp-onb (100vh column on --background) + the sticky screen header rp-onb-header (brand rp-onb-brand/
     -brand-word, phase caption rp-onb-phase, rp-onb-spacer, the brief-only accent credits chip
     rp-onb-credits, the ghost rp-onb-later «Заполню позже»), the scrolling body rp-onb-body; Brief phase
     rp-onb-brief (max-width column) — rp-onb-h1/-lead, the field label rp-onb-field/-label + controls
     rp-onb-textarea/-input/-select, the hint rp-onb-hint (link via var(--primary)), the two-column grid
     rp-onb-grid, the «Оформление» section rp-onb-section/-section-title/-logo-row, the footer rp-onb-actions
     with rp-onb-btn (--primary/--ghost/--outline, -btn-spin busy spinner); Generating phase rp-onb-gen/
     -spark (64px accent circle, @keyframes rp-onb-pulse)/-gen-title/-gen-sub + the skeleton stack
     rp-onb-skeletons/-skel (cascade animation-delay); Preview phase rp-onb-preview — the accent clarify
     panel rp-onb-clarify/-clarify-q/-clarify-row/-clarify-input, the rp-onb-explain caption, and the
     rp-onb-warn all-disabled notice (footer reuses rp-onb-actions/-btn; the block cards are
     LandingPreviewSurface's own rp-land-* chrome, T10).)
   rp-prof* (wave 6 Task 7 — /profile, Профиль.dc.html, П-10 «только личное»: the centered 640px
     column rp-prof, the section cards rp-prof-card/-card-title, the avatar row wrapper rp-prof-avatar
     (centers RpImageUpload ≤600px per the mobile mockup), the neutral outline button rp-prof-btn
     («Сменить пароль»/«Запросить архив»), the muted card text rp-prof-text, the info-muted plate
     rp-prof-hint/-hint-ico/-hint-text (BOTH the manager «Ищете настройки площадки…» pointer between
     the cards and, with the --flow modifier, the owner closure-first plate inside the delete zone),
     the «Аккаунт» action rows rp-prof-row/-row-main/-row-title(--danger)/-row-sub, the delete zone
     rp-prof-del/-del-lead, the destructive consent checkbox rp-prof-check, and the second warn heading
     spacer rp-prof-warn-title2; the 152-ФЗ consequences block, code field and destructive buttons
     REUSE rp-set-danger-warn/-warn-title/-list + rp-set-field/-label/-input/-err/-danger-lead/
     -danger-fullfield/-danger-actions + rp-btn-danger, rp-btn-danger-outline, rp-btn-textlink,
     rp-btn-submit).
   rp-rchat* (wave 7 Task 2 — RoomChatPanel, the /room/{LessonId} «Чат занятия» compact panel,
     Видеокомната.dc.html chat block: the column shell rp-rchat (card bg/border/radius-lg), head
     rp-rchat-head/-head-title, the scroll list rp-rchat-list (flex-column, gap 10px) + its loading/
     empty state rp-rchat-empty, message rows rp-rchat-msg(--mine)/-msg-meta, bubbles rp-rchat-bubble
     (--mine accent-filled, --removed dashed-muted tombstone), and the composer row rp-rchat-composer/
     -input/-send. Deliberately its own compact prefix, not a reuse of rp-msg*, rp-composer* — no
     avatars, receipts, attachments, or Markdown here, just author+time+text).
   rp-rtool* (wave 7 Task 3 — RoomToolRail, the board tool palette extracted out of WhiteboardSurface
     (Видеокомната.dc.html left rail): the shell rp-rtool (52px vertical column, card bg/border/
     radius-lg — default desktop/phone-landscape orientation) + its rp-rtool--row modifier (horizontal
     row for mobile/tablet, RoomPage T4 picks which), 36px square rp-rtool-btn(--active accent fill for
     the selected pen/eraser tool, :disabled dimmed while !CanDraw), the divider rp-rtool-sep (26px
     horizontal line in the column, 22px vertical bar via rp-rtool--row), and the 24px round swatches
     rp-rtool-color(--active primary ring) — the 6 stroke hex values stay inline `style="background:"`
     (LOCKED-1: sync between peers, never a CSS token). WhiteboardSurface keeps only wb-surface/
     wb-canvas — the old wb-toolbar/wb-color(-active)/wb-clear/wb-restore in app.css were Mud-era DEAD
     code, removed in the wave 7 Task 6 legacy-CSS sweep.
   rp-room* (wave 7 Task 4 — RoomPage /room/{LessonId} chrome rebuild, Видеокомната.dc.html): the
     full-screen shell rp-room (unchanged legacy flex-column base in app.css, still correct for the new
     chrome); rp-room-top (bar: rp-room-top-title/-name/-sub, rp-room-top-spacer, rp-room-top-scene —
     desktop-only slot for the shared scene-controls fragment, rp-room-top-users); rp-room-main (CSS
     Grid on desktop — 52px rail / 1fr square / 280–360px side columns; flex-column with `order` on
     mobile, see below); rp-room-square (the aspect-ratio:1/1 stage cell — HIGHER SPECIFICITY than the
     legacy `.rp-room-square` in app.css via the `.rp-room .rp-room-square` compound selector below, since
     app.css loads AFTER bp.css and the legacy 100cqmin rule would otherwise win the cascade and collapse
     it to 0×0 with no `.rp-room-stage` container-type ancestor left; `container-type:size` now lives
     directly on this rule so the moved rp-room-slide-* cqmin styles keep working), rp-room-overlay(--floor)
     (reconnecting/floor-granted pills, absolute-centered, LOCKED-12), rp-room-scenerow (mobile-only
     duplicate render position of the SAME scene-controls RenderFragment RoomPage builds once — safe to
     render twice since the fragment is stateless UI, unlike RoomChatPanel), rp-room-scenegroup/
     -scenetab-lbl (reuses rp-seg/-seg-tab for the board/slides segment + rp-chip--neutral for the
     student's read-only stage badge), rp-room-slidenav/-slidenav-btn/-slidenav-toggle (the «‹ Слайд N /
     M ›» control: arrows page, the toggle button opens the picker — counter reuses rp-room-slide-counter,
     T5, moved to bp.css from app.css in the Task 6 legacy sweep); rp-room-side (desktop:
     flex-column grid item grouping tiles/hand/chat; mobile: same flex-column, just re-ordered via `order`
     against its main-grid siblings) with rp-room-tiles (2-col grid desktop / horizontal-scroll row
     mobile) — ALL participants incl. self last (LOCKED-7): rp-room-tile(--speaking)/-tile-avatar/
     -tile-name/-tile-micoff/-tile-hand, and the tutor-only hover actions rp-room-tile-actions/-tile-act
     (--primary)/-tile-mute (LOCKED-3: "Дать маркер"/"Забрать" + mute, only on a REMOTE tile); rp-room-hand
     (the single raised-hand banner, replaces the old multi-row rp-room-hands queue — only the FIRST
     raiser shows, "+N ещё")/-hand-text/-hand-btn (reuses rp-btn-submit); rp-room-chathost (the ONE
     RoomChatPanel host — desktop: column via CSS; mobile: `position:absolute` bottom sheet anchored to the
     SAME below-stage baseline as the backdrop (top: 100vw-based, re-review fix — a vh-based height let the
     opaque sheet climb over the stage on short viewports) — LOCKED: never
     two instances) + rp-room-chat-close(-wrap, CSS-hidden on desktop); rp-room-sheetbackdrop (mobile/
     tablet-portrait only, click-to-close, gated by `_isNarrow` in C# so a mid-session resize past the
     breakpoint can't strand it; its mobile-media `top` is pushed below the top bar + square stage —
     review fix, see the portrait block); the
     audio-hosts block is unchanged legacy CSS (no new rules); rp-room-bar(-spacer/-btn(--off)/-lbl/-hand
     (--active)/-chat(-dot)/-leave) — labeled pill buttons on desktop, circular icon-only + a mobile-only
     chat FAB on narrow/short viewports; rp-room-state(-card/-title/-body/-actions) — the unsupported/join-error full-page
     cards (reuses rp-btn-submit + rp-prof-btn for "Обновить"). `_isNarrow` (IBrowserViewportObserver,
     mirrors Calendar.razor) is the ONLY C#-driven responsive signal on this page — it exists solely
     because RoomChatPanel's IsVisible contract and RoomToolRail's Horizontal genuinely need to know the
     breakpoint; every other desktop/mobile difference below is pure CSS. Mobile/tablet-portrait
     breakpoint widened to <960px in wave 7 Task 6 (see the portrait block below; `max-width:959.98px`,
     the .02px Sm|Md-boundary split, fix round 2 Minor-4) — no longer the shell's flat 768px (П-16); the
     phone/narrow-landscape block near the end of this file is gated on the SAME width bracket (T6
     re-review, Defect 2 — was height-only, see that block's header comment) so the two together cover
     the whole `_isNarrow == true` range regardless of orientation.
   rp-room-picker* (wave 7 Task 5 — the slide picker popup/sheet, Видеокомната.dc.html): desktop —
     rp-room-picker is an absolute popover anchored under the desktop-position slidenav (position:relative
     scoped to `.rp-room-top-scene .rp-room-slidenav` only, so the mobile-position duplicate stays static
     and lets the sheet override below resolve against `.rp-room` instead, same containing-block trick
     rp-room-chathost relies on) — rp-room-picker-head/-title (honest-data: "Слайды · {M}", no deck name —
     Slide carries none)/-changedeck ("Сменить колоду…", tutor-only by construction since the whole picker
     only ever renders for the tutor) and the 4-col rp-room-picker-grid/-num(--active ring). Closed by
     rp-room-pickerbackdrop, a transparent fixed click-catcher (desktop only has no equivalent to
     RoomChatPanel's always-a-static-column, so unlike chat this needed its own outside-click layer) —
     hidden for the whole `max-width:959.98px` narrow range (T6 re-review, Defect 2 — was a stale `768px`).
     Mobile/tablet-portrait (`_isNarrow` in C#) swaps the SAME rp-room-picker markup to a bottom sheet and
     reuses rp-room-sheetbackdrop verbatim for the dimming (same click-to-close backdrop the chat sheet
     uses) — the shared "100vw + Npx" baseline both sheets anchor to now lives once, as the
     `--room-sheet-top`/`--room-sheet-backdrop-top` custom properties on `.rp-room` inside the portrait
     media query, so neither sheet's magic number is duplicated. `rp-room-picker--overlay` (T6 re-review,
     Defect 1) is a SECOND rendered instance of the same markup (RoomPage.razor's `PickerPanel(overlay:
     true)`), a genuine `.rp-room-side` descendant, hidden (via a compound two-class selector — a flat
     one would lose the cascade to the portrait sheet rule and stack a duplicate sheet, fix round 2
     Important-1) everywhere except the phone/narrow-landscape
     block below where it becomes the true `inset:0`/`border-left` panel (mirrors rp-room-chathost there);
     the block also hides the popover/sheet instance so only one copy is ever interactive. rp-deckpick-*
     (SlideDeckPickerDialog's own BbDialog body, T5): the
     scrollable tree rp-deckpick-tree, course/module labels rp-deckpick-course/-module, the full-width row
     button rp-deckpick-lesson, and the fetch-in-flight rp-deckpick-loading (reuses the global rp-spin,
     recolored for a --popover background same as rp-notif-loading does for --card) — the dialog chrome
     itself (head/title/close, empty state) reuses the generic rp-covw-dlg/-empty shell already shared by
     PackageDialog/CourseHeaderDialog/RefundDialog/… (no new dialog-shell CSS needed).
   rp-room* orientation additions (wave 7 Task 6, Видеокомната.dc.html «Планшет · вертикально» + «Телефон
     · горизонтально»; T6 re-review closed 2 Important review defects, see the phone/narrow-landscape
     block's header comment for the full Defect-2 range-coverage analysis): the mobile-portrait block above
     widened from `max-width:768px` to `(orientation: portrait) and (max-width:959.98px)` — the same cutoff
     `_isNarrow`'s MudBlazor Sm breakpoint uses, so the CSS layout and the C#-driven visibility contracts
     never disagree (closes a real 769–959px gap where `_isNarrow` was already "narrow" but the CSS stayed
     desktop-shaped). Its "desktop-only" companion queries (rp-room-chathost's `flex:1`, rp-room-chat-
     close-wrap's/rp-room-sheetbackdrop's `display: none`, previously `min-width:769px`) became
     `(orientation:landscape), (min-width:960px)` — the TRUE complement — so a tablet-portrait chat sheet
     (769–959.98px) keeps its dimming backdrop (previously silently display:none'd, a real bug the widened
     range would otherwise have re-exposed). Phone/narrow-landscape block (`orientation:landscape` +
     `max-width:959.98px` — re-review widened this from a `max-height:500px`-only gate, Defect 2; fix
     round 2 Important-2 then capped the stage at `min(100%, calc(100vw - 248px))` so near-square
     landscape windows keep a ≥200px side column):
     `.rp-room-main{display:contents}` (blueprint-pitfalls П-25) promotes the rail/rp-room-square/
     rp-room-side to direct grid items of `.rp-room`, alongside its already-sibling rp-room-top/rp-room-bar,
     via a 3×3 grid-template-areas ("rail stage top" / "rail stage side" / "rail stage bar") — rail+stage
     span the full height, top/side/bar stack in the third column exactly like a "right column", with zero
     DOM change (RoomPageRenderTests asserts the nesting this depends on). A `.rp-room-main > .rp-rtool`
     override (2-class specificity beats the 1-class `.rp-rtool--row`) forces the rail back to a vertical
     column regardless of `_isNarrow`/`Horizontal` — the one place this page's C# breakpoint signal and
     its real CSS orientation disagree (`_isNarrow` is width-only), reconciled entirely in CSS per the task
     brief (no new RoomPage logic). Tiles go 16:9 here (LOCKED, was 16:10). Chat — already a genuine
     rp-room-side descendant — gets a true `inset:0`/`border-left` panel (LOCKED); re-review Defect 1 gave
     the slide picker the SAME treatment via its `--overlay` second instance (see rp-room-picker* above)
     instead of leaving it a floating popover, and this block hides the original popover/sheet instance in
     turn. Both lose their dimming backdrop (the stage must never darken, LOCKED) in favour of an explicit
     rp-room-picker-close ✕ (hidden everywhere else).
   rp-adm* (wave 8 Task 3 — admin shell CSS-каркас, Админ-обзор.dc.html): AdminPageHeader's
     rp-adm-head (flex row, h1 + chip + spacer + Actions)/-chip (the "Платформенный админ" warning-muted
     pill)/-head__spacer, plus three generic building blocks hub pages T4–T8 fill in: rp-adm-stats
     (the KPI card grid, 4 cols desktop → 2 ≤640px — T4 re-review aligned this to the rp-fin-* mobile
     cutoff, was 760px), rp-adm-table(-head/-row) (a grid-таблица shell whose column widths come from
     a `--adm-cols` custom property set on a page-specific modifier class, e.g. `.rp-adm-table--tenants`,
     so every hub reuses one table skin instead of a bespoke grid-template-columns each), and
     rp-adm-cards/-card (the ≤640px mobile fallback, same per-hub-modifier pattern).
     T4 (Обзор) additions living in the same block: rp-adm-tile (a stat tile is itself an `<a>` —
     -label/-row/-value/-sub, -sub takes a `--success`/`--muted`/`--danger` tone modifier), rp-adm-alert
     (the email-failures banner-link, -text/-cta), and rp-adm-lists/-list(-empty)/-list__head(-title/-link)/
     -list-row(-avatar/-dot(-active)/-body/-title(-mono)/-sub/-plan/-meta) for the two "Новые тенанты" /
     "Последние ошибки" panels — one shared row skin serves both an avatar+plan-pill tenant row and a
     dot+mono-type error row via the same -body/-title/-sub/-meta slots. rp-adm-lists collapses its
     2-column grid to 1 at ≤640px (the two list cards simply stack — "карточками-стопкой" per the T4
     brief, no per-row card treatment needed since each list is already its own bordered card).
   rp-adm* (wave 8 Task 5 additions — /admin/tenants hub, Тенанты и пользователи.dc.html): rp-adm-panel
     (tab-content spacing) + rp-adm-toolbar/-search(-input)/-toolbar-spacer/-count (the per-tab search
     box + result counter, one skin shared by all three panels; -count hides ≤640px, -search drops its
     340px cap ≤640px — the mockup's mobile toolbar is search-only). rp-adm-table gains three per-hub
     `--adm-cols` modifiers (rp-adm-table--tenants/-users/-students) plus generic cell content classes
     reused across them: rp-adm-cell-stack (two-line title+sub, e.g. tenant name + slug domain)/-main/
     -sub/-mono/-right/-user (avatar+name), rp-adm-avatar (round initials chip), rp-adm-rolechips
     (wrapping RpStatusChip row). rp-adm-rowact/-kebab is the row action cell — a BbDropdownMenu trigger
     button styled like rp-tm-kebab (kept as its own class rather than cross-referencing the tests-matrix
     page's prefix). rp-adm-more is the "Показать ещё" pagination button below a table/card list.
     rp-adm-card gains -top/-title/-sub for the ≤640px card body (title + wrapping chips row, then a
     muted meta line) and rp-adm-balance(--zero) for the lessons-remaining figure (zero tints
     destructive-muted, matching the mockup's balColor rule). rp-adm-accordion(-summary(-count)/-body)
     is a native details disclosure (no JS) for the «Ученики» tab's secondary «Приглашения» section;
     rp-adm-invtable(-head/-row) is its compact 5-column sub-table, collapsing to a stacked block
     ≤640px (its own header hides — the row already labels itself via the email/tenant/kind text).
   rp-adm* (wave 8 Task 6 additions — /admin/finance hub, Подписки и монетизация.dc.html): «Подписки»
     tab reuses rp-adm-stats/-tile verbatim for its 4 KPI tiles (plain non-link divs this time — no
     drill-through target per tile) plus two new tone modifiers rp-adm-tile__value--warning/--danger for
     a single-figure tile with no delta sub-caption (Истекают·7 дней / Просрочено — MRR intentionally
     carries no growth figure, honest-data: GetOverview has no historical MRR to diff against). The
     segment filter is its own pill-row rp-adm-filterbar/-filter(--active) — visually identical to the
     tutor-facing rp-fin-periods/-period(--active) but kept as its own class, same T5 precedent as
     rp-adm-kebab vs rp-tm-kebab. rp-adm-table gains `--adm-cols` modifier rp-adm-table--subs; the
     «Оплачено до» cell's tone follows the row's status via rp-adm-cell-tone--warning/--danger (plain
     rp-adm-cell-sub for the rest). «Планы и монетизация» tab: rp-adm-plans-grid/-plan-card(-head/-name/
     -count) for the 3 plan cards, generic rp-adm-field(-label/-input) form-field pair reused by every
     editable number in the tab (plan price/limit/quota, and the bottom «Настройки ИИ-биллинга» trio),
     rp-adm-plan-chips/-plan-chip for the read-only true-only feature chips, rp-adm-plans-savebar/
     -savebtn/-caption for the plans-only "Сохрань изменения" action (deliberately placed right under the
     plans grid, not at the tab's bottom like the mockup's single button — it only ever dispatches
     UpdatePlanCommand for dirty plans, never touches packs/promos/AI-config, so its position must not
     imply otherwise). rp-adm-section(-head/-title/-sub) + rp-adm-addbtn (mirrors rp-fin-price-addbtn)
     head the packs/promo/AI-billing sections; rp-adm-table gains `--adm-cols` modifiers rp-adm-table--
     packs/-promos, both reusing the T5 kebab (rp-adm-rowact/-kebab) and rp-adm-cell-mono for the promo
     code column. The AI-billing fields wrap in rp-adm-billing-fields (flex-wrap, so 3 fields + a save
     button reflow ≤640px without a bespoke mobile layout). The 36×21 "Активен" toggle (packs/promos rows
     + both create/edit dialogs) is RpAdminSwitch.razor's rp-adm-switch(-thumb) — a hand-rolled control,
     see П-9 note on the component itself; rp-adm-switchrow lays a dialog's own label + switch out as a
     flex row inside one rp-scard-dlg-field cell (the AiCreditPackDialog/PromoCodeDialog Bb rewrites reuse
     rp-scard-dlg* chrome + rp-sched-dlg-label/-input verbatim — no new dialog-chrome classes needed).
   NO Blazor scoped CSS — components cross component boundaries (same rationale as rp-cal-*). */

/* ── 1. Page header (паттерн №1) ─────────────────────────────────────────── */
.rp-ph {
  display: flex;
  align-items: flex-start;
  gap: 16px;
}

.rp-ph-text {
  flex: 1;
  min-width: 0;
}

.rp-ph-eyebrow {
  font-size: 12px;
  color: var(--muted-foreground);
  margin-bottom: 4px;
}

.rp-ph-title {
  font-size: 24px;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin: 0 0 2px;
}

.rp-ph-subtitle {
  font-size: 13.5px;
  color: var(--muted-foreground);
  margin: 0;
}

.rp-ph-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

/* Mobile: actions wrap below the title and go full-width */
@media (max-width: 390px) {
  .rp-ph {
    flex-wrap: wrap;
  }
  .rp-ph-text {
    width: 100%;
  }
  .rp-ph-title {
    font-size: 19px;
  }
  .rp-ph-actions {
    width: 100%;
    flex-shrink: 1;
  }
  .rp-ph-actions > * {
    flex: 1;
  }
}

/* ── 3. Section card (паттерн №3) ────────────────────────────────────────── */
.rp-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  box-shadow: var(--shadow-xs);
}

.rp-card-header {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px 20px;
  border-bottom: 1px solid var(--border);
}

.rp-card-title {
  flex: 1;
  font-size: 15px;
  font-weight: 600;
  margin: 0;
}

.rp-card-header-action {
  display: flex;
  align-items: center;
}

.rp-card-body {
  padding: 20px;
}

/* ── 12. Status chips (паттерн №12) ──────────────────────────────────────── */
.rp-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 12px;
  border-radius: 999px;
  font-size: 12.5px;
  font-weight: 600;
}

.rp-chip-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
}

.rp-chip--info    { background: var(--info-muted);        color: var(--info-muted-foreground); }
.rp-chip--success { background: var(--success-muted);     color: var(--success-muted-foreground); }
.rp-chip--warning { background: var(--warning-muted);     color: var(--warning-muted-foreground); }
.rp-chip--danger  { background: var(--destructive-muted); color: var(--destructive-muted-foreground); }
.rp-chip--neutral { background: var(--secondary);         color: var(--muted-foreground); }

/* ── 9. Context badge (паттерн №9) ───────────────────────────────────────── */
.rp-ctx {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 14px;
  border-radius: var(--radius-md);
  font-size: 13.5px;
  font-weight: 600;
}

.rp-ctx--info    { background: var(--accent);        color: var(--accent-foreground); }
.rp-ctx--warning { background: var(--warning-muted); color: var(--warning-muted-foreground); }

/* ── 8. Empty state (паттерн №8) ─────────────────────────────────────────── */
.rp-empty2 {
  border: 1px dashed var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 40px 24px;
  text-align: center;
}

.rp-empty2-icon {
  width: 56px;
  height: 56px;
  margin: 0 auto 16px;
  border-radius: 16px;
  background: var(--muted);
  color: var(--muted-foreground);
  display: flex;
  align-items: center;
  justify-content: center;
}

.rp-empty2-title {
  font-size: 16px;
  font-weight: 600;
  margin: 0 0 4px;
}

.rp-empty2-desc {
  font-size: 14px;
  color: var(--muted-foreground);
  margin: 0 0 18px;
}

.rp-empty2-action {
  display: flex;
  justify-content: center;
}

/* ── 2. Hub tabs (паттерн №2) ────────────────────────────────────────────── */
/* Desktop: underlined nav strip */
.rp-tabs-underline {
  display: flex;
  gap: 4px;
  padding: 0 20px;
  border-bottom: 1px solid var(--border);
}

.rp-tab {
  padding: 14px 6px;
  margin-right: 14px;
  font-size: 14px;
  font-weight: 500;
  color: var(--muted-foreground);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px; /* sit on top of container border */
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
  transition: color .15s, border-color .15s;
}

.rp-tab--active {
  font-weight: 600;
  color: var(--foreground);
  border-bottom-color: var(--primary);
}

/* Mobile chip row (hidden by default; shown ≤640 px) */
.rp-tabs-chips {
  display: none;
  flex-wrap: nowrap;
  gap: 8px;
  padding: 14px;
  overflow-x: auto;
  border-bottom: 1px solid var(--border);
  scrollbar-width: none; /* Firefox */
  -ms-overflow-style: none; /* IE/Edge */
}

.rp-tabs-chips::-webkit-scrollbar { display: none; }

.rp-tab-chip {
  flex-shrink: 0;
  padding: 7px 14px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 600;
  background: var(--secondary);
  color: var(--secondary-foreground);
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
}

.rp-tab-chip--active {
  background: var(--primary);
  color: var(--primary-foreground);
}

/* Mobile segment control — «icon + short label», full width (hidden by default; shown ≤640 px).
   Used when RpHubTab carries Icon/Short (Финансы.dc.html); grid-template-columns set inline to
   repeat(N,1fr) by the component. */
.rp-tabs-seg {
  display: none;
  gap: 2px;
  margin: 10px 12px 4px;
  padding: 3px;
  background: var(--muted);
  border-radius: var(--radius-lg);
}

.rp-tabs-seg-tab {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 7px 2px 6px;
  border: 0;
  border-radius: var(--radius-md);
  font: inherit;
  font-size: 10.5px;
  font-weight: 500;
  background: transparent;
  color: var(--muted-foreground);
  cursor: pointer;
}

.rp-tabs-seg-tab--active {
  font-weight: 700;
  background: var(--card);
  color: var(--foreground);
  box-shadow: var(--shadow-xs);
}

.rp-tabs-seg-ico {
  width: 17px;
  height: 17px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.rp-tabs-seg-lbl { white-space: nowrap; }

@media (max-width: 640px) {
  .rp-tabs-underline { display: none; }
  .rp-tabs-chips     { display: flex; }
  .rp-tabs-seg       { display: grid; }
}

/* ── 5. Submit button with spinner (паттерн №5) ──────────────────────────── */
@keyframes rp-spin { to { transform: rotate(360deg); } }

.rp-btn-submit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 40px;
  padding: 0 18px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-foreground);
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  min-width: 130px;
}

.rp-btn-submit:disabled {
  opacity: 0.7;
  cursor: not-allowed;
}

.rp-btn-submit--full { width: 100%; }

/* Spinner element inside RpSubmitButton */
.rp-spin {
  display: inline-block;
  flex-shrink: 0;
  width: 15px;
  height: 15px;
  border: 2px solid color-mix(in srgb, var(--primary-foreground) 40%, transparent);
  border-top-color: var(--primary-foreground);
  border-radius: 50%;
  animation: rp-spin .7s linear infinite;
}

/* ── 10. Balance widget (паттерн №10) ────────────────────────────────────── */
/* Compact inline pill */
.rp-bal-compact {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 8px 14px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--card);
}

.rp-bal-icon {
  width: 18px;
  height: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--primary);
}

.rp-bal-num {
  font-size: 14px;
  font-weight: 600;
}

.rp-bal-label {
  font-size: 13px;
  color: var(--muted-foreground);
}

/* Full card */
.rp-bal-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 20px;
  min-width: 220px;
  display: flex;
  flex-direction: column;
}

.rp-bal-card-eyebrow {
  font-size: 12px;
  font-weight: 600;
  color: var(--muted-foreground);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 12px;
}

.rp-bal-card-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 14px;
}

.rp-bal-card-num {
  font-size: 34px;
  font-weight: 700;
  letter-spacing: -0.02em;
}

.rp-bal-card-meta {
  font-size: 14px;
  color: var(--muted-foreground);
}

/* Low-balance warning strip (Home widget only — /pay's own RpBalanceCard has no such state). */
.rp-bal-warning {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-top: 8px;
  font-size: 12.5px;
  color: var(--warning-muted-foreground);
  background: var(--warning-muted);
  border-radius: var(--radius-sm);
  padding: 6px 10px;
}

/* margin-top: auto pins the button to the card's bottom edge (.rp-bal-card is a flex column) so it
   still lines up with a sibling grid card of different height (e.g. RpNextLessonCard). */
.rp-bal-topup {
  width: 100%;
  height: 38px;
  margin-top: auto;
  border: 1.5px solid var(--primary);
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--primary);
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
}

/* Full balance card (RpBalanceCard) — /pay only, distinct from the compact rp-bal-* pill/card above. */
.rp-balcard {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 20px;
}

.rp-balcard-avatar {
  width: 46px;
  height: 46px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 15px;
  font-weight: 700;
  flex-shrink: 0;
}

.rp-balcard-body { flex: 1; min-width: 180px; }
.rp-balcard-name { font-size: 14.5px; font-weight: 600; }

.rp-balcard-policy {
  font-size: 13px;
  color: var(--muted-foreground);
  margin-top: 2px;
}

.rp-balcard-count {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
}

.rp-balcard-num-row {
  display: flex;
  align-items: baseline;
  gap: 6px;
  justify-content: flex-end;
}

.rp-balcard-num {
  font-size: 28px;
  font-weight: 700;
  letter-spacing: -0.02em;
}

.rp-balcard-word {
  font-size: 13.5px;
  color: var(--muted-foreground);
}

.rp-balcard-toggle {
  border: 0;
  background: transparent;
  color: var(--primary);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  padding: 0;
}

.rp-balcard-history {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 6px 20px;
  margin-top: 12px;
}

/* Balance-history rows (RpBalanceHistory) — no outer chrome, composes into rp-balcard-history above. */
.rp-balhist-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 0;
  font-size: 13.5px;
}

.rp-balhist-row + .rp-balhist-row {
  border-top: 1px solid var(--border);
}

.rp-balhist-date { color: var(--muted-foreground); width: 86px; flex-shrink: 0; }
.rp-balhist-desc { flex: 1; }
.rp-balhist-delta { font-weight: 700; color: var(--foreground); }
.rp-balhist-delta--plus { color: var(--success); }

@media (max-width: 640px) {
  .rp-balcard { padding: 16px; gap: 10px 12px; }
  .rp-balcard-avatar { display: none; }
  .rp-balcard-body { order: 2; flex-basis: 100%; }
  .rp-balcard-count {
    order: 1;
    flex: 1;
    flex-direction: row;
    align-items: center;
    gap: 10px;
  }
  .rp-balcard-num-row { justify-content: flex-start; }
  .rp-balcard-toggle { margin-left: auto; }
}

/* ── 4. Table → cards — payments list (паттерн №4 / Оплата.dc.html) ─────── */
.rp-payrow-desktop {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  overflow: hidden;
}

.rp-payrow-head {
  display: grid;
  grid-template-columns: 110px 1fr 110px 110px 90px;
  gap: 12px;
  padding: 10px 20px;
  background: var(--muted);
  font-size: 11.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted-foreground);
}

.rp-payrow {
  display: grid;
  grid-template-columns: 110px 1fr 110px 110px 90px;
  gap: 12px;
  padding: 13px 20px;
  border-top: 1px solid var(--border);
  font-size: 13.5px;
  align-items: center;
}

.rp-payrow-date   { color: var(--muted-foreground); }
.rp-payrow-title  { font-weight: 500; }
.rp-payrow-amount { font-weight: 600; }

.rp-payrow-receipt {
  color: var(--primary);
  font-weight: 500;
  text-decoration: none;
  font-size: 13px;
}

.rp-payrow-receipt--none {
  color: var(--muted-foreground);
}

/* Mobile card-per-row — hidden by default, shown ≤640px (same switch as rp-tabs-underline/chips) */
.rp-payrow-cards {
  display: none;
  flex-direction: column;
  gap: 8px;
}

.rp-payrow-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 13px 14px;
}

.rp-payrow-card-top {
  display: flex;
  align-items: center;
  gap: 8px;
}

.rp-payrow-card-title {
  font-size: 13.5px;
  font-weight: 600;
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.rp-payrow-card-amount {
  font-size: 13.5px;
  font-weight: 700;
  white-space: nowrap;
}

.rp-payrow-card-bottom {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 5px;
}

.rp-payrow-card-date { font-size: 12px; color: var(--muted-foreground); }
.rp-payrow-card-spacer { flex: 1; }

.rp-payrow-card-receipt {
  font-size: 12px;
  color: var(--primary);
  font-weight: 500;
  text-decoration: none;
}

@media (max-width: 640px) {
  .rp-payrow-desktop { display: none; }
  .rp-payrow-cards   { display: flex; }
}

/* ── 11. Product card (паттерн №11) ──────────────────────────────────────── */
.rp-prod-card {
  position: relative;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* Featured variant (FeaturedTag set) — border tints toward --primary, matching the "Выгодно" card. */
.rp-prod-card--featured {
  border-color: color-mix(in srgb, var(--primary) 45%, var(--border));
}

/* Ribbon — absolute top-left, overhangs the card's top border. */
.rp-prod-tag {
  position: absolute;
  top: -9px;
  left: 16px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  background: var(--primary);
  color: var(--primary-foreground);
  border-radius: 999px;
  padding: 2px 9px;
}

.rp-prod-cover {
  height: 120px;
  overflow: hidden;
  background: var(--muted);
  flex-shrink: 0;
}

.rp-prod-cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.rp-prod-body {
  padding: 20px;
  display: flex;
  flex-direction: column;
  flex: 1;
}

.rp-prod-kind {
  align-self: flex-start;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 600;
  background: var(--accent);
  color: var(--accent-foreground);
  margin-bottom: 14px;
}

/* Explicit KindTone overrides the accent default above (e.g. warning for «Курс»). */
.rp-prod-kind--info    { background: var(--info-muted);        color: var(--info-muted-foreground); }
.rp-prod-kind--success { background: var(--success-muted);     color: var(--success-muted-foreground); }
.rp-prod-kind--warning { background: var(--warning-muted);     color: var(--warning-muted-foreground); }
.rp-prod-kind--danger  { background: var(--destructive-muted); color: var(--destructive-muted-foreground); }
.rp-prod-kind--neutral { background: var(--secondary);         color: var(--muted-foreground); }

.rp-prod-name {
  font-size: 17px;
  font-weight: 600;
  margin: 0 0 4px;
}

.rp-prod-desc {
  font-size: 13.5px;
  color: var(--muted-foreground);
  margin: 0 0 16px;
}

.rp-prod-price-row {
  display: flex;
  align-items: baseline;
  gap: 7px;
  margin-bottom: 16px;
}

.rp-prod-price {
  font-size: 24px;
  font-weight: 700;
}

.rp-prod-subprice {
  font-size: 12px;
  color: var(--muted-foreground);
}

.rp-prod-buy {
  margin-top: auto;
  width: 100%;
  height: 42px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-foreground);
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}

/* ── 12. Top-bar widgets (паттерн №12) ───────────────────────────────────── */
/* Shared primitives */
.rp-tbw-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 999px;
  /* Чат.dc.html: primary, not destructive — an unread count isn't an error state. */
  background: var(--primary);
  color: var(--primary-foreground);
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  position: absolute;
  top: -5px;
  right: -5px;
  border: 2px solid var(--card);
}

.rp-tbw-empty {
  padding: 8px 14px;
  font-size: 13px;
  color: var(--muted-foreground);
}

.rp-tbw-overflow {
  padding: 4px 14px 6px;
  font-size: 12px;
  color: var(--muted-foreground);
}

.rp-tbw-row {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.rp-tbw-row__head {
  display: flex;
  align-items: center;
  gap: 6px;
}

.rp-tbw-row__title {
  font-size: 13.5px;
  font-weight: 600;
}

.rp-tbw-row__meta {
  font-size: 12px;
  color: var(--muted-foreground);
}

.rp-tbw-row__meta--clamp {
  max-width: 260px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.rp-tbw-unread-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 999px;
  /* Чат.dc.html: primary, not destructive — matches .rp-tbw-badge above. */
  background: var(--primary);
  color: var(--primary-foreground);
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
}

/* Чат.dc.html's dropdown footer ("Открыть все чаты") is a primary-coloured 13.5px/600 call to
   action, not a regular muted menu row. Verified against the rendered menu-item markup: its own
   Tailwind classes (blazorblueprint.css, loaded before bp.css per App.razor) never set `color`
   directly on the item — it only inherits `text-popover-foreground` from the dropdown-content
   ancestor — so this rule is the sole `color` source for the element and needs no !important;
   `font-size` does collide with the item's own `.text-sm` utility class, but same-specificity +
   later-in-cascade (bp.css after blazorblueprint.css) settles it the same way. */
.rp-tbw-footer-link {
  color: var(--primary);
  font-size: 13.5px;
  font-weight: 600;
}

/* Schedule widget — handoff: 38px framed box, clock icon in --primary,
   two lines: muted 10.5px eyebrow + 12.5px semibold value. */
.rp-tbw-schedule {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  height: 38px;
  padding: 0 12px 0 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  cursor: pointer;
  position: relative;
}

.rp-tbw-schedule > svg {
  color: var(--primary);
  flex-shrink: 0;
}

.rp-tbw-schedule__lines {
  display: flex;
  flex-direction: column;
  line-height: 1.2;
  white-space: nowrap;
  text-align: left;
}

.rp-tbw-schedule__label {
  font-size: 10.5px;
  color: var(--muted-foreground);
}

.rp-tbw-schedule__value {
  font-size: 12.5px;
  font-weight: 600;
}

/* Chat button — handoff: 38×38 framed square on --card, badge overhangs the corner. */
.rp-tbw-chat {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  cursor: pointer;
  position: relative;
}

/* AI credits chip — handoff: 38px accent-filled box (radius-md, not a 999px pill). */
.rp-tbw-ai {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 38px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--accent);
  color: var(--accent-foreground);
  text-decoration: none;
  cursor: pointer;
}

.rp-tbw-ai__text {
  font-size: 12.5px;
  font-weight: 600;
}

/* Role switcher — handoff: 38px framed box on --card, 7px primary dot + 13px/500 label. */
.rp-tbw-role {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 38px;
  padding: 0 10px 0 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
}

.rp-tbw-role__dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--primary);
  flex-shrink: 0;
}

.rp-tbw-role__label {
  font-size: 13px;
}

/* User profile — handoff: borderless 38px button, 30px primary-filled avatar + chevron. */
.rp-tbw-profile {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 38px;
  padding: 0 8px 0 4px;
  border: 0;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--foreground);
  font: inherit;
  font-size: 13px;
  cursor: pointer;
}

.rp-tbw-profile__avatar {
  width: 30px !important;
  height: 30px !important;
  border-radius: 50%;
  overflow: hidden;
  flex-shrink: 0;
  background: var(--primary);
  color: var(--primary-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 12.5px;
  font-weight: 600;
}

.rp-tbw-profile__header {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.rp-tbw-profile__name {
  font-size: 13.5px;
  font-weight: 600;
}

.rp-tbw-profile__email {
  font-size: 12px;
  color: var(--muted-foreground);
}

/* Sign-in link (unauthenticated) */
.rp-tbw-signin {
  display: inline-flex;
  align-items: center;
  padding: 5px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--foreground);
  text-decoration: none;
  font-size: 14px;
  font-weight: 500;
}

/* Bb dropdown-menu skin (rp-menu) — blueprint-pitfalls.md П-20 follow-up.
   BbDropdownMenuItem ships flex+items-center but NO icon↔text gap, and its item padding
   (Tailwind px-2 py-1.5 = 8px/6px) undershoots the handoff row padding (Чат.dc.html unread-
   messages dropdown: rows padding 9px 10px) — dropdowns still read as cramped even after
   bb-compat.css restored the Mud-zeroed Tailwind utilities. rp-menu is the ONE shared skin
   applied to every BbDropdownMenuContent in the shell (TopBarUserMenu, TopBarScheduleWidget,
   TopBarChatButton, TopBarRoleSwitcher, ChatConversation's kebab).
   DOM shape (BlazorBlueprint.Components 3.13.0, confirmed via ilspycmd decompile — Class=
   on BbDropdownMenuContent lands on the outer <div role="menu">, not on the inner wrapper):
   the item list actually sits one level deeper, inside an unconditional Tailwind `.p-1` div
   the component renders around ChildContent. `.rp-menu > div` zeroes THAT wrapper's own
   padding so the 6px below (Чат.dc.html container recipe) is the only inset — otherwise the
   two would stack into a 10px gutter. */
.rp-menu {
  padding: 6px;
  min-width: 200px;
}

.rp-menu > div {
  padding: 0;
}

/* BbDropdownMenuItem renders role="menuitem" on both its <div> and Href <a> variants. */
.rp-menu [role=menuitem] {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border-radius: var(--radius-sm);
  font-size: 13.5px;
}

.rp-menu [role=menuitem]:hover {
  /* Чат.dc.html uses --secondary for row hover, not Tailwind's default hover:bg-accent. */
  background: var(--secondary);
}

/* BbDropdownMenuLabel renders role="presentation" — the handoff's uppercase muted section
   header idiom ("Сообщения" atop the unread-messages dropdown). */
.rp-menu [role=presentation] {
  padding: 8px 10px;
  font-size: 12px;
  font-weight: 600;
  color: var(--muted-foreground);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

/* BbDropdownMenuSeparator renders role="separator" with its own Tailwind -mx-1 (sized to the
   now-zeroed .p-1 wrapper's old 4px padding) — replace with a margin sized to OUR 6px inset so
   the rule still spans edge-to-edge. */
.rp-menu [role=separator],
.rp-menu hr {
  margin: 6px -6px;
}

/* Messages dropdown only (Чат.dc.html container recipe: width 320px) — combine with rp-menu,
   never baked into the shared skin (every other consumer keeps rp-menu's own min-width). */
.rp-tbw-chat-menu {
  width: 320px;
}

/* ─── SidebarNav ───────────────────────────────────────────────────────────── */

.rp-nav {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 12px;
}

/* Each nav link — base state */
.rp-nav__item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 9px 12px;
  border-radius: var(--radius-md);
  font-size: 14px;
  font-weight: 400;
  text-decoration: none;
  color: var(--foreground);
  background: transparent;
  transition: background 0.12s;
}

.rp-nav__item:hover {
  background: var(--accent);
}

/* Active item: accent background + foreground colour */
.rp-nav__item--active {
  background: var(--accent);
  color: var(--accent-foreground);
  font-weight: 500;
}

.rp-nav__item__icon {
  width: 18px;
  height: 18px;
  display: inline-flex;
  flex-shrink: 0;
  color: var(--muted-foreground);
}

.rp-nav__item--active .rp-nav__item__icon {
  color: var(--accent-foreground);
}

.rp-nav__item__label {
  flex: 1;
}

/* Task 12 — sidebar nav pill (grading-queue count / chat unread). Declarations are a verbatim
   copy of .rp-tbw-unread-badge (Чат.dc.html's pill token) minus its own positioning context —
   comma-joined so the two never drift; MoreSheet's pill shares the same rule. */
.rp-nav__badge,
.rp-more-sheet__badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--primary);
  color: var(--primary-foreground);
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  flex-shrink: 0;
}

/* Admin section divider + section heading */
.rp-nav__divider {
  height: 1px;
  background: var(--border);
  margin: 8px 0;
}

.rp-nav__section-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--muted-foreground);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 4px 12px;
  margin-bottom: 4px;
}

/* ─── BottomNav ────────────────────────────────────────────────────────────── */

.rp-bottom-nav {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  padding: 8px 6px 10px;
  background: color-mix(in srgb, var(--card) 92%, transparent);
  backdrop-filter: blur(10px);
  border-top: 1px solid var(--border);
  z-index: 100;
}

/* Each item — all rendered as <button> for uniform hit targets */
.rp-bottom-nav__item {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 4px 2px;
  min-height: 44px;
  border: 0;
  background: transparent;
  cursor: pointer;
  color: var(--muted-foreground);
  font: inherit;
  text-decoration: none;
}

.rp-bottom-nav__item--active {
  color: var(--primary);
}

/* Icon wrapper — positions the unread dot */
.rp-bottom-nav__icon {
  position: relative;
  width: 22px;
  height: 22px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Unread chat dot */
.rp-bottom-nav__dot {
  position: absolute;
  top: -2px;
  right: -4px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--destructive);
  border: 1.5px solid var(--card);
}

.rp-bottom-nav__label {
  font-size: 10.5px;
  font-weight: 400;
}

.rp-bottom-nav__item--active .rp-bottom-nav__label {
  font-weight: 600;
}

/* ─── MoreSheet ────────────────────────────────────────────────────────────── */

/* Full-screen semi-transparent backdrop */
.rp-more-sheet__overlay {
  position: fixed;
  inset: 0;
  background: color-mix(in srgb, var(--foreground) 40%, transparent);
  z-index: 200;
}

/* Slide-up panel */
.rp-more-sheet__panel {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 201;
  background: var(--popover);
  border-top-left-radius: 20px;
  border-top-right-radius: 20px;
  padding: 10px 16px 26px;
  box-shadow: var(--shadow-lg);
}

/* Drag handle */
.rp-more-sheet__handle {
  width: 40px;
  height: 4px;
  border-radius: 999px;
  background: var(--border);
  margin: 6px auto 14px;
}

.rp-more-sheet__title {
  font-size: 15px;
  font-weight: 700;
  margin-bottom: 12px;
}

/* 2-column grid of sheet items */
.rp-more-sheet__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}

.rp-more-sheet__item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 14px;
  border-radius: var(--radius-md);
  background: var(--secondary);
  color: var(--foreground);
  text-decoration: none;
  font-size: 14px;
  font-weight: 500;
}

.rp-more-sheet__item__icon {
  width: 19px;
  height: 19px;
  display: inline-flex;
  flex-shrink: 0;
  color: var(--muted-foreground);
}

/* Task 12 — label wrapper takes the remaining row width so a badge pill lands flush right,
   mirroring .rp-nav__item__label. */
.rp-more-sheet__item__label {
  flex: 1;
}

/* Admin section divider + heading inside the «Ещё» sheet */
.rp-more-sheet__divider {
  height: 1px;
  background: var(--border);
  margin: 12px 0 8px;
}

.rp-more-sheet__section-label {
  font-size: 11px;
  font-weight: 600;
  color: var(--muted-foreground);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 0 2px 6px;
}

/* ─── App shell (MainLayout / FocusLayout) ─────────────────────────────────
   Source: App-shell.dc.html. Mobile-first: compressed top-bar + bottom nav;
   ≥768px flips to sidebar 246px + right column (top-bar 64px + content).
   Responsive switching is PURE CSS — the layout renders one markup tree. */

.rp-shell {
  display: flex;
  min-height: 100vh;
  background: var(--background);
  color: var(--foreground);
}

/* Sidebar — hidden on mobile, sticky column on desktop */
.rp-shell__sidebar {
  display: none;
}

.rp-shell__sidebar-head {
  display: flex;
  align-items: center;
  height: 64px;
  padding: 0 20px;
  flex-shrink: 0;
}

.rp-shell__sidebar-spacer {
  flex: 1;
}

.rp-shell__sidebar-foot {
  padding: 14px 16px;
  border-top: 1px solid var(--border);
  flex-shrink: 0;
}

.rp-shell__sidebar-foot a {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--muted-foreground);
  text-decoration: none;
}

/* Right column */
.rp-shell__main {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* Top bar — 56px compressed on mobile, 64px on desktop */
.rp-shell__topbar {
  position: sticky;
  top: 0;
  z-index: 90; /* below the bottom nav (100) and the more-sheet (200) */
  display: flex;
  align-items: center;
  gap: 10px;
  height: 56px;
  padding: 0 16px;
  background: var(--card);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.rp-shell__topbar-spacer {
  flex: 1;
}

/* Wide-only widget group (schedule, AI credits, role switcher) */
.rp-shell__topbar-wide {
  display: none;
}

/* Brand mark + word (sidebar head on desktop, top-bar on mobile/anonymous) */
.rp-shell__brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
}

.rp-shell__brand img {
  display: block;
}

.rp-shell__brand-word {
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.05em;
  color: var(--primary);
}

.rp-shell__brand--sidebar .rp-shell__brand-word {
  font-size: 15.5px;
}

/* Content — bottom padding clears the fixed BottomNav on mobile */
.rp-shell__content {
  flex: 1;
  padding: 18px 16px 90px;
  background: var(--background);
}

.rp-shell__content-inner {
  max-width: 1200px;
  margin: 0 auto;
}

@media (min-width: 768px) {
  .rp-shell__sidebar {
    display: flex;
    flex-direction: column;
    width: 246px;
    flex-shrink: 0;
    position: sticky;
    top: 0;
    height: 100vh;
    overflow-y: auto;
    background: var(--card);
    border-right: 1px solid var(--border);
  }

  .rp-shell__topbar {
    height: 64px;
    padding: 0 24px;
    gap: 14px;
  }

  /* display:contents — the widgets join the top-bar flex row with its own gap */
  .rp-shell__topbar-wide {
    display: contents;
  }

  /* Authorized brand lives in the sidebar on desktop */
  .rp-shell__brand--mobile {
    display: none;
  }

  .rp-shell__content {
    padding: 28px;
  }

  /* Mobile-only chrome */
  .rp-bottom-nav {
    display: none;
  }

  .rp-more-sheet__overlay,
  .rp-more-sheet__panel {
    display: none;
  }
}

/* Focus mode (FocusLayout) — bare canvas, no chrome */
.rp-focus-layout {
  min-height: 100vh;
  background: var(--background);
  color: var(--foreground);
}

/* ── Auth pages (Экраны.dc.html · Экран A) ───────────────────────────────
   Centred brand + card on --background, reused by all 7 anonymous auth
   pages (sign-in, sign-up, registered, password reset, invite, self-signup).
   Below 640px the card chrome drops away (fields sit directly on the page,
   matching the prototype's mobile column). Colours via tokens only. */
.rp-auth {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 60vh;
  padding: 32px 20px;
}

.rp-auth__inner {
  width: 100%;
  max-width: 400px;
}

.rp-auth__brand {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  margin-bottom: 24px;
  text-decoration: none;
}

.rp-auth__brand img {
  width: 44px;
  height: 44px;
}

.rp-auth__brand-word {
  font-size: 18px;
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--primary);
}

.rp-auth__card {
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  background: var(--card);
  padding: 28px;
  box-shadow: var(--shadow-sm);
}

.rp-auth__title {
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.01em;
  text-align: center;
  margin: 0 0 4px;
}

.rp-auth__subtitle {
  font-size: 13.5px;
  color: var(--muted-foreground);
  text-align: center;
  margin: 0 0 22px;
}

/* Server-error / notice blocks above the submit button */
.rp-auth__error {
  background: var(--destructive-muted);
  color: var(--destructive-muted-foreground);
  border-radius: var(--radius-md);
  padding: 10px 12px;
  font-size: 13px;
  margin: 4px 0 14px;
}

.rp-auth__notice {
  background: var(--muted);
  color: var(--muted-foreground);
  border-radius: var(--radius-md);
  padding: 12px 14px;
  font-size: 13.5px;
  margin: 0 0 14px;
}

/* Footer link row under the card */
.rp-auth__foot {
  text-align: center;
  font-size: 13.5px;
  color: var(--muted-foreground);
  margin: 20px 0 0;
}

.rp-auth__foot a,
.rp-auth__link {
  color: var(--primary);
  font-weight: 600;
  text-decoration: none;
}

.rp-auth__foot a:hover,
.rp-auth__link:hover {
  text-decoration: underline;
}

/* Spacing helpers for stacked auth form fields */
.rp-auth__field + .rp-auth__field {
  margin-top: 14px;
}

.rp-auth__text {
  font-size: 14px;
  color: var(--foreground);
  margin: 0 0 14px;
}

/* Anchor styled as the primary submit button (button-less confirmation pages) */
a.rp-btn-submit {
  text-decoration: none;
}

.rp-auth__check {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 10px;
  font-size: 13.5px;
  color: var(--foreground);
  cursor: pointer;
}

.rp-auth__actions {
  margin-top: 18px;
}

.rp-auth__divider {
  height: 1px;
  background: var(--border);
  margin: 20px 0;
}

@media (max-width: 640px) {
  .rp-auth__card {
    border: 0;
    box-shadow: none;
    background: transparent;
    padding: 0;
  }
}

/* ── 13. Segmented tabs (Задания.dc.html) ────────────────────────────────── */
/* Muted-подложка control — distinct from the underlined rp-tab* hub tabs above (paттерн №2). */
.rp-seg {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  background: var(--muted);
  border-radius: var(--radius-md);
  width: fit-content;
}

.rp-seg-tab {
  padding: 7px 18px;
  border: 0;
  border-radius: var(--radius-sm);
  font: inherit;
  font-size: 13.5px;
  font-weight: 500;
  color: var(--muted-foreground);
  background: transparent;
  cursor: pointer;
  white-space: nowrap;
}

.rp-seg-tab--active {
  font-weight: 600;
  color: var(--foreground);
  background: var(--card);
  box-shadow: var(--shadow-xs);
}

@media (max-width: 640px) {
  .rp-seg {
    width: 100%;
  }
  .rp-seg-tab {
    flex: 1;
    padding: 8px 0;
    font-size: 13px;
  }
}

/* ── 14. Assignment list/card (Задания.dc.html) ──────────────────────────── */
.rp-asg-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.rp-asg-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 14px 18px;
}

/* Drip-lock treatment — the row stays visible with its reason, the CTA is simply never rendered. */
.rp-asg-row--locked {
  background: var(--muted);
  opacity: 0.75;
}

.rp-asg-icon {
  width: 36px;
  height: 36px;
  border-radius: var(--radius-md);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.rp-asg-icon--info    { background: var(--info-muted);        color: var(--info-muted-foreground); }
.rp-asg-icon--warning { background: var(--warning-muted);     color: var(--warning-muted-foreground); }
.rp-asg-icon--danger  { background: var(--destructive-muted); color: var(--destructive-muted-foreground); }
.rp-asg-icon--success { background: var(--success-muted);     color: var(--success-muted-foreground); }
.rp-asg-icon--neutral { background: var(--secondary);         color: var(--muted-foreground); }

/* Optional child-initials avatar before the icon tile (parent aggregator, Задания детей.dc.html) —
   rendered only when AssignmentRow.AvatarText is set; --warm is the alternating per-child tint
   (same rule as rp-phome-avatar--warm). Carried on BOTH viewports (wave-6 LOCKED-12 hides only the
   FILTER-chip avatar on mobile, not the row's). */
.rp-asg-avatar {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 700;
  flex-shrink: 0;
}

.rp-asg-avatar--warm {
  background: var(--warning-muted);
  color: var(--warning-muted-foreground);
}

.rp-asg-body {
  flex: 1;
  min-width: 160px;
}

.rp-asg-title {
  font-size: 14.5px;
  font-weight: 600;
}

.rp-asg-sub {
  font-size: 12.5px;
  color: var(--muted-foreground);
}

.rp-asg-chip {
  font-size: 12px;
  font-weight: 600;
  padding: 3px 10px;
  border-radius: 999px;
  white-space: nowrap;
}

.rp-asg-chip--info    { background: var(--info-muted);        color: var(--info-muted-foreground); }
.rp-asg-chip--warning { background: var(--warning-muted);     color: var(--warning-muted-foreground); }
.rp-asg-chip--danger  { background: var(--destructive-muted); color: var(--destructive-muted-foreground); }
.rp-asg-chip--success { background: var(--success-muted);     color: var(--success-muted-foreground); }
.rp-asg-chip--neutral { background: var(--secondary);         color: var(--muted-foreground); }

.rp-asg-cta {
  height: 36px;
  padding: 0 16px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: var(--radius-md);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}

.rp-asg-cta--primary   { background: var(--primary);   color: var(--primary-foreground); }
.rp-asg-cta--secondary { background: var(--secondary); color: var(--secondary-foreground); }

/* Mobile: icon/title/chip stay on one line, the CTA drops to a full-width line below it.
   Achieved by forcing the CTA flex item onto its own line (flex-basis 100% > remaining row space)
   rather than splitting the markup into two DOM variants like rp-tabs-underline/rp-tabs-chips. */
@media (max-width: 640px) {
  .rp-asg-row {
    padding: 13px 14px;
    row-gap: 10px;
    column-gap: 11px;
  }
  .rp-asg-icon {
    width: 32px;
    height: 32px;
  }
  .rp-asg-avatar {
    width: 26px;
    height: 26px;
    font-size: 10px;
  }
  .rp-asg-title {
    font-size: 13.5px;
    line-height: 1.35;
  }
  .rp-asg-sub {
    font-size: 12px;
  }
  .rp-asg-chip {
    font-size: 10.5px;
    padding: 3px 8px;
  }
  .rp-asg-cta {
    flex-basis: 100%;
    width: 100%;
    height: 40px;
    font-size: 13.5px;
  }
}

/* ── 15. Assignment empty state — "всё сдано" (Задания.dc.html) ─────────── */
/* NOT the dashed rp-empty2 variant: a success-tinted 64px circle for "nothing left to do". */
.rp-asg-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 48px 24px;
}

.rp-asg-empty-icon {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: var(--success-muted);
  color: var(--success-muted-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 18px;
}

.rp-asg-empty-title {
  font-size: 17px;
  font-weight: 700;
  margin: 0 0 6px;
}

.rp-asg-empty-desc {
  font-size: 13.5px;
  color: var(--muted-foreground);
  line-height: 1.55;
  margin: 0 0 20px;
  max-width: 340px;
}

.rp-asg-empty-action {
  display: flex;
  justify-content: center;
}

/* Convenience outline CTA matching the empty-state action in the handoff («К курсам →»). */
.rp-asg-empty-cta {
  height: 44px;
  padding: 0 22px;
  display: inline-flex;
  align-items: center;
  border: 1.5px solid var(--primary);
  border-radius: var(--radius-md);
  color: var(--primary);
  background: transparent;
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
}

/* ── 16. Success banner (Оплата.dc.html «После оплаты») ──────────────────── */
.rp-sban {
  display: flex;
  align-items: center;
  gap: 12px;
  border: 1px solid color-mix(in srgb, var(--success) 40%, var(--border));
  background: var(--success-muted);
  color: var(--success-muted-foreground);
  border-radius: var(--radius-lg);
  padding: 14px 18px;
}

.rp-sban-icon {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--success);
  color: var(--success-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.rp-sban-body { flex: 1; min-width: 0; }
.rp-sban-title { font-size: 14.5px; font-weight: 700; }
.rp-sban-desc { font-size: 13px; }

.rp-sban-link {
  font-size: 13px;
  font-weight: 600;
  color: var(--success-muted-foreground);
  white-space: nowrap;
  text-decoration: none;
}

@media (max-width: 640px) {
  .rp-sban { align-items: flex-start; padding: 12px 14px; gap: 10px; }
  .rp-sban-icon { width: 28px; height: 28px; }
}

/* ── 17. Course card (Мои курсы.dc.html) ─────────────────────────────────── */
.rp-crs {
  display: block;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  overflow: hidden;
  text-decoration: none;
  color: var(--foreground);
}

/* Fallback cover (no CoverUrl) — diagonal stripe gradient copied verbatim from the handoff. */
.rp-crs-cover {
  height: 120px;
  background: repeating-linear-gradient(
    -45deg,
    var(--accent),
    var(--accent) 12px,
    color-mix(in srgb, var(--accent) 60%, var(--card)) 12px,
    color-mix(in srgb, var(--accent) 60%, var(--card)) 24px
  );
}

.rp-crs-cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.rp-crs-body { padding: 16px 18px; }
.rp-crs-title { font-size: 15.5px; font-weight: 700; margin-bottom: 3px; }
.rp-crs-meta { font-size: 12.5px; color: var(--muted-foreground); margin-bottom: 12px; }

.rp-crs-bar {
  height: 6px;
  border-radius: 999px;
  background: var(--muted);
  overflow: hidden;
  margin-bottom: 6px;
}

.rp-crs-bar-fill {
  height: 100%;
  border-radius: 999px;
  background: var(--primary);
}

.rp-crs-foot { display: flex; align-items: center; }
.rp-crs-progress { font-size: 12px; color: var(--muted-foreground); }
.rp-crs-spacer { flex: 1; }
.rp-crs-cta { font-size: 12.5px; color: var(--primary); font-weight: 600; }

@media (max-width: 640px) {
  .rp-crs-cover { height: 88px; }
  .rp-crs-body { padding: 13px 14px; }
  .rp-crs-title { font-size: 14.5px; margin-bottom: 2px; }
  .rp-crs-meta { font-size: 12px; margin-bottom: 10px; }
  .rp-crs-bar { height: 5px; margin-bottom: 5px; }
  .rp-crs-progress { font-size: 11.5px; }
  .rp-crs-cta { font-size: 12px; }
}

/* ── Оплата (/pay) page layout — Task 6, Оплата.dc.html ──────────────────── */
/* Vertical rhythm between the page's sections (баланс / купить / история платежей). */
.rp-pay-section {
  margin-bottom: 26px;
}

/* Small uppercase section label above each section's content — Оплата.dc.html repeats this exact
   style (font-size/weight/letter-spacing/color) above the balance card, the shop grid, and the
   payments table; kept page-scoped rather than reusing rp-ph-eyebrow (that one is page-header-only). */
.rp-pay-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--muted-foreground);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin: 0 0 10px;
}

/* Stack of per-tenant RpBalanceCard rows (a multi-tutor student gets one card per tenant). */
.rp-pay-balances {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* Lesson-package + course shop — 3-column grid desktop, single column mobile (Оплата.dc.html). */
.rp-pay-shop {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
}

@media (max-width: 900px) {
  .rp-pay-shop {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 640px) {
  .rp-pay-shop {
    grid-template-columns: 1fr;
  }
}

.rp-pay-history-loading {
  display: flex;
  justify-content: center;
  padding: 10px 0;
}

/* ── /pay «За детей» blocks (wave 6, П-17 — Оплата.dc.html «Родитель») ─────────
   One rp-pay-kid per (child, tenant) guardian pair. Both layout variants live in
   the DOM (the rp-payrow idiom): desktop shows head + balance card + product grid,
   ≤768px (the shell mobile breakpoint) flips to an accordion card whose header
   carries the balance line and whose body lists compact product rows. */
.rp-pay-kid {
  margin-bottom: 30px;
}

/* Desktop block head: 36px initials avatar + child name + «Оплата за ребёнка · {площадка}»,
   underlined by the mockup's 2px divider. The --self variant is the «За себя» divider above
   the caller's own sections (shown only when kid blocks exist). */
.rp-pay-kid-head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding-bottom: 10px;
  border-bottom: 2px solid var(--border);
  margin-bottom: 14px;
}

.rp-pay-kid-head--self {
  margin-top: 2px;
}

.rp-pay-kid-avatar {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 700;
  flex-shrink: 0;
}

/* Warm alternation per distinct child — matches rp-phome-avatar--warm / rp-chw-chip-av--warm so the
   same child keeps one tone across /home/parent, /children-homework and /pay (final review F3). */
.rp-pay-kid-avatar--warm {
  background: var(--warning-muted);
  color: var(--warning-muted-foreground);
}

.rp-pay-kid-name {
  font-size: 16px;
  font-weight: 700;
  line-height: 1.25;
}

.rp-pay-kid-sub {
  font-size: 12.5px;
  color: var(--muted-foreground);
}

/* Balance-card wrapper; --warn tints the inner rp-balcard toward --warning at a zero
   balance (LOCKED-4: the warning tone is the only "needs payment" signal — no forecasts). */
.rp-pay-kid-bal {
  margin-bottom: 14px;
}

.rp-pay-kid-bal--warn .rp-balcard {
  border-color: color-mix(in srgb, var(--warning) 45%, var(--border));
  background: var(--warning-muted);
}

.rp-pay-kid-bal--warn .rp-balcard-num {
  color: var(--warning-muted-foreground);
}

/* Mobile accordion header button — hidden on desktop. */
.rp-pay-kid-acc {
  display: none;
  align-items: center;
  gap: 11px;
  width: 100%;
  padding: 14px;
  border: 0;
  background: transparent;
  color: var(--foreground);
  font: inherit;
  cursor: pointer;
  text-align: left;
}

.rp-pay-kid-acc-txt {
  flex: 1;
  min-width: 0;
  line-height: 1.3;
}

.rp-pay-kid-acc-name {
  display: block;
  font-size: 14px;
  font-weight: 700;
}

.rp-pay-kid-acc-bal {
  display: block;
  font-size: 12px;
  color: var(--muted-foreground);
}

.rp-pay-kid-acc-bal--warn {
  color: var(--warning-muted-foreground);
}

.rp-pay-kid-chev {
  width: 16px;
  height: 16px;
  display: inline-flex;
  color: var(--muted-foreground);
  transition: transform 0.15s;
}

.rp-pay-kid-chev--open {
  transform: rotate(180deg);
}

/* Mobile-only «Купить» label inside the accordion body (the desktop grid follows the
   balance card directly, mockup has no label there). */
.rp-pay-kid-shoplabel {
  display: none;
}

/* Compact product rows — the accordion body's mobile shop; hidden on desktop where the
   rp-pay-shop grid of RpProductCard renders instead. */
.rp-pay-kid-rows {
  display: none;
  flex-direction: column;
  gap: 9px;
}

.rp-pay-kid-row {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 12px 13px;
  display: flex;
  align-items: center;
  gap: 11px;
}

.rp-pay-kid-row-info {
  flex: 1;
  min-width: 0;
}

.rp-pay-kid-row-name {
  font-size: 13.5px;
  font-weight: 700;
}

.rp-pay-kid-row-sub {
  font-size: 11.5px;
  color: var(--muted-foreground);
}

.rp-pay-kid-row-buy {
  text-align: right;
  flex-shrink: 0;
}

.rp-pay-kid-row-price {
  font-size: 13.5px;
  font-weight: 700;
}

.rp-pay-kid-row-btn {
  margin-top: 6px;
  height: 34px;
  padding: 0 13px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-foreground);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
}

.rp-pay-kid-row-btn:disabled {
  opacity: 0.6;
  cursor: default;
}

/* Honest empty shop («Площадка пока ничего не продаёт») — both viewports. */
.rp-pay-kid-none {
  font-size: 13px;
  color: var(--muted-foreground);
}

@media (max-width: 768px) {
  .rp-pay-kid {
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--card);
    margin-bottom: 12px;
    overflow: hidden;
  }

  /* Scoped to .rp-pay-kid so the standalone «За себя» divider (same head class, outside a
     kid block) stays visible on mobile. */
  .rp-pay-kid .rp-pay-kid-head,
  .rp-pay-kid .rp-pay-kid-bal {
    display: none;
  }

  .rp-pay-kid-acc {
    display: flex;
  }

  /* Mockup's mobile accordion avatar is a touch smaller than the desktop head's 36px. */
  .rp-pay-kid-acc .rp-pay-kid-avatar {
    width: 34px;
    height: 34px;
    font-size: 12.5px;
  }

  .rp-pay-kid-body {
    display: none;
  }

  .rp-pay-kid-body--open {
    display: block;
    padding: 0 14px 14px;
    border-top: 1px solid var(--border);
  }

  .rp-pay-kid .rp-pay-shop {
    display: none;
  }

  .rp-pay-kid-rows {
    display: flex;
  }

  .rp-pay-kid-shoplabel {
    display: block;
    font-size: 10.5px;
    margin: 12px 0 8px;
  }

  .rp-pay-kid-none {
    padding-top: 12px;
  }
}

/* ── Week calendar + booking (Занятия.dc.html, wave 1) ───────────────────────
   rp-wk-head (compact balance strip), rp-wknav* (week navigator), rp-wkg* (desktop
   7-col grid), rp-wk-ev* (cells: lesson/slot/reservation/past), rp-wkm* (mobile
   chip strip + day list), rp-book* (booking dialog). @media switches grid↔mobile
   at 768px. All colours via tokens. rp-wk-ev--live / rp-wkm-card--live(-hit/-actions/
   -action/-chip--success) are the live/«скоро» treatment (Расписание.dc.html) — see below. */

/* Compact balance header strip */
.rp-wk-head {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 8px;
}
.rp-wk-head .rp-ph { margin-bottom: 0; }
.rp-wk-head-spacer { flex: 1; }
.rp-wk-balance { font-size: 13px; color: var(--muted-foreground); }
.rp-wk-balance b { color: var(--foreground); font-weight: 600; }
.rp-wk-topup {
  font-size: 13px;
  color: var(--primary);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}

/* Week navigator */
.rp-wknav {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin: 18px 0;
}
.rp-wknav-arrows {
  display: inline-flex;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--card);
}
.rp-wknav-arrow {
  width: 34px;
  height: 34px;
  border: 0;
  background: transparent;
  color: var(--muted-foreground);
  cursor: pointer;
  font-size: 18px;
  line-height: 1;
}
.rp-wknav-arrow--right { border-left: 1px solid var(--border); }
.rp-wknav-arrow:hover { background: var(--secondary); color: var(--foreground); }
.rp-wknav-range { font-size: 15px; font-weight: 600; }
.rp-wknav-today {
  height: 34px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
}
.rp-wknav-today:hover { background: var(--secondary); }
.rp-wknav-spacer { flex: 1; }
.rp-wknav-legend {
  display: flex;
  gap: 14px;
  font-size: 12.5px;
  color: var(--muted-foreground);
  align-items: center;
}
.rp-wknav-legend-item { display: inline-flex; align-items: center; gap: 6px; }
.rp-wknav-dot { width: 10px; height: 10px; border-radius: 3px; }
.rp-wknav-dot--lesson { background: var(--primary); }
.rp-wknav-dot--slot {
  border: 1.5px dashed color-mix(in srgb, var(--primary) 55%, transparent);
  background: var(--accent);
}

/* Desktop 7-column grid */
.rp-wkg {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 8px;
}
.rp-wkg-col { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.rp-wkg-head {
  text-align: center;
  padding: 8px 0 10px;
  border-bottom: 2px solid transparent;
}
.rp-wkg-head--today { border-bottom-color: var(--primary); }
.rp-wkg-dow {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted-foreground);
}
.rp-wkg-num { font-size: 16px; font-weight: 700; color: var(--foreground); }
.rp-wkg-num--today { color: var(--primary); }

/* Event cells (shared by grid; mobile has its own card shape) */
.rp-wk-ev {
  display: block;
  width: 100%;
  text-align: left;
  border-radius: var(--radius-md);
  padding: 9px 10px;
  font: inherit;
  cursor: pointer;
  border: 0;
}
.rp-wk-ev-time { font-size: 12px; font-weight: 700; }
.rp-wk-ev-title { font-size: 11.5px; line-height: 1.3; }
.rp-wk-ev.rp-wk-ev--lesson { background: var(--primary); color: var(--primary-foreground); }
.rp-wk-ev.rp-wk-ev--lesson .rp-wk-ev-title { opacity: 0.9; }
.rp-wk-ev.rp-wk-ev--slot {
  border: 1.5px dashed color-mix(in srgb, var(--primary) 55%, transparent);
  background: var(--accent);
  color: var(--accent-foreground);
}
.rp-wk-ev.rp-wk-ev--reservation {
  border: 1.5px solid var(--warning);
  background: var(--warning-muted);
  color: var(--warning-muted-foreground);
}
.rp-wk-ev.rp-wk-ev--past {
  background: var(--muted);
  color: var(--muted-foreground);
  cursor: default;
}
/* Tutor kinds (Расписание.dc.html) */
.rp-wk-ev-top { display: flex; align-items: center; gap: 5px; }
.rp-wk-ev-time--struck { text-decoration: line-through; }
.rp-wk-ev-badge {
  font-size: 10px;
  font-weight: 700;
  background: rgba(255, 255, 255, 0.25);
  border-radius: 999px;
  padding: 1px 6px;
}
.rp-wk-ev.rp-wk-ev--group { background: var(--brand-orange); color: #ffffff; }
.rp-wk-ev.rp-wk-ev--group .rp-wk-ev-title { opacity: 0.95; }
.rp-wk-ev.rp-wk-ev--done {
  background: var(--muted);
  color: var(--muted-foreground);
  cursor: default;
}
.rp-wk-ev.rp-wk-ev--cancelled {
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--muted-foreground);
  cursor: default;
}
/* Live/«скоро» desktop tint (fix-wave) — two classes so it wins over the single-class .rp-wk-ev--lesson
   background without depending on source order. */
.rp-wk-ev.rp-wk-ev--live { background: var(--success-muted); color: var(--success-muted-foreground); }

/* Mobile: chip strip + day list */
.rp-wkm { display: none; }
.rp-wkm-chips {
  display: flex;
  gap: 6px;
  overflow-x: auto;
  padding-bottom: 4px;
  margin-bottom: 14px;
}
.rp-wkm-chip {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  width: 44px;
  padding: 7px 0;
  border: 0;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--foreground);
  cursor: pointer;
  font: inherit;
}
.rp-wkm-chip-dow { font-size: 10px; font-weight: 600; text-transform: uppercase; }
.rp-wkm-chip-num { font-size: 15px; font-weight: 700; }
.rp-wkm-chip--today { color: var(--primary); }
.rp-wkm-chip--sel { background: var(--primary); color: var(--primary-foreground); }
.rp-wkm-daylabel {
  font-size: 12px;
  font-weight: 600;
  color: var(--muted-foreground);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 10px;
}
.rp-wkm-empty { font-size: 13px; color: var(--muted-foreground); }
.rp-wkm-card {
  display: block;
  width: 100%;
  text-align: left;
  border: 1px solid var(--border);
  border-left: 4px solid var(--primary);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 14px 16px;
  margin-bottom: 10px;
  font: inherit;
  cursor: pointer;
}
.rp-wkm-card-top { display: flex; align-items: center; gap: 8px; }
.rp-wkm-card-time { font-size: 14.5px; font-weight: 700; }
.rp-wkm-card-time--struck { text-decoration: line-through; }
.rp-wkm-card-chip {
  font-size: 11px;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--muted);
  color: var(--muted-foreground);
}
.rp-wkm-card-chip--info { background: var(--info-muted); color: var(--info-muted-foreground); }
.rp-wkm-card-chip--group {
  background: color-mix(in srgb, var(--brand-orange) 16%, transparent);
  color: var(--warning-muted-foreground);
}
.rp-wkm-card-chip--done { background: var(--muted); color: var(--muted-foreground); }
.rp-wkm-card-title { font-size: 14px; font-weight: 600; margin-top: 4px; }
.rp-wkm-card-sub { font-size: 12.5px; color: var(--muted-foreground); margin-top: 2px; }
.rp-wkm-card.rp-wk-ev--slot {
  border: 1.5px dashed color-mix(in srgb, var(--primary) 55%, transparent);
  background: var(--accent);
  color: var(--accent-foreground);
}
.rp-wkm-card.rp-wk-ev--slot .rp-wkm-card-title { color: var(--accent-foreground); }
.rp-wkm-card.rp-wk-ev--group { border-left-color: var(--brand-orange); }
.rp-wkm-card.rp-wk-ev--done { border-left-color: var(--muted-foreground); color: var(--muted-foreground); cursor: default; }
.rp-wkm-card.rp-wk-ev--done .rp-wkm-card-title { color: var(--muted-foreground); }
.rp-wkm-card.rp-wk-ev--cancelled { border-left-color: var(--border); color: var(--muted-foreground); cursor: default; }
.rp-wkm-card.rp-wk-ev--cancelled .rp-wkm-card-title { color: var(--muted-foreground); }
.rp-wkm-card.rp-wk-ev--reservation {
  border: 1px solid var(--warning);
  border-left: 4px solid var(--warning);
  background: var(--warning-muted);
}
.rp-wkm-card.rp-wk-ev--past { border-left-color: var(--muted-foreground); opacity: 0.8; cursor: default; }

/* Live/«скоро» mobile card (fix-wave, Расписание.dc.html lines ~171-177): success-tinted border + chip,
   plus a below-title «Войти в занятие»/«Перенести» action row. Two classes on rp-wkm-card--live so it
   wins over the single-class kind borders above (e.g. rp-wk-ev--lesson has none of its own, but this
   stays robust if a future kind adds one). rp-wkm-card-hit carries the click-to-open-dialog handler once
   the outer card becomes a plain <div> (RpWeekCalendar.razor) — the action row is its sibling, never a
   descendant, so button clicks can't bubble into it. */
.rp-wkm-card.rp-wkm-card--live { border-left-color: var(--success); }
.rp-wkm-card-hit { cursor: pointer; }
.rp-wkm-card-chip--success { background: var(--success-muted); color: var(--success-muted-foreground); }
.rp-wkm-card-actions { display: flex; gap: 8px; margin-top: 12px; }
.rp-wkm-card-action {
  flex: 1;
  height: 40px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-md);
  border: 0;
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
  text-decoration: none;
}
.rp-wkm-card-action--primary { background: var(--primary); color: var(--primary-foreground); }
.rp-wkm-card-action--outline {
  flex: none;
  padding: 0 14px;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--foreground);
  font-weight: 500;
}

@media (max-width: 768px) {
  .rp-wkg { display: none; }
  .rp-wkm { display: block; }
}

/* Empty-state CTA */
.rp-wk-empty-cta {
  height: 44px;
  padding: 0 24px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-foreground);
  font: inherit;
  font-size: 14.5px;
  font-weight: 600;
  cursor: pointer;
}

/* Booking dialog body */
.rp-book { max-width: 400px; }
.rp-book-title { font-size: 17px; font-weight: 700; }
.rp-book-sub { font-size: 13.5px; color: var(--muted-foreground); margin: 4px 0 16px; }
.rp-book-when {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 14px 16px;
  margin-bottom: 14px;
  display: flex;
  align-items: center;
  gap: 14px;
}
.rp-book-datecard {
  width: 46px;
  height: 46px;
  flex-shrink: 0;
  border-radius: var(--radius-md);
  background: var(--accent);
  color: var(--accent-foreground);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
.rp-book-datecard-day { font-size: 15px; font-weight: 700; line-height: 1; }
.rp-book-datecard-mon { font-size: 10px; }
.rp-book-when-title { font-size: 15px; font-weight: 600; }
.rp-book-when-sub { font-size: 13px; color: var(--muted-foreground); }
.rp-book-hold {
  display: flex;
  align-items: center;
  gap: 9px;
  background: var(--warning-muted);
  color: var(--warning-muted-foreground);
  border-radius: var(--radius-md);
  padding: 10px 12px;
  margin-bottom: 14px;
}
.rp-book-hold-label { font-size: 13px; font-weight: 500; }
.rp-book-hold-time { font-size: 14px; font-weight: 700; font-family: var(--font-mono); margin-left: auto; }
.rp-book-charge {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 13.5px;
  color: var(--muted-foreground);
  margin-bottom: 16px;
}
.rp-book-charge-val { font-weight: 600; color: var(--foreground); }
.rp-book-confirm {
  width: 100%;
  height: 44px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-foreground);
  font: inherit;
  font-size: 14.5px;
  font-weight: 600;
  cursor: pointer;
}
.rp-book-confirm:disabled { opacity: 0.6; cursor: default; }
.rp-book-cancel {
  width: 100%;
  height: 40px;
  margin-top: 8px;
  border: 0;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--muted-foreground);
  font: inherit;
  font-size: 13.5px;
  font-weight: 500;
  cursor: pointer;
}

/* ── Wave 3 Task 5 — tutor schedule page (/schedule, Расписание.dc.html) ──────
   Toolbar + nav row + legend + «День» single-day list + the two Bb dialog bodies.
   All colours via tokens; the week grid itself is rp-wkg/rp-wk-ev (shared, above). */
.rp-sched-toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 4px;
}
.rp-sched-toolbar .rp-ph { margin-bottom: 0; }
.rp-sched-toolbar-spacer { flex: 1; }
.rp-sched-btn {
  display: inline-flex;
  align-items: center;
  height: 36px;
  padding: 0 14px;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
}
.rp-sched-btn--primary { border: 0; background: var(--primary); color: var(--primary-foreground); font-weight: 600; }
.rp-sched-btn:hover { background: var(--secondary); }
.rp-sched-btn--primary:hover { background: var(--primary); opacity: 0.92; }

/* Nav row: reuses rp-wknav* for arrows/range/today; adds the view segment + legend. */
.rp-sched-nav {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin: 16px 0;
}
.rp-sched-nav-spacer { flex: 1; }
.rp-sched-seg {
  display: inline-flex;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--card);
}
.rp-sched-seg-btn {
  height: 34px;
  padding: 0 12px;
  border: 0;
  background: transparent;
  color: var(--muted-foreground);
  font: inherit;
  font-size: 12.5px;
  cursor: pointer;
}
.rp-sched-seg-btn + .rp-sched-seg-btn { border-left: 1px solid var(--border); }
.rp-sched-seg-btn--active { background: var(--secondary); color: var(--secondary-foreground); font-weight: 600; }
.rp-sched-legend {
  display: flex;
  gap: 14px;
  font-size: 12.5px;
  color: var(--muted-foreground);
  align-items: center;
}
.rp-sched-legend-item { display: inline-flex; align-items: center; gap: 6px; }
.rp-sched-legend-dot { width: 10px; height: 10px; border-radius: 3px; }
.rp-sched-legend-dot--lesson { background: var(--primary); }
.rp-sched-legend-dot--group { background: var(--brand-orange); }
.rp-sched-legend-dot--slot {
  border: 1.5px dashed color-mix(in srgb, var(--primary) 55%, transparent);
  background: var(--accent);
}
/* Legend is desktop-only (mockup). */
@media (max-width: 768px) { .rp-sched-legend { display: none; } }

/* «День» view: force RpWeekCalendar's mobile day-chip + card list to show on desktop too, so the
   single-day list reuses the exact same markup (no duplication). Week view leaves the @media default. */
.rp-sched-dayforce { max-width: 680px; }
.rp-sched-dayforce .rp-wkg { display: none; }
.rp-sched-dayforce .rp-wkm { display: block; }

/* Details dialog body */
.rp-sched-dlg { max-width: 420px; }
.rp-sched-dlg-title { font-size: 17px; font-weight: 700; }
.rp-sched-dlg-sub { font-size: 13.5px; color: var(--muted-foreground); margin: 4px 0 14px; }
.rp-sched-dlg-note {
  font-size: 13px;
  color: var(--foreground);
  background: var(--muted);
  border-radius: var(--radius-md);
  padding: 10px 12px;
  margin-bottom: 14px;
}
.rp-sched-dlg-fields {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-bottom: 14px;
}
.rp-sched-dlg-label { display: block; font-size: 12.5px; font-weight: 600; margin-bottom: 6px; }
.rp-sched-dlg-input {
  width: 100%;
  height: 42px;
  padding: 0 12px;
  border: 1px solid var(--input);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 13.5px;
}
.rp-sched-dlg-tz { font-size: 12px; color: var(--muted-foreground); margin: -6px 0 14px; }
.rp-sched-dlg-confirm { font-size: 13.5px; color: var(--foreground); margin-bottom: 12px; }
.rp-sched-dlg-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.rp-sched-dlg-btn {
  height: 40px;
  padding: 0 16px;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 13.5px;
  font-weight: 500;
  cursor: pointer;
}
.rp-sched-dlg-btn--primary { border: 0; background: var(--primary); color: var(--primary-foreground); font-weight: 600; }
.rp-sched-dlg-btn--success { border: 0; background: var(--success); color: var(--primary-foreground); font-weight: 600; }
.rp-sched-dlg-btn--danger { border: 0; background: var(--destructive); color: var(--primary-foreground); font-weight: 600; }
.rp-sched-dlg-btn--ghost { border: 0; background: transparent; color: var(--muted-foreground); }
.rp-sched-dlg-btn:disabled { opacity: 0.6; cursor: default; }
.rp-sched-dlg-spacer { flex: 1; }
.rp-sched-dlg-join {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 40px;
  padding: 0 16px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-foreground);
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  margin-bottom: 14px;
}

/* Conduct dialog body */
.rp-sched-conduct { max-width: 420px; }
.rp-sched-conduct-title { font-size: 17px; font-weight: 700; margin-bottom: 4px; }
.rp-sched-conduct-hint { font-size: 13px; color: var(--muted-foreground); margin-bottom: 14px; }
.rp-sched-conduct-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 0;
}
.rp-sched-conduct-name { flex: 1; font-size: 13.5px; font-weight: 500; }
.rp-sched-conduct-att {
  height: 36px;
  padding: 0 10px;
  border: 1px solid var(--input);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 13px;
}
.rp-sched-conduct-note {
  width: 100%;
  min-height: 72px;
  margin-top: 12px;
  padding: 10px 12px;
  border: 1px solid var(--input);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 13.5px;
  resize: vertical;
}
.rp-sched-conduct-debt {
  font-size: 12.5px;
  color: var(--warning-muted-foreground);
  background: var(--warning-muted);
  border-radius: var(--radius-md);
  padding: 10px 12px;
  margin-top: 12px;
}

@media (max-width: 600px) {
  .rp-sched-dlg-fields { grid-template-columns: 1fr; }
}

/* ── Task 6 — create-lesson (rp-cld*) + publish-slots (rp-psd*) Bb dialogs ─────────
   The create-lesson dialog owns the shared form chrome (head/close, segment, picker list, weekly-repeat
   switch, balance strip, «Дополнительно» collapse, full-width submit); the publish-slots dialog reuses it
   and adds only rp-psd* (hint + weekday multiselect). Field/label/input styles come from rp-sched-dlg-*. */
.rp-cld, .rp-psd { max-width: 440px; }
.rp-cld-head { display: flex; align-items: center; margin-bottom: 16px; }
.rp-cld-title { font-size: 17px; font-weight: 700; }
.rp-cld-spacer { flex: 1; }
.rp-cld-x {
  width: 30px;
  height: 30px;
  border: 0;
  background: transparent;
  color: var(--muted-foreground);
  font-size: 16px;
  cursor: pointer;
  border-radius: var(--radius-md);
}
.rp-cld-x:hover { background: var(--secondary); }
.rp-cld-field { margin-bottom: 12px; }

/* Individual/Группа segment */
.rp-cld-seg { display: flex; gap: 8px; margin-bottom: 14px; }
.rp-cld-seg-btn {
  flex: 1;
  height: 36px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--muted-foreground);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
}
.rp-cld-seg-btn--active {
  border-color: var(--primary);
  background: var(--accent);
  color: var(--accent-foreground);
  font-weight: 600;
}

/* Searchable student picker */
.rp-cld-search { margin-bottom: 8px; }
.rp-cld-list {
  max-height: 168px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  margin-bottom: 12px;
}
.rp-cld-item {
  display: block;
  width: 100%;
  text-align: left;
  padding: 9px 12px;
  border: 0;
  border-bottom: 1px solid var(--border);
  background: transparent;
  color: var(--foreground);
  font: inherit;
  font-size: 13.5px;
  cursor: pointer;
}
.rp-cld-item:last-child { border-bottom: 0; }
.rp-cld-item:hover { background: var(--secondary); }
.rp-cld-item--active { background: var(--accent); color: var(--accent-foreground); font-weight: 600; }
.rp-cld-empty, .rp-cld-note-empty {
  padding: 10px 12px;
  font-size: 13px;
  color: var(--muted-foreground);
}
.rp-cld-note-empty {
  background: var(--muted);
  border-radius: var(--radius-md);
  margin-bottom: 12px;
}

.rp-cld-tz { font-size: 12px; color: var(--muted-foreground); margin: -4px 0 14px; }

/* Weekly-repeat switch (bespoke role="switch", per П-9 — BbSwitch presets don't hit the mockup size) */
.rp-cld-toggle {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13.5px;
  cursor: pointer;
  margin-bottom: 12px;
  user-select: none;
}
.rp-cld-toggle:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; border-radius: var(--radius-md); }
.rp-cld-switch {
  position: relative;
  width: 34px;
  height: 20px;
  border-radius: 999px;
  background: var(--input);
  flex-shrink: 0;
  transition: background 0.15s;
}
.rp-cld-toggle[aria-checked="true"] .rp-cld-switch { background: var(--primary); }
.rp-cld-switch-thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #fff;
  transition: left 0.15s;
}
.rp-cld-toggle[aria-checked="true"] .rp-cld-switch-thumb { left: 16px; }
.rp-cld-toggle-label { color: var(--foreground); }

/* Balance strip */
.rp-cld-balance {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 13px;
  margin: 4px 0 14px;
  padding: 10px 12px;
  background: var(--muted);
  border-radius: var(--radius-md);
}
.rp-cld-balance-label { color: var(--muted-foreground); }
.rp-cld-balance-val { font-weight: 600; }
.rp-cld-balance--warn {
  background: var(--warning-muted);
}
.rp-cld-balance--warn .rp-cld-balance-label,
.rp-cld-balance--warn .rp-cld-balance-val { color: var(--warning-muted-foreground); }

/* «Дополнительно» collapse */
.rp-cld-more {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 10px 0;
  border: 0;
  border-top: 1px solid var(--border);
  background: transparent;
  color: var(--foreground);
  font: inherit;
  font-size: 13.5px;
  font-weight: 500;
  cursor: pointer;
}
.rp-cld-more-caret { color: var(--muted-foreground); font-size: 11px; }
.rp-cld-adv { padding-top: 4px; }

.rp-cld-error {
  font-size: 13px;
  color: var(--destructive);
  margin: 4px 0 12px;
}
.rp-cld-submit {
  width: 100%;
  height: 44px;
  margin-top: 8px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-foreground);
  font: inherit;
  font-size: 14.5px;
  font-weight: 600;
  cursor: pointer;
}
.rp-cld-submit:hover { opacity: 0.92; }
.rp-cld-submit:disabled { opacity: 0.6; cursor: default; }

/* Publish-slots extras */
.rp-psd-hint { font-size: 13px; color: var(--muted-foreground); margin-bottom: 14px; }
.rp-psd-days { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
.rp-psd-day {
  min-width: 40px;
  height: 34px;
  padding: 0 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--muted-foreground);
  font: inherit;
  font-size: 12.5px;
  cursor: pointer;
}
.rp-psd-day--active {
  border-color: var(--primary);
  background: var(--primary);
  color: var(--primary-foreground);
  font-weight: 600;
}

/* ── Task 8 — Занятие entity page (/lesson/{id}, Занятие.dc.html) ─────────
   Self-contained per the codebase's per-feature card convention (rp-balcard/rp-book above don't
   compose .rp-card either) — every visual value here is transplanted 1:1 from the handoff. */
.rp-les { max-width: 640px; margin: 0 auto; }

.rp-les-back {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13.5px;
  font-weight: 500;
  color: var(--muted-foreground);
  text-decoration: none;
  margin-bottom: 16px;
}
.rp-les-back:hover { color: var(--foreground); }

.rp-les-badge { margin-bottom: 16px; }

.rp-les-top {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 8px;
}

.rp-les-charge-note { font-size: 12.5px; color: var(--muted-foreground); }

.rp-les-title {
  font-size: 26px;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin: 0 0 22px;
}

.rp-les-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  box-shadow: var(--shadow-xs);
  padding: 20px 22px;
  margin-bottom: 14px;
}

.rp-les-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}

.rp-les-field {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}

.rp-les-field-icon {
  width: 36px;
  height: 36px;
  border-radius: var(--radius-md);
  background: var(--accent);
  color: var(--accent-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.rp-les-field-icon--avatar {
  border-radius: 50%;
  font-size: 12.5px;
  font-weight: 700;
}

.rp-les-field-icon--muted {
  background: var(--secondary);
  color: var(--muted-foreground);
}

.rp-les-field-text { min-width: 0; }
.rp-les-field-label { font-size: 12px; color: var(--muted-foreground); }
.rp-les-field-value { font-size: 14.5px; font-weight: 600; }

.rp-les-where {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 16px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}

.rp-les-where-text { flex: 1; min-width: 160px; }

.rp-les-join {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 44px;
  padding: 0 24px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-foreground);
  font: inherit;
  font-size: 14.5px;
  font-weight: 600;
  cursor: pointer;
  text-decoration: none;
}
.rp-les-join:disabled { opacity: 0.6; cursor: default; }

.rp-les-hint { font-size: 13px; color: var(--muted-foreground); }

.rp-les-hw-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--muted-foreground);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 10px;
}

.rp-les-hw-row {
  display: flex;
  align-items: center;
  gap: 12px;
}
.rp-les-hw-row + .rp-les-hw-row { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border); }

.rp-les-hw-icon {
  width: 32px;
  height: 32px;
  border-radius: var(--radius-md);
  background: var(--info-muted);
  color: var(--info-muted-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.rp-les-hw-text { flex: 1; min-width: 0; }
.rp-les-hw-title { font-size: 14px; font-weight: 600; }
.rp-les-hw-sub { font-size: 12.5px; color: var(--muted-foreground); margin-top: 1px; }

.rp-les-hw-open {
  font-size: 13px;
  color: var(--primary);
  font-weight: 600;
  text-decoration: none;
  flex-shrink: 0;
}

/* Materials-link footer row inside «К этому занятию» — always present when content is linked (even
   with zero homework blocks), so the card never dead-ends without a path to the lesson's materials. */
.rp-les-materials-row { margin-top: 4px; }
.rp-les-materials-row--divider { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border); }

.rp-les-materials-link {
  display: inline-flex;
  align-items: center;
  font-size: 13px;
  color: var(--primary);
  font-weight: 600;
  text-decoration: none;
}

.rp-les-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
}

.rp-les-cancel {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 40px;
  padding: 0 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--destructive);
  font: inherit;
  font-size: 13.5px;
  font-weight: 500;
  cursor: pointer;
}

.rp-les-cancel-note { font-size: 12.5px; color: var(--muted-foreground); }

.rp-les-summary-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 13.5px;
  padding: 6px 0;
}
.rp-les-summary-row + .rp-les-summary-row { border-top: 1px solid var(--border); }
.rp-les-summary-label { color: var(--muted-foreground); }
.rp-les-summary-value { font-weight: 600; }

.rp-les-note-text { font-size: 13.5px; line-height: 1.55; margin: 0; }

/* Cancel-confirm BbDialog content (mirrors .rp-book's max-width-only override pattern). */
.rp-les-cancel-dialog { max-width: 380px; }
.rp-les-cancel-dialog-title { font-size: 17px; font-weight: 700; margin-bottom: 8px; }
.rp-les-cancel-dialog-msg { font-size: 13.5px; color: var(--muted-foreground); line-height: 1.5; margin: 0 0 18px; }
.rp-les-cancel-dialog-actions { display: flex; gap: 10px; }

.rp-les-cancel-confirm {
  flex: 1;
  height: 40px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--destructive);
  color: var(--destructive-foreground);
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
}

.rp-les-cancel-back {
  flex: 1;
  height: 40px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 13.5px;
  font-weight: 500;
  cursor: pointer;
}

@media (max-width: 480px) {
  .rp-les-title { font-size: 21px; margin-bottom: 16px; }
  .rp-les-card { padding: 16px; }
  .rp-les-grid { grid-template-columns: 1fr; gap: 13px; }
  .rp-les-field-icon { width: 32px; height: 32px; }
  .rp-les-join { width: 100%; }
}

/* ── Задания (/homework) hub layout — Task 9, Задания.dc.html ────────────── */
/* Spacing glue only — the segmented control, rows, chips, and empty state all come free from the
   rp-seg* and rp-asg* blocks above (§13/14/15); this page is their first real consumer. */
.rp-hwh-tabs {
  margin-bottom: 22px;
}

.rp-hwh-section {
  margin-bottom: 24px;
}

/* Uppercase section label above each bucket («К выполнению» / «На проверке» / «Принято» /
   «Назначенные») — same look as rp-pay-label, kept page-scoped per that class's own precedent. */
.rp-hwh-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--muted-foreground);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin: 0 0 10px;
}

@media (max-width: 640px) {
  .rp-hwh-section { margin-bottom: 18px; }
  .rp-hwh-label { font-size: 11px; margin: 0 0 8px; }
}

/* ── Сдача ДЗ (/homework/block/{id}) focus-mode page — Task 10, Сдача ДЗ.dc.html ──────────── */
.rp-hws { min-height: 100vh; }

.rp-hws-header {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  gap: 14px;
  height: 60px;
  padding: 0 24px;
  border-bottom: 1px solid var(--border);
  background: var(--card);
}

.rp-hws-back {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 13.5px;
  font-weight: 500;
  color: var(--muted-foreground);
  text-decoration: none;
  flex-shrink: 0;
}
.rp-hws-back:hover { color: var(--foreground); }

.rp-hws-sep { width: 1px; height: 20px; background: var(--border); flex-shrink: 0; }

.rp-hws-title {
  font-size: 14px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.rp-hws-spacer { flex: 1; min-width: 8px; }

.rp-hws-autosave { font-size: 12.5px; color: var(--muted-foreground); white-space: nowrap; flex-shrink: 0; }
.rp-hws-autosave--error { color: var(--destructive); }
.rp-hws-autosave-short { display: none; }

.rp-hws-content { max-width: 760px; margin: 0 auto; padding: 32px 24px 60px; }

.rp-hws-loading { display: flex; justify-content: center; padding: 48px 0; }

.rp-hws-crumb { font-size: 12.5px; color: var(--muted-foreground); margin-bottom: 6px; }

.rp-hws-title-lg {
  font-size: 24px;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin: 0 0 18px;
}

.rp-hws-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 20px 22px;
  margin-bottom: 18px;
}

.rp-hws-card-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--muted-foreground);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 10px;
}

.rp-hws-textarea {
  width: 100%;
  min-height: 150px;
  padding: 12px 14px;
  border: 1px solid var(--input);
  border-radius: var(--radius-md);
  background: var(--background);
  color: var(--foreground);
  font: inherit;
  font-size: 14.5px;
  line-height: 1.6;
  resize: vertical;
}

.rp-hws-files {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin-top: 12px;
}

.rp-hws-file-token {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 38px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--secondary);
  font-size: 13px;
}

.rp-hws-file-name {
  color: inherit;
  text-decoration: none;
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rp-hws-file-name:hover { text-decoration: underline; }

.rp-hws-file-remove {
  display: inline-flex;
  align-items: center;
  border: 0;
  background: transparent;
  color: var(--muted-foreground);
  cursor: pointer;
  padding: 0;
}
.rp-hws-file-remove:hover { color: var(--destructive); }

.rp-hws-attach {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 38px;
  padding: 0 14px;
  margin-top: 12px;
  border: 1px dashed var(--input);
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--muted-foreground);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
}
.rp-hws-attach-input { display: none; }

.rp-hws-hint { font-size: 12px; color: var(--muted-foreground); margin-top: 6px; }

.rp-hws-cta-row { display: flex; align-items: center; flex-wrap: wrap; gap: 12px; }

.rp-hws-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 44px;
  padding: 0 26px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-foreground);
  font: inherit;
  font-size: 14.5px;
  font-weight: 600;
  cursor: pointer;
}
.rp-hws-cta:disabled { opacity: 0.6; cursor: default; }

.rp-hws-error {
  border: 1px solid color-mix(in srgb, var(--destructive) 35%, var(--border));
  border-radius: var(--radius-md);
  background: var(--destructive-muted);
  color: var(--destructive-muted-foreground);
  padding: 10px 14px;
  font-size: 13.5px;
  margin-bottom: 16px;
}

.rp-hws-info {
  border-radius: var(--radius-md);
  background: var(--info-muted);
  color: var(--info-muted-foreground);
  padding: 10px 14px;
  font-size: 13.5px;
  margin-bottom: 16px;
}

.rp-hws-decision { border-radius: var(--radius-md); padding: 10px 14px; font-size: 13.5px; margin-bottom: 16px; }
.rp-hws-decision--success { background: var(--success-muted); color: var(--success-muted-foreground); }
.rp-hws-decision--error { background: var(--destructive-muted); color: var(--destructive-muted-foreground); }
.rp-hws-decision-title { font-weight: 600; margin-bottom: 2px; }

.rp-hws-feedback {
  border: 1px solid color-mix(in srgb, var(--destructive) 35%, var(--border));
  border-radius: var(--radius-lg);
  background: var(--destructive-muted);
  padding: 14px 16px;
  margin-bottom: 12px;
}

.rp-hws-feedback-head { display: flex; align-items: center; gap: 9px; margin-bottom: 8px; }

.rp-hws-feedback-avatar {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.rp-hws-feedback-title { font-size: 12.5px; font-weight: 700; color: var(--destructive-muted-foreground); }
.rp-hws-feedback-text { font-size: 13.5px; line-height: 1.55; color: var(--destructive-muted-foreground); margin: 0; }

.rp-hws-prev-text { font-size: 13.5px; line-height: 1.6; color: var(--muted-foreground); margin: 0; }

.rp-hws-quiz-q {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 14px 16px;
  margin-bottom: 12px;
}
.rp-hws-quiz-q:last-child { margin-bottom: 0; }

.rp-hws-quiz-prompt { font-size: 14.5px; margin: 0 0 10px; }

.rp-hws-quiz-option {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  padding: 6px 0;
  cursor: pointer;
}
.rp-hws-quiz-option input { width: 16px; height: 16px; accent-color: var(--primary); flex-shrink: 0; }

.rp-hws-quiz-text { min-height: 80px; margin-top: 4px; }

.rp-hws-quiz-result-row { display: flex; align-items: center; gap: 8px; font-size: 14px; }
.rp-hws-quiz-correct { font-size: 13px; color: var(--muted-foreground); margin: 6px 0 0 24px; }

@media (max-width: 640px) {
  .rp-hws-header { height: 56px; padding: 0 12px; gap: 10px; }
  .rp-hws-back-label, .rp-hws-sep { display: none; }
  .rp-hws-back { width: 38px; height: 38px; justify-content: center; }
  .rp-hws-content { padding: 18px 16px 24px; }
  .rp-hws-title-lg { font-size: 20px; margin-bottom: 14px; }
  .rp-hws-card { padding: 16px; }
  .rp-hws-autosave-full { display: none; }
  .rp-hws-autosave-short { display: inline; }
  .rp-hws-cta-row {
    position: sticky;
    bottom: 0;
    margin: 24px -16px -24px;
    padding: 12px 16px 18px;
    border-top: 1px solid var(--border);
    background: var(--card);
  }
  .rp-hws-cta { width: 100%; height: 48px; font-size: 15px; }
}

/* ── Тест (/tests/take/{id}, /placement/{id} alias) focus-mode page — Task 11, Тест.dc.html ─── */
.rp-quiz { min-height: 100vh; }

.rp-quiz-header {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  gap: 14px;
  height: 60px;
  padding: 0 24px;
  border-bottom: 1px solid var(--border);
  background: var(--card);
}

.rp-quiz-back {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 13.5px;
  font-weight: 500;
  color: var(--muted-foreground);
  text-decoration: none;
  flex-shrink: 0;
}
.rp-quiz-back:hover { color: var(--foreground); }

.rp-quiz-sep { width: 1px; height: 20px; background: var(--border); flex-shrink: 0; }

.rp-quiz-title {
  font-size: 14px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.rp-quiz-spacer { flex: 1; min-width: 8px; }

.rp-quiz-counter { font-size: 13px; color: var(--muted-foreground); white-space: nowrap; flex-shrink: 0; }
.rp-quiz-counter b { color: var(--foreground); }
.rp-quiz-counter-short { display: none; }

/* Sticky right below the header so it stays visible on scroll (mirrors the mock's fixed-frame demo
   without needing to lock the whole page into a flex/height-constrained shell). */
.rp-quiz-progress { position: sticky; top: 60px; z-index: 4; height: 4px; background: var(--muted); }
.rp-quiz-progress-fill { height: 100%; background: var(--primary); transition: width .2s ease; }

.rp-quiz-loading { display: flex; justify-content: center; padding: 48px 0; }

.rp-quiz-question { max-width: 680px; margin: 0 auto; padding: 40px 24px 60px; }

.rp-quiz-prompt { font-size: 22px; font-weight: 700; letter-spacing: -0.01em; line-height: 1.4; margin: 0 0 24px; }

.rp-quiz-options { display: flex; flex-direction: column; gap: 10px; margin-bottom: 28px; }

.rp-quiz-option {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  padding: 16px 18px;
  border: 1.5px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 15.5px;
  text-align: left;
  cursor: pointer;
}
.rp-quiz-option--selected { border-color: var(--primary); background: var(--accent); }

.rp-quiz-option-dot {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 1.5px solid var(--input);
  background: transparent;
  color: var(--primary-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.rp-quiz-option-dot--multi { border-radius: var(--radius-sm); }
.rp-quiz-option--selected .rp-quiz-option-dot { border-color: var(--primary); background: var(--primary); }

.rp-quiz-textarea {
  width: 100%;
  min-height: 140px;
  padding: 12px 14px;
  border: 1px solid var(--input);
  border-radius: var(--radius-md);
  background: var(--background);
  color: var(--foreground);
  font: inherit;
  font-size: 14.5px;
  line-height: 1.6;
  resize: vertical;
  margin-bottom: 28px;
}

.rp-quiz-error {
  border: 1px solid color-mix(in srgb, var(--destructive) 35%, var(--border));
  border-radius: var(--radius-md);
  background: var(--destructive-muted);
  color: var(--destructive-muted-foreground);
  padding: 10px 14px;
  font-size: 13.5px;
  margin-bottom: 16px;
}

.rp-quiz-nav { display: flex; align-items: center; gap: 12px; }
.rp-quiz-nav-spacer { flex: 1; }

.rp-quiz-nav-back {
  height: 44px;
  padding: 0 20px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
}
.rp-quiz-nav-back:disabled { opacity: 0.5; cursor: default; }

.rp-quiz-nav-next {
  height: 44px;
  padding: 0 26px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-foreground);
  font: inherit;
  font-size: 14.5px;
  font-weight: 600;
  cursor: pointer;
}
.rp-quiz-nav-next:disabled { opacity: 0.6; cursor: default; }

/* ── Result screen ─────────────────────────────────────────────────────────────────────────── */
.rp-quiz-result {
  max-width: 420px;
  margin: 0 auto;
  padding: 60px 24px;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.rp-quiz-result-ring { position: relative; width: 120px; height: 120px; margin-bottom: 20px; }
.rp-quiz-result-percent {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 28px;
  font-weight: 700;
  letter-spacing: -0.02em;
}

.rp-quiz-result-title { font-size: 19px; font-weight: 700; margin-bottom: 6px; }
.rp-quiz-result-sub { font-size: 13.5px; color: var(--muted-foreground); line-height: 1.55; margin: 0 0 14px; }
.rp-quiz-result-chip { margin-bottom: 14px; }

.rp-quiz-result-actions { display: flex; flex-direction: column; gap: 9px; width: 100%; margin-top: 6px; }

.rp-quiz-result-cta {
  height: 46px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-foreground);
  font: inherit;
  font-size: 14.5px;
  font-weight: 600;
  cursor: pointer;
}
.rp-quiz-result-cta--secondary { background: var(--secondary); color: var(--foreground); }

.rp-quiz-result-link {
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-md);
  color: var(--muted-foreground);
  font-size: 13.5px;
  font-weight: 500;
  text-decoration: none;
}
.rp-quiz-result-link:hover { color: var(--foreground); }

/* Per-question review (existing render carried over from the old MudBlazor page, restyled). */
.rp-quiz-review { width: 100%; text-align: left; margin-top: 20px; }

.rp-quiz-review-q {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 14px 16px;
  margin-bottom: 12px;
}
.rp-quiz-review-q:last-child { margin-bottom: 0; }

.rp-quiz-review-row { display: flex; align-items: flex-start; gap: 8px; font-size: 14px; }
.rp-quiz-review-row svg { flex-shrink: 0; margin-top: 2px; }
.rp-quiz-review-correct { font-size: 13px; color: var(--muted-foreground); margin: 6px 0 0 24px; }

@media (max-width: 640px) {
  .rp-quiz-header { height: 56px; padding: 0 12px; gap: 8px; }
  .rp-quiz-back-label, .rp-quiz-sep { display: none; }
  .rp-quiz-back { width: 38px; height: 38px; justify-content: center; }
  .rp-quiz-title { flex: 1; min-width: 0; }
  .rp-quiz-progress { top: 56px; }
  .rp-quiz-counter-full { display: none; }
  .rp-quiz-counter-short { display: inline; }
  .rp-quiz-question { padding: 24px 16px 24px; }
  .rp-quiz-prompt { font-size: 19px; margin-bottom: 18px; }
  .rp-quiz-option { padding: 15px; gap: 12px; font-size: 15px; }
  .rp-quiz-option-dot { width: 24px; height: 24px; }
  .rp-quiz-nav-back-label { display: none; }
  .rp-quiz-nav {
    position: sticky;
    bottom: 0;
    margin: 24px -16px -24px;
    padding: 12px 16px 18px;
    border-top: 1px solid var(--border);
    background: var(--card);
  }
  .rp-quiz-nav-back { height: 48px; padding: 0 18px; }
  .rp-quiz-nav-next { flex: 1; height: 48px; font-size: 15px; }
}

/* ── Мои курсы (/my-courses) page layout — Task 12, Мои курсы.dc.html ────── */
.rp-mycrs-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}

.rp-mycrs-note {
  margin-top: 18px;
  font-size: 13px;
  color: var(--muted-foreground);
}

.rp-mycrs-note a {
  color: var(--primary);
  font-weight: 500;
  text-decoration: none;
}

@media (max-width: 640px) {
  .rp-mycrs-grid { grid-template-columns: 1fr; gap: 12px; }
}

/* ── Плеер курса + Урок (/my-courses/{id}, /content/{id}) — Task 13, Плеер курса.dc.html ─── */
/* The player is the desktop two-pane surface (wide); the standalone content page stays a single column. */
.rp-plr { max-width: 1200px; margin: 0 auto; }
.rp-plr-content { max-width: 760px; margin: 0 auto; }

/* Desktop two-pane: 300px structure aside (border-right) + inline lesson panel (mock §desktop). */
.rp-plr-body { display: flex; align-items: flex-start; min-height: 0; }
.rp-plr-aside {
  width: 300px;
  flex-shrink: 0;
  border-right: 1px solid var(--border);
  padding: 14px 10px;
  position: sticky;
  top: 72px;
  align-self: flex-start;
  max-height: calc(100vh - 88px);
  overflow-y: auto;
}
.rp-plr-panel { flex: 1; min-width: 0; }
.rp-plr-panel-inner { max-width: 720px; margin: 0 auto; padding: 24px 28px 60px; }

@media (max-width: 768px) {
  /* Mobile two-screen stack: the aside is the whole screen; the inline panel is hidden and a lesson click
     navigates to /content/{id} (the anchor's href — preventDefault is off on narrow). */
  .rp-plr-body { display: block; }
  .rp-plr-aside {
    width: 100%;
    border-right: 0;
    position: static;
    max-height: none;
    overflow-y: visible;
    padding: 8px 0;
  }
  .rp-plr-panel { display: none; }
}

/* header: back · name · progress */
.rp-plr-head {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 22px;
  flex-wrap: wrap;
}

.rp-plr-back {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 13.5px;
  font-weight: 500;
  color: var(--muted-foreground);
  text-decoration: none;
}
.rp-plr-back:hover { color: var(--foreground); }

.rp-plr-head-sep { width: 1px; height: 20px; background: var(--border); }
.rp-plr-name { font-size: 15px; font-weight: 600; color: var(--foreground); }
.rp-plr-spacer { flex: 1; }

.rp-plr-progress { display: inline-flex; align-items: center; gap: 10px; }

/* LessonContentBody's loading state (wave-9 T3 — replaces MudProgressCircular + Mud's d-flex/pa-8 utilities). */
.rp-plr-loading { display: flex; justify-content: center; padding: 32px; }
.rp-plr-progress-bar {
  width: 120px;
  height: 6px;
  border-radius: 999px;
  background: var(--muted);
  overflow: hidden;
}
.rp-plr-progress-fill { height: 100%; border-radius: 999px; background: var(--primary); }
.rp-plr-progress-count { font-size: 12.5px; color: var(--muted-foreground); }

/* structure: modules → lessons */
.rp-plr-mod {
  padding: 14px 4px 4px;
  font-size: 11.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted-foreground);
}
.rp-plr-mod-empty { padding: 4px 10px 8px; font-size: 13px; color: var(--muted-foreground); }

.rp-plr-lesson {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 10px;
  margin-bottom: 1px;
  border-radius: var(--radius-md);
  text-decoration: none;
  color: var(--foreground);
  cursor: pointer;
}
a.rp-plr-lesson:hover { background: var(--secondary); }

.rp-plr-dot {
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 700;
  background: var(--secondary);
  color: var(--muted-foreground);
}
.rp-plr-lesson-title { flex: 1; font-size: 13.5px; font-weight: 500; line-height: 1.35; }

.rp-plr-lesson--done .rp-plr-dot { background: var(--success-muted); color: var(--success-muted-foreground); }

.rp-plr-lesson--current { background: var(--accent); }
.rp-plr-lesson--current .rp-plr-dot { background: var(--primary); color: var(--primary-foreground); }
.rp-plr-lesson--current .rp-plr-lesson-title { font-weight: 600; color: var(--accent-foreground); }

.rp-plr-lesson--locked { opacity: 0.7; cursor: default; color: var(--muted-foreground); }

.rp-plr-badge {
  font-size: 10.5px;
  font-weight: 600;
  padding: 2px 7px;
  border-radius: 999px;
  white-space: nowrap;
  background: var(--warning-muted);
  color: var(--warning-muted-foreground);
}

/* lesson content page */
.rp-plr-preview { margin-bottom: 12px; }
.rp-plr-crumb { font-size: 12.5px; color: var(--muted-foreground); margin-bottom: 6px; }
.rp-plr-lesson-h { font-size: 24px; font-weight: 700; letter-spacing: -0.01em; margin: 0 0 14px; }

.rp-plr-locked-note {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 16px;
  margin: 8px 0 4px;
  border-radius: var(--radius-md);
  background: var(--muted);
  color: var(--muted-foreground);
  font-size: 13.5px;
}

.rp-plr-lesson-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 22px;
}

/* audio pill */
.rp-plr-audio {
  display: flex;
  align-items: center;
  gap: 10px;
  height: 44px;
  padding: 0 14px 0 6px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--card);
  flex: 1;
  max-width: 360px;
}
.rp-plr-audio-btn {
  width: 34px;
  height: 34px;
  flex-shrink: 0;
  border: 0;
  border-radius: 50%;
  background: var(--primary);
  color: var(--primary-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.rp-plr-audio-body { flex: 1; min-width: 0; }
.rp-plr-audio-label { font-size: 12px; font-weight: 600; line-height: 1.2; }
.rp-plr-audio-track {
  height: 4px;
  margin-top: 5px;
  border-radius: 999px;
  background: var(--muted);
  overflow: hidden;
}
.rp-plr-audio-fill { height: 100%; border-radius: 999px; background: var(--primary); }
.rp-plr-audio-time { font-size: 11.5px; color: var(--muted-foreground); font-family: var(--font-mono); flex-shrink: 0; }

/* reader link */
.rp-plr-reader {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 44px;
  padding: 0 16px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--card);
  color: var(--foreground);
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
  flex-shrink: 0;
}
.rp-plr-reader:hover { background: var(--secondary); }

/* content blocks */
.rp-plr-block { margin: 0 0 18px; }
.rp-plr-block.rp-markdown { font-size: 15.5px; line-height: 1.7; }

.rp-plr-video {
  position: relative;
  width: 100%;
  padding-top: 56.25%;
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid var(--border);
}
.rp-plr-video iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

.rp-plr-file {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
}
.rp-plr-file-icon {
  width: 38px;
  height: 38px;
  flex-shrink: 0;
  border-radius: var(--radius-md);
  background: var(--secondary);
  color: var(--muted-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.rp-plr-file-body { flex: 1; min-width: 0; }
.rp-plr-file-name { font-size: 13.5px; font-weight: 600; }
.rp-plr-file-size { font-size: 12px; color: var(--muted-foreground); }
.rp-plr-file-dl {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 36px;
  padding: 0 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font-size: 13px;
  font-weight: 500;
  text-decoration: none;
  flex-shrink: 0;
}
.rp-plr-file-dl:hover { background: var(--secondary); }

/* homework card (DZBlock) */
.rp-plr-dz {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 18px 20px;
  border: 1px solid color-mix(in srgb, var(--primary) 40%, var(--border));
  border-radius: var(--radius-lg);
  background: var(--accent);
}
.rp-plr-dz-icon {
  width: 38px;
  height: 38px;
  flex-shrink: 0;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.rp-plr-dz-body { flex: 1; min-width: 0; }
.rp-plr-dz-title { font-size: 14.5px; font-weight: 700; color: var(--accent-foreground); }
.rp-plr-dz-sub { font-size: 13px; color: var(--accent-foreground); }
.rp-plr-dz-cta {
  height: 38px;
  padding: 0 18px;
  display: inline-flex;
  align-items: center;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-foreground);
  font-size: 13.5px;
  font-weight: 600;
  text-decoration: none;
  flex-shrink: 0;
}
.rp-plr-dz-cta:hover { filter: brightness(0.95); }

/* prev/next nav */
.rp-plr-nav { display: flex; align-items: center; gap: 12px; margin-top: 26px; }
.rp-plr-nav-btn {
  height: 42px;
  padding: 0 18px;
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font-size: 13.5px;
  font-weight: 500;
  text-decoration: none;
  font-family: inherit;  /* the desktop-player prev/next render as <button> (in-place swap) */
  cursor: pointer;
}
.rp-plr-nav-btn:hover { background: var(--secondary); }

@media (max-width: 640px) {
  .rp-plr-reader { width: 42px; padding: 0; justify-content: center; border-radius: 50%; }
  .rp-plr-reader-label { display: none; }
  .rp-plr-lesson-h { font-size: 21px; }
  .rp-plr-dz { flex-wrap: wrap; }
  .rp-plr-dz-cta { width: 100%; justify-content: center; }
}

/* ── Главная ученика (/home/student) — Task 14, Главная ученика.dc.html ─────────────────────────── */

.rp-shome-grid {
  display: grid;
  grid-template-columns: 1.5fr 1fr;
  gap: 16px;
}

/* Shared header row for the two plain rp-card widgets in the grid (assignments + course-resume) —
   uppercase muted label + a trailing text-link, no bottom border (unlike the generic .rp-card-header). */
.rp-shome-card-head {
  display: flex;
  align-items: baseline;
  margin-bottom: 14px;
}

.rp-shome-card-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--muted-foreground);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.rp-shome-card-link {
  margin-left: auto;
  font-size: 12.5px;
  color: var(--primary);
  font-weight: 500;
  text-decoration: none;
}

.rp-shome-assignments {
  padding: 20px;
  display: flex;
  flex-direction: column;
}

@media (max-width: 640px) {
  .rp-shome-grid { grid-template-columns: 1fr; }
}

/* RpNextLessonCard — «Скоро начнётся». Accent-tinted, distinct from the neutral rp-card cards. */
.rp-nlc {
  border: 1px solid color-mix(in srgb, var(--primary) 40%, var(--border));
  border-radius: var(--radius-lg);
  background: var(--accent);
  padding: 20px;
}

.rp-nlc-eyebrow {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  font-weight: 600;
  color: var(--accent-foreground);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 14px;
}

.rp-nlc-row {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}

.rp-nlc-main { flex: 1; min-width: 0; }
.rp-nlc-title { font-size: 17px; font-weight: 600; }
.rp-nlc-sub { font-size: 13.5px; color: var(--accent-foreground); }
.rp-nlc-cta { flex-shrink: 0; }

.rp-nlc-foot {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid color-mix(in srgb, var(--primary) 22%, transparent);
  font-size: 13px;
  color: var(--accent-foreground);
}

.rp-nlc-foot-link {
  color: var(--accent-foreground);
  font-weight: 600;
  text-decoration: none;
}

.rp-nlc-empty {
  font-size: 14px;
  color: var(--accent-foreground);
  margin: 0 0 10px;
}

@media (max-width: 640px) {
  .rp-nlc-row { flex-direction: column; align-items: stretch; }
  .rp-nlc-cta { width: 100%; height: 44px; }
}

/* RpCourseResumeWidget — «Продолжить курс», desktop-only per the mock (dropped below 640px, not just
   visually squeezed — the mobile mock's card list has 3 cards, not 4). Reuses .rp-crs-bar/-bar-fill
   (identical 6px token values) so the progress bar isn't redefined twice. */
.rp-crw {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  box-shadow: var(--shadow-xs);
  padding: 20px;
  display: flex;
  flex-direction: column;
}

.rp-crw-title { font-size: 14.5px; font-weight: 600; margin-bottom: 4px; }
.rp-crw-progress { font-size: 12px; color: var(--muted-foreground); margin-top: 6px; }
.rp-crw-spacer { flex: 1; }
.rp-crw-empty { font-size: 13.5px; color: var(--muted-foreground); margin: 0; }

.rp-crw-cta {
  margin-top: 14px;
  height: 38px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-md);
  background: var(--secondary);
  color: var(--secondary-foreground);
  font-size: 13.5px;
  font-weight: 600;
  text-decoration: none;
}

@media (max-width: 640px) {
  .rp-crw { display: none; }
}

/* ── Чат (/chat) inbox pane — Task 3, wave 2, Чат.dc.html + Чат тьютора.dc.html ──────────────
   Restyles the inbox sidebar (ChatInbox.razor + MessageSearchResults.razor) and the desktop
   no-room-selected placeholder (ChatPage.razor). The conversation pane (rp-convo-, rp-msg- and
   rp-composer- prefixed rules, below) was restyled by Task 4, which also retired chat.css outright.
   Avatars use .rp-chat-avatar* — Task 4 repointed ChatMessage/ChatConversation onto the SAME
   classes (via a size modifier, .rp-msg-avatar, for the smaller 34px in-bubble avatar), so a
   room's avatar looks identical in the inbox row, the conversation header, and message bubbles.
   .rp-chat-inbox is ChatInbox's root; chat.css's mobile show/hide rule now lives on
   .rp-chat-shell/.rp-chat-shell--show-convo (below, Task 4). */
.rp-chat-inbox {
  display: flex;
  flex-direction: column;
  min-height: 0;
  background: var(--card);
  border-right: 1px solid var(--border);
}

.rp-chat-head {
  padding: 14px 14px 10px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.rp-chat-head-row {
  display: flex;
  /* Was baseline (text-only row); the tutor's «Объявление» trigger button (Task 5) needs its own
     box vertically centered against the title text, so switch to center — a plain text sibling
     (rp-chat-unread) looks the same under either alignment. */
  align-items: center;
  gap: 8px;
  margin-bottom: 10px;
}

.rp-chat-title { font-size: 15px; font-weight: 700; }
.rp-chat-unread { font-size: 12px; color: var(--muted-foreground); }

.rp-chat-search {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 36px;
  padding: 0 11px;
  border: 1px solid var(--input);
  border-radius: var(--radius-md);
  background: var(--background);
  color: var(--muted-foreground);
  margin-bottom: 10px;
}

.rp-chat-search input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: transparent;
  font: inherit;
  font-size: 13px;
  color: var(--foreground);
  outline: none;
}

.rp-chat-search-clear {
  display: inline-flex;
  flex-shrink: 0;
  border: 0;
  background: transparent;
  padding: 0;
  color: var(--muted-foreground);
  cursor: pointer;
}
.rp-chat-search-clear:hover { color: var(--foreground); }

/* The segmented control sits in a fixed 320px sidebar regardless of viewport width — unlike
   RpSegmentedTabs' other (full page-width) consumers, stretch every tab to fill it. The base
   .rp-seg-tab's 7px 18px padding (pattern 13, above) left no room for 3 columns at this width —
   the longest label («Непрочитанные») pushed the pill to 65/143/70px and overflowed at ≥768px too.
   Mirror Чат.dc.html's own tab style exactly (flex:1; padding:6px 0; font-size:12.5px) instead —
   same vertical-only-padding + smaller-font recipe already used by the 640px breakpoint below.
   Measured against the real self-hosted Inter font at the sidebar's actual 320px-14px×2=292px
   width: «Все»/«Непрочитанные»/«Объявления» render at ~91/99/91px — short of a literal equal
   third each (flex items won't shrink below their text's min-content width), but every label
   fits on one line with room to spare, matching the mockup's own (non-pixel-equal) result. */
.rp-chat-head .rp-seg { width: 100%; }
.rp-chat-head .rp-seg-tab {
  flex: 1;
  padding: 6px 0;
  font-size: 12.5px;
}

.rp-chat-list { flex: 1; overflow-y: auto; padding: 8px; }

.rp-chat-empty {
  padding: 24px 12px;
  text-align: center;
  font-size: 13px;
  color: var(--muted-foreground);
}

.rp-chat-group-head {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 8px 4px;
  color: var(--muted-foreground);
  cursor: pointer;
}
.rp-chat-group-head > svg { flex-shrink: 0; }
.rp-chat-group-name {
  flex: 1;
  font-size: 12px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rp-chat-group-count { font-size: 11.5px; font-weight: 700; color: var(--primary); }

.rp-chat-row {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  text-align: left;
  padding: 10px;
  border: 0;
  border-radius: var(--radius-md);
  background: transparent;
  font: inherit;
  color: var(--foreground);
  cursor: pointer;
}
.rp-chat-row:hover { background: var(--secondary); }
.rp-chat-row--active,
.rp-chat-row--active:hover { background: var(--accent); }

.rp-chat-avatar {
  width: 40px;
  height: 40px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  font-size: 15px;
  font-weight: 700;
}
.rp-chat-avatar-img { width: 100%; height: 100%; object-fit: cover; border-radius: inherit; display: block; }
/* Kind → shape/colour, per Чат.dc.html: bot = squared primary "Р"; human (Direct) = round accent
   initial; group (GroupLesson) = squared secondary initial (Чат тьютора.dc.html's "Г" card);
   announcement = squared warning-muted megaphone. */
.rp-chat-avatar--bot { border-radius: var(--radius-md); background: var(--primary); color: var(--primary-foreground); }
.rp-chat-avatar--human { border-radius: 50%; background: var(--accent); color: var(--accent-foreground); }
.rp-chat-avatar--group { border-radius: var(--radius-md); background: var(--secondary); color: var(--secondary-foreground); }
.rp-chat-avatar--announce { border-radius: var(--radius-md); background: var(--warning-muted); color: var(--warning-muted-foreground); }

.rp-chat-row-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.rp-chat-row-top { display: flex; align-items: baseline; gap: 6px; }
.rp-chat-row-title {
  font-size: 13.5px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rp-chat-row-title--unread { font-weight: 700; }
.rp-chat-row-muted { display: inline-flex; flex-shrink: 0; color: var(--muted-foreground); }
.rp-chat-row-time { font-size: 11.5px; color: var(--muted-foreground); flex-shrink: 0; }
.rp-chat-row-bottom { display: flex; align-items: center; gap: 6px; }
.rp-chat-row-preview {
  flex: 1;
  font-size: 12.5px;
  color: var(--muted-foreground);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rp-chat-row-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--primary);
  color: var(--primary-foreground);
  font-size: 11px;
  font-weight: 700;
}

.rp-chat-foot { padding: 10px 14px; border-top: 1px solid var(--border); flex-shrink: 0; }
.rp-chat-archive-btn {
  border: 0;
  background: transparent;
  padding: 0;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted-foreground);
  cursor: pointer;
}
.rp-chat-archive-btn:hover { color: var(--foreground); }

/* Debounced server-side message search hits (MessageSearchResults) — reuses .rp-chat-row/-avatar*
   so a hit looks like an ordinary inbox row, plus its own head/empty labels. */
.rp-chat-search-results { padding: 4px 8px 8px; }
.rp-chat-search-results-head { padding: 8px 8px 4px; font-size: 12px; font-weight: 600; color: var(--muted-foreground); }
.rp-chat-search-results-empty { padding: 12px; text-align: center; font-size: 13px; color: var(--muted-foreground); }

/* Desktop empty state: no room selected. .rp-convo-pane (below, Task 4) stays the outer wrapper
   purely so the mobile show/hide mechanic keeps hiding it until a room is picked — only this
   inner placeholder is Task 3's. */
.rp-chat-noroom { flex: 1; display: flex; align-items: center; justify-content: center; }
.rp-chat-noroom-inner { display: flex; flex-direction: column; align-items: center; gap: 12px; color: var(--muted-foreground); }
.rp-chat-noroom-inner svg { opacity: 0.7; }
.rp-chat-noroom-text { font-size: 13.5px; }

@media (max-width: 768px) {
  .rp-chat-avatar { width: 44px; height: 44px; font-size: 16px; }
  .rp-chat-row { padding: 11px 10px; }
}

/* ── Чат (/chat) page shell + conversation pane — Task 4, wave 2, Чат.dc.html ────────────────
   Retires chat.css outright: the two-pane/two-screen page shell (was .chat-shell, .show-convo)
   and the whole conversation pane (was .chat-pane.convo and chat.css's .convo-, .msg-, .composer-
   prefixed rules) move here, onto tokens.css vars directly — no bridge needed, unlike the old
   chat.css block, because the design-system v2 token NAMES (--card, --primary, --secondary,
   --border, --muted-foreground, …)
   already match the ones this file's other rp-* blocks use. Mobile collapse unifies on 768px
   (chat.css used 860px for the shell but bp.css uses 768px everywhere else — T3 review flagged
   the mismatch; this task fixes it). */
.rp-chat-shell {
  display: grid;
  grid-template-columns: var(--chat-inbox-w, 320px) minmax(0, 1fr);
  height: calc(100vh - 64px - 56px); /* topbar 64px + .rp-shell__content padding 28px top + 28px bottom */
  min-height: 480px;
  background: var(--muted);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  overflow: hidden;
}

/* Root of the conversation pane (ChatConversation.razor) AND the desktop no-room-selected
   placeholder's outer wrapper (ChatPage.razor) — kept as one class so the mobile show/hide rule
   below only has to target a single selector. */
.rp-convo-pane {
  background: var(--background);
  display: flex;
  flex-direction: column;
  min-height: 0;
}

/* ---------- Conversation header ---------- */
.rp-convo-head {
  display: flex;
  align-items: center;
  gap: 12px;
  height: 64px;
  padding: 0 20px;
  border-bottom: 1px solid var(--border);
  background: var(--card);
  flex-shrink: 0;
}

/* The back arrow exists only for the collapsed single-pane (mobile) layout — on desktop both
   panes are visible side by side, so it's hidden until the media query below. */
.rp-convo-back {
  display: none;
  width: 36px;
  height: 36px;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--foreground);
  cursor: pointer;
  flex-shrink: 0;
}
.rp-convo-back:hover { background: var(--secondary); }

.rp-convo-titleblock { flex: 1; min-width: 0; }
.rp-convo-name {
  font-size: 14.5px;
  font-weight: 700;
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}
/* Task: wave-2 smoke fix #5 — only the title text truncates; the chip(s) after it (Бот/audience/
   readonly) keep their own flex-shrink:0 below so they never get squeezed out. Without min-width:0
   here a flex item's default min-width:auto blocks the child from shrinking past its content size,
   so the ellipsis never kicks in and the row wraps instead — the bug this fixes. */
.rp-convo-name-text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rp-convo-chip {
  font-size: 10.5px;
  font-weight: 700;
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--info-muted);
  color: var(--info-muted-foreground);
  flex-shrink: 0;
}
.rp-convo-chip--readonly { background: var(--secondary); color: var(--secondary-foreground); }
.rp-convo-sub { font-size: 12px; color: var(--muted-foreground); margin-top: 1px; }

/* BbDropdownMenuTrigger AsChild="false" renders this as the trigger element itself (mirrors
   .rp-tbw-chat) — no separate wrapping <button>. */
.rp-convo-kebab {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border: 0;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--muted-foreground);
  cursor: pointer;
  flex-shrink: 0;
}
.rp-convo-kebab:hover { background: var(--secondary); }

/* In-conversation search navigator — shown when the room was opened from a search hit. Holds the
   query, a "k из N" counter, ↑/↓ to step matches, and ✕. No mockup equivalent (a repo-only
   mechanic layered onto the design); styled on the same tokens as the rest of the pane. */
.rp-convo-searchnav {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 16px;
  background: var(--accent);
  border-bottom: 1px solid var(--border);
  font-size: 13px;
  color: var(--accent-foreground);
}
.rp-convo-searchnav-q { font-weight: 600; max-width: 40%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rp-convo-searchnav-count { color: var(--muted-foreground); }
.rp-convo-searchnav-btns { display: flex; align-items: center; gap: 2px; margin-left: auto; }
.rp-convo-navbtn {
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--foreground);
  cursor: pointer;
}
.rp-convo-navbtn:hover { background: var(--secondary); }
.rp-convo-navbtn:disabled { opacity: 0.35; cursor: default; }
.rp-convo-navbtn--close { margin-left: 4px; }

/* ---------- Message list ---------- */
/* flex:1 + min-height:0 makes this the single scroll region: when the shell is short (mobile
   keyboard open, tiny viewport) the body shrinks and scrolls rather than pushing the fixed
   header/composer past the shell's overflow:hidden edge — which would clip the send button. */
.rp-convo-body { flex: 1; min-height: 0; overflow-y: auto; padding: 20px 0 12px; }
/* min-height: 100% makes .rp-convo-inner fill .rp-convo-body so .rp-convo-empty (place-items:
   center) can vertically centre the spinner/empty text. */
.rp-convo-inner { max-width: 820px; margin: 0 auto; padding: 0 20px; display: flex; flex-direction: column; min-height: 100%; }

.rp-convo-empty { flex: 1; display: flex; align-items: center; justify-content: center; padding: 40px; }
.rp-convo-empty-inner { display: flex; flex-direction: column; align-items: center; gap: 12px; color: var(--muted-foreground); }
.rp-convo-empty-inner svg { opacity: 0.7; }
.rp-convo-empty-text { font-size: 14px; }

.rp-convo-daysep {
  align-self: center;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--muted-foreground);
  background: var(--secondary);
  padding: 3px 12px;
  border-radius: 999px;
  margin: 6px 0 14px;
}

/* ---------- Message row & bubble ---------- */
.rp-msg-row { display: flex; gap: 10px; align-items: flex-start; margin-bottom: 14px; }
.rp-msg-mine { flex-direction: row-reverse; }
.rp-msg-mine .rp-msg-stack { align-items: flex-end; }
.rp-msg-gap { width: 34px; flex-shrink: 0; } /* aligns continuation messages with the 34px avatar grid */
/* Stacks onto the base .rp-chat-avatar (display/centering/flex-shrink + colour/shape modifiers) to
   shrink the in-bubble avatar from the 40px inbox/header size to the 34px grid above; must appear
   after .rp-chat-avatar's own 768px media-query bump (bp.css, pattern above) so equal-specificity
   cascade order keeps message avatars at 34px on mobile too. */
.rp-msg-avatar { width: 34px; height: 34px; font-size: 13px; }

.rp-msg-stack { display: flex; flex-direction: column; gap: 4px; min-width: 0; max-width: min(560px, 80%); }

.rp-msg-author { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--muted-foreground); margin: 0 0 4px; }
.rp-msg-who { font-weight: 600; color: var(--foreground); }
.rp-msg-role { color: var(--muted-foreground); }
.rp-msg-time { color: var(--muted-foreground); font-variant-numeric: tabular-nums; font-size: 11.5px; }

/* Sharp top-LEFT corner points toward the avatar on the left (other-party bubble); the --mine
   modifier flips the sharp corner to top-RIGHT, pointing away from the left-side avatar column. */
.rp-msg-bubble {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 4px var(--radius-lg) var(--radius-lg) var(--radius-lg);
  padding: 11px 14px;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--foreground);
  position: relative;
  /* anywhere (not break-word): break-word leaves the min-content width at the longest word, so a
     long unbreakable token (a pasted URL, a 40-char word) keeps the bubble that wide and overflows
     the column; anywhere folds break opportunities into min-content so the bubble shrinks to the
     column and the token wraps. */
  overflow-wrap: anywhere;
  word-break: break-word;
}
.rp-msg-bubble--mine {
  background: var(--primary);
  color: var(--primary-foreground);
  border: 0;
  border-radius: var(--radius-lg) 4px var(--radius-lg) var(--radius-lg);
}
.rp-msg-bubble--removed { color: var(--muted-foreground); font-style: italic; background: var(--secondary); border-style: dashed; }
.rp-msg-bubble--typing { color: var(--muted-foreground); font-size: 12.5px; padding: 9px 14px; font-style: italic; }

.rp-msg-bubble p { margin: 0; }
.rp-msg-bubble p + p { margin-top: 6px; }
.rp-msg-bubble strong { font-weight: 700; }
.rp-msg-bubble em { font-style: italic; }
.rp-msg-bubble a { color: var(--primary); text-decoration: underline; text-underline-offset: 2px; }
.rp-msg-bubble--mine a { color: inherit; }
.rp-msg-bubble blockquote {
  margin: 8px 0 4px;
  padding: 6px 12px;
  background: var(--secondary);
  border-left: 3px solid var(--border);
  color: var(--secondary-foreground);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  font-size: 13px;
}
/* White alpha (not a token) is intentional: the own-message bubble is always primary-filled in
   BOTH themes, so a translucent-white blockquote reads correctly on it in light and dark alike —
   a theme-flipping token here would fight the fixed primary background. */
.rp-msg-bubble--mine blockquote { background: rgba(255, 255, 255, 0.15); border-left-color: rgba(255, 255, 255, 0.4); color: inherit; }
.rp-msg-bubble ul, .rp-msg-bubble ol { margin: 6px 0 2px; padding-left: 22px; }
.rp-msg-bubble li { margin: 2px 0; }

/* Search-jump highlight — a brief flash on the bubble of the message scrolled to from a search
   hit (or a ↑/↓ step). chat-scroll.js toggles .rp-msg-highlight on the row; the animation runs
   once and decays to transparent so the row settles back into the normal list. */
@keyframes rp-msg-flash {
  0% { background: var(--accent); }
  100% { background: transparent; }
}
.rp-msg-row.rp-msg-highlight .rp-msg-bubble { animation: rp-msg-flash 2s ease-out; }

/* Optimistic-send stub. Translucent bubble + an "Отправляется…" footer; the dimming makes the
   in-flight state visually distinct from a committed message without looking broken. */
.rp-msg-bubble--pending { opacity: 0.65; }
.rp-msg-receipt--pending .rp-spin { width: 14px; height: 14px; }

/* Failed-send stub. Tints the bubble + footer so the user can tell at a glance the send didn't
   go through, while keeping the text legible (it's still the user's real draft). */
.rp-msg-bubble--failed { border: 1px solid var(--destructive); background: var(--destructive-muted); color: var(--destructive-muted-foreground); }
.rp-msg-receipt--failed { color: var(--destructive); }
.rp-msg-dismiss {
  background: transparent;
  border: 0;
  padding: 2px;
  margin-left: 2px;
  cursor: pointer;
  color: inherit;
  display: inline-flex;
  align-items: center;
  border-radius: var(--radius-sm);
}
.rp-msg-dismiss:hover { background: var(--secondary); }

/* Receipt under own messages. check-check is tinted --primary only once every recipient has
   read the message (Чат.dc.html); the single-check "delivered" state stays muted. */
.rp-msg-receipt {
  font-size: 11.5px;
  color: var(--muted-foreground);
  margin-top: 2px;
  font-variant-numeric: tabular-nums;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.rp-msg-receipt svg { color: var(--primary); }
.rp-msg-receipt--unread svg { color: var(--muted-foreground); }

/* Action buttons inside a bot/system message bubble. Rendered below attachments when
   ActionButtons is non-empty; each button is in state active (clickable) or a terminal status
   pill (done / declined / expired / error). Non-target viewers see active buttons disabled via
   CanClick=false (ChatService.ToView). The FIRST active button in a message is styled primary,
   any further one outline — a positional convention (Чат.dc.html's «Записаться» + «Другое
   время»), not a server-driven field. */
.rp-msg-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.rp-msg-action-btn {
  border: 0;
  border-radius: var(--radius-md);
  padding: 7px 16px;
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
}
.rp-msg-action-btn--primary { background: var(--primary); color: var(--primary-foreground); }
.rp-msg-action-btn--primary:hover:not(:disabled) { opacity: 0.92; }
.rp-msg-action-btn--outline { background: var(--card); color: var(--foreground); border: 1px solid var(--border); }
.rp-msg-action-btn--outline:hover:not(:disabled) { background: var(--secondary); }
.rp-msg-action-btn:disabled { opacity: 0.5; cursor: default; }

.rp-msg-status {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border-radius: var(--radius-md);
  font-size: 12.5px;
  font-weight: 600;
}
.rp-msg-status--done { background: var(--success-muted); color: var(--success-muted-foreground); }
.rp-msg-status--muted { background: var(--secondary); color: var(--muted-foreground); }
.rp-msg-status--error { background: var(--destructive-muted); color: var(--destructive-muted-foreground); }

/* Delete affordance on own messages — hover/focus-revealed, in the left gutter beside the bubble.
   Top-anchored (NOT vertical-centered) so the icon lands at the same relative spot regardless of
   bubble height. */
.rp-msg-del {
  position: absolute;
  top: 6px;
  left: -34px;
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--muted-foreground);
  cursor: pointer;
  opacity: 0;
  transition: opacity 120ms, background 120ms, color 120ms;
}
.rp-msg-row:hover .rp-msg-del,
.rp-msg-row:focus-within .rp-msg-del { opacity: 1; }
.rp-msg-del:hover { background: var(--destructive-muted); color: var(--destructive); }

/* Attachment rendering in message bubbles */
.rp-msg-attachment { margin-top: 8px; }
/* Cap on wide screens but never exceed the bubble width — a fixed 320px overflowed the bubble
   (and the shell, which clips) on narrow phones. */
.rp-msg-att-image { max-width: min(320px, 100%); max-height: 320px; border-radius: var(--radius-md); display: block; }
.rp-msg-attachment audio { max-width: 100%; }
.rp-msg-att-file { display: inline-flex; align-items: center; gap: 6px; padding: 6px 10px; border: 1px solid var(--border); border-radius: var(--radius-md); text-decoration: none; color: inherit; max-width: 100%; }
.rp-msg-att-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rp-msg-att-file--pending { color: var(--muted-foreground); }

/* ---------- Composer ---------- */
.rp-composer-wrap { background: var(--card); border-top: 1px solid var(--border); padding: 14px 20px 16px; flex-shrink: 0; }
.rp-composer-inner { max-width: 820px; margin: 0 auto; }

.rp-composer-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 0 0 8px;
  padding: 4px 8px;
  border-radius: var(--radius-md);
  background: var(--secondary);
  color: var(--secondary-foreground);
  font-size: 12.5px;
}
.rp-composer-chip-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 220px; }
.rp-composer-chip-x { border: 0; background: transparent; cursor: pointer; display: inline-flex; color: inherit; }

/* Live Markdown preview panel above the input, rendered through the SAME .rp-msg-bubble tokens
   as a real message — what the user sees here is exactly what gets posted. Height is capped +
   scrolls: without the cap a long draft pushes the input off-screen. */
.rp-composer-preview {
  margin-bottom: 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 10px 12px;
  background: var(--secondary);
  max-height: 180px;
  overflow-y: auto;
  overflow-wrap: anywhere;
}
.rp-composer-preview-label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted-foreground); margin-bottom: 6px; }
.rp-composer-preview-empty { color: var(--muted-foreground); font-size: 13px; }
.rp-composer-preview-bubble { display: inline-block; max-width: 100%; }

.rp-composer-row { display: flex; align-items: flex-end; gap: 10px; }

.rp-composer-attach {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--muted-foreground);
  cursor: pointer;
  flex-shrink: 0;
}
.rp-composer-attach:hover { background: var(--secondary); color: var(--primary); }

.rp-composer-field { flex: 1; min-width: 0; }
/* Plain <textarea>, not RpTextArea/MudTextField — see the component-file comment. rows is set
   from C# (Rows getter) to reproduce auto-grow without JS. */
.rp-composer-textarea {
  /* display:block kills the inline-baseline gap under the textarea (~6px) that pushed the
     field wrapper taller than the 40px attach/send buttons; line-height is a fixed 18px so a
     single line sums to exactly the button height (18 + 2×10 padding + 2×1 border = 40px
     desktop; 18 + 2×12 + 2 = 44px on the ≤768px override). */
  display: block;
  width: 100%;
  min-height: 40px;
  max-height: 160px;
  box-sizing: border-box;
  padding: 10px 14px;
  border: 1px solid var(--input);
  border-radius: var(--radius-md);
  background: var(--background);
  color: var(--foreground);
  font: inherit;
  font-size: 13.5px;
  line-height: 18px;
  resize: none;
  overflow-y: auto;
}
.rp-composer-textarea:focus { outline: none; border-color: var(--primary); box-shadow: var(--shadow-focus); }
.rp-composer-textarea::placeholder { color: var(--muted-foreground); }
.rp-composer-textarea:disabled { opacity: 0.6; }

.rp-composer-send {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-foreground);
  cursor: pointer;
  flex-shrink: 0;
}
.rp-composer-send:hover:not(:disabled) { opacity: 0.92; }
.rp-composer-send:disabled { opacity: 0.4; cursor: not-allowed; }

/* Editor tools (preview toggle + formatting help) live in the foot row below the field — never
   floating over the placeholder. Hidden on mobile with the whole foot (see media query below). */
.rp-composer-foot { margin-top: 8px; display: flex; justify-content: space-between; gap: 12px; font-size: 11.5px; color: var(--muted-foreground); }
.rp-composer-tools { display: flex; align-items: center; gap: 4px; }
.rp-composer-tool {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 24px;
  padding: 0 8px;
  gap: 6px;
  border: 0;
  background: transparent;
  color: var(--muted-foreground);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.rp-composer-tool:hover { background: var(--secondary); color: var(--primary); }
.rp-composer-tool--on { color: var(--primary); background: var(--accent); }
.rp-composer-tool-label { font-size: 11.5px; }

/* Formatting-help popover (MudMenu portal, body-level — outside .rp-chat-shell). Uses the SAME
   global tokens.css vars as everything above, so no bridge is needed even though the portal
   renders outside the shell's DOM subtree. */
.rp-composer-help { padding: 10px 12px; min-width: 230px; }
.rp-composer-help-title { font-weight: 600; font-size: 13px; margin-bottom: 8px; }
.rp-composer-help-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 3px 0; font-size: 12.5px; }
.rp-composer-help-row code { background: var(--secondary); color: var(--secondary-foreground); padding: 1px 6px; border-radius: var(--radius-sm); font-size: 12px; }
.rp-composer-help-row span { color: var(--muted-foreground); }
.rp-composer-help-foot { margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--border); font-size: 11.5px; color: var(--muted-foreground); }

/* Read-only stand-in for the composer in announcement rooms (recipients cannot reply). */
.rp-composer-disabled {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 16px 20px;
  border-top: 1px solid var(--border);
  background: var(--card);
  color: var(--muted-foreground);
  font-size: 13px;
  flex-shrink: 0;
}

/* ---------- Responsive: collapse to a single pane on narrow viewports ----------
   Below 768px the inbox and the conversation stack into one column; ChatPage adds
   .rp-chat-shell--show-convo once a room is selected so only the active pane is visible. The
   open pane fills the screen, so the conversation grows a back arrow to return to the list. */
@media (max-width: 768px) {
  .rp-chat-shell {
    /* minmax(0, 1fr) — NOT a bare 1fr (== minmax(auto, 1fr)): the auto minimum is the column's
       min-content, so a long unbreakable word or a fixed-width attachment expands the single
       column past the container, and .rp-chat-shell's overflow:hidden then CLIPS the right edge —
       the send button and message content get cut off. The 0 minimum lets the column shrink to
       the viewport so content wraps instead. */
    grid-template-columns: minmax(0, 1fr);
    /* 100vh on mobile is measured against the LARGEST viewport (URL bar retracted), so the
       composer ends up under the browser chrome; 100dvh tracks the visible height live. Subtract
       the mobile top-bar (56px) + the mobile content padding (18px top + 90px bottom reserved for
       the bottom nav). min-height:0 drops the 480px desktop floor that would otherwise overflow
       short phone screens. */
    height: calc(100dvh - 56px - 108px);
    min-height: 0;
  }
  .rp-chat-shell .rp-convo-pane { display: none; }
  .rp-chat-shell.rp-chat-shell--show-convo .rp-chat-inbox { display: none; }
  .rp-chat-shell.rp-chat-shell--show-convo .rp-convo-pane { display: flex; }

  /* Show the back arrow and give header controls finger-sized hit targets; shrink the header to
     the mockup's 60px mobile height. */
  .rp-convo-back { display: inline-flex; }
  .rp-convo-head { height: 60px; padding: 0 12px; gap: 10px; }
  .rp-convo-kebab { width: 36px; height: 36px; }

  /* Task: wave-2 smoke fix #5 — the tutor channel's «Новое объявление» button doesn't fit next to
     a title+chip at 390px; swap to the mockup's compact «Объявление» label instead of hiding the
     text entirely (an icon-only button would need a new icon this component doesn't have yet —
     the least invasive fix reuses the existing text, just shorter). */
  .rp-convo-newann { padding: 0 11px; }
  .rp-convo-newann-full { display: none; }
  .rp-convo-newann-short { display: inline; }

  /* Reclaim horizontal space eaten by the desktop gutters. */
  .rp-convo-inner { padding: 0 14px; }
  .rp-msg-stack { max-width: 86%; }

  /* Action buttons stack full-width per the mockup's phone-2 screen. */
  .rp-msg-actions { flex-direction: column; }
  .rp-msg-action-btn { width: 100%; height: 44px; }
  .rp-msg-status { width: 100%; height: 42px; justify-content: center; }

  .rp-composer-wrap { padding: 10px 12px 14px; }
  .rp-composer-attach, .rp-composer-send { width: 44px; height: 44px; }
  .rp-composer-textarea { min-height: 44px; padding: 12px 13px; }
  .rp-composer-disabled { padding: 14px 12px; }

  /* Drop the markdown/Enter hints — they wrap to two lines on a phone and steal the vertical
     room the composer needs when the on-screen keyboard is open. */
  .rp-composer-foot { display: none; }
}

/* ── Task 5, wave 2 — announcement compose (ОВ-2а, «Чат тьютора.dc.html») ──────────────────
   The inbox-header trigger button lives in ChatInbox's .rp-chat-head-row (rp-chat*, Task 3);
   everything else here belongs to AnnouncementComposeDialog's BbDialogContent (Class="rp-anncmp"). */

/* Portal z-index rules live in ONE consolidated block — «Portal stacking ladder» at the end of
   this file. (A wave-2 `.blazorblueprint-portal { z-index: 250 }` rule used to sit here; the
   portal wrapper is display:contents — it generates no box, so that rule was a silent no-op.) */

.rp-anncmp-trigger {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 32px;
  padding: 0 12px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-foreground);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  flex-shrink: 0;
}

.rp-anncmp { max-width: 520px; }

/* Hidden by default — shown only in the ≤600px bottom-sheet variant below. */
.rp-anncmp-grabber {
  display: none;
  width: 40px;
  height: 4px;
  border-radius: 999px;
  background: var(--border);
  margin: 0 auto 14px;
}

.rp-anncmp-head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 16px;
}

.rp-anncmp-icon {
  width: 34px;
  height: 34px;
  border-radius: var(--radius-md);
  background: var(--warning-muted);
  color: var(--warning-muted-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.rp-anncmp-title { font-size: 16px; font-weight: 700; flex: 1; }

.rp-anncmp-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border: 0;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--muted-foreground);
  cursor: pointer;
  flex-shrink: 0;
}
.rp-anncmp-close:hover { background: var(--secondary); }

.rp-anncmp-label {
  display: block;
  font-size: 12.5px;
  font-weight: 600;
  margin-bottom: 6px;
}
.rp-anncmp-label-hint { font-weight: 500; color: var(--muted-foreground); }

.rp-anncmp-input {
  display: block;
  width: 100%;
  height: 40px;
  padding: 0 12px;
  border: 1px solid var(--input);
  border-radius: var(--radius-md);
  background: var(--background);
  font: inherit;
  font-size: 13.5px;
  color: var(--foreground);
  outline: none;
  margin-bottom: 4px;
}

.rp-anncmp-textarea {
  display: block;
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--input);
  border-radius: var(--radius-md);
  background: var(--background);
  font: inherit;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--foreground);
  outline: none;
  resize: vertical;
  margin-bottom: 4px;
}

.rp-anncmp-input.invalid,
.rp-anncmp-textarea.invalid { border-color: var(--destructive); }

.rp-anncmp-err {
  display: block;
  font-size: 12px;
  color: var(--destructive);
  margin: 0 0 10px;
}

/* Segmented audience toggle sits full-width inside the dialog, same override recipe as .rp-chat-head. */
.rp-anncmp .rp-seg { width: 100%; margin-bottom: 14px; }

.rp-anncmp-preview {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12.5px;
  color: var(--muted-foreground);
  margin-bottom: 14px;
}
.rp-anncmp-preview b { color: var(--foreground); }

.rp-anncmp-limit {
  font-size: 12.5px;
  background: var(--warning-muted);
  color: var(--warning-muted-foreground);
  border-radius: var(--radius-md);
  padding: 9px 12px;
  margin-bottom: 14px;
}

.rp-anncmp-err-banner {
  font-size: 13px;
  background: var(--destructive-muted);
  color: var(--destructive-muted-foreground);
  border-radius: var(--radius-md);
  padding: 10px 12px;
  margin-bottom: 14px;
}

.rp-anncmp-actions {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
}

.rp-anncmp-cancel {
  height: 40px;
  padding: 0 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
}

.rp-anncmp-submit {
  height: 40px;
  padding: 0 20px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-foreground);
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
}
.rp-anncmp-submit:disabled { opacity: 0.6; cursor: default; }

/* Mobile bottom-sheet variant: same BbDialogContent, repositioned + full-width. Overrides the
   library's own centering (fixed + translate(-50%,-50%)) — !important mirrors the codebase's one
   other defensive override of a Blueprint component's own inline sizing (.rp-tbw-profile__avatar).
   BbDialogContent centers via the Tailwind v4 utilities `left-[50%] translate-x-[-50%]
   translate-y-[-50%]`; in Tailwind v4 translate-* compiles to the standalone CSS `translate`
   property, NOT into `transform` (`transform: none` here is a defensive no-op left for whatever
   else sets it, not the fix) — without also resetting `translate` the sheet keeps shifting -50%
   of its own width left from `left: 0`, landing at x ≈ -195px on a 390px viewport (off-screen). */
@media (max-width: 600px) {
  .rp-anncmp {
    position: fixed !important;
    top: auto !important;
    left: 0 !important;
    right: 0 !important;
    bottom: 0 !important;
    transform: none !important;
    translate: none !important;
    width: 100% !important;
    max-width: 100% !important;
    margin: 0 !important;
    border-radius: var(--radius-2xl) var(--radius-2xl) 0 0 !important;
    /* Dialog panels stack above the bottom nav via the global «Portal stacking ladder» (end of
       file), so the sheet only needs safe-area clearance, not a 74px band for the nav. */
    padding: 10px 18px calc(16px + env(safe-area-inset-bottom, 0px));
  }
  .rp-anncmp-grabber { display: block; }
  .rp-anncmp-close { display: none; }
  .rp-anncmp-cancel { display: none; }
  .rp-anncmp-submit { width: 100%; height: 48px; font-size: 14.5px; }
}

/* ── Task 6, wave 2 — announcement history tab + tutor channel meta (Чат тьютора.dc.html) ─────
   Two surfaces: (1) AnnouncementHistoryList, the ChatInbox «Объявления» tab body — a plain list of
   sent-broadcast cards inside .rp-chat-list, so it needs no scroll/pane rules of its own; (2) the
   tutor's per-message meta line inside the announcement conversation, replacing .rp-msg-receipt on
   their own bubble. The conversation header's audience chip and the daily-budget footer are
   deliberately NOT new classes — .rp-convo-chip (already info-muted, matching the mockup's "Вся
   площадка" pill) and .rp-composer-disabled (already the right flex/border/typography for a
   centered footer notice) are reused as-is; only .rp-convo-newann (the header's outline «Новое
   объявление» button) is new. */
.rp-annh-head { padding: 8px 8px 4px; font-size: 12px; font-weight: 600; color: var(--muted-foreground); }

.rp-annh-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  padding: 11px 12px;
  margin: 0 0 8px;
}

.rp-annh-row-top { display: flex; align-items: baseline; gap: 8px; }
.rp-annh-title {
  font-size: 13.5px;
  font-weight: 600;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rp-annh-date { font-size: 11.5px; color: var(--muted-foreground); flex-shrink: 0; }

.rp-annh-preview {
  font-size: 12.5px;
  color: var(--muted-foreground);
  margin: 3px 0 8px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.rp-annh-row-bottom { display: flex; align-items: center; gap: 10px; }
.rp-annh-chip { font-size: 12px; font-weight: 600; padding: 2px 9px; border-radius: 999px; }
.rp-annh-chip--partial { background: var(--info-muted); color: var(--info-muted-foreground); }
.rp-annh-chip--all { background: var(--success-muted); color: var(--success-muted-foreground); }
.rp-annh-audience { font-size: 12px; color: var(--muted-foreground); }
.rp-annh-revoke {
  border: 0;
  background: transparent;
  padding: 0;
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--destructive);
  cursor: pointer;
}
.rp-annh-revoke:hover { opacity: 0.8; }
.rp-annh-revoke:disabled { opacity: 0.5; cursor: default; }

.rp-annh-empty { padding: 24px 12px; text-align: center; color: var(--muted-foreground); }
.rp-annh-empty-text { font-size: 13px; margin-bottom: 4px; }
.rp-annh-empty-hint { font-size: 12px; }

/* Conversation header: tutor-only «Новое объявление» outline button, replacing the kebab menu
   (announcement rooms have no mute/archive actions of their own — see ChatConversation.razor). */
.rp-convo-newann {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 34px;
  padding: 0 14px;
  border: 1px solid var(--primary);
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--primary);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  flex-shrink: 0;
}
.rp-convo-newann:hover { background: var(--accent); }
/* Full label by default; the ≤768px media query below swaps in the mockup's compact «Объявление». */
.rp-convo-newann-short { display: none; }

/* Tutor's per-message meta line, under their own announcement bubble — reuses .rp-msg-receipt for
   the "прочитано N из M" segment (same check-check icon/tabular figures as every other receipt);
   only the surrounding flex row + the destructive revoke text-button are new. */
.rp-msg-annmeta {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 11.5px;
  color: var(--muted-foreground);
  margin-top: 4px;
}
.rp-msg-annmeta .rp-msg-receipt { margin-top: 0; }
.rp-msg-annmeta-revoke {
  border: 0;
  background: transparent;
  padding: 0;
  font: inherit;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--destructive);
  cursor: pointer;
}
.rp-msg-annmeta-revoke:hover { opacity: 0.8; }

/* ── rp-notif* (Task 7, wave 2 — /settings/notifications: Уведомления.dc.html) ───────────────
   Push status card + a 4-column event matrix (Событие/Чат/Email/Push) that collapses to one
   card per event ≤600px. Chat is a static check, never a switch — the channel is mandatory by
   product rule. Email/Push cells use NotifChannelSwitch.razor, a bespoke 40×23 pill switch (see
   that component's doc comment for why it isn't BbSwitch). Both the desktop matrix and the
   mobile cards always render; this media query is the only thing that picks between them, same
   idiom as rp-payrow-desktop/rp-payrow-cards. */
.rp-notif-push {
  display: flex;
  align-items: center;
  gap: 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 14px 18px;
  margin-bottom: 18px;
}

.rp-notif-push-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-md);
  flex-shrink: 0;
}

.rp-notif-push-icon--on  { background: var(--success-muted); color: var(--success-muted-foreground); }
.rp-notif-push-icon--off { background: var(--secondary);     color: var(--muted-foreground); }

.rp-notif-push-body { flex: 1; min-width: 0; }
.rp-notif-push-title { font-size: 14px; font-weight: 600; }
.rp-notif-push-sub   { font-size: 12.5px; color: var(--muted-foreground); }

.rp-notif-push-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 36px;
  padding: 0 16px;
  border-radius: var(--radius-md);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  flex-shrink: 0;
}
.rp-notif-push-btn:disabled { opacity: 0.7; cursor: not-allowed; }

.rp-notif-push-btn--primary {
  border: 0;
  background: var(--primary);
  color: var(--primary-foreground);
}

.rp-notif-push-btn--outline {
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--foreground);
}

/* Spinner inside a push button picks up the button's own text colour instead of the global
   .rp-spin default (which is tuned for --primary-foreground and would be invisible on the
   outline variant's --foreground text). */
.rp-notif-push-btn .rp-spin {
  border-color: color-mix(in srgb, currentColor 40%, transparent);
  border-top-color: currentColor;
}

.rp-notif-loading {
  display: flex;
  justify-content: center;
  padding: 24px 0;
}
.rp-notif-loading .rp-spin {
  border-color: color-mix(in srgb, var(--muted-foreground) 30%, transparent);
  border-top-color: var(--muted-foreground);
}

/* Desktop matrix. */
.rp-notif-matrix {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  overflow: hidden;
}

.rp-notif-matrix-head,
.rp-notif-matrix-row {
  display: grid;
  grid-template-columns: 1fr 84px 84px 84px;
  align-items: center;
  gap: 8px;
  padding: 12px 18px;
}

.rp-notif-matrix-head {
  padding: 11px 18px;
  background: var(--muted);
  border-bottom: 1px solid var(--border);
}

.rp-notif-matrix-head span {
  font-size: 12px;
  font-weight: 600;
  color: var(--muted-foreground);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.rp-notif-matrix-row + .rp-notif-matrix-row {
  border-top: 1px solid var(--border);
}

.rp-notif-col-center { display: flex; justify-content: center; }

.rp-notif-row-label {
  font-size: 13.5px;
  font-weight: 600;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.rp-notif-chat { display: inline-flex; color: var(--success); }

.rp-notif-push-note {
  font-size: 12.5px;
  color: var(--muted-foreground);
  margin: 10px 2px 0;
}

/* Bespoke pill switch — 40×23 track, 18px knob (NotifChannelSwitch.razor). The knob stays
   literal white in both themes, matching the mockup exactly (a switch thumb, unlike every other
   surface here, isn't meant to tint with dark mode). */
.rp-notif-switch {
  position: relative;
  width: 40px;
  height: 23px;
  border: 0;
  border-radius: 999px;
  background: var(--input);
  padding: 0;
  cursor: pointer;
  flex-shrink: 0;
  transition: background 0.15s;
}

.rp-notif-switch[aria-checked="true"] { background: var(--primary); }

/* A bespoke <button role="switch"> has no native focus ring — restore a visible keyboard focus
   indicator (a11y: keyboard users must see which switch is focused before toggling). */
.rp-notif-switch:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }

.rp-notif-switch:disabled,
.rp-notif-switch--disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

.rp-notif-switch-thumb {
  position: absolute;
  top: 2.5px;
  left: 3px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #fff;
  box-shadow: var(--shadow-sm);
  transition: left 0.15s;
}

.rp-notif-switch[aria-checked="true"] .rp-notif-switch-thumb { left: 19px; }

/* Mobile card-per-event — hidden by default, shown ≤600px (the mockup's own breakpoint; this
   screen has no wide table to begin with, so it doesn't share the 640px rp-payrow-cards value). */
.rp-notif-cards {
  display: none;
  flex-direction: column;
  gap: 10px;
}

.rp-notif-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 13px 14px;
}

.rp-notif-card-label { font-size: 13.5px; font-weight: 600; }

.rp-notif-card-row {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  margin-top: 10px;
}

.rp-notif-card-chat {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12.5px;
  color: var(--muted-foreground);
}
.rp-notif-card-chat .rp-notif-chat { width: 15px; height: 15px; }

.rp-notif-card-spacer { flex: 1; }

.rp-notif-card-toggle {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 12.5px;
  color: var(--muted-foreground);
}

@media (max-width: 600px) {
  .rp-notif-matrix    { display: none; }
  .rp-notif-push-note { display: none; }
  .rp-notif-cards     { display: flex; }
}

/* ── Главная тьютора (/home/tutor) — wave 3 Task 4, Главная тьютора.dc.html ─────────────────────
   Two DOM trees toggled by the shell's 768px breakpoint (.rp-th-desktop / .rp-th-mobile), not one
   grid reflowed by CSS: the mobile screen genuinely restructures the day (a single hero lesson +
   compact rows + a one-line grading summary) rather than just narrowing the desktop card. Both trees
   read the same TutorHome.TutorState — no duplicated business logic, only markup. */

.rp-th-head {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: 14px;
  margin-bottom: 22px;
}

.rp-th-head .rp-ph { flex: 1; }

.rp-th-actions {
  display: flex;
  gap: 8px;
  flex-shrink: 0;
}

.rp-th-btn {
  height: 38px;
  padding: 0 15px;
  border-radius: var(--radius-md);
  font-size: 13.5px;
  font-weight: 600;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  border: 0;
  cursor: pointer;
  font-family: inherit;
}

.rp-th-btn--primary { background: var(--primary); color: var(--primary-foreground); }

.rp-th-btn--outline {
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--foreground);
  font-weight: 500;
}

@media (max-width: 768px) {
  .rp-th-actions { display: none; }
}

/* Desktop grid — hidden entirely on mobile (see file-header rationale). */
.rp-th-grid {
  display: grid;
  grid-template-columns: 1.6fr 1fr;
  gap: 16px;
  align-items: start;
}

.rp-th-col-main, .rp-th-col-rail {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.rp-th-link {
  font-size: 12.5px;
  color: var(--primary);
  font-weight: 600;
  text-decoration: none;
}

.rp-th-badge {
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--warning-muted);
  color: var(--warning-muted-foreground);
  font-size: 12px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* «Сегодня» card rows */
.rp-th-today-row {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 13px 18px;
  border-bottom: 1px solid var(--border);
}

.rp-th-today-row:last-child { border-bottom: 0; }

.rp-th-today-row--live { background: color-mix(in srgb, var(--success-muted) 45%, transparent); }

.rp-th-today-time { width: 52px; flex-shrink: 0; }
.rp-th-today-time-val { font-size: 14px; font-weight: 700; }
.rp-th-today-time--live .rp-th-today-time-val { color: var(--foreground); }
.rp-th-today-time-dur { font-size: 11px; color: var(--muted-foreground); }

.rp-th-today-bar {
  width: 3px;
  align-self: stretch;
  border-radius: 2px;
  background: var(--border);
}

.rp-th-today-bar--live { background: var(--success); }
.rp-th-today-bar--planned { background: var(--primary); }

.rp-th-today-body { flex: 1; min-width: 0; }
.rp-th-today-who { font-size: 13.5px; font-weight: 600; }
.rp-th-today-what { font-size: 12.5px; color: var(--muted-foreground); }

.rp-th-live-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 34px;
  padding: 0 13px;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-foreground);
  font-size: 12.5px;
  font-weight: 600;
  text-decoration: none;
  flex-shrink: 0;
}

.rp-th-live-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #7EE2A8;
  flex-shrink: 0;
}

.rp-th-today-empty {
  padding: 20px 18px;
  font-size: 13.5px;
  color: var(--muted-foreground);
}

.rp-th-today-foot {
  padding: 11px 18px;
  font-size: 12.5px;
  color: var(--muted-foreground);
}

/* «На проверке» grading queue rows */
.rp-th-grading-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 18px;
  border-bottom: 1px solid var(--border);
  text-decoration: none;
  color: var(--foreground);
}

.rp-th-grading-row:last-child { border-bottom: 0; }
.rp-th-grading-row:hover { background: var(--secondary); }

.rp-th-grading-avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 600;
  flex-shrink: 0;
}

.rp-th-grading-body { flex: 1; min-width: 0; }
.rp-th-grading-name { font-size: 13.5px; font-weight: 600; }

.rp-th-grading-task {
  font-size: 12.5px;
  color: var(--muted-foreground);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.rp-th-grading-age {
  font-size: 12px;
  font-weight: 500;
  color: var(--muted-foreground);
  flex-shrink: 0;
}

.rp-th-grading-age--warn { color: var(--warning-muted-foreground); }

.rp-th-grading-empty {
  padding: 20px 18px;
  font-size: 13.5px;
  color: var(--muted-foreground);
}

/* «Новая заявка» card — shared markup between the desktop rail and the mobile stream. */
.rp-th-request {
  border: 1px solid color-mix(in srgb, var(--primary) 35%, var(--border));
  border-radius: var(--radius-lg);
  background: var(--info-muted);
  padding: 16px 18px;
}

.rp-th-request-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 6px;
  color: var(--info-muted-foreground);
}

.rp-th-request-title { font-size: 13.5px; font-weight: 700; color: var(--info-muted-foreground); }
.rp-th-request-name { font-size: 13.5px; font-weight: 600; }
.rp-th-request-note { font-size: 12.5px; color: var(--info-muted-foreground); margin: 2px 0 12px; }

.rp-th-request-actions { display: flex; gap: 8px; }

.rp-th-request-accept {
  flex: 1;
  height: 34px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-foreground);
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
}

.rp-th-request-decline {
  height: 34px;
  padding: 0 12px;
  border: 1px solid color-mix(in srgb, var(--primary) 35%, var(--border));
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--info-muted-foreground);
  font-size: 12.5px;
  font-weight: 500;
  cursor: pointer;
  font-family: inherit;
}

/* «Закончился баланс» rows */
.rp-th-debtor-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 18px;
  border-bottom: 1px solid var(--border);
}

.rp-th-debtor-row:last-child { border-bottom: 0; }

.rp-th-debtor-avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--destructive-muted);
  color: var(--destructive-muted-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 600;
  flex-shrink: 0;
}

.rp-th-debtor-body { flex: 1; }
.rp-th-debtor-name { font-size: 13.5px; font-weight: 600; }
.rp-th-debtor-note { font-size: 12px; color: var(--destructive-muted-foreground); }

.rp-th-debtor-remind {
  font-size: 12.5px;
  color: var(--primary);
  font-weight: 600;
  flex-shrink: 0;
  background: none;
  border: 0;
  cursor: pointer;
  font-family: inherit;
  padding: 0;
}

.rp-th-debtor-foot {
  padding: 11px 18px;
  font-size: 12px;
  color: var(--muted-foreground);
  line-height: 1.5;
}

/* «Эта неделя» card — its content sits directly inside .rp-card (no .rp-card-header/-body
   wrappers), and .rp-card itself carries no padding, so the card pads itself. */
.rp-th-week { padding: 16px 18px; }

.rp-th-week-title { font-size: 14.5px; font-weight: 700; margin-bottom: 12px; }

.rp-th-week-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

.rp-th-week-num { font-size: 20px; font-weight: 700; }
.rp-th-week-label { font-size: 12px; color: var(--muted-foreground); }

/* Mobile stream — hidden on desktop (see file-header rationale). */
.rp-th-mobile { display: none; }

@media (max-width: 768px) {
  .rp-th-desktop { display: none; }
  .rp-th-mobile { display: flex; flex-direction: column; gap: 10px; }
}

.rp-th-mhero {
  border: 1px solid var(--border);
  border-left: 4px solid var(--success);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 14px 16px;
}

.rp-th-mhero-top { display: flex; align-items: center; gap: 8px; }
.rp-th-mhero-time { font-size: 14.5px; font-weight: 700; }

.rp-th-mhero-soon {
  font-size: 11px;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--success-muted);
  color: var(--success-muted-foreground);
}

.rp-th-mhero-who { font-size: 14px; font-weight: 600; margin-top: 4px; }

.rp-th-mhero-btn {
  margin-top: 12px;
  height: 44px;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-foreground);
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
}

.rp-th-mcompact {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 12px 16px;
  display: flex;
  align-items: center;
  gap: 12px;
}

.rp-th-mcompact-time { width: 52px; flex-shrink: 0; }
.rp-th-mcompact-body { flex: 1; min-width: 0; }

.rp-th-mgrading-link {
  display: flex;
  align-items: center;
  gap: 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 14px 16px;
  text-decoration: none;
  color: var(--foreground);
}

.rp-th-mgrading-icon {
  width: 36px;
  height: 36px;
  border-radius: var(--radius-md);
  background: var(--warning-muted);
  color: var(--warning-muted-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.rp-th-mgrading-body { flex: 1; min-width: 0; }
.rp-th-mgrading-title { font-size: 14px; font-weight: 600; }
.rp-th-mgrading-sub { font-size: 12px; color: var(--muted-foreground); }
.rp-th-mgrading-chev { color: var(--muted-foreground); }

.rp-th-mempty {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 14px 16px;
  font-size: 13.5px;
  color: var(--muted-foreground);
}

/* ── Task 7 (wave 3): «Ученики» hub — /students. Roster table + cards, groups grid, invitations
   list, filters. Dialog chrome is reused from rp-sched-dlg* (see header note); this block is
   students-specific layout only. Single mobile switch at 640px mirrors rp-tabs-underline/chips. */
.rp-stu-toolbar {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin-bottom: 16px;
}
.rp-stu-toolbar .rp-ph { margin-bottom: 0; }
.rp-stu-toolbar-spacer { flex: 1; }
.rp-stu-btn {
  display: inline-flex;
  align-items: center;
  height: 36px;
  padding: 0 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
}
.rp-stu-btn:hover { background: var(--secondary); }
.rp-stu-btn--primary { border: 0; background: var(--primary); color: var(--primary-foreground); font-weight: 600; }
.rp-stu-btn--primary:hover { background: var(--primary); opacity: 0.92; }

.rp-stu-panel { padding-top: 20px; }

/* filters row (Ученики tab) */
.rp-stu-filters { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; flex-wrap: wrap; }
.rp-stu-search {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 36px;
  padding: 0 12px;
  border: 1px solid var(--input);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--muted-foreground);
  width: 260px;
  max-width: 100%;
}
.rp-stu-search-input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: transparent;
  color: var(--foreground);
  font: inherit;
  font-size: 13px;
  outline: none;
}
.rp-stu-filter {
  height: 36px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 12.5px;
  cursor: pointer;
}

/* roster table (desktop) */
.rp-stu-table {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  overflow: hidden;
}
.rp-stu-thead,
.rp-stu-row {
  display: grid;
  grid-template-columns: 2fr 1fr 1.4fr 1.3fr 40px;
  gap: 12px;
  align-items: center;
  padding: 12px 18px;
  border-bottom: 1px solid var(--border);
}
.rp-stu-thead--archived,
.rp-stu-row--archived { grid-template-columns: 2fr 1fr auto; }
.rp-stu-thead {
  font-size: 11.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted-foreground);
}
.rp-stu-row { text-decoration: none; color: var(--foreground); }
.rp-stu-row:last-child { border-bottom: 0; }
a.rp-stu-row:hover { background: var(--secondary); }
.rp-stu-row--pending { background: color-mix(in srgb, var(--info-muted) 30%, transparent); }
.rp-stu-user { display: flex; align-items: center; gap: 11px; min-width: 0; }
.rp-stu-avatar {
  width: 34px;
  height: 34px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 12.5px;
  font-weight: 600;
}
.rp-stu-name { font-size: 13.5px; font-weight: 600; }
.rp-stu-muted { font-size: 12.5px; color: var(--muted-foreground); }
.rp-stu-chev { color: var(--muted-foreground); text-align: right; }
.rp-stu-bal {
  display: inline-block;
  font-size: 12px;
  font-weight: 600;
  padding: 3px 10px;
  border-radius: 999px;
}
.rp-stu-bal--danger  { background: var(--destructive-muted); color: var(--destructive-muted-foreground); }
.rp-stu-bal--warning { background: var(--warning-muted);     color: var(--warning-muted-foreground); }
.rp-stu-bal--success { background: var(--success-muted);     color: var(--success-muted-foreground); }
.rp-stu-rowact { display: flex; align-items: center; justify-content: flex-end; gap: 8px; }
.rp-stu-pending-actions { display: flex; gap: 8px; }
.rp-stu-pact {
  height: 30px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 12.5px;
  cursor: pointer;
  white-space: nowrap;
}
.rp-stu-pact:disabled { opacity: 0.6; cursor: default; }
.rp-stu-pact--accept { border: 0; background: var(--primary); color: var(--primary-foreground); font-weight: 600; }
.rp-stu-pact--decline { color: var(--muted-foreground); }

/* roster cards (mobile) */
.rp-stu-cards { display: none; flex-direction: column; gap: 10px; }
.rp-stu-card {
  display: flex;
  align-items: center;
  gap: 11px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 14px 16px;
  text-decoration: none;
  color: var(--foreground);
}
.rp-stu-card-main { display: flex; align-items: center; gap: 11px; flex: 1; min-width: 0; }
.rp-stu-card-name { font-size: 14px; font-weight: 600; }
.rp-stu-card-sub { font-size: 12px; color: var(--muted-foreground); }

/* groups grid */
.rp-stu-groups { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; align-content: start; }
.rp-stu-gcard {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 18px 20px;
}
.rp-stu-gcard-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.rp-stu-gcard-dot { width: 14px; height: 14px; border-radius: 50%; flex-shrink: 0; }
.rp-stu-gcard-name { font-size: 15px; font-weight: 700; }
.rp-stu-gcard-spacer { flex: 1; }
.rp-stu-gcard-meta { display: flex; align-items: center; gap: 10px; font-size: 12.5px; color: var(--muted-foreground); }
.rp-stu-gedit {
  height: 30px;
  padding: 0 11px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 12px;
  cursor: pointer;
}
.rp-stu-gnew {
  border: 1.5px dashed var(--border);
  border-radius: var(--radius-lg);
  background: transparent;
  color: var(--muted-foreground);
  padding: 24px;
  font: inherit;
  font-size: 13.5px;
  font-weight: 500;
  cursor: pointer;
}
.rp-stu-gnew:hover:not(:disabled) { border-color: var(--primary); color: var(--primary); }
.rp-stu-gnew:disabled { opacity: 0.6; cursor: default; }
.rp-stu-upsell {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--info-muted);
  color: var(--info-muted-foreground);
  padding: 12px 16px;
  font-size: 13px;
  margin-bottom: 14px;
}

/* invitations list */
.rp-stu-inv {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  overflow: hidden;
}
.rp-stu-inv-row { display: flex; align-items: center; gap: 14px; padding: 14px 18px; border-bottom: 1px solid var(--border); }
.rp-stu-inv-icon {
  width: 34px;
  height: 34px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--muted);
  color: var(--muted-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.rp-stu-inv-main { flex: 1; min-width: 0; }
.rp-stu-inv-email { font-size: 13.5px; font-weight: 600; }
.rp-stu-inv-meta { font-size: 12px; color: var(--muted-foreground); }
.rp-stu-inv-act {
  height: 32px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 12.5px;
  cursor: pointer;
  white-space: nowrap;
}
.rp-stu-inv-act:disabled { opacity: 0.6; cursor: default; }
.rp-stu-inv-act--danger { color: var(--destructive); }
.rp-stu-inv-foot { padding: 12px 18px; font-size: 12.5px; color: var(--muted-foreground); }

/* dialog helpers (chrome itself is rp-sched-dlg*) */
.rp-stu-field { margin-bottom: 14px; }
.rp-stu-err { display: block; font-size: 12.5px; color: var(--destructive); margin-top: 6px; }
.rp-stu-hint { font-size: 12.5px; color: var(--muted-foreground); margin-bottom: 14px; }
.rp-stu-check { display: flex; align-items: flex-start; gap: 8px; font-size: 12.5px; color: var(--foreground); margin-bottom: 14px; cursor: pointer; }
.rp-stu-members { display: flex; flex-direction: column; gap: 6px; margin-bottom: 12px; }
.rp-stu-member {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  font-size: 13px;
}
.rp-stu-member-remove { border: 0; background: transparent; color: var(--destructive); font: inherit; font-size: 12.5px; cursor: pointer; }
.rp-stu-member-remove:disabled { opacity: 0.6; cursor: default; }
.rp-stu-addrow { display: flex; gap: 8px; align-items: center; margin-bottom: 10px; }
.rp-stu-addrow .rp-sched-dlg-input { flex: 1; }
.rp-stu-schedlink { display: inline-block; font-size: 12.5px; color: var(--primary); text-decoration: none; }
.rp-stu-schedlink:hover { text-decoration: underline; }

@media (max-width: 640px) {
  .rp-stu-table { display: none; }
  .rp-stu-cards { display: flex; }
  .rp-stu-groups { grid-template-columns: 1fr; }
}

/* ── Student card — /students/{id} (Карточка ученика.dc.html, Task 8) ───────
   Section cards reuse the same border/radius/token language as the rest of bp.css; the balance
   history rows are the reused rp-balhist* block wrapped in rp-scard-hist. Единый мобильный
   брейкпоинт 768px складывает грид в столбик (П-16). */
.rp-scard { max-width: 1080px; }
.rp-scard-loading { display: flex; justify-content: center; padding: 48px 0; }

.rp-scard-crumb { display: flex; align-items: center; gap: 8px; margin-bottom: 18px; font-size: 13px; }
.rp-scard-crumb-link { color: var(--muted-foreground); text-decoration: none; }
.rp-scard-crumb-link:hover { color: var(--foreground); text-decoration: underline; }
.rp-scard-crumb-sep { color: var(--muted-foreground); }
.rp-scard-crumb-cur { font-weight: 600; color: var(--foreground); }

.rp-scard-head {
  display: flex;
  align-items: center;
  gap: 18px;
  margin-bottom: 22px;
}
.rp-scard-avatar {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 22px;
  font-weight: 700;
  flex-shrink: 0;
}
.rp-scard-head-main { flex: 1; min-width: 0; }
.rp-scard-name-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.rp-scard-name { font-size: 21px; font-weight: 700; letter-spacing: -0.01em; }
.rp-scard-sub { font-size: 13px; color: var(--muted-foreground); margin-top: 3px; }
.rp-scard-actions { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }

.rp-scard-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 38px;
  padding: 0 15px;
  border-radius: var(--radius-md);
  font-size: 13.5px;
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--foreground);
  font-family: inherit;
}
.rp-scard-btn:disabled { opacity: 0.6; cursor: default; }
.rp-scard-btn--ghost { color: var(--foreground); }
.rp-scard-btn--primary { border: 0; background: var(--primary); color: var(--primary-foreground); font-weight: 600; }

.rp-scard-grid { display: grid; grid-template-columns: 1.5fr 1fr; gap: 16px; align-items: start; }
.rp-scard-col { display: flex; flex-direction: column; gap: 16px; min-width: 0; }

.rp-scard-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  overflow: hidden;
}
.rp-scard-card--pad { padding: 16px 18px; }
.rp-scard-card-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
}
.rp-scard-card-title { font-size: 14.5px; font-weight: 700; }
.rp-scard-card-title--inline { margin-bottom: 10px; }
.rp-scard-card-spacer { flex: 1; }
.rp-scard-card-foot { padding: 11px 18px; }
.rp-scard-card-link {
  border: 0;
  background: transparent;
  color: var(--primary);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  padding: 0;
}
.rp-scard-card-link:hover { text-decoration: underline; }
.rp-scard-card-link:disabled { opacity: 0.6; cursor: default; }
.rp-scard-card-link--danger { color: var(--destructive); }

.rp-scard-topup {
  height: 32px;
  padding: 0 13px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-foreground);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
}

.rp-scard-bal-row {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 16px 18px;
  border-bottom: 1px solid var(--border);
}
.rp-scard-bal-num { font-size: 30px; font-weight: 700; letter-spacing: -0.02em; }
.rp-scard-bal-cap { font-size: 12.5px; color: var(--muted-foreground); line-height: 1.45; }

.rp-scard-hist { padding: 6px 18px; }

.rp-scard-empty { padding: 16px 18px; font-size: 13px; color: var(--muted-foreground); }

.rp-scard-lesson {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 18px;
  border-bottom: 1px solid var(--border);
}
.rp-scard-lesson:last-child { border-bottom: 0; }
.rp-scard-lesson-when { width: 92px; flex-shrink: 0; }
.rp-scard-lesson-day { font-size: 13px; font-weight: 700; }
.rp-scard-lesson-time { font-size: 11.5px; color: var(--muted-foreground); }
.rp-scard-lesson-topic { flex: 1; min-width: 0; font-size: 13px; font-weight: 500; }

.rp-scard-crs { padding: 16px 18px; border-bottom: 1px solid var(--border); }
.rp-scard-crs:last-child { border-bottom: 0; }
.rp-scard-crs-top { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.rp-scard-crs-name { font-size: 13.5px; font-weight: 600; flex: 1; min-width: 0; }
.rp-scard-crs-count { font-size: 12px; color: var(--muted-foreground); flex-shrink: 0; }
.rp-scard-prog { height: 6px; border-radius: 999px; background: var(--muted); overflow: hidden; margin-bottom: 8px; }
.rp-scard-prog-fill { height: 100%; border-radius: 999px; background: var(--primary); }
.rp-scard-crs-foot { font-size: 12px; }

.rp-scard-work {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 18px;
  border-bottom: 1px solid var(--border);
}
.rp-scard-work:last-child { border-bottom: 0; }
.rp-scard-work-main { flex: 1; min-width: 0; }
.rp-scard-work-title { font-size: 13px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rp-scard-work-kind { font-size: 11.5px; color: var(--muted-foreground); }

.rp-scard-parent { display: flex; align-items: center; gap: 11px; }
.rp-scard-parent + .rp-scard-parent { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border); }
.rp-scard-parent-avatar {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--muted);
  color: var(--muted-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 12.5px;
  font-weight: 600;
  flex-shrink: 0;
}
.rp-scard-parent-main { flex: 1; min-width: 0; }
.rp-scard-parent-name { font-size: 13.5px; font-weight: 600; }
.rp-scard-parent-email { font-size: 12px; color: var(--muted-foreground); overflow: hidden; text-overflow: ellipsis; }

.rp-scard-note {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--muted);
  padding: 14px 18px;
  font-size: 12.5px;
  color: var(--muted-foreground);
  line-height: 1.55;
}

.rp-scard-danger {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-top: 24px;
  padding: 16px 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
}
.rp-scard-danger-text { flex: 1; min-width: 0; }
.rp-scard-danger-title { font-size: 13.5px; font-weight: 700; }
.rp-scard-danger-sub { font-size: 12.5px; color: var(--muted-foreground); margin-top: 2px; }
.rp-scard-danger-btn {
  height: 36px;
  padding: 0 15px;
  border-radius: var(--radius-md);
  border: 1px solid var(--destructive);
  background: transparent;
  color: var(--destructive);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  flex-shrink: 0;
}
.rp-scard-danger-btn:disabled { opacity: 0.6; cursor: default; }

/* «Начислить» dialog body (chrome — label/input/actions/btn — reused from rp-sched-dlg*) */
.rp-scard-dlg { max-width: 420px; }
.rp-scard-dlg-head { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.rp-scard-dlg-title { font-size: 17px; font-weight: 700; }
.rp-scard-dlg-spacer { flex: 1; }
.rp-scard-dlg-x { width: 30px; height: 30px; border: 0; background: transparent; color: var(--muted-foreground); font-size: 18px; cursor: pointer; }
.rp-scard-dlg-sub { font-size: 13px; color: var(--muted-foreground); margin: 0 0 16px; line-height: 1.5; }
.rp-scard-dlg-fields { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 14px; }
.rp-scard-dlg-field { min-width: 0; }
.rp-scard-dlg-preview {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 10px 12px;
  margin-bottom: 16px;
  background: var(--muted);
  border-radius: var(--radius-md);
  font-size: 13px;
}
.rp-scard-dlg-preview-label { color: var(--muted-foreground); }
.rp-scard-dlg-preview-val { font-weight: 600; }
.rp-scard-dlg-preview--danger { background: var(--destructive-muted); }
.rp-scard-dlg-preview--danger .rp-scard-dlg-preview-label,
.rp-scard-dlg-preview--danger .rp-scard-dlg-preview-val { color: var(--destructive-muted-foreground); }

@media (max-width: 768px) {
  .rp-scard-grid { grid-template-columns: 1fr; }
  .rp-scard-head { flex-wrap: wrap; }
  .rp-scard-actions { flex-basis: 100%; }
  .rp-scard-actions .rp-scard-btn { flex: 1; justify-content: center; }
  .rp-scard-dlg-fields { grid-template-columns: 1fr; }
  .rp-scard-danger { flex-wrap: wrap; }
  .rp-scard-danger-btn { flex-basis: 100%; }
}

/* ── Task 9 (wave 3): «Домашние задания» grading queue — /grading (Домашние задания.dc.html, top
   screen). Two DOM trees toggled by the shell's 768px breakpoint (.rp-gq-desktop / .rp-gq-mobile),
   same rationale as .rp-th-desktop/.rp-th-mobile (TutorHome) — don't merge into one responsive tree. */
.rp-gq-desktop { display: block; }
.rp-gq-mobile { display: none; }

.rp-gq-toolbar {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 14px;
}

.rp-gq-toolbar-spacer { flex: 1; }

.rp-gq-tabs { display: flex; gap: 6px; }

.rp-gq-tab {
  height: 34px;
  padding: 0 14px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 12.5px;
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
}

.rp-gq-tab--active {
  border-color: transparent;
  background: var(--primary);
  color: var(--primary-foreground);
  font-weight: 600;
}

.rp-gq-filters { display: flex; gap: 8px; }

.rp-gq-filter {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 34px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 12.5px;
  cursor: pointer;
}

.rp-gq-list {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  overflow: hidden;
}

.rp-gq-row {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
  text-decoration: none;
  color: var(--foreground);
}

.rp-gq-row:last-child { border-bottom: 0; }
.rp-gq-row:hover { background: var(--secondary); }

.rp-gq-avatar {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 600;
  flex-shrink: 0;
}

.rp-gq-body { flex: 1; min-width: 0; }
.rp-gq-title { font-size: 13.5px; }
.rp-gq-student { font-weight: 600; }
.rp-gq-task { font-weight: 500; }

.rp-gq-sub {
  font-size: 12.5px;
  color: var(--muted-foreground);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.rp-gq-files {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
  color: var(--muted-foreground);
  flex-shrink: 0;
}

.rp-gq-age {
  font-size: 11.5px;
  font-weight: 600;
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--muted);
  color: var(--muted-foreground);
  flex-shrink: 0;
}

.rp-gq-age--warn {
  background: var(--warning-muted);
  color: var(--warning-muted-foreground);
}

.rp-gq-chev { color: var(--muted-foreground); }

/* Mobile (≤768px) — header badge + scrollable chip tabs + card-per-row */
.rp-gq-mhead {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
}

.rp-gq-mtitle { font-size: 17px; font-weight: 700; }

.rp-gq-mbadge {
  min-width: 22px;
  height: 22px;
  padding: 0 7px;
  border-radius: 999px;
  background: var(--warning-muted);
  color: var(--warning-muted-foreground);
  font-size: 12px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.rp-gq-mtabs {
  display: flex;
  gap: 6px;
  overflow-x: auto;
  margin-bottom: 12px;
  padding-bottom: 2px;
}

.rp-gq-mtab {
  flex-shrink: 0;
  height: 32px;
  padding: 0 13px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 12.5px;
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
}

.rp-gq-mtab--active {
  border-color: transparent;
  background: var(--primary);
  color: var(--primary-foreground);
  font-weight: 600;
}

.rp-gq-mempty {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 20px 16px;
  font-size: 13.5px;
  color: var(--muted-foreground);
  text-align: center;
}

.rp-gq-mcard {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 14px 16px;
  margin-bottom: 10px;
}

.rp-gq-mcard-top {
  display: flex;
  align-items: center;
  gap: 10px;
}

.rp-gq-mcard-body { flex: 1; min-width: 0; }
.rp-gq-mcard-name { font-size: 13.5px; font-weight: 600; }

.rp-gq-mcard-task {
  font-size: 12px;
  color: var(--muted-foreground);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.rp-gq-mcard-btn {
  display: block;
  width: 100%;
  height: 40px;
  margin-top: 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--primary);
  font-size: 13px;
  font-weight: 600;
  text-align: center;
  line-height: 40px;
  text-decoration: none;
}

@media (max-width: 768px) {
  .rp-gq-desktop { display: none; }
  .rp-gq-mobile { display: block; }
  /* The mobile tree carries its own compact head (rp-gq-mhead) — hiding the page-level
     RpPageHeader avoids the doubled «Домашние задания» title (wave-9 visual audit). */
  .rp-gq > .rp-ph { display: none; }
}

/* ── Task 10 (wave 3): /grading/{SubmissionId} homework review page ─────────── */
.rp-grev-loading { display: flex; justify-content: center; padding: 48px 0; }

.rp-grev-head { display: flex; align-items: center; gap: 12px; margin-bottom: 18px; }
.rp-grev-head-spacer { flex: 1; }
.rp-grev-crumb { display: flex; align-items: center; gap: 8px; font-size: 13px; min-width: 0; }
.rp-grev-crumb-link { color: var(--muted-foreground); text-decoration: none; flex-shrink: 0; }
.rp-grev-crumb-link:hover { color: var(--foreground); text-decoration: underline; }
.rp-grev-crumb-sep { color: var(--muted-foreground); flex-shrink: 0; }
.rp-grev-crumb-cur {
  font-weight: 600;
  color: var(--foreground);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rp-grev-pos { font-size: 12.5px; color: var(--muted-foreground); flex-shrink: 0; }
.rp-grev-nav {
  display: inline-flex;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--card);
  flex-shrink: 0;
}
.rp-grev-navbtn {
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  background: transparent;
  color: var(--muted-foreground);
  font-size: 16px;
  text-decoration: none;
  cursor: pointer;
}
.rp-grev-navbtn + .rp-grev-navbtn { border-left: 1px solid var(--border); }
.rp-grev-navbtn:not(.rp-grev-navbtn--disabled):hover { color: var(--foreground); background: var(--muted); }
.rp-grev-navbtn--disabled { color: var(--border); cursor: default; }

.rp-grev-grid { display: grid; grid-template-columns: 1.5fr 1fr; gap: 16px; align-items: start; }
.rp-grev-col { display: flex; flex-direction: column; gap: 16px; min-width: 0; }

.rp-grev-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 18px 20px;
}
.rp-grev-card--muted { background: var(--muted); }
.rp-grev-card--pad { padding: 16px 18px; }
.rp-grev-card-label {
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted-foreground);
  margin-bottom: 8px;
}
.rp-grev-card-title { font-size: 14.5px; font-weight: 700; margin-bottom: 10px; }
.rp-grev-muted { font-size: 13px; color: var(--muted-foreground); }
.rp-grev-hint { margin-bottom: 12px; }

.rp-grev-answer-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.rp-grev-answer-head .rp-grev-card-label { margin-bottom: 0; }
.rp-grev-answer-spacer { flex: 1; }
.rp-grev-attempt {
  font-size: 11.5px;
  font-weight: 600;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--warning-muted);
  color: var(--warning-muted-foreground);
  flex-shrink: 0;
  white-space: nowrap;
}
.rp-grev-answer-text { font-size: 14px; line-height: 1.7; }

.rp-grev-files { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.rp-grev-file {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 36px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--muted);
  font-size: 12.5px;
  font-weight: 500;
  color: var(--foreground);
  text-decoration: none;
  max-width: 100%;
}
.rp-grev-file:hover { border-color: var(--primary); }
.rp-grev-file-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rp-grev-file-size { color: var(--muted-foreground); flex-shrink: 0; }

.rp-grev-score {
  font-size: 13px;
  font-weight: 600;
  padding: 8px 12px;
  margin-bottom: 12px;
  border-radius: var(--radius-md);
  background: var(--muted);
  color: var(--foreground);
}
.rp-grev-quiz-q { padding: 10px 0; border-bottom: 1px solid var(--border); }
.rp-grev-quiz-q:last-child { border-bottom: 0; padding-bottom: 0; }
.rp-grev-quiz-prompt { display: flex; align-items: flex-start; gap: 8px; font-size: 13.5px; font-weight: 500; }
.rp-grev-quiz-answer { font-size: 12.5px; color: var(--muted-foreground); margin-top: 5px; }
.rp-grev-quiz-correct { font-size: 12.5px; margin-top: 3px; }

.rp-grev-prev-text { font-size: 13px; line-height: 1.6; color: var(--muted-foreground); }

.rp-grev-conflict {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 11px 13px;
  border-radius: var(--radius-md);
  background: var(--warning-muted);
  color: var(--warning-muted-foreground);
  font-size: 13px;
  font-weight: 500;
}

.rp-grev-verdict { padding: 12px 14px; border-radius: var(--radius-md); }
.rp-grev-verdict--success { background: var(--success-muted); color: var(--success-muted-foreground); }
.rp-grev-verdict--warning { background: var(--warning-muted); color: var(--warning-muted-foreground); }
.rp-grev-verdict--danger { background: var(--destructive-muted, var(--muted)); color: var(--destructive); }
.rp-grev-verdict-label { font-size: 13.5px; font-weight: 700; }
.rp-grev-verdict-text { font-size: 13px; line-height: 1.55; margin-top: 4px; }

.rp-grev-field-label { display: block; font-size: 12.5px; font-weight: 600; margin-bottom: 6px; }
.rp-grev-textarea {
  width: 100%;
  min-height: 96px;
  padding: 10px 12px;
  border: 1px solid var(--input);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 13.5px;
  line-height: 1.55;
  resize: vertical;
  box-sizing: border-box;
}
.rp-grev-textarea:focus { outline: none; border-color: var(--primary); }

.rp-grev-actions { display: flex; flex-direction: column; gap: 8px; margin-top: 14px; }
.rp-grev-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-md);
  font: inherit;
  cursor: pointer;
  text-decoration: none;
}
.rp-grev-btn:disabled { opacity: 0.6; cursor: default; }
.rp-grev-btn--accept {
  height: 44px;
  border: 0;
  background: var(--success);
  color: var(--success-foreground);
  font-size: 14px;
  font-weight: 600;
}
.rp-grev-btn--outline {
  height: 40px;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--foreground);
  font-size: 13.5px;
  font-weight: 500;
}
.rp-grev-reject {
  align-self: center;
  margin-top: 2px;
  border: 0;
  background: transparent;
  color: var(--destructive);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  padding: 4px 8px;
}
.rp-grev-reject:hover { text-decoration: underline; }
.rp-grev-reject:disabled { opacity: 0.6; cursor: default; }

.rp-grev-stats { font-size: 12.5px; color: var(--muted-foreground); line-height: 1.7; }
.rp-grev-cardlink {
  display: inline-block;
  margin-top: 10px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--primary);
  text-decoration: none;
}
.rp-grev-cardlink:hover { text-decoration: underline; }

@media (max-width: 768px) {
  .rp-grev-grid { grid-template-columns: 1fr; }
  .rp-grev-head { flex-wrap: wrap; }
  .rp-grev-crumb { order: 1; width: 100%; }
  .rp-grev-head-spacer { display: none; }
}

/* ── Тесты (/tests) gradebook — Task 11, wave 3, Тесты.dc.html ──────────────────────────────
   Matrix is TRANSPOSED vs the contract: rows = students, columns = tests. Sticky first column +
   sticky header via position:sticky (a table, not the mockup's grid, so the corner cell stays
   pinned on both axes). All tokens so dark mode flips for free. */
.rp-tm-toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}
.rp-tm-toolbar-spacer { flex: 1; }
.rp-tm-filters { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.rp-tm-filter {
  height: 38px;
  padding: 0 12px;
  border: 1px solid var(--input);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 13px;
}
.rp-tm-inactive {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 13px;
  color: var(--muted-foreground);
  cursor: pointer;
}
.rp-tm-inactive input { accent-color: var(--primary); }

.rp-tm-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 38px;
  padding: 0 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.rp-tm-btn--primary { border: 0; background: var(--primary); color: var(--primary-foreground); }
.rp-tm-btn--ghost { border: 0; background: transparent; color: var(--muted-foreground); }
.rp-tm-btn:disabled { opacity: 0.6; cursor: default; }

.rp-tm-wrap {
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
}
.rp-tm { border-collapse: separate; border-spacing: 0; width: max-content; min-width: 100%; }
.rp-tm th, .rp-tm td {
  border-bottom: 1px solid var(--border);
  border-right: 1px solid var(--border);
  padding: 11px 14px;
  vertical-align: middle;
}
.rp-tm tbody tr:last-child th, .rp-tm tbody tr:last-child td { border-bottom: 0; }

/* Sticky header row + sticky first column; corner is pinned on both axes. */
.rp-tm thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--card);
  text-align: left;
  vertical-align: top;
}
.rp-tm-corner {
  position: sticky;
  left: 0;
  top: 0;
  z-index: 3;
  min-width: 190px;
  background: var(--card);
  font-size: 11.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted-foreground);
}
.rp-tm-rowhead {
  position: sticky;
  left: 0;
  z-index: 1;
  min-width: 190px;
  background: var(--card);
  text-align: left;
}

.rp-tm-colhead { min-width: 150px; }
.rp-tm-colhead--inactive { opacity: 0.55; }
.rp-tm-colhead-inner { display: flex; align-items: flex-start; gap: 6px; }
.rp-tm-colhead-main {
  display: flex;
  flex-direction: column;
  gap: 3px;
  flex: 1;
  min-width: 0;
  text-decoration: none;
  color: var(--foreground);
}
.rp-tm-colhead-main:hover .rp-tm-colhead-name { color: var(--primary); }
.rp-tm-colhead-name { font-size: 12.5px; font-weight: 700; line-height: 1.3; }
.rp-tm-colhead-meta { font-size: 11px; color: var(--muted-foreground); }

.rp-tm-badge {
  align-self: flex-start;
  margin-top: 2px;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--info-muted);
  color: var(--info-muted-foreground);
}
.rp-tm-badge--muted { background: var(--muted); color: var(--muted-foreground); }

.rp-tm-kebab {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  flex-shrink: 0;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--muted-foreground);
  cursor: pointer;
}
.rp-tm-kebab:hover { background: var(--secondary); color: var(--foreground); }

.rp-tm-student { display: inline-flex; align-items: center; gap: 9px; text-decoration: none; color: var(--foreground); }
.rp-tm-student-name { font-size: 13px; font-weight: 600; }
.rp-tm-student:hover .rp-tm-student-name { color: var(--primary); }
.rp-tm-avatar {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 600;
  flex-shrink: 0;
}

.rp-tm-cell { cursor: pointer; }
.rp-tm-cell:hover { background: var(--secondary); }
.rp-tm-chip {
  display: inline-block;
  font-size: 12.5px;
  font-weight: 700;
  padding: 3px 10px;
  border-radius: 999px;
}
.rp-tm-chip--passed { background: var(--success-muted); color: var(--success-muted-foreground); }
.rp-tm-chip--failed { background: var(--destructive-muted); color: var(--destructive-muted-foreground); }
.rp-tm-chip--scored { background: var(--muted); color: var(--foreground); }
.rp-tm-chip--assigned { background: var(--warning-muted); color: var(--warning-muted-foreground); }
.rp-tm-assigned { font-size: 11.5px; font-weight: 600; color: var(--warning-muted-foreground); }
.rp-tm-dash { font-size: 12.5px; color: var(--muted-foreground); }

.rp-tm-hint { font-size: 12px; color: var(--muted-foreground); margin: 12px 2px 0; line-height: 1.6; }

/* Mobile card view (per test). Hidden on desktop; the matrix is hidden ≤768px. */
.rp-tm-cards { display: none; flex-direction: column; gap: 10px; }
.rp-tm-card { border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--card); padding: 14px 16px; }
.rp-tm-card--inactive { opacity: 0.6; }
.rp-tm-card-head { display: flex; align-items: center; gap: 8px; margin-bottom: 2px; }
.rp-tm-card-name { font-size: 14px; font-weight: 700; flex: 1; text-decoration: none; color: var(--foreground); }
.rp-tm-card-meta { font-size: 12px; color: var(--muted-foreground); margin-bottom: 10px; }
.rp-tm-card-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.rp-tm-card-empty { font-size: 12px; color: var(--muted-foreground); }

/* Create-test dialog body (rendered inside BbDialogContent). */
.rp-tm-dlg { max-width: 420px; }
.rp-tm-dlg-title { font-size: 17px; font-weight: 700; }
.rp-tm-dlg-sub { font-size: 13.5px; color: var(--muted-foreground); margin: 4px 0 16px; }
.rp-tm-dlg-field { margin-bottom: 14px; }
.rp-tm-dlg-label { display: block; font-size: 12.5px; font-weight: 600; margin-bottom: 6px; }
.rp-tm-dlg-input {
  width: 100%;
  height: 42px;
  padding: 0 12px;
  border: 1px solid var(--input);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 13.5px;
}
.rp-tm-dlg-thr { position: relative; }
.rp-tm-dlg-thr-unit { position: absolute; right: 14px; top: 50%; transform: translateY(-50%); font-size: 13px; color: var(--muted-foreground); }
.rp-tm-dlg-help { font-size: 12px; color: var(--muted-foreground); margin-top: 6px; }
.rp-tm-dlg-switchrow {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 4px 0 18px;
  cursor: pointer;
}
.rp-tm-dlg-switchtext { flex: 1; font-size: 13.5px; }
.rp-tm-dlg-actions { display: flex; align-items: center; gap: 8px; }
.rp-tm-dlg-spacer { flex: 1; }

/* Pill switch (shared by the create dialog + the editor parameters card). */
.rp-tm-sw {
  position: relative;
  width: 40px;
  height: 23px;
  flex-shrink: 0;
  border: 0;
  border-radius: 999px;
  background: var(--input);
  cursor: pointer;
  transition: background 0.15s ease;
}
.rp-tm-sw--on { background: var(--primary); }
.rp-tm-sw-thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 19px;
  height: 19px;
  border-radius: 50%;
  background: #fff;
  box-shadow: var(--shadow-sm);
  transition: left 0.15s ease;
}
.rp-tm-sw--on .rp-tm-sw-thumb { left: 19px; }

.rp-tm-err { font-size: 12.5px; color: var(--destructive); margin-bottom: 10px; }

/* Cell-results popup body. */
.rp-tm-res-head { font-size: 14.5px; font-weight: 600; margin-bottom: 12px; }
.rp-tm-res-list { display: flex; flex-direction: column; gap: 8px; }
.rp-tm-res-row { display: flex; align-items: center; gap: 12px; }
.rp-tm-res-date { font-size: 12.5px; color: var(--muted-foreground); }

/* ── Редактор теста (/tests/{Id}) — Task 11, wave 3 ─────────────────────────────────────────── */
.rp-ted-head {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}
.rp-ted-head-spacer { flex: 1; }
.rp-ted-crumb { display: flex; align-items: center; gap: 8px; min-width: 0; }
.rp-ted-crumb-link { font-size: 13px; color: var(--muted-foreground); text-decoration: none; }
.rp-ted-crumb-link:hover { color: var(--primary); }
.rp-ted-crumb-sep { color: var(--muted-foreground); }
.rp-ted-crumb-cur { font-size: 15px; font-weight: 700; }
.rp-ted-status { font-size: 12.5px; }
.rp-ted-status--ok { color: var(--success-muted-foreground); }
.rp-ted-status--pending { color: var(--muted-foreground); }
.rp-ted-status--warn { color: var(--warning-muted-foreground); }

.rp-ted-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 36px;
  padding: 0 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
}
.rp-ted-btn--primary { border: 0; background: var(--primary); color: var(--primary-foreground); }

.rp-ted-grid { display: grid; grid-template-columns: 1.5fr 1fr; gap: 16px; align-items: start; }
.rp-ted-questions { display: flex; flex-direction: column; gap: 12px; }
.rp-ted-side { display: flex; flex-direction: column; gap: 16px; }

.rp-ted-field { display: flex; flex-direction: column; gap: 6px; }
.rp-ted-label { font-size: 12.5px; font-weight: 600; }
.rp-ted-input {
  width: 100%;
  height: 40px;
  padding: 0 12px;
  border: 1px solid var(--input);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 13.5px;
}
.rp-ted-alert {
  font-size: 13px;
  color: var(--destructive-muted-foreground);
  background: var(--destructive-muted);
  border-radius: var(--radius-md);
  padding: 10px 12px;
}

.rp-ted-qcard { border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--card); padding: 16px 18px; }
.rp-ted-qhead { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.rp-ted-qnum {
  width: 24px;
  height: 24px;
  border-radius: var(--radius-sm);
  background: var(--muted);
  color: var(--muted-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 700;
  flex-shrink: 0;
}
.rp-ted-qtype {
  height: 32px;
  padding: 0 10px;
  border: 1px solid var(--input);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 12.5px;
}
.rp-ted-qspacer { flex: 1; }
.rp-ted-qdel, .rp-ted-opt-del {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--muted-foreground);
  cursor: pointer;
}
.rp-ted-qdel:hover, .rp-ted-opt-del:hover { background: var(--secondary); color: var(--destructive); }
.rp-ted-qtext {
  width: 100%;
  min-height: 60px;
  padding: 10px 12px;
  margin-bottom: 10px;
  border: 1px solid var(--input);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 14px;
  line-height: 1.5;
  resize: vertical;
}

.rp-ted-opt { display: flex; align-items: center; gap: 9px; padding: 4px 0; }
.rp-ted-opt-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  border: 1.5px solid var(--input);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--primary-foreground);
  cursor: pointer;
}
.rp-ted-opt-mark--radio { border-radius: 50%; }
.rp-ted-opt-mark--on { border-color: var(--success); background: var(--success); }
.rp-ted-opt .rp-ted-input { height: 36px; }

.rp-ted-addopt {
  align-self: flex-start;
  margin-top: 4px;
  border: 0;
  background: transparent;
  color: var(--primary);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  padding: 4px 0;
}
.rp-ted-addq {
  border: 1.5px dashed var(--border);
  border-radius: var(--radius-lg);
  background: transparent;
  color: var(--muted-foreground);
  padding: 16px;
  font: inherit;
  font-size: 13.5px;
  font-weight: 500;
  cursor: pointer;
}
.rp-ted-addq:hover { border-color: var(--primary); color: var(--primary); }
.rp-ted-ai {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  align-self: flex-start;
  height: 38px;
  padding: 0 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--primary);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}

.rp-ted-card { border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--card); padding: 16px 18px; }
.rp-ted-card-title { display: flex; align-items: center; font-size: 14.5px; font-weight: 700; margin-bottom: 12px; }
.rp-ted-card-spacer { flex: 1; }
.rp-ted-card-count { font-size: 12px; font-weight: 500; color: var(--muted-foreground); }

.rp-ted-thr { position: relative; }
.rp-ted-thr-unit { position: absolute; right: 14px; top: 50%; transform: translateY(-50%); font-size: 13px; color: var(--muted-foreground); }

.rp-ted-prow { display: flex; justify-content: space-between; align-items: center; font-size: 13px; padding: 10px 0; border-bottom: 1px solid var(--border); }
.rp-ted-prow-key { color: var(--muted-foreground); }
.rp-ted-prow-val { font-weight: 600; }

.rp-ted-switchrow { display: flex; align-items: center; gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--border); cursor: pointer; }
.rp-ted-switchrow:last-child { border-bottom: 0; }
.rp-ted-switchtext { flex: 1; font-size: 13.5px; }

.rp-ted-empty { font-size: 13px; color: var(--muted-foreground); }
.rp-ted-batch { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 8px 0; border-bottom: 1px solid var(--border); }
.rp-ted-batch-aud { font-size: 13px; font-weight: 600; }
.rp-ted-batch-meta { font-size: 12px; color: var(--muted-foreground); }
.rp-ted-reslabel { font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted-foreground); margin: 12px 0 6px; }
.rp-ted-resrow { display: flex; align-items: center; gap: 11px; padding: 7px 0; }
.rp-ted-resname { flex: 1; font-size: 13px; font-weight: 600; }

@media (max-width: 768px) {
  .rp-tm-wrap, .rp-tm-hint { display: none; }
  .rp-tm-cards { display: flex; }
  .rp-ted-grid { grid-template-columns: 1fr; }
}

/* ── rp-crsl* (wave 4 Task 3 — /courses list, Курсы.dc.html) ─────────────────────────────────── */
.rp-crsl-toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 4px;
}
.rp-crsl-toolbar .rp-ph { margin-bottom: 0; }
.rp-crsl-toolbar-spacer { flex: 1; }
.rp-crsl-btn {
  display: inline-flex;
  align-items: center;
  height: 36px;
  padding: 0 14px;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
}
.rp-crsl-btn--primary { border: 0; background: var(--primary); color: var(--primary-foreground); font-weight: 600; }
.rp-crsl-btn--primary:hover { background: var(--primary); opacity: 0.92; }
.rp-crsl-btn-compact { display: none; }

.rp-crsl-filters { display: flex; align-items: center; gap: 8px; margin: 20px 0 18px; flex-wrap: wrap; }
.rp-crsl-chip {
  padding: 6px 14px;
  border-radius: 999px;
  font-size: 12.5px;
  font-weight: 500;
  background: var(--secondary);
  color: var(--secondary-foreground);
  cursor: pointer;
  user-select: none;
}
.rp-crsl-chip--active { background: var(--foreground); color: var(--background); font-weight: 600; }

.rp-crsl-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }

.rp-crsl-card {
  display: block;
  border: 1px solid var(--border);
  border-radius: 16px;
  background: var(--card);
  overflow: hidden;
  text-decoration: none;
  color: var(--foreground);
  transition: box-shadow 0.15s ease, border-color 0.15s ease;
}
.rp-crsl-card:hover { box-shadow: var(--shadow-md); border-color: var(--input); }
.rp-crsl-card--archived { opacity: 0.62; }

.rp-crsl-cover {
  height: 112px;
  background: repeating-linear-gradient(45deg, var(--muted), var(--muted) 7px, var(--secondary) 7px, var(--secondary) 14px);
}
.rp-crsl-cover img { width: 100%; height: 100%; object-fit: cover; display: block; }

.rp-crsl-body { padding: 13px 14px 14px; }
.rp-crsl-name {
  font-size: 14.5px;
  font-weight: 650;
  margin-bottom: 3px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rp-crsl-meta { font-size: 12.5px; color: var(--muted-foreground); margin-bottom: 10px; }
.rp-crsl-row { display: flex; align-items: center; gap: 8px; }
.rp-crsl-students { font-size: 12px; color: var(--muted-foreground); }
.rp-crsl-spacer { flex: 1; }
.rp-crsl-price { font-size: 13px; font-weight: 650; }

.rp-crsl-info {
  margin-top: 18px;
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12.5px;
  color: var(--muted-foreground);
}

/* CreateCourseDialog — field/label/input chrome REUSED from rp-sched-dlg*; only the header, note row,
   textarea sizing and full-width submit are page-specific. */
.rp-crsl-dlg { max-width: 440px; }
.rp-crsl-dlg-head { display: flex; align-items: center; gap: 8px; margin-bottom: 16px; }
.rp-crsl-dlg-title { font-size: 17px; font-weight: 700; }
.rp-crsl-dlg-spacer { flex: 1; }
.rp-crsl-dlg-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border: 0;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--muted-foreground);
  cursor: pointer;
}
.rp-crsl-dlg-close:hover { background: var(--secondary); }
.rp-crsl-field { margin-bottom: 14px; }
.rp-crsl-dlg-optional { font-weight: 400; color: var(--muted-foreground); }
.rp-crsl-dlg-textarea { height: 66px; padding: 10px 12px; resize: vertical; }
.rp-crsl-dlg-note {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12.5px;
  color: var(--muted-foreground);
  margin: 4px 0 16px;
}
.rp-crsl-dlg-submit {
  width: 100%;
  height: 44px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-foreground);
  font: inherit;
  font-size: 14.5px;
  font-weight: 600;
  cursor: pointer;
}
.rp-crsl-dlg-submit:disabled { opacity: 0.6; cursor: default; }
.rp-crsl-err { display: block; font-size: 12px; color: var(--destructive); margin: 6px 0 0; }
.rp-crsl-err-banner {
  font-size: 13px;
  background: var(--destructive-muted);
  color: var(--destructive-muted-foreground);
  border-radius: var(--radius-md);
  padding: 10px 12px;
  margin-bottom: 14px;
}

@media (max-width: 768px) {
  .rp-crsl-btn-full { display: none; }
  .rp-crsl-btn-compact { display: inline; }
  .rp-crsl-grid { grid-template-columns: 1fr; }
  .rp-crsl-cover { height: 96px; }
}

/* ── Task 4 (wave 4) — /courses/{Id} course overview (rp-covw*), Обзор курса.dc.html ───────────────
   Product hub: publication banner, header (cover + status + name + kebab), «Продукт» card (price/
   duration/validity/sequential-unlock + per-module lesson-count steppers). All colours via tokens. */
.rp-covw-loading { display: flex; justify-content: center; padding: 48px 0; }
.rp-covw { max-width: 960px; margin: 0 auto; }

/* breadcrumb */
.rp-covw-crumb { display: flex; align-items: center; gap: 7px; font-size: 13px; margin-bottom: 16px; }
.rp-covw-crumb-link { color: var(--muted-foreground); text-decoration: none; }
.rp-covw-crumb-link:hover { color: var(--foreground); }
.rp-covw-crumb-back { display: none; align-items: center; justify-content: center; }
.rp-covw-crumb-sep { color: var(--input); }
.rp-covw-crumb-cur { font-weight: 650; color: var(--foreground); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* draft banner */
.rp-covw-banner {
  display: flex; align-items: center; gap: 12px;
  border: 1px solid color-mix(in srgb, var(--warning) 35%, var(--border));
  border-radius: 14px; background: var(--warning-muted);
  padding: 12px 14px; margin-bottom: 16px;
}
.rp-covw-banner-text { flex: 1; font-size: 13px; line-height: 1.45; color: var(--warning-muted-foreground); }
.rp-covw-banner-btn {
  height: 36px; padding: 0 16px; border: 0; border-radius: var(--radius-md);
  background: var(--primary); color: var(--primary-foreground);
  font: inherit; font-size: 13px; font-weight: 600; cursor: pointer; flex-shrink: 0;
}
.rp-covw-banner-btn:disabled { opacity: 0.6; cursor: default; }

/* header */
.rp-covw-head { display: flex; gap: 20px; margin-bottom: 20px; }
.rp-covw-cover {
  width: 220px; height: 142px; border-radius: 16px; flex-shrink: 0;
  background-size: cover; background-position: center; background-color: var(--muted);
}
.rp-covw-cover--placeholder {
  background-image: repeating-linear-gradient(45deg, var(--muted), var(--muted) 7px, var(--secondary) 7px, var(--secondary) 14px);
}
.rp-covw-head-main { flex: 1; min-width: 0; }
.rp-covw-title-row { display: flex; align-items: center; gap: 8px; margin-top: 8px; }
.rp-covw-title { font-size: 22px; font-weight: 700; letter-spacing: -0.01em; margin: 0; flex: 1; min-width: 0; }
.rp-covw-kebab {
  width: 32px; height: 32px; display: inline-flex; align-items: center; justify-content: center;
  border: 0; border-radius: 8px; background: transparent; color: var(--muted-foreground); cursor: pointer;
}
.rp-covw-kebab:hover { background: var(--secondary); color: var(--foreground); }
.rp-covw-desc { font-size: 13px; color: var(--muted-foreground); margin: 5px 0 12px; line-height: 1.5; }
.rp-covw-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.rp-covw-btn {
  display: inline-flex; align-items: center; gap: 8px; height: 38px; padding: 0 16px;
  border-radius: var(--radius-md); font: inherit; font-size: 13px; font-weight: 600;
  text-decoration: none; cursor: pointer;
}
.rp-covw-btn--primary { border: 0; background: var(--primary); color: var(--primary-foreground); }
.rp-covw-btn--outline { border: 1px solid var(--border); background: var(--card); color: var(--foreground); font-weight: 500; }

/* card grid */
.rp-covw-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; align-items: start; }

/* «Продукт» card */
.rp-covw-card { border: 1px solid var(--border); border-radius: 16px; background: var(--card); overflow: hidden; }
.rp-covw-card-head { padding: 13px 16px 11px; border-bottom: 1px solid var(--border); font-size: 13.5px; font-weight: 650; }
.rp-covw-row { display: flex; align-items: center; gap: 10px; padding: 11px 16px; border-bottom: 1px solid var(--border); }
.rp-covw-row--switch { }
.rp-covw-row-label { flex: 1; font-size: 13px; color: var(--muted-foreground); }
.rp-covw-row-val { font-size: 13.5px; font-weight: 650; }
.rp-covw-row-val--muted { font-weight: 550; }
.rp-covw-row-edit {
  width: 26px; height: 26px; display: inline-flex; align-items: center; justify-content: center;
  border: 0; border-radius: 8px; background: transparent; color: var(--muted-foreground); cursor: pointer;
}
.rp-covw-row-edit:hover { background: var(--secondary); color: var(--foreground); }
.rp-covw-subhead {
  padding: 11px 16px 6px; font-size: 12px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted-foreground);
}
.rp-covw-mod { display: flex; align-items: center; gap: 10px; padding: 8px 16px; }
.rp-covw-mod-title { flex: 1; min-width: 0; font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rp-covw-mod-count { min-width: 20px; text-align: center; font-size: 13.5px; font-weight: 650; font-variant-numeric: tabular-nums; }
.rp-covw-step {
  width: 26px; height: 26px; display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border); border-radius: 8px; background: var(--card); color: var(--foreground);
  cursor: pointer; font: inherit; font-size: 14px; font-weight: 600; user-select: none;
}
.rp-covw-step:hover:not(:disabled) { background: var(--secondary); }
.rp-covw-step:disabled { opacity: 0.45; cursor: default; }
.rp-covw-foot {
  padding: 10px 16px 13px; font-size: 12px; color: var(--muted-foreground);
  border-top: 1px solid var(--border); margin-top: 4px;
}
.rp-covw-empty { padding: 8px 16px 12px; font-size: 12.5px; color: var(--muted-foreground); }

/* dialog bodies (price + name/desc + cover). Chrome for labels/inputs reuses rp-sched-dlg-*. */
.rp-covw-dlg { max-width: 440px; }
.rp-covw-dlg-head { display: flex; align-items: center; margin-bottom: 16px; }
.rp-covw-dlg-title { font-size: 17px; font-weight: 700; }
.rp-covw-dlg-spacer { flex: 1; }
.rp-covw-dlg-close {
  width: 30px; height: 30px; display: inline-flex; align-items: center; justify-content: center;
  border: 0; background: transparent; color: var(--muted-foreground); cursor: pointer; border-radius: 8px;
}
.rp-covw-dlg-close:hover { background: var(--secondary); color: var(--foreground); }
.rp-covw-dlg-fields { display: grid; gap: 12px; margin-bottom: 14px; }
.rp-covw-field { margin-bottom: 12px; }
.rp-covw-dlg-textarea { min-height: 72px; resize: vertical; }
.rp-covw-dlg-hint-inline { display: block; font-size: 12px; color: var(--muted-foreground); margin-top: 4px; }
.rp-covw-dlg-summary {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  font-size: 13px; margin-bottom: 16px; padding: 10px 12px; background: var(--muted); border-radius: var(--radius-md);
}
.rp-covw-dlg-summary-label { color: var(--muted-foreground); }
.rp-covw-dlg-summary-val { font-weight: 600; }
.rp-covw-dlg-note {
  display: flex; align-items: center; gap: 8px; font-size: 12.5px;
  color: var(--muted-foreground); margin-bottom: 16px;
}
.rp-covw-dlg-submit {
  width: 100%; height: 44px; border: 0; border-radius: var(--radius-md);
  background: var(--primary); color: var(--primary-foreground);
  font: inherit; font-size: 14.5px; font-weight: 600; cursor: pointer;
}
.rp-covw-dlg-submit:disabled { opacity: 0.6; cursor: default; }
.rp-covw-err { display: block; font-size: 12px; color: var(--destructive); margin-top: 4px; }
.rp-covw-err-banner {
  font-size: 12.5px; color: var(--destructive); background: var(--destructive-muted, var(--muted));
  border-radius: var(--radius-md); padding: 8px 12px; margin-bottom: 12px;
}

/* ── AI generation dialogs (Task 9, wave 4): «Заполнить урок» / «Вопросы автотеста» (form-only) +
   «План курса» (two-phase preview). Reuse the rp-covw-dlg head/close/spacer chrome. ── */
.rp-gen-dlg { max-width: 480px; }
.rp-gen-dlg--wide { max-width: 560px; }
.rp-gen-dlg-title { display: inline-flex; align-items: center; gap: 8px; font-size: 15.5px; font-weight: 700; }
.rp-gen-dlg-title svg { color: var(--primary); }
.rp-gen-dlg-lead { font-size: 13px; line-height: 1.5; color: var(--muted-foreground); margin: 0 0 12px; }
.rp-gen-dlg-hint {
  width: 100%; box-sizing: border-box;
  border: 1px solid var(--input); border-radius: var(--radius-md); background: var(--card);
  padding: 12px 14px; font: inherit; font-size: 13.5px; line-height: 1.5; color: var(--foreground);
  resize: vertical; margin-bottom: 12px;
}
.rp-gen-dlg-hint:focus { outline: none; border-color: var(--ring); }
.rp-gen-dlg-fields { display: grid; gap: 12px; margin-bottom: 12px; }
.rp-gen-dlg-label {
  display: block; font-size: 12px; font-weight: 600; color: var(--muted-foreground); margin-bottom: 4px;
}
.rp-gen-dlg-input {
  width: 100%; box-sizing: border-box; height: 40px;
  border: 1px solid var(--input); border-radius: var(--radius-md); background: var(--card);
  padding: 0 12px; font: inherit; font-size: 13.5px; color: var(--foreground);
}
.rp-gen-dlg-input:focus { outline: none; border-color: var(--ring); }
.rp-gen-dlg-row { display: flex; gap: 10px; }
.rp-gen-dlg-col { flex: 1; min-width: 0; }
.rp-gen-dlg-foot { display: flex; align-items: center; gap: 10px; }
.rp-gen-dlg-bal { flex: 1; font-size: 12.5px; color: var(--muted-foreground); }
.rp-gen-dlg-btn {
  display: inline-flex; align-items: center; gap: 8px;
  height: 40px; padding: 0 18px;
  border: 0; border-radius: var(--radius-md);
  background: var(--primary); color: var(--primary-foreground);
  font: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
}
.rp-gen-dlg-btn:disabled { opacity: 0.7; cursor: default; }
.rp-gen-dlg-btn--ghost {
  background: var(--card); color: var(--foreground); border: 1px solid var(--border);
}
.rp-gen-dlg-btn--ghost:hover { background: var(--secondary); }
.rp-gen-dlg-counts { font-size: 12.5px; color: var(--muted-foreground); margin-bottom: 12px; }
/* «План курса» preview list */
.rp-gen-out-list { display: flex; flex-direction: column; gap: 10px; margin-bottom: 12px; max-height: 46vh; overflow-y: auto; }
.rp-gen-out-mod {
  border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--card); padding: 10px;
}
.rp-gen-out-modrow, .rp-gen-out-lesrow { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.rp-gen-out-lesrow { padding-left: 20px; margin-bottom: 6px; }
.rp-gen-out-lesrow:last-child { margin-bottom: 0; }
.rp-gen-out-del {
  width: 30px; height: 30px; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; border-radius: 8px; background: transparent; color: var(--muted-foreground); cursor: pointer;
}
.rp-gen-out-del:hover { background: var(--secondary); color: var(--destructive); }

/* ── Task 5 (wave 4) — «Озвучка уроков» card ────────────────────────────────────────────────────── */
.rp-covw-audio-head { display: flex; align-items: center; gap: 10px; padding: 13px 16px 11px; border-bottom: 1px solid var(--border); color: var(--muted-foreground); }
.rp-covw-audio-title { flex: 1; font-size: 13.5px; font-weight: 650; color: var(--foreground); }
.rp-covw-voice { padding: 12px 16px; border-bottom: 1px solid var(--border); }
.rp-covw-voice-label {
  font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--muted-foreground); margin-bottom: 8px;
}
.rp-covw-voice-chips { display: flex; gap: 6px; flex-wrap: wrap; }
.rp-covw-voice-chip {
  padding: 6px 13px; border: 0; border-radius: 999px; font: inherit; font-size: 12.5px; font-weight: 600;
  background: var(--secondary); color: var(--secondary-foreground); cursor: pointer;
}
.rp-covw-voice-chip:disabled { opacity: 0.6; cursor: default; }
.rp-covw-voice-chip--active { background: var(--accent); color: var(--accent-foreground); }
.rp-covw-audio-refresh { display: flex; align-items: center; gap: 10px; padding: 12px 16px; flex-wrap: wrap; }
.rp-covw-audio-btn {
  display: inline-flex; align-items: center; gap: 7px; height: 34px; padding: 0 13px;
  border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--card);
  color: var(--foreground); font: inherit; font-size: 12.5px; font-weight: 600; cursor: pointer;
}
.rp-covw-audio-btn:disabled { opacity: 0.6; cursor: default; }
.rp-covw-audio-est { font-size: 12px; color: var(--muted-foreground); }
.rp-covw-hint { padding: 8px 16px 12px; font-size: 12px; color: var(--muted-foreground); }

/* «Ученики» card — spans both grid columns */
.rp-covw-card--students { grid-column: 1 / -1; }
.rp-covw-students-head { display: flex; align-items: center; gap: 10px; padding: 13px 16px 11px; border-bottom: 1px solid var(--border); }
.rp-covw-students-title { font-size: 13.5px; font-weight: 650; }
.rp-covw-students-sub { flex: 1; font-size: 12.5px; color: var(--muted-foreground); }
.rp-covw-enroll-btn {
  height: 32px; padding: 0 13px; border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--card); color: var(--foreground); font: inherit; font-size: 12.5px; font-weight: 600;
  cursor: pointer; flex-shrink: 0;
}
.rp-covw-enroll-btn:disabled { opacity: 0.6; cursor: default; }
.rp-covw-students-rows { display: flex; flex-direction: column; }
.rp-covw-student-row { display: flex; align-items: center; gap: 12px; padding: 10px 16px; border-bottom: 1px solid var(--border); }
.rp-covw-student-row:last-child { border-bottom: 0; }
.rp-covw-student-avatar {
  width: 30px; height: 30px; border-radius: 50%; flex-shrink: 0;
  background: var(--accent); color: var(--accent-foreground);
  display: inline-flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 700;
}
.rp-covw-student-name {
  flex: 1; min-width: 0; font-size: 13.5px; font-weight: 550; color: var(--foreground);
  text-decoration: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rp-covw-student-name:hover { text-decoration: underline; }
.rp-covw-student-date { font-size: 12.5px; color: var(--muted-foreground); flex-shrink: 0; }
.rp-covw-student-progress { width: 120px; height: 6px; border-radius: 999px; background: var(--muted); overflow: hidden; flex-shrink: 0; }
.rp-covw-student-progress-fill { height: 100%; background: var(--primary); border-radius: 999px; }
.rp-covw-student-progress-pct {
  min-width: 32px; text-align: right; font-size: 12px; color: var(--muted-foreground);
  font-variant-numeric: tabular-nums; flex-shrink: 0;
}
.rp-covw-student-progress-none { min-width: 32px; text-align: right; font-size: 12px; color: var(--muted-foreground); flex-shrink: 0; }
.rp-covw-student-unenroll {
  height: 30px; padding: 0 12px; border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--card); color: var(--destructive); font: inherit; font-size: 12px; font-weight: 600;
  cursor: pointer; flex-shrink: 0;
}
.rp-covw-student-unenroll:disabled { opacity: 0.6; cursor: default; }

/* Mobile compact student cards — hidden on desktop; swapped in at ≤768px below. */
.rp-covw-students-cards { display: none; }
.rp-covw-student-card {
  display: flex; align-items: center; gap: 11px; padding: 10px 16px; border-bottom: 1px solid var(--border);
  text-decoration: none; color: inherit;
}
.rp-covw-student-card:last-child { border-bottom: 0; }
.rp-covw-student-card-main { flex: 1; min-width: 0; }
.rp-covw-student-card-name { font-size: 13.5px; font-weight: 550; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--foreground); }
.rp-covw-student-card-meta { font-size: 11.5px; color: var(--muted-foreground); }

/* «Записать ученика» dialog — chrome reuses rp-covw-dlg, rp-covw-student-avatar. */
.rp-covw-enroll-search {
  display: flex; align-items: center; gap: 8px; height: 36px; padding: 0 12px;
  border: 1px solid var(--input); border-radius: var(--radius-md); background: var(--card);
  color: var(--muted-foreground); margin-bottom: 12px;
}
.rp-covw-enroll-search-input { flex: 1; min-width: 0; border: 0; background: transparent; color: var(--foreground); font: inherit; font-size: 13px; outline: none; }
.rp-covw-enroll-list { display: flex; flex-direction: column; gap: 4px; max-height: 320px; overflow-y: auto; }
.rp-covw-enroll-row {
  display: flex; align-items: center; gap: 10px; width: 100%; padding: 8px 10px;
  border: 0; border-radius: var(--radius-md); background: transparent; color: var(--foreground);
  font: inherit; font-size: 13.5px; text-align: left; cursor: pointer;
}
.rp-covw-enroll-row:hover:not(:disabled) { background: var(--secondary); }
.rp-covw-enroll-row--disabled, .rp-covw-enroll-row:disabled { opacity: 0.55; cursor: default; }
.rp-covw-enroll-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rp-covw-enroll-chip {
  font-size: 11px; font-weight: 600; padding: 2px 9px; border-radius: 999px;
  background: var(--muted); color: var(--muted-foreground); flex-shrink: 0;
}

/* Mobile: back-arrow crumb, vertical card stack (single 768 shell breakpoint). */
@media (max-width: 768px) {
  .rp-covw-crumb-back { display: inline-flex; }
  .rp-covw-crumb-link:not(.rp-covw-crumb-back),
  .rp-covw-crumb-sep { display: none; }
  .rp-covw-head { flex-direction: column; gap: 12px; }
  .rp-covw-cover { width: 100%; height: 120px; }
  .rp-covw-grid { grid-template-columns: 1fr; }
  .rp-covw-students-rows { display: none; }
  .rp-covw-students-cards { display: flex; flex-direction: column; }
}

/* ── Content editor shell (wave 4 Task 6 — /courses/{Id}/content, Редактор содержания.dc.html) ──────────
   Full-screen authoring surface on ReaderLayout (no cabinet shell). Tokens only → dual-theme free. */
.rp-ced {
  display: flex;
  flex-direction: column;
  height: 100vh;
  background: var(--background);
  color: var(--foreground);
}
.rp-ced-loading { display: flex; justify-content: center; align-items: center; min-height: 60vh; padding: 32px; }

/* header */
.rp-ced-head {
  display: flex;
  align-items: center;
  gap: 12px;
  height: 56px;
  padding: 0 20px;
  border-bottom: 1px solid var(--border);
  background: var(--card);
  flex-shrink: 0;
}
.rp-ced-crumb { display: inline-flex; align-items: center; gap: 7px; font-size: 13px; min-width: 0; }
.rp-ced-crumb-link {
  color: var(--muted-foreground);
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 360px;
}
.rp-ced-crumb-link:hover { color: var(--foreground); }
.rp-ced-crumb-sep { color: var(--input); }
.rp-ced-crumb-cur { font-weight: 650; }
.rp-ced-head-spacer { flex: 1; }
.rp-ced-credits {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 36px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--accent);
  color: var(--accent-foreground);
  text-decoration: none;
  font-size: 12.5px;
  font-weight: 600;
}

/* body split */
.rp-ced-body { flex: 1; display: flex; min-height: 0; }

/* tree pane */
.rp-ced-tree {
  width: 300px;
  flex-shrink: 0;
  border-right: 1px solid var(--border);
  background: var(--card);
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.rp-ced-tree-head { padding: 14px 16px 12px; border-bottom: 1px solid var(--border); }
.rp-ced-course-row { display: flex; align-items: center; gap: 8px; }
.rp-ced-course-name {
  flex: 1;
  min-width: 0;
  font-size: 14px;
  font-weight: 650;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rp-ced-course-meta { display: flex; align-items: center; gap: 8px; margin-top: 6px; }
.rp-ced-course-counts { font-size: 12px; color: var(--muted-foreground); }
.rp-ced-course-actions { display: flex; gap: 6px; margin-top: 10px; }
.rp-ced-course-btn {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 32px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font-size: 12px;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
}
.rp-ced-course-btn:hover { background: var(--secondary); }
.rp-ced-course-btn--disabled { opacity: 0.5; pointer-events: none; }

/* kebab trigger (shared: course/module/lesson) */
.rp-ced-kebab {
  width: 26px;
  height: 26px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  background: transparent;
  border-radius: 8px;
  color: var(--muted-foreground);
  cursor: pointer;
  flex-shrink: 0;
}
.rp-ced-kebab:hover { background: var(--secondary); color: var(--foreground); }

/* scroll area */
.rp-ced-tree-scroll { flex: 1; overflow-y: auto; padding: 8px 10px; }
.rp-ced-tree-empty { padding: 16px 10px; font-size: 12.5px; color: var(--muted-foreground); }

/* module row */
.rp-ced-modrow { display: flex; align-items: center; gap: 8px; padding: 9px 2px 5px 8px; }
.rp-ced-mod-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  background: transparent;
  color: var(--muted-foreground);
  cursor: pointer;
  padding: 0;
}
.rp-ced-mod-title {
  flex: 1;
  min-width: 0;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted-foreground);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: pointer;
}
.rp-ced-mod-meta { font-size: 11.5px; color: var(--muted-foreground); flex-shrink: 0; }

/* lesson row */
.rp-ced-lesson {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 4px 8px 30px;
  border-radius: 11px;
  background: transparent;
}
.rp-ced-lesson:hover { background: var(--secondary); }
.rp-ced-lesson--active { background: var(--accent); }
.rp-ced-lesson-title {
  flex: 1;
  min-width: 0;
  font-size: 13.5px;
  font-weight: 500;
  color: var(--foreground);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: pointer;
}
.rp-ced-lesson--active .rp-ced-lesson-title { color: var(--accent-foreground); font-weight: 650; }
.rp-ced-lesson-meta { font-size: 11.5px; color: var(--muted-foreground); flex-shrink: 0; }

/* + Урок affordance */
.rp-ced-addlesson {
  display: flex;
  align-items: center;
  gap: 7px;
  width: 100%;
  padding: 8px 10px 10px 30px;
  border: 0;
  background: transparent;
  color: var(--muted-foreground);
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  text-align: left;
}
.rp-ced-addlesson:hover { color: var(--foreground); }

/* footer */
.rp-ced-tree-foot { display: flex; gap: 8px; padding: 10px 14px 14px; border-top: 1px solid var(--border); }
.rp-ced-foot-btn {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  height: 36px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font-size: 12.5px;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
}
.rp-ced-foot-btn:hover { background: var(--secondary); }
.rp-ced-foot-btn--accent { background: var(--accent); color: var(--accent-foreground); border-color: var(--border); }

/* canvas host */
.rp-ced-canvas { flex: 1; overflow-y: auto; background: var(--background); min-height: 0; }
.rp-ced-canvas-inner { max-width: 820px; margin: 0 auto; padding: 28px 32px 140px; }
.rp-ced-canvas-context { font-size: 12px; color: var(--muted-foreground); margin-bottom: 8px; }

/* mobile pane headers — hidden on desktop */
.rp-ced-mhead { display: none; }
.rp-ced-mhead-back {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border: 0;
  background: transparent;
  color: var(--foreground);
  text-decoration: none;
  cursor: pointer;
  flex-shrink: 0;
}
.rp-ced-mhead-main { flex: 1; min-width: 0; }
.rp-ced-mhead-title { font-size: 14.5px; font-weight: 650; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rp-ced-mhead-sub { font-size: 11.5px; color: var(--muted-foreground); }
/* ≤768px: two-pane stack (structure ↔ lesson), toggled by [data-mobile-pane] */
@media (max-width: 768px) {
  .rp-ced-head { display: none; }
  .rp-ced-tree, .rp-ced-canvas { width: 100%; border-right: 0; }
  .rp-ced-tree-head { display: none; }
  .rp-ced-mhead {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 56px;
    padding: 0 14px;
    border-bottom: 1px solid var(--border);
    background: var(--card);
    flex-shrink: 0;
  }
  .rp-ced[data-mobile-pane="structure"] .rp-ced-canvas { display: none; }
  .rp-ced[data-mobile-pane="lesson"] .rp-ced-tree { display: none; }
  .rp-ced-canvas-inner { padding: 16px 16px 120px; }
}

/* ── LessonCanvas block document (Task 7) — inside rp-ced-canvas-inner ─────── */
.rp-lc-titlebar { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
.rp-lc-title {
  flex: 1; min-width: 0;
  font-size: 23px; font-weight: 700; letter-spacing: -0.01em; margin: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rp-lc-title-input {
  flex: 1; min-width: 0;
  font-size: 23px; font-weight: 700; letter-spacing: -0.01em;
  font-family: inherit;
  padding: 2px 8px;
  border: 1px solid var(--ring); border-radius: var(--radius-md);
  background: var(--card); color: var(--foreground);
}
.rp-lc-title-input:focus { outline: none; }
.rp-lc-pencil {
  width: 32px; height: 32px; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; border-radius: 8px; background: transparent;
  color: var(--muted-foreground); cursor: pointer;
}
.rp-lc-pencil:hover { background: var(--secondary); color: var(--foreground); }
.rp-lc-ai {
  display: inline-flex; align-items: center; gap: 7px; flex-shrink: 0;
  height: 36px; padding: 0 14px;
  border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--accent); color: var(--accent-foreground);
  font-size: 13px; font-weight: 600; cursor: pointer;
}
.rp-lc-status { font-size: 12.5px; color: var(--muted-foreground); margin: 4px 0 16px; }
.rp-lc-cover { max-width: 320px; margin-bottom: 16px; }

/* block cards */
.rp-lc-block {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 15px 16px; margin-bottom: 12px;
  border: 1px solid var(--border); border-radius: 14px; background: var(--card);
}
.rp-lc-block-icon { display: inline-flex; flex-shrink: 0; color: var(--muted-foreground); margin-top: 3px; }
.rp-lc-block-body { flex: 1; min-width: 0; }
.rp-lc-kebab {
  width: 28px; height: 28px; flex-shrink: 0; align-self: flex-start;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; border-radius: 8px; background: transparent;
  color: var(--muted-foreground); cursor: pointer;
}
.rp-lc-kebab:hover { background: var(--secondary); color: var(--foreground); }
.rp-menu .rp-lc-danger { color: var(--destructive); }
.rp-menu .rp-lc-danger:hover { background: var(--destructive-muted, var(--secondary)); color: var(--destructive); }

/* «+ Блок» affordance + in-canvas type popover */
.rp-lc-add { position: relative; margin-top: 4px; }
.rp-lc-addbtn {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; height: 44px;
  border: 1.5px dashed var(--input); border-radius: 14px; background: transparent;
  color: var(--muted-foreground); font: inherit; font-size: 13.5px; font-weight: 600; cursor: pointer;
}
.rp-lc-addbtn:hover { border-color: var(--ring); color: var(--foreground); }
.rp-lc-addbtn:disabled { opacity: 0.5; cursor: default; }
.rp-lc-add-backdrop { position: fixed; inset: 0; z-index: 11; }
.rp-lc-add-pop {
  position: absolute; left: 0; right: 0; bottom: 52px; z-index: 12;
  padding: 12px;
  background: var(--popover); border: 1px solid var(--border);
  border-radius: 16px; box-shadow: var(--shadow-lg);
}
.rp-lc-add-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-bottom: 10px; }
.rp-lc-add-tile {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 12px 4px 10px;
  border: 1px solid var(--border); border-radius: 13px; background: var(--card);
  color: var(--foreground); font: inherit; cursor: pointer;
}
.rp-lc-add-tile span { font-size: 11px; font-weight: 600; text-align: center; line-height: 1.2; }
.rp-lc-add-tile:hover { background: var(--accent); border-color: var(--ring); }
.rp-lc-add-tile:disabled { opacity: 0.5; cursor: default; }
.rp-lc-add-ai {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; height: 40px;
  border: 0; border-radius: var(--radius-lg);
  background: var(--accent); color: var(--accent-foreground);
  font: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
}
.rp-lc-add-ai:disabled { opacity: 0.5; cursor: default; }

@media (max-width: 600px) {
  .rp-lc-title, .rp-lc-title-input { font-size: 19px; }
  /* rp-lc-add-grid is already 4 columns at every width (Формула-мини-волна Task 3, 8 tiles → 2×4) —
     no mobile override needed. */
}

/* ── Autotest block: collapsed summary card body (opens the canvas editor, Task 8) ── */
.rp-lc-atsum {
  display: flex; align-items: center; gap: 12px; width: 100%;
  background: none; border: 0; cursor: pointer; text-align: left; padding: 4px 0;
  color: var(--foreground); font: inherit;
}
.rp-lc-atsum-title { font-size: 14.5px; font-weight: 600; }
.rp-lc-atsum-meta { font-size: 13px; color: var(--muted-foreground); }
.rp-lc-atsum-chev { margin-left: auto; display: inline-flex; color: var(--muted-foreground); }
.rp-lc-atsum:hover .rp-lc-atsum-chev { color: var(--primary); }

/* ── «✦ ИИ» menu: credits header + items (Task 9). The header is a non-menuitem row inside rp-menu. ── */
.rp-lc-ai-menu { min-width: 250px; }
.rp-lc-ai-head {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 12px 10px; margin: -2px -2px 4px;
  border-bottom: 1px solid var(--border); background: var(--background);
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
}
.rp-lc-ai-head-bolt { display: inline-flex; color: var(--warning, var(--primary)); }
.rp-lc-ai-head-bal { flex: 1; font-size: 13px; font-weight: 650; }
.rp-lc-ai-head-top { font-size: 12px; font-weight: 600; color: var(--primary); text-decoration: none; }
.rp-lc-ai-head-top:hover { text-decoration: underline; }

/* ── Inline AI drafts (Task 9): primary-tinted card border + «✦ ЧЕРНОВИК ИИ» badge ── */
.rp-lc-block--draft { border-color: color-mix(in srgb, var(--primary) 45%, var(--border)); border-width: 1.5px; }
.rp-lc-draft-badge {
  display: inline-flex; align-items: center; gap: 4px; margin-bottom: 7px;
  padding: 2px 9px; border-radius: 999px;
  font-size: 10.5px; font-weight: 700;
  background: var(--accent); color: var(--accent-foreground);
}
.rp-lc-draft-md { font-size: 14px; line-height: 1.6; }
.rp-lc-draft-at { font-size: 13.5px; color: var(--muted-foreground); }

/* ── Sticky «Черновики ИИ: N» accept/discard bar. Sticky inside the scrolling canvas (rp-ced-canvas). ── */
.rp-lc-draftbar {
  position: sticky; bottom: 18px; z-index: 14;
  display: flex; align-items: center; gap: 10px;
  width: min(440px, 100%); margin: 16px auto 0;
  padding: 10px 14px;
  background: var(--card); border: 1px solid var(--border);
  border-radius: 16px; box-shadow: var(--shadow-lg);
}
.rp-lc-draftbar-icon { display: inline-flex; color: var(--primary); flex-shrink: 0; }
.rp-lc-draftbar-label { flex: 1; font-size: 13px; font-weight: 600; min-width: 0; }
.rp-lc-draftbar-discard {
  height: 34px; padding: 0 13px; flex-shrink: 0;
  border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--card); color: var(--destructive);
  font: inherit; font-size: 12.5px; font-weight: 600; cursor: pointer;
}
.rp-lc-draftbar-discard:hover { background: var(--secondary); }
.rp-lc-draftbar-discard:disabled { opacity: 0.6; cursor: default; }
.rp-lc-draftbar-accept {
  display: inline-flex; align-items: center; gap: 7px;
  height: 34px; padding: 0 15px; flex-shrink: 0;
  border: 0; border-radius: var(--radius-md);
  background: var(--primary); color: var(--primary-foreground);
  font: inherit; font-size: 12.5px; font-weight: 600; cursor: pointer;
}
.rp-lc-draftbar-accept:disabled { opacity: 0.7; cursor: default; }

@media (max-width: 768px) {
  /* Mobile: the bar floats above the content edge (mockup 390px), safe-area padded (П-15 doesn't apply —
     the editor canvas has no bottom nav — but keep the inset so it clears the home indicator). */
  .rp-lc-draftbar {
    width: auto; margin: 12px 4px 0;
    bottom: calc(12px + env(safe-area-inset-bottom, 0px));
  }
}

/* ── Formula block editor (rp-frm, Формула-мини-волна Task 3): rendered INLINE in the rp-lc-block card
   body, alongside text/video/file/image — no full-canvas takeover (unlike the autotest editor below). ── */
.rp-frm { display: flex; flex-direction: column; gap: 8px; }
.rp-frm-input {
  width: 100%; min-height: 88px; resize: vertical;
  padding: 10px 12px;
  border: 1px solid var(--input); border-radius: var(--radius-md);
  background: var(--card); color: var(--foreground);
  font-family: var(--font-mono); font-size: 13.5px; line-height: 1.5;
}
.rp-frm-count { align-self: flex-end; font-size: 12px; color: var(--muted-foreground); }
.rp-frm-count--over { color: var(--destructive); font-weight: 600; }
.rp-frm-preview {
  display: flex; justify-content: center;
  min-height: 44px; padding: 14px; overflow-x: auto;
  border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--background);
}
.rp-frm-foot { display: flex; align-items: center; gap: 10px; }
.rp-frm-error { font-size: 12.5px; color: var(--destructive); min-width: 0; }
.rp-frm-spacer { flex: 1; }

/* ── Formula display card (rp-formula, Формула-мини-волна Task 4): katex-render.js's render target,
   shared verbatim by the editor preview (Task 3, above) and every student surface (LessonContentBody,
   ReaderDocument). ── */
.rp-formula {
  display: flex; justify-content: center;
  padding: 14px; overflow-x: auto;
  border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--card);
}

/* ── Autotest editor IN THE CANVAS (rp-atc chrome + rp-atf settings; questions reuse rp-ted-*) ── */
.rp-atc { display: flex; flex-direction: column; gap: 14px; }
.rp-atc-back {
  display: inline-flex; align-items: center; gap: 6px; align-self: flex-start;
  background: none; border: 0; cursor: pointer; padding: 0;
  color: var(--muted-foreground); font: inherit; font-size: 13px; font-weight: 500;
}
.rp-atc-back:hover { color: var(--foreground); }
.rp-atc-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.rp-atc-titlewrap { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.rp-atc-title { font-size: 22px; font-weight: 800; letter-spacing: -0.01em; margin: 0; }
.rp-atc-meta { font-size: 12.5px; color: var(--muted-foreground); }
.rp-atc-head-spacer { flex: 1; }

.rp-atf { display: flex; flex-direction: column; gap: 12px; }
.rp-atf-settings {
  display: flex; align-items: center; flex-wrap: wrap; gap: 20px;
  padding: 14px 16px; border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--card);
}
.rp-atf-set { display: flex; align-items: center; gap: 10px; }
.rp-atf-set-label { font-size: 13.5px; font-weight: 600; }
.rp-atf-thr { display: flex; align-items: center; gap: 6px; }
.rp-atf-thr .rp-ted-input { width: 84px; height: 34px; }
.rp-atf-thr-unit { font-size: 13px; color: var(--muted-foreground); }
.rp-atf-correct-tag { font-size: 10.5px; font-weight: 700; letter-spacing: 0.03em; color: var(--success-muted-foreground); flex-shrink: 0; }
.rp-atf-ansdot { width: 6px; height: 6px; border-radius: 50%; background: var(--muted-foreground); flex-shrink: 0; }
.rp-atf-desc { display: flex; flex-direction: column; gap: 8px; }
.rp-atf-desc-toggle {
  display: flex; align-items: center; gap: 8px; width: 100%;
  background: none; border: 0; cursor: pointer; text-align: left; padding: 2px 0;
  color: var(--muted-foreground); font: inherit;
}
.rp-atf-desc-toggle:hover { color: var(--foreground); }
.rp-atf-desc-label { font-size: 13.5px; font-weight: 600; color: var(--foreground); }
.rp-atf-desc-excerpt {
  font-size: 13px; color: var(--muted-foreground); overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; min-width: 0;
}
.rp-atf-desc-text {
  width: 100%; min-height: 64px; padding: 10px 12px;
  border: 1px solid var(--input); border-radius: var(--radius-md); background: var(--card);
  color: var(--foreground); font: inherit; font-size: 14px; line-height: 1.5; resize: vertical;
}
.rp-ted-opt--correct { border-radius: 11px; padding: 6px 8px; border: 1px solid var(--success); background: var(--success-muted); }
.rp-ted-opt--correct .rp-ted-input { color: var(--success-muted-foreground); }

/* ── Финансы (/finance) hub — wave 5 Task 2, Финансы.dc.html «Платежи» tab ────────────────────────
   The /finance page shell (toolbar + tab panel wrapper) plus the payments tab: the received-per-period
   summary card, the Месяц/Квартал/Год period segment, the status dropdown, the desktop payments table
   (grid 100px 1.3fr 1.2fr 110px 120px 24px) + its ≤640px card view, «Показать ещё» + the footnote.
   Amounts use tabular-nums. All colours via var(--…) tokens (dark mode flips for free). */
.rp-fin-toolbar { display: flex; align-items: center; margin-bottom: 4px; }
.rp-fin-panel { padding-top: 4px; }

/* summary row: card · spacer · period segment · status filter */
.rp-fin-summary {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin: 18px 0;
}
.rp-fin-spacer { flex: 1; }

.rp-fin-sumcard {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 14px 20px;
}
.rp-fin-sumcard-label {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--muted-foreground);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.rp-fin-sumcard-row { display: flex; align-items: baseline; gap: 8px; }
.rp-fin-sumcard-amount {
  font-size: 26px;
  font-weight: 700;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.rp-fin-sumcard-count { font-size: 12.5px; font-weight: 600; color: var(--success-muted-foreground); }

.rp-fin-periods {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  background: var(--muted);
  border-radius: var(--radius-md);
}
.rp-fin-period {
  padding: 6px 12px;
  border: 0;
  border-radius: var(--radius-sm);
  font: inherit;
  font-size: 12.5px;
  font-weight: 500;
  background: transparent;
  color: var(--muted-foreground);
  cursor: pointer;
}
.rp-fin-period--active {
  font-weight: 600;
  background: var(--card);
  color: var(--foreground);
  box-shadow: var(--shadow-xs);
}

.rp-fin-filterbox { position: relative; display: inline-flex; align-items: center; }
.rp-fin-filter-ico {
  position: absolute;
  left: 10px;
  width: 14px;
  height: 14px;
  display: inline-flex;
  color: var(--muted-foreground);
  pointer-events: none;
}
.rp-fin-filter {
  height: 34px;
  padding: 0 12px 0 30px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 12.5px;
  cursor: pointer;
}

/* payments table (desktop) */
.rp-fin-table {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  overflow: hidden;
}
.rp-fin-thead,
.rp-fin-row {
  display: grid;
  grid-template-columns: 100px 1.3fr 1.2fr 110px 120px 24px;
  gap: 12px;
  align-items: center;
  padding: 13px 18px;
  border-bottom: 1px solid var(--border);
}
.rp-fin-thead {
  padding: 10px 18px;
  font-size: 11.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted-foreground);
}
.rp-fin-row { text-decoration: none; color: var(--foreground); }
.rp-fin-row:last-child { border-bottom: 0; }
a.rp-fin-row:hover { background: var(--secondary); }
.rp-fin-date { font-size: 13px; color: var(--muted-foreground); }
.rp-fin-payer { min-width: 0; }
.rp-fin-payer-name {
  display: block;
  font-size: 13.5px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.rp-fin-payer-sub { display: block; font-size: 12px; color: var(--muted-foreground); }
.rp-fin-item { font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rp-fin-amount { font-size: 13.5px; font-weight: 600; text-align: right; font-variant-numeric: tabular-nums; }
.rp-fin-chev { color: var(--muted-foreground); text-align: right; }

/* payments cards (mobile) */
.rp-fin-cards { display: none; flex-direction: column; gap: 9px; }
.rp-fin-card {
  display: block;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 13px 15px;
  text-decoration: none;
  color: var(--foreground);
}
.rp-fin-card-top { display: flex; align-items: center; gap: 8px; margin-bottom: 3px; }
.rp-fin-card-payer {
  flex: 1;
  min-width: 0;
  font-size: 13.5px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.rp-fin-card-amount { font-size: 14px; font-weight: 700; font-variant-numeric: tabular-nums; }
.rp-fin-card-mid { display: flex; align-items: center; gap: 8px; }
.rp-fin-card-item {
  flex: 1;
  min-width: 0;
  font-size: 12.5px;
  color: var(--muted-foreground);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.rp-fin-card-meta { font-size: 11.5px; color: var(--muted-foreground); margin-top: 3px; }

.rp-fin-more {
  margin-top: 12px;
  height: 36px;
  padding: 0 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.rp-fin-more:hover { background: var(--secondary); }

.rp-fin-none { padding: 24px 4px; font-size: 13px; color: var(--muted-foreground); }
.rp-fin-note { font-size: 12px; color: var(--muted-foreground); margin: 12px 2px 0; }

@media (max-width: 640px) {
  .rp-fin-table { display: none; }
  .rp-fin-cards { display: flex; }
  .rp-fin-sumcard { width: 100%; order: 2; }
  .rp-fin-summary { gap: 8px; }
}

/* ── Финансы «Прайс» tab — wave 5 Task 3, Финансы.dc.html §Прайс ──────────────────────────────────
   Two read sections stacked in PricingPanel: «Пакеты занятий» (desktop table, grid
   1.2fr 1fr 100px 100px 110px 70px 40px — Название/Состав/Цена/Срок/Кому видно/Активен/edit) with its
   ≤640px card view (no toggle/pencil, LOCKED-12), and read-only «Курсы-продукты» (desktop table, grid
   1.6fr 1fr 100px 110px 110px, NO header row, Published-only) + its own ≤640px card view. Cell classes
   rp-fin-amount/-price-name/-price-mix are generic enough to sit in either grid — reused rather than
   duplicated. The Активен toggle is hand-rolled (rp-fin-price-switch) — 36×21 doesn't match any of
   BbSwitch's three fixed presets (П-9), same reasoning as NotifChannelSwitch. */
.rp-fin-price-section { margin-bottom: 32px; }
.rp-fin-price-sectionhead { display: flex; align-items: center; margin-bottom: 12px; }
.rp-fin-price-title { font-size: 15px; font-weight: 700; }
.rp-fin-price-sub { font-size: 12.5px; color: var(--muted-foreground); margin-top: 2px; }

.rp-fin-price-addbtn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 36px;
  padding: 0 14px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-foreground);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.rp-fin-price-addbtn:hover { opacity: 0.92; }

/* packages table (desktop) */
.rp-fin-price-table {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  overflow: hidden;
}
.rp-fin-price-thead,
.rp-fin-price-row {
  display: grid;
  grid-template-columns: 1.2fr 1fr 100px 100px 110px 70px 40px;
  gap: 12px;
  align-items: center;
  padding: 13px 18px;
  border-bottom: 1px solid var(--border);
}
.rp-fin-price-thead {
  padding: 10px 18px;
  font-size: 11.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted-foreground);
}
.rp-fin-price-row:last-child { border-bottom: 0; }
.rp-fin-price-name { font-size: 13.5px; font-weight: 600; }
.rp-fin-price-mix { font-size: 13px; color: var(--muted-foreground); }
.rp-fin-price-term { font-size: 13px; color: var(--muted-foreground); }

.rp-fin-price-vis {
  display: inline-block;
  padding: 3px 9px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 600;
  background: var(--muted);
  color: var(--muted-foreground);
}
.rp-fin-price-vis--accent { background: var(--accent); color: var(--accent-foreground); }

/* hand-rolled 36×21 switch — see file-header note + П-9 */
.rp-fin-price-switch {
  position: relative;
  width: 36px;
  height: 21px;
  border: 0;
  border-radius: 999px;
  background: var(--border);
  padding: 0;
  cursor: pointer;
}
.rp-fin-price-switch[aria-checked="true"] { background: var(--primary); }
.rp-fin-price-switch-thumb {
  position: absolute;
  top: 2.5px;
  left: 2.5px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #fff;
  box-shadow: var(--shadow-xs);
  transition: left 0.15s;
}
.rp-fin-price-switch[aria-checked="true"] .rp-fin-price-switch-thumb { left: 17.5px; }

.rp-fin-price-edit {
  width: 30px;
  height: 30px;
  border: 0;
  background: transparent;
  color: var(--muted-foreground);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.rp-fin-price-edit:hover { color: var(--foreground); }

/* courses-products table (desktop, no header row) */
.rp-fin-price-coursetable {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  overflow: hidden;
}
.rp-fin-price-courserow {
  display: grid;
  grid-template-columns: 1.6fr 1fr 100px 110px 110px;
  gap: 12px;
  align-items: center;
  padding: 13px 18px;
  border-bottom: 1px solid var(--border);
}
.rp-fin-price-courserow:last-child { border-bottom: 0; }
.rp-fin-price-courselink { font-size: 12.5px; font-weight: 600; color: var(--primary); text-decoration: none; text-align: right; }
.rp-fin-price-courselink:hover { text-decoration: underline; }

/* mobile cards (≤640px) — shared by packages AND courses-products; no toggle/pencil (LOCKED-12) */
.rp-fin-price-cards { display: none; flex-direction: column; gap: 9px; }
.rp-fin-price-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 13px 15px;
}
.rp-fin-price-card-top { display: flex; align-items: center; gap: 8px; }
.rp-fin-price-card-name {
  flex: 1;
  min-width: 0;
  font-size: 13.5px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.rp-fin-price-card-amount { font-size: 14px; font-weight: 700; font-variant-numeric: tabular-nums; }
.rp-fin-price-card-meta { font-size: 12.5px; color: var(--muted-foreground); margin-top: 2px; }
.rp-fin-price-card-mid { display: flex; align-items: center; gap: 8px; margin-top: 2px; }
.rp-fin-price-card-mid .rp-fin-price-card-meta { flex: 1; margin-top: 0; }

@media (max-width: 640px) {
  .rp-fin-price-table,
  .rp-fin-price-coursetable { display: none; }
  .rp-fin-price-cards { display: flex; }
}

/* PackageDialog (Финансы → Прайс «Новый пакет»/«Пакет «{имя}»») audience multi-select — reuses
   rp-covw-dlg* chrome (head/close/fields/err/submit) verbatim; only the checkbox-style roster picker
   below is new (rp-fin-pkg-*). */
.rp-fin-pkg-audlist { display: flex; flex-direction: column; gap: 4px; max-height: 220px; overflow-y: auto; }
.rp-fin-pkg-audrow {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border: 0;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--foreground);
  font: inherit;
  font-size: 13px;
  text-align: left;
  cursor: pointer;
}
.rp-fin-pkg-audrow:hover { background: var(--secondary); }
.rp-fin-pkg-audrow--picked { background: var(--accent); color: var(--accent-foreground); }
.rp-fin-pkg-audcheck {
  width: 16px;
  height: 16px;
  border: 1px solid var(--border);
  border-radius: 4px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.rp-fin-pkg-audrow--picked .rp-fin-pkg-audcheck { border-color: var(--accent-foreground); }
.rp-fin-pkg-audname { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ── Финансы «Приём оплат» tab — wave 5 Task 4, Финансы.dc.html §Приём оплат ──────────────────────
   GatewayPanel's connect form (ported from the retired /finance/gateway page): a max-width 560px column
   with the intro copy, the green «Подключено» banner (rp-gw-banner, --off when reception is disabled),
   the Robokassa/ЮКасса segment toggle (rp-gw-seg) + 54-ФЗ recommendation caption, the provider fields
   (rp-gw-fields / -row2 two-up rows / -field / -label / -input / -hint), the «Партнёрский API возвратов»
   details disclosure (rp-gw-details) and the submit row (rp-gw-actions). ≤640px: single column, inputs
   42-44px, buttons full-width (mockup mobile). All colours via var(--…) tokens. */
.rp-gw { max-width: 560px; }
.rp-gw-intro { font-size: 13px; color: var(--muted-foreground); line-height: 1.6; margin: 0 0 16px; }

.rp-gw-banner {
  display: flex;
  align-items: center;
  gap: 12px;
  border: 1px solid color-mix(in srgb, var(--success) 40%, var(--border));
  background: var(--success-muted);
  color: var(--success-muted-foreground);
  border-radius: var(--radius-lg);
  padding: 12px 16px;
  margin-bottom: 18px;
}
.rp-gw-banner-ico {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--success);
  color: var(--success-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.rp-gw-banner--off { border-color: var(--border); background: var(--muted); color: var(--muted-foreground); }
.rp-gw-banner--off .rp-gw-banner-ico { background: var(--muted-foreground); color: var(--card); }
.rp-gw-banner-txt { flex: 1; min-width: 0; }
.rp-gw-banner-title { font-size: 13.5px; font-weight: 700; }
.rp-gw-banner-sub { font-size: 12.5px; }
.rp-gw-banner-btn {
  height: 32px;
  padding: 0 12px;
  border: 1px solid color-mix(in srgb, var(--success) 45%, var(--border));
  border-radius: var(--radius-md);
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  flex-shrink: 0;
}
.rp-gw-banner-btn:disabled { opacity: 0.6; cursor: not-allowed; }

.rp-gw-seg {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  background: var(--muted);
  border-radius: var(--radius-md);
  margin-bottom: 6px;
}
.rp-gw-seg-tab {
  padding: 7px 16px;
  border: 0;
  border-radius: var(--radius-sm);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  background: transparent;
  color: var(--muted-foreground);
  cursor: pointer;
}
.rp-gw-seg-tab--active { font-weight: 600; background: var(--card); color: var(--foreground); box-shadow: var(--shadow-xs); }

.rp-gw-reco { font-size: 12px; color: var(--success-muted-foreground); font-weight: 600; margin-bottom: 16px; }

.rp-gw-fields { display: grid; gap: 14px; margin-bottom: 18px; }
.rp-gw-row2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.rp-gw-field { display: block; }
.rp-gw-field--half { max-width: 262px; }
.rp-gw-label { display: block; font-size: 12.5px; font-weight: 600; margin-bottom: 5px; }
.rp-gw-input {
  width: 100%;
  height: 38px;
  padding: 0 12px;
  border: 1px solid var(--input);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 13.5px;
}
select.rp-gw-input { padding: 0 10px; cursor: pointer; }
.rp-gw-hint { display: block; font-size: 11.5px; color: var(--muted-foreground); margin-top: 4px; }
.rp-gw-check { display: flex; align-items: center; gap: 8px; font-size: 13.5px; cursor: pointer; }
.rp-gw-check input { width: 16px; height: 16px; accent-color: var(--primary); cursor: pointer; }

.rp-gw-details {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 10px 14px;
  font-size: 13px;
}
.rp-gw-details > summary { cursor: pointer; font-weight: 600; color: var(--muted-foreground); }
.rp-gw-details-body { display: grid; gap: 14px; padding-top: 12px; }

.rp-gw-actions { display: flex; gap: 10px; }

@media (max-width: 640px) {
  .rp-gw { max-width: none; }
  .rp-gw-banner { flex-wrap: wrap; }
  .rp-gw-banner-btn { width: 100%; height: 44px; }
  .rp-gw-row2 { grid-template-columns: 1fr; }
  .rp-gw-field--half { max-width: none; }
  .rp-gw-input { height: 44px; font-size: 14px; }
  .rp-gw-actions { flex-direction: column; }
  .rp-gw-actions .rp-btn-submit { width: 100%; height: 44px; }
}

/* ── Финансы «Подписка» tab — wave 5 Task 4, Финансы.dc.html §Подписка ────────────────────────────
   SubscriptionPanel (ported from the retired /finance/subscription page): the status pill (rp-sub-pill,
   tone --ok/--warn/--danger from the shared subscription vocabulary, П-6) + «Оплачено до …» line
   (rp-sub-status/-paid), the 3-plan grid (rp-sub-plans, max-width 880px) with per-plan cards
   (rp-sub-plan, --current gets the primary border + «Текущий» badge), the ✓/✗ feature list from the real
   PlatformPlanLimits (rp-sub-feats/-feat(--off)/-feat-ico), the CTA (rp-sub-plan-cta --primary «Продлить»
   / --outline «Перейти на план» / --free disabled) and the promo field (rp-sub-promo, reuses rp-gw-field).
   ≤640px: single column, feature list hidden, status boxed, CTAs full-width (mockup mobile). */
.rp-sub-status { display: flex; align-items: center; gap: 10px; margin-bottom: 20px; flex-wrap: wrap; }
.rp-sub-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 11px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
}
.rp-sub-pill-dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.rp-sub-pill--ok { background: var(--success-muted); color: var(--success-muted-foreground); }
.rp-sub-pill--warn { background: var(--warning-muted); color: var(--warning-muted-foreground); }
.rp-sub-pill--danger { background: var(--destructive-muted); color: var(--destructive-muted-foreground); }
.rp-sub-paid { font-size: 13px; color: var(--muted-foreground); }

.rp-sub-plans { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; max-width: 880px; }
.rp-sub-plan {
  border: 1.5px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 20px;
  display: flex;
  flex-direction: column;
}
.rp-sub-plan--current { border-color: var(--primary); }
.rp-sub-plan-head { display: flex; align-items: center; gap: 8px; }
.rp-sub-plan-name { font-size: 15.5px; font-weight: 700; }
.rp-sub-plan-badge {
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--primary);
  color: var(--primary-foreground);
  font-size: 10.5px;
  font-weight: 700;
}
.rp-sub-plan-price { margin: 8px 0 12px; font-size: 26px; font-weight: 700; letter-spacing: -0.02em; }
.rp-sub-plan-per { font-size: 12.5px; color: var(--muted-foreground); font-weight: 500; }

.rp-sub-feats { display: flex; flex-direction: column; }
.rp-sub-feat { display: flex; align-items: center; gap: 8px; font-size: 12.5px; padding: 3px 0; color: var(--foreground); }
.rp-sub-feat--off { color: var(--muted-foreground); }
.rp-sub-feat-ico { width: 14px; height: 14px; display: inline-flex; flex-shrink: 0; }

.rp-sub-plan-grow { flex: 1; }
.rp-sub-plan-cta {
  margin-top: 14px;
  height: 36px;
  border: 0;
  border-radius: var(--radius-md);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.rp-sub-plan-cta--primary { background: var(--primary); color: var(--primary-foreground); }
.rp-sub-plan-cta--outline { background: transparent; color: var(--primary); border: 1.5px solid var(--primary); }
.rp-sub-plan-cta--free { background: transparent; color: var(--muted-foreground); border: 1px solid var(--border); cursor: not-allowed; }
.rp-sub-plan-cta:disabled { opacity: 0.7; cursor: not-allowed; }

.rp-sub-promo { margin-top: 18px; max-width: 340px; }

@media (max-width: 640px) {
  .rp-sub-plans { grid-template-columns: 1fr; }
  .rp-sub-feats { display: none; }
  .rp-sub-status {
    padding: 8px 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--card);
  }
  .rp-sub-plan-cta { width: 100%; height: 38px; }
  .rp-sub-promo { max-width: none; }
}

/* ── Финансы «ИИ-кредиты» tab — wave 5 Task 5, Финансы.dc.html §ИИ-кредиты ─────────────────────────
   AiCreditsPanel (ported from the retired /finance/ai-credits page): the balance+promo-redeem two-card
   row (rp-ai-top/-card/-card-label, rp-ai-avail/-avail-num/-avail-meta/-avail-note, rp-ai-promo-title/
   -promo-row/-promo-btn — the redeem input reuses rp-gw-input), the discount-code field for a pack
   purchase (rp-ai-discount, a distinct mechanism from the redeem box above — a percent code applied at
   checkout, carried over from the retired page's _discountCode — reuses rp-gw-field/-label), the pack
   grid (rp-ai-packs/-pack/-pack-name/-pack-credits/-pack-bottom/-pack-price/-pack-buy) + its ≤640px row
   list (rp-ai-packs-m/-pack-row/-pack-row-info/-pack-row-name/-pack-row-credits/-pack-row-price/
   -pack-row-buy), and the desktop-only history (rp-ai-history-section hides the whole title+card at
   ≤640px per the mockup's LOCKED-12 — no mobile counterpart exists; rp-ai-history/-history-row/
   -history-date/-history-kind/-history-delta(--plus) — grid 130px 1fr 80px, no header row). */
.rp-ai-top { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; max-width: 880px; margin-bottom: 24px; }
.rp-ai-card { border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--card); padding: 20px; }
.rp-ai-card-label {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--muted-foreground);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 8px;
}
.rp-ai-avail { display: flex; align-items: baseline; gap: 8px; }
.rp-ai-avail-num { font-size: 30px; font-weight: 700; letter-spacing: -0.02em; }
.rp-ai-avail-meta { font-size: 13px; color: var(--muted-foreground); }
.rp-ai-avail-note { font-size: 12.5px; color: var(--muted-foreground); margin-top: 6px; }

.rp-ai-promo-title { font-size: 13.5px; font-weight: 700; margin-bottom: 8px; }
.rp-ai-promo-row { display: flex; gap: 8px; }
.rp-ai-promo-btn {
  flex-shrink: 0;
  height: 38px;
  padding: 0 16px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-foreground);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.rp-ai-promo-btn:disabled { opacity: 0.7; cursor: not-allowed; }

.rp-ai-discount { margin-bottom: 16px; max-width: 340px; }

.rp-ai-section-title { font-size: 15px; font-weight: 700; margin-bottom: 10px; }

.rp-ai-packs { display: grid; grid-template-columns: repeat(3, minmax(0, 220px)); gap: 12px; margin-bottom: 24px; }
.rp-ai-pack { border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--card); padding: 18px; }
.rp-ai-pack-name { font-size: 14px; font-weight: 700; }
.rp-ai-pack-credits { font-size: 13px; color: var(--muted-foreground); margin: 2px 0 10px; }
.rp-ai-pack-bottom { display: flex; align-items: center; gap: 10px; }
.rp-ai-pack-price { font-size: 17px; font-weight: 700; }
.rp-ai-pack-buy {
  margin-left: auto;
  height: 32px;
  padding: 0 14px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-foreground);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
}
.rp-ai-pack-buy:disabled { opacity: 0.7; cursor: not-allowed; }

.rp-ai-packs-m { display: none; flex-direction: column; gap: 9px; margin-bottom: 24px; }
.rp-ai-pack-row {
  display: flex;
  align-items: center;
  gap: 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 13px 15px;
}
.rp-ai-pack-row-info { flex: 1; min-width: 0; }
.rp-ai-pack-row-name { font-size: 13.5px; font-weight: 600; }
.rp-ai-pack-row-credits { font-size: 12px; color: var(--muted-foreground); }
.rp-ai-pack-row-price { font-size: 14px; font-weight: 700; }
.rp-ai-pack-row-buy {
  height: 34px;
  padding: 0 14px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-foreground);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
}
.rp-ai-pack-row-buy:disabled { opacity: 0.7; cursor: not-allowed; }

.rp-ai-history { border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--card); overflow: hidden; max-width: 680px; }
.rp-ai-history-row { display: grid; grid-template-columns: 130px 1fr 80px; gap: 12px; align-items: center; padding: 11px 18px; border-bottom: 1px solid var(--border); }
.rp-ai-history-row:last-child { border-bottom: 0; }
.rp-ai-history-date { font-size: 12.5px; color: var(--muted-foreground); }
.rp-ai-history-kind { font-size: 13px; }
.rp-ai-history-delta { font-size: 13px; font-weight: 600; text-align: right; font-variant-numeric: tabular-nums; color: var(--foreground); }
.rp-ai-history-delta--plus { color: var(--success-muted-foreground); }
.rp-ai-history-empty { padding: 24px 4px; font-size: 13px; color: var(--muted-foreground); }

@media (max-width: 640px) {
  .rp-ai-top { grid-template-columns: 1fr; gap: 10px; margin-bottom: 10px; }
  .rp-ai-card { padding: 16px; }
  .rp-ai-card-label { font-size: 11px; }
  .rp-ai-avail-num { font-size: 26px; }
  .rp-ai-avail-note { font-size: 12px; }
  .rp-ai-promo-title { font-size: 12.5px; }
  .rp-ai-discount { max-width: none; }
  .rp-ai-section-title { font-size: 13.5px; }
  .rp-ai-packs { display: none; }
  .rp-ai-packs-m { display: flex; }
  /* LOCKED-12: the mockup has no mobile history block at all — hide the whole section, not just the table. */
  .rp-ai-history-section { display: none; }
}

/* ── Task 6 (wave 5): /payments/{id} + /receipts/{id} (Платёж и чек.dc.html) ────────────────────────
   Two entity pages sharing one column wrapper. All colours/radii/shadows via tokens. Requisites stay
   two-column on mobile (brief); cards go full-width (the wrapper is already single-column in the shell). */
.rp-pmt { max-width: 640px; margin: 0 auto; }

/* Payment card */
.rp-pmt-card {
  position: relative;
  border: 1px solid var(--border); border-radius: var(--radius-xl);
  background: var(--card); box-shadow: var(--shadow-lg); padding: 28px; overflow: hidden;
}
.rp-pmt-crumb {
  display: inline-flex; align-items: center; gap: 5px; margin-bottom: 4px;
  font-size: 12.5px; font-weight: 600; color: var(--muted-foreground); text-decoration: none;
}
.rp-pmt-crumb:hover { color: var(--foreground); }
.rp-pmt-head { display: flex; align-items: flex-start; gap: 12px; margin: 6px 0 22px; }
.rp-pmt-head-main { flex: 1; min-width: 0; }
.rp-pmt-title { font-size: 22px; font-weight: 700; letter-spacing: -0.01em; margin: 0 0 2px; }
.rp-pmt-ulid { font-size: 13px; color: var(--muted-foreground); font-family: var(--font-mono); }

/* Requisites table */
.rp-pmt-rows { border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; margin-bottom: 18px; }
.rp-pmt-row {
  display: grid; grid-template-columns: 150px 1fr; gap: 12px;
  padding: 11px 16px; border-bottom: 1px solid var(--border); font-size: 13.5px;
}
.rp-pmt-row--last { border-bottom: 0; }
.rp-pmt-rows .rp-pmt-row:last-child { border-bottom: 0; }
.rp-pmt-k { color: var(--muted-foreground); }
.rp-pmt-v { font-weight: 500; }
.rp-pmt-v--strong { font-weight: 600; }

/* Refund action */
.rp-pmt-actions { display: flex; align-items: center; gap: 10px; margin-bottom: 20px; }
.rp-pmt-refund-btn {
  display: inline-flex; align-items: center; gap: 7px; height: 36px; padding: 0 14px;
  border: 1.5px solid var(--destructive); border-radius: var(--radius-md);
  background: transparent; color: var(--destructive);
  font: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
}
.rp-pmt-refund-btn:hover { background: var(--destructive-muted, var(--muted)); }

/* Refunds table */
.rp-pmt-refunds-title { font-size: 13.5px; font-weight: 700; margin-bottom: 8px; }
.rp-pmt-rf-table { border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; }
.rp-pmt-rf-thead, .rp-pmt-rf-row {
  display: grid; grid-template-columns: 90px 90px 1fr 120px; gap: 10px; align-items: center;
}
.rp-pmt-rf-thead {
  padding: 9px 16px; border-bottom: 1px solid var(--border);
  font-size: 11px; font-weight: 600; color: var(--muted-foreground);
  text-transform: uppercase; letter-spacing: 0.04em;
}
.rp-pmt-rf-row { padding: 11px 16px; border-bottom: 1px solid var(--border); font-size: 13px; }
.rp-pmt-rf-row:last-child { border-bottom: 0; }
.rp-pmt-rf-amount { font-weight: 600; }
.rp-pmt-rf-date { color: var(--muted-foreground); }

/* Refund dialog (reuses rp-covw-dlg head/close chrome + rp-sched-dlg-label/-input) */
.rp-pmt-rf-dlg { max-width: 400px; }
.rp-pmt-rf-desc { font-size: 12.5px; color: var(--muted-foreground); line-height: 1.55; margin: 0 0 16px; }
.rp-pmt-rf-fields { display: grid; gap: 12px; }
.rp-pmt-rf-hint { font-size: 12px; color: var(--muted-foreground); margin: 8px 0 0; }
.rp-pmt-rf-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 18px; }
.rp-pmt-rf-cancel {
  height: 36px; padding: 0 14px; border: 1px solid var(--border); border-radius: var(--radius-md);
  background: transparent; color: var(--foreground); font: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
}
.rp-pmt-rf-cancel:hover { background: var(--secondary); }
.rp-pmt-rf-submit {
  height: 36px; padding: 0 16px; border: 0; border-radius: var(--radius-md);
  background: var(--destructive); color: var(--destructive-foreground);
  font: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
}
.rp-pmt-rf-submit:disabled { opacity: 0.6; cursor: default; }

/* Receipt card */
.rp-pmt-rcpt-card {
  border: 1px solid var(--border); border-radius: var(--radius-xl);
  background: var(--card); box-shadow: var(--shadow-lg); padding: 28px;
}
.rp-pmt-rcpt-head { display: flex; align-items: center; gap: 12px; margin-bottom: 20px; }
.rp-pmt-rcpt-badge {
  width: 40px; height: 40px; flex-shrink: 0; border-radius: var(--radius-md);
  background: var(--accent); color: var(--accent-foreground);
  display: inline-flex; align-items: center; justify-content: center;
}
.rp-pmt-rcpt-title { font-size: 19px; font-weight: 700; margin: 0; }
.rp-pmt-rcpt-sub { font-size: 12.5px; color: var(--muted-foreground); }
.rp-pmt-rcpt-table {
  border: 1px dashed var(--border); border-radius: var(--radius-lg);
  padding: 6px 16px; margin-bottom: 18px;
}
.rp-pmt-rcpt-row {
  display: flex; align-items: baseline; gap: 12px;
  padding: 10px 0; border-bottom: 1px dashed var(--border); font-size: 13.5px;
}
.rp-pmt-rcpt-k { color: var(--muted-foreground); }
.rp-pmt-rcpt-leader { flex: 1; border-bottom: 1px dotted var(--border); transform: translateY(-4px); }
.rp-pmt-rcpt-v { font-weight: 500; text-align: right; }
.rp-pmt-rcpt-v--strong { font-weight: 600; }
.rp-pmt-rcpt-total { display: flex; align-items: baseline; gap: 12px; padding: 12px 0; font-size: 15px; }
.rp-pmt-rcpt-total-k { font-weight: 700; }
.rp-pmt-rcpt-spacer { flex: 1; }
.rp-pmt-rcpt-total-v { font-weight: 700; font-size: 18px; }
.rp-pmt-rcpt-pdf {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; height: 40px; padding: 0 18px;
  border: 1.5px solid var(--primary); border-radius: var(--radius-md);
  background: transparent; color: var(--primary);
  font: inherit; font-size: 13.5px; font-weight: 600; text-decoration: none; cursor: pointer;
}
.rp-pmt-rcpt-pdf:hover { background: var(--accent); }
.rp-pmt-rcpt-note { font-size: 12px; color: var(--muted-foreground); line-height: 1.55; margin: 14px 0 0; }

@media (max-width: 600px) {
  .rp-pmt-card, .rp-pmt-rcpt-card { padding: 20px; }
  .rp-pmt-title { font-size: 20px; }
  /* Requisites stay two-column (brief) — just tighten the label column on narrow screens. */
  .rp-pmt-row { grid-template-columns: 116px 1fr; }
}

/* ── /settings hub form tabs (rp-set*, wave 5 Task 7 — Настройки.dc.html, П-20) ─────────────────
   Signup / cancellation / video settings forms. Native HTML on tokens (no MudBlazor); the desktop
   card is a 600px column, the mobile view (≤640px) collapses the two-column grid to one and stretches
   the submit full-width — one markup tree, CSS-only responsive switch. */
.rp-set { max-width: 600px; }
.rp-set-loading { display: flex; justify-content: center; padding: 32px; }

.rp-set-introrow { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
.rp-set-intro {
  flex: 1;
  min-width: 0;
  font-size: 13px;
  color: var(--muted-foreground);
  line-height: 1.6;
  margin: 0 0 16px;
}
.rp-set-introrow .rp-set-intro { margin: 0; }
.rp-set-sitelink {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 34px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font-size: 12.5px;
  font-weight: 600;
  text-decoration: none;
}
.rp-set-sitelink:hover { background: var(--accent); }

.rp-set-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 20px;
}

/* switch row — bespoke 38×22 pill switch (П-9; the mockup size matches no BbSwitch/prior preset) */
.rp-set-switchrow { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 16px; }
.rp-set-switchrow--dim { opacity: 0.45; }
.rp-set-switch {
  position: relative;
  width: 38px;
  height: 22px;
  border: 0;
  border-radius: 999px;
  background: var(--border);
  padding: 0;
  cursor: pointer;
  flex-shrink: 0;
  margin-top: 1px;
  transition: background 0.15s;
}
.rp-set-switch[aria-checked="true"] { background: var(--primary); }
.rp-set-switch:disabled { cursor: not-allowed; }
/* A bespoke <button role="switch"> has no native focus ring — restore a visible keyboard focus indicator. */
.rp-set-switch:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }
.rp-set-switch-thumb {
  position: absolute;
  top: 2.5px;
  left: 2.5px;
  width: 17px;
  height: 17px;
  border-radius: 50%;
  background: #fff;
  box-shadow: var(--shadow-xs);
  transition: left 0.15s;
}
.rp-set-switch[aria-checked="true"] .rp-set-switch-thumb { left: 18.5px; }
.rp-set-switchtext { min-width: 0; }
.rp-set-switch-label { font-size: 13.5px; font-weight: 600; }
.rp-set-switch-cap { font-size: 12.5px; color: var(--muted-foreground); line-height: 1.5; }

/* field grid + inputs */
.rp-set-grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-bottom: 16px; }
.rp-set-field { display: block; }
.rp-set-field--minage { max-width: 240px; margin-bottom: 18px; }
.rp-set-field--dim { opacity: 0.45; }
.rp-set-label { display: block; font-size: 12.5px; font-weight: 600; margin-bottom: 5px; }
.rp-set-input {
  width: 100%;
  height: 38px;
  padding: 0 12px;
  border: 1px solid var(--input);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 13.5px;
}
select.rp-set-input { padding: 0 10px; cursor: pointer; }
.rp-set-hint { display: block; font-size: 11.5px; color: var(--muted-foreground); margin-top: 4px; }

.rp-set-err {
  font-size: 12.5px;
  color: var(--destructive);
  margin-bottom: 12px;
}

@media (max-width: 640px) {
  .rp-set-grid2 { grid-template-columns: 1fr; }
  .rp-set-field--minage { max-width: none; }
  .rp-set-card .rp-btn-submit { width: 100%; height: 44px; }
}

/* ── «ИИ-функции» tab (rp-set-aicard / rp-set-infocard, wave 5 Task 8 — Настройки.dc.html) ────────── */
.rp-set-aicard { margin-bottom: 14px; }
.rp-set-field--voice { max-width: 262px; margin-bottom: 16px; }

.rp-set-infocard {
  display: flex;
  align-items: center;
  gap: 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 16px 20px;
}
.rp-set-infocard-text { flex: 1; min-width: 0; }
.rp-set-infocard-title { font-size: 13.5px; font-weight: 600; }
.rp-set-infocard-cap { font-size: 12.5px; color: var(--muted-foreground); line-height: 1.5; }
.rp-set-infocard-chip { flex-shrink: 0; }

/* ── «Площадка» tab: tenant card + destructive close zone (rp-set-tenant* / rp-set-danger*) ────────── */
.rp-set-tenantcard {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 20px;
  margin-bottom: 14px;
}
.rp-set-tenant-name { font-size: 14.5px; font-weight: 700; margin-bottom: 4px; }
.rp-set-tenant-host { font-size: 13px; color: var(--muted-foreground); }

.rp-set-danger {
  border: 1px solid color-mix(in srgb, var(--destructive) 35%, var(--border));
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 20px;
}
.rp-set-danger-title { font-size: 14.5px; font-weight: 700; color: var(--destructive); margin-bottom: 10px; }
.rp-set-danger-warn {
  border: 1px solid color-mix(in srgb, var(--destructive) 25%, var(--border));
  background: color-mix(in srgb, var(--destructive) 6%, var(--card));
  border-radius: var(--radius-md);
  padding: 13px 16px;
  margin-bottom: 16px;
  font-size: 12.5px;
  line-height: 1.6;
}
.rp-set-danger-warn-title { font-size: 12.5px; font-weight: 700; margin-bottom: 6px; }
.rp-set-danger-list { margin: 0; padding-left: 18px; font-size: 12.5px; line-height: 1.7; color: var(--muted-foreground); }
.rp-set-danger-note { font-size: 12.5px; margin-top: 8px; }
.rp-set-danger-lead { font-size: 13px; color: var(--muted-foreground); margin: 0 0 10px; }

.rp-set-danger-row { display: flex; gap: 8px; align-items: flex-end; }
.rp-set-danger-field { flex: 1; }
.rp-set-danger-fullfield { display: block; margin-bottom: 12px; }
.rp-set-danger-actions { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }

/* destructive buttons — 38px tall, tokens only */
.rp-btn-danger,
.rp-btn-danger-outline {
  height: 38px;
  padding: 0 16px;
  border-radius: var(--radius-md);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  flex-shrink: 0;
}
.rp-btn-danger { border: 0; background: var(--destructive); color: var(--destructive-foreground); }
.rp-btn-danger-outline { border: 1.5px solid var(--destructive); background: transparent; color: var(--destructive); }
.rp-btn-danger:disabled,
.rp-btn-danger-outline:disabled { opacity: 0.6; cursor: not-allowed; }

.rp-btn-textlink {
  border: 0;
  background: transparent;
  color: var(--muted-foreground);
  font: inherit;
  font-size: 13px;
  cursor: pointer;
  padding: 0 4px;
}
.rp-btn-textlink:hover { color: var(--foreground); }
.rp-btn-textlink:disabled { opacity: 0.6; cursor: not-allowed; }

@media (max-width: 640px) {
  .rp-set-danger-row { flex-direction: column; align-items: stretch; }
  .rp-set-danger-row .rp-btn-danger-outline { width: 100%; height: 44px; }
  .rp-set-danger-actions .rp-btn-danger,
  .rp-set-danger-actions .rp-btn-submit { width: 100%; height: 44px; }
  .rp-set-danger .rp-btn-submit { width: 100%; height: 44px; }
}

/* ── «Мой сайт» hub §Оформление (wave 5 Task 9, Мой сайт.dc.html) ───────────
   Cabinet CHROME (topbtn, grid, controls, template/colour pickers) uses var(--…) tokens so it flips
   with dark mode. The LIVE PREVIEW (.rp-site-pv-*) is an imitation of the PUBLIC landing and carries a
   HARDCODED light palette on purpose — see the header inventory + SiteLivePreview.razor's comment. */

/* SitePage top-action links (RpPageHeader Actions slot) */
.rp-site-topbtn {
  display: inline-flex; align-items: center; gap: 7px;
  height: 36px; padding: 0 13px;
  border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--card); color: var(--foreground);
  font-size: 12.5px; font-weight: 600; text-decoration: none; white-space: nowrap;
}
.rp-site-topbtn:hover { border-color: var(--primary); color: var(--primary); }
.rp-site-topbtn--primary {
  border: 1.5px solid var(--primary); background: transparent; color: var(--primary);
}

/* Appearance tab: desktop 300px controls + fluid preview; mobile = preview first, controls below */
.rp-site {
  display: grid; grid-template-columns: 300px 1fr; gap: 22px; align-items: start;
}
.rp-site-loading { display: flex; justify-content: center; padding: 32px; }
/* min-width: 0 — grid children default to min-width:auto, so the fluid preview column could not
   shrink below its content (416px pv-head) and pushed 390px phones into horizontal scroll. */
.rp-site-preview { order: 2; min-width: 0; }
.rp-site-controls { order: 1; min-width: 0; }
.rp-site-spacer { flex: 1; }

.rp-site-group-title { font-size: 13.5px; font-weight: 700; margin-bottom: 10px; }
.rp-site-hexfield { max-width: 160px; }
.rp-site-save { width: 100%; height: 38px; margin-top: 4px; }

/* Template cards */
.rp-site-templates { display: grid; gap: 10px; margin-bottom: 22px; }
.rp-site-tpl {
  display: flex; align-items: center; gap: 12px; text-align: left;
  border: 1.5px solid var(--border); border-radius: var(--radius-lg);
  background: var(--card); padding: 10px 12px; cursor: pointer; font: inherit;
}
.rp-site-tpl:hover { border-color: color-mix(in srgb, var(--primary) 50%, var(--border)); }
.rp-site-tpl--active { border-color: var(--primary); }
.rp-site-tpl-thumb {
  width: 64px; height: 46px; flex-shrink: 0;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 6px; display: flex; flex-direction: column; gap: 4px;
}
.rp-site-tpl-bar { width: 80%; height: 6px; border-radius: 2px; }
.rp-site-tpl-sub { width: 60%; height: 3px; border-radius: 2px; background: var(--border); }
.rp-site-tpl-text { flex: 1; min-width: 0; }
.rp-site-tpl-name {
  display: flex; align-items: center; gap: 6px;
  font-size: 13px; font-weight: 600; color: var(--foreground);
}
.rp-site-tpl-name svg { color: var(--primary); }
.rp-site-tpl-desc {
  display: block; font-size: 11.5px; color: var(--muted-foreground); line-height: 1.4; margin-top: 2px;
}

/* Colour presets */
.rp-site-colors { display: flex; align-items: center; gap: 9px; margin-bottom: 8px; }
.rp-site-color {
  width: 34px; height: 34px; border-radius: 50%;
  border: 2.5px solid transparent; cursor: pointer;
  box-shadow: 0 0 0 2px var(--card) inset;
}
.rp-site-color--active { border-color: var(--foreground); }

/* Preview header meta */
/* flex-wrap + ellipsis: on 390px the eyebrow + host don't fit one row — without them the host
   pushed the page 44px past the viewport (horizontal scroll on «Мой сайт → Оформление»). */
.rp-site-preview-head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; flex-wrap: wrap; }
.rp-site-preview-eyebrow {
  font-size: 11.5px; font-weight: 600; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--muted-foreground);
}
.rp-site-preview-host {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 11.5px; color: var(--muted-foreground);
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rp-site-preview-note {
  font-size: 12px; color: var(--muted-foreground); line-height: 1.55; margin: 10px 2px 0;
}

/* ── Live preview — HARDCODED public-landing palette (NOT cabinet tokens) ──── */
.rp-site-pv {
  border: 1px solid #eceae6; border-radius: 12px; overflow: hidden;
  background: #fff; box-shadow: 0 4px 16px rgba(28,26,23,0.08);
}
.rp-site-pv-head {
  display: flex; align-items: center; gap: 9px;
  padding: 12px 22px; border-bottom: 1px solid #eceae6;
}
.rp-site-pv-logo {
  width: 26px; height: 26px; flex-shrink: 0; border-radius: 6px; color: #fff;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 700;
}
.rp-site-pv-logo-img { width: 26px; height: 26px; flex-shrink: 0; border-radius: 6px; object-fit: cover; }
.rp-site-pv-name {
  font-size: 13px; font-weight: 700; color: #1c1a17;
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rp-site-pv-spacer { flex: 1; }
.rp-site-pv-menu { font-size: 11.5px; color: #8a857c; white-space: nowrap; }
.rp-site-pv-hcta {
  display: inline-flex; align-items: center; height: 28px; padding: 0 12px;
  border-radius: 6px; font-size: 11px; font-weight: 600; white-space: nowrap;
}
.rp-site-pv-hero { display: flex; gap: 24px; align-items: center; }
.rp-site-pv-hero-text { max-width: 400px; }
.rp-site-pv-htitle {
  font-weight: 800; letter-spacing: -0.015em; line-height: 1.15; color: #1c1a17;
}
.rp-site-pv-hsub { font-size: 12.5px; color: #6f6a61; line-height: 1.55; margin: 9px 0 14px; }
.rp-site-pv-hero-cta {
  height: 34px; padding: 0 17px; font-size: 12.5px;
}
.rp-site-pv-photo {
  width: 170px; height: 150px; flex-shrink: 0; border-radius: 12px;
  background: repeating-linear-gradient(45deg, #f2f0ec, #f2f0ec 8px, #e9e6e0 8px, #e9e6e0 16px);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-mono, monospace); font-size: 10px; color: #8a857c;
}
.rp-site-pv-stats {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
  gap: 10px; padding: 16px 22px; border-top: 1px solid #eceae6;
}
.rp-site-pv-stat { border: 1px solid #eceae6; padding: 11px 12px; }
.rp-site-pv-stat-num { font-size: 14px; font-weight: 800; }
.rp-site-pv-stat-lbl { font-size: 10.5px; color: #6f6a61; line-height: 1.4; }
.rp-site-pv-price {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 13px 22px; border-top: 1px solid #eceae6; background: #faf9f7;
}
.rp-site-pv-price-name { font-size: 11.5px; font-weight: 700; color: #1c1a17; }
.rp-site-pv-price-src { font-size: 10.5px; color: #8a857c; }
.rp-site-pv-price-buy {
  display: inline-flex; align-items: center; height: 26px; padding: 0 11px;
  font-size: 10.5px; font-weight: 600;
}

@media (max-width: 768px) {
  .rp-site { grid-template-columns: 1fr; gap: 18px; }
  /* Mobile: preview FIRST (top), controls below — flips the desktop controls-left/preview-right order. */
  .rp-site-preview { order: 1; }
  .rp-site-controls { order: 2; }
  .rp-site-hexfield { max-width: 200px; }
  .rp-site-color { width: 38px; height: 38px; }
  .rp-site-pv-menu { display: none; }
}

/* ── Landing-block surface + edit dialog (wave 5 Task 10, rp-land*) ───────────────────────────
   Shared chrome for LandingPreviewSurface (Мой сайт §Содержание + онбординг превью) and the
   LandingBlockEditDialog. Structure/tokens only; the accent icon colour is applied inline. */
.rp-land-intro {
  font-size: 13px; color: var(--muted-foreground); line-height: 1.6; margin: 0 0 16px;
}

.rp-land-block {
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  background: var(--card); padding: 14px 18px; margin-bottom: 10px;
}
.rp-land-block--off { opacity: 0.55; }

.rp-land-chrome { display: flex; align-items: center; gap: 10px; }

.rp-land-ico {
  width: 34px; height: 34px; flex-shrink: 0; border-radius: var(--radius-md);
  display: inline-flex; align-items: center; justify-content: center;
}

.rp-land-meta { flex: 1; min-width: 0; }
.rp-land-titlerow { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.rp-land-name { font-size: 14px; font-weight: 700; }
.rp-land-hint { font-size: 12.5px; color: var(--muted-foreground); line-height: 1.5; }

.rp-land-badge {
  padding: 1.5px 7px; border-radius: 999px; font-size: 10px; font-weight: 700; white-space: nowrap;
}
.rp-land-badge--auto { background: var(--accent); color: var(--accent-foreground); }
.rp-land-badge--empty {
  background: var(--warning-muted, var(--muted));
  color: var(--warning-muted-foreground, var(--muted-foreground));
}
.rp-land-badge-short { display: none; }

.rp-land-edit {
  flex-shrink: 0; height: 32px; padding: 0 12px; border: 1px solid var(--border);
  border-radius: var(--radius-md); background: var(--card); color: var(--foreground);
  font: inherit; font-size: 12.5px; font-weight: 600; cursor: pointer;
}
.rp-land-edit:hover { border-color: var(--primary); color: var(--primary); }

.rp-land-toggle {
  flex-shrink: 0; position: relative; width: 36px; height: 21px; border: 0;
  border-radius: 999px; background: var(--border); cursor: pointer; padding: 0;
}
.rp-land-toggle--on { background: var(--primary); }
.rp-land-toggle-thumb {
  position: absolute; top: 2.5px; left: 2.5px; width: 16px; height: 16px; border-radius: 50%;
  background: #fff; box-shadow: var(--shadow-xs); transition: left .15s;
}
.rp-land-toggle--on .rp-land-toggle-thumb { left: 17.5px; }

.rp-land-kebab {
  flex-shrink: 0; width: 30px; height: 30px; border: 1px solid var(--border);
  border-radius: var(--radius-md); background: var(--card); color: var(--muted-foreground);
  cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
}
.rp-land-kebab:hover { color: var(--foreground); }

.rp-land-preview { margin-top: 12px; }

/* ── Edit dialog (BbDialogContent Class="rp-land-dlg") ── */
/* height cap + inner scroll come from the global [role="dialog"] rule (end of file) */
.rp-land-dlg { width: 440px; max-width: calc(100vw - 32px); }
.rp-land-dlg-handle { display: none; }
.rp-land-dlg-head { display: flex; align-items: center; gap: 10px; margin-bottom: 4px; }
.rp-land-dlg-title { font-size: 16px; font-weight: 700; }
.rp-land-dlg-spacer { flex: 1; }
.rp-land-dlg-close {
  width: 28px; height: 28px; border: 0; background: transparent; color: var(--muted-foreground);
  cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--radius-md);
}
.rp-land-dlg-close:hover { background: var(--secondary); color: var(--foreground); }
.rp-land-dlg-desc { font-size: 12.5px; color: var(--muted-foreground); line-height: 1.55; margin: 0 0 8px; }
.rp-land-dlg-hint { font-size: 12px; color: var(--muted-foreground); line-height: 1.5; margin-bottom: 8px; }
.rp-land-dlg-help {
  display: inline-flex; align-items: center; gap: 4px; font-size: 12px; font-weight: 600;
  color: var(--primary); text-decoration: none; margin-bottom: 12px;
}
.rp-land-dlg-help:hover { text-decoration: underline; }
.rp-land-dlg-platform {
  font-size: 12px; color: var(--muted-foreground); line-height: 1.5;
  background: var(--muted); border-radius: var(--radius-md); padding: 9px 12px; margin-bottom: 12px;
}
.rp-land-dlg-body { margin-bottom: 14px; }
.rp-land-dlg-actions { display: flex; align-items: center; gap: 8px; }
.rp-land-dlg-tpl {
  display: inline-flex; align-items: center; gap: 6px; height: 36px; padding: 0 12px;
  border: 1px solid var(--border); border-radius: var(--radius-md); background: transparent;
  color: var(--foreground); font: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
}
.rp-land-dlg-tpl:hover { border-color: var(--primary); color: var(--primary); }
.rp-land-dlg-cancel {
  height: 36px; padding: 0 14px; border: 1px solid var(--border); border-radius: var(--radius-md);
  background: transparent; color: var(--foreground); font: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
}
.rp-land-dlg-save {
  height: 36px; padding: 0 16px; border: 0; border-radius: var(--radius-md);
  background: var(--primary); color: var(--primary-foreground); font: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
}

@media (max-width: 640px) {
  /* Chrome only on mobile — the schematic preview is hidden; short badge texts «сам»/«пусто». */
  .rp-land-preview { display: none; }
  .rp-land-badge-full { display: none; }
  .rp-land-badge-short { display: inline; }

  /* Edit dialog becomes a bottom sheet: pinned to the bottom, rounded top, drag handle. П-14 resets
     BOTH transform and translate (the shipped BbDialogContent centres via one of them); П-15 keeps the
     submit clear of the bottom nav. */
  .rp-land-dlg {
    position: fixed; left: 0; right: 0; bottom: 0; top: auto;
    transform: none; translate: none;
    width: 100%; max-width: 100%; max-height: 85vh;
    border-radius: 20px 20px 0 0;
    padding-bottom: calc(74px + env(safe-area-inset-bottom, 0px));
  }
  .rp-land-dlg-handle {
    display: block; width: 40px; height: 4px; border-radius: 999px;
    background: var(--border); margin: 6px auto 12px;
  }
  .rp-land-dlg-actions { flex-wrap: wrap; }
  .rp-land-dlg-save { flex: 1 0 100%; order: 3; height: 44px; }
}

/* ── «Мой сайт» hub §Домен (wave 5 Task 11, Мой сайт.dc.html) ─────────────────────────────────────── */
.rp-site-dom { max-width: 640px; }
.rp-site-dom-intro {
  font-size: 13px; color: var(--muted-foreground); line-height: 1.6; margin: 0 0 16px;
}

.rp-site-dom-card {
  border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--card);
  padding: 16px 18px; margin-bottom: 14px;
}
.rp-site-dom-card--primary {
  display: flex; align-items: center; gap: 12px; margin-bottom: 12px;
}
.rp-site-dom-primary-text { flex: 1; min-width: 0; }
.rp-site-dom-primary-label {
  font-size: 11px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--muted-foreground); margin-bottom: 2px;
}
.rp-site-dom-primary-value { font-size: 14.5px; font-weight: 700; }

.rp-site-dom-headrow { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.rp-site-dom-host { font-size: 14.5px; font-weight: 700; flex: 1; min-width: 0; }

.rp-site-dom-badge {
  display: inline-block; flex-shrink: 0; padding: 3px 10px; border-radius: 999px;
  font-size: 11.5px; font-weight: 600; white-space: nowrap;
}
.rp-site-dom-badge--success { background: var(--success-muted); color: var(--success-muted-foreground); }
.rp-site-dom-badge--warning { background: var(--warning-muted, var(--muted)); color: var(--warning-muted-foreground, var(--muted-foreground)); }
.rp-site-dom-badge-short { display: none; }

.rp-site-dom-step { font-size: 13px; color: var(--muted-foreground); margin-bottom: 8px; }

.rp-site-dom-code {
  background: var(--muted); border-radius: var(--radius-md); padding: 11px 14px;
  font-family: var(--font-mono); font-size: 12px; line-height: 1.7; word-break: break-all; margin-bottom: 10px;
}
.rp-site-dom-code-label-full, .rp-site-dom-code-label-short { color: var(--muted-foreground); }
.rp-site-dom-code-label-short { display: none; }
.rp-site-dom-note { font-size: 12px; color: var(--muted-foreground); margin-bottom: 12px; }

.rp-site-dom-error { display: block; font-size: 12.5px; color: var(--destructive); margin-bottom: 10px; }

.rp-site-dom-actions { display: flex; gap: 8px; }
.rp-site-dom-single { margin-top: 4px; }

.rp-site-dom-btn,
.rp-site-dom-btn--danger {
  height: 36px; border-radius: var(--radius-md); font: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
}
.rp-site-dom-btn { padding: 0 16px; border: 0; background: var(--primary); color: var(--primary-foreground); }
.rp-site-dom-btn--danger { padding: 0 14px; border: 1px solid var(--border); background: transparent; color: var(--destructive); }
.rp-site-dom-btn:disabled,
.rp-site-dom-btn--danger:disabled { opacity: 0.7; cursor: not-allowed; }

.rp-site-dom-form { display: flex; gap: 8px; }
.rp-site-dom-input {
  flex: 1; min-width: 0; height: 38px; padding: 0 12px; border: 1px solid var(--input);
  border-radius: var(--radius-md); background: var(--card); color: var(--foreground); font: inherit; font-size: 13.5px;
}
.rp-site-dom-input:disabled { opacity: 0.7; cursor: not-allowed; }
.rp-site-dom-add {
  flex-shrink: 0; height: 38px; padding: 0 16px; border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--card); color: var(--foreground); font: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
}
.rp-site-dom-add:hover { border-color: var(--primary); color: var(--primary); }
.rp-site-dom-add:disabled { opacity: 0.7; cursor: not-allowed; }
.rp-site-dom-add-short { display: none; }

.rp-site-dom-upsell-text { font-size: 13px; color: var(--muted-foreground); line-height: 1.6; margin: 0 0 12px; }

@media (max-width: 640px) {
  /* The mobile pending/verified card drops the «Шаг N» copy + desktop-only caption entirely — TXT/DNS
     code block + actions only (Мой сайт.dc.html mobile screen has no equivalent lines). */
  .rp-site-dom-step,
  .rp-site-dom-note { display: none; }

  .rp-site-dom-headrow { gap: 8px; margin-bottom: 8px; }
  .rp-site-dom-host { font-size: 13.5px; }
  .rp-site-dom-badge { padding: 2px 8px; font-size: 10.5px; }
  .rp-site-dom-badge-full { display: none; }
  .rp-site-dom-badge-short { display: inline; }

  .rp-site-dom-code { padding: 9px 12px; font-size: 10.5px; }
  .rp-site-dom-code-label-full { display: none; }
  .rp-site-dom-code-label-short { display: inline; }

  .rp-site-dom-actions { display: grid; grid-template-columns: 1fr 1fr; }
  .rp-site-dom-actions .rp-site-dom-btn,
  .rp-site-dom-actions .rp-site-dom-btn--danger { height: 40px; }
  .rp-site-dom-single .rp-site-dom-btn--danger { width: 100%; height: 44px; }

  .rp-site-dom-input { height: 42px; font-size: 14px; }
  .rp-site-dom-add { height: 42px; padding: 0 13px; }
  .rp-site-dom-add-full { display: none; }
  .rp-site-dom-add-short { display: inline; }
}

/* ── Onboarding «сайт за минуту» (wave 5 Task 12 · Онбординг.dc.html) ─────────
   Focus-mode page on ReaderLayout: own sticky screen header + a scrolling body
   carrying the three phases (Brief / Generating / Preview). Colours via tokens
   only, so dark mode flips for free. The preview block cards are rendered by
   LandingPreviewSurface (rp-land-*, Task 10) — not restyled here. */
@keyframes rp-onb-pulse { 0%, 100% { opacity: 0.45; } 50% { opacity: 1; } }

.rp-onb {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  background: var(--background);
  color: var(--foreground);
}

.rp-onb-header {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  gap: 12px;
  height: 58px;
  padding: 0 24px;
  border-bottom: 1px solid var(--border);
  background: var(--card);
}

.rp-onb-brand { display: inline-flex; align-items: center; gap: 10px; flex-shrink: 0; }
.rp-onb-mark { display: block; }
/* Theme-swap the brand mark in pure CSS — theme.js sets `.dark` on <html> pre-paint, so no
   ThemeController is needed on this ReaderLayout page (which never inits it). */
.rp-onb-mark--dark { display: none; }
.dark .rp-onb-mark--light { display: none; }
.dark .rp-onb-mark--dark { display: block; }
.rp-onb-brand-word {
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--primary);
}

.rp-onb-phase {
  font-size: 12.5px;
  color: var(--muted-foreground);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.rp-onb-spacer { flex: 1; min-width: 8px; }

.rp-onb-credits {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 34px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--accent);
  color: var(--accent-foreground);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  flex-shrink: 0;
}

.rp-onb-later {
  height: 34px;
  padding: 0 12px;
  border: 0;
  background: transparent;
  color: var(--muted-foreground);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  flex-shrink: 0;
}
.rp-onb-later:hover:not(:disabled) { color: var(--foreground); }
.rp-onb-later:disabled { opacity: 0.5; cursor: default; }

.rp-onb-body {
  flex: 1;
  width: 100%;
  padding: 32px 24px 80px;
}

/* ── Brief phase ─────────────────────────────────────────────────────────── */
.rp-onb-brief { max-width: 640px; margin: 0 auto; }

.rp-onb-h1 {
  font-size: 24px;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin: 0 0 6px;
}

.rp-onb-lead {
  font-size: 13.5px;
  color: var(--muted-foreground);
  line-height: 1.6;
  margin: 0 0 22px;
}

.rp-onb-field { display: block; margin-bottom: 6px; }
.rp-onb-label {
  display: block;
  font-size: 12.5px;
  font-weight: 600;
  margin-bottom: 5px;
}

.rp-onb-textarea,
.rp-onb-input,
.rp-onb-select {
  width: 100%;
  border: 1px solid var(--input);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 13.5px;
}
.rp-onb-textarea {
  padding: 12px;
  line-height: 1.55;
  resize: vertical;
  min-height: 150px;
}
.rp-onb-input { height: 38px; padding: 0 12px; }
.rp-onb-select { height: 38px; padding: 0 10px; }
.rp-onb-textarea:focus-visible,
.rp-onb-input:focus-visible,
.rp-onb-select:focus-visible {
  outline: none;
  border-color: var(--primary);
}

.rp-onb-hint {
  font-size: 12px;
  color: var(--muted-foreground);
  line-height: 1.55;
  margin: 0 0 20px;
}
.rp-onb-hint a { color: var(--primary); text-decoration: none; }
.rp-onb-hint a:hover { text-decoration: underline; }

.rp-onb-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  margin-bottom: 20px;
}

.rp-onb-section {
  border-top: 1px solid var(--border);
  padding-top: 18px;
  margin-bottom: 24px;
}
.rp-onb-section-title { font-size: 13px; font-weight: 700; margin-bottom: 10px; }
.rp-onb-logo-row { display: flex; align-items: center; gap: 14px; }

.rp-onb-actions {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
  align-items: center;
  flex-wrap: wrap;
}

.rp-onb-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 40px;
  padding: 0 18px;
  border: 0;
  border-radius: var(--radius-md);
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
}
.rp-onb-btn:disabled { opacity: 0.6; cursor: default; }
.rp-onb-btn--primary { background: var(--primary); color: var(--primary-foreground); padding: 0 20px; }
.rp-onb-btn--ghost { background: transparent; color: var(--muted-foreground); }
.rp-onb-btn--ghost:hover:not(:disabled) { color: var(--foreground); }
.rp-onb-btn--outline { border: 1px solid var(--border); background: var(--card); color: var(--foreground); }

.rp-onb-btn-spin {
  width: 15px;
  height: 15px;
  border: 2px solid color-mix(in srgb, currentColor 35%, transparent);
  border-top-color: currentColor;
  border-radius: 50%;
  animation: rp-spin 0.7s linear infinite;
}

/* ── Generating phase ────────────────────────────────────────────────────── */
.rp-onb-gen { max-width: 640px; margin: 60px auto 0; text-align: center; }
.rp-onb-spark {
  width: 64px;
  height: 64px;
  margin: 0 auto 20px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-foreground);
  display: flex;
  align-items: center;
  justify-content: center;
  animation: rp-onb-pulse 1.6s ease-in-out infinite;
}
.rp-onb-gen-title { font-size: 17px; font-weight: 700; margin-bottom: 6px; }
.rp-onb-gen-sub { font-size: 13px; color: var(--muted-foreground); }

.rp-onb-skeletons {
  max-width: 420px;
  margin: 28px auto 0;
  display: grid;
  gap: 10px;
}
.rp-onb-skel {
  border-radius: var(--radius-md);
  background: var(--muted);
  animation: rp-onb-pulse 1.6s ease-in-out infinite;
}

/* ── Preview phase ───────────────────────────────────────────────────────── */
.rp-onb-preview { max-width: 760px; margin: 0 auto; }

.rp-onb-clarify {
  border: 1px solid color-mix(in srgb, var(--primary) 35%, var(--border));
  background: var(--accent);
  color: var(--accent-foreground);
  border-radius: var(--radius-lg);
  padding: 14px 18px;
  margin-bottom: 18px;
}
.rp-onb-clarify-q { font-size: 13.5px; font-weight: 700; margin-bottom: 8px; }
.rp-onb-clarify-row { display: flex; gap: 8px; flex-wrap: wrap; }
.rp-onb-clarify-input {
  flex: 1;
  min-width: 160px;
  height: 36px;
  padding: 0 12px;
  border: 1px solid var(--input);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 13px;
}
.rp-onb-clarify-input:focus-visible { outline: none; border-color: var(--primary); }
.rp-onb-clarify .rp-onb-btn { height: 36px; }

.rp-onb-explain {
  font-size: 13px;
  color: var(--muted-foreground);
  line-height: 1.6;
  margin: 0 0 14px;
}

.rp-onb-warn {
  border: 1px solid color-mix(in srgb, var(--warning) 35%, var(--border));
  background: color-mix(in srgb, var(--warning) 10%, var(--card));
  color: var(--foreground);
  border-radius: var(--radius-md);
  padding: 12px 16px;
  font-size: 13px;
  line-height: 1.55;
  margin-bottom: 18px;
}

@media (max-width: 768px) {
  .rp-onb-header { height: 54px; padding: 0 14px; gap: 10px; }
  .rp-onb-body { padding: 24px 14px 72px; }
  .rp-onb-grid { grid-template-columns: 1fr; }
}

/* ── Главная родителя (/home/parent) — wave 6 Task 3, Главная родителя.dc.html ──────────────────── */

.rp-phome-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  margin-bottom: 16px;
}

.rp-phome-card {
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.rp-phome-head {
  display: flex;
  align-items: center;
  gap: 12px;
}

.rp-phome-head-text { flex: 1; min-width: 0; }
.rp-phome-name { font-size: 15.5px; font-weight: 700; }
.rp-phome-tenant { font-size: 12.5px; color: var(--muted-foreground); }

/* Shared initials avatar (card head 40px, week rows 26px via --sm). --warm is the alternating
   per-child tint — children are told apart by avatar tone, not by fabricated subject colours. */
.rp-phome-avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  font-weight: 700;
  flex-shrink: 0;
}

.rp-phome-avatar--warm {
  background: var(--warning-muted);
  color: var(--warning-muted-foreground);
}

.rp-phome-avatar--sm {
  width: 26px;
  height: 26px;
  font-size: 10.5px;
}

.rp-phome-next {
  display: flex;
  align-items: center;
  gap: 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 10px 12px;
}

.rp-phome-next-ico {
  width: 16px;
  height: 16px;
  display: inline-flex;
  color: var(--primary);
  flex-shrink: 0;
}

.rp-phome-next-body { flex: 1; min-width: 0; line-height: 1.3; }
.rp-phome-next-title { font-size: 13px; font-weight: 600; }
.rp-phome-next-when { font-size: 12px; color: var(--muted-foreground); }
.rp-phome-next-none { font-size: 13px; color: var(--muted-foreground); }

.rp-phome-next-link {
  font-size: 12.5px;
  color: var(--primary);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}

.rp-phome-bal {
  display: flex;
  align-items: center;
  gap: 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 10px 12px;
}

.rp-phome-bal--warn {
  border-color: color-mix(in srgb, var(--warning) 45%, var(--border));
  background: var(--warning-muted);
}

.rp-phome-bal-body { flex: 1; line-height: 1.3; }

.rp-phome-bal-label {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted-foreground);
}

.rp-phome-bal-num { font-size: 13.5px; font-weight: 700; }

.rp-phome-bal--warn .rp-phome-bal-label,
.rp-phome-bal--warn .rp-phome-bal-num { color: var(--warning-muted-foreground); }

.rp-phome-topup {
  height: 34px;
  padding: 0 14px;
  display: inline-flex;
  align-items: center;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--primary);
  border: 1.5px solid var(--primary);
  font-size: 12.5px;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  flex-shrink: 0;
}

.rp-phome-topup--primary {
  background: var(--primary);
  color: var(--primary-foreground);
  border: 0;
}

.rp-phome-tasks { display: flex; flex-direction: column; }
.rp-phome-tasks .rp-shome-card-head { margin-bottom: 4px; }

.rp-phome-week { padding: 20px; }

.rp-phome-week-row {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 11px 0;
  border-top: 1px solid var(--border);
}

.rp-phome-week-list .rp-phome-week-row:first-child { border-top: 0; }

.rp-phome-week-when {
  width: 84px;
  flex-shrink: 0;
  font-size: 13px;
  color: var(--muted-foreground);
  font-variant-numeric: tabular-nums;
}

.rp-phome-week-body { flex: 1; min-width: 0; }
.rp-phome-week-title { font-size: 13.5px; font-weight: 600; }
.rp-phome-week-child { font-size: 12.5px; color: var(--muted-foreground); }
.rp-phome-week-none { font-size: 13px; color: var(--muted-foreground); }

.rp-phome-empty { font-size: 14px; color: var(--muted-foreground); margin: 0; }

@media (max-width: 768px) {
  .rp-phome-grid { grid-template-columns: 1fr; margin-bottom: 0; }
  /* Мокап: недельная карточка есть только на десктопе — на мобиле карточки детей несут ту же
     информацию per-child. */
  .rp-phome-week { display: none; }
}

/* ── Задания детей (/children-homework) — wave 6 Task 4, Задания детей.dc.html ─────────────────── */
/* Per-child filter chips + three status sections on the shared AssignmentList (rp-asg*). */

.rp-chw-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 20px;
}

.rp-chw-chip {
  height: 34px;
  padding: 0 14px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

.rp-chw-chip--active {
  background: var(--accent);
  color: var(--accent-foreground);
  border-color: color-mix(in srgb, var(--primary) 45%, var(--border));
}

/* Chip avatar — 20px initials circle; --warm alternating per-child tint (rp-phome-avatar rule). */
.rp-chw-chip-av {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 9.5px;
  font-weight: 700;
  flex-shrink: 0;
}

.rp-chw-chip-av--warm {
  background: var(--warning-muted);
  color: var(--warning-muted-foreground);
}

.rp-chw-sec { margin-bottom: 22px; }

.rp-chw-sec-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 10px;
}

.rp-chw-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--muted-foreground);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

/* Section-tone counter badge («Требуют внимания» destructive / «На проверке» info / «Готово» success). */
.rp-chw-count {
  min-width: 19px;
  height: 19px;
  padding: 0 6px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.rp-chw-count--danger  { background: var(--destructive-muted); color: var(--destructive-muted-foreground); }
.rp-chw-count--info    { background: var(--info-muted);        color: var(--info-muted-foreground); }
.rp-chw-count--success { background: var(--success-muted);     color: var(--success-muted-foreground); }

@media (max-width: 640px) {
  .rp-chw-chip {
    height: 32px;
    padding: 0 12px;
    font-size: 12.5px;
  }
  /* LOCKED-12: одна разметка — аватар фильтр-чипа прячется на мобиле (аватар СТРОКИ остаётся). */
  .rp-chw-chip-av { display: none; }
  .rp-chw-sec { margin-bottom: 16px; }
  .rp-chw-label { font-size: 11px; }
  .rp-chw-count {
    min-width: 17px;
    height: 17px;
    padding: 0 5px;
    font-size: 10.5px;
  }
}

/* ── Wave 6 Task 6 — /child/{id}/homework/block/{id}, parent read-only submission view
   (Задания детей.dc.html detail frame). Chrome only: the engine cards below are
   HomeworkSubmissionDetail's own. Back link mirrors .rp-les-back (Занятие page). ── */
.rp-chw-sub { max-width: 720px; margin: 0 auto; }

.rp-chw-sub-back {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13.5px;
  font-weight: 500;
  color: var(--muted-foreground);
  text-decoration: none;
  margin-bottom: 16px;
}
.rp-chw-sub-back:hover { color: var(--foreground); }

.rp-chw-sub-badge { margin-bottom: 16px; }

/* ══════════════════════════════════════════════════════════════════════════════════════════════
   ParentModeBadge (wave 6 Task 5 — Режим родителя.dc.html, П-14)
   Explicit parent-mode context on shared entity pages: the inline pill next to the /my-lessons
   title, the full-width read-only banner above /lesson/{id} content, and the LOCKED-10 info card.
   ══════════════════════════════════════════════════════════════════════════════════════════════ */

.rp-pbadge-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 26px;
  padding: 0 11px;
  border-radius: 999px;
  background: var(--info-muted);
  color: var(--info-muted-foreground);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}

.rp-pbadge-banner {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 8px 14px;
  background: var(--info-muted);
  color: var(--info-muted-foreground);
  border-bottom: 1px solid var(--border);
  font-size: 12px;
  font-weight: 600;
}

.rp-pbadge-banner-text { min-width: 0; }

/* LOCKED-10 info card: neutral card tone (the banner already carries the info tint). */
.rp-pbadge-info {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 13px 15px;
  margin-bottom: 12px;
}

.rp-pbadge-info-ico {
  display: inline-flex;
  flex-shrink: 0;
  margin-top: 2px;
  color: var(--muted-foreground);
}

.rp-pbadge-info-text {
  font-size: 12.5px;
  color: var(--muted-foreground);
  line-height: 1.55;
}

/* ══════════════════════════════════════════════════════════════════════════════════════════════
   /profile (wave 6 Task 7 — Профиль.dc.html, П-10 «только личное»)
   A centered 640px column of section cards: «Личные данные» (Rp Mud inputs inside a Bp card —
   the MixedState engine is untouched), «Пароль» (dialog trigger), the manager-only info pointer,
   and the «Аккаунт» card (export row + delete zone). The 152-ФЗ consequences block and the
   code-confirm flow reuse the rp-set-danger-star and rp-btn-danger-star chrome from TenantPanel.
   ══════════════════════════════════════════════════════════════════════════════════════════════ */

.rp-prof {
  max-width: 640px;
  margin: 0 auto;
}

.rp-prof-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 22px;
  margin-bottom: 16px;
}

.rp-prof-card-title {
  font-size: 14px;
  font-weight: 700;
  margin-bottom: 16px;
}

.rp-prof-avatar { margin-bottom: 4px; }

/* neutral outline action button (mockup: «Сменить пароль», «Запросить архив»).
   Also worn by <label><InputFile/></label> picker buttons (RpImageUpload/RpImageField/
   FileBlockEditor) — a label doesn't center its content the way a button does, hence the
   explicit inline-flex centering; gap spaces the optional leading icon. */
.rp-prof-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 36px;
  padding: 0 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  flex-shrink: 0;
}
.rp-prof-btn:disabled { opacity: 0.6; cursor: not-allowed; }

.rp-prof-text {
  font-size: 12.5px;
  color: var(--muted-foreground);
  line-height: 1.55;
  margin: 0 0 14px;
}

/* info-muted plate: the «Ищете настройки площадки…» pointer between the cards and (--flow) the
   owner closure-first plate inside the delete zone. */
.rp-prof-hint {
  display: flex;
  align-items: flex-start;
  gap: 11px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--info-muted);
  color: var(--info-muted-foreground);
  padding: 13px 16px;
  margin-bottom: 16px;
}
.rp-prof-hint--flow { margin-bottom: 0; }
.rp-prof-hint-ico { display: inline-flex; flex-shrink: 0; margin-top: 1px; }
.rp-prof-hint-text { font-size: 13px; line-height: 1.55; }
.rp-prof-hint-text a { color: var(--info-muted-foreground); font-weight: 600; }

/* «Аккаунт» card action rows */
.rp-prof-row {
  display: flex;
  align-items: center;
  gap: 14px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 14px;
}
.rp-prof-row-main { flex: 1; min-width: 0; }
.rp-prof-row-title { font-size: 13.5px; font-weight: 600; }
.rp-prof-row-title--danger { color: var(--destructive); }
.rp-prof-row-sub {
  font-size: 12.5px;
  color: var(--muted-foreground);
  line-height: 1.5;
}

/* delete zone (the second «Аккаунт» row grown into the inline UC-22 flow) */
.rp-prof-del > .rp-prof-row-title--danger { margin-bottom: 6px; }
.rp-prof-del-lead { margin-bottom: 12px; }
.rp-prof-warn-title2 { margin-top: 8px; }

.rp-prof-check {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  font-size: 13px;
  line-height: 1.5;
  margin: 12px 0;
  cursor: pointer;
}
.rp-prof-check input {
  width: 16px;
  height: 16px;
  margin: 1px 0 0;
  accent-color: var(--destructive);
  cursor: pointer;
  flex-shrink: 0;
}

@media (max-width: 600px) {
  .rp-prof-card { padding: 16px; }

  /* Mobile mockup centers the avatar block; RpImageUpload's own layout is Mud utility flex —
     restack its root row into a centered column without touching the shared component. */
  .rp-prof-avatar > div {
    flex-direction: column;
    align-items: center;
    text-align: center;
  }
  .rp-prof-avatar > div > div { align-items: center; }

  .rp-prof-row { flex-direction: column; align-items: stretch; }
  .rp-prof-btn { width: 100%; height: 44px; }
  .rp-prof-del .rp-btn-danger-outline { width: 100%; height: 44px; }
}

/* ---------- RoomChatPanel (wave 7 Task 2) ---------- */
/* Compact «Чат занятия» panel for /room/{LessonId} — see the header inventory comment for the full
   rationale. RoomPage (T4) owns show/hide + desktop-column vs mobile-sheet placement around this
   markup; the panel itself is a plain flex column that fills whatever box it's given. */
.rp-rchat {
  display: flex;
  flex-direction: column;
  min-height: 0;
  height: 100%;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.rp-rchat-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
  font-weight: 600;
  flex-shrink: 0;
}
.rp-rchat-head-title { flex: 1; }

.rp-rchat-list {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.rp-rchat-empty {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted-foreground);
  font-size: 13px;
  text-align: center;
  padding: 20px;
}
/* Loading state (wave-7 final review, Important-3 — was MudProgressCircular): the base .rp-spin is
   tuned for --primary-foreground on a --primary button fill, invisible on this panel's --card
   background — same override .rp-deckpick-loading .rp-spin already applies below for the identical
   "spinner over a card" shape. */
.rp-rchat-empty .rp-spin {
  border-color: color-mix(in srgb, var(--muted-foreground) 30%, transparent);
  border-top-color: var(--muted-foreground);
}

.rp-rchat-msg { display: flex; flex-direction: column; align-items: flex-start; }
.rp-rchat-msg--mine { align-items: flex-end; }
.rp-rchat-msg-meta { font-size: 11.5px; color: var(--muted-foreground); margin-bottom: 2px; }

.rp-rchat-bubble {
  display: inline-block;
  max-width: 90%;
  padding: 7px 11px;
  border-radius: 12px;
  background: var(--secondary);
  color: var(--secondary-foreground);
  font-size: 13px;
  line-height: 1.45;
  overflow-wrap: anywhere;
  word-break: break-word;
}
/* Own bubble — accent-filled, mirrors rp-msg-bubble--mine's own-message convention. */
.rp-rchat-bubble--mine { background: var(--primary); color: var(--primary-foreground); }
/* Tombstone for a removed message — muted/dashed, no fill (rp-msg-bubble--removed's compact cousin). */
.rp-rchat-bubble--removed { background: transparent; border: 1px dashed var(--border); color: var(--muted-foreground); font-style: italic; }

.rp-rchat-composer {
  display: flex;
  gap: 8px;
  padding: 10px;
  border-top: 1px solid var(--border);
  flex-shrink: 0;
}
.rp-rchat-input {
  flex: 1;
  height: 36px;
  padding: 0 12px;
  border: 1px solid var(--input);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 13px;
}
.rp-rchat-send {
  width: 36px;
  height: 36px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex-shrink: 0;
}
.rp-rchat-send:disabled { opacity: 0.5; cursor: default; }

/* ---------- RoomToolRail (wave 7 Task 3) ---------- */
/* Board tool palette extracted out of WhiteboardSurface into its own always-visible rail — see the
   header inventory comment for the full rationale. Default orientation is a vertical 52px column
   (desktop / phone-landscape); RoomPage (T4) applies rp-rtool--row for the mobile/tablet horizontal
   layout. Every button calls repetitumBoard.* directly — this component owns no canvas. */
.rp-rtool {
  width: 52px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 10px 0;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}
.rp-rtool--row {
  width: auto;
  flex-direction: row;
  padding: 6px 12px;
}

.rp-rtool-btn {
  width: 36px;
  height: 36px;
  flex-shrink: 0;
  border: 0;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--muted-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
/* Active pen/eraser tool — accent fill, mirrors the stageTabs/boardTools active treatment in the
   mockup's demo script. */
.rp-rtool-btn--active { background: var(--accent); color: var(--accent-foreground); }
.rp-rtool-btn:disabled { opacity: 0.4; cursor: default; }

.rp-rtool-sep { width: 26px; height: 1px; background: var(--border); margin: 4px 0; flex-shrink: 0; }
.rp-rtool--row .rp-rtool-sep { width: 1px; height: 22px; margin: 0 6px; }

.rp-rtool-color {
  width: 24px;
  height: 24px;
  flex-shrink: 0;
  border-radius: 50%;
  border: 2px solid transparent;
  padding: 0;
  cursor: pointer;
}
/* The ring is a UI-chrome token; the swatch fill itself is the inline hex stroke color (LOCKED-1). */
.rp-rtool-color--active { border-color: var(--primary); }
.rp-rtool-color:disabled { opacity: 0.4; cursor: default; }

/* ---------- RoomPage chrome (wave 7 Task 4) ---------- */
/* Full rationale in the header inventory comment. `.rp-room` itself keeps the legacy full-viewport
   flex-column base from app.css (display:flex/flex-direction:column/height:100dvh/position:relative) —
   it's still exactly right for this chrome, so it isn't redefined here. */

/* rp-room-slide(-title/-image/-body) — SlideStage's own markup, MOVED here verbatim from app.css
   (wave 7 Task 4; the rest of the legacy rp-room-* block stays in app.css for T6 to remove). Needs a
   `container-type:size` ancestor for the cqmin units — `.rp-room-square` below provides it directly,
   replacing the old separate `.rp-room-stage` container. */
.rp-room-slide { position: absolute; inset: 0; overflow: auto; padding: 4% 5%;
    background: var(--card); color: var(--foreground); }
/* Font sizes are PURE container-query units (cqmin) — no px clamp. The clamp's px floor/ceiling made the
   same slide look bigger (floor on small screens) or smaller (ceiling on large screens) relative to the
   square, so a deck rendered differently per device. Pure cqmin makes the slide a uniform zoom of the
   square: identical proportions on every screen. Markdown children inside the body are em-relative, so
   they scale with the body size automatically. */
.rp-room-slide-title { margin: 0 0 0.6em; font-size: 5cqmin; font-weight: 600; }
/* An AI image is the slide's focal element — large, centered, contained (never cropped), capped so the
   title + a short body still fit in the square. cqmin keeps it proportional like the text. */
.rp-room-slide-image { display: block; max-width: 100%; max-height: 60cqmin; margin: 0 auto 0.6em;
    object-fit: contain; border-radius: 8px; }
.rp-room-slide-body { font-size: 3.2cqmin; line-height: 1.4; }

/* Full-viewport flex-column shell for /room/{lessonId} (ReaderLayout, no sidebar/appbar). MOVED here
   from app.css (post-T6 smoke fix): app.css loads AFTER bp.css, so while this base rule lived there its
   `display:flex` outranked the phone-landscape block's `.rp-room{display:grid}` below by source order
   (equal 0,1,0 specificity) — the landscape grid never applied in a real browser. Inside bp.css the
   later-in-file landscape block wins the tie, which is the intended cascade. */
.rp-room { display: flex; flex-direction: column; height: 100dvh; background: var(--background);
    position: relative; overflow: hidden; }

/* Top bar: title/subtitle, timer pill (rp-chip--success, reused), scene controls, participant count. */
.rp-room-top {
  display: flex;
  align-items: center;
  gap: 14px;
  height: 52px;
  padding: 0 16px;
  background: var(--card);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.rp-room-top-title { line-height: 1.2; min-width: 0; }
.rp-room-top-name {
  font-size: 13.5px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rp-room-top-sub { font-size: 11.5px; color: var(--muted-foreground); }
.rp-room-top-spacer { flex: 1; }
.rp-room-top-users {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12.5px;
  color: var(--muted-foreground);
  flex-shrink: 0;
}

/* Scene controls (board/slides segment + the «‹ Слайд N / M ›» control, or the student's read-only
   stage badge) — ONE RenderFragment, rendered in two static CSS-gated positions (desktop:
   rp-room-top-scene; mobile: rp-room-scenerow, its own row right under the square) so the page never
   needs a duplicate-instance guard the way RoomChatPanel does (this fragment has no autonomous side
   effects) — the picker popup underneath is duplicated the same safe way. */
.rp-room-scenegroup { display: flex; align-items: center; gap: 8px; }
.rp-room-scenetab-lbl { white-space: nowrap; }
.rp-room-slidenav { display: inline-flex; align-items: center; gap: 4px; }
.rp-room-slidenav-btn {
  width: 30px;
  height: 32px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--card);
  color: var(--muted-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.rp-room-slidenav-btn:disabled { opacity: 0.5; cursor: default; }
.rp-room-slidenav-toggle {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 32px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
}
/* Base rule — MOVED here verbatim from app.css (wave 7 Task 6 legacy sweep; it was the one alive
   fragment of the old "Video room" app.css section, everything else there was dead SP1/SP2-A chrome). */
.rp-room-slide-counter { font-size: 13px; color: var(--foreground); min-width: 44px; text-align: center; }
.rp-room-slidenav-toggle .rp-room-slide-counter { color: inherit; font-size: inherit; }

/* Desktop-only anchor for the picker popup: position:relative is scoped to the top-bar instance of the
   twice-duplicated rp-room-slidenav so the popup (rp-room-picker, position:absolute below) resolves
   against IT — the mobile-position duplicate (inside rp-room-scenerow) stays position:static so its own
   copy of rp-room-picker falls through to `.rp-room` instead, letting the mobile sheet override further
   down resolve against the whole room the same way rp-room-chathost's sheet does. */
.rp-room-top-scene .rp-room-slidenav { position: relative; }

/* Picker popup (desktop: floating popover under the toggle button; mobile: bottom sheet, see the mobile
   block) — the SAME markup repositioned by breakpoint, mirroring rp-room-chathost. Honest-data: only
   "Слайды · {M}" (Slide carries no deck title) — the "Сменить колоду…" affordance always renders since
   the whole picker only ever mounts for the tutor. */
.rp-room-picker {
  position: absolute;
  top: 40px;
  right: 0;
  width: 308px;
  padding: 14px;
  background: var(--popover);
  color: var(--popover-foreground);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  z-index: 30;
}
/* Review fix (wave-7 T6 re-review, Defect 1): a SECOND rendered instance of this same markup
   (RoomPage.razor's `PickerPanel(overlay: true)`) lives directly inside `.rp-room-side` — a genuine
   descendant, unlike the SceneControls-nested instance above (which is a `.rp-room-top` descendant and
   can never resolve `inset:0` "over the side column" without dissolving 4 more ancestors). The
   phone/narrow-landscape media query near the end of this file is the ONE place it's shown (and the
   other instance hidden instead), mirroring how `.rp-room-chathost` already gets a real `inset:0` panel
   there. This hide MUST be the two-class compound (0,2,0), not a flat `.rp-room-picker--overlay`
   (0,1,0): the twin carries BOTH classes, and the portrait sheet rule (`.rp-room-picker { … display:
   flex … }` inside the portrait block, LATER in the file at the same 0,1,0) would out-cascade a flat
   hide and render the twin as a SECOND stacked sheet on portrait ≤960 — two overlapping sheets, two
   focusable button sets in the tab order (fix round 2, Important-1). The landscape show rule uses the
   same compound form so it still beats this base hide by file order. */
.rp-room-picker.rp-room-picker--overlay { display: none; }
.rp-room-picker-head { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; }
.rp-room-picker-title {
  flex: 1;
  min-width: 0;
  font-size: 13px;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.rp-room-picker-changedeck {
  height: 28px;
  padding: 0 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--secondary);
  color: var(--secondary-foreground);
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}
/* Hidden everywhere except phone-landscape (see the media query near the end of this file), where the
   picker loses its dimming backdrop (the stage must never darken) and this ✕ becomes the only way to
   dismiss it — mirrors rp-room-chat-close-wrap's hidden-by-default/shown-narrower pattern. */
.rp-room-picker-close {
  display: none;
  width: 26px;
  height: 26px;
  flex-shrink: 0;
  border: 0;
  border-radius: var(--radius-sm);
  background: var(--secondary);
  color: var(--secondary-foreground);
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.rp-room-picker-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.rp-room-picker-num {
  aspect-ratio: 1 / 1;
  border: 2px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--muted);
  color: var(--muted-foreground);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.rp-room-picker-num--active { border-color: var(--primary); color: var(--primary); }

/* Desktop-only transparent click-catcher closing the popup on outside click — chat has no equivalent
   because RoomChatPanel is always a static column on desktop, never an overlay. */
.rp-room-pickerbackdrop { position: fixed; inset: 0; z-index: 29; }
@media (max-width: 959.98px) {
  /* Review fix (wave-7 T6 re-review, Defect 2): threshold raised from the stale `768px` to the narrow
     cutoff `_isNarrow` uses — so this hides for the FULL narrow range, not just the old sub-769px slice
     (959.98, not a flat 960: MudBlazor's Md bracket starts AT 960, so a viewport of exactly 960px is
     `_isNarrow == false` desktop and must keep the click-catcher — fix round 2, Minor-4). Narrow-portrait
     reuses `.rp-room-sheetbackdrop` for dimming; narrow-landscape shows the picker as an undimmed
     `.rp-room-picker--overlay` panel instead (see below) — neither wants this desktop click-catcher. */
  .rp-room-pickerbackdrop { display: none; }
}

/* SlideDeckPickerDialog body (T5) — the dialog chrome itself (head/title/close, empty state) reuses the
   generic rp-covw-dlg/-empty shell shared across the cabinet; only the tree list below is new. */
.rp-deckpick-tree { display: flex; flex-direction: column; gap: 2px; max-height: 360px; overflow-y: auto; }
.rp-deckpick-course { font-size: 12.5px; font-weight: 700; margin: 10px 0 2px; }
.rp-deckpick-course:first-child { margin-top: 0; }
.rp-deckpick-module { font-size: 11.5px; color: var(--muted-foreground); margin: 6px 0 2px; }
.rp-deckpick-lesson {
  display: block;
  width: 100%;
  text-align: left;
  padding: 8px 10px;
  border: 0;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--foreground);
  font: inherit;
  font-size: 13px;
  cursor: pointer;
}
.rp-deckpick-lesson:hover { background: var(--secondary); }
.rp-deckpick-loading { display: flex; justify-content: center; padding: 24px 0; }
.rp-deckpick-loading .rp-spin {
  border-color: color-mix(in srgb, var(--muted-foreground) 30%, transparent);
  border-top-color: var(--muted-foreground);
}

.rp-room-scenerow { display: none; }

/* Content row: 52px rail / flexible square / 260–360px side column on desktop (CSS Grid auto-placement —
   the mobile-only rp-room-scenerow is display:none there so it never consumes a track); a single ordered
   flex column on mobile. */
.rp-room-main {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: 52px 1fr minmax(260px, 340px);
  gap: 12px;
  padding: 12px;
}

/* .rp-room .rp-room-square used the compound selector to outrank a legacy single-class `.rp-room-square`
   rule that used to live in app.css (100cqmin sizing, needed the since-removed `.rp-room-stage`
   container ancestor) — that legacy rule is gone (wave 7 Task 6 legacy sweep), the compound selector
   is kept unchanged (no need to churn it now that it's no longer load-bearing for specificity).
   `container-type:size` lives here so the moved rp-room-slide-* cqmin rules above keep resolving
   correctly with no separate container element.

   Height cap (wave-7 final review, Important-2) — mirrors the phone-landscape grid's `min(100%,
   calc(100vw - 248px))` cap above for the SAME reason: `height:100%` and `width:auto` +
   `aspect-ratio:1/1` + `max-width:100%` are independent constraints, so on a portrait/narrow-tall
   desktop viewport (this grid applies at ANY width ≥960px, portrait or landscape — the orientation-
   gated blocks below only cover <960px) the row-height-driven `height:100%` can exceed the 1fr
   column's available width; `max-width:100%` then clips the WIDTH but nothing shrinks the height, so
   the box stops being square (e.g. a 1024×1366 iPad Pro portrait rendered ~660×1226 before this fix).
   The cap derives the column's actual available width from `.rp-room-main`'s own grid (`grid-template-
   columns: 52px 1fr minmax(260px, 340px)`, `gap: 12px`, `padding: 12px`): CSS Grid's "maximize tracks"
   step grows the minmax range track to its max BEFORE the 1fr track gets anything, and every viewport
   this rule applies to (≥960px) has far more than 340px + a near-zero square minimum to spare, so the
   side column is effectively always 340px (its ceiling) here — unlike the landscape grid above, where
   the flexible track is the SIDE column and 200px there is a floor, not an always-hit ceiling. So the
   square's width is `100vw − 52 (rail) − 12×2 (gaps) − 12×2 (.rp-room-main padding) − 340 (side column
   max) = 100vw − 440`: 52+24+24+340 = 440. Capping height to that same budget keeps the square exactly
   as wide as it is tall with no clipping. Verified: 1440×900 ordinary desktop → natural height (100dvh
   − 52px top bar − 64px bottom bar − 24px .rp-room-main padding = 760px) is already ≤ 1440−440=1000px,
   so `min()` picks the 100% branch and the cap never engages (unchanged from before this fix); 1024×1366
   iPad Pro portrait → natural height 1366−140=1226px > 1024−440=584px, so the cap engages and the stage
   renders a true 584×584 square with the side column intact at its full 340px. `align-self: center`
   (new here, matching the landscape stage's own centering) keeps the now possibly-shorter-than-row
   square vertically centered in `.rp-room-main`'s row instead of pinned to its top edge — the row's
   own height is unchanged, so a capped square would otherwise leave dead space below it. */
.rp-room .rp-room-square {
  position: relative;
  overflow: hidden;
  container-type: size;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  flex-shrink: 0;
  height: min(100%, calc(100vw - 440px));
  width: auto;
  aspect-ratio: 1 / 1;
  max-width: 100%;
  margin-inline: auto;
  align-self: center;
}
/* When a slide is shown the whiteboard surface must be transparent so the slide shows through — WhiteboardSurface
   mounts unconditionally alongside SlideStage (both are position/z-index:auto "positioned" descendants painted in
   tree order, so it paints AFTER and would otherwise fully occlude the slide beneath it). MOVED here verbatim from
   app.css (wave 7 Task 6 legacy sweep) — the only other alive fragment of the old "Video room" section besides
   rp-room-slide-counter above; both were left behind (dead-but-necessary) when the rest of that section's rules
   were superseded by this Task 4/5/6 chrome. */
.rp-room-square .wb-surface { background: transparent; }
/* Reconnecting / floor-granted pills — absolute-centered over the square, never shift the layout. */
.rp-room-overlay {
  position: absolute;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 10;
}
.rp-room-overlay--floor { top: 56px; }

.rp-room-side {
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-height: 0;
  min-width: 0;
}

/* Tiles: 2-column grid on desktop, horizontal-scroll strip on mobile — same markup, CSS-only reflow. */
.rp-room-tiles {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}

.rp-room-tile {
  position: relative;
  aspect-ratio: 16 / 10;
  background: var(--muted);
  border: 2px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}
/* Active speaker — primary ring, mirrors the mockup's active-speaker treatment. */
.rp-room-tile--speaking { border-color: var(--primary); }
.rp-room-tile video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.rp-room-tile-avatar {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--secondary);
  color: var(--secondary-foreground);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 600;
}
.rp-room-tile-name {
  position: absolute;
  left: 6px;
  bottom: 5px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 7px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--foreground) 78%, transparent);
  color: var(--background);
  font-size: 10.5px;
  font-weight: 600;
  max-width: calc(100% - 12px);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rp-room-tile-micoff {
  position: absolute;
  right: 6px;
  bottom: 5px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--foreground) 78%, transparent);
  color: var(--background);
  display: flex;
  align-items: center;
  justify-content: center;
}
.rp-room-tile-hand {
  position: absolute;
  right: 6px;
  top: 5px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--warning);
  color: var(--warning-foreground);
  display: flex;
  align-items: center;
  justify-content: center;
}
/* Tutor-only hover actions on a REMOTE tile (LOCKED-3): "Дать маркер"/"Забрать" + mute. Visible on
   hover/focus — this is a desktop mouse interaction per the mockup; a touch equivalent is future polish. */
.rp-room-tile-actions {
  position: absolute;
  right: 5px;
  top: 5px;
  display: flex;
  gap: 4px;
  opacity: 0;
  transition: opacity 0.15s ease;
}
.rp-room-tile:hover .rp-room-tile-actions,
.rp-room-tile:focus-within .rp-room-tile-actions { opacity: 1; }
.rp-room-tile-act {
  height: 24px;
  padding: 0 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 11px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}
.rp-room-tile-act--primary { border: 0; background: var(--primary); color: var(--primary-foreground); }
.rp-room-tile-mute {
  width: 24px;
  height: 24px;
  border: 0;
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--foreground) 78%, transparent);
  color: var(--background);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

/* The single raised-hand banner (LOCKED-3) — replaces the old multi-row queue: only the first raiser is
   named, "+N ещё" covers the rest. Tutor-only. */
.rp-room-hand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  background: var(--warning-muted);
  border: 1px solid color-mix(in srgb, var(--warning) 30%, transparent);
  border-radius: var(--radius-md);
  color: var(--warning-muted-foreground);
}
.rp-room-hand-text { flex: 1; font-size: 13px; font-weight: 600; }
.rp-room-hand-btn { min-width: 0; height: 30px; padding: 0 12px; font-size: 12.5px; }

/* The ONE RoomChatPanel host (LOCKED: never two instances) — desktop: a normal column; mobile/tablet
   portrait: an absolute bottom sheet toggled by the --open modifier (see RoomPage's `_chatOpen`); phone
   landscape: an absolute inset:0 panel (see the landscape media query near the end of this file). Panel
   is always mounted; only its CSS position/visibility differs.
   The three `@media` blocks below are the TRUE COMPLEMENT of the widened mobile-portrait condition
   below — `(orientation: landscape), (min-width: 960px)` — not the old flat `min-width:769px` (wave 7
   Task 6). Reusing the old 769px cutoff here after widening the portrait block would have left a
   769–960px tablet-portrait gap where the chat sheet's `.rp-room-sheetbackdrop` was silently
   `display:none`d (no dimming, but the sheet itself still slid up correctly) — a real bug the widened
   range would otherwise have re-exposed. `min-width: 960px` (not 961, fix round 2 Minor-4) pairs with
   the portrait block's `max-width: 959.98px`, the Bootstrap/MudBlazor-convention .02px split at the
   Sm|Md boundary: a viewport of exactly 960px is `_isNarrow == false` desktop and lands here, not in
   a dead zone. In narrow LANDSCAPE these rules also match (first arm) but the landscape block near the
   end of the file re-overrides them later in the cascade — intended. `.rp-room-chat-close-wrap`
   staying hidden in the portrait 769–959.98px range is harmless/desirable (a tablet-portrait chat
   sheet closes via the (now-dimmed) backdrop, matching that width's mockup frame, which shows no
   close ✕). */
.rp-room-chathost {
  display: flex;
  flex-direction: column;
  min-height: 0;
}
@media (orientation: landscape), (min-width: 960px) {
  .rp-room-chathost { flex: 1; }
}
.rp-room-chat-close-wrap { display: inline-flex; }
.rp-room-chat-close {
  width: 26px;
  height: 26px;
  border: 0;
  border-radius: var(--radius-sm);
  background: var(--secondary);
  color: var(--secondary-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
@media (orientation: landscape), (min-width: 960px) {
  .rp-room-chat-close-wrap { display: none; }
}
.rp-room-sheetbackdrop {
  position: absolute;
  inset: 0;
  z-index: 20;
  background: rgba(0, 0, 0, 0.4);
}
@media (orientation: landscape), (min-width: 960px) {
  .rp-room-sheetbackdrop { display: none; }
}

/* Bottom controls bar — labeled pills on desktop, circular icon-only + a mobile-only chat FAB ≤768px. */
.rp-room-bar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 10px;
  height: 64px;
  padding: 0 16px;
  background: var(--card);
  border-top: 1px solid var(--border);
}
.rp-room-bar-spacer { flex: 1; }
.rp-room-bar-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 40px;
  padding: 0 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
/* Mic/cam off tone — labels stay "Микрофон"/"Камера" always (LOCKED-9); only the icon + this tone change. */
.rp-room-bar-btn--off {
  border-color: color-mix(in srgb, var(--destructive) 40%, transparent);
  background: var(--destructive-muted);
  color: var(--destructive-muted-foreground);
}
.rp-room-bar-hand--active {
  border-color: color-mix(in srgb, var(--warning) 45%, transparent);
  background: var(--warning-muted);
  color: var(--warning-muted-foreground);
}
.rp-room-bar-chat {
  display: none;
  position: relative;
  width: 46px;
  height: 46px;
  border: 1px solid var(--border);
  border-radius: 50%;
  background: var(--card);
  color: var(--foreground);
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.rp-room-bar-chat-dot {
  position: absolute;
  top: 0;
  right: 0;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--destructive);
  border: 2px solid var(--card);
}
.rp-room-bar-leave {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 40px;
  padding: 0 16px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--destructive);
  color: var(--destructive-foreground);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}

/* State cards: unsupported-browser / join-error full-page fallbacks. */
.rp-room-state {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100dvh;
  padding: 24px;
}
.rp-room-state-card {
  width: 100%;
  max-width: 440px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  text-align: center;
  padding: 44px 32px;
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  background: var(--background);
  box-shadow: var(--shadow-md);
}
.rp-room-state-title { font-size: 16px; font-weight: 700; }
.rp-room-state-body { font-size: 13.5px; color: var(--muted-foreground); line-height: 1.6; }
.rp-room-state-actions { display: flex; gap: 10px; margin-top: 16px; flex-wrap: wrap; justify-content: center; }

/* ---------- Mobile/tablet portrait (orientation: portrait, <960px — wave 7 Task 6) ---------- */
/* Widened from the shell's flat `max-width:768px` (Видеокомната.dc.html "Планшет · вертикально", 834px)
   to `(orientation:portrait) and (max-width:959.98px)` — the SAME cutoff `_isNarrow`'s MudBlazor
   Sm breakpoint uses (RoomPage.razor), so the CSS layout and the C#-driven RoomChatPanel/RoomToolRail
   visibility contracts never disagree (959.98 not 960: MudBlazor's Md bracket starts AT 960, so a
   viewport of exactly 960px is `_isNarrow == false` desktop and must get the desktop CSS too — fix
   round 2, Minor-4; the .02px split is the Bootstrap/MudBlazor convention at breakpoint boundaries).
   Before this widening there was a real 769–959px gap: `_isNarrow` was already "narrow" there (Sm
   bracket, <960) so the chat sheet/mobile chat-FAB rendered, but this block's CSS didn't apply yet
   (still desktop-shaped `.rp-room-main` grid) — a tablet in portrait fell through the crack. Gating on
   `orientation:portrait` (not just width) also means a genuinely landscape-oriented narrow window
   (e.g. a resized short-but-wide desktop browser) no longer gets this stacked-square treatment — see
   the narrow-landscape block near the end of this file instead. Everything inside stays width-driven
   (vw-based), so it needs no change to keep working at tablet widths — only the trigger condition
   widened. */
@media (orientation: portrait) and (max-width: 959.98px) {
  /* Shared bottom-sheet baseline (wave-7 T5 refactor): both the chat sheet (rp-room-chathost) and the
     slide-picker sheet (rp-room-picker, below) anchor to the SAME "top bar + square stage" line — the
     derivation is unchanged from the original rp-room-chathost/rp-room-sheetbackdrop comments (still
     below), just named once here so a third sheet never has to re-derive or duplicate the "100vw + Npx"
     magic. */
  .rp-room {
    --room-sheet-top: calc(100vw + 40px);
    --room-sheet-backdrop-top: calc(100vw + 32px);
  }

  .rp-room-top { height: 48px; padding: 0 14px; gap: 10px; }
  .rp-room-top-scene { display: none; }

  .rp-room-scenerow {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px 0;
    order: 2;
  }

  .rp-room-main {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 8px 12px 12px;
    overflow-y: auto;
  }
  .rp-room-main > .rp-rtool { order: 3; }
  .rp-room .rp-room-square { order: 1; width: 100%; height: auto; aspect-ratio: 1 / 1; max-width: 100%; }
  .rp-room-side { order: 4; }

  .rp-room-tiles {
    display: flex;
    flex-direction: row;
    gap: 6px;
    overflow-x: auto;
  }
  .rp-room-tiles .rp-room-tile { flex: 0 0 132px; }

  /* Re-review fix (wave-7 T4): the sheet's top must share the backdrop's baseline (`top:
     calc(100vw + 32px)` below), NOT be an independent viewport fraction — the previous
     `height: min(60vh, 420px)` had a vh basis while the backdrop line has a vw basis, so on a short
     viewport (visible browser address bar shrinking the effective vh; iPhone SE 375×667 ≈ 140px of
     overlap) the OPAQUE sheet's top edge climbed ABOVE the backdrop line and covered part of the live
     stage — undimmed, a straight card-over-video occlusion. Anchoring `top` to the same `100vw + …`
     baseline (+8px gap below the backdrop line, mirroring the mockup's sheet top sitting 10px below its
     backdrop's top) makes the sheet structurally unable to reach the stage on ANY portrait viewport;
     the height now falls out of the top/bottom constraints instead of being fixed. The closed-state
     slide-away keeps working unchanged: `translateY(100%)` is relative to the element's own (now
     computed) height, which moves its top edge exactly to the viewport bottom. The panel inside is
     already a flex column (.rp-rchat: list flexes + scrolls, composer pinned at the bottom), so a
     shorter/taller sheet just changes the list's scroll area. (T5 generalized this baseline into the
     --room-sheet-top custom property above so the slide-picker sheet, rp-room-picker below, reuses it
     verbatim instead of re-deriving the same "100vw + Npx" math.) */
  .rp-room-chathost {
    position: absolute;
    left: 0;
    right: 0;
    top: var(--room-sheet-top);
    bottom: 0;
    height: auto;
    z-index: 21;
    border-top-left-radius: 20px;
    border-top-right-radius: 20px;
    box-shadow: var(--shadow-lg);
    transform: translateY(100%);
    transition: transform 0.2s ease;
    pointer-events: none;
  }
  .rp-room-chathost--open {
    transform: translateY(0);
    pointer-events: auto;
  }

  /* Slide-picker sheet (T5): the SAME rp-room-picker markup as the desktop popover, just repositioned —
     conditionally rendered (Razor `@if (_pickerOpen)`), not always-mounted, so no transform/open-modifier
     is needed the way rp-room-chathost's live component instance requires. Shares the chat sheet's
     baseline via --room-sheet-top (see the shared block above) so the magic number lives in one place. */
  .rp-room-picker {
    position: absolute;
    left: 0;
    right: 0;
    top: var(--room-sheet-top);
    bottom: 0;
    width: auto;
    height: auto;
    z-index: 21;
    padding: 14px 18px 18px;
    border-radius: 20px 20px 0 0;
    box-shadow: var(--shadow-lg);
    display: flex;
    flex-direction: column;
    overflow-y: auto;
  }

  /* Review fix (wave-7 T4): .rp-room-sheetbackdrop's base rule (`inset: 0`, resolved against `.rp-room`,
     the nearest positioned ancestor) covered the ENTIRE room — including the top bar and the square stage
     — whenever the mobile chat sheet was open. The mockup (Видеокомната.dc.html, mobile 390px frame) never
     darkens the stage: its backdrop starts at `top: calc(48px + 390px)` (top-bar height + stage height).
     Reproduced responsively here — 48px top bar + `.rp-room-main`'s 8px top padding + the square's own
     rendered height (100vw minus `.rp-room-main`'s 12px+12px side padding, since the square is
     `width:100%; aspect-ratio:1/1` there) simplifies to `100vw + 32px`. Only `top` is overridden; the
     `left/right/bottom: 0` from the base rule are unchanged, so the dimmed area still reaches the very
     bottom of the screen (through the tool rail / tiles / hand banner / bottom control bar) — it just
     never climbs above the stage. */
  .rp-room-sheetbackdrop { top: var(--room-sheet-backdrop-top); }

  .rp-room-bar { justify-content: center; gap: 10px; padding: 12px 14px 16px; height: auto; }
  .rp-room-bar-spacer { display: none; }
  .rp-room-bar-btn {
    width: 46px;
    height: 46px;
    padding: 0;
    border-radius: 50%;
    justify-content: center;
  }
  .rp-room-bar-lbl { display: none; }
  .rp-room-bar-chat { display: inline-flex; }
  .rp-room-bar-leave {
    width: 56px;
    height: 46px;
    padding: 0;
    justify-content: center;
    border-radius: 999px;
  }
}

/* ---------- Phone/narrow landscape (wave 7 Task 6, widened by the T6 re-review) ---------- */
/* Видеокомната.dc.html "Телефон · горизонтально" (844×390): rail (48px, vertical, scrolls y) | square
   stage (height-bound, LOCKED) | right column — header row (title/timer/scene tabs/slide-nav, compact) /
   2×2 16:9 tile grid / hand banner / round controls.

   Review fix (Defect 2): gated on `max-width:959.98px` — the SAME width bracket `_isNarrow` uses (the
   .02px split at the Sm|Md boundary, see the portrait block's comment / fix round 2 Minor-4) — not the
   original `max-height:500px`. The original height gate left a real complement hole: `orientation:
   landscape AND width<960 AND min-height:501px` (e.g. a foldable split-view ~840×673) matched NEITHER this block
   NOR the portrait block above (portrait requires `orientation:portrait`), so it fell through to the
   desktop 3-column grid while `_isNarrow` (width-only, RoomPage.razor) was already "narrow" — the SAME
   disagreement class the file already documents for RoomToolRail below, just for a wider slice of the
   viewport space. Two concrete symptoms this closed: (a) `RoomToolRail` rendered `Horizontal=true` (rail
   row) squeezed into the OLD desktop grid's fixed 52px rail column → overflow; (b) `.rp-room-chathost`
   stayed a permanently-visible desktop column (`ChatVisible` reads `_isNarrow ? _chatOpen : true`, but the
   CSS never hid it) while the chat FAB toggle button was ALSO hidden (mobile-only CSS) — chat was neither
   properly shown nor reachable. Widening the trigger to width-only makes `_isNarrow` and this grid's
   applicability agree on every (orientation × width × height) combination: portrait ≤959.98 → portrait
   block; landscape ≤959.98 → this block (any height); either orientation ≥960 → desktop grid, matching
   `_isNarrow == false` (959.98/960 split mirrors MudBlazor's own Sm|Md boundary — see fix round 2,
   Minor-4). Geometry note for the tall-narrow end of the new range: the stage stays a perfect 1:1 square
   (LOCKED) but its height is capped at `min(100%, calc(100vw - 248px))` (see the stage rule below, fix
   round 2 Important-2), which guarantees the right/"side" column ≥ ~200px on ANY viewport in this range:
   844×390 → stage 390 (min picks 100%, the phone case is untouched), side 406px; 840×673 foldable →
   stage 592 (was an uncapped 673 leaving only 119px), side 200px; ≈955×880 snap-left half-screen →
   stage 707 (was an uncapped 880 leaving a clipped ~27px), side 200px. Squareness survives the cap —
   width follows from aspect-ratio, only the height input shrinks.

   `.rp-room-main` is dissolved via `display:contents` (blueprint-pitfalls П-25 — the same "reflow without
   a DOM change" trick reader.css uses) so its children — the rail, `.rp-room-square`, the always-hidden
   `.rp-room-scenerow`, and `.rp-room-side` — become direct grid items of `.rp-room`, ALONGSIDE its
   already-sibling `.rp-room-top`/`.rp-room-bar`. A 3×3 `grid-template-areas` then places rail+stage
   spanning the full height (column 1/2) and top/side/bar stacked in column 3 — visually identical to
   nesting the header/tiles/controls inside one "right column" wrapper, with zero DOM change.
   `RoomPageRenderTests.Room_main_and_top_bar_nesting_matches_what_the_landscape_grid_relies_on` is the
   structural guard П-25 requires.

   RoomToolRail's `Horizontal` param is still bound to `_isNarrow` (RoomPage.razor, C#, width-only) — the
   ONE place that signal and true orientation disagree, since a phone-landscape width (844px) sits inside
   MudBlazor's Sm ("narrow") bracket, so `Horizontal` renders the row modifier here even though the rail
   must stay a vertical column. Reconciled entirely in CSS, no RoomPage logic change (per the task brief):
   `.rp-room-main > .rp-rtool` (2-class specificity) outranks the single-class `.rp-rtool--row` rule and
   wins regardless of which shape `Horizontal` picked.

   Chat is a genuine `.rp-room-side` descendant already, so it gets the mockup's true `inset:0`/
   `border-left` panel. Review fix (Defect 1): the slide picker NOW gets the same treatment, via a SECOND
   rendered instance (RoomPage.razor's `PickerPanel(overlay: true)`) that lives directly inside
   `.rp-room-side` — the original SceneControls-nested instance (`.rp-room-top-scene` → `.rp-room-
   slidenav` → `.rp-room-picker`, still the desktop popover/portrait sheet) is hidden here instead of
   trying to reach `inset:0` through 4 more ancestor dissolves. Both copies read the same `_pickerOpen`/
   `_slideIndex`/`_deck` fields, so there's nothing to keep in sync — only one is ever mounted-and-visible
   at a time. It still loses its dimming backdrop (the stage must never darken, LOCKED — the SAME rule
   that motivated the portrait sheetbackdrop's below-stage `top` above), so `rp-room-picker-close` takes
   over dismissal. */
@media (orientation: landscape) and (max-width: 959.98px) {
  .rp-room {
    display: grid;
    grid-template-columns: 48px auto 1fr;
    grid-template-rows: auto 1fr auto;
    grid-template-areas:
      "rail stage top"
      "rail stage side"
      "rail stage bar";
  }
  .rp-room-main { display: contents; }

  .rp-room-main > .rp-rtool {
    grid-area: rail;
    width: 48px;
    flex-direction: column;
    padding: 8px 0;
    border: 0;
    border-right: 1px solid var(--border);
    border-radius: 0;
    overflow-y: auto;
    min-height: 0;
  }
  .rp-room-main > .rp-rtool .rp-rtool-sep { width: 26px; height: 1px; margin: 4px 0; }

  /* Stage cap (fix round 2, Important-2): without it, a near-square landscape window ≤960 wide (e.g. a
     snap-left browser half on 1920×1080 → viewport ≈955×880) let the height-bound 1:1 stage eat
     width−48−height ≈ 27px of side column — every control clipped under `.rp-room`'s overflow:hidden.
     `min(100%, calc(100vw - 248px))` keeps the phone case untouched (844×390: 100vw−248 = 596 > the
     100%-of-area 390 → min picks 390, exactly as before) while guaranteeing the side column never drops
     below ~200px: 248 = 48px rail + 200px minimum side column (the grid has no gaps, so the side column
     gets exactly 100vw − 48 − stage-width). Squareness is preserved — width still follows from the
     unchanged aspect-ratio:1/1, only the height input shrinks (840×673 → stage 592, side 200; 955×880 →
     stage 707, side 200). Compound selector: the base `.rp-room .rp-room-square` sets height:100% at
     0,2,0, which a flat `.rp-room-square` here couldn't override. align-self centers the now
     possibly-shorter-than-viewport square vertically in its 3-row area instead of pinning it to the top. */
  .rp-room .rp-room-square {
    grid-area: stage;
    min-width: 0;
    height: min(100%, calc(100vw - 248px));
    align-self: center;
  }

  .rp-room-top {
    grid-area: top;
    min-width: 0;
    height: auto;
    padding: 8px 12px;
    gap: 8px;
    /* The header column is narrow (width − rail − stage); title + timer + scene tabs + slidenav don't
       fit on one line. Wrapping keeps every control reachable — without it the nowrap flex row's
       max-content width inflates the 1fr track and the whole grid overflows .rp-room (smoke find). */
    flex-wrap: wrap;
  }
  /* Same overflow inside the scene group: near the cap the column bottoms out at 200px, narrower than
     tabs + slidenav side by side (~367px) — they must be allowed onto separate wrapped lines too. And
     the tab segment itself (~200px with labels) must shrink below the 200px floor: let the tabs give up
     label width via ellipsis instead of inflating the track. */
  .rp-room-top-scene { flex-wrap: wrap; min-width: 0; }
  .rp-room-top-scene .rp-seg { min-width: 0; max-width: 100%; }
  .rp-room-top-scene .rp-seg-tab { min-width: 0; }
  .rp-room-top-scene .rp-room-scenetab-lbl { overflow: hidden; text-overflow: ellipsis; }
  .rp-room-top-users { display: none; } /* dropped for space — not shown in the mockup's compact header */

  .rp-room-side {
    grid-area: side;
    position: relative;
    min-width: 0;
    overflow-y: auto;
  }
  .rp-room-tiles { gap: 6px; }
  .rp-room-tile { aspect-ratio: 16 / 9; } /* LOCKED: 16:9 here, unlike desktop/portrait's 16:10 */

  .rp-room-bar {
    grid-area: bar;
    min-width: 0;
    height: auto;
    justify-content: center;
    gap: 8px;
    padding: 6px 12px 10px;
  }
  .rp-room-bar-spacer { display: none; }
  .rp-room-bar-btn { width: 40px; height: 40px; padding: 0; border-radius: 50%; justify-content: center; }
  .rp-room-bar-lbl { display: none; }
  .rp-room-bar-chat { display: inline-flex; width: 40px; height: 40px; }
  .rp-room-bar-leave { width: 48px; height: 40px; padding: 0; justify-content: center; }

  /* Chat: true inset:0 panel over the (now-relative) side column, LOCKED. Base .rp-room-chathost stays
     mounted unconditionally (RoomChatPanel is never destroyed, per its own contract) but is display:none
     until the --open modifier lands, since there's no off-screen direction to slide it to here (unlike
     the portrait sheet's translateY). */
  .rp-room-chathost {
    display: none;
    position: absolute;
    inset: 0;
    border: 0;
    border-left: 1px solid var(--border);
    border-radius: 0;
    box-shadow: none;
    z-index: 21;
  }
  .rp-room-chathost.rp-room-chathost--open { display: flex; }
  .rp-room-chat-close-wrap { display: inline-flex; } /* re-shown — the landscape-arm complement above hides it */

  .rp-room-sheetbackdrop { display: none; } /* the stage must never dim (LOCKED) — the ✕es dismiss instead */
  .rp-room-picker-close { display: inline-flex; }

  /* Slide picker (review fix, wave-7 T6 re-review, Defect 1): swap which of the two rendered instances is
     interactive — hide the SceneControls-nested popover/sheet instance (still physically inside
     `.rp-room-top`), show the `.rp-room-side`-hosted one as a true `inset:0`/`border-left` panel over the
     (now-relative) side column, mirroring the chat host immediately above. No backdrop (the stage must
     never dim, LOCKED) — the close ✕ is the only dismissal. Compound selector on purpose — must match the
     base hide's 0,2,0 specificity so this later-in-file rule wins here and ONLY here (see the base rule's
     comment; a flat 0,1,0 form would lose to the compound hide everywhere). */
  .rp-room-top .rp-room-picker { display: none; }
  .rp-room-picker.rp-room-picker--overlay {
    display: flex;
    flex-direction: column;
    position: absolute;
    inset: 0;
    width: auto;
    border: 0;
    border-left: 1px solid var(--border);
    border-radius: 0;
    box-shadow: none;
    z-index: 22;
  }
  .rp-room-picker--overlay .rp-room-picker-head { flex-shrink: 0; }
  /* align-content:start is load-bearing: the overlay's inset:0 gives the grid a definite (tall) height,
     and a stretched row + the cells' aspect-ratio:1/1 would re-derive cell WIDTH from the stretched row
     height — 177px cells overflowing the panel horizontally (smoke find). Start-packed rows keep the
     height column-driven (1fr width → same height), as in the desktop popover. */
  .rp-room-picker--overlay .rp-room-picker-grid { flex: 1; overflow-y: auto; align-content: start; }
}

/* ── Admin shell (rp-adm*, wave 8 Task 3 — AdminPageHeader + hub-page CSS-каркас for T4–T8,
   Админ-обзор.dc.html) ──────────────────────────────────────────────────────────────────── */

.rp-adm-head {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 20px;
}
.rp-adm-head h1 {
  margin: 0;
  font-size: 18px;
  font-weight: 700;
}
.rp-adm-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 600;
  background: var(--warning-muted);
  color: var(--warning-muted-foreground);
  white-space: nowrap;
}
.rp-adm-head__spacer { flex: 1; }

/* KPI card grid (/admin Обзор — the 4 top-level stat tiles). */
.rp-adm-stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px;
  margin-bottom: 14px;
}

/* Stat tile — the whole card is a link (Админ-обзор.dc.html §stats). */
.rp-adm-tile {
  display: block;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 16px 18px;
  text-decoration: none;
  color: var(--foreground);
  transition: border-color 0.15s ease;
}
.rp-adm-tile:hover { border-color: color-mix(in srgb, var(--primary) 45%, var(--border)); }
.rp-adm-tile__label {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--muted-foreground);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 6px;
}
.rp-adm-tile__row { display: flex; align-items: baseline; gap: 8px; }
.rp-adm-tile__value {
  font-size: 26px;
  font-weight: 700;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.rp-adm-tile__sub { font-size: 12.5px; font-weight: 600; }
.rp-adm-tile__sub--success { color: var(--success-muted-foreground); }
.rp-adm-tile__sub--muted   { color: var(--muted-foreground); }
.rp-adm-tile__sub--danger  { color: var(--destructive-muted-foreground); }

/* Email-failures banner-link (visible only when EmailFailures > 0). */
.rp-adm-alert {
  display: flex;
  align-items: center;
  gap: 12px;
  border: 1px solid color-mix(in srgb, var(--warning) 40%, var(--border));
  background: var(--warning-muted);
  color: var(--warning-muted-foreground);
  border-radius: var(--radius-lg);
  padding: 11px 16px;
  margin-bottom: 22px;
  text-decoration: none;
}
.rp-adm-alert__text { flex: 1; font-size: 13px; }
.rp-adm-alert__cta { font-size: 12.5px; font-weight: 600; white-space: nowrap; }

/* "Новые тенанты" / "Последние ошибки" — two bordered list-cards, side by side on desktop. */
.rp-adm-lists { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.rp-adm-list {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  overflow: hidden;
}
.rp-adm-list__head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 13px 18px;
  border-bottom: 1px solid var(--border);
}
.rp-adm-list__title { font-size: 14px; font-weight: 700; flex: 1; }
.rp-adm-list__link { font-size: 12.5px; font-weight: 600; color: var(--primary); text-decoration: none; white-space: nowrap; }
.rp-adm-list-empty { padding: 16px 18px; font-size: 13px; color: var(--muted-foreground); }

/* One row skin for both list kinds: tenant rows use -avatar/-plan, error rows use -dot; both share
   -body/-title/-sub/-meta. Error rows are `<a>` (clickable to the detail page), tenant rows a plain
   `<div>` (no per-row destination). */
.rp-adm-list-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 18px;
  border-bottom: 1px solid var(--border);
  text-decoration: none;
  color: var(--foreground);
}
.rp-adm-list-row:last-child { border-bottom: 0; }
a.rp-adm-list-row:hover { background: var(--secondary); }
.rp-adm-list-row__avatar {
  width: 30px;
  height: 30px;
  flex-shrink: 0;
  border-radius: var(--radius-md);
  background: var(--accent);
  color: var(--accent-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 700;
}
.rp-adm-list-row__dot {
  width: 8px;
  height: 8px;
  flex-shrink: 0;
  border-radius: 999px;
  background: var(--border);
}
.rp-adm-list-row__dot--active { background: var(--destructive); }
.rp-adm-list-row__body { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.rp-adm-list-row__title {
  font-size: 13.5px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.rp-adm-list-row__title--mono { font-family: var(--font-mono); font-size: 13px; }
.rp-adm-list-row__sub {
  font-size: 12px;
  color: var(--muted-foreground);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.rp-adm-list-row__plan {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  background: var(--muted);
  color: var(--muted-foreground);
  white-space: nowrap;
  /* Long plan names («Профессиональный») exceed the grid column: without max-width+ellipsis the
     pill gets hard-clipped mid-letter by the cell (wave-8 live smoke finding). */
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: bottom;
}
.rp-adm-list-row__meta {
  font-size: 12px;
  color: var(--muted-foreground);
  white-space: nowrap;
  flex-shrink: 0;
}

/* Generic grid-таблица shell for hub pages (T5 «Пользователи», T6 «Подписки», T7 «Ошибки») —
   each page sets its own column widths via a `--adm-cols` custom property on a modifier class
   (e.g. `.rp-adm-table--tenants { --adm-cols: 100px 1fr 120px 90px; }`) instead of a bespoke
   grid-template-columns per hub, mirroring rp-fin-table/-thead/-row. */
.rp-adm-table {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  overflow: hidden;
}
.rp-adm-table__head,
.rp-adm-table__row {
  display: grid;
  grid-template-columns: var(--adm-cols, 1fr);
  gap: 12px;
  align-items: center;
  padding: 13px 18px;
  border-bottom: 1px solid var(--border);
}
.rp-adm-table__head {
  padding: 10px 18px;
  font-size: 11.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted-foreground);
}
.rp-adm-table__row { text-decoration: none; color: var(--foreground); }
.rp-adm-table__row:last-child { border-bottom: 0; }
.rp-adm-table__row:hover { background: var(--secondary); }

/* Mobile card fallback for rp-adm-table (same per-hub-modifier pattern, mirrors rp-fin-cards). */
.rp-adm-cards { display: none; flex-direction: column; gap: 9px; }
.rp-adm-card {
  display: block;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 13px 15px;
}

/* ── /admin/tenants hub (T5) ──────────────────────────────────────────────────────────────── */

.rp-adm-panel { padding-top: 4px; }

.rp-adm-toolbar { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; }
.rp-adm-search {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
  max-width: 340px;
  height: 38px;
  padding: 0 12px;
  border: 1px solid var(--input);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--muted-foreground);
}
.rp-adm-search-input {
  flex: 1;
  min-width: 0;
  border: 0;
  outline: none;
  background: transparent;
  color: var(--foreground);
  font: inherit;
  font-size: 13.5px;
}
.rp-adm-toolbar-spacer { flex: 1; }
.rp-adm-count { font-size: 12.5px; color: var(--muted-foreground); white-space: nowrap; }

/* Per-hub column widths for the three /admin/tenants tabs (last column = kebab, omitted for the
   read-only «Ученики» tab). */
.rp-adm-table--tenants  { --adm-cols: 1.5fr 1.1fr 90px 90px 90px 140px 40px; }
.rp-adm-table--users    { --adm-cols: 1.3fr 1.4fr 1.3fr 1fr 100px 40px; }
.rp-adm-table--students { --adm-cols: 1.3fr 1fr 110px 130px 110px; }

/* Generic cell content, reused across the three tables. */
.rp-adm-cell-stack { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.rp-adm-cell-main {
  font-size: 13.5px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.rp-adm-cell-sub {
  font-size: 12px;
  color: var(--muted-foreground);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.rp-adm-cell-mono { font-family: var(--font-mono); }
.rp-adm-cell-right { text-align: right; font-variant-numeric: tabular-nums; }
.rp-adm-cell-user { display: flex; align-items: center; gap: 10px; min-width: 0; }
.rp-adm-avatar {
  width: 28px;
  height: 28px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--muted);
  color: var(--muted-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 700;
}
.rp-adm-rolechips { display: flex; gap: 4px; flex-wrap: wrap; }

/* Row action cell — a BbDropdownMenu trigger, mirrors rp-tm-kebab (TestsPage). */
.rp-adm-rowact { display: flex; justify-content: center; }
.rp-adm-kebab {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  flex-shrink: 0;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--muted-foreground);
  cursor: pointer;
}
.rp-adm-kebab:hover { background: var(--secondary); color: var(--foreground); }

/* "Показать ещё" — grows the panel's local `take` and re-fires ComputeState. */
.rp-adm-more {
  display: block;
  width: 100%;
  margin-top: 10px;
  padding: 10px;
  border: 1px dashed var(--border);
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--muted-foreground);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  text-align: center;
}
.rp-adm-more:hover { background: var(--secondary); color: var(--foreground); }

/* Mobile card body (rp-adm-card's own content — T4 only sets the outer card shell above). */
.rp-adm-card-top { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.rp-adm-card-title {
  font-size: 13.5px;
  font-weight: 600;
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.rp-adm-card-sub { font-size: 12px; color: var(--muted-foreground); margin-top: 3px; }

/* Balance-of-lessons figure — bold weight (unlike the plain rp-adm-cell-right student-count column);
   zero tints destructive-muted (mockup's balColor rule). */
.rp-adm-balance { font-weight: 600; }
.rp-adm-balance--zero { color: var(--destructive-muted-foreground); }

/* «Приглашения» collapsed section on the «Ученики» tab — native <details>, no JS. */
.rp-adm-accordion {
  margin-top: 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  overflow: hidden;
}
.rp-adm-accordion-summary {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 13px 18px;
  cursor: pointer;
  font-size: 14px;
  font-weight: 700;
  list-style: none;
}
.rp-adm-accordion-summary::-webkit-details-marker { display: none; }
.rp-adm-accordion-count { font-weight: 500; color: var(--muted-foreground); }
.rp-adm-accordion-body { border-top: 1px solid var(--border); padding: 4px 0; }

.rp-adm-invtable { display: flex; flex-direction: column; }
.rp-adm-invtable__head,
.rp-adm-invtable__row {
  display: grid;
  grid-template-columns: 1.3fr 1fr 100px 100px 100px;
  gap: 12px;
  align-items: center;
  padding: 9px 18px;
}
.rp-adm-invtable__head {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted-foreground);
}
.rp-adm-invtable__row { border-top: 1px solid var(--border); font-size: 12.5px; }

@media (max-width: 640px) {
  .rp-adm-stats { grid-template-columns: repeat(2, 1fr); }
  .rp-adm-table { display: none; }
  .rp-adm-cards { display: flex; }
  .rp-adm-lists { grid-template-columns: 1fr; }

  .rp-adm-search { max-width: none; }
  .rp-adm-count { display: none; }

  .rp-adm-invtable__head { display: none; }
  .rp-adm-invtable__row {
    grid-template-columns: 1fr;
    gap: 2px;
    padding: 10px 16px;
  }
}

/* ── /admin/finance hub (T6) ──────────────────────────────────────────────────────────────── */

/* «Подписки» tab: 4 KPI tiles reuse rp-adm-stats/-tile as plain divs (no href — no per-tile drill
   target here, unlike /admin Обзор's tiles). A tile with a single figure and no delta gets its tone
   on the VALUE itself rather than on a -sub caption (there's nothing to caption). */
.rp-adm-tile__value--warning { color: var(--warning-muted-foreground); }
.rp-adm-tile__value--danger  { color: var(--destructive-muted-foreground); }

.rp-adm-filterbar {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  background: var(--muted);
  border-radius: var(--radius-md);
}
.rp-adm-filter {
  padding: 6px 12px;
  border: 0;
  border-radius: var(--radius-sm);
  font: inherit;
  font-size: 12.5px;
  font-weight: 500;
  background: transparent;
  color: var(--muted-foreground);
  cursor: pointer;
}
.rp-adm-filter--active {
  font-weight: 600;
  background: var(--card);
  color: var(--foreground);
  box-shadow: var(--shadow-xs);
}

/* «План» column is minmax so long plan names («Профессиональный») get room before the pill
   falls back to its own ellipsis (wave-8 live smoke finding). */
.rp-adm-table--subs { --adm-cols: 1.4fr minmax(100px, max-content) 130px 130px 110px 40px; }

/* «Оплачено до» cell tone — mirrors the row's status tone (rp-adm-cell-sub is the neutral default). */
.rp-adm-cell-tone--warning { color: var(--warning-muted-foreground); }
.rp-adm-cell-tone--danger  { color: var(--destructive-muted-foreground); }

/* ── «Планы и монетизация» tab ────────────────────────────────────────────────────────────── */

.rp-adm-plans-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  max-width: 920px;
  margin-bottom: 10px;
}
.rp-adm-plan-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 18px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.rp-adm-plan-head { display: flex; align-items: center; gap: 8px; }
.rp-adm-plan-name { font-size: 14.5px; font-weight: 700; flex: 1; }
.rp-adm-plan-count { font-size: 12px; color: var(--muted-foreground); white-space: nowrap; }

.rp-adm-plan-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 2px; }
.rp-adm-plan-chip {
  display: inline-flex;
  align-items: center;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  background: var(--muted);
  color: var(--muted-foreground);
}

.rp-adm-plans-savebar { margin: 12px 0 4px; }
.rp-adm-plans-savebtn {
  height: 38px;
  padding: 0 18px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-foreground);
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
}
.rp-adm-plans-savebtn:disabled { opacity: 0.6; cursor: default; }
.rp-adm-plans-caption { font-size: 12px; color: var(--muted-foreground); margin-top: 8px; }

/* Generic labelled-input field pair — plan cards + the bottom AI-billing trio. */
.rp-adm-field { display: block; min-width: 0; }
.rp-adm-field-label {
  display: block;
  font-size: 12px;
  font-weight: 600;
  margin-bottom: 4px;
  color: var(--muted-foreground);
}
.rp-adm-field-input {
  width: 100%;
  height: 36px;
  padding: 0 11px;
  border: 1px solid var(--input);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 13.5px;
  font-variant-numeric: tabular-nums;
}

/* Section headers shared by packs / promos / AI-billing. */
.rp-adm-section { margin-bottom: 28px; }
.rp-adm-section-head { display: flex; align-items: center; margin-bottom: 12px; gap: 12px; }
.rp-adm-section-title { font-size: 15px; font-weight: 700; }
.rp-adm-section-sub { font-size: 12.5px; color: var(--muted-foreground); margin-top: 2px; }
.rp-adm-addbtn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 36px;
  padding: 0 14px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-foreground);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}
.rp-adm-addbtn:hover { opacity: 0.92; }

.rp-adm-table--packs  { --adm-cols: 1fr 110px 110px 70px 40px; }
.rp-adm-table--promos { --adm-cols: 130px 1fr 120px 100px 70px 40px; }

.rp-adm-billing-fields { display: flex; align-items: flex-end; gap: 16px; flex-wrap: wrap; max-width: 720px; }
.rp-adm-billing-fields .rp-adm-field { flex: 1; min-width: 160px; }

/* Hand-rolled 36×21 switch (RpAdminSwitch.razor) — see П-9 note on the component. */
.rp-adm-switch {
  position: relative;
  width: 36px;
  height: 21px;
  border: 0;
  border-radius: 999px;
  background: var(--border);
  padding: 0;
  cursor: pointer;
}
.rp-adm-switch[aria-checked="true"] { background: var(--primary); }
.rp-adm-switch:disabled { cursor: not-allowed; opacity: 0.6; }
.rp-adm-switch-thumb {
  position: absolute;
  top: 2.5px;
  left: 2.5px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #fff;
  box-shadow: var(--shadow-xs);
  transition: left 0.15s;
}
.rp-adm-switch[aria-checked="true"] .rp-adm-switch-thumb { left: 17.5px; }

/* A dialog's own "Активен" field: label + switch as a flex row inside one rp-scard-dlg-field cell. */
.rp-adm-switchrow { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.rp-adm-switchrow .rp-sched-dlg-label { margin-bottom: 0; }

@media (max-width: 640px) {
  .rp-adm-plans-grid { grid-template-columns: 1fr; }
  .rp-adm-section-head { flex-wrap: wrap; }
}

/* ── /admin/errors hub (T7) ───────────────────────────────────────────────────────────────── */

/* «Ошибки» tab (Ошибки и Email-сбои.dc.html): reuses rp-adm-filterbar/-filter(--active) verbatim
   for the Новые/Все/Решённые segment (T6 precedent) plus a compact native select (rp-adm-select)
   for the ErrorSource filter — the old MudToggleGroup's "Все/API/WASM/MAUI" labels, kept as a
   select per the task brief rather than a second segment row (no room for two segment bars on
   mobile); rp-adm-toolbar--wrap lets that combined toolbar row wrap under rp-adm-toolbar without
   touching the class every other hub's toolbar shares. rp-adm-table gains --adm-cols modifier
   rp-adm-table--errors (7 cols: when / exception+message / route / tenant / count / status /
   chevron); the trailing chevron cell (rp-adm-chevron, a centered muted glyph) is purely
   decorative — the row itself is the click target, an anchor wrapping rp-adm-table__row exactly
   like AdminIndex's rp-adm-list-row. Mobile cards reuse rp-adm-card verbatim, also wrapped in an
   anchor — a.rp-adm-card resets link styling (text-decoration/color) the same way a.rp-adm-list-row
   already does. rp-adm-note is the small "показаны первые N из M" honest-truncation caption (no
   "Показать ещё" here per the brief — take is a fixed 100).
   Деталь (ErrorDetail.razor): rp-adm-back is the "← Ошибки" pill button; rp-adm-detail-head/
   -title-wrap/-title/-msg lay out the ExceptionType(mono)+Message header next to the "Отметить
   решённой" button (reuses rp-adm-addbtn — same primary-filled recipe as the packs/promos "+"
   button, T6). rp-adm-metachips/-metachip(-k/-v) is the bordered pill row for non-empty meta
   fields (Маршрут/Тенант/Пользователь/Источник/Браузер/CorrelationId/Когда) — a chip only renders
   when its field is non-null (ErrorDetail.razor's own filter), never shown empty. rp-adm-panel-card
   (-head/-title/-body) is the generic bordered-card shell reused by both the Stack trace block
   (rp-adm-stacktrace + rp-adm-copybtn) and the "Повторы этой группы" block (rp-adm-repeats-row +
   rp-adm-repeats-more "Показать все N →" link, which expands the already-fetched list client-side —
   no second read).
   «Email-сбои» tab: rp-adm-table--email is its --adm-cols modifier (6 cols); rp-adm-rowbtn is the
   per-row "Повторить" button (also reused, full-width, on the ≤640px card); rp-adm-retryall is the
   toolbar's "Повторить все неотправленные" button (same bordered recipe as rp-adm-rowbtn plus an
   icon gap + disabled-while-busy dimming). rp-adm-empty-success(-icon/-title) is a dedicated
   success-toned empty state ("Все письма доставлены") — NOT the dashed rp-empty2/RpEmpty look;
   mirrors rp-asg-empty's success-circle recipe (Задания.dc.html) but kept in this file's rp-adm-*
   namespace since it's a different feature. */

.rp-adm-toolbar--wrap { flex-wrap: wrap; row-gap: 8px; }

.rp-adm-select {
  height: 34px;
  padding: 0 10px;
  border: 1px solid var(--input);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 12.5px;
  cursor: pointer;
}

.rp-adm-table--errors { --adm-cols: 110px 1.8fr 1fr 1fr 70px 110px 24px; }
.rp-adm-table--email  { --adm-cols: 110px 1.3fr 1.1fr 1.5fr 80px 110px; }

.rp-adm-chevron { display: flex; justify-content: center; color: var(--muted-foreground); }

a.rp-adm-card { text-decoration: none; color: inherit; cursor: pointer; display: block; }

.rp-adm-note { font-size: 12px; color: var(--muted-foreground); margin: 12px 2px 0; }

.rp-adm-back {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 32px;
  padding: 0 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--muted-foreground);
  font: inherit;
  font-size: 12.5px;
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
  margin-bottom: 12px;
}
.rp-adm-back:hover { color: var(--foreground); background: var(--secondary); }

.rp-adm-detail-head { display: flex; align-items: flex-start; gap: 12px; flex-wrap: wrap; margin-bottom: 16px; }
.rp-adm-detail-title-wrap { flex: 1; min-width: 260px; }
.rp-adm-detail-title { font-size: 17px; font-weight: 700; font-family: var(--font-mono); letter-spacing: -0.01em; }
.rp-adm-detail-msg { font-size: 13.5px; color: var(--muted-foreground); margin-top: 3px; }

.rp-adm-metachips { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; }
.rp-adm-metachip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 11px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--card);
  font-size: 12px;
}
.rp-adm-metachip-k { color: var(--muted-foreground); }
.rp-adm-metachip-v { font-weight: 600; font-family: var(--font-mono); font-size: 11.5px; }

.rp-adm-panel-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  overflow: hidden;
  margin-bottom: 14px;
}
.rp-adm-panel-card-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 11px 18px;
  border-bottom: 1px solid var(--border);
}
.rp-adm-panel-card-title { font-size: 13px; font-weight: 700; flex: 1; }
.rp-adm-panel-card-body { padding: 14px 18px; }

.rp-adm-copybtn {
  height: 28px;
  padding: 0 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--muted-foreground);
  font: inherit;
  font-size: 11.5px;
  font-weight: 500;
  cursor: pointer;
}
.rp-adm-copybtn:hover { background: var(--secondary); color: var(--foreground); }

.rp-adm-stacktrace {
  margin: 0;
  padding: 16px 18px;
  font-family: var(--font-mono);
  font-size: 11.5px;
  line-height: 1.7;
  color: var(--muted-foreground);
  overflow-x: auto;
  background: var(--background);
  white-space: pre;
}

.rp-adm-repeats-row {
  font-size: 12.5px;
  color: var(--muted-foreground);
  padding: 3px 0;
}
.rp-adm-repeats-more {
  display: block;
  font-size: 12.5px;
  color: var(--primary);
  font-weight: 600;
  cursor: pointer;
  background: none;
  border: 0;
  padding: 3px 0;
  font-family: inherit;
  text-align: left;
}

.rp-adm-retryall {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 34px;
  padding: 0 13px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}
.rp-adm-retryall:hover { background: var(--secondary); }
.rp-adm-retryall:disabled { opacity: 0.6; cursor: default; }

.rp-adm-rowbtn {
  height: 30px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}
.rp-adm-rowbtn:hover { border-color: var(--primary); color: var(--primary); }
.rp-adm-rowbtn:disabled { opacity: 0.6; cursor: default; }

.rp-adm-empty-success {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 40px 24px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
}
.rp-adm-empty-success-icon {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--success-muted);
  color: var(--success-muted-foreground);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 14px;
}
.rp-adm-empty-success-title { font-size: 15px; font-weight: 700; }

@media (max-width: 640px) {
  .rp-adm-detail-head { flex-wrap: wrap; }
  .rp-adm-back { margin-bottom: 10px; }
}

/* ── PlatformBannerCard (rp-banner-card*, wave 8 Task 8 — Баннеры.dc.html) ───────────────────
   Shared banner look, deliberately its own prefix rather than rp-adm* — PlatformBannerCard.razor
   is reused OUTSIDE /admin too (PlatformBanner.razor in MainLayout, every cabinet page). Tone
   modifiers rp-banner-card--info/--warning (background/foreground/border from the --info-muted
   and --warning-muted token pairs + a color-mix border tint, matching the mockup's preview alert box); -icon
   (leading Lucide triangle-alert/info), -body (title+text stack), -title/-text with a --placeholder
   modifier for the admin publish page's live-preview empty state (muted italic "Заголовок баннера"/
   "Текст баннера" so the preview never looks broken while the form is empty — the real MainLayout
   consumer never hits this branch), -close (the dismiss crestik, rendered only when the caller wires
   OnDismiss). PlatformBanner.razor wraps its list in rp-banner-list (flex column, gap — per-card
   spacing the shared component itself doesn't assume, since the admin preview renders a single card
   with no list wrapper at all). */
.rp-banner-list { display: flex; flex-direction: column; gap: 10px; margin-bottom: 16px; }

.rp-banner-card {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  border-radius: var(--radius-md);
  padding: 10px 14px;
}
.rp-banner-card--warning {
  border: 1px solid color-mix(in srgb, var(--warning) 40%, var(--border));
  background: var(--warning-muted);
  color: var(--warning-muted-foreground);
}
.rp-banner-card--info {
  border: 1px solid color-mix(in srgb, var(--info) 40%, var(--border));
  background: var(--info-muted);
  color: var(--info-muted-foreground);
}
.rp-banner-card__icon { flex-shrink: 0; display: inline-flex; margin-top: 1px; }
.rp-banner-card__body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.rp-banner-card__title { font-size: 13px; font-weight: 700; line-height: 1.4; }
.rp-banner-card__text { font-size: 13px; line-height: 1.5; }
.rp-banner-card__text p { margin: 0; }
.rp-banner-card__title--placeholder,
.rp-banner-card__text--placeholder { opacity: 0.65; font-style: italic; }
.rp-banner-card__close {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border: 0;
  background: transparent;
  color: inherit;
  padding: 0;
  cursor: pointer;
  opacity: 0.7;
}
.rp-banner-card__close:hover { opacity: 1; }

/* ── /admin/platform-announcements «Баннеры» (rp-ban*, wave 8 Task 8) ────────────────────────
   Two-column publish layout (SiteAppearancePanel's controls/preview split, reused for a banner
   instead of a whole landing page): rp-ban-grid (420px/1fr, collapses to one column <760px per the
   task brief — the dedicated breakpoint below, distinct from the shell's 768px / the rp-adm-table
   640px table-to-cards cutoff). rp-ban-form wraps the form in the generic rp-adm-panel-card shell;
   rp-ban-form-row is the Тип/Аудитория two-up sub-grid. rp-adm-field-input gains a --textarea
   modifier (auto height, resize:vertical, line-height) reused by the "Текст" field. rp-ban-preview
   (-eyebrow/-frame/-note) hosts the live PlatformBannerCard plus the mockup's dimmed page-skeleton
   (rp-ban-preview-skeleton/-skel-thumb/-skel-lines/-skel-line, opacity .45 + per-line width
   modifiers --60/--85/--70, exactly the mockup's "rest of the page" placeholder under the banner).
   History reuses rp-adm-table with a new --adm-cols modifier rp-adm-table--banners (Текст/Тип/
   Аудитория/Период/Статус/kebab) — mobile cards are read-only (no action), matching both the
   mockup and the T5/T6 no-kebab-on-mobile-card precedent (AdminTenantsPanel/AdminPlansPanel). */
.rp-ban-grid {
  display: grid;
  grid-template-columns: minmax(0, 420px) 1fr;
  gap: 20px;
  margin-bottom: 26px;
  align-items: start;
}

.rp-ban-form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }

.rp-adm-field-input--textarea { height: auto; padding: 10px 12px; resize: vertical; line-height: 1.5; }

.rp-ban-preview-eyebrow {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted-foreground);
  margin-bottom: 10px;
}
.rp-ban-preview-frame {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--background);
  box-shadow: var(--shadow-xs);
  padding: 14px;
}
.rp-ban-preview-skeleton { display: flex; gap: 10px; opacity: 0.45; margin-top: 10px; }
.rp-ban-preview-skel-thumb {
  width: 130px;
  height: 88px;
  flex-shrink: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
}
.rp-ban-preview-skel-lines { flex: 1; display: flex; flex-direction: column; gap: 8px; padding-top: 4px; }
.rp-ban-preview-skel-line { height: 10px; background: var(--muted); border-radius: 4px; }
.rp-ban-preview-skel-line--60 { height: 14px; width: 60%; }
.rp-ban-preview-skel-line--85 { width: 85%; }
.rp-ban-preview-skel-line--70 { width: 70%; }
.rp-ban-preview-note { font-size: 12px; color: var(--muted-foreground); line-height: 1.6; margin: 10px 2px 0; }

.rp-adm-table--banners { --adm-cols: 1.8fr 130px 130px 150px 90px 40px; }

@media (max-width: 760px) {
  .rp-ban-grid { grid-template-columns: 1fr; }
}

/* ── rp-banner-card--success/--danger (wave 9 Task 1) ─────────────────────────────────────────
   The --warning/--info tone modifiers above predate wave 9; --success/--danger complete the set
   so PlatformBannerCard (and any wave-9 replacement of a MudBlazor success/error Alert) can reuse
   the same card shape for a positive or destructive tone, matching the --success/--destructive
   muted token pairs used elsewhere (rp-chip--success/--danger, rp-prod-kind--success/--danger). */
.rp-banner-card--success {
  border: 1px solid color-mix(in srgb, var(--success) 40%, var(--border));
  background: var(--success-muted);
  color: var(--success-muted-foreground);
}
.rp-banner-card--danger {
  border: 1px solid color-mix(in srgb, var(--destructive) 40%, var(--border));
  background: var(--destructive-muted);
  color: var(--destructive-muted-foreground);
}

/* ── Wave-9: shared spinner, confirm dialog, long-tail utility classes ─── */
.rp-spin { display: inline-block; width: 24px; height: 24px; border-radius: 50%;
  border: 2.5px solid color-mix(in srgb, var(--primary) 25%, transparent);
  border-top-color: var(--primary); animation: rp-spin-rotate .7s linear infinite; }
.rp-spin--sm { width: 16px; height: 16px; border-width: 2px; }
@keyframes rp-spin-rotate { to { transform: rotate(360deg); } }
.rp-confirm-dlg { max-width: 420px; }
.rp-confirm-dlg__title { font-size: 1.0625rem; font-weight: 600; color: var(--foreground); }
.rp-confirm-dlg__text {
  margin: 10px 0 0;
  font-size: .875rem;
  color: var(--muted-foreground);
  /* wave-9 T2: TutorHome's Decline confirm folds a consequences bullet list into this plain string —
     the first multi-line caller, so newlines need to actually break. */
  white-space: pre-line;
}
.rp-confirm-dlg__actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 20px; }
.rp-dim { color: var(--muted-foreground); font-size: .8125rem; }
.rp-icon-btn { display: inline-flex; align-items: center; justify-content: center; width: 36px; height: 36px;
  border: none; background: transparent; border-radius: var(--radius-md); color: var(--muted-foreground);
  cursor: pointer; }
.rp-icon-btn:hover { background: var(--accent); color: var(--accent-foreground); }

/* ── Wave-9 Task 2: native Rp*-input primitives ──────────────────────────────────────────────────
   RpTextField/RpSelect/RpAutocomplete replace their MudBlazor-backed versions with plain HTML,
   reusing the existing rp-sched-dlg-input look (no new visual language — blueprint-pitfalls.md).
   rp-field is the shared label+control+hint column; rp-ac* is the native <input list=…><datalist>
   autocomplete (RpAutocomplete); rp-avatar is RpAvatar's circle; rp-busybtn-spin is RpBusyButton's
   inline spinner gap. */
.rp-field { display: flex; flex-direction: column; gap: 6px; }
.rp-field textarea.rp-sched-dlg-input { height: auto; min-height: 72px; padding: 10px 12px; resize: vertical; }
.rp-field select.rp-sched-dlg-input { cursor: pointer; }
.rp-field input.rp-sched-dlg-input[readonly] { background: var(--muted); cursor: default; }
.rp-field-counter { align-self: flex-end; font-size: 11.5px; color: var(--muted-foreground); margin-top: -2px; }
.rp-field-err { font-size: 12.5px; color: var(--destructive); }

.rp-ac-wrap { position: relative; display: flex; align-items: center; }
.rp-ac-wrap input.rp-sched-dlg-input { padding-right: 30px; }
.rp-ac-clear {
  position: absolute;
  right: 4px;
  width: 24px;
  height: 24px;
  border: none;
  background: transparent;
  border-radius: 50%;
  color: var(--muted-foreground);
  cursor: pointer;
  font-size: 15px;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.rp-ac-clear:hover { background: var(--accent); color: var(--accent-foreground); }

.rp-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  border-radius: 50%;
  background: var(--primary);
  color: var(--primary-foreground);
  font-weight: 600;
  width: 40px;
  height: 40px;
  font-size: 15px;
  flex-shrink: 0;
}
.rp-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }

.rp-busybtn-spin { margin-right: 6px; }

/* RpImageField's preview: no rule existed pre-wave-9 (MudImage's Fluid="true" supplied the
   max-width:100% responsive sizing via Mud's own CSS) — added here so dropping MudImage doesn't
   let a full-resolution cover image blow out its unconstrained parent (LessonCoverEditor,
   CourseOverviewPage, ImageBlockEditor all render it with no fixed-size wrapper). */
.rp-image-field-preview { max-width: 100%; height: auto; display: block; border-radius: var(--radius-md); }
.rp-image-field-placeholder { display: flex; align-items: center; justify-content: center; color: var(--muted-foreground); }

/* OnboardingChecklistCard — the "Начало работы" card on TutorHome (wave-9 T3, MudPaper/MudList/
   MudListItem → rp-card chrome + a plain checklist). Header/body/title/chip chrome is REUSED from
   rp-card/-card-header/-card-title/-card-body + rp-chip verbatim; only the list rows below are new.
   .rp-onboarding-done (line-through + muted opacity on a completed item's label) already existed
   pre-wave-9 in app.css — reused unchanged. */
.rp-onboarding-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.rp-onboarding-item { display: flex; align-items: center; gap: 10px; padding: 8px 0; }
.rp-onboarding-item--disabled { color: var(--muted-foreground); }
.rp-onboarding-link {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 1;
  min-width: 0;
  color: var(--foreground);
  text-decoration: none;
}
.rp-onboarding-link:hover { color: var(--primary); }
.rp-onboarding-ico--done { color: var(--success); flex-shrink: 0; display: inline-flex; }
.rp-onboarding-ico--todo { color: var(--primary); flex-shrink: 0; display: inline-flex; }
.rp-onboarding-ico--soon { color: var(--muted-foreground); flex-shrink: 0; display: inline-flex; }
.rp-onboarding-sub { margin: 0 0 12px; }
.rp-onboarding-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 8px;
}
.rp-onboarding-continue { display: inline-flex; align-items: center; gap: 6px; }

/* CalendarHeader's «Сегодня» button (wave-9 T3 — replaces MudButton Size=Small Variant=Outlined). */
.rp-cal-today-btn {
  height: 32px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
}
.rp-cal-today-btn:hover { background: var(--accent); color: var(--accent-foreground); }

/* AiCreditBalanceWidget — the AiFeaturesPanel credit chip (wave-9 T3, replaces MudTooltip+MudChip+MudLink). */
.rp-aicb { display: inline-flex; align-items: center; gap: 8px; }
.rp-aicb-buy { font-size: 12px; color: var(--muted-foreground); text-decoration: underline; }
.rp-aicb-buy:hover { color: var(--foreground); }

/* LandingBlockForm — the per-block editor form body shared by SiteContentPanel/LandingBlockEditDialog
   and the onboarding preview (wave-9 T3, replaces MudPaper/MudText/MudButton/MudIcon/MudIconButton/
   MudAlert/MudSwitch/MudLink). Fields keep RpTextField/RpSelect (T2) with rp-lbf-field standing in for
   Mud's mb-2/mb-3/mb-4 utility classes (one flat 12px gap instead of three different values — a
   deliberate simplification, not a pixel-exact port). */
.rp-lbf-field { margin-bottom: 12px; }
.rp-lbf-card { border: 1px solid var(--border); border-radius: var(--radius-md); padding: 12px; margin-bottom: 8px; }
.rp-lbf-row { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.rp-lbf-row--between { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.rp-lbf-grow { flex: 1; min-width: 0; }
.rp-lbf-del {
  display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 28px; height: 28px; border: 0; border-radius: var(--radius-sm);
  background: transparent; color: var(--muted-foreground); cursor: pointer;
}
.rp-lbf-del:hover { background: var(--secondary); color: var(--destructive); }
.rp-lbf-add {
  display: inline-flex; align-items: center; gap: 6px; border: 0; background: transparent;
  color: var(--primary); font: inherit; font-size: 13.5px; font-weight: 500; cursor: pointer;
  padding: 6px 0; margin-bottom: 16px;
}
.rp-lbf-add:hover { text-decoration: underline; }
.rp-lbf-subtitle { font-size: 13.5px; font-weight: 600; margin: 0 0 8px; }
.rp-lbf-caption { display: block; font-size: 12px; color: var(--muted-foreground); margin: -4px 0 8px; }
.rp-lbf-item-caption { font-size: 12px; color: var(--muted-foreground); }

/* wave-9 T7 — Pages/Tests + Pages/Homework + Pages/Onboarding sweep (replaces the remaining Mud* usage
   there). rp-hws-decision--warning completes the tone set HomeworkSubmissionPage's read-only arm already
   uses (--success/--error) for HomeworkSubmissionDetail's 3-way decision banner (parent view can show a
   RevisionRequested attempt the student page never renders read-only, since it auto-enters redo instead). */
.rp-hws-decision--warning { background: var(--warning-muted); color: var(--warning-muted-foreground); }

/* rp-obp-card — the onboarding-wizard schematic block-preview card (Pages/Onboarding/Preview/*.razor),
   replacing the MudPaper Elevation="0" Class="pa-4" wrapper repeated identically across all ten
   token-styled previews (ParentsPreview keeps its own fixed dark-band inline style — not token-driven). */
.rp-obp-card { padding: 16px; border: 1px solid var(--border); border-radius: 16px; background: var(--card); }

/* rp-obp-chip — ContactsPreview's contact-channel pill (icon + value), replacing a MudIcon-in-span. */
.rp-obp-chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 6px 12px; border-radius: 999px; font-size: 12px; color: var(--foreground);
}

/* ========================================================================
   Mud utility compat (wave-9 T9, LOCKED-11) — MudBlazor.min.css left the bundle entirely this
   task (package reference + <script>/<link> tags removed), but its own bare utility classes
   (d-flex, pa-8, gap-2, ...) are still literally written into class="..." attributes across
   Cabinet.Shared's .razor markup — pages converted off Mud components in earlier wave-9 tasks
   kept these utility classes as-is rather than migrating every call site to a named rp-* class
   (see wave9-minor-backlog.md item 14). Losing MudBlazor.min.css would otherwise silently drop
   every one of these declarations and reflow dozens of pages.

   This is NOT a general-purpose utility system — it re-emits ONLY the exact classes the
   following inventory found in use at T9 time, at MudBlazor's own scale (1 spacing unit = 4px:
   pa-8 = padding 32px, mt-1 = margin-top 4px, gap-2 = gap 8px), so already-converted layouts
   stay pixel-for-pixel identical. Re-run before trusting this block stale:

     grep -rhoE 'class="[^"]*"' src/Repetitum.Cabinet.Shared --include='*.razor' \
       | grep -oE '\b(d-[a-z-]+|flex-[a-z0-9-]+|justify-[a-z-]+|align-[a-z-]+|gap-[0-9]+|[mp][atblrxy]?-[0-9]+|rounded[a-z-]*|w-100|h-100)\b' \
       | sort | uniq -c | sort -rn

   Redistributing these call sites onto named rp-* classes (removing the need for this block
   entirely) is backlog, not this task's job — see wave9-minor-backlog.md item 14. */
.d-flex { display: flex; }
.d-block { display: block; }

.flex-column { flex-direction: column; }
.flex-wrap { flex-wrap: wrap; }
.flex-grow-1 { flex-grow: 1; }

.justify-center { justify-content: center; }
.align-center { align-items: center; }
.align-start { align-items: flex-start; }

.gap-1 { gap: 4px; }
.gap-2 { gap: 8px; }
.gap-3 { gap: 12px; }
.gap-4 { gap: 16px; }

.pa-3 { padding: 12px; }
.pa-8 { padding: 32px; }
.py-4 { padding-top: 16px; padding-bottom: 16px; }

.mt-1 { margin-top: 4px; }
.mt-2 { margin-top: 8px; }
.mt-3 { margin-top: 12px; }
.mb-1 { margin-bottom: 4px; }
.mb-2 { margin-bottom: 8px; }
.mb-3 { margin-bottom: 12px; }
.mb-4 { margin-bottom: 16px; }

/* ── Wave-9 visual audit: landing block chrome collapses at phone widths ──
   The chrome row is icon + meta + Редактировать + toggle + kebab; below 640px the fixed
   controls left the meta ~90px wide (one-word lines). Wrap: meta owns the first row next
   to the icon, the actions drop to a second row aligned under the text. */
@media (max-width: 640px) {
  .rp-land-chrome { flex-wrap: wrap; }
  .rp-land-meta { flex: 1 1 calc(100% - 44px); }
  .rp-land-edit { margin-left: 44px; }
}

/* ── Portal stacking ladder (consolidated — the ONLY place portal z-indexes are set) ──
   .blazorblueprint-portal is display:contents: it generates NO box, so position/z-index on the
   wrapper itself is a silent no-op (a wave-2 `z-index: 250` rule pretended otherwise for months).
   Portal children stack DIRECTLY against the shell chrome in the body context, and their Tailwind
   z-50 loses to it — symptom: a mobile dialog's close «✕» sat under the sticky topbar and clicks
   landed on the topbar. The explicit ladder (bp.css is un-layered, Tailwind utilities are
   @layer'ed, so these win without !important):
     shell chrome: topbar 90 · bottom nav 100 · more-sheet 200/201
     → 205 portal surfaces (dropdowns/popovers/tooltips — no dropdown nests inside a dialog, and
       an open kebab must close UNDER an awaited confirm: wave-9)
     → 220 dialog backdrop → 230 dialog panel
     → 240 toast viewport (a toast fired from a dialog handler must paint above the open dialog). */
.blazorblueprint-portal > * { z-index: 205; }
.blazorblueprint-portal > .fixed.inset-0 { z-index: 220; }
.blazorblueprint-portal [role="dialog"],
.blazorblueprint-portal [role="alertdialog"] { z-index: 230; }
body > .fixed.pointer-events-none { z-index: 240; }

/* ── Dialogs taller than the viewport must scroll INSIDE the panel ──
   The Bb dialog panel is position:fixed + translate-centered with no height cap, and the open
   dialog locks body scroll (body overflow:hidden) — so on a phone a tall dialog (e.g. publish-slots
   with weekly repeat expanded: 943px vs 844px viewport) ran off BOTH edges with its submit button
   unreachable and nothing scrollable. Cap every dialog panel to the small-viewport height (dvh —
   mobile URL-bar-aware) and scroll overflow inside. This is the ONLY height/scroll rule for
   dialog panels — per-dialog rp-* classes must not duplicate it (rp-land-dlg's old 88vh copy
   was removed in its favour). */
.blazorblueprint-portal [role="dialog"],
.blazorblueprint-portal [role="alertdialog"] {
  max-height: calc(100dvh - 24px);
  overflow-y: auto;
}
