/* ============================================================================
   Varelyno v10 — the living canvas, styled.

   Every effect below is driven by a custom property the JS writes onto the node
   (--v10-fog, --v10-heat, --v10-depth, --v10-balance), so the paint pass never
   has to touch a stylesheet and a toggle just stops setting the variable.

   Restraint is the whole point. These read at a glance across a full canvas and
   are almost invisible on any single circle — the moment one of them shouts,
   the map stops being calm and starts being a dashboard.
   ========================================================================== */

/* the layer carrying horizons, constellations and trails — behind the edges */
.v10-layer{
  position:absolute;left:0;top:0;width:100%;height:100%;
  pointer-events:none;overflow:visible;z-index:0;
}

/* ---------------------------------------------------------------- horizon
   Deadlines given a place on the map. Deliberately fainter than the zone
   rings, which are structure; these are just information. */
.v10-horizon{
  fill:none;stroke:rgba(24,40,90,.16);stroke-width:1.5;
  stroke-dasharray:1 14;stroke-linecap:round;
}
.v10-horizon.quarter{stroke:rgba(24,40,90,.11);stroke-dasharray:1 20}
.v10-horizon-label{
  fill:rgba(24,40,90,.34);font-size:15px;font-weight:650;letter-spacing:.1em;
  text-transform:uppercase;font-family:inherit;
}
.v10-horizon-label.quarter{fill:rgba(24,40,90,.24)}

/* --------------------------------------------------------- constellations
   The shape a person makes across the projects they are on. Filled so faintly
   that three overlapping people read as a gradient of involvement rather than
   three outlines fighting each other. */
.v10-constellation{
  fill:color-mix(in srgb,var(--cc) 7%,transparent);
  stroke:color-mix(in srgb,var(--cc) 16%,transparent);
  stroke-width:1;stroke-linejoin:round;
}

/* ----------------------------------------------------------------- trails */
.v10-trail{
  fill:none;
  stroke:color-mix(in srgb,var(--tc) 30%,transparent);
  stroke-width:2;stroke-linecap:round;stroke-linejoin:round;
  stroke-dasharray:4 7;
}
.v10-trail-dot{fill:var(--tc)}

/* ============================================================ the circles */

/* Base: every project node gets the transition once, so the effects below can
   animate in as data changes rather than snapping. */
.graph-node.project-node{
  transition:filter .5s ease, opacity .5s ease, box-shadow .45s ease;
}

/* ---- fog of neglect ----
   Saturation floors at 0.46 and opacity at 0.62: quiet must read as quiet, and
   must still be perfectly clickable. A project you cannot see is a project you
   cannot rescue. */
.graph-node.project-node{
  --v10-fog:0;--v10-heat:0;--v10-depth:0;--v10-balance:0;
  filter:saturate(calc(1 - var(--v10-fog) * 0.54 - var(--v10-depth) * 0.18))
         contrast(calc(1 - var(--v10-depth) * 0.12));
  opacity:calc(1 - var(--v10-fog) * 0.38 - var(--v10-depth) * 0.06);
}
/* A dotted edge is the one unmistakable signal that something has gone quiet —
   colour alone would be lost on anyone with reduced colour vision. */
.graph-node.project-node.v10-quiet::after{
  content:'';position:absolute;inset:-7px;border-radius:50%;
  border:1.5px dashed color-mix(in srgb,var(--node) 34%,transparent);
  pointer-events:none;
}

/* ---- heat ----
   A warm bloom UNDER the circle, never on it, so the project's own colour is
   never misreported. This is the one effect meant to be seen from the far side
   of the room. */
.graph-node.project-node.v10-hot::after{
  content:'';position:absolute;
  /* On ::after, not ::before. The dotted ring lives on .project-node::before
     (universe.css) with inset:-14px, and that selector outranks this one, so
     its left/top:-14px leaked onto the bloom and left:50%/top:50% never won —
     the bloom sat ~47px up-and-left of its circle. ::after is uncontested, so
     left/top:50% + translate(-50%,-50%) centres it exactly. Centre with the
     transform ONLY; the keyframe carries the same translate, so do not also
     set the `translate` property here or the two stack to -100%. */
  left:50%;top:50%;transform:translate(-50%,-50%);
  width:calc(var(--project-size,150px) * 1.9);
  height:calc(var(--project-size,150px) * 1.9);
  border-radius:50%;pointer-events:none;z-index:-1;
  background:radial-gradient(circle,
    rgba(237,15,104,calc(var(--v10-heat) * .28)) 0%,
    rgba(240,120,60,calc(var(--v10-heat) * .13)) 42%,
    transparent 68%);
  filter:blur(10px);
  animation:v10-breathe 5.5s ease-in-out infinite;
}
@keyframes v10-breathe{
  0%,100%{transform:translate(-50%,-50%) scale(1);opacity:.85}
  50%    {transform:translate(-50%,-50%) scale(1.07);opacity:1}
}

