/* Nico avatar: the Macrodeep chevron star on a brand-blue badge.
   <span class="nico-av" data-state="idle" style="--av-size:24px" aria-hidden="true"><svg>…</svg></span>
   States (data-state): idle listening thinking speaking done attention error. Missing = idle.
   Size: --av-size on the span or any ancestor (default 32px). Optical tier comes from a container query:
     xs <=20px · sm <28px · md <73px · lg >=73px.
   Theme: reads the app's own tokens (--brand-blue, --brand-paper, --text, --bg, --run), so it follows
     dark / light / sierra with no theme selectors.
   Motion: every state's STATIC pose is written first (plain rules). Motion is layered on top only inside
     @media (prefers-reduced-motion: no-preference) and only when the span is not .is-static.
   Animated properties: transform, opacity (and the registered --av-level number). No canvas, no layout. */

@property --av-level { syntax: '<number>'; inherits: true; initial-value: 0; }

.nico-av {
  --av-blue: var(--brand-blue, #507099);
  --av-ink: var(--brand-paper, #F5F1E8);
  --av-slate: oklch(.52 .03 255);   /* paper on it 4.88:1; vs grounds 3.54 / 5.42 / 5.04 */
  --av-amber: oklch(.88 .125 82);   /* on-badge amber, 3.51:1 on the blue (theme --run is 1.47:1 on it in light) */
  display: inline-block; flex: none; vertical-align: middle; position: relative;
  width: var(--av-size, 32px); height: var(--av-size, 32px);
  container: nav / size;
}
.nico-av > svg { display: block; width: 100%; height: 100%; overflow: visible; }
.nico-av svg { --av-ms: .70; --av-sw: 6.2; }
.nico-av :is(.av-mark, .av-look, .av-breath, .av-spin, .av-arm, .av-ring, .av-emit, .av-sweep) {
  transform-box: view-box; transform-origin: 32px 32px;
}
.nico-av .av-s0 { stop-color: oklch(.63 .08 252); }
.nico-av .av-s1 { stop-color: var(--av-blue); }
.nico-av .av-s2 { stop-color: oklch(.45 .07 258); }
.nico-av .av-slate { fill: var(--av-slate); opacity: 0; }
/* the rim is the theme's own ink at 20%: lifts the edge on dark (4.2:1), deepens it on light/sierra */
.nico-av .av-rim { stroke: var(--text, #fff); stroke-opacity: .2; }
.nico-av .av-ring, .nico-av .av-emit, .nico-av .av-sweep { stroke: var(--av-ink); opacity: 0; }
.nico-av .av-mark {
  stroke: var(--av-ink); stroke-width: var(--av-sw);
  transform: scale(calc(var(--av-ms) * var(--av-k, 1) * (1 - var(--av-room, 0) * var(--av-tr, 0)))) rotate(var(--av-rot, 0deg));
}
.nico-av .av-look { transform: translate(calc(var(--av-lx, 0) * var(--av-g, 0px)), calc(var(--av-ly, 1) * var(--av-g, 0px))); }
.nico-av .av-core { stroke: var(--av-ink); }
.nico-av .av-halo { display: none; stroke: var(--av-ink); stroke-width: 10; opacity: .3; }
.nico-av .av-pip { fill: var(--run, #e0a93a); stroke: var(--bg, #101216); stroke-width: 3.5; opacity: 0; transform: scale(.4); transform-origin: 53px 11px; }

/* ---- optical tiers: bigger mark, near-native stroke when small (a heavier stroke fills each chevron's notch).
   --av-tr: how much the mark gives way when a state draws on the rim (listening ring, thinking arc) ---- */
@container nav (width <= 20px) {
  .nico-av svg { --av-ms: .90; --av-sw: 6.6; --av-ps: 1.25; --av-tr: .16; }
  .nico-av .av-rim { display: none; }
  .nico-av .av-ring { stroke-width: 3.2; }
  .nico-av .av-sweep { stroke-width: 4.2; }
  .nico-av .av-pip { stroke-width: 4; }
}
@container nav (20px < width < 28px) {
  .nico-av svg { --av-ms: .84; --av-sw: 6.6; --av-ps: 1.12; --av-tr: .1; }
  .nico-av .av-ring { stroke-width: 2.4; }
  .nico-av .av-sweep { stroke-width: 3.4; }
}
@container nav (28px <= width < 73px) { .nico-av svg { --av-ms: .74; } .nico-av .av-sweep { stroke-width: 2.8; } }
/* the top arc is 64deg long; from 28px up only its middle 32deg is drawn (small sizes need the full length to read) */
@container nav (width >= 28px) { .nico-av .av-sweep { stroke-dasharray: 16 60; stroke-dashoffset: -7.75; } }
@container nav (width >= 73px) { .nico-av .av-halo { display: inline; } }

/* ================= STATIC POSES (also the reduced-motion / .is-static rendering) ================= */
/* idle: the mark at rest */
/* listening: mark draws in, a thin inner ring opens, the mark glances toward the composer (--av-lx/--av-ly, default down) */
.nico-av:is([data-state=listening], [data-state=thinking]) { --av-room: 1; }
.nico-av[data-state=listening] { --av-k: calc(.92 + var(--av-level) * .06); --av-g: 1.6px; }
.nico-av[data-state=listening] .av-ring { opacity: calc(.62 + var(--av-level) * .38); transform: scale(calc(.94 + var(--av-level) * .1)); }
.nico-av[data-state=listening] .av-halo { opacity: .42; }
/* thinking: a short paper arc on the TOP edge only (never an orbit); arms draw in a touch */
.nico-av[data-state=thinking] .av-sweep { opacity: .92; }
.nico-av[data-state=thinking] .av-arm { transform: translate(0, -1.4px); }
.nico-av[data-state=thinking] .av-halo { opacity: .36; }
/* speaking: the mark opens, alternate arms quieter */
.nico-av[data-state=speaking] { --av-k: 1.05; }
.nico-av[data-state=speaking] .av-arm { transform: translate(0, 1.6px); }
.nico-av[data-state=speaking] .av-arm:is([style*="--i:1"], [style*="--i:3"]) { opacity: .66; transform: none; }
/* done: the settled pose, halo lit */
.nico-av[data-state=done] .av-halo { opacity: .55; }
/* attention: pip at <=27px, one amber arm at >=28px (the arm at 1 o'clock) */
@container nav (width < 28px) { .nico-av[data-state=attention] .av-pip { opacity: 1; transform: scale(var(--av-ps, 1)); } }
@container nav (width >= 28px) {
  .nico-av[data-state=attention] .av-arm { opacity: .5; }
  .nico-av[data-state=attention] .av-arm[style*="--i:3"] { opacity: 1; }
  .nico-av[data-state=attention] .av-arm[style*="--i:3"] > * { stroke: var(--av-amber); }
  .nico-av[data-state=attention] .av-arm[style*="--i:3"] .av-halo { opacity: .7; }
}
/* error: calm slate, a small tilt, stillness */
.nico-av[data-state=error] { --av-k: .94; --av-rot: -8deg; }
.nico-av[data-state=error] .av-slate { opacity: .94; }
.nico-av[data-state=error] .av-rim { stroke-opacity: .1; }
.nico-av[data-state=error] .av-arm { opacity: .9; }
.nico-av[data-state=error] .av-halo { opacity: 0; }

/* ================= MOTION (layered on the poses) ================= */
@media (prefers-reduced-motion: no-preference) {
  .nico-av:not(.is-static) { transition: --av-level .12s linear; }
  .nico-av:not(.is-static) :is(.av-mark, .av-look) { transition: transform .45s cubic-bezier(.3, .7, .3, 1); }
  .nico-av:not(.is-static) :is(.av-arm, .av-ring, .av-sweep, .av-pip, .av-halo) { transition: opacity .35s ease, transform .35s ease; }
  .nico-av:not(.is-static) .av-core { transition: stroke .5s ease; }
  .nico-av:not(.is-static) .av-slate { transition: opacity .7s ease; }

  /* idle: one slow breath; an arm "blinks" once every 7 s */
  .nico-av:not(.is-static):is([data-state=idle], :not([data-state])) .av-breath { animation: av-breathe 2s ease-in-out infinite alternate; }
  .nico-av:not(.is-static):is([data-state=idle], :not([data-state])) .av-halo { animation: av-glow 2s ease-in-out infinite alternate; }
  .nico-av:not(.is-static):is([data-state=idle], :not([data-state])) .av-arm[style*="--i:1"] { animation: av-blink 7s ease-in-out 2.5s infinite; }

  /* listening: arms lean in on uneven beats (plus --av-level from the mic/keys) */
  .nico-av:not(.is-static)[data-state=listening] .av-arm { animation: av-lean 1.1s ease-in-out infinite alternate; }
  .nico-av:not(.is-static)[data-state=listening] .av-arm[style*="--i:1"] { animation-duration: .8s; animation-delay: -.3s; }
  .nico-av:not(.is-static)[data-state=listening] .av-arm[style*="--i:2"] { animation-duration: 1.3s; animation-delay: -.7s; }
  .nico-av:not(.is-static)[data-state=listening] .av-arm[style*="--i:3"] { animation-duration: .9s; animation-delay: -.2s; }
  .nico-av:not(.is-static)[data-state=listening] .av-arm[style*="--i:4"] { animation-duration: 1.2s; animation-delay: -.5s; }

  /* thinking: the dial turns one arm (72deg, lands on the identical pose) and holds; the top arc sweeps once per beat */
  .nico-av:not(.is-static)[data-state=thinking] .av-spin { animation: av-dial 1.6s cubic-bezier(.55, 0, .25, 1) infinite; }
  .nico-av:not(.is-static)[data-state=thinking] .av-arm { animation: av-gear 1.6s cubic-bezier(.55, 0, .25, 1) infinite; animation-delay: calc(var(--i) * -.07s); }
  @container nav (width >= 28px) { .nico-av:not(.is-static)[data-state=thinking] .av-sweep { animation: av-sweep 1.6s ease-in-out infinite; } }

  /* speaking: arms pulse outward in sequence; at >=73px one soft paper ring leaves the badge per beat */
  .nico-av:not(.is-static)[data-state=speaking] .av-arm { animation: av-pulse 1s cubic-bezier(.3, 0, .3, 1) infinite; animation-delay: calc(var(--i) * .2s - 1s); }
  @container nav (width >= 73px) { .nico-av:not(.is-static)[data-state=speaking] .av-emit { animation: av-emit 1.2s ease-out infinite; } }

  /* done: one exact 72deg turn, a small lift, a glow flash, then the app returns to idle */
  .nico-av:not(.is-static)[data-state=done] .av-spin { animation: av-turn .9s cubic-bezier(.3, 0, .2, 1) both; }
  .nico-av:not(.is-static)[data-state=done] .av-breath { animation: av-settle .9s cubic-bezier(.2, .7, .2, 1) both; }
  .nico-av:not(.is-static)[data-state=done] .av-ring { animation: av-flash .9s ease-out both; }
  .nico-av:not(.is-static)[data-state=done] .av-halo { animation: av-flash-h .9s ease-out both; }

  /* attention: the pip / amber arm nudges, calm and slow */
  .nico-av:not(.is-static)[data-state=attention] .av-pip { animation: av-pip 2s ease-in-out infinite; }
  .nico-av:not(.is-static)[data-state=attention] .av-arm[style*="--i:3"] { animation: av-nudge 1.6s ease-in-out infinite; }
  /* error: no loop. The slate crossfades in (.7 s) and the tilt eases in; then it is still. */
}

@keyframes av-breathe { from { transform: scale(1); } to { transform: scale(1.03); } }
@keyframes av-glow { from { opacity: .22; } to { opacity: .42; } }
@keyframes av-blink { 0%, 93%, 100% { opacity: 1; } 96% { opacity: .3; } }
@keyframes av-lean { from { transform: translate(0, 0); } to { transform: translate(0, calc(-1.6px - var(--av-level) * 1.2px)); } }
@keyframes av-dial { 0% { transform: rotate(0); } 72%, 100% { transform: rotate(72deg); } }
@keyframes av-gear { 0%, 100% { transform: translate(0, -1.4px); opacity: 1; } 36% { transform: translate(0, -3px); opacity: .62; } 72% { transform: translate(0, -1.4px); opacity: 1; } }
@keyframes av-sweep { 0% { transform: rotate(-50deg); opacity: 0; } 25%, 75% { opacity: .92; } 100% { transform: rotate(50deg); opacity: 0; } }
@keyframes av-pulse { 0%, 100% { transform: translate(0, 0); opacity: .72; } 30% { transform: translate(0, calc(2.4px + var(--av-level) * 1.6px)); opacity: 1; } }
@keyframes av-emit { from { transform: scale(1); opacity: calc(.2 + var(--av-level) * .45); } to { transform: scale(calc(1.16 + var(--av-level) * .22)); opacity: 0; } }
@keyframes av-turn { from { transform: rotate(0); } to { transform: rotate(72deg); } }
@keyframes av-settle { 0% { transform: scale(.9); } 55% { transform: scale(1.05); } 100% { transform: scale(1); } }
@keyframes av-flash { 0% { opacity: 0; transform: scale(.9); } 35% { opacity: .8; transform: scale(1); } 100% { opacity: 0; transform: scale(1.03); } }
@keyframes av-flash-h { 0% { opacity: .2; } 30% { opacity: .85; } 100% { opacity: .55; } }
@keyframes av-pip { 0%, 100% { transform: scale(var(--av-ps, 1)); } 50% { transform: scale(calc(var(--av-ps, 1) * 1.14)); } }
@keyframes av-nudge { 0%, 100% { transform: translate(0, 0); } 18% { transform: translate(0, 3px); } 34% { transform: translate(0, .6px); } 46% { transform: translate(0, 2px); } 62% { transform: translate(0, 0); } }
