/* Self-hosted variable fonts (fonts/ in this repo). The build spec bans
   third-party requests at runtime, so these are bundled, not CDN-loaded.
   Both files are latin-subset variable fonts from Google Fonts. */
/* Lato ships static weights, not a variable axis: 400 and 700 cover the
   file's weight usage (500 resolves down to 400, 600 up to 700 by CSS
   font matching). Two latin subsets total 28 KB, lighter than the single
   variable file they replaced. */
@font-face {
  font-family: "Lato";
  src: url("../fonts/Lato-latin.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Lato";
  src: url("../fonts/Lato-bold-latin.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Playfair Display";
  src: url("../fonts/PlayfairDisplay-latin.woff2") format("woff2");
  font-weight: 400 900;
  font-style: normal;
  font-display: swap;
}

/* Cobalt sky palette (user-supplied): cobalt #0047AB, navy #000080,
   light blue #82C8E5, slate #6D8196. Raw slate only reaches 4.01:1 on
   white, so it is reserved for borders and large text; the faint-text
   role uses a darkened slate that clears 4.5:1. Navy carries display
   headings in light mode. Danger stays red: errors keep convention
   regardless of brand palette. */
:root {
  --ink: #14181d;
  --ink-soft: #3d4a58;
  --ink-faint: #52647a;
  --paper: #ffffff;
  --paper-sunk: #f1f5f8;
  --line: #c9d6e0;
  --accent: #0047ab;
  --accent-soft: #e7f2fa;
  --heading: #000080;
  --valid: #82c8e5;
  --danger: #c1301f;
  --focus: #0047ab;
  --radius: 4px;
  --max-width: 640px;

  /* Spacing scale. Everything in this file traces back to one of these. */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;
  --space-7: 2rem;
  --space-8: 3rem;

  /* Semantic z-scale: content < topbar < footer-nav. */
  --z-topbar: 20;
  --z-footer: 10;

  --transition-fast: 150ms cubic-bezier(0.16, 1, 0.3, 1);
  --transition-screen: 220ms cubic-bezier(0.16, 1, 0.3, 1);

  /* Playfair Display for display type, Lato for body and UI. Both are
     self-hosted from fonts/ (see @font-face above), so no runtime
     third-party request. System stacks as fallback while they load. */
  --font-serif: "Playfair Display", Georgia, Cambria, "Times New Roman", serif;
  --font-sans: "Lato", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

  font-size: 16px;
}

/* Theme resolution: the OS preference is the default; an explicit choice
   from the header toggle (persisted, stamped as data-theme by app.js)
   wins over it in both directions. The dark token set appears twice on
   purpose: once for OS-dark with no override, once for chosen-dark. Keep
   the two blocks identical. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --ink: #ecf0f4;
    --ink-soft: #c2ccd8;
    --ink-faint: #94a3b3;
    --paper: #0d1420;
    --paper-sunk: #16202e;
    --line: #2c3c50;
    --accent: #82c8e5;
    --accent-soft: #14283c;
    --heading: #ecf0f4;
    --valid: #3d6f8a;
    --danger: #f06f52;
    --focus: #82c8e5;
  }
}

:root[data-theme="dark"] {
  --ink: #ecf0f4;
  --ink-soft: #c2ccd8;
  --ink-faint: #94a3b3;
  --paper: #0d1420;
  --paper-sunk: #16202e;
  --line: #2c3c50;
  --accent: #82c8e5;
  --accent-soft: #14283c;
  --heading: #ecf0f4;
  --valid: #3d6f8a;
  --danger: #f06f52;
  --focus: #82c8e5;
}

* {
  box-sizing: border-box;
}

html, body {
  margin: 0;
  padding: 0;
}

body {
  font-family: var(--font-sans);
  font-size: 1rem;
  color: var(--ink);
  background: var(--paper);
  line-height: 1.55;
}

.app {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.topbar {
  position: sticky;
  top: 0;
  z-index: var(--z-topbar);
  background: var(--paper);
  padding: var(--space-3) var(--space-5);
  border-bottom: 1px solid var(--line);
}

/* Small screens pay for every sticky pixel: halve the vertical padding
   so the two header rows cost as little as their content allows. */
@media (max-width: 719px) {
  .topbar {
    padding-top: var(--space-1);
    padding-bottom: var(--space-1);
  }
}

.progress-bar {
  height: 3px;
  background: var(--line);
  border-radius: 999px;
  overflow: hidden;
  margin-bottom: var(--space-2);
}

.progress-bar-fill {
  height: 100%;
  width: 100%;
  transform: scaleX(0);
  transform-origin: left;
  background: var(--accent);
  border-radius: inherit;
  transition: transform var(--transition-screen);
}

.topbar-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-1) var(--space-3);
  min-height: 1.75rem;
  flex-wrap: wrap; /* small screens: identity row above the controls row */
}