/* ---- balance ----
   A whisper, not a label: a soft edge-light on the side that owns the work.
   Left-lit = sitting with you. Right-lit = sitting with someone else. */
.graph-node.project-node.v10-mine{
  box-shadow:-9px 0 22px -14px rgba(194,86,127,.75);
}
.graph-node.project-node.v10-owed{
  box-shadow:9px 0 22px -14px rgba(0,179,166,.75);
}

/* ---- something changed ---- */
@keyframes v10-pulse{
  0%  {box-shadow:0 0 0 0 color-mix(in srgb,var(--node) 55%,transparent)}
  70% {box-shadow:0 0 0 26px transparent}
  100%{box-shadow:0 0 0 0 transparent}
}
.graph-node.project-node.v10-changed{animation:v10-pulse 1.6s ease-out 1}

/* --------------------------------------------------------------- respect */
@media(prefers-reduced-motion:reduce){
  .graph-node.project-node.v10-hot::after{animation:none}
  .graph-node.project-node.v10-changed{animation:none}
  .graph-node.project-node{transition:none}
}
html[data-motion=off] .graph-node.project-node.v10-hot::after{animation:none}
html[data-motion=off] .graph-node.project-node.v10-changed{animation:none}

/* Dark themes: the haze has to lift off a dark ground, not sink into it. */
html:is([data-theme=dark],[data-tone="dark"]) .v10-horizon{stroke:rgba(255,255,255,.14)}
html:is([data-theme=dark],[data-tone="dark"]) .v10-horizon-label{fill:rgba(255,255,255,.3)}
html:is([data-theme=dark],[data-tone="dark"]) .graph-node.project-node.v10-hot::after{
  background:radial-gradient(circle,
    rgba(255,120,150,calc(var(--v10-heat) * .34)) 0%,
    rgba(255,170,90,calc(var(--v10-heat) * .16)) 42%,
    transparent 68%);
}

/* A finger is on the map (v10-touch.js): the effects that are expensive to
   repaint at every zoom step rest until it lifts, so the map keeps up. */
#graphViewport.graph-gesturing #graphWorld{will-change:transform}
#graphViewport.graph-gesturing .graph-node,
#graphViewport.graph-gesturing .graph-node *,
#graphViewport.graph-gesturing .graph-edges,
#graphViewport.graph-gesturing .graph-edges *{
  filter:none!important;backdrop-filter:none!important;-webkit-backdrop-filter:none!important;
  animation-play-state:paused!important;transition:none!important}
#graphViewport.graph-gesturing .graph-node{box-shadow:none!important}

/* ---------------------------------------------- QIP and audit on the map
   (v10-ptype.js). A thin ring outside the circle -- solid violet for a QIP,
   dashed teal for an audit -- and a small label on top. */
.graph-node.project-node > .v10-ptype-ring{position:absolute;inset:-14px;border-radius:50%;pointer-events:none;
  border:3px solid color-mix(in srgb,var(--pt) 85%,transparent);box-shadow:0 0 0 6px color-mix(in srgb,var(--pt) 12%,transparent)}
.graph-node.ptype-qip{--pt:#7C5CE7}
.graph-node.ptype-audit{--pt:#0E9AA7}
.graph-node.ptype-audit > .v10-ptype-ring{border-style:dashed}
.graph-node.project-node > .v10-ptype-badge{position:absolute;left:50%;top:-14px;transform:translate(-50%,-50%);z-index:3;pointer-events:none;
  font-size:10.5px;font-weight:800;letter-spacing:.12em;line-height:1;padding:5px 9px 4px;border-radius:999px;white-space:nowrap;
  color:#fff;background:color-mix(in srgb,var(--pt) 80%,#000);box-shadow:0 4px 10px -4px color-mix(in srgb,var(--pt) 70%,transparent),0 0 0 2px #fff}
html[data-tone=dark] .graph-node.project-node > .v10-ptype-badge{box-shadow:0 0 0 2px #10192B}
/* the same label on the Projects cards, beside the name */
.project-card-title .v10-ptype-tag{flex:none;align-self:center;padding:2px 7px;border-radius:6px;font-size:9.5px;letter-spacing:.08em;line-height:1.35}
