/* issue-report.css — the support page's issue reporter and its FAQ.
 *
 * @docs ../../../README.md
 *
 * Markup and behaviour are layouts/issue-report.yml and issue-report.js
 * beside this file. Adapted from
 * ../../../../bounce/site/www/src/pages/support/issue-report.css — the shape
 * is that file's (itself adapted from terminal-c's src/css/forms.css), every
 * colour is Touchtone's own generated token, not a literal.
 *
 * PAGE-SCOPED. pipeline/emit.mjs's ported writePageAssets concatenates every
 * stylesheet in this directory, in filename order, into
 * public/pages/support.css — linked ONLY by layouts/issue-report.yml's own
 * markup (see that file's header on why the link tag lives there and not in
 * src/html/_shell.html). Nothing else on this site pays for these bytes.
 *
 * 🔴 EVERY COLOUR IS A THEME TOKEN, generated by theme/build-tokens.mjs +
 * hand-authored in theme/law.css (loaded after tokens.css, so it wins the
 * cascade — see that file's own header). A hand-picked hex here is the one
 * thing that would not repaint if the theme ever changes.
 *
 * ⚠️ `--success`/`--warning`/`--error` ARE THE ONE PLACE ON THIS SITE REAL
 * COLOUR SURVIVES THE SITE'S "colour is only ever a note" LAW — theme/law.css
 * names this exact form's validation states as the sanctioned reason: they
 * are functional state signals (pass/fail/in-flight) on "an ordinary web
 * form," not the play surface the app's zero-decorative-colour law describes,
 * and WCAG 1.4.1 already requires the state to be carried by more than colour
 * (the WORDS change too — see .report-status below). Nowhere else in this
 * file uses anything but the neutral/white ramp `theme/law.css` collapses
 * everything else to.
 *
 * `.visually-hidden` is defined HERE, not reused from base.css — that class
 * does not exist there today (unlike Bounce's own base.css:210, which is why
 * its own copy of this file could skip it). One utility class, one caller
 * (the form's `<legend>`), page-scoped like everything else in this file.
 */

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ── the section ─────────────────────────────────────────────────────────── */

.issue-report { max-width: var(--measure); }
.report-title { margin-bottom: var(--space-2); }
.report-intro { color: var(--text-secondary); }

/* ── the stand-down notice ───────────────────────────────────────────────── */
/* 🔴 ADDED 2026-09-25 — a defect found by MEASURING the rendered page, not by
 * any programmatic check: this site's only explanation for a disabled form
 * used to be `.report-status`, sitting AFTER the fieldset, 673px below the
 * fold at a 963px viewport. See layouts/issue-report.yml's header and
 * issue-report.js's `standDown()` for the full account — including that this
 * same gap is latent in Bounce's own file, not fixed there.
 *
 * A SEPARATE node from `.report-status` below, styled to be found without
 * scrolling and to read as a NOTICE rather than a submission outcome — bolder
 * border, a background fill, sitting between the intro and the form so it's
 * the thing a reader meets right before the (dimmed) fieldset, not after it.
 * `--warning`, not `--error`: this is a precondition the reader didn't cause
 * — theme/law.css's exception for this form's semantic colours covers
 * exactly this kind of functional state signal. */