/* Identity + status as one unit, all controls as another: the row wraps
   between the two groups, never inside them mid-icon. */
.topbar-status {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  min-width: 0;
  flex: 1 1 auto;
  flex-wrap: wrap; /* lets the armed clear-draft warning take a full row */
}

.topbar-controls {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-2);
  justify-content: flex-end;
  margin-left: auto;
}

/* Icon buttons draw small but hit big: a 16px glyph in a 2.5rem square
   is tappable with a thumb, not just a cursor. */
.icon-btn {
  min-width: 2.5rem;
  min-height: 2.5rem;
  justify-content: center;
  border: none;
  background: transparent;
  font: inherit;
}

/* Persistent identity in the sticky header. Truncates before it can crowd
   the language toggle; the full title is always in the intro h1. */
.brand {
  margin: 0;
  min-width: 8ch; /* never crushed to nothing by the controls */
  flex: 0 1 auto;
  font-family: var(--font-serif);
  font-weight: 600;
  font-size: 0.9375rem;
  line-height: 1.2;
  color: var(--heading);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The online chip carries two labels: the full one for roomy headers, a
   short one under 720px. aria-label holds the full name in both cases. */
.chip-short { display: none; }

@media (max-width: 719px) {
  .chip-full { display: none; }
  .chip-short { display: inline; }
}

.progress {
  margin: 0;
  flex: none;
  font-size: 0.875rem;
  color: var(--ink-faint);
}

.save-note {
  margin-left: auto;
  font-size: 0.8125rem;
  color: var(--ink-faint);
  opacity: 0;
  transition: opacity var(--transition-fast);
}

.save-note.show {
  opacity: 1;
}

.clear-draft {
  font: inherit;
  font-size: 0.8125rem;
  color: var(--ink-faint);
  background: transparent;
  border: none;
  padding: 0.2rem var(--space-1);
  min-height: 2.25rem;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
  /* One line that can shrink and truncate, never fold or overflow:
     flex: none here once let the armed label push 200px past the
     viewport edge on phones. The brand ellipsis absorbs the rest. */
  white-space: nowrap;
  flex: 0 1 auto;
  min-width: 0;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The armed warning is a sentence describing the app's only destructive
   action: it takes its own full-width row and wraps, fully readable on
   the smallest phone. */
.clear-draft.arming {
  white-space: normal;
  flex-basis: 100%;
  text-align: right;
  overflow: visible;
}

.clear-draft:hover {
  color: var(--danger);
}

/* Armed state: the first tap turned the label into a warning; the second
   executes. Danger-coloured so the escalation is unmistakable. */
.clear-draft.arming {
  color: var(--danger);
  font-weight: 700;
}

.lang-toggle {
  display: flex;
  gap: var(--space-1);
}

/* Theme toggle and bug report: a matched pair of soft round chips. The
   moon shows in light mode (click for dark), the sun in dark mode.
   app.js stamps data-theme with the RESOLVED theme on load, so the icon
   pair only needs the attribute, never the media query. */
.theme-toggle,
.bug-report {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--accent);
  background: var(--accent-soft);
  border: none;
  border-radius: 999px;
  cursor: pointer;
  transition: color var(--transition-fast), background-color var(--transition-fast), transform var(--transition-fast);
}

.theme-toggle svg,
.bug-report svg {
  width: 18px;
  height: 18px;
}

.theme-toggle:hover,
.bug-report:hover {
  color: var(--paper);
  background: var(--accent);
  transform: scale(1.08);
}

/* The moon leans in on hover; the sun gets a lazy quarter turn. */
.theme-toggle:hover .icon-moon { transform: rotate(-14deg); }
.theme-toggle:hover .icon-sun { transform: rotate(45deg); }
.theme-toggle svg { transition: transform var(--transition-fast); }

.theme-toggle:active,
.bug-report:active {
  transform: scale(0.9);
}

.theme-toggle:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

.theme-toggle .icon-sun { display: none; }

:root[data-theme="dark"] .theme-toggle .icon-moon { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-sun { display: inline; }

/* Tapped, the bug wiggles: proof of life even when the action itself is
   invisible (mailto opening elsewhere, or the pre-launch note). */
@keyframes bug-wiggle {
  0% { transform: rotate(0); }
  25% { transform: rotate(-14deg) scale(1.1); }
  55% { transform: rotate(12deg) scale(1.05); }
  80% { transform: rotate(-6deg); }
  100% { transform: rotate(0); }
}

.bug-report.wiggling svg {
  animation: bug-wiggle 0.5s ease-out;
}

.bug-report:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

.lang-chip {
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--ink-soft);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 0.3rem 0.7rem; /* >=4px vertical: breathing room for 13px text */
  min-height: 2.5rem; /* thumb-sized, matching the 40px icon buttons */
  cursor: pointer;
  transition: border-color var(--transition-fast), background-color var(--transition-fast), color var(--transition-fast);
}

.lang-chip:hover {
  border-color: var(--ink-faint);
}

.lang-chip[aria-pressed="true"] {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent);
  font-weight: 600;
}

