/*
  Aeris Interview: app/shared/app.css, every screen's frame and components on the design pack (DSi's copy: packs/dsi-platforms/).
  Owns: the page frame (top bar, admin navigation, heading band, panel, footer), cards, buttons, status pills, messages, forms,
  tables, the candidate pages and the interview, the job roles page, and Aeris's sign-in page.
  Depends on: the pack's stylesheet, loaded first, for every colour, the font and the page's base. Spec 16.8 and 16.9, the design
  note "Aeris Interview screens in the new Light and Dark look" v1 (rules 1 to 10) and screen mock v0.5, which Nathan approved on
  23 October 2026.
  Contract: every colour is one of the pack's tokens, so both themes read, and the one colour written here is the white backing
  panel the DSi logo file needs. Boxes are the brief's card, with no coloured bar along any edge. Nothing is only a colour: a
  status is a word in a pill, and a refused field changes shape. Two columns below 1100 px and one below 700 px, with no
  sideways scrolling at 375 px: wide tables become stacked cards below 1100 px. Those layouts are for screens only, so a
  printed page keeps its tables. No rule here sets a style that the Content-Security-Policy would need to allow inline.
*/
:root {
  /* The approved logo file is a transparent PNG for light backgrounds, so it sits on a white backing panel (visual
     identity 5.6). White is constant in both themes. */
  --logo-panel: #ffffff;
}

[hidden] {
  display: none !important;
}

/* One page: top bar, main and footer. */
.app {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

a {
  color: var(--brand);
}

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

.app-skip {
  position: absolute;
  top: -60px;
  left: 16px;
  z-index: 10;
  padding: 8px 14px;
  border-radius: 6px;
  background: var(--cyan);
  color: var(--on-cyan);
  font-weight: 700;
  text-decoration: none;
}

.app-skip:focus {
  top: 12px;
}

/* ===== the top bar (rule 6): wordmark, product and area, then the name, the platforms link, the switch and Sign out ===== */
.app-top {
  background: var(--bg-deep);
  border-bottom: 1px solid var(--divider);
}

.app-top-row {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 18px 48px;
}

.app-mark {
  font-size: 24px;
  font-weight: 700;
  line-height: 1.2;
  white-space: nowrap;
}

.app-mark span {
  color: var(--brand);
}

.app-product {
  display: inline-flex;
  align-items: baseline;
  gap: 10px;
  color: var(--text);
  text-decoration: none;
  white-space: nowrap;
}

/* Only after a wordmark that shows: the sign-in page keeps its wordmark in the markup, hidden, on a customer's copy. */
.app-mark:not([hidden]) + .app-product {
  padding-left: 16px;
  border-left: 1px solid var(--border-quiet);
}

.app-product b {
  font-size: 18px;
}

.app-product span {
  color: var(--text-muted);
  font-size: 14px;
}

.app-tools {
  margin-left: auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 14px;
}

/* A name is one long word at worst, so it breaks rather than push the bar sideways. */
.app-user {
  max-width: 16em;
  color: var(--text-soft);
  font-size: 15px;
  overflow-wrap: anywhere;
}

.app-plain {
  color: var(--text-soft);
  font-size: 15px;
  text-decoration: none;
  white-space: nowrap;
}

.app-plain:hover,
.app-foot a:hover {
  color: var(--text);
  text-decoration: underline;
}

/* The Light and Dark switch (brief v1.1): a radiogroup of two radios in a pill, as the front door's. With no script the theme is
   the default and cannot change, so a switch in a page's own markup is not shown. */
.app-toggle {
  display: inline-flex;
  padding: 2px;
  border: 1px solid var(--border-quiet);
  border-radius: 20px;
}

:root:not([data-theme]) .app-toggle {
  display: none;
}

.app-toggle button {
  padding: 5px 14px;
  border: 0;
  border-radius: 18px;
  background: transparent;
  color: var(--text-muted);
  font: 700 13px var(--font);
  cursor: pointer;
}

.app-toggle button[aria-checked="true"] {
  background: var(--cyan);
  color: var(--on-cyan);
}

/* The admin pages' navigation: a second row of the top bar. The page you are on is bold, with a line under it in the brand
   colour. */
.app-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 8px;
  padding: 0 40px;
}

