/* ===========================================================================
   FS - THE TRACE

   The signature motif: a continuous line routing orthogonally between NAMED
   endpoints. Reads as a PCB trace, a transit map, a network route, and a
   distributed trace in observability tooling - all of which say "engineered
   systems", none of which is an AI cliche.

   THE RULE: every node carries a real system name or a real outcome. No
   unlabelled decorative nodes, ever. That label is the entire difference
   between information design and circuit-board clip art.
   =========================================================================== */

.fs-trace {
	position: relative;
	inline-size: 100%;
}

.fs-trace__svg {
	display: block;
	inline-size: 100%;
	height: auto;
	overflow: visible;
}

/* ---------------------------------------------------------------------------
   LINES
   --------------------------------------------------------------------------- */

.fs-trace__line {
	fill: none;
	stroke: var(--fs-trace-line);
	stroke-width: 1;
	stroke-linecap: butt;
	transition: opacity var(--fs-duration-fast) var(--fs-ease);
}

/* Every density draws at 1px now, so the inline override is redundant. */

/* ---------------------------------------------------------------------------
   PULSE
   A short lit segment travelling the full route. stroke-dasharray and the
   travel distance are set per-path from getTotalLength() in trace.js, because
   every route is a different length - a single hard-coded dash offset would
   make short routes finish early and long ones never arrive.

   Glow is the one permitted glow in the system, and only from the Trace.
   --------------------------------------------------------------------------- */

.fs-trace__pulse {
	fill: none;
	stroke: var(--fs-rose);
	stroke-width: 2;
	stroke-linecap: butt;
	opacity: 0;
}

.fs-trace__pulse.is-firing {
	opacity: 1;
}

.fs-section--dark .fs-trace__pulse,
.fs-card--dark .fs-trace__pulse {
	stroke: var(--fs-rose-lift);
}

/* ---------------------------------------------------------------------------
   NODES
   --------------------------------------------------------------------------- */

/* Endpoints are FILLED SQUARES with no stroke - filled reads as definite.
   Circles are reserved for junctions, and a junction only exists where a
   route genuinely divides. In the current parallel-trace geometry no route
   shares a segment with another, so there are no junctions and therefore no
   circles. A circle that is not a decision point is decoration. */
.fs-trace__dot {
	/* var(--fs-ink) directly, NOT via an alias declared on :root. A custom
	   property resolves its var() references on the element that DECLARES it,
	   then inherits the resolved value - so an alias defined at :root freezes
	   the light-ground ink and never picks up the dark section's remap. This
	   painted the squares near-black on near-black. */
	fill: var(--fs-ink);
	stroke: none;
	transition: fill var(--fs-duration-fast) var(--fs-ease);
}

.fs-trace__label {
	fill: var(--fs-muted);
	font-family: var(--fs-font-mono);
	font-size: 12px;
	letter-spacing: 0.02em;
	transition: fill var(--fs-duration-fast) var(--fs-ease);
}

.fs-trace--inline .fs-trace__label {
	font-size: 10px;
}

/* Engine block - the FastSource core. */
/* Machinery is a rectangle. The paper fill is deliberate: a pulse passing
   through a product vanishes inside it and re-emerges on the far side, which
   reads as the item being handled rather than merely passing by. */
.fs-trace__engine-box,
.fs-trace__product-box {
	fill: var(--fs-bg);
	stroke: var(--fs-border-strong);
	stroke-width: 1;
	transition: stroke var(--fs-duration-fast) var(--fs-ease);
}

.fs-trace__product-label {
	fill: var(--fs-ink);
	font-family: var(--fs-font-mono);
	font-size: 11px;
	letter-spacing: 0.02em;
	text-anchor: middle;
}

.fs-trace__engine-label {
	fill: var(--fs-ink);
	font-family: var(--fs-font-mono);
	font-size: 12px;
	letter-spacing: 0.02em;
	text-anchor: middle;
}

.fs-trace__engine-sub {
	fill: var(--fs-muted);
	font-family: var(--fs-font-mono);
	font-size: 10px;
	text-anchor: middle;
}

/* ---------------------------------------------------------------------------
   HOVER - "trace a path through my business"
   Routes touching the hovered node stay lit; everything else drops back.
   --------------------------------------------------------------------------- */

.fs-trace.is-focused .fs-trace__route {
	opacity: 0.25;
}

.fs-trace.is-focused .fs-trace__route.is-active {
	opacity: 1;
}

/* Active is a COLOUR change only. A line that thickens on hover is
   performing; a line that changes colour is reporting. */
.fs-trace.is-focused .fs-trace__route.is-active .fs-trace__line {
	stroke: var(--fs-rose);
}

.fs-section--dark .fs-trace.is-focused .fs-trace__route.is-active .fs-trace__line,
.fs-card--dark .fs-trace.is-focused .fs-trace__route.is-active .fs-trace__line {
	stroke: var(--fs-rose-lift);
}

.fs-trace__node {
	cursor: default;
}

.fs-trace__node.is-active .fs-trace__dot {
	fill: var(--fs-rose);
}

.fs-section--dark .fs-trace__node.is-active .fs-trace__dot,
.fs-card--dark .fs-trace__node.is-active .fs-trace__dot {
	fill: var(--fs-rose-lift);
}

.fs-trace__node.is-active .fs-trace__label {
	fill: var(--fs-ink);
}

.fs-trace.is-focused .fs-trace__node:not(.is-active) {
	opacity: 0.4;
}

.fs-trace__node,
.fs-trace__route {
	transition: opacity var(--fs-duration-fast) var(--fs-ease);
}

/* ---------------------------------------------------------------------------
   TICKER
   Decorative by design: it restates what the h1 already says. It is
   aria-hidden and must NEVER be aria-live - a live region firing every 1.6s
   is a screen-reader denial of service.
   --------------------------------------------------------------------------- */

.fs-trace-ticker {
	list-style: none;
	margin: var(--fs-space-md) 0 0;
	padding: 0;
	font-family: var(--fs-font-mono);
	font-size: var(--fs-t-mono);
	line-height: 1.9;
	color: var(--fs-muted);
	min-block-size: calc( 3 * 1.9em );
}

.fs-trace-ticker li {
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	animation: fs-ticker-in var(--fs-duration-base) var(--fs-ease) both;
}

.fs-trace-ticker li:first-child {
	color: var(--fs-rose-ink);
}

.fs-section--dark .fs-trace-ticker li:first-child {
	color: var(--fs-rose-lift);
}

@keyframes fs-ticker-in {
	from {
		opacity: 0;
		transform: translateY(-4px);
	}

	to {
		opacity: 1;
		transform: none;
	}
}

/* ---------------------------------------------------------------------------
   STATIC STATE
   Reduced motion, or no JS. Every line is drawn at rest and the ticker shows
   fixed rows. Nothing that carried meaning is lost - only the movement.
   --------------------------------------------------------------------------- */

.fs-trace.is-static .fs-trace__pulse {
	display: none;
}

@media (prefers-reduced-motion: reduce) {
	.fs-trace__pulse {
		display: none;
	}

	.fs-trace-ticker li {
		animation: none;
	}
}

/* ---------------------------------------------------------------------------
   DENSITIES
   --------------------------------------------------------------------------- */

.fs-trace--inline {
	max-inline-size: 320px;
}

.fs-trace--hero {
	max-inline-size: 560px;
}

/* Mobile gets a purpose-drawn simpler trace, never a shrunk desktop one -
   scaling a 6-route diagram to 390px produces unreadable 6px labels. */
@media (max-width: 767px) {
	.fs-trace--hero .fs-trace__label {
		font-size: 13px;
	}
}
