/* FREQUENCITY // SIGNAL.CHROMA — Concept 04 / KINETIC LAYER
   ------------------------------------------------------------------
   Loaded after styles.css, os.css and chroma.css.
   Purpose: motion and interaction only. No content, layout or colour
   system is replaced here; every rule either adds a reactive state,
   an ambient effect, or a transition between existing states.

   Animation budget, in order of cost:
     1. transform / opacity (compositor only)          — used everywhere
     2. CSS custom property reads (no layout)          — scan proximity
     3. one small 2D canvas, repainted on selection    — signal signature
   No continuous layout-affecting animation. No animated blur radius.
   ------------------------------------------------------------------ */

/* ------------------------------------------------------------------
   1. TOKENS
------------------------------------------------------------------ */
:root{
  --k-ease:cubic-bezier(.22,.72,.24,1);
  --k-ease-out:cubic-bezier(.16,1,.3,1);
  --k-fast:160ms;
  --k-mid:320ms;
  --k-slow:620ms;

  /* Live pointer position within a panel, as percentages. Falls back to
     a fixed resting light so the surface still reads without a pointer. */
  --mx:50%;
  --my:0%;

  --emit:var(--active-emit,#b385ff);
}
body[data-pointer="off"]{--mx:50%;--my:0%}

/* ------------------------------------------------------------------
   2. ENTRANCE — the page assembles, it does not just appear
------------------------------------------------------------------ */
@keyframes k-rise{from{opacity:0;transform:translate3d(0,16px,0)}to{opacity:1;transform:none}}
@keyframes k-rise-sm{from{opacity:0;transform:translate3d(0,9px,0)}to{opacity:1;transform:none}}

@media (prefers-reduced-motion:no-preference){
  .notice-strip{animation:k-rise-sm .5s var(--k-ease-out) both}
  .site-header{animation:k-rise-sm .55s .05s var(--k-ease-out) both}
  .os-dock{animation:k-rise-sm .6s .1s var(--k-ease-out) both}
  .hero-content>*{animation:k-rise .7s var(--k-ease-out) both}
  .hero-content>*:nth-child(1){animation-delay:.10s}
  .hero-content>*:nth-child(2){animation-delay:.16s}
  .hero-content>*:nth-child(3){animation-delay:.22s}
  .hero-content>*:nth-child(4){animation-delay:.30s}
  .hero-content>*:nth-child(5){animation-delay:.38s}
  .hero-content>*:nth-child(6){animation-delay:.44s}
  .hero-content>*:nth-child(7){animation-delay:.50s}
  .hero-instrument{animation:k-rise .8s .18s var(--k-ease-out) both}
}

/* ------------------------------------------------------------------
   3. NAVIGATION — deliberate hover / focus / active states
------------------------------------------------------------------ */
.main-nav a{
  position:relative;
  transition:color var(--k-fast) linear;
}
.main-nav a::after{
  content:"";
  position:absolute;
  left:0;right:0;bottom:2px;
  height:1px;
  background:linear-gradient(90deg,#f07ce9,#8f7bff 55%,#35e6ff);
  transform:scaleX(0);
  transform-origin:left center;
  transition:transform var(--k-mid) var(--k-ease);
  box-shadow:0 0 9px #b45cff9e;
}
.main-nav a:hover::after,
.main-nav a:focus-visible::after,
.main-nav a[aria-current="true"]::after{transform:scaleX(1)}
.nav-label{display:inline-block;transition:transform var(--k-mid) var(--k-ease)}
.main-nav a:hover .nav-label,
.main-nav a:focus-visible .nav-label{transform:translateY(-1px)}
.nav-index{transition:color var(--k-fast) linear,transform var(--k-mid) var(--k-ease)}
.main-nav a:hover .nav-index{color:#8fe9ff;transform:translateY(-2px)}

/* Travelling sheen on framed controls. The topology nodes are appended
   to their own rule below: they are absolutely positioned inside the
   field and must not inherit `position` from this group. */
.header-cta,
.button,
.live-open,
.inspector-link,
.ambient-toggle,
.filter-button,
.dock-item,
.process-step{position:relative;overflow:hidden}
.node{position:absolute;overflow:visible}

/* A single travelling sheen, reused by every framed control. */
.header-cta::after,
.button::after,
.live-open::after,
.inspector-link::after,
.ambient-toggle::after{
  content:"";
  position:absolute;
  top:0;bottom:0;
  left:-60%;
  width:45%;
  pointer-events:none;
  background:linear-gradient(100deg,transparent,#ffffff2e 45%,transparent);
  transform:translate3d(-40%,0,0) skewX(-14deg);
  opacity:0;
  transition:transform 620ms var(--k-ease),opacity 200ms linear;
}
.header-cta:hover::after,
.button:hover::after,
.live-open:hover::after,
.inspector-link:hover::after,
.ambient-toggle:hover::after{
  transform:translate3d(330%,0,0) skewX(-14deg);
  opacity:1;
}
.button:active,
.header-cta:active,
.live-open:active,
.ambient-toggle:active{transform:translateY(0) scale(.985)}
.button{transition:background var(--k-fast) linear,border-color var(--k-fast) linear,transform var(--k-fast) var(--k-ease),box-shadow var(--k-mid) var(--k-ease)}
.button-primary:hover{box-shadow:0 0 34px #cf5fff6b,0 14px 40px #4b78ff2b,inset 0 1px #fff9}
.button-primary .button-signal{transition:transform 520ms var(--k-ease)}
.button-primary:hover .button-signal{transform:rotate(90deg) scale(1.06)}

.dock-item{transition:background var(--k-fast) linear,color var(--k-fast) linear,border-color var(--k-fast) linear,transform var(--k-mid) var(--k-ease)}
.dock-item:hover{transform:translateX(2px)}
.dock-item>span{transition:transform var(--k-mid) var(--k-ease),filter var(--k-mid) var(--k-ease)}
.dock-item:hover>span{transform:translateY(-1px) scale(1.06);filter:drop-shadow(0 0 8px #b56bff)}
.dock-item.dock-active>span{filter:drop-shadow(0 0 10px #e26aff)}

.filter-button{
  transition:color var(--k-fast) linear,background var(--k-fast) linear,border-color var(--k-fast) linear;
  border-radius:3px;
}
.filter-button.active{box-shadow:inset 0 -2px #f47ce6,0 0 18px #a94cff2e}

.process-step{
  transition:background var(--k-fast) linear,color var(--k-fast) linear,box-shadow var(--k-mid) var(--k-ease);
}
.process-step.is-current{box-shadow:inset 0 -3px #ef7cff,inset 0 -14px 22px -14px #ff7ce566}
.process-step::after{
  content:"";
  position:absolute;
  inset:0;
  pointer-events:none;
  background:linear-gradient(180deg,#ffffff1a,transparent 60%);
  opacity:0;
  transition:opacity var(--k-fast) linear;
}
.process-step:hover::after{opacity:1}

/* ------------------------------------------------------------------
   4. AMBIENT — the interface is lit, not just coloured
------------------------------------------------------------------ */

/* Circuitry: drawn once on load, then left almost still. */
.circuit-field{
  position:absolute;
  inset:0;
  z-index:0;
  pointer-events:none;
  opacity:.5;
  mask-image:linear-gradient(120deg,#000 0%,#0002 62%,transparent 88%);
}
.circuit-field svg{width:100%;height:100%;display:block}
.circuit-lines path{fill:none;stroke:#7d5fd6;stroke-width:1;stroke-opacity:.36}
.circuit-junctions circle{fill:#8ee7ff;fill-opacity:.55}
.circuit-dashes path{
  fill:none;
  stroke:#41e6ff;
  stroke-width:1.6;
  stroke-linecap:round;
  stroke-dasharray:26 300;
  stroke-dashoffset:0;
  opacity:.75;
  filter:drop-shadow(0 0 4px #35dcff);
}

/* Scan proximity. --k-scan is written by app.js from a slow rotating
   trace; only opacity and a glow read it, so this never reflows. */
.node{--k-scan:0}
.node-point{
  box-shadow:
    0 0 calc(14px + var(--k-scan) * 16px) rgba(66,224,255,calc(.28 + var(--k-scan) * .5)),
    inset 0 0 0 4px #181239;
  transition:box-shadow 220ms linear;
}
.node[aria-pressed="true"] .node-point{
  animation:k-emit 2.6s ease-in-out infinite;
}
@keyframes k-emit{
  0%,100%{box-shadow:0 0 0 5px #b66aff26,0 0 20px var(--active-emit),0 0 34px #ca64ff7a}
  50%{box-shadow:0 0 0 8px #b66aff3d,0 0 30px var(--active-emit),0 0 54px #e379ffa6}
}

/* Field lighting reacts to the last selection. */
.signal-field::after{
  transition:background var(--k-slow) var(--k-ease),transform var(--k-mid) var(--k-ease);
}
.core-flare{
  transform-origin:250px 250px;
  stroke:#d9b4ff;
  stroke-width:1.4;
  opacity:0;
  pointer-events:none;
}
.core-flare.is-firing{animation:k-core-flare 900ms var(--k-ease-out) 1}
@keyframes k-core-flare{
  0%{opacity:0;transform:scale(.9)}
  22%{opacity:.95}
  100%{opacity:0;transform:scale(2.15)}
}

/* ------------------------------------------------------------------
   5. LIVING TOPOLOGY — connections that carry a signal
------------------------------------------------------------------
   Geometry note, measured in Chrome and recorded in TEST-REPORT.md:
   the live paths declare pathLength="100", so stroke-dash units map 1:1
   onto a 100-unit path regardless of its real length (link 1 is 172.41
   user units). A dash must therefore be a small fraction of 100. The
   previous fallback of 180 was larger than the entire path, so the path
   painted as one solid dash and no travel was ever visible.

   Travel direction: path 1 runs hub -> node. stroke-dashoffset decreases
   monotonically across each cycle (104 -> -10), which moves the lit dash
   from the hub outward to the node, then repeats seamlessly because the
   cycle advances by exactly the dasharray period (10 + 104).
------------------------------------------------------------------ */
.field-link{fill:none;stroke-linecap:round}
.field-link.live{
  stroke-width:2.4;
  stroke-dasharray:var(--dash,10) var(--gap,104);
  stroke:var(--emit);
  stroke-opacity:0;
  filter:drop-shadow(0 0 6px var(--emit));
}
/* Charged: the trace draws outward only once, as the selection reads. */
.field-link.live.is-charged{
  stroke-opacity:.95;
  transition:stroke-opacity 260ms linear;
}
/* Live: continuous travel, driven purely by the animation. */
.field-link.live.is-live{
  stroke-opacity:.95;
  animation:k-comet var(--period,2600ms) linear infinite;
  animation-delay:var(--lag,0ms);
}
/* Rest: connected, but carrying nothing. */
.field-link.live.is-resting{
  stroke-opacity:.2;
  animation:none;
}
@keyframes k-comet{
  from{stroke-dashoffset:104}
  to{stroke-dashoffset:-10}
}
.node-stage .link-base .field-link{stroke-opacity:.28;transition:stroke-opacity var(--k-slow) linear}
.node-stage:has(.node[data-select]:hover) .link-base .field-link{stroke-opacity:.4}

/* The travelling marks ride their connection. --tx/--ty are the measured
   travel vector for the matching path (written by app.js); --period and
   --lag are its duration and phase. Transform and opacity only, so travel
   is compositor work and is readable from getComputedStyle for testing.

   A mark only animates, and is only visible, while its own connection is the
   selected one. The markup carries four pulse groups, so without this scoping
   every inactive connection also appeared to be carrying traffic.

   The fade multiplies a --mark-on factor that app.js sets to 1 on the selected
   connection and 0 on all others. Driving visibility from the selection, rather
   than merely pausing the animation, means an unselected connection is
   provably dark even if one of its marks was mid-cycle when the selection
   moved. */
.link-pulse{
  --mark-on:0;
  fill:#fff;
  opacity:0;
  pointer-events:none;
  filter:drop-shadow(0 0 6px var(--emit)) drop-shadow(0 0 13px var(--emit));
  will-change:transform,opacity;
}
.link-pulse.pulse-run,
.link-pulse.pulse-run-2{
  /* Explicitly inert without a selected connection: no travel, no light. */
  animation:none;
  opacity:0;
}
/* The marks are siblings of the connection paths, not descendants, so the
   selected state is carried on the marks themselves (set by app.js). */
.link-pulse[is-selected].pulse-run{
  animation:k-pulse-run var(--period,2600ms) linear infinite;
  animation-delay:var(--lag,0ms);
}
.link-pulse[is-selected].pulse-run-2{
  animation:k-pulse-run-2 var(--period,2600ms) linear infinite;
  animation-delay:var(--lag2,0ms);
}
.link-pulse[is-selected]{--mark-on:1}
@keyframes k-pulse-run{
  0%{transform:translate3d(0,0,0);opacity:0}
  10%{opacity:var(--mark-on,0)}
  82%{opacity:var(--mark-on,0)}
  96%{opacity:0}
  100%{transform:translate3d(var(--tx,0px),var(--ty,0px),0);opacity:0}
}
@keyframes k-pulse-run-2{
  0%{transform:translate3d(0,0,0);opacity:0}
  48%{opacity:0}
  56%{opacity:calc(var(--mark-on,0) * .9)}
  90%{opacity:calc(var(--mark-on,0) * .9)}
  100%{transform:translate3d(var(--tx,0px),var(--ty,0px),0);opacity:0}
}
.heat-ring{
  stroke:var(--emit);
  stroke-width:1.4;
  opacity:0;
  /* User-space origin: these rings are r=12 at r=0, so a fill-box origin
     would collapse to a point and the scale would fly off-centre. */
  transform-origin:250px 250px;
  pointer-events:none;
}
.heat-ring.is-firing{animation:k-heat 900ms var(--k-ease-out) 1}
@keyframes k-heat{
  0%{opacity:.9;transform:scale(.35)}
  70%{opacity:.5}
  100%{opacity:0;transform:scale(2.5)}
}

/* Travel is driven by the k-comet animation on .is-live; see section 5. */

/* The node stage exists only to give the scan-proximity pass a single
   subtree to read. It must be a positioned, non-flow box: the nodes are
   placed with percentages against .signal-field, and a static div here
   would make them resolve against the wrong containing block. */
.node-stage{position:absolute;inset:0;z-index:3}

/* Selection feedback on the node label and point.
   NOTE: the base layer positions .node absolutely against .signal-field.
   Only the transform may be animated here — never `position`, or every
   inset silently becomes a relative offset and the constellation folds
   into the corner. */
.node{transition:color var(--k-fast) linear,transform var(--k-mid) var(--k-ease)}
.node:hover{transform:translate3d(3px,0,0) scale(1.02)}
.node[aria-pressed="true"]{transform:translate3d(4px,0,0)}
.node.is-dimmed{opacity:.4}
.node-name{display:inline-block;transition:letter-spacing var(--k-slow) var(--k-ease),text-shadow var(--k-mid) linear}
/* The labels sit on a live radial gradient whose brightness moves with
   the emit colour, so the halo is part of legibility, not decoration. */
.node .node-name{text-shadow:0 0 4px #05040f,0 0 9px #05040fcc,0 0 18px #05040f8c}
.node[aria-pressed="true"] .node-name{letter-spacing:.09em;text-shadow:0 0 12px var(--emit)}
.node.is-focus-host::after{
  content:"";
  position:absolute;
  inset:-8px -10px;
  border:1px solid var(--emit);
  border-radius:4px;
  opacity:.55;
  pointer-events:none;
  animation:k-focus-hold 1.6s var(--k-ease-out) 1;
}
@keyframes k-focus-hold{from{opacity:.9;transform:scale(.94)}to{opacity:0;transform:scale(1.04)}}

/* ------------------------------------------------------------------
   6. COORDINATED SECTION CHOREOGRAPHY
------------------------------------------------------------------ */
@media (prefers-reduced-motion:no-preference){
  .is-revealing .k-reveal{animation:k-rise-sm 620ms var(--k-ease-out) both}
  .is-revealing .k-reveal.k-d0{animation-delay:0ms}
  .is-revealing .k-reveal.k-d1{animation-delay:70ms}
  .is-revealing .k-reveal.k-d2{animation-delay:140ms}
  .is-revealing .k-reveal.k-d3{animation-delay:210ms}
  .is-revealing .k-reveal.k-d4{animation-delay:280ms}
  .is-revealing .k-reveal.k-d5{animation-delay:350ms}
  .is-revealing .k-reveal.k-d6{animation-delay:420ms}
  .is-revealing .k-reveal.k-d7{animation-delay:490ms}

  .section-intro .k-reveal{animation:k-rise-sm 700ms var(--k-ease-out) both}
}

/* Ambient circuits animate in once, then only two dashes keep moving. */
@media (prefers-reduced-motion:no-preference){
  .circuit-run{
    stroke-dasharray:1;
    stroke-dashoffset:1;
    animation:k-circuit-draw 1.9s var(--k-ease-out) both;
  }
  .circuit-run:nth-child(2){animation-delay:.14s}
  .circuit-run:nth-child(3){animation-delay:.28s}
  .circuit-run:nth-child(4){animation-delay:.42s}
  .circuit-run:nth-child(5){animation-delay:.56s}
  .circuit-run:nth-child(6){animation-delay:.7s}
  .circuit-dash{animation:k-circuit-flow 7.5s linear infinite}
  .circuit-dash:nth-child(2){animation-duration:9.5s;animation-delay:-3s}
}
@keyframes k-circuit-draw{to{stroke-dashoffset:0}}
@keyframes k-circuit-flow{
  from{stroke-dashoffset:326}
  to{stroke-dashoffset:0}
}

/* ------------------------------------------------------------------
   7. PANEL LIGHT RESPONSE
------------------------------------------------------------------ */
.atlas-list-col,
.inspector,
.method-console,
.principles>div{
  position:relative;
}
.inspector::after,
.atlas-list-col::after,
.method-console::after{
  content:"";
  position:absolute;
  inset:0;
  z-index:3;
  pointer-events:none;
  opacity:0;
  background:radial-gradient(420px circle at var(--mx) var(--my),#c08cff1f,transparent 62%);
  transition:opacity var(--k-mid) linear;
}
.inspector:hover::after,
.atlas-list-col:hover::after,
.method-console:hover::after{opacity:1}

/* The inspector edge light carries the selected project's colour. */
.inspector{
  transition:box-shadow var(--k-slow) var(--k-ease),border-color var(--k-slow) linear;
}
.inspector::before{
  content:"";
  position:absolute;
  left:0;top:0;bottom:0;
  width:2px;
  z-index:4;
  pointer-events:none;
  background:linear-gradient(180deg,transparent,var(--emit) 22%,#7ff0ff 62%,transparent);
  opacity:.85;
  transform:scaleY(0);
  transform-origin:top center;
  transition:transform var(--k-slow) var(--k-ease),background var(--k-mid) linear;
}
.inspector.is-charged::before{transform:scaleY(1)}
.inspector.is-updating{box-shadow:0 22px 75px #0005,0 0 60px -8px var(--emit),0 0 120px -40px var(--emit)}
.inspector.is-updating .inspector-body{animation:k-body-swap 520ms var(--k-ease-out) 1}
@keyframes k-body-swap{
  0%{opacity:.25}
  35%{opacity:.5}
  100%{opacity:1}
}

/* Staggered inspector content — one coordinated transition. */
.inspector-body .k-enter{animation:k-rise-sm 480ms var(--k-ease-out) both}
.inspector-body .k-enter.k-e1{animation-delay:40ms}
.inspector-body .k-enter.k-e2{animation-delay:90ms}
.inspector-body .k-enter.k-e3{animation-delay:130ms}
.inspector-body .k-enter.k-e4{animation-delay:170ms}
.inspector-body .k-enter.k-e5{animation-delay:210ms}
.inspector-body .k-enter.k-e6{animation-delay:250ms}
.inspector-body .k-enter.k-e7{animation-delay:290ms}

/* Selecting a record the current filter hides clears the filter. That is
   the right behaviour, but it used to happen with no acknowledgement, so
   the toolbar silently rewrote itself. This states what happened. */
.filter-notice{
  margin:0;
  padding:9px 18px;
  border-bottom:1px solid #4b3b7d;
  background:linear-gradient(90deg,#2a1a52a8,#1b1f4c8c 60%,transparent);
  color:#cbbdf5;
  font:700 8px var(--mono);
  letter-spacing:.09em;
}
.filter-notice[hidden]{display:none}
.filter-notice b{color:#f3d9ff;font-weight:700}
.filter-notice .filter-notice-mark{color:var(--emit);margin-right:7px}
@media (prefers-reduced-motion:no-preference){
  .filter-notice.is-stating{animation:k-rise-sm 320ms var(--k-ease-out) both}
}

/* Project cards: selection bar travels, hover lifts, arrow leads. */
.project-card{
  transition:background var(--k-fast) linear,box-shadow var(--k-mid) var(--k-ease);
  scroll-margin:120px;
}
.project-card::before{
  transition:transform var(--k-mid) var(--k-ease),box-shadow var(--k-mid) linear,background 200ms linear;
  background:var(--emit);
}
.project-card[aria-pressed="true"]::before{box-shadow:0 0 14px var(--emit)}
.project-card:hover::before{transform:scaleY(.55)}
.project-card[aria-pressed="true"]:hover::before{transform:scaleY(1)}
.project-card[aria-pressed="true"]{box-shadow:inset 3px 0 transparent,0 0 44px -20px var(--emit)}
.project-card .card-title{transition:transform var(--k-mid) var(--k-ease),color var(--k-fast) linear}
.project-card:hover .card-title,
.project-card:focus-visible .card-title{transform:translateX(2px)}
.card-arrow{transition:transform var(--k-mid) var(--k-ease),color var(--k-fast) linear,filter var(--k-mid) linear}
.project-card:hover .card-arrow{filter:drop-shadow(0 0 7px var(--emit));color:#fff}
.project-card:active{transform:scale(.995)}

.list-foot #result-count{transition:color var(--k-mid) linear}
#result-count.is-changed{animation:k-count-pulse 520ms var(--k-ease-out) 1}
@keyframes k-count-pulse{
  0%{transform:translateY(0);color:#fff}
  40%{transform:translateY(-2px)}
  100%{transform:translateY(0)}
}

/* Method console: waveform redraws on stage change. */
.console-graph path{
  stroke-dasharray:1200;
  stroke-dashoffset:0;
  transition:stroke var(--k-mid) linear,filter var(--k-mid) linear;
}
.console-display.is-updating .console-graph path{
  animation:k-trace-redraw 900ms var(--k-ease-out) 1;
}
@keyframes k-trace-redraw{
  0%{stroke-dashoffset:1200;filter:drop-shadow(0 0 0 transparent)}
  45%{filter:drop-shadow(0 0 8px #d76bff)}
  100%{stroke-dashoffset:0}
}
.console-display .console-big,
.console-display #stage-description,
.console-label{transition:opacity var(--k-mid) linear}
.console-display.is-updating .console-big,
.console-display.is-updating #stage-description,
.console-display.is-updating .console-label{animation:k-rise-sm 460ms var(--k-ease-out) both}
.console-display.is-updating .console-big{animation-delay:60ms}
.console-display.is-updating #stage-description{animation-delay:120ms}

/* Principles strip: light sweeps across the three columns in turn. */
.principles>div{transition:background var(--k-slow) linear}
.principles>div::after{
  content:"";
  position:absolute;
  left:0;right:0;top:0;
  height:1px;
  background:linear-gradient(90deg,transparent,var(--emit),transparent);
  transform:scaleX(0);
  transition:transform var(--k-slow) var(--k-ease);
}
.principles>div:hover::after{transform:scaleX(1)}

/* ------------------------------------------------------------------
   8. HERO READOUT — the node signal arrives here
------------------------------------------------------------------ */
.hero-instrument{position:relative}
.instrument-rail{
  position:absolute;
  left:0;top:14%;bottom:24%;
  width:1px;
  pointer-events:none;
  background:linear-gradient(180deg,transparent,#6b4bbf5c 18%,#6b4bbf5c 82%,transparent);
  opacity:0;
}
.rail-bead{
  position:absolute;
  left:-1.5px;
  top:0;
  width:4px;height:26px;
  border-radius:3px;
  background:linear-gradient(180deg,transparent,var(--emit),transparent);
  filter:drop-shadow(0 0 6px var(--emit));
  transform:translate3d(0,var(--bead,0),0);
  opacity:0;
}
.live-readout{position:relative}
.live-readout::after{
  content:"";
  position:absolute;
  left:0;right:0;bottom:0;
  height:1px;
  background:linear-gradient(90deg,transparent,var(--emit) 30%,#6ff0ff 70%,transparent);
  opacity:0;
  transform:scaleX(.3);
  transform-origin:left center;
  transition:opacity var(--k-mid) linear,transform var(--k-slow) var(--k-ease);
}
.live-readout.is-updating::after{opacity:1;transform:scaleX(1)}
.live-readout.is-updating .live-readout-data{animation:k-rise-sm 520ms var(--k-ease-out) both}
.live-readout.is-updating .live-kicker{animation-delay:40ms}

/* ------------------------------------------------------------------
   9. SIGNAL SIGNATURE VIEW — the one canvas on the page
------------------------------------------------------------------ */
.signal-view{
  position:relative;
  z-index:2;
  margin-top:10px;
  padding:11px 19px 13px;
  border-top:1px solid #3b2f66;
  background:linear-gradient(100deg,#1a1240a8,#121a3d8c 60%,#0d1c3a6b);
}
.signal-view-head{
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:10px;
  font:700 8px var(--mono);
  letter-spacing:.11em;
  color:#9d94d8;
}
.signal-view-state{
  color:var(--emit);
  transition:color var(--k-mid) linear;
}
.signal-view-state::before{
  content:"";
  display:inline-block;
  width:5px;height:5px;
  margin-right:6px;
  border-radius:50%;
  background:var(--emit);
  box-shadow:0 0 9px var(--emit);
  vertical-align:middle;
}
#signal-canvas{
  display:block;
  width:100%;
  height:44px;
  margin:8px 0 0;
}
.signal-view-note{
  margin:7px 0 0;
  font:8px/1.5 var(--mono);
  letter-spacing:.04em;
  color:#7d78ad;
}

/* ------------------------------------------------------------------
   10. SYSTEM BAR — real local interface state
------------------------------------------------------------------ */
.system-bar{
  display:flex;
  align-items:center;
  gap:clamp(14px,3vw,38px);
  flex-wrap:wrap;
  margin-left:72px;
  padding:11px clamp(26px,4.4vw,74px);
  border-top:1px solid #3a2d63;
  background:linear-gradient(90deg,#0d0d2a,#131037 54%,#0c1430);
  font:700 8px var(--mono);
  letter-spacing:.1em;
  color:#8e8cc4;
}
.system-bar b{color:#ded8ff;font-weight:700}
.system-bar-label{color:#6f6aa4}
.system-bar-item{display:inline-flex;align-items:center;gap:7px}
.system-bar-tail{margin-left:auto;color:#7c79ad}
.status-dot{
  width:6px;height:6px;border-radius:50%;
  background:#42f2d0;
  box-shadow:0 0 10px #2fe6c4;
  animation:k-beat 2.4s ease-in-out infinite;
}
@keyframes k-beat{50%{opacity:.45;transform:scale(.82)}}
body.ambient-off .status-dot{animation:none;background:#7f88a8;box-shadow:none}

/* ------------------------------------------------------------------
   11. TOUCH — equivalent function, larger targets
------------------------------------------------------------------ */
@media (hover:none){
  .node{padding:4px 2px}
  .node-point{box-shadow:inset 0 0 0 3px #181239}
  .node:active{transform:translate3d(2px,0,0) scale(1.03)}
  .filter-button{min-height:40px;padding-inline:14px}
  .process-step{min-height:52px}
  .dock-item{min-height:56px}
  .button{min-height:50px}
  .project-card{min-height:96px}
}

/* ------------------------------------------------------------------
   12. FX OFF — decorative layer genuinely stops
------------------------------------------------------------------ */
body.ambient-off .circuit-field,
body.ambient-off .signal-view,
body.ambient-off .node.is-focus-host::after{display:none!important}

/* chroma.css and os.css already try to stop the global decorators, but
   earlier `!important` rules (for instance on .method-small) outspecificity
   those attempts, so the kill switch is restated here at full strength. */
body.ambient-off .scan-sweep,
body.ambient-off .orbit-outer,
body.ambient-off .orbit-mid,
body.ambient-off .orbit-breathe,
body.ambient-off .ambient-aurora i,
body.ambient-off .energy-arc{animation:none!important}
body.ambient-off .spectral-scale .scale-lights i,
body.ambient-off .chromatic-orbits *,
body.ambient-off .field-celestials i{transition:none!important}
body.ambient-off .rail-bead,
body.ambient-off .heat-ring{opacity:0!important}
body.ambient-off .field-link.live{
  stroke-opacity:.24;
  animation:none!important;
  filter:none;
  stroke-dasharray:none;
}
body.ambient-off .link-pulse{display:none}
body.ambient-off .core-flare{animation:none!important;opacity:0}
body.ambient-off .node[aria-pressed="true"] .node-point{animation:none;box-shadow:0 0 0 5px #b66aff26,0 0 16px var(--emit)}
body.ambient-off .inspector::after,
body.ambient-off .atlas-list-col::after,
body.ambient-off .method-console::after{display:none}
body.ambient-off .inspector.is-updating{box-shadow:0 22px 75px #0005}
body.ambient-off *,
body.ambient-off *::before,
body.ambient-off *::after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:120ms!important}

/* ------------------------------------------------------------------
   13. LOW-POWER TIER — set by app.js when frames are missed
------------------------------------------------------------------ */
body[data-tier="low"] .circuit-field,
body[data-tier="low"] .field-celestials,
body[data-tier="low"] .hero-noise,
body[data-tier="low"] .signal-view{display:none}
body[data-tier="low"] .ambient-aurora i{animation:none;opacity:.32}
body[data-tier="low"] .scan-sweep{animation-duration:48s}
body[data-tier="low"] .orbit-outer,body[data-tier="low"] .orbit-mid{animation-duration:120s}
body[data-tier="low"] .pulse-run-2{display:none}
body[data-tier="low"] .energy-arc{animation:none}

/* ------------------------------------------------------------------
   14. RESPONSIVE
------------------------------------------------------------------ */
@media(max-width:1060px){
  .system-bar{margin-left:0}
}
@media(max-width:920px){
  .hero-instrument{position:relative}
  body[data-pointer="on"] .instrument-rail{display:none}
  .signal-view{padding-inline:22px}
  .circuit-field{opacity:.34}
}
@media(max-width:650px){
  .system-bar{
    padding:10px 14px;
    gap:10px 16px;
    font-size:7px;
  }
  .system-bar-tail{display:none}
  .signal-view{padding:10px 15px 12px}
  #signal-canvas{height:38px}
  .signal-view-note{display:none}
  .node[aria-pressed="true"]{transform:none}
  .node:hover{transform:none}
  .node-name{letter-spacing:.03em}
  .node[aria-pressed="true"] .node-name{letter-spacing:.04em}
}
@media(max-width:370px){
  .system-bar{justify-content:space-between}
  .system-bar-item:nth-child(2){display:none}
}

/* ------------------------------------------------------------------
   15. REDUCED MOTION — all decoration resolves to a static state
------------------------------------------------------------------ */
@media (prefers-reduced-motion:reduce){
  .circuit-run{stroke-dasharray:none;stroke-dashoffset:0;animation:none!important}
  .circuit-dash{animation:none!important;stroke-dasharray:26 300;stroke-dashoffset:0}
  /* No travel: the selected connection becomes a full, calm bright line. */
  .field-link.live{animation:none!important;transition:none!important}
  .field-link.live.is-charged,
  .field-link.live.is-live{--dash:100;--gap:0;stroke-opacity:.5}
  .field-link.live.is-resting{stroke-opacity:.18}
  .link-pulse{display:none;animation:none!important}
  .rail-bead,.core-flare,.heat-ring{display:none}
  .node[aria-pressed="true"] .node-point{animation:none}
  .status-dot{animation:none}
  .inspector-body .k-enter,
  .is-revealing .k-reveal,
  .hero-content>*,
  .notice-strip,.site-header,.os-dock,.hero-instrument{animation:none!important;opacity:1!important;transform:none!important}
}
