/* ══════════════════════════════════════════════════════════════════════════
   DIGITAL UMBRELLA: the Drafted components, at product speed.
   Needs tokens.css. Plain CSS; drafted.js only moves the pen between states.

   The pen has three states, set as data-pen on any container:
     (none)     undrawn: strokes hidden (once drafted.js has marked the page), and a reset back to here never moves
     "drawn"    each stroke draws in order, --i apart
     "lifted"   each stroke leaves the way it came, faster
   Any SVG stroke with pathLength="100" and class du-pen follows it.
   ══════════════════════════════════════════════════════════════════════════ */

/* the family is set on body, not only on a screen's wrapper: menus and dialogs a framework portals
   straight under <body> would otherwise fall back to the browser's serif */
body { font-family: var(--font); }
/* an element that switches theme repaints itself: text colour and ground inherit as computed values, so
   without this a data-theme="light" section kept the dark theme's --ink-2 on paper (1.80:1) */
[data-theme] { background-color: var(--bg); color: var(--ink-2); }

/* ── the pen ──────────────────────────────────────────────────────────── */
/* strokes hide only once drafted.js has run and marked the page (class du-js on <html>): with no
   script, or one that failed to load, every drawing shows finished instead of blank */
.du-pen { fill: none; stroke-dasharray: 100 100; stroke-dashoffset: 0; transition: none; }
.du-js .du-pen { stroke-dashoffset: 100; }
[data-pen="drawn"] .du-pen {
  stroke-dashoffset: 0;
  transition: stroke-dashoffset var(--pen-stroke) var(--ease-pen) calc(min(var(--i, 0), var(--pen-cap)) * var(--pen-stagger));
}
[data-pen="lifted"] .du-pen {
  stroke-dashoffset: -100;
  transition: stroke-dashoffset calc(var(--pen-stroke) * .75) var(--ease-pen) calc(var(--i, 0) * var(--pen-stagger) * .5);
}
/* what appears once its stroke has landed: the runner, a note's words */
.du-after { transition: none; }
.du-js .du-after { opacity: 0; }
[data-pen="drawn"] .du-after { opacity: 1; transition: opacity var(--pen-stroke) ease calc(min(var(--i, 0), var(--pen-cap)) * var(--pen-stagger) + var(--pen-note)); }
[data-pen="lifted"] .du-after { opacity: 0; transition: opacity 120ms ease; }
/* the homepage drawing is the one place the pen takes its time */
.du-show { --pen-stroke: var(--pen-stroke-show); --pen-stagger: var(--pen-stagger-show); --pen-cap: 40; }

/* ── the drawing's inks ─────────────────────────────────────────────── */
.du-ink    { stroke: var(--pen); }
.du-rib    { stroke: var(--pen-2); }
.du-strut  { stroke: var(--amber-line); }
.du-runner { fill: var(--amber-line); }

/* ── button: amber is the action; the pen boxes it in ───────────────── */
.du-btn {
  position: relative; display: inline-flex; align-items: center; justify-content: center; gap: var(--s-2);
  min-height: var(--target); padding: 0 var(--s-5); border: 0; border-radius: var(--r);
  background: var(--amber); color: var(--on-amber); font: 700 15px/1 var(--font); text-decoration: none; cursor: pointer;
  transition: transform 120ms ease;
}
.du-btn--quiet { background: none; color: var(--ink); box-shadow: inset 0 0 0 1.5px var(--edge); }
.du-btn:active { transform: translateY(1px); }
.du-btn:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; }
.du-btn[aria-busy="true"] { pointer-events: none; }
.du-trace { position: absolute; inset: -6px; pointer-events: none; }
.du-trace svg { display: block; width: 100%; height: 100%; overflow: visible; }
.du-trace rect { fill: none; stroke: var(--pen); stroke-width: 1.2; stroke-dasharray: 100 100; stroke-dashoffset: 100; transition: stroke-dashoffset 300ms var(--ease-pen); }
.du-btn:hover .du-trace rect { stroke-dashoffset: 0; }
/* busy: a CSS-only trace, no timer in script; label and width stay put, so lock the button's
   width before setting aria-busy (DESIGN.md 4.2) */
