/*
 * PulseVeter unified component rules.
 *
 * New home for consolidated component CSS as Phase 2 (visual consolidation,
 * see artifacts/claude-audit/FULL_REMEDIATION_AND_REDESIGN_PLAN_2026-08-17.md
 * section 3.5) moves components out of the 7-file legacy bundle chain.
 * Loaded right after pulseveter_tokens.css and before the legacy bundle
 * (pulseveter_webapp.bundle.css / pulseveter_miniapp.bundle.css), so rules
 * here need enough specificity/!important to win against the legacy chain
 * where they intentionally override it -- this file does not rely on load
 * order alone.
 *
 * Existing legacy .chip rules in the 7 source files are intentionally left
 * in place (not deleted) until the full unified base is verified and the
 * legacy rules are retired in a separate follow-up task -- see
 * artifacts/claude-audit/COMPONENT_CONTRACT_CHIP.md.
 */

/*
 * .chip -- selected-state visibility fix for the "sound" wizard step.
 *
 * Contract: artifacts/claude-audit/COMPONENT_CONTRACT_CHIP.md, section 5,
 * option A (owner decision 2026-08-19).
 *
 * Confirmed via getComputedStyle on a local server: on
 * body[data-studio-step="sound"], pulseveter_v3_art.css:1322-1331
 * ("body[data-studio-step="sound"] .pv3-reference .chips:not([data-target="mood"])
 * .chip", !important, no @media gating) resets border-color/background/
 * box-shadow identically whether or not the chip has .is-active -- so
 * selecting a genre/topic/style/tempo/language/instrument chip on the
 * create-track screen gave zero visual feedback. Only the mood chip group
 * had a working selected state at this step (a dedicated, narrower
 * exception rule already existed for [data-target="mood"] .chip.is-active).
 *
 * Fix: an .is-active override using the exact same selector context as the
 * flattening rule (same specificity contributors, plus the .is-active
 * class) so it wins purely on specificity regardless of file load order,
 * scoped to the same body[data-studio-step="sound"] state so it cannot
 * affect any other step. Deliberately reuses the identical visual language
 * already live and working for the mood group's selected state (border +
 * glow) rather than introducing a new style -- --pv5-cyan is the existing
 * token for the matching shadow layers; the brighter border cyan
 * (rgba(91, 225, 255, .98)) has no equivalent token yet and is copied
 * verbatim from the mood rule (pulseveter_v4_unified.css:1541-1548) so the
 * two groups look consistent with each other. The box-shadow's first two
 * layers are the literal rgba() values --pv5-cyan (#2acbff) expands to at
 * .12/.38 alpha -- written out directly rather than through color-mix(),
 * since var(--pv5-cyan) alone can't express a translucent alpha of a hex
 * token without an extra indirection this file doesn't need to introduce.
 */
body[data-studio-step="sound"] .pv3-reference .chips:not([data-target="mood"]) .chip.is-active,
body[data-studio-step="sound"] .pv3-reference .chip-row:not([data-target="mood"]) .chip.is-active {
  z-index: 2 !important;
  border: 3px solid rgba(91, 225, 255, .98) !important;
  box-shadow:
    0 0 0 4px rgba(42, 203, 255, .12),
    0 0 42px rgba(42, 203, 255, .38),
    0 22px 52px rgba(0, 0, 0, .22) !important;
}

