/* The dots (scripts/dots.js): the layer they fly on, and what a target looks
   like while the dots serve it. Every size and time is a token in
   variables.css (--dots-*), set from /sandbox/dots/.

   A target is marked data-dots="busy" while its call is out, "tracing"
   while the dots trace its result (data-dots-trace says what kind), and
   "revealing" for as long as it takes to come back in. */

/* ── The layer ───────────────────────────────────────────────────────
   Over the whole screen and the nav (the nav's buttons are targets too),
   never catching a tap. The dots are sized and placed by the script. */
.tdc-dots {
	position: fixed;
	inset: 0;
	z-index: 1000;
	overflow: hidden;
	pointer-events: none;
}
.tdc-dots canvas {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
}
/* The lines a number's or a tab's dots trace, drawn here by the script and
   faded in as a whole, then crossfaded into the real thing. */
.tdc-dots-lines {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	overflow: visible;
	fill: none;
	stroke-linecap: round;
	stroke-linejoin: round;
}
.tdc-dot {
	position: absolute;
	left: 0;
	top: 0;
	border-radius: var(--radius-round);
	opacity: 0;
	will-change: transform, opacity;
}

/* ── A ring icon ─────────────────────────────────────────────────────
   Its ring hides and its icon dims while it waits; both come back in
   --dots-reveal, which the script reads to know when the ring is fully in.
   data-dots-ring is set by the script on a target that is a ring icon (a
   button, a switch, a ring), so a section that only holds some (a planner
   of fixture buttons loading with the page) dims as a whole instead. */
[data-dots="busy"][data-dots-ring] .tdc-ring .ring { opacity: 0; transition: opacity var(--dots-dim) ease; }
[data-dots="busy"][data-dots-ring] .tdc-ring .mark { opacity: var(--dots-busy-dim); transition: opacity var(--dots-dim) ease, stroke-dashoffset 0.35s ease; }
[data-dots="revealing"][data-dots-ring] .tdc-ring .ring { transition: opacity var(--dots-reveal) ease; }
[data-dots="revealing"][data-dots-ring] .tdc-ring .mark { transition: opacity var(--dots-reveal) ease, stroke-dashoffset 0.35s ease; }

/* ── Anything else ───────────────────────────────────────────────────
   Its outline hides and the whole of it dims. !important because a
   button's border can be (.btn-secondary). */
[data-dots="busy"]:not([data-dots-ring]):not([data-dots-hold]):not([data-dots-ink]) {
	opacity: var(--dots-busy-dim);
	border-color: transparent !important;
	transition: opacity var(--dots-dim) ease, border-color var(--dots-dim) ease;
}
[data-dots="revealing"]:not([data-dots-ring]) {
	transition: opacity var(--dots-reveal) ease, border-color var(--dots-reveal) ease;
}

/* Something loading with the page (track) is not shown at all until it is
   loaded and ready to use (UV, 28 Oct): the dots stand in for it, and it
   fades in when it is back. */
[data-dots="busy"][data-dots-load] { opacity: 0 !important; transition: opacity var(--dots-dim) ease; }
[data-dots="revealing"][data-dots-load] { transition: opacity var(--dots-reveal) ease; }

/* A button, or a dropdown pill's green pill, keeps some of its colour
   while it waits and while the dots trace it (UV, 28 Oct: at --dots-busy-dim
   its words, the colour of the page behind, all but vanished), and the
   chosen option's words turn cream until the pill is full again. */
.btn[data-dots="busy"]:not([data-dots-ring]):not([data-dots-hold]):not([data-dots-ink]),
.tdc-select-thumb[data-dots="busy"]:not([data-dots-ring]):not([data-dots-hold]):not([data-dots-ink]),
.tdc-select-thumb[data-dots="tracing"] {
	opacity: var(--dots-busy-fill);
}
.tdc-select:has(.tdc-select-thumb[data-dots]) .tdc-select-option.is-selected { color: var(--text-primary); }

/* ── Digits that are a part of the target (opts.ink) ────────────────
   A stepper's number, a score in its button: only they dim while it
   waits, and only they fade in under the dots, so the chevrons and the
   button stay put. data-dots-hold (a finger still on it) keeps them lit. */
[data-dots="busy"][data-dots-ink]:not([data-dots-hold]) [data-dots-inked] {
	opacity: var(--dots-busy-dim);
	transition: opacity var(--dots-dim) ease;
}
[data-dots="revealing"][data-dots-ink] [data-dots-inked] {
	transition: opacity var(--dots-reveal) ease;
}