.du-btn[aria-busy="true"]::after {
  content: ""; position: absolute; left: var(--s-4); right: var(--s-4); bottom: 11px; height: 2px; background: currentColor;
  animation: du-busy 900ms var(--ease-pen) infinite;
}
/* disabled: no longer the action, so no amber and no pen; the words stay readable (--ink-3) and the
   outline drops to --rule-2. Say beside it, in words, what would enable it. */
.du-btn:disabled, .du-btn[aria-disabled="true"] { background: none; color: var(--ink-3); box-shadow: inset 0 0 0 1.5px var(--rule-2); cursor: not-allowed; transform: none; }
.du-btn:disabled .du-trace, .du-btn[aria-disabled="true"] .du-trace { display: none; }

/* the busy trace and the inline wait (below) share one loop: drawn from the start, lifted from
   the end, held, repeat */
@keyframes du-busy {
  0%   { transform: scaleX(0); transform-origin: 0 50%; }
  45%  { transform: scaleX(1); transform-origin: 0 50%; }
  50%  { transform: scaleX(1); transform-origin: 100% 50%; }
  95%, 100% { transform: scaleX(0); transform-origin: 100% 50%; }
}

/* ── link: the underline is drawn, not always there ──────────────────
   zero specificity on the bare selector, so any page style still wins over it.
   The ink line is the TOP layer (listed first): with the --edge line listed first, as until 7 Oct 2026,
   the resting line was painted over the ink one and the hover draw was never visible */
.du-link, :where(a:not([class])) {
  color: var(--ink); text-decoration: none; cursor: pointer;
  background-repeat: no-repeat, no-repeat;
  background-image: linear-gradient(var(--ink), var(--ink)), linear-gradient(var(--edge), var(--edge));
  background-position: 0 100%, 0 100%;
  background-size: 0% 1px, 100% 1px;
  transition: background-size var(--pen-stroke) var(--ease-pen);
  /* box-decoration-break defaults to slice: a link wrapped across lines draws across them in order */
}
.du-link:hover, .du-link:focus-visible, :where(a:not([class])):hover, :where(a:not([class])):focus-visible {
  background-size: 100% 1px, 100% 1px;
}
/* navigation is not running text: a bare link in a nav, header, footer, menu, tab list or heading has no
   resting underline, and the pen draws the ink line on hover or focus. An explicit .du-link keeps its line */
:where(nav, header, footer, h1, h2, h3, h4, [role="menu"], [role="tablist"]) :where(a:not([class])) { background-size: 0% 1px, 0% 1px; }
:where(nav, header, footer, h1, h2, h3, h4, [role="menu"], [role="tablist"]) :where(a:not([class])):hover,
:where(nav, header, footer, h1, h2, h3, h4, [role="menu"], [role="tablist"]) :where(a:not([class])):focus-visible { background-size: 100% 1px, 0% 1px; }
.du-link:focus-visible, :where(a:not([class])):focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
[dir="rtl"] .du-link, [dir="rtl"] :where(a:not([class])) { background-position: 100% 100%, 100% 100%; }

/* ── field: a label and a ruled line, as on a drawing ─────────────────
   the line is two background layers, not a border, so focus and error never shift the layout:
   a 1px --edge line always there, and a 2px line drawn in on top from the reading start */
.du-field { display: grid; gap: var(--s-1); }
/* the label is a <span> inside a <label class="du-field">, or a <label> of its own beside the input */
.du-field > span, .du-field > label { font-size: var(--fs-label); color: var(--ink-2); }
.du-field input, .du-field textarea, .du-field select {
  width: 100%; min-width: 0;
  font: 500 var(--fs-ui)/1.4 var(--font); color: var(--ink); background-color: transparent;
  border: 0; border-radius: 0; padding: var(--s-2) 0;
  background-repeat: no-repeat, no-repeat;
  background-image: linear-gradient(var(--edge), var(--edge)), linear-gradient(var(--amber-line), var(--amber-line));
  background-position: 0 100%, 0 100%;
  background-size: 100% 1px, 0% 2px;
  transition: background-size var(--pen-stroke) var(--ease-pen);
}
.du-field input:focus-visible, .du-field textarea:focus-visible, .du-field select:focus-visible {
  outline: none; background-size: 100% 1px, 100% 2px;
}
/* invalid is a fact, not a hover state: the line is already danger-coloured and already drawn */
.du-field input[aria-invalid="true"], .du-field textarea[aria-invalid="true"], .du-field select[aria-invalid="true"] {
  background-image: linear-gradient(var(--edge), var(--edge)), linear-gradient(var(--danger), var(--danger));
  background-size: 100% 1px, 100% 2px;
}
.du-error { display: block; margin-top: var(--s-1); font-size: 12.5px; font-weight: 600; color: var(--danger); animation: du-write 150ms ease both; animation-delay: var(--pen-stroke); }
/* a placeholder is text, so it takes the dimmest ink allowed (6.12:1 on --bg) rather than the
   browser's grey (4.00:1 on --bg); opacity 1 because one engine fades placeholders to .54 by default */