/* 🔴 THE PERIMETER MOVED OFF `--warning`, 2026-09-29 — MEASURED, NOT
 * EYEBALLED, AND ON THE ONE ELEMENT THAT CAN LEAST AFFORD IT.
 *
 * This box carries the only sentence on the page that explains why the form
 * below does nothing, so "reads as a notice" is not decoration here — it is the
 * whole function. theme/law.css's ground flip to cream (`--bg` #FAECD7) left
 * both of the things that made it a box below any usable threshold:
 *
 *     --surface #f2f0ea fill  on --bg #FAECD7   1.02:1   (no fill at all)
 *     --warning #E8B84D edge  on --bg #FAECD7   1.58:1   (a pale line on cream)
 *
 * A yellow hairline on cream. On the old black ground the same pair read fine;
 * nothing here changed, the floor under it did. Net effect: a paragraph that
 * looked like it had simply been typed above the form.
 *
 * The perimeter is now `--border` (#111111 at root, 16.23:1 on `--bg`) — the
 * same structural hairline `.report-status` below already uses, so the two
 * message boxes on this page finally agree on what a box is. `--warning`
 * survives as a 3px LEADING EDGE rather than a hairline: mass, not hue, is what
 * makes a low-contrast colour carry at small area, and it stays a redundant
 * cue — WCAG 1.4.1 is satisfied by the WORDS, which is why this file's header
 * argues the semantic colours are sanctioned in the first place.
 *
 * The `--surface` fill is kept even at 1.02:1. It is doing nothing on the cream
 * ground and it is not TRYING to: it is what keeps the box right if this ever
 * renders inside `.toy-stage`/`.band.void`, where `--surface` is #0f0f0f and
 * the relationship to `--bg` is the one it was authored for. */
.report-standdown:empty { display: none; }
.report-standdown {
  margin: var(--space-3) 0;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--border);
  border-inline-start: 3px solid var(--warning);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text-primary);
  font-size: 0.9375rem;
  max-width: var(--measure);
}

.report-form {
  margin-top: var(--space-3);
  margin-bottom: var(--space-6);
  max-width: 34rem;
}

/* 🔴 The fieldset ships `disabled` and the driver enables it — the layout's
 * header says why this form cannot degrade to a plain POST. Styled so the
 * not-yet-available state reads as "not yet", never as "broken". */
.report-form fieldset {
  border: 0;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-3);
}
/* 🔴 THE DIMMING IS SCOPED TO THE CONTROLS, NOT THE WHOLE FIELDSET — A WCAG
 * 1.4.3 DEFECT FIXED 2026-09-29, AND THE MECHANISM WAS THE BUG, NOT THE TIER.
 *
 * Both rules used to sit on `fieldset[disabled]` itself, which made the ENTIRE
 * subtree one composited group at 0.55 (and 0.4 once stood down). CSS `opacity`
 * on an ancestor composites every descendant against what is BEHIND the group,
 * so the page ground gets mixed into the ink at (1 − α) and there is no colour
 * a descendant can choose to escape it. Computed against the live tokens
 * (`--bg` #FAECD7, the cream root ground — this section is not inside
 * `.toy-stage`/`.band.void`, so it never sees the dark ramp):
 *
 *     α      ceiling: PURE BLACK over --bg      --text-muted (.report-hint)
 *     0.40   2.79:1                             1.71:1
 *     0.55   4.58:1                             2.16:1
 *     1.00   16.23:1                            4.89:1
 *
 * Read the middle column: at α=0.4 the BEST any text in the group can reach is
 * 2.79:1, so the 4.5:1 floor was unreachable by any recolouring — darkening
 * `--text-muted`, the usual fix when a muted tier fails, could not have worked
 * here. At α=0.55 only pure black clears it, and only by 0.08.
 *
 * WCAG 1.4.3's "incidental" exception covers text that is part of an INACTIVE
 * user-interface component, which is every control below. It does NOT cover
 * `.report-hint` — that is instructional prose telling the reader what leaving
 * name/email blank does, and on this page it is prose a visitor reads for real:
 * the form is stood down for everyone today (see issue-report.js), so the words
 * around it are the only part still doing work.
 *
 * So the opacity moved onto the interactive surfaces — the boxes you would
 * click, the challenge frame, the submit button — and every piece of TEXT is
 * left at its own token: `.report-hint` 4.89:1, `.report-label` 6.11:1, both
 * clearing AA. The "off" signal is unchanged in strength and is now carried by
 * the controls themselves, which is exactly where the exception puts it.
 *
 * ⚠️ `input[type="text"]`/`[type="email"]` ARE NAMED RATHER THAN A BARE
 * `input`. A bare `input` here would compute to (0,3,0) and outrank
 * `.report-kind input { opacity: 0 }` at (0,2,0), un-hiding the visually
 * hidden radios as bare dots beside the segmented thumb. The radios stay
 * hidden by inheriting the `.report-kinds` group's opacity times their own 0. */
