/* Studio status mark (core/partials/_nav_live.html, canvas_studio/partials/_nav_status.html).

   STRUCTURE AND TIMING ONLY, for every design and both shells. A small mark sits at the top corner of
   the Studio icon in the sidebar (expanded and collapsed), the phone dock and the More sheet. It says
   what the Studio has in progress, in four shapes that never rely on colour alone:

     running  a ring with a travelling arc        (quiet loop)
     needs    two still bars on a disc            (waiting for the person; static)
     ready    a check that draws once, then a dot (the dot stays until the lesson is opened)
     failed   an exclamation on a disc            (static)

   Every colour, size and the cut-out ring come from the design on screen, as custom properties it
   defines in its own shell file (--nav-live-busy / -wait / -ready / -error / -cut, --nav-live-size,
   --nav-live-ring, --nav-live-spin, --nav-live-glow). The fallbacks here are system keywords, so a
   design that has not answered still shows a legible mark. No colour literal, no typeface and no
   design selector may live in this file. */

.nav-live-host, .tb-dock__pill { position: relative; }
.nav-live-host { display: inline-flex; flex-shrink: 0; }

.nav-live {
  position: absolute;
  inset-block-start: -5px;
  inset-inline-end: -6px;
  inline-size: calc(var(--nav-live-size, 12px) * var(--nav-live-scale, 1.25));
  block-size: calc(var(--nav-live-size, 12px) * var(--nav-live-scale, 1.25));
  display: none;
  pointer-events: none;      /* the whole row stays the click target */
}
.nav-live:not(:empty) { display: block; }

.nav-live__mark {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  border-radius: var(--nav-live-radius, 50%);
  background: var(--nav-live-cut, Canvas);
  box-shadow: 0 0 0 var(--nav-live-ring, 2px) var(--nav-live-cut, Canvas);
  filter: var(--nav-live-glow, none);
}
.nav-live__mark svg { display: block; inline-size: 100%; block-size: 100%; overflow: visible; }

.nav-live__mark[data-state="running"] { color: var(--nav-live-busy, CanvasText); }
.nav-live__mark[data-state="needs"]   { color: var(--nav-live-wait, CanvasText); }
.nav-live__mark[data-state="ready"]   { color: var(--nav-live-ready, CanvasText); }
.nav-live__mark[data-state="failed"]  { color: var(--nav-live-error, CanvasText); }

/* Status unreachable: the last known mark stays, but nothing moves and it is dimmed. */
.nav-live[data-stale] .nav-live__mark { opacity: .55; }
.nav-live[data-stale] .nl-arc { animation-play-state: paused; }

.nl-track { opacity: .3; }
.nl-arc { transform-origin: 8px 8px; transform-box: view-box; animation: nav-live-spin var(--nav-live-spin-dur, 1.8s) var(--nav-live-spin, linear) infinite; }
.nl-cut { fill: var(--nav-live-cut, Canvas); }

/* Ready: without `data-just` it is only the dot (every later look). With it, the check draws once,
   holds, then gives way to the dot. */
.nl-check { display: none; stroke-dasharray: 14; stroke-dashoffset: 14; }
.nl-dot { transform-origin: 8px 8px; transform-box: view-box; }
.nav-live__mark[data-just] .nl-check { display: block; animation: nav-live-draw .42s ease-out forwards, nav-live-fade .3s 1.7s ease-in forwards; }
.nav-live__mark[data-just] .nl-dot { animation: nav-live-pop .3s 1.85s ease-out backwards; }

@keyframes nav-live-spin { to { transform: rotate(360deg); } }
@keyframes nav-live-draw { to { stroke-dashoffset: 0; } }
@keyframes nav-live-fade { to { opacity: 0; } }
@keyframes nav-live-pop { from { transform: scale(0); } to { transform: scale(1); } }

@media (prefers-reduced-motion: reduce) {
  .nl-arc { animation: none; }
  /* The check is simply there, then the dot: nothing draws, nothing pops. */
  .nav-live__mark[data-just] .nl-check { animation: none; stroke-dashoffset: 0; }
  .nav-live__mark[data-just] .nl-dot { animation: none; }
}

/* Words for assistive technology. Inside the link, so the Studio link's name carries the state;
   and one polite status region (in the notifications shell) that speaks a change once. */
.nav-live__sr, .nav-live__announce {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---- the row itself changes ---------------------------------------------------------------------------------------
   Studio is where lessons are drawn, so while one is being made the row's own icon moves and the row takes a wash and
   an edge in the state's colour: a visible change that is not the "selected" look (the selected row keeps its solid
   fill; this is a translucent layer over whatever the row already has, in `background-image` only). Size, label and
   click target never change: the icon moves by transform, the wash and edge are backgrounds. Every colour and tempo is
   the active design's (--nav-live-busy/-wait/-ready/-error, --nav-live-tint, --nav-live-icon-*). */