.app-nav a {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding: 8px 8px 6px;
  border-bottom: 2px solid transparent;
  color: var(--text-soft);
  font-size: 15px;
  text-decoration: none;
}

.app-nav a:hover {
  color: var(--text);
}

.app-nav a[aria-current="page"] {
  border-bottom-color: var(--brand);
  color: var(--text);
  font-weight: 700;
}

.app-icon {
  flex: none;
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ===== the page's heading in the brief's hero band (rule 1), and the content under it ===== */
.app-main {
  flex: 1 0 auto;
}

.app-main:focus {
  outline: none;
}

.app-band {
  padding: 44px 48px 32px;
  background: linear-gradient(180deg, var(--hero-a) 0%, var(--hero-b) 100%);
}

.app-band h1 {
  margin: 0;
  font-size: 40px;
  font-weight: 700;
  line-height: 1.15;
  overflow-wrap: anywhere;
}

.app-panel {
  padding: 4px 48px 56px;
}

/* A candidate's pages read in one column of comfortable width; the admin pages use the whole width. */
.app-in.is-narrow {
  max-width: 760px;
  margin: 0 auto;
}

/* The pages under Settings, as small outline tabs under the heading (Claude's proposal: the mock does not draw them). */
.app-subnav {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 20px 0 0;
}

.app-subnav a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 16px;
  border: 1px solid var(--border-quiet);
  border-radius: 999px;
  background: var(--bg-card);
  color: var(--text-soft);
  font-size: 15px;
  text-decoration: none;
}

.app-subnav a:hover {
  color: var(--text);
}

.app-subnav a[aria-current="page"] {
  border-color: var(--brand);
  color: var(--text);
  font-weight: 700;
}

/* ===== the footer (rule 7), as the front door's, with the "Powered by" line and the version ===== */
.app-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px 24px;
  padding: 24px 48px;
  background: var(--bg-deep);
  border-top: 1px solid var(--divider);
  color: var(--text-muted);
  font-size: 14px;
}