/*
 * Profile / Help utility panels (#studio-help-panel, #studio-profile-panel)
 * -- pure tokenization pass, section 3.1 item 2 / section 3.5 of the plan,
 * "least risky screens first". Unlike the .chip fix above, this is NOT a
 * bug fix: getComputedStyle on a local server (before this rule existed)
 * and after adding it must produce IDENTICAL values -- confirmed by hand
 * for both panels before writing this rule.
 *
 * Provenance of every property below, traced the same way as the .chip
 * investigation (live getComputedStyle first, then grep for the exact
 * literal to find which file actually wins):
 *   - background, border-color, border-radius: currently won by
 *     pulseveter_v2.css:390-393 ("body.studio-wizard-enabled
 *     .studio-utility-panel, ...", !important). background/border-color
 *     already reference --pv2-panel/--pv2-line, defined once in
 *     pulseveter_v2.css's own :root (no competing redefinition anywhere
 *     in the 7-file chain, confirmed by grep) -- reused verbatim here via
 *     var(), not duplicated as new tokens, since CSS custom properties
 *     resolve at paint time regardless of which stylesheet references
 *     them vs which one declares them.
 *   - border-radius (30px) has no existing match in pulseveter_tokens.css
 *     (--radius-xl/-lg/-md are 34/28/20px) -- written as a literal rather
 *     than inventing a new token for a single-use value, consistent with
 *     "don't invent tokens without necessity".
 *   - box-shadow: currently won by miniapp.css:646-653 (same selector
 *     family, no !important but higher specificity than the base .card
 *     rule it sits on top of). No existing token matches this exact
 *     shadow (--shadow-xl is 0 34px 100px/.48, --shadow-card is
 *     0 20px 56px/.28, neither equals 0 26px 86px/.36) -- literal, same
 *     reasoning as border-radius.
 *   - padding (24px): currently won by miniapp.css:3739-3743
 *     (".studio-utility-panel", no !important, nothing else overrides
 *     it) -- no dedicated spacing token exists in pulseveter_tokens.css
 *     to reuse, literal.
 *   - text color inside both panels already comes from the global
 *     "html body.pv2-exact, ... .pv3-reference { color: var(--pv5-text)
 *     !important; }" rule (pulseveter_v4_unified.css:418-424) -- already
 *     tokenized and inherited, not panel-specific, so not duplicated here.
 *
 * Scoped to the two panel IDs only (not the shared .studio-utility-panel
 * class) so this does not touch the drafts/billing utility panels at the
 * time this rule was written -- #billing-panel and #studio-max-billing-panel
 * were added in a later, separate pass below once verified (see that rule's
 * own comment for why padding is deliberately NOT included there).
 */
#studio-help-panel,
#studio-profile-panel {
  background: var(--pv2-panel) !important;
  border-color: var(--pv2-line) !important;
  border-radius: 30px !important;
  box-shadow: 0 26px 86px rgba(0, 0, 0, .36) !important;
  padding: 24px !important;
}

/*
 * Billing panel container (#billing-panel web host, #studio-max-billing-panel
 * MAX mini-app host) -- Phase 2 step 6 continued, Billing/Tracks screens.
 *
 * Both share the .studio-utility-panel class with Help/Profile, and live
 * verification confirmed background/border-color/border-radius/box-shadow
 * are won by the exact same rules as Help/Profile (pulseveter_v2.css:390-393
 * !important for background/border-color/border-radius; miniapp.css:646-653
 * for box-shadow) -- so the same four properties/tokens apply here.
 *
 * padding is deliberately NOT included, unlike Help/Profile: #billing-panel
 * has its own higher-specificity rule, ".page--web .billing-panel { padding:
 * clamp(20px, 2.6vw, 30px); ... }" (webapp.css:1864-1868), which is a real,
 * intentional responsive rule (confirmed live at 1280px -> 30px, would
 * shrink toward 20px on narrower viewports). Forcing a flat "padding: 24px
 * !important" here would silently break that responsiveness -- a real
 * visual regression, not a token-parity improvement. #studio-max-billing-panel
 * (no .billing-panel class, no .page--web ancestor on the MAX host) was NOT
 * reachable live in this environment (requires MAX host detection this
 * local server can't simulate) to confirm whether it shares that same
 * clamp() rule or falls back to the plain 24px like Help/Profile -- since
 * it's unverified, its padding is left untouched here too rather than
 * guessed at.
 *
 * .billing-card / .pv3-plan (the actual tariff cards inside #billing-plans)
 * and .track-card (inside #tracks-list) are explicitly OUT of scope for
 * this rule -- see the note further down this file for why.
 */
#billing-panel,
#studio-max-billing-panel {
  background: var(--pv2-panel) !important;
  border-color: var(--pv2-line) !important;
  border-radius: 30px !important;
  box-shadow: 0 26px 86px rgba(0, 0, 0, .36) !important;
}