::placeholder { color: var(--ink-3); opacity: 1; }

/* ── note: a result written in the margin, on a leader line ───────────
   inserted straight into a live page, with no draw() call: the dot appears, the line draws
   itself from a plain CSS keyframe (works the instant the node lands in the DOM), then the
   words are written --pen-note after. Replaying one (motion.html) means re-inserting the node,
   not DU.draw: an animation already at its last keyframe holds there, so a second draw() call
   on the same element has nothing left to animate. */
.du-leader { position: absolute; overflow: visible; pointer-events: none; }
/* explicit to as well as from: a leader's path and circle may also carry du-pen/du-after
   (the old, container-drawn pieces use the same markup), whose own rules would otherwise
   supply the "to" value and hide these forever; naming both ends keeps this piece self-playing
   no matter what other classes it carries */
.du-leader path { stroke: var(--amber-line); stroke-width: var(--note-w); fill: none; stroke-dasharray: 100 100; animation: du-leader-stroke var(--pen-stroke) var(--ease-pen) both; }
.du-leader circle { fill: var(--amber-line); animation: du-note-in 150ms ease both; }
.du-note { position: absolute; display: grid; gap: 2px; font-size: var(--fs-small); line-height: 1.35; color: var(--ink-2); animation: du-note-in 150ms ease both; animation-delay: calc(var(--pen-stroke) + var(--pen-note)); }
.du-note b { font-size: var(--fs-ui); color: var(--ink); }
.du-note a { color: var(--ink); font-weight: 600; text-underline-offset: 3px; }
@keyframes du-leader-stroke { from { stroke-dashoffset: 100; } to { stroke-dashoffset: 0; } }
@keyframes du-note-in { from { opacity: 0; } to { opacity: 1; } }

/* ── measure: progress as a dimension line, its value written above ── */
.du-measure { display: block; width: 100%; max-width: 340px; height: auto; overflow: visible; } /* capped so its value stays at label size */
.du-measure .ext  { stroke: var(--pen-2); stroke-width: 1; }
.du-measure .base { stroke: var(--rule-2); stroke-width: 1; stroke-dasharray: 2 3; }
.du-measure .amt  { stroke: var(--amber-line); stroke-width: 1.5; transform-box: fill-box; transform-origin: 0 50%; transform: scaleX(var(--p, 0)); transition: transform 200ms linear; }
.du-measure .head { fill: var(--amber-line); }
.du-measure .tip  { transform: translateX(calc(var(--p, 0) * 264px)); transition: transform 200ms linear; }
.du-measure .val  { fill: var(--ink); font: 500 12px var(--font); font-variant-numeric: tabular-nums; transform: translateX(clamp(34px, calc(var(--p, 0) * 132px), 132px)); transition: transform 200ms linear; }
.du-measure .end  { stroke: var(--amber-line); stroke-width: 1.4; opacity: 0; transition: opacity 300ms; }
[data-done] .du-measure .end { opacity: 1; }

/* ── tabs: the pen underlines the new one and lifts off the old ─────── */
/* never wider than its row: tabs that do not fit scroll inside the list, never the page. The rule under
   them is an inset line rather than a border, because a scroller clips at its padding edge and the
   selected underline has to cross the rule. No scrollbar: in a 60px header a scrollbar takes the
   height the tabs need, so the cut edge is marked by the arrow below instead */
