/* =====================================================================
   Voice mirror and the voice time capsule (docs/plan/2026-10-05-signature-feature.md, leo approved 2026-10-04).
   Looks only: the recording and the loudness numbers come from the research room's code. Two outlines of loudness over time, the course voice above the learner's, on one time axis.
   No score and no colour that means right or wrong: the course is blue, the learner violet, both on a lightness scale.
   Markup: js/voice-art.js (window.PolyVoiceArt). Built on css/ui-kit.css tokens; looks-only rules sit in :where(html:not(.a11y-contrast)).
   ===================================================================== */

/* ---------- 1. The mirror: two strips, one above the other (side by side is too narrow on a phone) ---------- */
.vm { display: grid; gap: var(--sp-3); margin: var(--sp-4) 0; }
.vm-track { --vm: var(--info); display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "label play" "art art"; align-items: center; gap: var(--sp-1) var(--sp-3); }
.vm-track.vm-me { --vm: var(--accent-2); }
.vm-label { grid-area: label; margin: 0; font: 600 var(--fs-sm)/1.3 var(--font-body); }
.vm-play { grid-area: play; display: inline-flex; align-items: center; gap: 6px; min-height: 44px; min-width: 44px; padding: 0 14px; margin: 0;
  border-radius: 999px; font: 600 var(--fs-sm)/1 var(--font-body); color: var(--ink); cursor: pointer; }
.vm-play svg { width: 16px; height: 16px; fill: currentColor; }
.vm-play:disabled { cursor: default; opacity: .45; }
.vm-art { grid-area: art; position: relative; height: 96px; border-radius: var(--r); overflow: hidden; }
/* sound runs left to right in every interface, Hebrew and Arabic too */
.vm-svg { display: block; width: 100%; height: 100%; direction: ltr; }
.vm-shape { fill: color-mix(in srgb, var(--vm) 34%, transparent); stroke: var(--vm); stroke-width: 1.5; vector-effect: non-scaling-stroke; stroke-linejoin: round; }
.vm-mid { stroke: color-mix(in srgb, var(--vm) 30%, transparent); stroke-width: 1; vector-effect: non-scaling-stroke; }
/* the vowel (or the part the caption talks about): a soft band with a bar on top, the same on both strips */
.vm-mark { fill: color-mix(in srgb, var(--vm) 12%, transparent); }
.vm-mark-bar { fill: var(--vm); }
.vm-axis { display: flex; justify-content: space-between; margin: 0; font-size: var(--fs-xs, .75rem); color: var(--muted); direction: ltr; }
.vm-axis span:last-child::after { content: ' →'; }
/* before the learner speaks: an empty strip that says what to do */
.vm-me.is-empty .vm-art { display: grid; place-items: center; }
.vm-me.is-empty .vm-svg { position: absolute; inset: 0; }
.vm-wait { position: relative; margin: 0; padding: 0 var(--sp-3); font-size: var(--fs-sm); text-align: center; color: var(--muted); }
/* while recording: a small dot by the label, never a moving scale or a countdown */
.vm-rec-dot { display: none; width: 10px; height: 10px; margin-inline-end: 6px; border-radius: 50%; background: var(--bad); vertical-align: 0; }
.vm-me.is-live .vm-rec-dot { display: inline-block; animation: vm-blink 1.2s ease-in-out infinite; }
@keyframes vm-blink { 50% { opacity: .35; } }
/* the plain-words sentence under the strips (also what a screen reader hears), and the privacy line */
.vm-note { margin: 0; font-size: var(--fs-md, 1rem); line-height: 1.5; }
.vm-note:empty { display: none; }
.vm-private, .vc-private { display: flex; align-items: center; gap: 6px; margin: 0; font-size: var(--fs-sm); color: var(--muted); }
.vm-private svg, .vc-private svg { width: 14px; height: 14px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }
.vm-actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.vm-rec { min-height: 48px; }

:where(html:not(.a11y-contrast)) .vm-art { background: var(--surface-2); border: 1px solid var(--hairline); }
:where(html:not(.a11y-contrast)) .vm-play { background: var(--surface); border: 1px solid var(--hairline-strong); }
:where(html:not(.a11y-contrast)) .vm-me.is-empty .vm-art { background: transparent; border: 1.5px dashed var(--hairline-strong); }