.app-foot-text {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.app-foot-text b {
  color: var(--text-soft);
}

.app-foot nav {
  margin-left: auto;
  display: flex;
  flex-wrap: wrap;
  gap: 18px;
}

.app-foot a {
  color: inherit;
  text-decoration: none;
}

.app-logo-panel {
  display: inline-flex;
  padding: 12px;
  border-radius: 10px;
  background: var(--logo-panel);
}

.app-logo {
  display: block;
  height: 120px;
  width: auto;
}

/* ===== cards (rule 2): the brief's card, with no coloured bar along any edge ===== */
.app-tile {
  margin: 0 0 24px;
  padding: 24px 28px 28px;
  border: 1px solid var(--border-card);
  border-radius: 14px;
  background: var(--bg-card);
  box-shadow: var(--card-shadow);
}

.app-panel .app-tile:first-child,
.app-panel .app-msg:first-child {
  margin-top: 28px;
}

h2.sub {
  margin: 0 0 8px;
  font-size: 24px;
  line-height: 1.25;
}

h3.sub {
  margin: 28px 0 10px;
  font-size: 20px;
  line-height: 1.3;
}

.app-tile > h2:first-child,
.app-tile > h3:first-child {
  margin-top: 0;
}

.app-lead {
  max-width: 62em;
  margin: 0 0 18px;
  color: var(--text-soft);
}

.app-hint {
  margin: 6px 0;
  color: var(--text-soft);
  font-size: 15px;
}

.app-empty {
  margin: 8px 0;
  color: var(--text-soft);
}

/* ===== messages: always a word as well as a colour ===== */
.app-msg {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin: 16px 0;
  padding: 14px 18px;
  border: 1px solid var(--info-bd);
  border-radius: 14px;
  background: var(--bg-card);
  color: var(--text);
}

.app-msg.is-ok {
  border-color: var(--ok-bd);
}

.app-msg.is-bad {
  border-color: var(--bad);
}

.app-msg.is-warn {
  border-color: var(--warn-bd);
  background: var(--warn-bg);
}

.app-msg .app-icon {
  width: 20px;
  height: 20px;
  margin-top: 2px;
}

.app-msg-text {
  margin: 0;
}

.app-msg.is-bad strong,
.app-msg.is-bad .app-icon {
  color: var(--bad);
}

.app-msg.is-warn strong,
.app-msg.is-warn .app-icon {
  color: var(--warn);
}

/* ===== forms: fields, selects and choices ===== */
.app-form {
  display: grid;
  gap: 16px;
  max-width: 40rem;
}

.app-field {
  display: grid;
  gap: 6px;
  min-width: 0;
}

.app-field label,
.app-fieldset legend {
  color: var(--text);
  font-weight: 700;
}

.app-fieldset {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.app-fieldset legend {
  margin: 0 0 8px;
  padding: 0;
}

.app-input,
.app-select {
  width: 100%;
  min-height: 44px;
  padding: 8px 12px;
  border: 1px solid var(--border-quiet);
  border-radius: 8px;
  background: var(--bg-page);
  color: var(--text);
  font: inherit;
}

/* A field the server refused: a thicker edge and a bar down its left side as well as the problem colour, so the mark is a change of
   shape and not colour alone. The message that names the field in words is tied to it (components.js, markInvalid). */
.app-input[aria-invalid="true"],
.app-fieldset[aria-invalid="true"] {
  border: 2px solid var(--bad);
  box-shadow: inset 6px 0 0 var(--bad);
}

.app-input[aria-invalid="true"] {
  padding-left: 16px;
}

.app-fieldset[aria-invalid="true"] {
  padding: 4px 12px 12px 18px;
  border-radius: 9px;
}

.app-choices {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.app-choice {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  margin: 10px 0 0;
  padding: 10px 14px;
  border: 1px solid var(--border-quiet);
  border-radius: 10px;
  background: var(--bg-page);
  color: var(--text);
  cursor: pointer;
}

.app-choices .app-choice {
  margin: 0;
  font-weight: 700;
}

.app-choice:has(input:checked) {
  border-color: var(--brand);
}

.app-choice input {
  flex: none;
  width: 20px;
  height: 20px;
  margin: 0;
  accent-color: var(--brand);
}

/* A choice that cannot be used while Aeris is thinking is greyed like a button that cannot. */
.app-choice:has(input:disabled) {
  border-color: var(--border-quiet);
  color: var(--text-disabled);
  cursor: default;
}

/* ===== buttons (rule 3): cyan with dark words, an outline in the brand colour, the danger outline, and disabled ===== */
.app-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin: 18px 0 0;
}

.app-actions + .app-actions {
  margin-top: 10px;
}

.app-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 44px;
  padding: 10px 22px;
  border: 1px solid transparent;
  border-radius: 8px;
  background: var(--cyan);
  color: var(--on-cyan);
  font: inherit;
  font-size: 16px;
  font-weight: 700;
  line-height: 1.25;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
}

.app-btn:hover {
  filter: brightness(1.08);
}

.app-btn.is-ghost {
  border-color: var(--brand);
  background: transparent;
  color: var(--text);
}

.app-btn.is-ghost:hover,
.app-btn.is-out:hover {
  filter: none;
  background: var(--chip-bg);
}

/* Sign out: the brief's smaller outline button. */
.app-btn.is-out {
  min-height: 0;
  padding: 8px 18px;
  border-color: var(--brand);
  border-radius: 6px;
  background: transparent;
  color: var(--text);
  font-size: 15px;
  white-space: nowrap;
}

.app-btn.is-danger {
  border-color: var(--bad);
  background: transparent;
  color: var(--bad);
}

.app-btn.is-danger:hover {
  filter: none;
  background: var(--bad-bg);
}

.app-btn:disabled,
.app-btn[aria-disabled="true"] {
  border-color: var(--border-quiet);
  background: var(--bg-page);
  color: var(--text-disabled);
  cursor: default;
  filter: none;
}

/* ===== status labels (rule 5): a word in a small pill, as the brief's badges. Lime is never used here. ===== */
.app-badge {
  display: inline-block;
  padding: 3px 10px;
  border: 1px solid var(--neutral-bd);
  border-radius: 999px;
  background: var(--neutral-bg);
  color: var(--neutral);
  font-size: 13px;
  font-weight: 700;
  line-height: 1.3;
  white-space: nowrap;
}

.app-badge.is-ok {
  border-color: var(--ok-bd);
  background: var(--ok-bg);
  color: var(--ok);
}

.app-badge.is-warn {
  border-color: var(--warn-bd);
  background: var(--warn-bg);
  color: var(--warn);
}

.app-badge.is-bad {
  border-color: var(--bad-bd);
  background: var(--bad-bg);
  color: var(--bad);
}

.app-badge.is-info {
  border-color: var(--info-bd);
  background: var(--info-bg);
  color: var(--info);
}

/* AI-written text carries "Written by AI" in purple (spec 16.9), as a word and not only a colour. */
.app-badge.is-ai {
  border-color: var(--ai-bd);
  background: var(--ai-bg);
  color: var(--ai);
}

.app-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

/* ===== tables and lists (rule 4): rows on the card colour with thin dividers, header words in the muted colour ===== */
.app-filters {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
  gap: 12px 16px;
  margin: 0 0 18px;
}

.app-table {
  width: 100%;
  border-collapse: collapse;
}

.app-table th,
.app-table td {
  padding: 12px 10px;
  border-bottom: 1px solid var(--border-card);
  text-align: left;
  vertical-align: top;
  overflow-wrap: break-word;
}

.app-table th {
  color: var(--text-muted);
  font-size: 14px;
  font-weight: 700;
}

.app-table td {
  color: var(--text);
  font-size: 15px;
}

.app-table tbody tr:last-child td {
  border-bottom: 0;
}

.app-table .app-badge {
  white-space: normal;
  border-radius: 12px;
}

/* A row's buttons (Up, Down, Retire, Withdraw) line up with the row's other cells. */
.app-table .app-actions {
  margin-top: 0;
}

/* A name has no spaces to break at, and break-word does not shrink a table cell, so a link (a candidate's name) breaks anywhere.
   Not on every cell: a table of ten columns would then break ordinary words. */
.app-table a {
  font-weight: 700;
  text-decoration: none;
  overflow-wrap: anywhere;
}

.app-table a:hover {
  text-decoration: underline;
}

.app-kv {
  display: grid;
  grid-template-columns: minmax(8rem, 14rem) 1fr;
  gap: 8px 16px;
  margin: 0;
}

.app-kv dt {
  color: var(--text-muted);
  font-weight: 700;
}

.app-kv dd {
  margin: 0;
  overflow-wrap: anywhere;
}

/* A rating's level bar: always beside the rating in words, never the only signal. */
.app-rating {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}

.app-level {
  display: inline-flex;
  gap: 3px;
  vertical-align: middle;
}

.app-level i {
  width: 14px;
  height: 8px;
  border: 1px solid var(--brand);
  border-radius: 2px;
}

.app-level i.on {
  background: var(--brand);
}

/* A field the work-behaviour review removed: its fixed note, as plain text and not as the candidate's words. */
.app-removed {
  color: var(--text-soft);
  font-style: italic;
}

/* ===== the job roles page (Settings, Job roles) ===== */
.jr-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 12px 0;
}