main {
  flex: 1;
  padding: var(--space-6) var(--space-5) var(--space-7);
  transition: opacity 150ms ease;
}

/* Quick dip while the language copy swaps underneath, so the two registers
   crossfade rather than hard-cut. */
main.lang-swapping {
  opacity: 0.25;
}

@media (prefers-reduced-motion: reduce) {
  main {
    transition: none;
  }
}

.form-col {
  min-width: 0;
}

.screen {
  max-width: var(--max-width);
  margin: 0 auto;
  opacity: 1;
  transform: translateY(0);
  transition: opacity var(--transition-screen), transform var(--transition-screen);
}

.screen.screen-entering {
  opacity: 0;
  transform: translateY(8px);
}

h1 {
  font-family: var(--font-serif);
  font-weight: 900;
  font-size: 2.25rem;
  line-height: 1.15;
  color: var(--heading);
  margin: 0 0 var(--space-2);
  text-wrap: balance;
}

h2 {
  font-family: var(--font-serif);
  font-weight: 800;
  font-size: 1.625rem;
  line-height: 1.2;
  color: var(--heading);
  margin: calc(var(--space-6) + var(--space-1)) 0 var(--space-3);
  text-wrap: balance;
}

h2:first-child {
  margin-top: 0;
}

/* Screen headings receive programmatic focus on step change (so keyboard
   and screen-reader users land on the new screen instead of <body>).
   That focus is managed, not user-tabbed, so no ring. */
h1:focus,
h2:focus {
  outline: none;
}

.subheading {
  color: var(--ink-soft);
  margin: 0 0 var(--space-5);
}

p {
  margin: 0 0 var(--space-4);
  text-wrap: pretty;
}