.report-form fieldset[disabled] input[type="text"],
.report-form fieldset[disabled] input[type="email"],
.report-form fieldset[disabled] select,
.report-form fieldset[disabled] textarea,
.report-form fieldset[disabled] .report-kinds,
.report-form fieldset[disabled] .report-challenge,
.report-form fieldset[disabled] button[type="submit"] { opacity: 0.55; }

/* `is-standing-down` (set once, permanently, by `standDown()`) dims further
 * than the plain `disabled` state above — that default 0.55 also covers the
 * pre-JS and mid-probe moments where the form might still come alive a
 * second later, and reads correctly as "not yet". Once `standDown()` has
 * actually run, "not yet" is wrong; nothing will make this form work on this
 * page load, and the coordinator's review found 0.55 alone too subtle a
 * signal next to the text notice above — a reader's first cue that the title
 * field won't respond shouldn't be the click itself. */
.report-form.is-standing-down fieldset[disabled] input[type="text"],
.report-form.is-standing-down fieldset[disabled] input[type="email"],
.report-form.is-standing-down fieldset[disabled] select,
.report-form.is-standing-down fieldset[disabled] textarea,
.report-form.is-standing-down fieldset[disabled] .report-kinds,
.report-form.is-standing-down fieldset[disabled] .report-challenge,
.report-form.is-standing-down fieldset[disabled] button[type="submit"] { opacity: 0.4; }

.report-field { display: grid; gap: 0.4rem; }
.report-label {
  font-size: 0.875rem;
  color: var(--text-secondary);
}

.report-form input[type="text"],
.report-form input[type="email"],
.report-form select,
.report-form textarea {
  font: inherit;
  color: var(--text-primary);
  background: var(--input);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.6rem 0.7rem;
  width: 100%;
}

/* ⚠️ A `<select>` NEEDS ITS OWN RESET AS WELL AS THE SHARED RULE ABOVE, or the
 * field above it and the field below it do not match — a select keeps its
 * platform look until `appearance` is cleared, and the platform look is not
 * `--input` on any ground. (The original note here said "on a dark theme means
 * a white box in the middle of the form"; since the 2026-09-29 ground flip the
 * page is cream, so the mismatch is subtler but not gone — the UA control still
 * brings its own border, radius and, on macOS, its own disclosure chrome.)
 * Clearing `appearance` removes the
 * disclosure arrow with it, so one is drawn back as an inline SVG with a
 * `currentColor` stroke, so it follows the theme's ink instead of being a
 * second colour to keep in step. `padding-inline-end` leaves it room. */
.report-form select {
  appearance: none;
  -webkit-appearance: none;
  padding-inline-end: 2.25rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1 1.5 6 6.5l5-5' stroke='currentColor' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.85rem center;
  cursor: pointer;
}

/* The prompt row reads as a prompt rather than as a chosen value. It is
 * `disabled` in the markup so it can never be submitted; this is the visual
 * half of saying so. */
.report-form select:invalid { color: var(--text-placeholder); }
.report-form textarea { resize: vertical; min-height: 7rem; }

.report-form input::placeholder,
.report-form textarea::placeholder { color: var(--text-placeholder); }

/* No focus-visible rule for the plain inputs/select/textarea/button here —
 * base.css's site-wide `:focus-visible { outline: 2px solid var(--text-bright);
 * … }` already covers every real focusable element with the structural ring the
 * site's design law requires. The one control below that DOES need its own is
 * the segmented "kind" picker, whose actual `<input>` is visually hidden — the
 * ring has to be drawn on its sibling label instead.
 *
 * ⚠️ THAT TOKEN NAME IS LOAD-BEARING AND THIS COMMENT USED TO NAME THE WRONG
 * ONE (`--structure`). base.css moved its ring to `--text-bright` when the page
 * ground went light, precisely because `--structure` is pinned #ffffff forever
 * and a white ring measures 1.16:1 on the cream `--bg` — invisible. Keep the
 * rule below on the same token base.css uses; see its own note there. */