/* ---------- 2. The time capsule card: day 1, day 30, day 90 ---------- */
.vc-card { display: grid; gap: var(--sp-3); padding: var(--sp-5); }
.vc-card h3 { margin: 0; font: 700 var(--fs-lg, 1.15rem)/1.25 var(--font-display); }
.vc-slots { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-2); margin: 0; padding: 0; list-style: none; }
.vc-slot { --vm: var(--accent-2); display: grid; align-content: start; gap: 6px; min-width: 0; padding: var(--sp-3); border-radius: var(--r); }
.vc-day { font: 700 var(--fs-sm)/1.2 var(--font-body); }
.vc-date { font-size: var(--fs-xs, .75rem); color: var(--muted); }
.vc-mini { height: 40px; border-radius: 8px; overflow: hidden; }
.vc-slot .vm-play { grid-area: auto; justify-self: start; padding: 0 12px; } /* not the mirror's named "play" cell */
.vc-slot.is-later .vc-mini, .vc-slot.is-due .vc-mini { display: none; }
.vc-intro, .vc-off { margin: 0; line-height: 1.5; }
.vc-off { color: var(--muted); }
.vc-wait { margin: 0; font-size: var(--fs-sm); color: var(--muted); }
.vc-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-4); }
.vc-actions .link-btn { min-height: 44px; }
/* kids: off until a parent turns it on in #family */
.vc-card.is-off .vc-slots, .vc-card.is-off .vc-actions { display: none; }

:where(html:not(.a11y-contrast)) .vc-card { border-radius: var(--r-lg); background: var(--surface); border: 1px solid var(--hairline); box-shadow: var(--e2); }
:where(html:not(.a11y-contrast)) .vc-slot { background: var(--surface-2); }
:where(html:not(.a11y-contrast)) .vc-slot.is-due { background: color-mix(in srgb, var(--accent-2) 10%, var(--surface)); outline: 1.5px solid color-mix(in srgb, var(--accent-2) 45%, transparent); }
:where(html:not(.a11y-contrast)) .vc-slot.is-later { background: transparent; border: 1.5px dashed var(--hairline-strong); }
:where(html:not(.a11y-contrast)) .vc-mini { background: var(--surface); }

/* a narrow phone: the three days stack, each a row */
@media (max-width: 420px) {
  .vc-slots { grid-template-columns: minmax(0, 1fr); }
  .vc-slot { grid-template-columns: minmax(0, 1fr) auto; align-items: center; }
  .vc-slot .vc-mini { grid-column: 1 / -1; }
  .vc-slot .vm-play { grid-column: 2; grid-row: 1 / span 2; }
}

/* ---------- 3. Modes ---------- */
html.a11y-contrast .vm-art, html.a11y-contrast .vc-mini { background: var(--bg); border: 2px solid var(--ink); }
html.a11y-contrast .vm-track, html.a11y-contrast .vc-slot { --vm: var(--ink); }
html.a11y-contrast .vm-shape { fill: none; stroke-width: 2.5; }
html.a11y-contrast .vm-me .vm-shape { stroke-dasharray: 6 3; } /* the two strips differ by line, not only by colour */
html.a11y-contrast .vm-play, html.a11y-contrast .vc-card, html.a11y-contrast .vc-slot { border: 2px solid var(--ink); background: var(--bg); color: var(--ink); }
html.a11y-contrast :is(.vm-axis, .vm-wait, .vm-private, .vc-private, .vc-date, .vc-wait, .vc-off) { color: var(--ink); }
html.pref-calm .vm-me.is-live .vm-rec-dot { animation: none; } /* pref-calm also covers easy learning */
@media (prefers-reduced-motion: reduce) { .vm-me.is-live .vm-rec-dot { animation: none; } }

/* ---------- 4. Conversation characters (docs/plan/2026-10-05-character-portraits.md; markup: window.PolyTalkArt) ----------
   Illustrated, fictional, always labelled "AI character". Pictures are 4:5; until they exist a character shows its initial
   on a soft tint. The mouth is an SVG placed on the picture by --mx/--my/--mw (per character, from the illustration). */