.fine-print {
  font-size: 0.8125rem;
  color: var(--ink-faint);
  max-width: 70ch; /* small type needs a reading measure, not column width */
}

.field-help {
  font-size: 0.875rem;
  color: var(--ink-soft);
  margin: var(--space-1) 0 0;
}

.computed-note {
  font-size: 0.875rem;
  color: var(--ink-soft);
  margin: var(--space-1) 0 0;
}

.optional-tag {
  font-weight: 400;
  color: var(--ink-faint);
}

/* Turnstile widget: empty and zero-height until the check renders, so it
   adds no gap in dev where no key is configured. */
.turnstile:not(:empty) {
  margin: var(--space-5) 0;
}

/* .inline-error: identical look, but exempt from clearFieldErrors, which
   sweeps every .error-text in a screen. For static, self-managed errors
   like the notify field's. */
.error-text,
.inline-error {
  color: var(--danger);
  font-weight: 600;
  font-size: 0.875rem;
  margin: var(--space-1) 0 0;
}

/* Shown when the form quietly fixed formatting for the user (added
   https:// to a link, stripped spaces from a phone number). Telling them
   beats silently rewriting their input. */
.fixed-note {
  color: var(--accent);
  font-size: 0.8125rem;
  margin: var(--space-1) 0 0;
}

/* The failing control reddens, not everything sharing its field: marking
   rides on aria-invalid (set per-input by renderError), so the phone
   code select stays calm when only the number is wrong. Tap-choices keep
   the container rule, since their inputs are visually hidden. */
form input[aria-invalid="true"],
form select[aria-invalid="true"],
form textarea[aria-invalid="true"] {
  border-color: var(--danger);
}

.has-error .tap-choice {
  border-color: var(--danger);
}

/* Quiet per-field success state, set on blur when the field validates.
   A border tint, not a green tick parade: confirmation, not celebration. */
input.is-valid,
select.is-valid,
textarea.is-valid {
  border-color: var(--valid);
}

.field {
  margin-bottom: var(--space-6);
  border: none;
  padding: 0;
}

/* Sections within a step, e.g. Contact / Background / Skills on
   Particulars, mirroring the old Google Form's own section structure.
   Nests ordinary .field elements, so its own last field's margin-bottom
   already provides the internal bottom spacing. */
.field-group {
  border: none;
  padding: 0;
  margin: 0 0 var(--space-7);
}

.field-group > legend {
  font-family: var(--font-serif);
  font-weight: 700;
  font-size: 1.125rem;
  color: var(--accent);
  width: 100%;
  padding-bottom: var(--space-2);
  margin-bottom: var(--space-4);
  border-bottom: 1px solid var(--line);
}

.field-row {
  display: flex;
  gap: var(--space-4);
  flex-wrap: wrap;
}

.field-row .field {
  flex: 1 1 200px;
  margin-bottom: 0;
}

.status-followup {
  margin-top: var(--space-4);
  margin-bottom: 0;
}

.sub-label {
  font-size: 0.875rem;
  margin-bottom: var(--space-1);
}

.phone-code-field {
  flex: 0 0 10rem;
}

.phone-number-field {
  flex: 1 1 200px;
}

/* Small tertiary action: add/remove qualification blocks. */
.btn-ghost {
  font: inherit;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--accent);
  background: transparent;
  border: 1px dashed var(--line);
  border-radius: var(--radius);
  padding: var(--space-2) var(--space-4);
  cursor: pointer;
  transition: border-color var(--transition-fast), background-color var(--transition-fast);
}

.btn-ghost:hover {
  border-color: var(--accent);
  background: var(--accent-soft);
}

.edu-block {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--space-4);
  margin-bottom: var(--space-4);
}

.edu-block .field-row {
  margin-bottom: var(--space-2);
}

.edu-block .btn-ghost {
  border-style: solid;
  color: var(--ink-faint);
}