/*
 * .track-card and the tariff cards (.billing-card / .pv3-plan) inside
 * #billing-plans -- investigated, NOT tokenized in this pass, stopping per
 * the same procedure as the .chip finding (document and wait rather than
 * guess a visual decision or verify something that can't actually be
 * verified live).
 *
 * Two separate reasons:
 *
 * 1. .billing-card / .pv3-plan never rendered in this environment: the
 *    balance/plans fetch on #billing-panel stayed stuck on "Проверяем
 *    доступные генерации..." with zero network requests recorded (the
 *    fetch is gated client-side behind an authenticated session that
 *    doesn't exist here, same as the Profile panel in the previous task).
 *    Writing a token override for markup that has never actually been
 *    seen rendered would be exactly the kind of unverified guess this
 *    project's methodology explicitly rules out.
 *
 * 2. .track-card has genuinely conflicting !important declarations across
 *    3 files with no single obvious winner:
 *      - pulseveter_v2_reference.css:730-734 (.pv3-reference .track-card):
 *        border-radius 18px, background rgba(4, 18, 31, .72)
 *      - pulseveter_v3_art.css:414 (.pv3-reference .track-card, identical
 *        specificity, later in bundle order so it wins for radius/color):
 *        border-radius 14px, background linear-gradient(145deg, ...)
 *      - pulseveter_v4_unified.css:1746-1757 (.pv3-reference .pv2-library
 *        .track-card, higher specificity, wins for background only):
 *        background rgba(2, 13, 23, .22) -- confirmed live, this is what
 *        actually renders for the empty-state placeholder card.
 *      - The same v4_unified.css block also lists #billing-panel
 *        .billing-card, #studio-help-panel .studio-help-note, and others
 *        under a ".pv3-force-utility" conditional class that was NOT
 *        active during live verification (.studio-help-note rendered its
 *        normal gradient, not this flat color) -- nothing in the traced
 *        JS/CSS was found that ever toggles .pv3-force-utility on, so
 *        whether it's a live feature flag or dead code is unresolved.
 *    Given real track cards were never actually observed (only the
 *    logged-out placeholder), and the winning rule for the placeholder
 *    already differs across three files for reasons not fully understood,
 *    writing an override here risks guessing at a component whose true
 *    live appearance (for a logged-in user with real tracks) hasn't been
 *    confirmed at all.
 */

/*
 * .studio-stepper -- "done" state fix (owner decision 2026-08-19: this is a
 * bug, not a design intent -- same procedure as the .chip finding, fix it).
 *
 * Confirmed live across 3 wizard steps (story -> sound -> voice, 1/2/3
 * completed steps respectively): a "done" (already-completed) step and an
 * "upcoming" (not-yet-reached) step render with byte-identical
 * getComputedStyle on .studio-stepper__index -- same border, background,
 * box-shadow, and the .studio-stepper__text label color/weight also don't
 * differ. Only "active" (the current step) is visually distinct. So a user
 * cannot tell "I already finished step 1" apart from "step 3 is still
 * ahead" by looking at the stepper -- only "where am I now" is visible.
 *
 * This has the same shape as the .chip bug: there IS a specific, intended
 * "done" treatment in the code --
 *   body.studio-wizard-enabled .studio-stepper__item.is-done .studio-stepper__index
 *   { border-color: rgba(99, 224, 200, .72); color: #8df7db; }
 *   (pulseveter_v2.css:145-148 -- a mint/green accent, distinct from both
 *   the neutral default and the cyan "active" treatment)
 * -- but it never renders, because a later, blunter rule resets every
 * .studio-stepper__index unconditionally with !important and only carves
 * out an exception for .is-active, not .is-done:
 *   .pv3-reference .studio-stepper__index
 *   { border: 1px solid rgba(151,224,255,.26) !important; color:
 *   rgba(230,246,252,.72) !important; background: rgba(2,10,19,.78)
 *   !important; box-shadow: 0 0 0 4px rgba(1,7,14,.28) !important; }
 *   (pulseveter_v3_art.css:362-367)
 * The v2.css rule has higher selector specificity (body + 3 classes vs 2
 * classes) but no !important, so it loses outright regardless of file
 * order -- the same "forgot !important on the specific rule, a later blunt
 * !important reset clobbers it" pattern as the .chip regression.
 *
 * Fix: an .is-done override using the same selector-context trick as the
 * .chip fix -- add .studio-stepper__item.is-done on top of the exact
 * context the flattening rule uses (.pv3-reference ... .studio-stepper__index),
 * so it wins purely on specificity (0,4,0 vs the flattening rule's 0,2,0)
 * regardless of file load order, plus !important since the flattening rule
 * has it too. Only overrides border-color and color, exactly like the
 * original v2.css rule did -- border width/style and background stay from
 * the flattening rule untouched, so nothing else about the circle changes.
 *
 * Color check before reusing anything: pulseveter_tokens.css has a
 * --success token (#7ce8b4) that's in the same mint/green family, but it's
 * a visibly different hue balance from the specific rgba(99, 224, 200, .72)
 * border / #8df7db text pulseveter_v2.css:145-148 actually specifies --
 * "close" is not "matching", and the instruction was to restore the
 * existing intended style, not substitute an adjacent one. Used the exact
 * original literals instead of --success.
 */
