/* Public visitor pages — one framed composition (Phase 10 redesign, ADR-0092).
   A warm page with two very faint tonal washes; over it, a translucent "stage" whose top
   band is the fixed institutional identity and whose bottom edge is the attribution.
   Campaign identity arrives only through /c/{id}/theme.css custom properties (ADR-0085)
   and touches the action, focus and small accents — never the institutional band.
   Healthcare visual language (ADR-0093): abstract care rings and a health-pulse line,
   static SVG files used only as CSS masks and painted with the theme's derived tones —
   below the institutional band only. Mobile-first; no raster decoration; no motion loops. */

:root {
  /* Platform fallback when a page has no campaign theme (e.g. not found). */
  --campaign-accent: var(--accent);
  --campaign-button-bg: var(--accent);
  --campaign-button-fg: #fff;
  --campaign-button-hover: var(--accent-hover);
  --campaign-button-border: var(--accent);
  --campaign-ink: var(--accent);
  --campaign-soft: var(--accent-soft);
  --campaign-line: #b3a28e; /* neutral decorative tones when no theme applies */
  --campaign-faint: #f1ede7;
  --campaign-glow: #e9e2d8;
  --campaign-mark: var(--accent);

  --stage-max: 72rem;
  --stage-radius: 22px;
  --stage-pad: clamp(1.25rem, 0.6rem + 3.2vw, 4rem);
  --glass: rgb(255 255 255 / 58%);
  --glass-strong: rgb(255 255 255 / 78%);
  --hairline: rgb(24 24 27 / 7%);
}

/* --- Page and background washes -------------------------------------------------------- */

.public-page {
  --focus: var(--campaign-ink);
  --motif-rings: url("../images/motif/care-rings.svg");
  --motif-pulse: url("../images/motif/pulse.svg");
  min-block-size: 100dvh;
  background: #f5f3ef;
  overflow-x: hidden;
}

/* Two fixed, very soft washes: warm sand low on one side, a trace of the campaign colour
   high on the other. They give the glass something real to blur — nothing more. */
.public-page::before,
.public-page::after {
  content: "";
  position: fixed;
  z-index: -1;
  inline-size: 70vmax;
  block-size: 70vmax;
  border-radius: 50%;
  pointer-events: none;
}

.public-page::before {
  inset-block-start: -30vmax;
  inset-inline-start: -24vmax;
  background: radial-gradient(closest-side, var(--campaign-faint), rgb(255 255 255 / 0%));
}

.public-page::after {
  inset-block-end: -36vmax;
  inset-inline-end: -28vmax;
  background: radial-gradient(closest-side, #e9dfd2, rgb(245 243 239 / 0%));
}

/* --- The stage --------------------------------------------------------------------------- */

/* The page shell: at least one viewport tall (svh, vh fallback), a flex column. Header and
   sections keep their natural height, the main region takes what is left, and the footer
   rests at the bottom of a short page — or simply follows a long one. Nothing is fixed,
   sticky or absolutely positioned. */
.stage {
  position: relative;
  isolation: isolate;
  display: flex;
  flex-direction: column;
  min-block-size: 100vh;
  min-block-size: 100svh; /* the smallest viewport: no jump when browser chrome moves */
}

.stage-body {
  flex: 1 0 auto;
  display: grid;
  align-content: center;
  gap: clamp(1.5rem, 1rem + 2.5vw, 3rem);
  padding: clamp(1.25rem, 0.8rem + 2.5vw, 3.5rem) var(--stage-pad);
}

@media (min-width: 40rem) {
  .public-page {
    padding: 1.25rem; /* padding, not margins: no collapse, no stray scroll */
  }

  .stage {
    inline-size: min(100%, var(--stage-max));
    min-block-size: calc(100vh - 2.5rem);
    min-block-size: calc(100svh - 2.5rem);
    margin-inline: auto;
    background: var(--glass);
    border: 1px solid rgb(255 255 255 / 80%);
    border-radius: var(--stage-radius);
    box-shadow:
      0 0 0 1px var(--hairline),
      0 40px 80px -48px rgb(24 24 27 / 22%);
    -webkit-backdrop-filter: blur(22px) saturate(1.12);
    backdrop-filter: blur(22px) saturate(1.12);
    overflow: clip;
  }
}

@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .stage {
    background: #fbfaf8; /* clean opaque fallback */
  }
}