/* The chosen tab is tinted and has a line along its foot in the brand colour, as the admin navigation marks the page you are on,
   so it shows by shape as well as colour. */
.jr-tab[aria-selected='true'] {
  background: var(--chip-bg);
  box-shadow: inset 0 -3px 0 var(--brand);
  color: var(--text);
}

.jr-personas {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 10px;
}

.jr-persona {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-height: 32px;
}

.jr-persona input,
.app-choice input[type='checkbox'] {
  flex: none;
  width: 22px;
  height: 22px;
  margin: 0;
  accent-color: var(--brand);
}

.jr-name {
  min-width: 14rem;
}

/* A role name is read in its field, so on a wide screen its column is wide enough for the starting list's longest names. On a
   narrow one the card gives the field a line of its own. */
@media screen and (min-width: 1100px) {
  .app-table td:has(> .jr-name) {
    min-width: 22rem;
  }
}

.jr-autonomy {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}

.jr-autonomy .app-select {
  width: auto;
}

.jr-scoring {
  margin: 8px 0;
  padding: 10px 14px;
  border: 1px solid var(--warn-bd);
  border-radius: 10px;
  background: var(--warn-bg);
  color: var(--text);
  font-weight: 700;
}

@media screen and (max-width: 1099px) {
  .jr-personas {
    justify-content: flex-end;
  }

  .jr-persona {
    min-height: 44px;
    min-width: 44px;
  }

  /* In the stacked card a field takes its own line under its label, so a name is not cut short and a select stays inside. */
  .app-table td > .app-input,
  .app-table td > .jr-autonomy {
    clear: left;
    width: 100%;
    margin-top: 6px;
    text-align: left;
  }

  .app-table td > .app-input {
    display: block;
  }

  .jr-autonomy {
    display: flex;
    flex-direction: column;
    align-items: stretch;
  }

  .jr-autonomy .app-select {
    width: 100%;
  }
}