:is(.tb-side__item, .tb-dock__item, .tb-more__tile, .tm-nav-link, .tm-mobile-nav a, .tm-more-grid a):has(.nav-live__mark[data-state="running"]) { --nl-c: var(--nav-live-busy, currentColor); }
:is(.tb-side__item, .tb-dock__item, .tb-more__tile, .tm-nav-link, .tm-mobile-nav a, .tm-more-grid a):has(.nav-live__mark[data-state="needs"]) { --nl-c: var(--nav-live-wait, currentColor); }
:is(.tb-side__item, .tb-dock__item, .tb-more__tile, .tm-nav-link, .tm-mobile-nav a, .tm-more-grid a):has(.nav-live__mark[data-state="ready"]) { --nl-c: var(--nav-live-ready, currentColor); }
:is(.tb-side__item, .tb-dock__item, .tb-more__tile, .tm-nav-link, .tm-mobile-nav a, .tm-more-grid a):has(.nav-live__mark[data-state="failed"]) { --nl-c: var(--nav-live-error, currentColor); }

.sidebar .tb-side__item:not([aria-current]):has(.nav-live__mark),
.tb-more__tile:not([aria-current]):has(.nav-live__mark),
.tm-nav-link:not([aria-current]):has(.nav-live__mark),
.tm-more-grid a:not([aria-current]):has(.nav-live__mark),
.tm-mobile-nav a:not([aria-current]):has(.nav-live__mark),
.tb-dock__item:has(.nav-live__mark) .tb-dock__pill {
  background-image:
    linear-gradient(var(--nl-c), var(--nl-c)),
    linear-gradient(color-mix(in srgb, var(--nl-c) var(--nav-live-tint, 12%), transparent), color-mix(in srgb, var(--nl-c) var(--nav-live-tint, 12%), transparent));
  background-size: 3px 56%, 100% 100%;
  background-repeat: no-repeat;
  background-position: var(--nav-live-edge-pos, left) center, 0 0;
}
/* The page that is open keeps its solid fill; activity is then only the edge and the moving icon (no wash), so Studio
   can be current and still show that it is working, and the two never look like the same thing. */
.sidebar .tb-side__item[aria-current]:has(.nav-live__mark),
.tb-more__tile[aria-current]:has(.nav-live__mark),
.tm-nav-link[aria-current]:has(.nav-live__mark),
.tm-more-grid a[aria-current]:has(.nav-live__mark) {
  background-image: linear-gradient(var(--nl-c), var(--nl-c));
  background-size: 3px 56%;
  background-repeat: no-repeat;
  background-position: var(--nav-live-edge-pos, left) center;
}
body[dir="rtl"] { --nav-live-edge-pos: right; }
/* The dock's pill is small: no edge, only the wash. */
.tb-dock__item:has(.nav-live__mark) .tb-dock__pill { background-size: 0 0, 100% 100%; }

/* While it runs, the corner mark steps aside: the icon is the signal. A build waiting, failed or ready keeps its mark. */
.nav-live__mark[data-state="running"] { display: none; }

:is(.sidebar-icon, .tb-dock__pill > :first-child, .nav-live-host > :first-child) { transform-box: fill-box; }
a:has(.nav-live__mark[data-running]) :is(.sidebar-icon, .tb-dock__pill > :first-child, .nav-live-host > :first-child) {
  transform-origin: 50% 88%;
  animation: nav-live-icon var(--nav-live-icon-dur, 2.2s) var(--nav-live-icon-ease, ease-in-out) infinite;
}
/* The icon itself takes the state's colour, so the moving icon is the signal even where the row's wash is faint. */
a:has(.nav-live__mark[data-running]) :is(.sidebar-icon, .tb-dock__pill > :first-child, .nav-live-host > :first-child) { color: var(--nav-live-busy, currentColor); }
@keyframes nav-live-icon {
  0%, 100% { transform: translate(0, 0) rotate(0); }
  22% { transform: translate(1px, -1px) rotate(var(--nav-live-icon-tilt, -6deg)); }
  48% { transform: translate(-1px, 0) rotate(calc(var(--nav-live-icon-tilt, -6deg) * -.6)); }
  72% { transform: translate(1px, -1px) rotate(calc(var(--nav-live-icon-tilt, -6deg) * .5)); }
}
/* No answer from the server: the icon holds still and the wash is dimmed. */
a:has(.nav-live[data-stale]) :is(.sidebar-icon, .tb-dock__pill > :first-child, .nav-live-host > :first-child) { animation-play-state: paused; }
a:has(.nav-live[data-stale]) { opacity: .8; }
@media (prefers-reduced-motion: reduce) {
  a:has(.nav-live__mark[data-running]) :is(.sidebar-icon, .tb-dock__pill > :first-child, .nav-live-host > :first-child) { animation: none; }
}