.edu-block .btn-ghost:hover {
  color: var(--danger);
  border-color: var(--danger);
  background: transparent;
}

/* Screen-time slider: one thumb-drag instead of two number fields. */
.slider-wrap {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--space-4) var(--space-5);
}

.slider-readout {
  font-family: var(--font-serif);
  font-weight: 900;
  font-size: 2rem;
  color: var(--accent);
  margin: 0 0 var(--space-2);
  font-variant-numeric: tabular-nums;
}

.slider-scale {
  display: flex;
  justify-content: space-between;
  font-size: 0.75rem;
  color: var(--ink-faint);
  margin-top: 2px;
}

/* Before the slider is touched: an instruction, not a value. Smaller,
   quiet, no accent, so it cannot be mistaken for an answer. */
.slider-readout.unset {
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: 1rem;
  color: var(--ink-faint);
}

.slider-band {
  min-height: 1.4em;
}

input[type="range"] {
  width: 100%;
  accent-color: var(--accent);
  margin: 0;
}

input[type="range"]:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 4px;
}

label, legend {
  display: block;
  font-weight: 600;
  margin-bottom: var(--space-2);
}

/* UA default fieldset chrome (2px inline margin, ~12px inline padding,
   border) indents everything inside it a few pixels relative to the
   surrounding prose. Reset it so help text and choices sit flush with
   the column edge. */
fieldset {
  margin: 0;
  padding: 0;
  border: 0;
  min-width: 0;
}

legend {
  padding: 0;
  width: 100%;
}

/* Honeypot: off-screen, never display:none (some password managers and
   assistive tools still fill display:none fields, discarding real
   applications server-side). */
.hp-wrap {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

input[type="text"],
input[type="email"],
input[type="tel"],
input[type="url"],
input[type="date"],
input[type="number"],
select,
textarea {
  width: 100%;
  font: inherit;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--space-3);
  transition: border-color var(--transition-fast);
}

textarea {
  resize: vertical;
}

input:hover,
select:hover,
textarea:hover {
  border-color: var(--ink-faint);
}

input:focus-visible,
select:focus-visible,
textarea:focus-visible,
button:focus-visible,
a:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

.other-text {
  margin-top: var(--space-2);
}

.meme-link-field {
  margin-top: var(--space-4);
  margin-bottom: 0;
}

.tap-choice-group {
  display: grid;
  gap: var(--space-3);
  grid-template-columns: 1fr 1fr;
}

.tap-choice {
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  font-weight: 600;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--space-4);
  cursor: pointer;
  min-height: 3rem;
  transition: border-color var(--transition-fast), background-color var(--transition-fast);
}

.tap-choice input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}

.tap-choice:hover {
  border-color: var(--ink-faint);
}

.tap-choice:active {
  background: var(--paper-sunk);
}

/* Two duplicate rules on purpose, NOT one selector list: a browser
   without :has() drops an entire rule containing it, so grouping them
   would kill the fallback in exactly the browsers that need it.
   .checked is mirrored by JS (syncChoiceClasses); keep both in sync. */
.tap-choice:has(input:checked) {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--accent);
}

.tap-choice.checked {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--accent);
}