.du-tabs {
  display: flex; gap: var(--s-1); box-shadow: inset 0 -1px 0 var(--rule);
  min-width: 0; overflow-x: auto; overflow-y: hidden; scrollbar-width: none; scroll-padding-inline-end: 28px;
}
.du-tabs::-webkit-scrollbar { display: none; }
/* more tabs than fit: an arrow at the cut edge, pinned there while tabs lie past it. It is covered,
   and so gone, when the last tab is in view, by a patch of ground that travels just after the last tab.
   Both are the page's ground; tabs on another surface set --tabs-ground to it */
.du-tabs::after {
  content: "\203A"; content: "\203A" / "";
  position: sticky; inset-inline-end: 0; flex: none; width: 24px; margin-block-end: 1px;
  display: grid; place-items: center; background: var(--tabs-ground, var(--bg));
  font: 400 20px/1 var(--font); color: var(--ink-2); pointer-events: none;
}
.du-tab:last-child::before {
  content: ""; position: absolute; inset-block: 0 1px; inset-inline-start: 100%; width: calc(var(--s-1) + 24px);
  background: var(--tabs-ground, var(--bg)); z-index: 1; pointer-events: none;
}
/* inline-flex centres the label itself, so a tab need not be a <button> (a div[role=tab] is centred too) */
.du-tab {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  flex: none; white-space: nowrap;
  min-height: var(--target); padding: 0 var(--s-3); background: none; border: 0;
  font: 600 var(--fs-ui)/1 var(--font); color: var(--ink-2); cursor: pointer;
}
.du-tab[aria-selected="true"] { color: var(--ink); }
.du-tab:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
.du-tab::after {
  content: ""; position: absolute; left: var(--s-3); right: var(--s-3); bottom: 0; height: 2px; background: var(--amber-line);
  transform: scaleX(0); transform-origin: 100% 50%; transition: transform var(--pen-stroke) var(--ease-pen);
}
.du-tab[aria-selected="true"]::after { transform: scaleX(1); transform-origin: 0 50%; transition-delay: calc(var(--pen-stroke) * .5); }
/* how many need you, written after the tab's name ("Needs you 2"): amber written as text, so
   --amber-text (6.09:1 on print white), never --amber-line (4.88:1 there, a line's token) */
.count { margin-inline-start: var(--s-1); font-size: var(--fs-label); font-variant-numeric: tabular-nums; color: var(--amber-text); }

/* ── rows: ruled, never boxed; only the row that needs you is amber ── */
.du-rows { list-style: none; margin: 0; padding: 0; }
.du-rows > li { position: relative; display: flex; align-items: center; gap: var(--s-3); padding: var(--s-3) 2px; font-size: var(--fs-ui); color: var(--ink); }
.du-rows > li::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px; background: var(--rule-2); transform-origin: 0 50%; }
/* a row that links, or the one row that is selected, redraws its rule over the base one; ::before
   sits under ::after in source order, so it needs z-index to paint on top of the base rule */
.du-rows > li:has(a)::before, .du-rows > li[aria-selected="true"]::before {
  content: ""; position: absolute; z-index: 1; left: 0; right: 0; bottom: 0; height: 1px; background: var(--pen);
  transform: scaleX(0); transform-origin: 0 50%; transition: transform var(--pen-stroke) var(--ease-pen);
}
.du-rows > li:has(a):hover::before { transform: scaleX(1); }
.du-rows > li[aria-selected="true"]::before { background: var(--ink); transform: scaleX(1); } /* impeccable-disable-line low-contrast: a 1px rule at the row's own bottom edge, not a text background; the row's text sits on --raise/--bg */
.du-rows .meta { margin-inline-start: auto; font-size: var(--fs-small); color: var(--ink-2); white-space: nowrap; font-variant-numeric: tabular-nums; }
/* any number in a column: Sora's default figures differ in width, so columns jitter without this */
.du-num { font-variant-numeric: tabular-nums; }
.du-rows .node { flex: none; width: 9px; height: 9px; border-radius: 50%; box-shadow: inset 0 0 0 1.3px var(--pen-2); }
.du-rows .node--needs { background: var(--amber-line); box-shadow: none; }
/* a state is a word, never a coloured chip: "Blocked", "Due 30 Sep"; an error is also bold, not red alone */
.word { font-size: var(--fs-small); color: var(--ink-2); white-space: nowrap; font-variant-numeric: tabular-nums; }
.word.danger { color: var(--danger); font-weight: 600; }
/* arriving: each rule is drawn, then its words are written. Rows are visible without this. */
/* capped: a list of any length lands in about 0.6 s; rows past the cap arrive with the last staggered one */
.du-rows[data-pen="drawn"] > li::after { animation: du-rule var(--pen-stroke) var(--ease-pen) both; animation-delay: calc(min(var(--i, 0), var(--pen-cap)) * var(--pen-stagger)); }
.du-rows[data-pen="drawn"] > li > * { animation: du-write 150ms ease both; animation-delay: calc(min(var(--i, 0), var(--pen-cap)) * var(--pen-stagger) + var(--pen-stroke) * .6); }
@keyframes du-rule { from { transform: scaleX(0); } }
@keyframes du-write { from { opacity: 0; } }