.tk-pick { display: grid; gap: var(--sp-3); }
.tk-pick h2 { margin: 0; }
.tk-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-3); }
@media (min-width: 720px) { .tk-grid { grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)); } }
.tk-card { display: grid; align-content: start; gap: 2px; min-width: 0; margin: 0; padding: 0 0 var(--sp-3); text-align: start; font: inherit; color: var(--ink); cursor: pointer; overflow: hidden; border-radius: var(--r-lg); }
.tk-card > :is(.tk-name, .tk-job, .tk-meta) { padding-inline: var(--sp-3); overflow-wrap: anywhere; }
.tk-card .tk-name { margin-top: var(--sp-2); font-size: var(--fs-md, 1rem); }
.tk-job { font-size: var(--fs-sm); color: var(--muted); }
.tk-meta { font-size: var(--fs-xs, .75rem); }
.tk-ph { position: relative; display: block; aspect-ratio: 4 / 5; overflow: hidden; }
.tk-img { display: block; width: 100%; height: 100%; object-fit: cover; }
.tk-mono { display: grid; place-items: center; width: 100%; height: 100%; font: 700 2.4rem/1 var(--font-display); color: var(--tint-ink-2, var(--accent-2)); background: var(--tint-2, var(--surface-2)); }
.tk-card.is-cat .tk-mono, .tk-face.is-cat .tk-mono { color: var(--tint-ink-4, var(--muted)); background: var(--tint-4, var(--surface-2)); }
/* the label is words, on every picture and next to every name */
.tk-ai { display: inline-block; padding: 1px 8px; border-radius: var(--r-pill); font: 700 var(--fs-xs, .72rem)/1.6 var(--font-body); color: var(--bg); background: var(--ink); white-space: nowrap; vertical-align: 1px; }
.tk-ph .tk-ai { position: absolute; inset-block-start: 8px; inset-inline-start: 8px; }
.tk-note { margin: 0; font-size: var(--fs-sm); color: var(--muted); }
.tk-card:focus-visible { outline: none; box-shadow: var(--ring); }

.tk-head { display: flex; align-items: center; gap: var(--sp-3); }
.tk-face { position: relative; flex: none; width: 96px; aspect-ratio: 4 / 5; border-radius: 20px; overflow: hidden; }
@media (min-width: 720px) { .tk-face { width: 128px; border-radius: 24px; } }
.tk-who { min-width: 0; }
.tk-who .tk-name { margin: 0; }
.tk-status { margin: 2px 0 0; font-size: var(--fs-sm); color: var(--muted); }
.tk-mouth { position: absolute; left: var(--mx); top: var(--my); width: var(--mw); transform: translate(-50%, -50%); overflow: visible; }
.tk-mouth path { fill: var(--lip, var(--ink)); stroke: var(--lip, var(--ink)); stroke-width: 2.5; stroke-linejoin: round; stroke-linecap: round; }
/* blinking: the illustration's closed-eyes layer (c.lids) shows for a moment every few seconds */
.tk-lids { display: none; }
.tk-head:has(.tk-img) .tk-lids[style] { display: block; background: var(--lids) center / cover no-repeat; position: absolute; inset: 0; pointer-events: none; animation: tk-blink 5.3s steps(1) infinite; }
@keyframes tk-blink { 0%, 96% { opacity: 0; } 97%, 99% { opacity: 1; } }
/* speaking: a soft ring that breathes; thinking: a calm dotted ring; listening: a still ring */
.tk-head .tk-face { box-shadow: 0 0 0 3px var(--surface), 0 0 0 5px var(--hairline-strong); }
.tk-head[data-tk-state="speaking"] .tk-face { box-shadow: 0 0 0 3px var(--surface), 0 0 0 6px color-mix(in srgb, var(--accent-2) 60%, transparent); animation: tk-ring 1.6s ease-in-out infinite; }
.tk-head[data-tk-state="thinking"] .tk-face { box-shadow: 0 0 0 3px var(--surface), 0 0 0 5px color-mix(in srgb, var(--accent-2) 30%, transparent); }
@keyframes tk-ring { 50% { box-shadow: 0 0 0 3px var(--surface), 0 0 0 9px color-mix(in srgb, var(--accent-2) 28%, transparent); } }

:where(html:not(.a11y-contrast)) .tk-card { background: var(--surface); border: 1px solid var(--hairline); box-shadow: var(--e1, none); }
:where(html:not(.a11y-contrast)) .tk-card:hover { box-shadow: var(--e2); }
html.a11y-contrast .tk-card, html.a11y-contrast .tk-face { background: var(--bg); border: 2px solid var(--ink); box-shadow: none; }
html.a11y-contrast .tk-head[data-tk-state] .tk-face { box-shadow: none; animation: none; }
html.a11y-contrast .tk-head[data-tk-state="speaking"] .tk-face { outline: 3px solid var(--ink); outline-offset: 2px; }
html.a11y-contrast :is(.tk-job, .tk-note, .tk-status) { color: var(--ink); }
/* calm mode, easy learning and reduced motion: no ring, no blink, and the page leaves the mouth still */
html.pref-calm .tk-head .tk-face, html.pref-calm .tk-lids { animation: none !important; }
@media (prefers-reduced-motion: reduce) { .tk-head .tk-face, .tk-lids { animation: none !important; } }