/* ===== the candidate pages (build step 6D) and the interview (spec 16.4 to 16.7): the question, Talk, the thinking panel ===== */
/* A paragraph that may hold a contact address (the consent screen and the under-18 holding message): an address has no space to
   break at, so it wraps anywhere rather than run past a 375 px screen. */
.cand-copy {
  overflow-wrap: anywhere;
}

.iv-question {
  margin: 0 0 18px;
}

.iv-progress,
.iv-ack {
  margin: 0 0 8px;
  color: var(--text-soft);
}

.iv-question-text {
  margin: 0;
  font-size: 24px;
  line-height: 1.35;
  overflow-wrap: anywhere;
}

.iv-followup,
.iv-checkin {
  margin: 14px 0 0;
  padding-top: 14px;
  border-top: 1px solid var(--border-card);
  overflow-wrap: anywhere;
}

.iv-options {
  display: grid;
  gap: 10px;
}

.app-btn.iv-option {
  justify-content: flex-start;
  width: 100%;
  text-align: left;
}

.iv-answer {
  min-height: 8em;
  resize: vertical;
}

.iv-status {
  min-height: 1.5em;
  margin: 8px 0;
  color: var(--text-soft);
}

.iv-controls,
.iv-stop {
  margin: 18px 0 0;
}

.iv-services {
  display: grid;
  gap: 12px;
  margin: 12px 0;
  padding: 0;
  list-style: none;
}

.iv-services .app-hint {
  margin: 4px 0 0;
}

/* Talk mode (build step 7): the "Listening" cue, the level meter, the pause ring and what Aeris heard. */
.iv-talk {
  margin: 0 0 8px;
  padding: 18px 20px;
  border: 1px solid var(--border-card);
  border-radius: 12px;
  background: var(--bg-page);
}

.iv-cue {
  min-height: 1.5em;
  margin: 0 0 10px;
  font-weight: 700;
}

.iv-meter {
  display: block;
  width: 100%;
  max-width: 320px;
  height: 14px;
  border: 1px solid var(--border-quiet);
  border-radius: 7px;
  background: var(--bg-card);
  appearance: none;
  -webkit-appearance: none;
}

.iv-meter::-webkit-meter-bar {
  height: 12px;
  border: 0;
  border-radius: 7px;
  background: var(--bg-card);
}

.iv-meter::-webkit-meter-optimum-value,
.iv-meter::-webkit-meter-suboptimum-value,
.iv-meter::-webkit-meter-even-less-good-value {
  border-radius: 7px;
  background: var(--brand);
}

.iv-meter::-moz-meter-bar {
  border-radius: 7px;
  background: var(--brand);
}

/* The pause ring fills while Aeris waits in case there is more to say. */
.iv-ring {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 14px 0;
}

.iv-ring.is-held {
  visibility: hidden;
}

.iv-ring p {
  margin: 0;
}

.iv-ring svg {
  flex: none;
  width: 44px;
  height: 44px;
  transform: rotate(-90deg);
}

.iv-ring circle {
  fill: none;
  stroke-width: 4;
}

.iv-ring-track {
  stroke: var(--border-quiet);
}

.iv-ring-fill {
  stroke: var(--brand);
  stroke-linecap: round;
  transition: stroke-dashoffset 0.1s linear;
}

.iv-heard-title {
  margin: 0 0 8px;
  font-size: 20px;
}