.tap-choice:has(input:focus-visible) {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

/* JS-mirrored focus for :has-less browsers; a separate rule on purpose,
   same reason as .checked above. */
.tap-choice.focus {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

.checkbox-group,
.radio-group {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.checkbox-item {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  font-weight: 400;
  cursor: pointer;
  padding: var(--space-3) var(--space-2);
  margin: 0 calc(var(--space-2) * -1);
  border-radius: var(--radius);
  transition: background-color var(--transition-fast);
}

.checkbox-item:hover {
  background: var(--paper-sunk);
}

.checkbox-item:active {
  background: var(--accent-soft);
}

.checkbox-item input {
  margin-top: 0.15rem;
  flex-shrink: 0;
  width: 1.1rem;
  height: 1.1rem;
}

.checkbox-item-other {
  margin-top: var(--space-2);
}

.checkbox-field .checkbox-item {
  font-weight: 400;
}

.notice-block {
  background: var(--paper-sunk);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--space-4) var(--space-5);
  margin-bottom: var(--space-5);
}

.notice-block p:last-child {
  margin-bottom: 0;
}

.resume-banner p {
  margin-bottom: var(--space-3);
}

.resume-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}

/* The resume buttons sit inline in the banner, so the primary button must
   not keep its footer-nav margin-left:auto that would shove them apart. */
.resume-actions .btn {
  margin-left: 0;
}

.review-summary dt {
  font-weight: 600;
  margin-top: var(--space-3);
}

.review-summary dd {
  margin: var(--space-1) 0 0;
  color: var(--ink-soft);
}

.review-summary a {
  font-size: 0.8125rem;
}

a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
  transition: text-decoration-thickness var(--transition-fast);
}

a:hover {
  text-decoration-thickness: 2px;
}

.footer-nav {
  position: sticky;
  bottom: 0;
  z-index: var(--z-footer);
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--line);
  background: var(--paper);
}

/* Full-width whisper above the buttons when Continue is not yet ready. */
.next-hint {
  width: 100%;
  margin: 0;
  font-size: 0.8125rem;
  color: var(--ink-faint);
  text-align: right;
}

.btn {
  font: inherit;
  font-weight: 600;
  border-radius: var(--radius);
  padding: var(--space-3) var(--space-6);
  border: 1px solid transparent;
  cursor: pointer;
  min-height: 2.75rem;
  transition: filter var(--transition-fast), transform var(--transition-fast), opacity var(--transition-fast);
}

.btn:hover {
  filter: brightness(0.94);
}

.btn:active {
  transform: scale(0.98);
}

.btn-primary {
  background: var(--accent);
  color: var(--paper);
  margin-left: auto;
}

.btn-secondary {
  background: transparent;
  border-color: var(--line);
  color: var(--ink);
}

.btn-secondary:hover {
  background: var(--paper-sunk);
}

/* Greyed while the current screen is incomplete, per the disable-until-
   valid pattern, but still receives clicks: clicking it renders every
   missing-field error and focuses the first one, so "what is missing" is
   one tap away instead of a guessing game. aria-disabled (not disabled)
   keeps it clickable, focusable, and announced. */
/* "Incomplete", not "dead": this button stays clickable on purpose (a tap
   reveals what is missing), so it must read as pressable-but-not-done.
   Soft accent surface with full-contrast accent text, and never the
   not-allowed cursor, which promises the opposite of what a click does. */
.btn[aria-disabled="true"] {
  background: var(--accent-soft);
  color: var(--accent);
  border: 1px solid var(--line);
  cursor: pointer;
}

.btn[aria-disabled="true"]:hover {
  filter: none;
}

.btn[aria-disabled="true"]:active {
  transform: none;
}

/* The attention-span accompaniment: a muted looping video beside the form,
   desktop only, shown only to applicants who asked for it. */
.runner-pane {
  display: none;
}

.runner-caption {
  font-size: 0.8125rem;
  color: var(--ink-faint);
  margin: var(--space-2) 0 0;
}

/* Confirmation screen: the one moment that has earned a flourish. A stamp,
   not confetti, since "your application has been recorded" is literally
   what a stamp means on a government form. Restarts on its own each time
   the screen goes from hidden to visible; no JS needed.

   width: fit-content matters: as a full-width block, the 0% keyframe's
   scale(1.6) briefly overflowed the viewport horizontally on phones.
   The base rotate(-8deg) matters too: without it the tilt vanished the
   moment the animation finished (no fill-mode, so the element snapped
   back to its unrotated base style). */
.stamp {
  color: var(--accent);
  margin-bottom: var(--space-3);
  width: fit-content;
  transform: rotate(-8deg);
  animation: stamp-in 420ms cubic-bezier(0.16, 1, 0.3, 1);
}