/* ── bug / feature ───────────────────────────────────────────────────────── */
/* Both are first-class choices and both get a plain noun, so neither is styled
 * as the lesser option.
 *
 * ⚠️ WRITTEN LOCALLY RATHER THAN AS A SHARED PRIMITIVE — same call Bounce's
 * own file makes and for the same reason: this site has no `.segmented` and
 * no second caller (PLAN.md §6 flags this exact gap), so a shared primitive
 * would add weight to the sitewide bundle for one control on one page. When a
 * second caller appears, that is the day it moves to src/css/components.css.
 *
 * `justify-self` for the same reason the submit button has one further down:
 * the fieldset is a grid and a grid stretches its children, so an
 * `inline-flex` track would still come out as wide as a textarea. A choice
 * between two words that spans the form reads as a banner, not a control. */
.report-kinds {
  justify-self: start;
  display: inline-flex;
  gap: 4px;
  padding: 4px;
  border: 1px solid var(--border-bright);
  /* Concentric with the thumb: the track's radius is the option's plus the
   * padding, so the two curves stay parallel instead of the inner one looking
   * flattened against the outer. */
  border-radius: calc(var(--radius) + 4px);
  background: var(--surface);
}

.report-kind { cursor: pointer; display: inline-flex; }
/* Out of paint, still focusable, still arrow-key switchable. Not
 * `display: none` and not `visibility: hidden` — both would take the radio out
 * of the tab order and out of the accessibility tree, which is the opposite of
 * the point for the control that carries the choice. */
.report-kind input { position: absolute; opacity: 0; pointer-events: none; }

.report-kind-face {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 2.75rem;              /* the 44px tap-target floor, as .btn */
  padding: 0 1rem;
  border-radius: var(--radius);
  font-size: 0.9375rem;
  color: var(--text-secondary);
  /* Colour only, and under 200ms — design.md's motion budget. A control that
   * bounces when picked is decoration; this one only reports a state change.
   * prefers-reduced-motion is honoured once, sitewide, in base.css — nothing
   * further is needed here. */
  transition: background var(--motion-duration) var(--motion-ease),
              color var(--motion-duration) var(--motion-ease);
}
.report-kind-face:hover { background: var(--surface-high); color: var(--text-bright); }

/* The thumb. `--ink-on-accent` and never `--text-primary`, because the theme
 * carries its own on-accent ink precisely so a label on top of the fill is not
 * a contrast question to re-answer per component.
 *
 * 🔴 COMMENT CORRECTED 2026-09-29 — it used to assert "`--accent` is white …
 * (black)", which stopped being true TWICE. theme/law.css's restructure retired
 * `--accent` as a colour of its own: it now falls through to `--text-bright`,
 * and `--ink-on-accent` was re-pointed from `--ink` to `--bg` in the same edit.
 * So the literal values are now the OPPOSITE of what that sentence said at the
 * root scope, and neither is a fixed colour any more:
 *
 *     root (this page, cream ground)  --accent #111111  on --ink-on-accent #FAECD7  16.23:1
 *     .toy-stage / .band.void (dark)  --accent #dadada  on --ink-on-accent #000000  15.02:1
 *
 * ⭐ WHAT TO RELY ON IS THE INVARIANT, NOT EITHER ROW: both tokens are scope-
 * aware and law.css moves them AS A PAIR, so the fill and its ink always invert
 * together and the thumb stays legible in whichever scope this control is
 * mounted. Naming the pair rather than a hex is what keeps this comment from
 * rotting a third time. */
.report-kind input:checked + .report-kind-face {
  background: var(--accent);
  color: var(--ink-on-accent);
}