.iv-heard-text {
  margin: 0 0 8px;
  font-size: 18px;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

/* A word the speech service was unsure of is bold and underlined as well as tinted, so it shows without colour. */
.iv-unsure {
  background: var(--warn-bg);
  color: inherit;
  font-weight: 700;
  text-decoration: underline wavy var(--warn);
  text-underline-offset: 3px;
}

.iv-countdown {
  margin: 8px 0;
  color: var(--text-soft);
}

.iv-send-row {
  margin-top: 20px;
}

/* The thinking panel (piece 6F, Part C), in place of the answer area while an answer is worked on. The small Aeris avatar sits on
   a dark disc in both themes (rule 8), because its colours are fixed, and pulses gently, and three dots rise in turn. The words
   carry the meaning, so the motion is decoration and goes with reduced motion. */
.iv-thinking {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  margin: 0 0 8px;
  padding: 28px 20px;
  border: 1px solid var(--border-card);
  border-radius: 12px;
  background: var(--bg-page);
  text-align: center;
}

.iv-thinking-art {
  display: flex;
  align-items: center;
  gap: 16px;
}

.iv-disc {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 92px;
  height: 92px;
  border: 1px solid var(--border-card);
  border-radius: 50%;
  background: var(--art-bg);
  box-shadow: var(--live-glow);
}

/* The Aeris illustration (1280 by 720) cropped round to the face and headset: a circle 460 px across, centred at 615, 245 in the
   picture, so the picture is shown 1280 / 460 times the circle's width and moved to put that centre in the middle. */
.iv-thinking-avatar {
  position: relative;
  display: block;
  width: 76px;
  height: 76px;
  overflow: hidden;
  border-radius: 50%;
  animation: iv-pulse 2.4s ease-in-out infinite;
}

.iv-thinking-avatar img {
  position: absolute;
  top: -3.3%;
  left: -83.7%;
  width: 278.3%;
  max-width: none;
  height: auto;
}

.iv-dots {
  display: inline-flex;
  gap: 6px;
}

.iv-dots span {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--brand);
  animation: iv-dot 1.2s ease-in-out infinite;
}

.iv-dots span:nth-child(2) {
  animation-delay: 0.2s;
}

.iv-dots span:nth-child(3) {
  animation-delay: 0.4s;
}

.iv-thinking-words {
  max-width: 32em;
  margin: 0;
  font-size: 21px;
  font-weight: 700;
  line-height: 1.4;
  overflow-wrap: anywhere;
}

.iv-thinking-more {
  margin: 0;
  color: var(--text-soft);
}

@keyframes iv-pulse {
  0%,
  100% {
    transform: scale(1);
    opacity: 1;
  }

  50% {
    transform: scale(1.06);
    opacity: 0.8;
  }
}

@keyframes iv-dot {
  0%,
  80%,
  100% {
    opacity: 0.3;
    transform: translateY(0);
  }

  40% {
    opacity: 1;
    transform: translateY(-4px);
  }
}

@media (prefers-reduced-motion: reduce) {
  .iv-thinking-avatar,
  .iv-dots span {
    animation: none;
    opacity: 1;
    transform: none;
  }
}

@media screen and (max-width: 699px) {
  .iv-question-text {
    font-size: 21px;
  }

  .iv-thinking-words {
    font-size: 19px;
  }

  .iv-talk {
    padding: 16px;
  }
}

/* ===== Aeris's own sign-in page (rule 8): the front door's layout, the Aeris illustration beside Clerk's panel ===== */
.app-signin-wrap {
  padding: 56px 48px 72px;
  background: linear-gradient(180deg, var(--hero-a) 0%, var(--hero-b) 100%);
}

.app-signin {
  display: grid;
  grid-template-columns: 1.1fr 0.9fr;
  max-width: 1040px;
  margin: 0 auto;
  overflow: hidden;
  border: 1px solid var(--border-card);
  border-radius: 14px;
  background: var(--bg-card);
  box-shadow: var(--card-shadow);
}

.app-art {
  position: relative;
  min-height: 480px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 32px;
  background: var(--art-bg);
}

.app-art img {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The art is dark in both themes, so its caption keeps the dark theme's words. */
.app-art::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 55%;
  background: linear-gradient(transparent, rgba(7, 17, 32, 0.95));
}