/* ── rule: a ruled line on its own, drawn like any other stroke ─────── */
.du-rule { display: block; border: 0; margin: 0; height: 1px; background: var(--rule-2); transform: scaleX(1); transform-origin: 0 50%; }
.du-js .du-rule:not([data-pen]) { transform: scaleX(0); }
.du-rule[data-pen="drawn"] { transform: scaleX(1); transition: transform var(--pen-stroke) var(--ease-pen); }
.du-rule[data-pen="lifted"] { transform: scaleX(0); transition: transform calc(var(--pen-stroke) * .75) var(--ease-pen); }

/* ── outline: a traced frame instead of a border ─────────────────────
   drafted.js injects the frame (an svg.du-frame first child, du-pen rect); without it the plain
   inset outline below is the whole story, and the two never show at once (A3) */
.du-outline { position: relative; border-radius: var(--r-lg); box-shadow: inset 0 0 0 var(--line-w) var(--edge); }
.du-js .du-outline { box-shadow: none; }
/* width and height are set, not left to inset: an svg is a replaced element, so with only inset: 0 it keeps
   its default 300 by 150 and every box got a frame that size, whatever its content (found 1 Oct 2026) */
.du-frame { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; }
.du-frame rect { x: .75px; y: .75px; width: calc(100% - 1.5px); height: calc(100% - 1.5px); rx: calc(var(--r-lg) - .75px); fill: none; stroke: var(--edge); stroke-width: var(--line-w); }

/* ── checkbox: the box is drawn once, the tick every time ────────────
   <label class="du-check"><input type="checkbox"><svg>...<path class="tick">...<span>Label</span></label>;
   the input stays in the accessibility tree, sized and placed over the box, just invisible */
.du-check { position: relative; display: inline-flex; align-items: center; gap: var(--s-2); min-height: var(--target); cursor: pointer; font: 500 var(--fs-ui)/1.4 var(--font); color: var(--ink); }
.du-check input { position: absolute; left: 0; width: 16px; height: 16px; margin: 0; opacity: 0; }
.du-check svg { flex: none; width: 16px; height: 16px; overflow: visible; }
.du-check rect { fill: none; stroke: var(--edge); stroke-width: 1.5; }
.du-check .tick { fill: none; stroke: var(--ink); stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 100 100; stroke-dashoffset: 100; transition: stroke-dashoffset calc(var(--pen-stroke) * .75) var(--ease-pen); }
.du-check input:checked ~ svg rect { stroke: var(--ink); }
.du-check input:checked ~ svg .tick { stroke-dashoffset: 0; transition: stroke-dashoffset var(--pen-stroke) var(--ease-pen); }
.du-check input:focus-visible ~ svg { outline: 2px solid var(--focus); outline-offset: 2px; border-radius: 5px; }

/* ── segmented choice: one outlined group, the pen underlines the pick ──
   <div class="du-seg" role="radiogroup"><label><input type="radio" name="x"><span>Minimum</span></label>...</div> */