/* The ring's offset is arithmetic rather than taste: the face sits inside a
 * track that is 1px of border plus 4px of padding, so the 2px used site-wide
 * would draw the ring ON the track's own edge and read as a thickened border.
 * 1px keeps the whole ring in the padding, where it reads as a ring.
 *
 * 🔴 `--text-bright`, NOT `--structure` — FIXED 2026-09-29, a live WCAG 2.4.7
 * failure, and the worst possible control to have it on. `--structure` is
 * pinned #ffffff in every scope by design (theme/law.css says so explicitly, so
 * this is not a token that can be "fixed" upstream), and against the cream root
 * ground it measures:
 *
 *     --structure   #ffffff on --bg #FAECD7    1.16:1   invisible
 *     --text-bright #111111 on --bg #FAECD7   16.23:1
 *
 * base.css's site-wide `:focus-visible` had already been moved to
 * `--text-bright` for exactly this reason when the ground flipped; this rule
 * was missed because it is page-scoped and lives in this file. The cost of the
 * miss is higher here than anywhere else on the site: `.report-kind input` is
 * `opacity: 0`, so this outline is the ONLY focus indicator the segmented
 * bug/feature picker has — no ring means a keyboard reader arrowing between the
 * two options gets no visible feedback at all. */
.report-kind input:focus-visible + .report-kind-face {
  outline: 2px solid var(--text-bright);
  outline-offset: 1px;
}

/* ── the optional pair ───────────────────────────────────────────────────── */

.report-optional {
  display: grid;
  gap: var(--space-2);
}
/* Mobile-second, desktop-third: one column is the baseline and two is what the
 * extra room buys, never the other way round. */
@media (min-width: 34rem) {
  .report-optional { grid-template-columns: 1fr 1fr; }
}

.report-hint,
.report-noscript {
  font-size: 0.875rem;
  color: var(--text-muted);
  max-width: var(--measure);
  margin: 0;
}

/* The grid stretches its children, which is right for the fields and wrong for
 * the button — a submit as wide as a textarea reads as a banner, not a
 * control. */
.report-form button[type="submit"] { justify-self: start; }

/* ── the challenge ───────────────────────────────────────────────────────── */
/* The hosted Turnstile page. It renders its own widget at its own size on a
 * transparent ground, so the frame only has to reserve the room and get out
 * of the way — reserving it is what stops the submit button jumping down the
 * page once the challenge finishes loading.
 *
 * 🔴 `color-scheme: light`, CORRECTED 2026-09-29 — it said `dark`, under a
 * comment reading "this site has exactly one theme … and it is dark, so there
 * is no light case to defer to." Both halves are now false. theme/law.css's
 * ground flip the same day made the root `--bg` #FAECD7, a warm cream, and
 * scoped the black ramp to `.toy-stage`/`.band.void` only. The support page's
 * `<section class="issue-report">` is in neither scope (checked in the built
 * public/support.html, not assumed), so this frame sits on cream. A dark
 * Turnstile widget on a cream page is the one thing the old value guaranteed.
 *
 * 🔴 THE `color-scheme` BELOW DOES NOT DO WHAT THIS NOTE USED TO CLAIM, AND
 * THE CLAIM IS THE PART THAT WAS WRONG — corrected 2026-09-30, by measurement.
 * It read: "we cannot pass [the challenge page] a parameter — but the
 * embedder's `color-scheme` does reach the embedded document". Both halves
 * were false.
 *
 * ✅ CLOSING THE OPEN CHECK THAT STOOD HERE. The `touchtone` key was
 * provisioned 2026-09-30 (dboio/issue-reporter), so the widget could finally
 * be LOOKED AT — which is what the check asked for. Rendered on the live page
 * under an emulated dark OS: a black widget on the cream form, exactly the
 * outcome this file predicted. Then `color-scheme: light` was forced onto the
 * iframe against that same live page, and THE WIDGET STAYED DARK. Turnstile
 * reads the scheme inside its own cross-origin document, which an embedder's
 * `color-scheme` does not reach.
 *
 * ✅ SO THE LEVER IS THE PARAMETER, and it exists now: the service takes
 * `?theme=light|dark|auto` (added the same day, allow-listed, defaulting to
 * `auto` so every other app is unaffected). issue-report.js appends
 * `?theme=light` to the challenge URL and THAT is what makes the widget light.
 *
 * ⚠️ THE DECLARATION BELOW IS KEPT ON PURPOSE, and it is not the fix. It
 * governs what this DOCUMENT renders for the frame itself — its own scrollbar
 * and any UA chrome around it — which matters more here than on most pages,
 * because theme/tokens.css sets `color-scheme: dark` at :root from the Stage
 * theme while this page paints itself cream. Removing this line would let that
 * root value style the frame dark on a cream ground. It is a local correction,
 * not the widget's theme. */