/* --- Institutional band (ADR-0091) ------------------------------------------------------- */

.institution {
  display: flex;
  gap: var(--space-4);
  align-items: center;
  justify-content: space-between;
  padding: clamp(0.7rem, 0.5rem + 1vw, 1.35rem) var(--stage-pad);
  padding-block-start: calc(clamp(0.7rem, 0.5rem + 1vw, 1.35rem) + env(safe-area-inset-top, 0px));
  background: rgb(253 252 250 / 96%); /* a stable neutral identity surface: no campaign light reaches it */
  border-block-end: 1px solid var(--hairline);
}

.institution-logo {
  display: block;
  flex: 0 1 auto;
  min-inline-size: 0;
  inline-size: auto;
  block-size: clamp(2.25rem, 1.8rem + 2.1vw, 3.75rem);
  max-inline-size: 62%;
  object-fit: contain; /* the official logo: never cropped, stretched or recoloured */
}

.institution-department {
  flex: 0 1 auto;
  margin: 0;
  margin-inline-start: auto; /* always on the left in RTL, with or without the logo */
  padding-inline-start: clamp(0.75rem, 0.4rem + 1.2vw, 1.25rem);
  border-inline-start: 1px solid var(--border-strong);
  color: var(--ink);
  font-size: clamp(0.875rem, 0.8rem + 0.35vw, 1.0625rem);
  font-weight: 700;
  line-height: 1.5;
  text-wrap: balance; /* one line at normal text sizes; wraps only under large text zoom */
}

/* --- Campaign: initial state --------------------------------------------------------------- */

/* The campaign field: the campaign's own tinted ground, directly under the institutional
   band — a band on phones, a full-height half of the stage on wide screens. */
.stage-campaign {
  align-content: start; /* band, then the action right below it: nothing re-centres */
  gap: clamp(1.5rem, 3.5svh, 2.25rem);
  padding-block-start: 0;
}

.campaign-intro {
  position: relative;
  display: grid;
  gap: 0.75rem;
  justify-items: start;
  align-content: center;
  margin-inline: calc(var(--stage-pad) * -1);
  min-block-size: 24vh;
  min-block-size: 24svh; /* proportionate on tall phones, never a hero */
  padding: clamp(1.25rem, 0.9rem + 1.6vw, 3rem) var(--stage-pad) clamp(1.5rem, 1.1rem + 1.6vw, 3.25rem);
  overflow: hidden;
  isolation: isolate; /* motifs sit above the field's ground, below its text */
  /* Reflected light (ADR-0093): only the feathered edge of a source beyond the right
     perimeter (the page is always RTL) enters; the title stays on a neutral surface. */
  background:
    radial-gradient(16% 75% at 104% 70%, var(--campaign-faint), rgb(255 255 255 / 0%) 100%),
    rgb(255 255 255 / 35%);
  border-block-end: 1px solid var(--hairline);
}

.stage-campaign.is-result {
  padding-block-start: clamp(1.25rem, 0.8rem + 2.5vw, 3.5rem);
  /* The same reflected light, at the heading side's perimeter only. */
  background: radial-gradient(14% 45% at 103% 26%, var(--campaign-faint), rgb(255 255 255 / 0%) 100%);
}

/* --- Healthcare motifs (ADR-0093) -----------------------------------------------------------
   Each motif is one pseudo-element: a block of the derived line tone, cut by a static SVG
   mask. No mask support → no motif (never a solid block). */
.campaign-intro::after,
.campaign-intro::before,
.campaign-title::after,
.result-head::before {
  content: none;
}