/* ── Tracing ─────────────────────────────────────────────────────────
   The call is back and its result is on the page while the dots trace it.
   A ring icon's marks and a number (in its own font: nothing else is drawn,
   UV 26 Oct) fade in as a whole (--dots-lines, 0 to 1, set by the script),
   and the icon's ring stays hidden until the reveal. A tab stays faint and
   unfilled while its pill is traced, then fills. */
[data-dots="tracing"][data-dots-ring] .tdc-ring .ring { opacity: 0; }
[data-dots="tracing"][data-dots-ring] .tdc-ring .mark { opacity: var(--dots-lines, 0); transition: none; }
[data-dots="tracing"][data-dots-trace="number"]:not([data-dots-ink]),
[data-dots="tracing"][data-dots-ink] [data-dots-inked] {
	opacity: var(--dots-lines, 0);
	transition: none;
}
[data-dots="tracing"][data-dots-trace="tab"]:not(.tdc-select-thumb) {
	opacity: var(--dots-busy-dim);
	background: transparent !important;
	color: var(--text-primary) !important;
}
[data-dots="revealing"][data-dots-trace="tab"] {
	transition: opacity var(--dots-reveal) ease, background-color var(--dots-reveal) ease, color var(--dots-reveal) ease;
}

/* ── Reduced motion (spec §14) ──────────────────────────────────────
   No dots. A tapped target breathes while its call is out
   (data-dots-calm, set by the script when the device asks for less motion
   or the page's root says data-motion="reduce"): a ring icon's ring, else
   the whole element. Opacity only, nothing moves. The pulse waits for the
   dimming (--dots-dim) and starts from where it left the target, so nothing
   jumps; when the call is back the target fades in (revealing) from
   wherever the pulse has got to. Something loading with the page only dims
   (UV, 26 Oct). */
[data-dots="busy"][data-dots-calm][data-dots-ring] .tdc-ring .ring {
	animation: dots-pulse-ring var(--dots-pulse) ease-in-out var(--dots-dim) infinite;
}
[data-dots="busy"][data-dots-calm]:not([data-dots-ring]) {
	animation: dots-pulse var(--dots-pulse) ease-in-out var(--dots-dim) infinite;
}
@keyframes dots-pulse {
	0%, 100% { opacity: var(--dots-busy-dim); }
	50% { opacity: var(--dots-pulse-peak); }
}
@keyframes dots-pulse-ring {
	0%, 100% { opacity: 0; }
	50% { opacity: var(--dots-pulse-peak); }
}

/* ── A failure ───────────────────────────────────────────────────────
   "TDC (Error): …" when the page gave the dots no status line of its own:
   at the foot of the screen, over everything, for a few seconds. The line
   inside is the site's own .status.error (set by TDC.error). */
.tdc-dots-error {
	position: fixed;
	left: var(--space-4);
	right: var(--space-4);
	bottom: calc(var(--space-4) + env(safe-area-inset-bottom, 0px));
	z-index: 1001;
	display: flex;
	justify-content: center;
	pointer-events: none;
	opacity: 0;
	transition: opacity var(--dots-reveal) ease;
}
.tdc-dots-error[data-shown] { opacity: 1; }
.tdc-dots-error .status {
	margin: 0;
	max-width: 36rem;
	padding: var(--space-2) var(--space-3);
	background: var(--bg-base);
	border: 1px solid var(--color-error);
	border-radius: var(--radius-md);
	overflow-wrap: anywhere;
}

/* Where the dots sit while a folding group loads (TDC.groupDots, UV 29 Oct):
   on the heading's + / – at its right end (forms.css), which hides while
   they are there. The spot is never seen itself: its outline is
   transparent, so only its width counts (the dots' size), and the dots take
   its text colour, the site's green. Not quite square, or the ring margin
   round a square would be added and the ring outgrow the heading. */
summary:has(> .group-dots) { position: relative; }
summary:has(> .group-dots[data-dots])::after { opacity: 0; }
.group-dots {
	position: absolute;
	right: 0;
	top: 50%;
	width: var(--group-dots-size);
	height: calc(var(--group-dots-size) - 2px);
	transform: translateY(-50%);
	box-sizing: border-box;
	border: var(--group-dots-stroke) solid transparent;
	border-radius: var(--radius-round);
	color: var(--color-primary);
	pointer-events: none;
}