@keyframes stamp-in {
  0% {
    opacity: 0;
    transform: scale(1.6) rotate(-8deg);
  }
  100% {
    opacity: 1;
    transform: scale(1) rotate(-8deg);
  }
}

/* Optional post-submit feedback: set apart from the confirmation prose,
   deliberately quiet. */
.feedback-block {
  margin-top: var(--space-7);
  padding: var(--space-4) var(--space-5);
  background: var(--paper-sunk);
  border-radius: var(--radius);
}

.feedback-block label {
  display: block;
  font-weight: 600;
  margin-bottom: var(--space-2);
}

.feedback-block textarea {
  width: 100%;
  margin-bottom: var(--space-2);
}

.feedback-thanks {
  margin: var(--space-2) 0 0;
  color: var(--ink-soft);
  font-weight: 600;
}

/* The one notice with safety consequences earns a distinct full border,
   quiet but unmistakably different from the sympathetic dead-end block. */
.notice-fee {
  border: 1px solid var(--danger);
}

/* The cycle line sits between the terms prose and the presence question;
   without its own bottom margin it visually fuses with the bold legend
   below it. */
#cycle-dates {
  margin-bottom: var(--space-5);
}

/* Intro language picker: same chips as the header, offered first. The
   coming-soon entry is a label, not a control; it steps back visually
   and cannot be pressed. */
.lang-first .langpick-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
}

.langpick-soon {
  opacity: 0.55;
  cursor: default;
  border-style: dashed; /* visibly not a pressable sibling of the buttons */
}

.soon-tag {
  font-size: 0.6875rem;
  font-style: italic;
  color: var(--ink-faint);
}

/* The office's accounts, on the two screens that end a session. Quiet
   icons at thumb size; the accent arrives on hover, not by default. */
.social-block {
  margin-top: var(--space-6);
  padding-top: var(--space-4);
  border-top: 1px solid var(--line);
}

.social-caption {
  margin: 0 0 var(--space-2);
  font-size: 0.875rem;
  color: var(--ink-soft);
  font-weight: 600;
}

.social-row {
  display: flex;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}

.social-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.5rem;
  min-height: 2.5rem;
  color: var(--ink-faint);
  border-radius: var(--radius);
  transition: color var(--transition-fast);
}

.social-link:hover {
  color: var(--accent);
}

.social-link:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

/* The no-JS message: a class, not a style attribute, because the
   production CSP has no 'unsafe-inline' for styles either. */
.noscript-note {
  max-width: 640px;
  margin: 2rem auto;
  padding: 0 1.25rem;
  font: 1rem/1.5 sans-serif;
}

/* Screen-reader-only live region. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* Soft word cap: over the limit, the counter and field flag it; the text
   itself is never touched. Danger red does the talking. */
.computed-note.over-cap {
  color: var(--danger);
  font-weight: 600;
}

textarea.is-over-cap {
  border-color: var(--danger);
}

/* The one-time paste wink. A status, not a warning: no red. */
.paste-note {
  font-size: 0.8125rem;
  color: var(--ink-faint);
  font-style: italic;
  margin: var(--space-1) 0 0;
}

/* Next-cycle capture inside the terms dead-end. */
.notify-block {
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--line);
}

.notify-block label {
  display: block;
  font-weight: 600;
  margin-bottom: var(--space-2);
}

.notify-row {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
}

.notify-row input {
  flex: 1 1 14rem;
}

/* Review recap: each step's answers under its own heading, the edit
   affordance in the heading row where the eye lands first. */
.review-section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  margin-top: var(--space-6);
  border-bottom: 1px solid var(--line);
  padding-bottom: var(--space-1);
}

.review-section-head:first-child {
  margin-top: 0;
}

.review-section-head h3 {
  margin: 0;
}

.review-edit {
  font-size: 0.875rem;
  white-space: nowrap;
}