.du-seg { display: flex; border-radius: var(--r); box-shadow: inset 0 0 0 var(--line-w) var(--edge); overflow: hidden; }
.du-seg label { position: relative; flex: auto; display: flex; align-items: center; justify-content: center; min-height: var(--target); padding: 0 var(--s-3); font-size: 13px; text-align: center; color: var(--ink-2); cursor: pointer; }
.du-seg label + label { box-shadow: inset 1px 0 0 var(--rule-2); }
.du-seg input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.du-seg input:checked + span { color: var(--ink); font-weight: 600; }
.du-seg input:focus-visible + span { outline: 2px solid var(--focus); outline-offset: -2px; border-radius: 4px; }
.du-seg label::after {
  content: ""; position: absolute; left: var(--s-3); right: var(--s-3); bottom: 0; height: 2px; background: var(--amber-line);
  transform: scaleX(0); transform-origin: 100% 50%; transition: transform var(--pen-stroke) var(--ease-pen);
}
.du-seg label:has(input:checked)::after { transform: scaleX(1); transform-origin: 0 50%; transition-delay: calc(var(--pen-stroke) * .5); }

/* ── disclosure: a plus mark in two strokes, opening leaves the minus ──
   <details class="du-more"><summary>Question</summary><div>Answer, one wrapper</div></details> */
details.du-more > summary { position: relative; display: flex; align-items: center; gap: var(--s-3); min-height: var(--target); padding-inline-start: 24px; list-style: none; cursor: pointer; font: 600 var(--fs-ui)/1 var(--font); color: var(--ink); }
details.du-more > summary::-webkit-details-marker { display: none; }
details.du-more > summary::marker { content: ""; }
details.du-more > summary::before, details.du-more > summary::after { content: ""; position: absolute; inset-inline-start: 0; top: 50%; background: var(--pen); }
details.du-more > summary::before { width: 16px; height: var(--line-w); margin-top: calc(var(--line-w) / -2); }
details.du-more > summary::after { inset-inline-start: 7.25px; width: var(--line-w); height: 16px; margin-top: -8px; transform-origin: 50% 50%; transition: transform calc(var(--pen-stroke) * .75) var(--ease-pen); }
details.du-more[open] > summary::after { transform: scaleY(0); }
details.du-more > summary + * { position: relative; margin-top: var(--s-3); padding-top: var(--s-3); opacity: 0; transition: opacity 150ms ease; }
details.du-more > summary + *::before {
  content: ""; position: absolute; inset-inline: 0; top: 0; height: 1px; background: var(--rule-2);
  transform: scaleX(0); transform-origin: 0 50%; transition: transform var(--pen-stroke) var(--ease-pen);
}
details.du-more[open] > summary + *::before { transform: scaleX(1); }
details.du-more[open] > summary + * { opacity: 1; transition-delay: var(--pen-stroke); }

/* ── menu and dialog: the same traced frame as .du-outline, drawn on insertion or open ──
   the frame is decoration only: items are legible and clickable from the first frame, at the 44px
   target, and a 1.5px --edge outline holds the menu's edge with no script (product bar, 7 Oct 2026) */
.du-menu { position: relative; min-width: 180px; background: var(--raise); border-radius: var(--r-lg); padding: var(--s-1) 0; box-shadow: inset 0 0 0 var(--line-w) var(--edge); }
.du-js .du-menu:has(> .du-frame) { box-shadow: none; }
.du-menu, .du-menu * { box-sizing: border-box; }
.du-menu [role="option"], .du-menu [role="menuitem"], .du-menu li, .du-menu > button, .du-menu > a {
  display: flex; align-items: center; width: 100%; min-height: var(--target); padding: 0 var(--s-4);
  font: 400 var(--fs-ui)/1.3 var(--font); color: var(--ink); text-align: start; text-decoration: none; background: none; border: 0; cursor: pointer;
}
.du-menu [role="option"]:hover, .du-menu [role="option"]:focus-visible, .du-menu [aria-selected="true"],
.du-menu [role="menuitem"]:hover, .du-menu [role="menuitem"]:focus-visible,
.du-menu li:hover, .du-menu > button:hover, .du-menu > a:hover { background: var(--rule); }
.du-menu [role="option"]:focus-visible, .du-menu [role="menuitem"]:focus-visible, .du-menu > button:focus-visible, .du-menu > a:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }

/* the one thing that sits above the page (DESIGN.md 6): the scrim is the only fade allowed,
   because it is the ground the dialog sits on, not a thing the pen draws.
   SIMPLIFIED: only the opening fades in, through @starting-style; close() removes the dialog
   outright rather than choreographing an exit through script, which this kit's "no library, no
   build step" ceiling accepts */
dialog.du-dialog { position: relative; background: var(--raise); color: var(--ink-2); border: 0; border-radius: var(--r-lg); padding: var(--s-5); max-width: min(480px, calc(100vw - var(--s-4) * 2)); }
dialog.du-dialog::backdrop { background: var(--scrim); transition: opacity 150ms ease; opacity: 1; }
@starting-style { dialog.du-dialog::backdrop { opacity: 0; } }

/* ── inline wait: a short line beside a sentence, drawn and lifted, on loop ── */
.du-wait { position: relative; display: inline-flex; align-items: center; gap: var(--s-2); color: var(--ink-2); font-size: var(--fs-ui); }
.du-wait::before { content: ""; display: inline-block; width: 24px; height: var(--line-w); background: var(--pen); animation: du-busy 900ms var(--ease-pen) infinite; }

/* ── right to left: lines are drawn from where reading starts ───────── */
[dir="rtl"] .du-rows > li::after,
[dir="rtl"] .du-rows > li::before,
[dir="rtl"] .du-rule { transform-origin: 100% 50%; }
[dir="rtl"] details.du-more > summary + *::before { transform-origin: 100% 50%; }
[dir="rtl"] .du-seg label::after { transform-origin: 0 50%; }
[dir="rtl"] .du-seg label:has(input:checked)::after { transform-origin: 100% 50%; }
[dir="rtl"] .du-tab::after { transform-origin: 0 50%; }
[dir="rtl"] .du-tab[aria-selected="true"]::after { transform-origin: 100% 50%; }
[dir="rtl"] .du-tabs::after { content: "\2039"; content: "\2039" / ""; }
[dir="rtl"] .du-measure { transform: scaleX(-1); }                     /* the measure fills from the right */
[dir="rtl"] .du-measure .val { transform: translateX(clamp(34px, calc(var(--p, 0) * 132px), 132px)) scaleX(-1); transform-box: fill-box; transform-origin: 50% 50%; }
/* Arabic letters join; any letter-spacing breaks the joins, so none is ever applied to Arabic */
:lang(ar), :lang(ar) * { letter-spacing: 0 !important; }

/* ── paper: an export never waits for a pen, and never ships a blank drawing ── */
@media print {
  .du-pen { stroke-dashoffset: 0 !important; transition: none !important; }
  .du-after { opacity: 1 !important; transition: none !important; }
  .du-rows > li::after, .du-rows > li > * { animation: none !important; }
  .du-trace, .du-btn[aria-busy="true"]::after, .du-wait::before { display: none; }
  .du-rule { transform: scaleX(1) !important; transition: none !important; }
  .du-leader path, .du-leader circle, .du-note { animation: none !important; opacity: 1 !important; }
  .du-leader path { stroke-dashoffset: 0 !important; }
  details.du-more > summary + * { opacity: 1 !important; }
  details.du-more > summary + *::before { transform: scaleX(1) !important; }
}

/* ── less motion: every state is reached at once ────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .du-pen, .du-after, .du-trace rect, .du-tab::after, .du-measure .amt, .du-measure .tip, .du-measure .val { transition: none !important; }
  .du-rows > li::after, .du-rows > li > * { animation: none !important; }
  .du-rule, .du-rows > li::before, .du-link, :where(a:not([class])),
  .du-field input, .du-field textarea, .du-field select, .du-check .tick, .du-seg label::after,
  details.du-more > summary::after, details.du-more > summary + *, details.du-more > summary + *::before,
  dialog.du-dialog::backdrop { transition: none !important; }
  .du-btn[aria-busy="true"]::after, .du-wait::before { animation: none !important; }
  .du-leader path, .du-leader circle, .du-note { animation: none !important; opacity: 1 !important; }
  .du-leader path { stroke-dashoffset: 0 !important; }
}