.pv3-reference .studio-stepper__item.is-done .studio-stepper__index {
  border-color: rgba(99, 224, 200, .72) !important;
  color: #8df7db !important;
}

/*
 * Wizard navigation buttons (.studio-wizard-actions primary/secondary/ghost)
 * -- pure tokenization, no bug found here (unlike the stepper above).
 *
 * Verified live across story/sound/voice steps (all render identically to
 * each other; the wizard-actions bar itself is hidden entirely on the
 * "start" step via a separate rule, pulseveter_v2_reference.css:197, so
 * "start" was not a relevant comparison point).
 *
 * Provenance:
 *   - Primary button: the general "One button hierarchy everywhere"
 *     treatment (pulseveter_v4_unified.css:1784-1791, bright cyan gradient)
 *     is NOT what actually renders -- a higher-specificity, deliberately
 *     "quieter" override wins on every step except "start":
 *     "body:not([data-studio-step="start"]) .pv3-reference .pv2-studio
 *     .studio-wizard-actions__primary, ...primary-button { border: 1px
 *     solid rgba(79, 211, 255, .46) !important; color: rgba(238, 249, 253,
 *     .9) !important; background: linear-gradient(180deg, rgba(6, 31, 48,
 *     .72), rgba(2, 15, 26, .7)) !important; box-shadow: inset 0 1px
 *     rgba(255,255,255,.03), 0 0 26px rgba(26, 179, 230, .1) !important; }"
 *     (pulseveter_v3_art.css:624-629, its own comment reads "Studio
 *     refinement: keep the approved start scene, quieten every later
 *     step" -- confirmed intentional, not a bug). No matching token exists
 *     for these exact values, kept as literals.
 *   - Secondary/ghost buttons: pulseveter_v4_unified.css:1804-1812 ("One
 *     button hierarchy everywhere" section) is what actually wins here
 *     (no step-conditional override exists for the classes actually
 *     rendered -- .studio-wizard-actions__back is dead markup, never
 *     generated by pulseveter_studio_wizard.js, which only emits
 *     __secondary/__clear/__ghost/__primary). Its border already
 *     references var(--pv5-line) -- reused verbatim. background/color have
 *     no matching token, kept as literals.
 *   - min-height (44px) / border-radius (999px):
 *     pulseveter_v4_unified.css:1793-1796, unconditional, no per-component
 *     token exists for either (999px pill radius is a literal used
 *     throughout the codebase, not a named token) -- literals.
 *
 * This file (pulseveter_components.css) is CSS-only and does not touch
 * pulseveter_studio_wizard.js -- that file is under the owner's no-rewrite
 * caution and this task doesn't need to change it.
 */
body:not([data-studio-step="start"]) .pv3-reference .pv2-studio .studio-wizard-actions__primary,
body:not([data-studio-step="start"]) .pv3-reference .pv2-studio .primary-button {
  border: 1px solid rgba(79, 211, 255, .46) !important;
  color: rgba(238, 249, 253, .9) !important;
  background: linear-gradient(180deg, rgba(6, 31, 48, .72), rgba(2, 15, 26, .7)) !important;
  box-shadow: inset 0 1px rgba(255, 255, 255, .03), 0 0 26px rgba(26, 179, 230, .1) !important;
}

.pv3-reference .secondary-button,
.pv3-reference .ghost-button {
  border: 1px solid var(--pv5-line) !important;
  color: rgba(232, 245, 250, .74) !important;
  background: rgba(2, 13, 23, .18) !important;
  box-shadow: none !important;
}

.pv3-reference .studio-wizard-actions button {
  min-height: 44px !important;
  border-radius: 999px !important;
}