/* Skills at the cap: the remaining boxes step back instead of erroring. */
.checkbox-item.capped {
  opacity: 0.5;
}

/* Long prose reads justified on wide screens, with hyphenation so the
   rivers stay closed. Form labels, help lines, and errors stay
   left-aligned: ragged right scans faster at control size. */
@media (min-width: 720px) {
  .screen[data-screen="intro"] > p:not(.fine-print),
  .screen[data-screen="terms"] > p,
  .screen[data-screen="confirmation"] > p {
    text-align: justify;
    hyphens: auto;
  }
}

@media (prefers-reduced-motion: reduce) {
  .screen,
  input,
  select,
  textarea,
  .tap-choice,
  .checkbox-item,
  a,
  .btn,
  .lang-chip,
  .save-note,
  .progress-bar-fill {
    transition: none;
  }

  .stamp {
    animation: none;
  }

  .bug-report.wiggling svg {
    animation: none;
  }

  .theme-toggle:hover,
  .bug-report:hover,
  .theme-toggle:active,
  .bug-report:active,
  .theme-toggle:hover .icon-moon,
  .theme-toggle:hover .icon-sun {
    transform: none;
  }
}

@media (min-width: 720px) {
  main {
    padding: var(--space-8) var(--space-5) calc(var(--space-8) + var(--space-2));
  }

  .footer-nav {
    width: 100%;
    max-width: var(--max-width);
    margin: 0 auto;
    border-top: none;
    position: static;
    padding: 0 0 var(--space-8);
  }
}

/* Desktop with the accompaniment active: the form keeps its column, the
   video docks beside it. body.runner-on is the applicant's yes;
   body.in-form limits it to the form steps (not intro or confirmation);
   body.runner-ok means the video file actually loaded. */
@media (min-width: 1100px) {
  body.runner-on.in-form.runner-ok:not(.runner-dismissed) main {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 300px;
    gap: var(--space-7);
    max-width: calc(var(--max-width) + 300px + var(--space-7) + 2 * var(--space-5));
    margin: 0 auto;
    width: 100%;
  }

  body.runner-on.in-form.runner-ok:not(.runner-dismissed) .runner-pane {
    display: block;
    position: sticky;
    top: calc(var(--space-8) + var(--space-4));
    align-self: start;
  }

  .runner-pane video {
    width: 100%;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    display: block;
    background: var(--paper-sunk);
  }

  /* Muted autoplay refused: the pane owns up and plays on a tap instead
     of posing as a broken video. */
  .runner-pane.needs-tap {
    cursor: pointer;
    position: relative;
  }

  .runner-pane.needs-tap video {
    opacity: 0.55;
  }

  .runner-pane.needs-tap::after {
    content: "Tap to play";
    position: absolute;
    top: 40%;
    left: 50%;
    transform: translate(-50%, -50%);
    font-weight: 700;
    font-size: 0.9375rem;
    color: var(--ink);
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: 999px;
    padding: 0.4rem 1rem;
  }

  /* The footer must track the FORM column, not the page: when main
     becomes a two-column grid for the video pane, a page-centered footer
     drifts right and Continue ends up under the video. Same overall
     width as the grid, with the pane's width held as right padding so
     the buttons stay aligned with the answers they advance. */
  body.runner-on.in-form.runner-ok:not(.runner-dismissed) .footer-nav {
    max-width: calc(var(--max-width) + 300px + var(--space-7));
    padding-right: calc(300px + var(--space-7));
  }

  /* The polite way out of the gag: quiet, under the caption, and the
     recorded answer to the attention question stays untouched. */
  .runner-hide {
    font: inherit;
    font-size: 0.75rem;
    color: var(--ink-faint);
    background: transparent;
    border: none;
    padding: 0.2rem 0;
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 2px;
  }

  .runner-hide:hover {
    color: var(--ink-soft);
  }
}
