/* AI实战对练 · one fixed screen (E1), entering load screen (E2), pause (E3), voice wave (E4).
   The ONLY copy of these rules: the static prototype practice-call.html links this file and the
   app imports it from layout.tsx, so the two cannot drift. tests/practice-live.spec.cjs opens
   both side by side and compares structure, geometry and computed style state by state.
   Class names carry a pc- prefix because the app already uses generic ones (.status, .controls). */
.pc {
  --brand-500: #4C63E6;
  --brand-600: #3A50CC;
  --ink: #f4f8ff;
  --ink-2: #c5dbea;
  --ink-3: #8fb0c4;
  --line: #577485;
  --danger: #de3e42;
  --s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px; --s5: 20px; --s6: 24px; --s7: 32px; --s8: 48px;
}
.pc, .pc * { box-sizing: border-box; }
.pc button { font: inherit; color: inherit; touch-action: manipulation; cursor: pointer; }
.pc button:focus-visible { outline: 3px solid #8fa0ff; outline-offset: 4px; box-shadow: none; }
.pc svg { display: block; }

/* ---------- the one screen: exactly the viewport, never scrolls ---------- */
/* The page behind is locked only while a call screen exists; the score screen that follows is
   an ordinary page again and scrolls. */
html:has(.pc) { overflow: hidden; overscroll-behavior: none; }
.pc {
  position: fixed;
  inset: 0;
  /* above the store shell's bottom tabs: a call takes the whole phone, like a phone call */
  z-index: 40;
  display: grid;
  grid-template-rows: auto auto minmax(0, 1fr) auto auto;
  height: 100dvh;
  max-width: 520px;
  margin: 0 auto;
  padding: max(var(--s2), env(safe-area-inset-top)) var(--s5) max(var(--s4), env(safe-area-inset-bottom));
  background: radial-gradient(ellipse at 50% 24%, #174967 0%, #0a2a3f 48%, #051b29 100%);
  color: var(--ink);
  font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", "Microsoft YaHei", sans-serif;
  -webkit-tap-highlight-color: transparent;
  overflow: hidden;
  overscroll-behavior: none;
}
@media (min-width: 640px) {
  /* the column sits on a dark floor that covers whatever page is behind it */
  .pc { box-shadow: 0 0 0 1px #0f3347, 0 0 0 100vmax #031420; }
}

.pc-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 48px;
}
.pc-head h1 { margin: 0; font-size: 17px; font-weight: 600; }
.pc-ghost {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  padding: 0 var(--s2);
  border: 0;
  background: transparent;
  font-size: 14px;
}
.pc-ghost:disabled { opacity: .35; cursor: default; }
.pc[data-view="subtitles"] .pc-subs-btn { visibility: hidden; }
.pc-ghost svg { width: 20px; height: 20px; }
.pc-back svg { transform: rotate(180deg); }

/* portrait scales with the viewport HEIGHT so short phones shrink it instead of scrolling */
.pc-person { text-align: center; padding-top: var(--s2); }
.pc-avatar {
  position: relative;
  width: clamp(88px, min(42vw, 20dvh), 208px);
  aspect-ratio: 1;
  margin: 0 auto var(--s3);
  border-radius: 50%;
}
.pc-avatar i {
  position: absolute;
  inset: 0;
  border: 3px solid #a6c3d3;
  border-radius: 50%;
  background: url(/images/practice/role-portraits.jpg) left center / 300% 100% no-repeat;
  box-shadow: 0 8px 40px #00111d55;
}
/* speaking halo: a steady glow that eases in and out with the customer's turn */
.pc-avatar::before {
  content: "";
  position: absolute;
  inset: -10px;
  border-radius: 50%;
  background: radial-gradient(circle, #7acbff55 55%, transparent 72%);
  transform: scale(var(--halo, 1));
  opacity: var(--halo-o, 0);
  transition: opacity .3s, transform .3s;
}
.pc-person h2 { margin: 0; font-size: clamp(20px, 3.2dvh, 26px); }
.pc-topic { margin: var(--s1) 0 0; color: var(--ink-2); font-size: 14px; }
.pc .pc-desc {
  display: -webkit-box;
  max-width: 380px;
  margin: var(--s2) auto 0;
  overflow: hidden;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  color: var(--ink-2);
  font-size: 14px;
  line-height: 1.6;
}
.pc:not([data-state="intro"]) .pc-desc { display: none; }

.pc-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 0;
  overflow: hidden;
}
/* max-height lets the wave give way on a short phone instead of pushing the buttons off it */
.pc-wave { display: block; width: 100%; height: clamp(40px, 16dvh, 140px); max-height: 100%; }

.pc-status { min-height: 64px; text-align: center; }
.pc-status p { margin: 0; }
/* Keeps its line when empty (in-call states show no caption) so the wave never moves when a
   caption such as 已暂停 or 已静音 appears. */
.pc-say { font-size: clamp(16px, 2.4dvh, 18px); line-height: 1.5; min-height: 1.5em; }
.pc .pc-time { margin-top: var(--s1); color: var(--ink-3); font-size: 13px; font-variant-numeric: tabular-nums; }

/* ---------- entering: the wait is told as the scene (reference screenshot 3) ----------
   Every real step (mic, voice client, room, media, customer ready) moves the bar; it only
   reaches 100% once the customer is in the room, and the customer speaks right after. */
.pc-loading, .pc-queue { display: none; width: min(100%, 300px); text-align: center; }
.pc[data-state="connecting"] .pc-loading { display: block; }
.pc[data-state="queued"] .pc-queue { display: block; }
/* 排队中 (2026-10-07): the same screen as 进入加载, with the queue in place of the progress bar. */
.pc:is([data-state="connecting"], [data-state="queued"]) :is(.pc-wave, .pc-status, .pc-controls, .pc-foot, .pc-topic) { display: none; }
.pc:is([data-state="connecting"], [data-state="queued"]) .pc-stage { justify-content: flex-start; padding-top: var(--s6); }
.pc:is([data-state="connecting"], [data-state="queued"]) .pc-avatar { width: clamp(120px, min(52vw, 30dvh), 240px); margin-top: var(--s7); }
.pc .pc-queue-ahead { margin: 0 0 var(--s3); font-size: 15px; line-height: 1.4; }
.pc .pc-queue-ahead b { margin: 0 6px; font-size: 40px; font-weight: 650; line-height: 1; font-variant-numeric: tabular-nums; }
.pc .pc-scene { margin: 0 0 var(--s3); font-size: 16px; line-height: 1.5; }
.pc-bar { height: 6px; border-radius: 999px; background: #ffffff2e; overflow: hidden; }
.pc-bar i {
  display: block;
  height: 100%;
  width: calc(var(--p, 0) * 1%);
  border-radius: 999px;
  background: linear-gradient(90deg, #6f8bff, #4C63E6);
  transition: width .25s linear;
}
.pc .pc-pct { margin: var(--s2) 0 0; font-size: 14px; font-variant-numeric: tabular-nums; }
.pc .pc-step { margin: var(--s1) 0 0; color: var(--ink-3); font-size: 12px; }

/* ---------- 生成点评: recap cards and a score reveal (the "9" version, confirmed 09-25) ----------
   On the call's own dark floor with a faint aurora and a few rising motes. Cards pop in with
   counting numbers and a light sweep; the ring breathes and two dots orbit while scoring; on the
   score it fills, counts up and bursts, a verdict appears, and the recap lifts away before the
   score page opens. */
.pc-recap, .pc-fx { display: none; }
.pc[data-state="scoring"] :is(.pc-person, .pc-stage, .pc-status, .pc-controls, .pc-foot) { display: none; }
.pc[data-state="scoring"] .pc-fx {
  position: absolute;
  inset: 0;
  display: block;
  overflow: hidden;
  pointer-events: none;
}
/* aurora: two soft glows drifting slowly, clipped to the screen. Radial gradients moved by
   transform only (no blur filter): a blurred full-screen layer made the score page's own
   animation wait ~2.5 s in a test browser and would cost phones the same. */
.pc-fx::before, .pc-fx::after {
  content: "";
  position: absolute;
  width: 120%;
  height: 70%;
  border-radius: 50%;
  will-change: transform;
}
.pc-fx::before {
  top: -20%; left: -30%;
  background: radial-gradient(closest-side, #2f8fc255, transparent);
  animation: pc-glow-a 14s ease-in-out infinite alternate;
}
.pc-fx::after {
  bottom: -25%; right: -35%;
  background: radial-gradient(closest-side, #5a6fe044, transparent);
  animation: pc-glow-b 17s ease-in-out infinite alternate;
}
@keyframes pc-glow-a { to { transform: translate(25%, 30%); } }
@keyframes pc-glow-b { to { transform: translate(-25%, -35%); } }
.pc-fx i {
  position: absolute;
  bottom: -10px;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: #cfe9ff;
  box-shadow: 0 0 8px #9fd4ff;
  opacity: 0;
  animation: pc-mote 7s linear infinite;
}
.pc-fx i:nth-child(1) { left: 12%; animation-delay: 0s; }
.pc-fx i:nth-child(2) { left: 30%; animation-delay: 1.6s; animation-duration: 8s; }
.pc-fx i:nth-child(3) { left: 52%; animation-delay: 3.1s; }
.pc-fx i:nth-child(4) { left: 71%; animation-delay: .8s; animation-duration: 9s; }
.pc-fx i:nth-child(5) { left: 88%; animation-delay: 2.4s; }
.pc-fx i:nth-child(6) { left: 42%; animation-delay: 4.6s; animation-duration: 8.5s; }
@keyframes pc-mote {
  0% { opacity: 0; transform: translateY(0) scale(.6); }
  15% { opacity: .8; }
  100% { opacity: 0; transform: translateY(-105dvh) scale(1.2); }
}
.pc[data-state="scoring"] .pc-head { position: relative; z-index: 2; }

.pc[data-state="scoring"] .pc-recap {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--s5);
  min-height: 0;
  grid-row: 2 / -1;
  text-align: center;
}
.pc[data-state="scoring"].is-leaving .pc-recap { animation: pc-leave .5s ease-in both; }
@keyframes pc-leave { to { opacity: 0; transform: translateY(-24px) scale(.96); } }
.pc .pc-recap-title { margin: 0; font-size: 15px; font-weight: 600; letter-spacing: 2px; color: var(--ink-2); animation: pc-rise .4s ease-out both; }
.pc-recap-stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s3);
  width: min(100%, 340px);
  margin: 0;
  padding: 0;
  list-style: none;
}
.pc-stat {
  position: relative;
  overflow: hidden;
  padding: var(--s3) var(--s2);
  border: 1px solid #ffffff1f;
  border-radius: 16px;
  background: linear-gradient(160deg, #ffffff1a, #ffffff08);
  animation: pc-pop .5s cubic-bezier(.2, 1.5, .4, 1) both;
}
/* a light sweep crosses each card once, right after it lands */
.pc-stat::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, transparent 30%, #ffffff33 50%, transparent 70%);
  transform: translateX(-120%);
  animation: pc-sweep .9s ease-out both;
}
.pc-stat:nth-child(1), .pc-stat:nth-child(1)::after { animation-delay: .15s, .55s; }
.pc-stat:nth-child(2), .pc-stat:nth-child(2)::after { animation-delay: .35s, .75s; }
.pc-stat:nth-child(3), .pc-stat:nth-child(3)::after { animation-delay: .55s, .95s; }
.pc-stat:nth-child(4), .pc-stat:nth-child(4)::after { animation-delay: .75s, 1.15s; }
@keyframes pc-sweep { to { transform: translateX(120%); } }
.pc-stat b { display: block; font-size: clamp(22px, 3.6dvh, 28px); font-variant-numeric: tabular-nums; }
.pc-stat span { display: block; margin-top: var(--s1); color: var(--ink-2); font-size: 12px; }
@keyframes pc-pop { from { opacity: 0; transform: translateY(16px) scale(.8); } }
@keyframes pc-rise { from { opacity: 0; transform: translateY(8px); } }

.pc-ring {
  position: relative;
  width: clamp(120px, 20dvh, 168px);
  aspect-ratio: 1;
  animation: pc-pop .5s 1s cubic-bezier(.2, 1.5, .4, 1) both;
}
/* breathing glow while scoring */
.pc-ring::before {
  content: "";
  position: absolute;
  inset: 10%;
  border-radius: 50%;
  box-shadow: 0 0 40px 6px #5de0e655;
  animation: pc-breathe 2.2s ease-in-out infinite;
}
@keyframes pc-breathe { 50% { box-shadow: 0 0 60px 14px #6f8bff66; } }
.pc-ring svg { position: relative; width: 100%; height: 100%; transform: rotate(-90deg); }
.pc-ring circle { fill: none; stroke-width: 8; stroke-linecap: round; }
.pc-ring .pc-ring-track { stroke: #ffffff1a; }
.pc-ring .pc-ring-arc {
  stroke: url(#pcRingInk);
  stroke-dasharray: 80 327;
  transform-box: fill-box;
  transform-origin: center;
  animation: pc-spin 1.1s linear infinite;
}
.pc-ring.is-scored .pc-ring-arc {
  stroke-dasharray: calc(var(--score, 0) * 3.27) 327;
  animation: none;
  transition: stroke-dasharray 1.2s ease-out;
}
/* two dots orbit the ring while scoring, gone once it is scored */
.pc-ring-orbit {
  position: absolute;
  inset: -6px;
  border-radius: 50%;
  animation: pc-spin 3.2s linear infinite;
}
.pc-ring-orbit::before, .pc-ring-orbit::after {
  content: "";
  position: absolute;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #e8fbff;
  box-shadow: 0 0 10px #8fe8ff;
}
.pc-ring-orbit::before { top: 0; left: calc(50% - 4px); }
.pc-ring-orbit::after { bottom: 0; left: calc(50% - 4px); opacity: .6; }
.pc-ring.is-scored .pc-ring-orbit { opacity: 0; transition: opacity .3s; }
/* on the score: a ring of sparks flies out once */
.pc-ring-burst { position: absolute; inset: 0; pointer-events: none; }
.pc-ring-burst i {
  position: absolute;
  top: calc(50% - 3px);
  left: calc(50% - 3px);
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #fff3b0;
  opacity: 0;
  transform: rotate(var(--a)) translateY(0);
}
.pc-ring.is-scored .pc-ring-burst i { animation: pc-burst .9s .9s ease-out both; }
@keyframes pc-burst {
  0% { opacity: 1; transform: rotate(var(--a)) translateY(-40%); }
  100% { opacity: 0; transform: rotate(var(--a)) translateY(-120px) scale(.4); }
}
.pc-ring-value {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
.pc-ring-value b { font-size: clamp(30px, 5.5dvh, 42px); font-variant-numeric: tabular-nums; line-height: 1; }
.pc-ring-value span { margin-top: var(--s1); color: var(--ink-2); font-size: 12px; }
.pc .pc-recap-step { margin: 0; color: var(--ink-2); font-size: 13px; min-height: 20px; }
.pc .pc-verdict {
  margin: 0;
  padding: var(--s1) var(--s4);
  border-radius: 999px;
  background: #ffffff1f;
  font-size: 14px;
  font-weight: 600;
  opacity: 0;
}
.pc-ring.is-scored ~ .pc-verdict { animation: pc-rise .4s 1.3s ease-out both; opacity: 1; }
@keyframes pc-spin { to { transform: rotate(360deg); } }

/* ---------- controls: pinned to the bottom, three round buttons ---------- */
.pc-controls {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--s3);
  width: 100%;
  max-width: 360px;
  margin: var(--s3) auto 0;
}
.pc-ctl {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s2);
  padding: 0;
  border: 0;
  background: transparent;
  font-size: 13px;
}
.pc-ctl b {
  display: grid;
  place-items: center;
  width: clamp(56px, 8.5dvh, 68px);
  aspect-ratio: 1;
  border: 1px solid #7593a6;
  border-radius: 50%;
  background: #193a4c;
}
.pc-ctl b svg { width: 42%; height: 42%; }
.pc-ctl[aria-pressed="true"] b { background: #f4f8ff; color: #0a2a3f; border-color: #f4f8ff; }
.pc-ctl.is-end b { background: var(--danger); border-color: #fb8382; }
.pc-ctl:disabled { opacity: .4; cursor: default; }
.pc-ctl.is-start {
  grid-column: 1 / -1;
  justify-self: center;
}
.pc-ctl.is-start b {
  width: clamp(68px, 10dvh, 84px);
  background: var(--brand-500);
  border-color: #839bff;
  box-shadow: 0 6px 22px #00142666;
}
.pc .pc-foot {
  margin: var(--s3) 0 0;
  color: var(--ink-3);
  text-align: center;
  font-size: 12px;
}

/* ---------- subtitles: the only part that scrolls, inside its own box ---------- */
.pc[data-view="subtitles"] .pc-person,
.pc[data-view="subtitles"] .pc-stage,
.pc[data-view="subtitles"] .pc-status { display: none; }
.pc[data-view="subtitles"] { grid-template-rows: auto minmax(0, 1fr) auto auto; }
.pc-subs { display: none; }
.pc[data-view="subtitles"] .pc-subs {
  display: block;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  margin: 0 calc(-1 * var(--s5));
  padding: var(--s2) var(--s5);
  -webkit-overflow-scrolling: touch;
}
.pc-subs ol { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s4); }
.pc-subs li { display: flex; gap: var(--s3); align-items: flex-start; }
.pc-subs li.is-me { flex-direction: row-reverse; }
.pc-who {
  flex: none;
  width: 32px; height: 32px;
  border-radius: 50%;
  background: url(/images/practice/role-portraits.jpg) left center / 300% 100% no-repeat;
}
.pc-subs li.is-me .pc-who { display: grid; place-items: center; background: #385af4; font-size: 12px; }
.pc-subs p {
  margin: 0;
  max-width: 78%;
  padding: var(--s2) var(--s3);
  border-radius: 14px;
  background: #173747;
  font-size: 15px;
  line-height: 1.55;
}
.pc-subs li.is-me p { background: #2d47c9; }
.pc-subs li.is-live p { opacity: .75; }
.pc-mini {
  display: none;
  align-items: center;
  gap: var(--s3);
  padding-top: var(--s3);
  border-top: 1px solid #16394b;
}
.pc[data-view="subtitles"] .pc-mini { display: flex; }
.pc[data-view="subtitles"] .pc-controls { display: none; }
.pc-mini .pc-wave { flex: 1; height: 40px; }
.pc-mini .pc-ctl b { width: 48px; }

@media (prefers-reduced-motion: reduce) {
  .pc-avatar::before { transition: none; }
  .pc-stat, .pc-stat::after, .pc-ring, .pc-ring::before, .pc-fx::before, .pc-fx::after, .pc-fx i,
  .pc-recap-title { animation: none; }
  .pc-ring .pc-ring-arc, .pc-ring-orbit { animation-duration: 3s; }
}