@supports (mask-image: url("")) or (-webkit-mask-image: url("")) {
  .campaign-intro::after,
  .campaign-intro::before,
  .campaign-title::after,
  .result-head::before {
    content: "";
    position: absolute;
    z-index: -1;
    background: var(--campaign-line);
    pointer-events: none;
    -webkit-mask: var(--motif-rings) center / contain no-repeat;
    mask: var(--motif-rings) center / contain no-repeat;
  }

  /* Phones: one small cluster tucked into the band's far corner, away from the title. */
  .campaign-intro::after {
    inset-block-start: -5rem;
    inset-inline-end: -4.5rem;
    inline-size: 11rem;
    block-size: 11rem;
    opacity: 0.14;
  }

  /* The pulse: a thin line passing under the title, fading out at both ends. */
  .campaign-title {
    position: relative;
  }

  .campaign-title::after {
    inset-block-start: calc(100% - 0.1rem);
    inset-inline-start: calc(var(--stage-pad) * -1);
    inline-size: 26rem;
    block-size: 1.75rem;
    opacity: 0.36;
    -webkit-mask: var(--motif-pulse) 0 0 / 100% 100% no-repeat;
    mask: var(--motif-pulse) 0 0 / 100% 100% no-repeat;
  }
}

/* --- Campaign logo: a white "logo safe area" (ADR-0096) ------------------------------------
   One intended surface for any logo — transparent, white-background or opaque — so a white
   JPEG blends into the card instead of reading as a pasted rectangle. The frame hugs the
   logo's own shape (wide, square, tall), the image keeps its ratio (contain, never cropped
   or stretched) and is never enlarged beyond its natural size. Neutral surface and
   border: the campaign colour is not used as its background. */
.campaign-logo {
  display: flex;
  align-items: center;
  justify-content: center;
  inline-size: fit-content;
  max-inline-size: min(100%, 23.5rem);
  padding: clamp(0.75rem, 0.55rem + 0.6vw, 1rem) clamp(0.9rem, 0.6rem + 1vw, 1.375rem);
  background: #fff;
  border: 1px solid rgb(24 24 27 / 8%);
  border-radius: 16px;
  box-shadow:
    0 1px 2px rgb(24 24 27 / 4%),
    0 10px 24px -20px rgb(24 24 27 / 22%);
}

.campaign-logo img {
  display: block;
  inline-size: auto;
  block-size: auto;
  max-inline-size: min(100%, 20rem); /* ~320 px for wide logos */
  max-block-size: 6.5rem; /* ~104 px */
  object-fit: contain;
}

/* Result: the card is the hero — a smaller, quieter version keeps the actions close. */
.campaign-logo--compact {
  padding: 0.5rem 0.85rem;
  border-radius: 14px;
}

.campaign-logo--compact img {
  max-inline-size: min(100%, 13rem);
  max-block-size: 3.75rem;
}

.campaign-intro .campaign-logo {
  margin-block-end: 0.75rem; /* breathing room before the title's lead-in stroke */
}

.result-head .campaign-logo {
  justify-self: center;
  margin-block-end: 0.5rem;
}

.ended .campaign-logo {
  margin-block-end: 1.25rem;
}

/* The title's lead-in: a short solid stroke that thins out like the pulse line, starting
   exactly at the title's edge. */
.accent-mark {
  display: block;
  inline-size: 4.75rem;
  block-size: 3px;
  background: linear-gradient(to left, var(--campaign-mark) 0 2.25rem, rgb(255 255 255 / 0%));
  border-radius: 2px;
}

.campaign-title {
  margin: 0;
  margin-block-end: 0.5rem; /* room for the pulse */
  max-inline-size: 16ch;
  color: var(--ink);
  font-size: clamp(1.875rem, 1.3rem + 2.6vw, 3.5rem);
  font-weight: 700;
  line-height: 1.22;
  overflow-wrap: anywhere;
  text-wrap: balance;
}

/* The action: an integrated, refined panel — not a heavy card. */
/* The action: label, field and button as one short sequence — spacing and hierarchy, no
   card chrome around a single input. */
.name-panel {
  display: grid;
  gap: 0.875rem;
  inline-size: 100%;
  max-inline-size: 30rem;
  justify-self: center;
  align-self: start;
}

.name-panel .field {
  gap: 0.25rem;
}

.name-panel label {
  font-size: 1.125rem;
}

.name-hint {
  margin: 0 0 0.5rem;
  color: var(--muted);
  font-size: 0.875rem;
  line-height: 1.5;
}

