/*
 * Lead Trajectory.
 *
 * Same rules as every component stylesheet: design-system `--btx-*` tokens
 * only, a fallback on every var(). See cta-button/style.css for the full note.
 *
 * Everything geometric is in the SVG's own user units and lives in the render
 * callback. What is here is colour, type, the two schemes, and the draw-on.
 *
 * ONE DELIBERATE EXCEPTION TO "TOKENS ONLY": the source note is set in
 * `monospace`. The design system publishes a heading family and a body family
 * and no third, so a mono face cannot come from a token today. The generic
 * keyword is the smallest possible version of that exception — no font file, no
 * new size, no new colour, all three of which are still tokens below. If a mono
 * family is ever added to the DSM, this is the one declaration to change.
 *
 * The colours are not free choices. Each scheme's accent/muted pair was checked
 * for colour-vision separation against that scheme's surface; the values and
 * their margins are recorded in component.php. Re-picking either one without
 * re-checking the pair is how a chart becomes two identical grey lines for
 * roughly one man in twelve.
 */

@layer bertex-components {

	/* ── Shell ─────────────────────────────────────────────────────────── */

	.btxc-trajectory {
		margin: 0;
		box-sizing: border-box;
		display: flex;
		flex-direction: column;
		gap: var(--btx-spacing-s, 0.65rem);

		/* Establishes the query container the responsive rules at the bottom
		 * of this file measure. Without it they never match and the chart
		 * keeps desktop type at every size. */
		container-type: inline-size;

		font-family: var(--btx-font-body-family, system-ui, sans-serif);

		/*
		 * Local channels, set per scheme below and consumed by the marks. The
		 * chart does not paint a surface of its own — it sits on whatever
		 * section holds it, including the hero's gradient — so there is no
		 * `background` here and no surface-coloured ring on any mark. A ring
		 * would have to guess one colour out of a gradient and would read as a
		 * halo everywhere it guessed wrong. The marks are far enough apart not
		 * to need one; the only two that would have overlapped, the launch
		 * points of both series, are drawn as a single shared dot instead.
		 */
		/*
		 * Light surface. The growing line is the brand green, stepped down the
		 * ramp because the base token is a 2:1 wash on cream — bright enough on
		 * a dark panel, not nearly enough on paper.
		 *
		 * The second line is NOT the brand yellow here, and that is measured
		 * rather than preferred. On cream the base yellow is 1.18:1, which is
		 * invisible; darkening it far enough to be legible walks it into the
		 * green, and the two end up ΔE 11.4 apart — under the 15 floor, which
		 * means ordinary full-colour vision struggles to tell them apart. There
		 * is no step of that ramp that is both visible on cream and distinct
		 * from the green, so light keeps the recessive line.
		 *
		 * That line used to name `text-bg-2-light-50` and `-light-60`, which the
		 * DSM has never emitted — lightening a slot that starts at 90.6% clips —
		 * so for as long as this palette has been in place both schemes painted
		 * the hard-coded grey in the var() instead, and the ΔE figures in the
		 * README were measured against that grey. `text-bg-2-dark-60` is the
		 * darkest step the slot does emit: 2.32:1 on paper and 6.12:1 on the
		 * navy, quiet on both, and already proven as the recessive graphic
		 * channel in management-model. It is a background slot doing graphic
		 * work, which is allowed; what it must never do is carry type.
		 * THE SEPARATION FROM THE GREEN HAS NOT BEEN RE-RUN — see the README.
		 */
		--btxc-trajectory-accent: var(--btx-color-primary-2-dark-20, #3f8f4a);
		--btxc-trajectory-muted: var(--btx-color-text-bg-2-dark-60, #8fa8cf);
		--btxc-trajectory-ink: var(--btx-color-primary-1, #1a2744);
		--btxc-trajectory-ink-quiet: var(--btx-color-primary-1-light-40, #2e4578);
		--btxc-trajectory-rule: var(--btx-color-text-bg-1-dark-40, #d1d3d4);
	}

	/*
	 * A dark panel inside the light palette — the hero paints its own navy
	 * inline rather than switching the design system to dark mode, so the ink
	 * ramp here is still the light one and the paper ramp is what inverts. That
	 * is the same reasoning hero/style.css uses for its own `--dark` rules.
	 */
	/*
	 * Dark panel — a hero paints its own background rather than switching the
	 * design system to dark mode, so the ink ramp here is still the light one
	 * and it is the paper ramp that inverts. Same reasoning as hero/style.css.
	 *
	 * Both series wear brand colour here, and the pair was measured on the hero
	 * navy before it shipped: ΔE 19.8 to ordinary vision and 15.3 at worst-case
	 * colour blindness, comfortably clear of the floors.
	 *
	 * One thing to know if the palette ever moves. Green against a *bright*
	 * yellow is a safe pair; green against a muted GOLD is not — that lands at
	 * ΔE 5.4 under deuteranopia, which is two identical lines for roughly one
	 * man in twelve. If secondary-1 is ever retuned toward gold, this pairing
	 * has to be re-measured, and the honest answer then is the neutral variant
	 * below.
	 *
	 * The fallback hexes are estimates of the live palette read off a rendered
	 * page, not values from the Tokens tab. They apply only when the plugin is
	 * inactive, but correct them if you are passing anyway.
	 */
	.btxc-trajectory--dark {
		--btxc-trajectory-accent: var(--btx-color-primary-2, #5dc264);
		--btxc-trajectory-muted: var(--btx-color-secondary-1, #e3ea4d);
		--btxc-trajectory-ink: var(--btx-color-text-bg-1, #f6f3ee);
		--btxc-trajectory-ink-quiet: var(--btx-color-text-bg-1-dark-20, rgba(246, 243, 238, 0.7));
		--btxc-trajectory-rule: var(--btx-color-text-bg-1-dark-30, rgba(246, 243, 238, 0.25));
	}

	/*
	 * Neutral: the declining series drops back to grey.
	 *
	 * Two brand colours make two peers, and the argument this chart exists to
	 * make is that one of these is not a peer. Weight still separates them —
	 * the accent line is thicker and carries the area wash — but colour is the
	 * louder channel, and in brand mode it is saying "two options" while the
	 * shape says "one is dying". Reach for this where that matters more than
	 * matching the section's palette.
	 *
	 * Ordered after both scheme rules so it wins in either. On light this is
	 * already what `brand` resolves to, for the contrast reason noted above.
	 */
	.btxc-trajectory--accent-neutral {
		--btxc-trajectory-muted: var(--btx-color-text-bg-2-dark-60, #8fa8cf);
	}

	.btxc-trajectory--dark.btxc-trajectory--accent-neutral {
		--btxc-trajectory-muted: var(--btx-color-text-bg-2-dark-60, #8fa8cf);
	}

	/* ── The SVG box ───────────────────────────────────────────────────── */

	/*
	 * Height comes from the aspect ratio, not from the content, so the element
	 * occupies its final box before the paths paint and nothing below it moves.
	 * The ratio matches the viewBox; change one and change the other.
	 */
	.btxc-trajectory__svg {
		display: block;
		width: 100%;
		height: auto;
		aspect-ratio: 720 / 424;

		/*
		 * Nothing is drawn outside the viewBox — the right margin is sized so
		 * that even the largest end-point value clears it. This is here so that
		 * if a future label does grow past the edge it sticks out visibly
		 * instead of being silently cropped mid-digit, which is the failure
		 * nobody notices. The hero's own `overflow: hidden` is the backstop.
		 */
		overflow: visible;
	}

	/* ── Grid and axis ─────────────────────────────────────────────────── */

	/* Hairline, solid, one step off the surface. Never dashed. */
	.btxc-trajectory__baseline,
	.btxc-trajectory__axis {
		stroke: var(--btxc-trajectory-rule);
		stroke-width: 1;
		fill: none;
	}

	.btxc-trajectory__tick,
	.btxc-trajectory__baseline-label {
		fill: var(--btxc-trajectory-ink-quiet);
		font-size: 14px;
		font-variant-numeric: tabular-nums;
	}

	.btxc-trajectory__baseline-label {
		font-size: 13px;
		letter-spacing: 0.04em;
		text-transform: uppercase;
	}

	/* ── Series ────────────────────────────────────────────────────────── */

	.btxc-trajectory__line {
		fill: none;
		stroke-linecap: round;
		stroke-linejoin: round;
	}

	/*
	 * Thinner as well as greyer. Weight is the second channel telling a reader
	 * which of these two is the claim and which is the thing being compared to
	 * — it survives greyscale printing, where the colours do not.
	 */
	.btxc-trajectory__line--a {
		stroke: var(--btxc-trajectory-muted);
		stroke-width: 2;
	}

	.btxc-trajectory__line--b {
		stroke: var(--btxc-trajectory-accent);
		stroke-width: 2.75;
	}

	/* A wash, not a block — and bounded by the 100 line, so it reads as gain. */
	.btxc-trajectory__area {
		fill: var(--btxc-trajectory-accent);
		opacity: 0.1;
		stroke: none;
	}

	.btxc-trajectory__origin {
		fill: var(--btxc-trajectory-ink-quiet);
	}

	.btxc-trajectory__dot--a {
		fill: var(--btxc-trajectory-muted);
	}

	.btxc-trajectory__dot--b {
		fill: var(--btxc-trajectory-accent);
	}

	/* ── Labels ────────────────────────────────────────────────────────── */

	/*
	 * Ink, never the series colour. The line arriving at the number is what
	 * says which series it belongs to; colouring the text as well would make
	 * the accent value harder to read and would not add any information.
	 *
	 * Proportional figures, not tabular: these are two standalone display
	 * numbers, and equal-width digits make a three-digit value look gappy at
	 * this size. The tick labels and the table below get tabular instead,
	 * because those are numbers in a column.
	 */
	.btxc-trajectory__endval {
		fill: var(--btxc-trajectory-ink);
		dominant-baseline: middle;
		font-weight: 700;
	}

	.btxc-trajectory__endval--b {
		font-size: 30px;
	}

	.btxc-trajectory__endval--a {
		font-size: 21px;
		fill: var(--btxc-trajectory-ink-quiet);
	}

	/* ── Legend ────────────────────────────────────────────────────────── */

	/* Wraps to two lines rather than overlapping — the whole reason this is
	 * HTML and not two <text> nodes at fixed viewBox coordinates. */
	.btxc-trajectory__legend {
		margin: 0;
		display: flex;
		flex-wrap: wrap;
		gap: var(--btx-spacing-xs, 0.45rem) var(--btx-spacing-lg, 1.5rem);

		font-size: var(--btx-font-body-s, 0.875rem);
		line-height: var(--btx-line-height-body, 1.6);
		color: var(--btxc-trajectory-ink);
	}

	.btxc-trajectory__legend-item {
		display: inline-flex;
		align-items: center;
		gap: var(--btx-spacing-xs, 0.45rem);
	}

	/* The line-key repeats the mark it stands for, weight included: the accent
	 * key is thicker exactly as the accent line is. */
	.btxc-trajectory__key {
		flex: none;
		width: 1.375rem;
		border-radius: var(--btx-border-radius-round, 9999px);
	}

	.btxc-trajectory__key--a {
		height: 2px;
		background-color: var(--btxc-trajectory-muted);
	}

	.btxc-trajectory__key--b {
		height: 3px;
		background-color: var(--btxc-trajectory-accent);
	}

	/* ── Caption ───────────────────────────────────────────────────────── */

	/*
	 * Out here as HTML rather than as <text> in the SVG. Inside, it would scale
	 * with the viewBox down to about six pixels at 375px, and it could not wrap
	 * — SVG text does not. As HTML it wraps, it stays at a readable size, and
	 * it is selectable and translatable like any other prose on the page.
	 */
	.btxc-trajectory__caption {
		display: flex;
		flex-direction: column;
		gap: var(--btx-spacing-xxs, 0.3rem);
		line-height: var(--btx-line-height-body, 1.6);
	}

	.btxc-trajectory__measure {
		font-size: var(--btx-font-body-s, 0.875rem);
		color: var(--btxc-trajectory-ink-quiet);
	}

	.btxc-trajectory__source {
		/* See the exception noted at the top of this file. */
		font-family: monospace;
		font-size: var(--btx-font-body-xs, 0.8rem);
		color: var(--btxc-trajectory-ink-quiet);
	}

	/* ── Table ─────────────────────────────────────────────────────────── */

	/*
	 * Visually hidden, not display:none — the numbers behind the picture have
	 * to reach a screen reader, and `display:none` would take them out of the
	 * accessibility tree along with the pixels.
	 *
	 * This is on the wrapping <div>, never on the <table> itself. See the note
	 * in component.php: a table's caption and header row belong to the table
	 * wrapper box, so clipping the table does not reliably clip them, and on a
	 * real site they escaped and painted over the legend.
	 *
	 * `!important` on the containment properties, which is not decoration
	 * either. WordPress prints theme.json global styles UNLAYERED, and an
	 * unlayered rule beats every cascade layer no matter its specificity — so a
	 * global `table { width: 100% }` or a `figure > *` rule can undo this from
	 * outside and the failure is a wall of numbers across the chart. These four
	 * are the ones that must survive that; everything else here stays normal.
	 */
	.btxc-trajectory__table {
		position: absolute !important;
		width: 1px !important;
		height: 1px !important;
		overflow: hidden !important;
		margin: -1px;
		padding: 0;
		border: 0;
		clip-path: inset(50%);
		white-space: nowrap;
	}

	/* ── Responsive ────────────────────────────────────────────────────── */

	/*
	 * The curve shape never changes — it is one viewBox at every width. Only
	 * two things happen as the box narrows: type grows in user units so that it
	 * still lands at a readable pixel size once the whole drawing has been
	 * scaled down, and the labels that were only ever supplementary go away.
	 *
	 * CONTAINER queries, not media queries, and the difference is not
	 * theoretical here. This chart's whole reason to exist is sitting in one
	 * half of a split hero, so at a 1200px viewport it is about 500px wide. A
	 * viewport query would still be applying desktop type to it and the labels
	 * would be scaled down to roughly nine pixels — the exact case this rule
	 * exists to catch, and the one a viewport query misses.
	 *
	 * What survives at the narrowest tier, in priority order: the two curves,
	 * the two end-point values, the legend, the span of the x axis, and the
	 * source note. What goes: the interior month ticks and the "100 at launch"
	 * annotation, both of which restate something the shape already shows.
	 */
	@container (max-width: 560px) {
		.btxc-trajectory__tick {
			font-size: 18px;
		}

		.btxc-trajectory__baseline-label {
			font-size: 16px;
		}

		.btxc-trajectory__endval--b {
			font-size: 36px;
		}

		.btxc-trajectory__endval--a {
			font-size: 26px;
		}
	}

	@container (max-width: 400px) {
		.btxc-trajectory__drop-narrow {
			display: none;
		}

		.btxc-trajectory__tick {
			font-size: 24px;
		}

		.btxc-trajectory__endval--b {
			font-size: 46px;
		}

		.btxc-trajectory__endval--a {
			font-size: 34px;
		}
	}

	/* ── Draw-on ───────────────────────────────────────────────────────── */

	/*
	 * On load rather than on scroll, and on purpose: this is a hero graphic, so
	 * it is already in the viewport when the page paints and the two triggers
	 * fire at the same moment. Doing it in CSS keeps the component free of
	 * JavaScript entirely — an IntersectionObserver here would be a script
	 * loaded on every page to watch an element that is above the fold.
	 *
	 * pathLength="1" in the markup is what lets both curves share one dash
	 * value and finish together despite having different arc lengths.
	 *
	 * The muted series is drawn first and finishes first. The accent series
	 * starts with it but runs longer, so the last thing that moves is the line
	 * that is still climbing.
	 */
	.btxc-trajectory--animate .btxc-trajectory__line {
		stroke-dasharray: 1;
		stroke-dashoffset: 1;
		animation: btxc-trajectory-draw 1.4s cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
	}

	.btxc-trajectory--animate .btxc-trajectory__line--b {
		animation-duration: 1.9s;
	}

	/* Everything that annotates the curves waits for them. */
	.btxc-trajectory--animate .btxc-trajectory__area,
	.btxc-trajectory--animate .btxc-trajectory__dot,
	.btxc-trajectory--animate .btxc-trajectory__endval {
		opacity: 0;
		animation: btxc-trajectory-fade 0.5s ease-out 1.5s forwards;
	}

	.btxc-trajectory--animate .btxc-trajectory__area {
		animation-name: btxc-trajectory-fade-area;
	}

	@keyframes btxc-trajectory-draw {
		to {
			stroke-dashoffset: 0;
		}
	}

	@keyframes btxc-trajectory-fade {
		to {
			opacity: 1;
		}
	}

	/* The wash lands at its 10%, not at full strength. */
	@keyframes btxc-trajectory-fade-area {
		to {
			opacity: 0.1;
		}
	}
}

/* ── Reduced motion ──────────────────────────────────────────────────────── */

/*
 * Not "a faster animation" — no animation, and the finished chart on the first
 * frame. Cancelling the animation is not enough on its own: the dash offset and
 * the zero opacity are the animation's starting state, so they have to be put
 * back by hand or the chart animates to visible and then stays invisible.
 */
@media (prefers-reduced-motion: reduce) {
	@layer bertex-components {
		.btxc-trajectory--animate .btxc-trajectory__line {
			animation: none;
			stroke-dasharray: none;
			stroke-dashoffset: 0;
		}

		.btxc-trajectory--animate .btxc-trajectory__dot,
		.btxc-trajectory--animate .btxc-trajectory__endval {
			animation: none;
			opacity: 1;
		}

		.btxc-trajectory--animate .btxc-trajectory__area {
			animation: none;
			opacity: 0.1;
		}
	}
}