/*
 * Custom-voice verification step ordering -- real user report to the owner:
 * "нажатие «Записать фразу» запускает этап ПРОВЕРОЧНОЙ записи, хотя должен
 * запускаться только после записи ОБРАЗЦА голоса", plus the sample-record
 * button (the "кружок в центре") not reading as the primary/first action.
 *
 * Traced live (getComputedStyle on a local server, "Свой голос" voice mode):
 *
 * 1. CONFIRMED BUG: pulseveter_v3_art.css:1975-1988 (repeated with size
 *    tweaks in pulseveter_v4_unified.css) targets
 *    "...#custom_voice_verify_actions" by ID alone, !important, with no
 *    ".hidden" in the selector -- so it forces display:flex unconditionally,
 *    completely ignoring the .hidden class that
 *    startVoiceFromFile()/verifyCustomVoiceFromFile() (webapp.js/miniapp.js)
 *    toggle to gate this exact container. Confirmed live: #custom_voice_verify_actions
 *    has class "actions-row hidden" in the DOM (JS did its job correctly)
 *    but getComputedStyle showed display:flex and the buttons were
 *    genuinely clickable -- before any sample was ever recorded. This is
 *    the actual mechanism behind the reported bug, not a JS logic error.
 *
 * 2. #record-custom-voice (the real "record sample" button, step 1) is
 *    intentionally rendered as a 56px circle with color:transparent and a
 *    "■" glyph via ::after (pulseveter_v2_reference.css:565-582) -- the
 *    button's real text ("Записать свой голос") is still in the DOM
 *    (confirmed live), just visually invisible, which is why it doesn't
 *    read as the primary action.
 *
 * 3. The existing instructional paragraph that already explains the
 *    two-step order in the user's own words --
 *    "Сначала запишите или загрузите чистый образец своего голоса. После
 *    этого сервис покажет проверочную фразу, её нужно будет записать
 *    вторым шагом." (webapp.html/miniapp.html, #custom-voice-panel > .muted)
 *    -- is hidden by pulseveter_v2_reference.css:544-547
 *    ("#custom-voice-panel > .muted { display: none !important; }"),
 *    confirmed live (offsetParent null).
 *
 * Fix scope, chosen as the minimal restore-what-exists option rather than
 * the fuller "single button that changes text + step counter" redesign the
 * owner also suggested as an acceptable direction -- flagged as an open
 * alternative in the commit message, not implemented here:
 *   (a) make #custom_voice_verify_actions actually respect .hidden again
 *       (fixes the real premature-click bug -- not a visual choice, a
 *       functional correction).
 *   (b) restore the existing guidance paragraph's visibility, and move it
 *       ahead of the record/upload buttons via CSS `order` (the parent
 *       .field is display:grid, so `order` applies) so a user reads
 *       "record the sample first" before deciding what to click -- reusing
 *       the text that was already written for exactly this purpose, not
 *       inventing new copy or a new component.
 */
html body.pv2-exact.studio-wizard-enabled[data-studio-step="voice"] .pv3-reference #custom_voice_verify_actions.hidden {
  display: none !important;
}

html body.pv2-exact.studio-wizard-enabled[data-studio-step="voice"] .pv3-reference #custom-voice-panel > .muted:not(.custom-voice-record-hint) {
  display: block !important;
  order: -1 !important;
  margin: 0 0 10px !important;
  color: rgba(232, 245, 250, .74) !important;
  font-size: 13px !important;
}

/*
 * "не каждый поймет что надо нажать на кружок" -- owner follow-up after
 * seeing the fix above live. Investigated why #record-custom-voice uses
 * color:transparent before touching it (pulseveter_v2_reference.css:565-582):
 * no aria-label is set anywhere on the button (checked webapp.html,
 * miniapp.html, pulseveter_v2_reference.js) and no icon/SVG stands in for
 * the hidden text -- only a generic "■" glyph from ::after and the circular
 * shape/glow itself. Screen readers are unaffected (the real button text,
 * "Записать свой голос", is still in the DOM, just visually transparent),
 * so this reads as a deliberate minimalist icon-button treatment, not a
 * forgotten label -- but it demonstrably fails for sighted first-time users
 * per the owner's report.
 *
 * Chose option (b) from the owner's two suggestions (add a short caption)
 * over option (a) (restore the button's own text color): the button is
 * only 56-64px with overflow:hidden and no font-size/white-space handling
 * for its text, so simply un-hiding "Записать свой голос" at default size
 * would very likely clip mid-word inside the circle -- a real visual risk,
 * not a safe restore-only fix like the .muted paragraph above. A short
 * caption below the button avoids guessing at in-circle typography.
 *
 * Default-hidden everywhere (see the plain .custom-voice-record-hint rule
 * near the top of this file's non-scoped rules -- actually declared right
 * below, since only this scoped context has a circle button to explain);
 * only shown where the circle transform is actually active, so the text
 * ("Нажмите на кружок выше...") stays accurate -- in the base (non
 * pv3-reference) skin the button already shows its own visible label, so
 * this caption would be redundant there and stays hidden.
 */