.report-challenge iframe {
  border: 0;
  width: 100%;
  max-width: 20rem;
  height: 70px;
  display: block;
  color-scheme: light;
}

/* 🔴 A REAL BUG FOUND BY DRIVING THIS PAGE, NOT PRESENT IN BOUNCE'S OWN FILE
 * BUT INHERITED FROM IT — Bounce's issue-report.css carries the rule above
 * with no `[hidden]` override either, so the same defect is latent there too.
 * issue-report.js's `standDown()` sets `frame.hidden = true` when the
 * reporter is off, with a comment saying the dead frame is REMOVED rather
 * than left showing a third party's error page. It isn't removed: the
 * class+type selector above (`.report-challenge iframe`, specificity 0,1,1)
 * outranks the UA stylesheet's `[hidden] { display: none }` (0,1,0), so the
 * `hidden` attribute is silently overridden and an empty `about:blank` box
 * stays visible at full height. Caught with Playwright
 * (`getComputedStyle(frame).display === "block"` after `standDown()` ran) —
 * verified 2026-09-25, not assumed. One more attribute selector is enough to
 * win back the specificity. */
.report-challenge iframe[hidden] { display: none; }

/* ── the answer ──────────────────────────────────────────────────────────── */
/* `role="status"` + `aria-live="polite"` in the markup, so this is announced
 * rather than merely coloured. Colour is never the only carrier of a state
 * (WCAG 1.4.1) — which is why each state also changes the WORDS, and why the
 * border rather than the text colour is what moves. See this file's header
 * for why `--success`/`--error` are the one place real colour survives here. */
.report-status:empty { display: none; }
.report-status {
  margin-top: var(--space-2);
  font-size: 0.9375rem;
  padding: 0.6rem 0.7rem;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  color: var(--text-secondary);
  max-width: var(--measure);
}
.report-status.is-ok    { border-color: var(--success); color: var(--text-primary); }
.report-status.is-error { border-color: var(--error);   color: var(--text-primary); }

/* ── the FAQ ─────────────────────────────────────────────────────────────── */
/* Same one-column-of-prose shape as layouts/legal.yml's `.legal-*` classes —
 * not reused directly (those are scoped to that layout by
 * components.css's own section comment), so this is its own small set with
 * the same rules: no figure, no accent, nothing this site's design law would
 * call decoration. */

.report-faq { margin-top: var(--space-5); }
.report-faq-intro { color: var(--text-secondary); }

.report-faq-section { margin: var(--space-4) 0; }
.report-faq-heading { margin-bottom: var(--space-2); }

.report-faq-list {
  margin: 0 0 var(--space-2);
  padding-left: 1.25em;
  color: var(--text-secondary);
}
.report-faq-list li { margin-bottom: var(--space-1); }

/* Destinations (another page of this site), never words mid-sentence — see
 * layouts/issue-report.yml's header on why FAQ links are structured data
 * rather than an <a> typed into copy.json. */
.report-faq-links { list-style: none; margin: 0 0 var(--space-2); padding: 0; }
.report-faq-links li { margin-bottom: var(--space-1); }