.name-panel input[type="text"] {
  min-block-size: 3.375rem;
  inline-size: 100%;
  padding-inline: var(--space-4);
  font-size: 1.125rem; /* >= 16px also prevents iOS zoom on focus */
  background: #fff;
  border: 1.5px solid var(--input-border);
  border-radius: 12px;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.name-panel input[type="text"]:focus-visible {
  border-color: var(--campaign-ink);
  outline: none;
  box-shadow: 0 0 0 4px var(--campaign-soft), 0 0 0 5.5px var(--campaign-ink);
}

.name-panel input[aria-invalid="true"] {
  border-color: var(--danger);
}

/* Loading: a thin, truthful activity line along the panel's top edge (no skeleton). */
.name-panel[aria-busy="true"] {
  position: relative;
  overflow: hidden;
}

.name-panel[aria-busy="true"]::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  block-size: 3px;
  background: linear-gradient(90deg, transparent, var(--campaign-accent), transparent);
  background-size: 50% 100%;
  background-repeat: no-repeat;
  animation: activity 1.4s ease-in-out infinite;
}

@keyframes activity {
  from {
    background-position: -60% 0;
  }

  to {
    background-position: 160% 0;
  }
}

/* --- Buttons in the campaign colour ------------------------------------------------------- */

.button-campaign {
  min-block-size: 3.5rem;
  font-size: 1.125rem;
  color: var(--campaign-button-fg);
  background: var(--campaign-button-bg);
  border: 1px solid var(--campaign-button-border);
  border-radius: 12px;
}

.button-campaign:hover {
  color: var(--campaign-button-fg);
  background: var(--campaign-button-hover);
}

.button-campaign:focus-visible,
.button-outline:focus-visible,
.result-again:focus-visible {
  outline: 3px solid var(--campaign-ink);
  outline-offset: 3px;
}

.button-campaign[aria-busy="true"],
.button-campaign:disabled {
  opacity: 0.8;
  cursor: progress;
}