.app-cap {
  position: relative;
  z-index: 1;
  color: var(--art-text);
}

.app-cap h1 {
  margin: 0 0 8px;
  font-size: 28px;
  line-height: 1.2;
}

.app-cap p {
  margin: 0;
  color: var(--art-text-soft);
}

.app-signin-panel {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 12px;
  min-width: 0;
  padding: 44px 40px;
}

.app-signin-panel p {
  margin: 0;
  color: var(--text-soft);
}

/* Clerk draws its own panel here. On a narrow column it scrolls inside rather than push the page sideways. */
.app-clerk {
  max-width: 100%;
  overflow-x: auto;
}

/* ===== motion is decoration only, so a person who asks for less gets none ===== */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation: none !important;
    transition: none !important;
  }
}

/* ===== below 1100 px: two columns, and wide tables become stacked cards ===== */
@media screen and (max-width: 1099px) {
  .app-top-row {
    flex-wrap: wrap;
  }

  .app-table thead {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
  }

  .app-table,
  .app-table tbody,
  .app-table tr,
  .app-table td {
    display: block;
  }

  .app-table tr {
    margin: 0 0 12px;
    padding: 6px 14px;
    border: 1px solid var(--border-card);
    border-radius: 10px;
    background: var(--bg-page);
  }

  /* The column's name floats at the left of each cell and the value sits at the right, so a value of several parts (a link, a
     comma, a link) stays together. */
  .app-table td,
  .app-table tbody tr:last-child td {
    display: flow-root;
    padding: 8px 0;
    border-bottom: 1px solid var(--border-card);
    text-align: right;
    overflow-wrap: anywhere;
  }

  .app-table tbody tr td:last-child {
    border-bottom: 0;
  }

  .app-table td::before {
    content: attr(data-label);
    float: left;
    width: 42%;
    margin-right: 12px;
    color: var(--text-muted);
    font-weight: 700;
    text-align: left;
  }

  .app-table .app-chips,
  .app-table .app-rating,
  .app-table .app-actions {
    justify-content: flex-end;
  }

  /* A link in a stacked card is a touch target on a phone or tablet: 44 px tall, without moving the line it sits on. */
  .app-table a {
    display: inline-block;
    margin: -10px 0;
    padding: 10px 0;
  }
}

/* ===== below 700 px: one column, 20 px at the sides, the heading at 32 px ===== */
@media screen and (max-width: 699px) {
  .app-top-row {
    gap: 10px 14px;
    padding: 14px 20px;
  }

  /* Three rows: the wordmark with Sign out, then the product and area, then the platforms link and the switch. */
  .app-tools {
    display: contents;
  }

  .app-mark {
    order: 1;
    font-size: 22px;
  }

  .app-tools > .app-btn.is-out,
  .app-tools > .app-toggle:only-child {
    order: 2;
    margin-left: auto;
  }

  .app-product {
    order: 3;
    flex-basis: 100%;
    flex-wrap: wrap;
    white-space: normal;
  }

  .app-mark:not([hidden]) + .app-product {
    padding-left: 0;
    border-left: 0;
  }

  .app-product b {
    font-size: 17px;
  }

  .app-plain,
  .app-toggle {
    order: 4;
  }

  .app-user {
    display: none;
  }

  .app-toggle button {
    padding: 5px 12px;
  }

  .app-nav {
    padding: 0 12px;
  }

  .app-band {
    padding: 28px 20px 22px;
  }

  .app-band h1 {
    font-size: 32px;
  }

  .app-panel {
    padding: 4px 20px 40px;
  }

  .app-tile {
    padding: 20px 18px 22px;
  }

  h2.sub {
    font-size: 22px;
  }

  .app-choices,
  .app-signin {
    grid-template-columns: 1fr;
  }

  .app-kv {
    grid-template-columns: 1fr;
    gap: 2px;
  }

  .app-kv dd {
    margin-bottom: 10px;
  }

  .app-signin-wrap {
    padding: 28px 20px 40px;
  }

  .app-art {
    min-height: 260px;
    padding: 22px;
  }

  .app-signin-panel {
    padding: 28px 22px;
  }

  .app-foot {
    padding: 22px 20px;
  }

  .app-foot nav {
    margin-left: 0;
  }
}