.custom-voice-record-hint {
  display: none;
}

html body.pv2-exact.studio-wizard-enabled[data-studio-step="voice"] .pv3-reference #custom-voice-panel > .muted.custom-voice-record-hint {
  display: block !important;
  margin: 8px 0 0 !important;
  text-align: center !important;
  font-size: 12px !important;
  color: rgba(232, 245, 250, .6) !important;
}

/*
 * Follow-up owner request after seeing the caption fix live: make the
 * circle itself red (the universal "record" association, like a
 * camcorder/dictaphone) with a short label directly on the button
 * ("Начать запись") instead of only explaining it via the caption below.
 * The caption (.custom-voice-record-hint, immediately above) stays as
 * additional detail -- this doesn't replace it.
 *
 * Uses --danger (#ff8a8a, pulseveter_tokens.css) verbatim -- the only
 * red-family token that exists, no new color invented.
 *
 * Button text changed from "Записать свой голос" to the shorter "Начать
 * запись" directly in webapp.html/miniapp.html (not just a CSS ::after
 * swap) so the accessible name and the visible label are the same string
 * -- translated via the same EXACT_TEXT mechanism as everything else this
 * session. The old ::after "■" glyph is removed (content: none) since the
 * real text now serves that purpose; overflow stays hidden as a safety
 * net, but confirmed live at 56px (the width/height this button actually
 * computes to, per pulseveter_v4_unified.css:1627-1631 -- the "up to 64px"
 * from pulseveter_v2_reference.css never actually applies, that rule is
 * always beaten by the more specific 56px one) that "Начать запись" wraps
 * onto two lines and fits without clipping at the font-size below.
 */
html body.pv2-exact.studio-wizard-enabled[data-studio-step="voice"] .pv3-reference #record-custom-voice {
  color: #2a0a0a !important;
  background: var(--danger) !important;
  border-color: var(--danger) !important;
  box-shadow: 0 0 0 5px rgba(255, 138, 138, .16), 0 0 22px rgba(255, 138, 138, .38) !important;
  white-space: normal !important;
  line-height: 1.08 !important;
  font-size: 10px !important;
  font-weight: 800 !important;
  letter-spacing: 0 !important;
  text-align: center !important;
  padding: 4px !important;
}

html body.pv2-exact.studio-wizard-enabled[data-studio-step="voice"] .pv3-reference #record-custom-voice::after {
  content: none !important;
}
/* Track revisions are shared by Web App, Telegram and MAX. */
.track-revision-modal {
  position: fixed;
  inset: 0;
  /* The v2 shell and shared mini-player use 1000 and 13000 respectively. */
  z-index: 14000;
  display: grid;
  place-items: center;
  padding: max(16px, env(safe-area-inset-top)) 16px max(16px, env(safe-area-inset-bottom));
}

.track-revision-modal.hidden { display: none !important; }

.track-revision-modal__backdrop {
  position: absolute;
  inset: 0;
  border: 0;
  background: rgba(0, 9, 18, .78);
}