.button-campaign[aria-busy="true"]::before {
  content: "";
  inline-size: 1rem;
  block-size: 1rem;
  border: 2px solid currentcolor;
  border-inline-end-color: transparent;
  border-radius: 50%;
  animation: spin 0.9s linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

.button-outline {
  min-block-size: 3.25rem;
  color: var(--ink);
  background: rgb(255 255 255 / 70%);
  border: 1px solid var(--border-strong);
  border-radius: 12px;
}

.button-outline:hover {
  color: var(--ink);
  background: #fff;
  border-color: var(--input-border);
}

.visitor-status {
  min-block-size: 1.6em;
  margin: 0;
  color: var(--muted);
  font-size: 0.9375rem;
  text-align: center;
}

/* Empty status lines take no space but stay rendered, so aria-live still announces. */
.visitor-status:empty {
  min-block-size: 0;
  block-size: 0;
  overflow: hidden;
}

.visitor-status.is-error {
  color: var(--danger);
  font-weight: 700;
}

/* --- Result: the generated card becomes the hero ------------------------------------------ */

.result {
  display: grid;
  gap: var(--space-5);
}

.result-head {
  position: relative;
  isolation: isolate;
  display: grid;
  gap: var(--space-2);
  text-align: center;
}

@supports (mask-image: url("")) or (-webkit-mask-image: url("")) {
  /* The same care rings, quietly behind the heading: the card stays the hero. */
  .result-head::before {
    inset-block-start: 50%;
    inset-inline-start: 50%;
    inline-size: 13rem;
    block-size: 13rem;
    opacity: 0.09; /* phones: barely there, drifting off the outer edge */
    transform: translate(95%, -60%);
  }
}

.result-eyebrow {
  margin: 0;
  color: var(--campaign-ink);
  font-size: 0.9375rem;
  font-weight: 700;
}

.result h1 {
  margin: 0;
  font-size: clamp(1.75rem, 1.35rem + 1.8vw, 2.5rem);
  line-height: 1.25;
}

.result h1:focus {
  outline: none;
}

.result-lead {
  margin: 0;
  color: var(--muted);
}

.result-card {
  justify-self: center;
  margin: 0;
  padding: clamp(0.4rem, 0.3rem + 0.4vw, 0.65rem);
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 18px;
  box-shadow: 0 30px 60px -34px rgb(24 24 27 / 38%);
}

.result-card img {
  display: block;
  inline-size: auto;
  block-size: auto;
  max-inline-size: 100%;
  max-block-size: min(56vh, 46rem);
  max-block-size: min(56svh, 46rem); /* actions stay within reach below the card */
  border-radius: 12px;
}

.result-actions {
  display: grid;
  gap: var(--space-3);
  inline-size: 100%;
  max-inline-size: 26rem;
  justify-self: center;
}

.result-again {
  justify-self: center;
  min-block-size: 2.75rem;
  padding-inline: var(--space-3);
  font-size: 1rem;
}

.result-hint {
  margin: 0;
  color: var(--muted);
  font-size: 0.875rem;
  text-align: center;
}

/* A deliberate reveal (skipped with reduced motion). */
.is-result .result {
  animation: reveal 0.45s ease-out both;
}

@keyframes reveal {
  from {
    opacity: 0;
    transform: translateY(12px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

/* --- Ended / not available: a closing chapter (ADR-0093) ------------------------------------
   The same campaign atmosphere, rearranged: light from the upper outer corner, partial care
   rings at the periphery, a short pulse fading in from the far side. No icon, no action. */

.stage-ended {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  align-content: center;
  justify-items: start;
  /* Peripheral reflected light framing the message — never behind the text itself. */
  background:
    radial-gradient(22% 40% at 104% 0%, var(--campaign-glow), rgb(255 255 255 / 0%) 100%),
    radial-gradient(20% 34% at -4% 104%, var(--campaign-faint), rgb(255 255 255 / 0%) 100%);
}

.ended {
  display: grid;
  max-inline-size: 36rem;
}

.ended-context {
  display: flex;
  gap: var(--space-3);
  align-items: center;
  margin: 0 0 0.6rem;
  color: var(--campaign-ink);
  font-size: 1rem;
  font-weight: 700;
}

/* The campaign's lead-in stroke, as above the active title. */
.ended-rule {
  flex: none;
  inline-size: 3.25rem;
  block-size: 2px;
  background: linear-gradient(to left, var(--campaign-mark) 0 1.5rem, rgb(255 255 255 / 0%));
  border-radius: 2px;
}

.ended-title {
  margin: 0;
  font-size: clamp(2.25rem, 1.5rem + 3vw, 3.75rem);
  font-weight: 700;
  line-height: 1.2;
  text-wrap: balance;
}

.ended-thanks {
  margin: 1.1rem 0 0;
  color: var(--muted);
  font-size: clamp(1.125rem, 1rem + 0.5vw, 1.375rem);
}

@supports (mask-image: url("")) or (-webkit-mask-image: url("")) {
  .stage-ended::before,
  .stage-ended::after,
  .ended::after {
    content: "";
    position: absolute;
    z-index: -1;
    background: var(--campaign-line);
    pointer-events: none;
    -webkit-mask: var(--motif-rings) center / contain no-repeat;
    mask: var(--motif-rings) center / contain no-repeat;
  }

  /* Phones: one partial cluster entering from the upper outer corner … */
  .stage-ended::before {
    inset-block-start: -6rem;
    inset-inline-start: -6rem;
    inline-size: 14rem;
    block-size: 14rem;
    opacity: 0.16;
    transform: rotate(30deg);
  }

  /* … and a short pulse fading in from the far side, below the message. */
  .ended::after {
    inset-block-start: calc(50% + 6rem);
    inset-inline-end: -9rem;
    inline-size: 22rem;
    block-size: 2.25rem;
    opacity: 0.32;
    -webkit-mask: var(--motif-pulse) 0 0 / 100% 100% no-repeat;
    mask: var(--motif-pulse) 0 0 / 100% 100% no-repeat;
  }

  /* Not available: the same family, quieter — light and rings only. */
  .ended-quiet .ended::after {
    content: none;
  }

  .ended-quiet::before {
    opacity: 0.1;
  }
}

/* --- Footer: the stage's quiet bottom edge ------------------------------------------------- */

.stage-footer {
  margin-block-start: auto; /* rests at the bottom of the shell when content is short */
  display: flex;
  flex-wrap: wrap;
  gap: 0.15rem 1.25rem;
  justify-content: center;
  padding: var(--space-4) var(--stage-pad) calc(var(--space-4) + env(safe-area-inset-bottom, 0px));
  color: var(--muted);
  font-size: 0.8125rem;
  line-height: 1.8;
  text-align: center;
  border-block-start: 1px solid var(--hairline);
}

.stage-footer p {
  margin: 0;
}

.stage-footer p + p {
  font-size: 0.75rem; /* the attribution stays secondary to the rights line */
}

.footer-rights {
  text-wrap: balance; /* wraps gracefully on phones instead of shrinking */
}

.developer-link {
  color: var(--ink);
  font-weight: 600;
  text-decoration: none;
  unicode-bidi: isolate;
}

.developer-link:hover,
.developer-link:focus-visible {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
}

.developer-link:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
  border-radius: 2px;
}

/* --- Wider screens: an asymmetric two-part stage ------------------------------------------ */

@media (min-width: 56rem) {
  .stage-campaign {
    grid-template-columns: minmax(0, 1.1fr) minmax(24rem, 0.9fr);
    align-content: stretch;
    padding: 0;
    gap: 0;
  }

  .campaign-intro {
    margin: 0;
    padding: var(--stage-pad);
    border-block-end: 0;
    border-inline-end: 1px solid var(--hairline);
    /* Background depth: offset, overlapping fields of reflected light from the far right —
       broad and feathered, never a visible circle; the inner side stays near-white. */
    background:
      radial-gradient(18% 46% at 106% 66%, var(--campaign-glow), var(--campaign-faint) 45%, rgb(255 255 255 / 0%) 100%),
      radial-gradient(30% 24% at 102% 104%, var(--campaign-faint), rgb(255 255 255 / 0%) 100%),
      radial-gradient(24% 14% at 92% 94%, var(--campaign-faint), rgb(255 255 255 / 0%) 100%),
      rgb(255 255 255 / 30%);
  }

  @supports (mask-image: url("")) or (-webkit-mask-image: url("")) {
    /* Midground: a large cluster dissolving into the light at the lower outer corner, a
       small, fainter one near the split — different scales, both cut by the edges. */
    .campaign-intro::after {
      inset-block-start: auto;
      inset-block-end: -13rem;
      inset-inline-end: auto;
      inset-inline-start: -10rem;
      inline-size: 32rem;
      block-size: 32rem;
      opacity: 0.22;
      transform: rotate(-24deg);
      -webkit-mask:
        var(--motif-rings) center / contain no-repeat,
        radial-gradient(closest-side circle at 66% 62%, #000, rgb(0 0 0 / 30%));
      -webkit-mask-composite: source-in;
      mask:
        var(--motif-rings) center / contain no-repeat intersect,
        radial-gradient(closest-side circle at 66% 62%, #000, rgb(0 0 0 / 30%));
    }

    .campaign-intro::before {
      inset-block-start: -4.5rem;
      inset-inline-end: -3rem;
      inline-size: 12rem;
      block-size: 12rem;
      opacity: 0.12;
      transform: rotate(150deg);
    }

    .campaign-title::after {
      inset-block-start: calc(100% + 0.75rem);
      inline-size: 44rem;
      block-size: 3.25rem;
      opacity: 0.6;
    }

    .result-head::before {
      inset-inline-start: 0;
      inline-size: 20rem;
      block-size: 20rem;
      opacity: 0.16;
      transform: translate(10%, -50%);
    }
  }

  .campaign-title {
    font-size: clamp(2.5rem, 1.2rem + 2.6vw, 3.75rem);
  }

  .stage-campaign {
    grid-template-rows: none;
  }

  .name-panel label {
    font-size: 1.375rem;
  }

  .name-hint {
    font-size: 1rem;
  }

  /* The action half is itself the panel: no card inside a card. */
  .name-panel {
    align-self: center;
    margin: var(--stage-pad);
    inline-size: calc(100% - 2 * var(--stage-pad));
    max-inline-size: 26rem;
    padding: 0;
    background: none;
    border: 0;
    box-shadow: none;
  }

  .name-panel[aria-busy="true"]::before {
    inset-block-start: -1rem;
  }

  /* Result: the card on one side, the heading and actions on the other. */
  .stage-campaign.is-result {
    grid-template-columns: 1fr;
    align-content: center;
    padding: clamp(1.75rem, 1rem + 3vw, 3.5rem) var(--stage-pad);
  }

  .result {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "head card"
      "actions card";
    align-items: center;
    column-gap: clamp(2.5rem, 1rem + 4vw, 5.5rem);
    row-gap: var(--space-5);
  }

  .result-head {
    grid-area: head;
    align-self: end;
    text-align: start;
  }

  .result-head .campaign-logo {
    justify-self: start;
  }

  .result-card {
    grid-area: card;
  }

  .result-card img {
    max-block-size: min(56vh, 44rem);
  }

  .result-actions {
    grid-area: actions;
    align-self: start;
    justify-self: start;
  }

  .result-again,
  .result-hint {
    justify-self: start;
    text-align: start;
  }

  .stage-footer {
    justify-content: space-between;
  }
}

@media (min-width: 56rem) {
  /* Ended: the message sits in the light's side, offset from the centre; the periphery
     carries the larger forms; the far side keeps quiet negative space. */
  .stage-ended {
    padding-inline-start: calc(var(--stage-pad) + 4vw);
  }

  @supports (mask-image: url("")) or (-webkit-mask-image: url("")) {
    .stage-ended::before {
      inset-block-start: -10rem;
      inset-inline-start: -8rem;
      inline-size: 24rem;
      block-size: 24rem;
      opacity: 0.18;
    }

    .stage-ended::after {
      inset-block-end: -22rem;
      inset-inline-end: -14rem;
      inline-size: 44rem;
      block-size: 44rem;
      opacity: 0.16;
      transform: rotate(-40deg);
    }

    .ended::after {
      inset-block-start: calc(50% + 3rem);
      inset-inline-end: -14rem;
      inline-size: 52rem;
      block-size: 3rem;
      opacity: 0.4;
    }

    .ended-quiet::after {
      opacity: 0.07;
    }
  }
}

/* --- Phones and small tablets: a calmer, compact, content-sized composition ----------------
   Mobile is the primary experience (ADR-0093); everything here is subtraction relative to the
   shared rules, and nothing here reaches the desktop layout (≥ 56rem). */
@media (max-width: 55.99rem) {
  :root {
    --stage-pad: 1.375rem; /* ~22px gutters */
  }

  .institution {
    padding-block: 0.75rem;
    padding-block-start: calc(0.75rem + env(safe-area-inset-top, 0px));
  }

  .institution-logo {
    block-size: 2.5rem;
  }

  .institution-department {
    padding-inline-start: 0.75rem;
    font-size: 0.8125rem;
    font-weight: 600;
  }

  /* Active: a compact identity strip. */
  .stage-campaign {
    gap: 1.5rem;
    padding-block-end: 2rem;
  }

  .campaign-intro {
    min-block-size: 9.5rem;
    gap: 0.625rem;
    padding-block: 1.5rem 1.75rem;
    background:
      radial-gradient(10% 55% at 103% 70%, var(--campaign-faint), rgb(255 255 255 / 0%) 100%),
      rgb(255 255 255 / 35%);
  }

  .campaign-intro .campaign-logo {
    justify-self: center; /* phones: centred between the header and the title */
    max-inline-size: min(100%, 19rem);
    margin-block-end: 0.5rem;
  }

  .campaign-logo img {
    max-block-size: 4.5rem; /* wide logos stay short on a phone */
  }

  .campaign-logo--compact img {
    max-inline-size: min(100%, 11rem);
    max-block-size: 3.25rem;
  }

  .accent-mark {
    inline-size: 3.5rem;
    background: linear-gradient(to left, var(--campaign-mark) 0 1.75rem, rgb(255 255 255 / 0%));
  }

  .campaign-title {
    font-size: clamp(1.75rem, 1.45rem + 1.3vw, 2.25rem);
    line-height: 1.3;
  }

  @supports (mask-image: url("")) or (-webkit-mask-image: url("")) {
    /* One quiet cluster, mostly outside the canvas: only fragments enter. */
    .campaign-intro::after {
      inset-block-start: -7rem;
      inset-inline-end: -7rem;
      inline-size: 11rem;
      block-size: 11rem;
      opacity: 0.1;
    }

    /* A short pulse segment under the title — never a full-width rule. */
    .campaign-title::after {
      inset-block-start: calc(100% - 0.15rem);
      inset-inline-start: -0.75rem;
      inline-size: 11.5rem;
      block-size: 1.5rem;
      opacity: 0.32;
    }

    .result-head::before {
      opacity: 0.05;
    }
  }

  /* The interaction: one compact unit. */
  .name-panel {
    gap: 0.75rem;
  }

  .name-panel .field {
    gap: 0.125rem;
  }

  .name-panel label {
    font-size: 1.25rem;
  }

  .name-hint {
    margin-block-end: 0.375rem;
    font-size: 0.9375rem;
  }

  .name-panel input[type="text"] {
    min-block-size: 3.25rem;
    font-size: 1.0625rem; /* still >= 16px: no iOS zoom */
    border: 1px solid var(--border-strong);
    border-radius: 12px;
  }

  .name-panel input[type="text"]:focus-visible {
    border-color: var(--campaign-ink);
    box-shadow: 0 0 0 3px var(--campaign-soft); /* one soft ring, no nested borders */
  }

  .button-campaign {
    min-block-size: 3.25rem;
    font-size: 1.0625rem;
    border-radius: 12px;
  }

  .button-outline {
    min-block-size: 3.25rem;
    font-size: 1rem;
    border-color: var(--border);
  }

  /* Result: a compact heading, a preview-sized card, a short action stack. */
  .stage-campaign.is-result {
    padding-block-start: 1.25rem;
  }

  .result {
    gap: 1rem;
  }

  .result-head {
    gap: 0.125rem;
  }

  .result-eyebrow {
    font-size: 0.8125rem;
  }

  .result h1 {
    font-size: 1.625rem;
  }

  .result-lead {
    font-size: 0.9375rem;
  }

  .result-card {
    padding: 4px;
    border-radius: 14px;
    box-shadow: 0 12px 28px -22px rgb(24 24 27 / 30%);
  }

  .result-card img {
    max-inline-size: min(70vw, 18rem);
    max-block-size: min(54vh, 28rem);
    max-block-size: min(54svh, 28rem);
    border-radius: 10px;
  }

  .result-actions {
    gap: 0.625rem;
  }

  .result-again {
    min-block-size: 2.75rem;
    font-size: 0.9375rem;
  }

  .result-hint {
    font-size: 0.8125rem;
  }

  /* Ended: content-sized, with its own breathing room. */
  .stage-ended {
    padding-block: 3.5rem 4rem;
  }

  /* Footer: lighter, tighter, secondary. */
  .stage-footer {
    padding-block: 0.875rem calc(0.875rem + env(safe-area-inset-bottom, 0px));
    font-size: 0.75rem;
    line-height: 1.7;
  }

  .stage-footer p + p {
    font-size: 0.6875rem;
  }
}

/* Short phones (e.g. 320 x 568): keep the result actions near — a smaller compact logo and
   card preview, so the campaign logo never pushes the download far below the fold. */
@media (max-width: 55.99rem) and (max-height: 40rem) {
  .campaign-logo--compact {
    padding: 0.375rem 0.7rem;
  }

  .campaign-logo--compact img {
    max-block-size: 2.5rem;
  }

  .result-card img {
    max-block-size: min(44vh, 24rem);
    max-block-size: min(44svh, 24rem);
  }
}

@media (max-width: 22.5rem) {
  :root {
    --stage-pad: 1rem;
  }

  .institution {
    gap: var(--space-3);
  }

  .institution-logo {
    block-size: 2.25rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .is-result .result,
  .name-panel[aria-busy="true"]::before,
  .button-campaign[aria-busy="true"]::before {
    animation: none;
  }

  .button-campaign[aria-busy="true"]::before {
    display: none;
  }
}