.track-revision-modal__panel {
  position: relative;
  width: min(720px, 100%);
  max-height: min(88dvh, 860px);
  overflow: auto;
  overscroll-behavior: contain;
  padding: clamp(22px, 4vw, 40px);
  border: 1px solid rgba(79, 211, 255, .3);
  border-radius: 28px;
  color: var(--text, #effaff);
  background: linear-gradient(150deg, rgba(5, 35, 52, .98), rgba(0, 13, 26, .98));
  box-shadow: 0 30px 90px rgba(0, 0, 0, .55), inset 0 1px rgba(255, 255, 255, .06);
}

.track-revision-modal__close {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 44px;
  height: 44px;
  border: 1px solid rgba(103, 216, 255, .25);
  border-radius: 50%;
  color: #dff8ff;
  background: rgba(0, 18, 31, .72);
  font-size: 26px;
  cursor: pointer;
}

.track-revision-modal__header { padding-right: 42px; }
.track-revision-modal__header h2 { margin: 5px 0 10px; font-size: clamp(30px, 5vw, 50px); }
.track-revision-modal__header p:last-child { color: var(--muted, #a9bec9); line-height: 1.55; }
.track-revision-loading {
  display: flex;
  min-height: 240px;
  align-items: center;
  justify-content: center;
  gap: 16px;
  color: #e7f9ff;
  text-align: center;
}
.track-revision-loading__spinner {
  width: 30px;
  height: 30px;
  flex: 0 0 30px;
  border: 2px solid rgba(84, 215, 255, .24);
  border-top-color: #54d7ff;
  border-radius: 50%;
  animation: pv-revision-spin .8s linear infinite;
}
@keyframes pv-revision-spin { to { transform: rotate(360deg); } }
.track-revision-form { display: grid; gap: 18px; margin-top: 24px; }
.track-revision-form [data-revision-fields][hidden] { display: none !important; }

.track-revision-form .field { display: grid; gap: 8px; }
.track-revision-form .field > span { color: #bfeffc; font-size: 13px; letter-spacing: .06em; }
.track-revision-form input,
.track-revision-form select,
.track-revision-form textarea {
  width: 100%;
  box-sizing: border-box;
  min-height: 48px;
  border: 1px solid rgba(79, 211, 255, .24);
  border-radius: 15px;
  padding: 13px 15px;
  color: #f1fbff;
  background: rgba(0, 10, 20, .64);
  font: inherit;
}
.track-revision-form textarea { resize: vertical; line-height: 1.5; }
.track-revision-form input:focus-visible,
.track-revision-form select:focus-visible,
.track-revision-form textarea:focus-visible { outline: 2px solid #35cdf7; outline-offset: 2px; }

.track-revision-modes { display: grid; grid-template-columns: repeat(3, 1fr); gap: 9px; border: 0; padding: 0; margin: 0; }
.track-revision-modes > button {
  display: grid;
  min-height: 62px;
  place-items: center;
  padding: 10px;
  border: 1px solid rgba(79, 211, 255, .22);
  border-radius: 17px;
  color: var(--muted, #a9bec9);
  text-align: center;
  background: rgba(0, 18, 32, .62);
  font: inherit;
  cursor: pointer;
}
.track-revision-modes > button[aria-pressed="true"] { border-color: #41d6ff; color: #f5fdff; background: rgba(20, 142, 180, .28); box-shadow: inset 0 0 24px rgba(48, 205, 247, .1); }
.track-revision-time-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.track-revision-line-picker { display: grid; gap: 8px; }
.track-revision-line-picker > strong { color: #d8f6ff; font-size: 15px; }
.track-revision-line-picker > p { margin: 0; color: var(--muted, #9ab0bb); line-height: 1.45; }
.track-revision-lines { display: grid; gap: 7px; max-height: 260px; overflow-y: auto; padding: 5px 4px 5px 0; scrollbar-width: thin; }
.track-revision-lines > button { width: 100%; min-height: 44px; padding: 10px 13px; border: 1px solid rgba(100, 202, 232, .2); border-radius: 13px; color: #dcebf0; background: rgba(0, 15, 27, .54); text-align: left; line-height: 1.4; cursor: pointer; }
.track-revision-lines > button[aria-pressed="true"] { border-color: #48d8ff; color: #fff; background: rgba(20, 142, 180, .3); box-shadow: inset 0 0 22px rgba(48, 205, 247, .1), 0 0 18px rgba(48, 205, 247, .1); }
.track-revision-lines > button[data-edited="true"] { border-color: rgba(111, 229, 176, .75); color: #effff8; background: rgba(22, 117, 83, .28); }
.track-revision-lines > button[data-edited="true"]::after { content: " ✓"; color: #87f0be; font-weight: 700; }
.track-revision-lines > button[data-edited="true"][aria-pressed="true"] { border-color: #54e8ff; background: linear-gradient(135deg, rgba(20, 142, 180, .34), rgba(22, 117, 83, .3)); }
.track-revision-lines__status { margin: 0; padding: 14px; border: 1px dashed rgba(100, 202, 232, .2); border-radius: 13px; color: var(--muted, #9ab0bb); }
.track-revision-lines__status--error { border-color: rgba(216, 184, 106, .35); color: #e4d4aa; }
.track-revision-manual { border-top: 1px solid rgba(100, 202, 232, .15); padding-top: 12px; }
.track-revision-manual > summary { color: #9edced; cursor: pointer; }
.track-revision-manual[open] > summary { margin-bottom: 14px; }
.track-revision-manual[open] { display: grid; gap: 14px; }
.track-revision-presets { display: flex; flex-wrap: wrap; gap: 8px; }
.track-revision-preset {
  min-height: 38px;
  padding: 8px 13px;
  border: 1px solid rgba(92, 203, 236, .28);
  border-radius: 999px;
  color: #c7dbe4;
  background: rgba(2, 26, 41, .66);
  cursor: pointer;
}
.track-revision-preset[aria-pressed="true"] { border-color: #45d6ff; color: #fff; background: rgba(20, 142, 180, .3); box-shadow: 0 0 18px rgba(40, 198, 240, .14); }
.track-revision-help { display: grid; gap: 10px; margin-bottom: 14px; }
.track-revision-help__trigger {
  display: inline-flex;
  width: fit-content;
  min-height: 44px;
  align-items: center;
  gap: 9px;
  padding: 7px 13px 7px 8px;
  border: 1px solid rgba(79, 211, 255, .28);
  border-radius: 999px;
  color: #cdeef7;
  background: rgba(3, 30, 45, .72);
  font: inherit;
  cursor: pointer;
}
.track-revision-help__trigger > span:first-child {
  display: grid;
  width: 28px;
  height: 28px;
  place-items: center;
  border: 1px solid rgba(73, 215, 255, .48);
  border-radius: 50%;
  color: #75e4ff;
  font-weight: 700;
}
.track-revision-help__trigger[aria-expanded="true"] { border-color: #45d6ff; color: #fff; background: rgba(20, 142, 180, .24); }
.track-revision-help__panel {
  padding: 15px 16px;
  border: 1px solid rgba(79, 211, 255, .2);
  border-radius: 16px;
  color: #c5d7df;
  background: rgba(0, 13, 25, .58);
  line-height: 1.5;
}
.track-revision-help__panel[hidden] { display: none !important; }
.track-revision-help__panel strong { display: block; margin-bottom: 6px; color: #effbff; }
.track-revision-help__panel p { margin: 0; }
.track-revision-warning { margin: 0; padding: 14px 16px; border-left: 2px solid #d8b86a; color: #d7dce0; background: rgba(210, 173, 83, .08); line-height: 1.45; }
.track-revision-error { margin: 0; padding: 12px 14px; border: 1px solid rgba(255, 111, 111, .55); border-radius: 14px; color: #ffd4d4; background: rgba(102, 16, 25, .42); line-height: 1.45; }
.track-revision-error[hidden] { display: none !important; }
.track-revision-actions { display: flex; justify-content: flex-end; gap: 10px; }
.track-revision-action { min-width: 210px; }
body.track-revision-open { overflow: hidden; }

@media (max-width: 620px) {
  .track-revision-modal { align-items: end; padding: 0; }
  .track-revision-modal__panel { width: 100%; max-height: calc(100dvh - env(safe-area-inset-top)); border-radius: 26px 26px 0 0; padding: 24px 18px max(22px, env(safe-area-inset-bottom)); }
  .track-revision-modes { grid-template-columns: 1fr; }
  .track-revision-modes > button { min-height: 48px; }
  .track-revision-help__trigger { width: 100%; justify-content: flex-start; }
  .track-revision-help__panel { font-size: 14px; }
  .track-revision-actions { position: sticky; bottom: 0; padding-top: 12px; background: linear-gradient(transparent, #00101d 30%); }
  .track-revision-actions > * { flex: 1; }
}

@media (prefers-reduced-motion: no-preference) {
  .track-revision-modal:not(.hidden) .track-revision-modal__backdrop { animation: pv-revision-fade .22s ease-out both; }
  .track-revision-modal:not(.hidden) .track-revision-modal__panel { animation: pv-revision-rise .36s cubic-bezier(.16, 1, .3, 1) both; }
  @keyframes pv-revision-fade { from { opacity: 0; } }
  @keyframes pv-revision-rise { from { opacity: 0; transform: translateY(20px) scale(.985); } }
}

@media (prefers-reduced-motion: reduce) {
  .track-revision-loading__spinner { animation-duration: 1.8s; }
}
