/* ============================================================================
   NiyuktiAI — Everything that belongs to one page

   Load order: tokens.css, base.css, components.css, shell.css, pages.css.
   Bootstrap comes before all of them and is configured by base.css rather
   than overridden — its custom properties are pointed at our tokens.
   ========================================================================== */

/* ============================================================================
   Dashboard
   ========================================================================== */

/* The two accents the landing page signs its work with, carried into the
   product for the greeting and the tile hairline. Same values as the public
   surface holds, named here so the app pages need not load that stylesheet. */
:root {
  --brand: #6d3df5;
  --brand2: #8b5cf6;
  --ai-500: var(--accent-500);
  --ai-700: var(--accent-700);
}

.greeting h1 {
  font-size: var(--text-2xl);
  font-weight: 600;
  letter-spacing: -0.02em;
  margin: 0;
}

@media (min-width: 768px) {
  .greeting h1 {
    font-size: var(--text-3xl);
  }
}

.greeting-name {
  background: linear-gradient(to right, var(--brand), var(--brand2));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.greeting p {
  color: var(--muted-foreground);
  font-size: var(--text-md);
  margin: 0.375rem 0 0;
}

/* --- Stat tiles ----------------------------------------------------------- */

/* Two across even on the narrowest phone: one per row put six hundred pixels
   of four numbers between the greeting and the jobs, which is the page. */
.stat-grid {
  display: grid;
  gap: 0.75rem;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (min-width: 576px) {
  .stat-grid {
    gap: 1rem;
  }
}

@media (min-width: 1200px) {
  .stat-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

.stat-tile {
  position: relative;
  height: 100%;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background-color: var(--card);
  box-shadow: var(--elevation-xs);
  padding: 1.25rem;
  transition: border-color 150ms, box-shadow 150ms;
}

.stat-tile:hover {
  border-color: var(--border-strong);
  box-shadow: var(--elevation-sm);
}

/* The hairline that lights up on hover — the landing page's accent. */
.stat-tile::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: 0;
  height: 2px;
  background: linear-gradient(to right, var(--brand), var(--brand2));
  opacity: 0;
  transition: opacity 150ms;
}

.stat-tile:hover::before {
  opacity: 1;
}

.stat-tile-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.75rem;
}

.stat-tile-label {
  color: var(--muted-foreground);
  font-size: var(--text-md);
  font-weight: 500;
  line-height: 1.375;
  margin: 0;
}

.stat-tile-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  flex-shrink: 0;
  border-radius: 10px;
  color: #fff;
  transition: scale 150ms;
}

.stat-tile:hover .stat-tile-icon {
  scale: 1.05;
}

.stat-tile-icon .fa-solid {
  font-size: 18px;
}

.stat-tile-value {
  font-size: 2rem;
  line-height: 1;
  font-weight: 600;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  margin: 0.75rem 0 0;
}

.stat-tile-caption {
  font-size: var(--text-sm);
  line-height: 1.375;
  font-weight: 500;
  margin: 0.625rem 0 0;
}

/* The caption is the whole tile's link — the ::after covers it. */
.stat-tile-caption a::after {
  content: "";
  position: absolute;
  inset: 0;
}

.tone-brand .stat-tile-icon {
  background: linear-gradient(to bottom right, var(--brand-500), var(--brand-700));
  box-shadow: 0 1px 2px color-mix(in oklab, var(--brand-500) 40%, transparent);
}
.tone-brand .stat-tile-caption {
  color: var(--primary);
}
.tone-success .stat-tile-icon {
  background: linear-gradient(to bottom right, var(--success-500), var(--success-700));
  box-shadow: 0 1px 2px color-mix(in oklab, var(--success-500) 40%, transparent);
}
.tone-success .stat-tile-caption {
  color: var(--success-700);
}
.tone-warning .stat-tile-icon {
  background: linear-gradient(to bottom right, var(--warning-500), var(--warning-700));
  box-shadow: 0 1px 2px color-mix(in oklab, var(--warning-500) 40%, transparent);
}
.tone-warning .stat-tile-caption {
  color: var(--warning-700);
}
.tone-danger .stat-tile-icon {
  background: linear-gradient(to bottom right, var(--danger-500), var(--danger-700));
  box-shadow: 0 1px 2px color-mix(in oklab, var(--danger-500) 40%, transparent);
}
.tone-danger .stat-tile-caption {
  color: var(--danger-700);
}
.tone-info .stat-tile-icon {
  background: linear-gradient(to bottom right, var(--info-500), var(--info-700));
  box-shadow: 0 1px 2px color-mix(in oklab, var(--info-500) 40%, transparent);
}
.tone-info .stat-tile-caption {
  color: var(--info-700);
}

/* --- The dashboard's two columns ------------------------------------------ */

.dash-grid {
  display: grid;
  align-items: start;
  gap: 1.25rem;
  grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 1200px) {
  .dash-grid {
    grid-template-columns: minmax(0, 1.75fr) minmax(0, 1fr);
  }
}

.dash-column {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

/* --- Progress ------------------------------------------------------------- */

.progress {
  --bs-progress-bg: var(--surface-sunken);
  --bs-progress-height: 0.5rem;
  --bs-progress-border-radius: 999px;
  overflow: hidden;
}

.progress-bar {
  border-radius: 999px;
  background-color: var(--primary);
  transition: width 400ms ease-out;
}

.progress-sm {
  --bs-progress-height: 0.375rem;
}

.progress-success .progress-bar {
  background-color: var(--success-600);
}
.progress-warning .progress-bar {
  background-color: var(--warning-500);
}
.progress-danger .progress-bar {
  background-color: var(--danger-600);
}

/* The circular match meter. One SVG, two circles, the arc set by
   stroke-dasharray — no library and nothing to load. */
.ring {
  position: relative;
  display: grid;
  place-items: center;
}

.ring svg {
  transform: rotate(-90deg);
  width: 100%;
  height: 100%;
}

.ring circle {
  fill: none;
  stroke-linecap: round;
}

.ring .ring-track {
  stroke: var(--surface-sunken);
}

.ring .ring-value {
  transition: stroke-dasharray 500ms ease-out;
}

.ring-label {
  position: absolute;
  font-size: var(--text-xs);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.ring-success .ring-value {
  stroke: var(--success-600);
}
.ring-warning .ring-value {
  stroke: var(--warning-500);
}
.ring-danger .ring-value {
  stroke: var(--danger-600);
}
.ring-brand .ring-value {
  stroke: var(--primary);
}

/* --- The AI match list ---------------------------------------------------- */

.match-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.match-row {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  border-bottom: 1px solid var(--border);
  padding: 1rem 0;
}

.match-row:last-child {
  border-bottom: 0;
}

@media (min-width: 576px) {
  .match-row {
    flex-direction: row;
    align-items: center;
  }
}

.match-main {
  display: flex;
  min-width: 0;
  flex: 1 1 auto;
  align-items: center;
  gap: 0.875rem;
}

.crest {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  flex-shrink: 0;
  border: 1px solid var(--brand-100);
  border-radius: 999px;
  background-color: var(--brand-50);
  color: var(--brand-700);
  font-size: var(--text-2xs);
  font-weight: 700;
  letter-spacing: -0.01em;
}

.match-row h3 {
  font-size: var(--text-md);
  font-weight: 600;
  line-height: 1.375;
  letter-spacing: -0.01em;
  margin: 0;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.match-org {
  color: var(--muted-foreground);
  font-size: var(--text-sm);
  margin: 0.125rem 0 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.match-facts {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 1rem;
  color: var(--muted-foreground);
  font-size: var(--text-xs);
  margin-top: 0.375rem;
}

.match-facts span {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
}

.match-facts .fa-solid {
  font-size: 0.875rem;
}

.match-meter {
  display: flex;
  flex-shrink: 0;
  flex-direction: column;
  align-items: center;
  gap: 0.125rem;
}

.match-meter > span {
  color: var(--muted-foreground);
  font-size: var(--text-2xs);
  font-weight: 500;
}

.match-date {
  flex-shrink: 0;
}

@media (min-width: 576px) {
  .match-date {
    width: 8rem;
  }
}

.match-date-label {
  color: var(--muted-foreground);
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  font-size: var(--text-2xs);
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin: 0;
}

.match-date-label .fa-solid {
  font-size: 0.75rem;
}

.match-date-value {
  font-size: var(--text-sm);
  font-weight: 600;
  margin: 0.125rem 0 0;
}

.match-date-left {
  font-size: var(--text-2xs);
  font-weight: 500;
  margin: 0;
}

/* --- Application progress rows -------------------------------------------- */

.app-row {
  display: block;
  border: 1px solid var(--border);
  border-radius: 0.75rem;
  background-color: var(--surface);
  padding: 0.875rem;
  transition: border-color 150ms, box-shadow 150ms;
}

.app-row:hover {
  border-color: var(--border-strong);
  box-shadow: var(--elevation-xs);
}

.app-row:hover .app-row-title {
  color: var(--primary);
}

.app-row-title {
  font-size: var(--text-base);
  font-weight: 600;
  margin: 0;
  transition: color 150ms;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.app-row-sub {
  color: var(--muted-foreground);
  font-size: var(--text-sm);
  margin: 0;
}

/* --- Alert rows ----------------------------------------------------------- */

.alert-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.alert-list li {
  border-top: 1px solid var(--border);
  padding: 0.75rem 0;
}

.alert-list li:first-child {
  border-top: 0;
  padding-top: 0;
}

.alert-list li:last-child {
  padding-bottom: 0;
}

.alert-row {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
}

.alert-row:hover .alert-title {
  color: var(--primary);
}

.alert-icon {
  display: flex;
  width: 2.25rem;
  height: 2.25rem;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  border: 1px solid;
  border-radius: 0.5rem;
}

.alert-critical {
  background-color: var(--danger-50);
  color: var(--danger-600);
  border-color: var(--danger-200);
}
.alert-warning {
  background-color: var(--warning-50);
  color: var(--warning-600);
  border-color: var(--warning-200);
}
.alert-info {
  background-color: var(--info-50);
  color: var(--info-600);
  border-color: var(--info-200);
}
.alert-success {
  background-color: var(--success-50);
  color: var(--success-600);
  border-color: var(--success-200);
}

.alert-title {
  font-size: var(--text-base);
  font-weight: 500;
  margin: 0;
  text-wrap: pretty;
  transition: color 150ms;
}

.alert-message {
  color: var(--muted-foreground);
  font-size: var(--text-sm);
  margin: 0.125rem 0 0;
  text-wrap: pretty;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.alert-when {
  color: var(--muted-foreground);
  flex-shrink: 0;
  font-size: var(--text-2xs);
  white-space: nowrap;
}

/* --- The live band -------------------------------------------------------- */

.live-band {
  border: 1px solid var(--brand-200);
  border-radius: var(--radius);
  background: linear-gradient(to right, color-mix(in oklab, var(--brand-50) 60%, transparent), transparent);
  padding: 1.25rem;
}

.live-band-idle {
  border-color: var(--border);
  background: var(--card);
}

.live-band-inner {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

@media (min-width: 576px) {
  .live-band-inner {
    flex-direction: row;
    align-items: center;
  }
}

.live-band-icon {
  display: flex;
  width: 2.75rem;
  height: 2.75rem;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  border-radius: 0.75rem;
  background: linear-gradient(to bottom right, var(--brand-500), var(--brand-700));
  color: #fff;
  box-shadow: 0 1px 3px color-mix(in oklab, var(--brand-500) 40%, transparent);
}

.live-band-idle .live-band-icon {
  background: var(--surface-sunken);
  color: var(--muted-foreground);
  border: 1px solid var(--border);
  box-shadow: none;
}

.live-band-icon .fa-solid {
  font-size: 1.25rem;
}

.live-dot {
  width: 0.375rem;
  height: 0.375rem;
  border-radius: 999px;
  background-color: currentColor;
  animation: live-pulse 1.6s ease-in-out infinite;
}

@keyframes live-pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.35;
  }
}

/* ============================================================================
   Jobs
   ========================================================================== */

.page-header h1 {
  font-size: var(--text-2xl);
  font-weight: 600;
  letter-spacing: -0.02em;
  margin: 0;
}

.page-header p {
  color: var(--muted-foreground);
  font-size: var(--text-md);
  margin: 0.375rem 0 0;
  max-width: 60ch;
  text-wrap: pretty;
}

.jobs-toolbar {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.jobs-toolbar .form-select {
  width: 11rem;
}

/* On a phone the search keeps its own row and Filters shares the next one
   with the sort, which otherwise sat alone beside half a row of nothing. */
@media (max-width: 575.98px) {
  .jobs-toolbar {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
  }

  .jobs-toolbar > .input-group-search {
    flex: 1 0 100%;
  }

  .jobs-toolbar > button,
  .jobs-toolbar > .row-center {
    flex: 1 1 0;
  }

  .jobs-toolbar > button {
    justify-content: center;
  }

  .jobs-toolbar .form-select {
    width: 100%;
  }
}

@media (min-width: 576px) {
  .jobs-toolbar {
    flex-direction: row;
    align-items: center;
  }
}

/* Search box: the icon and the clear button sit inside the field rather than
   beside it, so the field itself is the whole control. */
.input-group-search {
  position: relative;
  flex: 1 1 auto;
  display: flex;
  align-items: center;
}

.input-group-search > .fa-solid:first-child {
  position: absolute;
  left: 0.75rem;
  font-size: 0.875rem;
  color: var(--muted-foreground);
  pointer-events: none;
}

.input-group-search input {
  padding-left: 2.25rem;
  padding-right: 2.5rem;
}

.input-group-search > button {
  position: absolute;
  right: 0.375rem;
}

.jobs-layout {
  display: flex;
  gap: 1.5rem;
}

.jobs-rail {
  width: 16rem;
  flex-shrink: 0;
}

/* Two columns from wide, three on a very wide screen — a government post
   title needs the width, so this does not go narrower than that. */
.job-grid {
  display: grid;
  gap: 1rem;
  grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 1200px) {
  .job-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1800px) {
  .job-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

.job-card {
  position: relative;
  display: flex;
  height: 100%;
  flex-direction: column;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background-color: var(--card);
  box-shadow: var(--elevation-xs);
  padding: 1.25rem;
  transition: border-color 150ms, box-shadow 150ms;
}

.job-card:hover {
  border-color: var(--border-strong);
  box-shadow: var(--elevation-sm);
}

.job-card.is-closed {
  opacity: 0.75;
}

.job-card-org {
  color: var(--muted-foreground);
  font-size: var(--text-sm);
  font-weight: 500;
  margin: 0;
}

.job-card-title {
  font-size: var(--text-lg);
  font-weight: 600;
  line-height: 1.375;
  letter-spacing: -0.015em;
  margin: 0.125rem 0 0;
  /* Clamped, not balanced: balance optimises for the full text, clamp then
     hides the rest, and together they make a needlessly narrow box. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* The title's link covers the card, so anywhere on it opens the job — while
   the buttons at the foot, which sit above it, still do their own thing. */
.job-card-title a::after {
  content: "";
  position: absolute;
  inset: 0;
}

.job-card-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1rem;
  margin-top: 1rem;
  color: var(--muted-foreground);
  font-size: var(--text-sm);
}

.job-card-meta span {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
}

.job-card-meta .fa-solid {
  font-size: 0.875rem;
}

.job-card-facts {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.75rem;
  margin-top: 1rem;
  border: 1px solid var(--border);
  border-radius: 0.5rem;
  background-color: var(--surface-subtle);
  padding: 0.625rem 0.75rem;
}

.fact-label {
  color: var(--muted-foreground);
  font-size: var(--text-2xs);
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin: 0;
}

.fact-value {
  font-size: var(--text-base);
  font-weight: 600;
  margin: 0.125rem 0 0;
}

.job-card-actions {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: auto;
  padding-top: 1.25rem;
}

.job-card-actions > * {
  flex: 1 1 0;
}

/* --- The filter rail ------------------------------------------------------ */

.filter-group {
  border: 0;
  border-top: 1px solid var(--border);
  margin: 0;
  padding: 0.875rem 0 0;
}

.filter-group + .filter-group {
  margin-top: 0.875rem;
}

.filter-group legend {
  font-size: var(--text-sm);
  font-weight: 600;
  margin-bottom: 0.5rem;
  padding: 0;
  float: none;
  width: auto;
}

.filter-option {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.25rem 0;
  font-size: var(--text-base);
  color: var(--muted-foreground);
  cursor: pointer;
}

.filter-option:hover {
  color: var(--foreground);
}

.filter-option input {
  accent-color: var(--primary);
  width: 0.875rem;
  height: 0.875rem;
  flex-shrink: 0;
}

.filter-option:has(input:checked) {
  color: var(--foreground);
  font-weight: 500;
}

/* ============================================================================
   One recruitment
   ========================================================================== */

.back-link {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--muted-foreground);
  font-size: var(--text-base);
  font-weight: 500;
  width: fit-content;
}

.back-link:hover {
  color: var(--foreground);
}

.job-head {
  padding: 1.25rem;
}

@media (min-width: 768px) {
  .job-head {
    padding: 1.5rem;
  }
}

.job-head-top {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

@media (min-width: 576px) {
  .job-head-top {
    flex-direction: row;
    align-items: flex-start;
  }
}

.crest-lg {
  width: 3.5rem;
  height: 3.5rem;
  font-size: var(--text-sm);
}

.job-head h1 {
  font-size: var(--text-2xl);
  font-weight: 600;
  letter-spacing: -0.02em;
  margin: 0.25rem 0 0;
  text-wrap: balance;
}

@media (min-width: 768px) {
  .job-head h1 {
    font-size: var(--text-3xl);
  }
}

.rule {
  border: 0;
  border-top: 1px solid var(--border);
  margin: 1.25rem 0;
  opacity: 1;
}

.detail-blocks {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.25rem;
}

@media (min-width: 768px) {
  .detail-blocks {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

.detail-block .fact-label {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  text-transform: none;
  letter-spacing: 0;
  font-size: var(--text-xs);
}

.detail-block-value {
  font-size: var(--text-md);
  font-weight: 600;
  margin: 0.25rem 0 0;
  text-wrap: pretty;
}

.source-note {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  margin: 1.25rem 0 0;
  border: 1px solid var(--border);
  border-radius: 0.5rem;
  background-color: var(--surface-subtle);
  padding: 0.75rem;
  color: var(--muted-foreground);
  font-size: var(--text-sm);
  text-wrap: pretty;
}

.source-note .fa-solid {
  font-size: 0.875rem;
  margin-top: 0.125rem;
}

.source-note a {
  color: var(--primary);
  font-weight: 500;
}

.source-note a:hover {
  text-decoration: underline;
}

.job-head-actions {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  border-top: 1px solid var(--border);
  margin-top: 1.25rem;
  padding-top: 1.25rem;
}

@media (min-width: 576px) {
  .job-head-actions {
    flex-direction: row;
  }
}

.job-detail-grid {
  display: grid;
  gap: 1.5rem;
  grid-template-columns: minmax(0, 1fr);
  margin-top: 1.5rem;
}

@media (min-width: 992px) {
  .job-detail-grid {
    grid-template-columns: minmax(0, 1fr) 23rem;
  }

  /* The verdict is what the person reads the rest of the page against, so it
     follows them down it — and the column stops being half a screen of empty
     white once the notification's own sections run past it. */
  .job-detail-grid > aside {
    position: sticky;
    top: 5.5rem;
    align-self: start;
  }
}

/* --- Lists ---------------------------------------------------------------- */

.tick-list {
  list-style: none;
  margin: 1rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.tick-list li {
  display: flex;
  align-items: flex-start;
  gap: 0.625rem;
  font-size: var(--text-base);
  text-wrap: pretty;
}

.tick-list .fa-solid {
  color: var(--success-600);
  margin-top: 0.1875rem;
}

.step-list {
  margin: 0.75rem 0 0;
  padding-left: 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  font-size: var(--text-base);
}

.detail-rows {
  margin: 0.75rem 0 0;
}

.detail-row {
  display: grid;
  gap: 0.25rem 1rem;
  border-top: 1px solid var(--border);
  padding: 0.75rem 0;
}

.detail-row:first-child {
  border-top: 0;
  padding-top: 0;
}

@media (min-width: 576px) {
  .detail-row {
    grid-template-columns: 12rem minmax(0, 1fr);
  }
}

.detail-row dt {
  color: var(--muted-foreground);
  font-size: var(--text-sm);
  font-weight: 500;
}

.detail-row dd {
  margin: 0;
  font-size: var(--text-base);
  text-wrap: pretty;
}

.detail-hint {
  display: block;
  color: var(--muted-foreground);
  font-size: var(--text-xs);
  margin-top: 0.25rem;
}

/* --- The eligibility panel ------------------------------------------------ */

.criteria {
  list-style: none;
  margin: 1rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.875rem;
}

.criterion {
  display: flex;
  align-items: flex-start;
  gap: 0.625rem;
}

.criterion-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  flex-shrink: 0;
  border-radius: 999px;
  font-size: 0.75rem;
}

.criteria-ok .criterion-icon {
  background-color: var(--success-50);
  color: var(--success-700);
}
.criteria-warn .criterion-icon {
  background-color: var(--warning-50);
  color: var(--warning-700);
}
.criteria-bad .criterion-icon {
  background-color: var(--danger-50);
  color: var(--danger-700);
}

.criterion-label {
  font-size: var(--text-base);
  font-weight: 600;
  margin: 0;
}

.criterion-detail {
  color: var(--muted-foreground);
  font-size: var(--text-sm);
  margin: 0.125rem 0 0;
  text-wrap: pretty;
}

/* ============================================================================
   Live Working
   ========================================================================== */

.runner-banner {
  border: 1px solid var(--warning-200);
  border-radius: var(--radius);
  background-color: var(--warning-50);
  color: var(--warning-700);
  padding: 0.75rem 1rem;
  font-size: var(--text-base);
  margin: 0;
  text-wrap: pretty;
}

.live-grid {
  display: grid;
  align-items: start;
  gap: 1.25rem;
  grid-template-columns: minmax(0, 1fr);
  margin-top: 1.25rem;
}

@media (min-width: 1200px) {
  .live-grid:not(.is-wide) {
    grid-template-columns: minmax(0, 1fr) 360px;
  }
}

/* Widened, the portal takes the full width and the panels fall in beneath
   it — a government form at 0.6 scale is not usable. */
.live-grid.is-wide [data-side] {
  display: grid;
  gap: 1.25rem;
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
}

/* --- The portal ----------------------------------------------------------- */

.portal-card {
  overflow: hidden;
  padding: 0;
}

.portal-bar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  border-bottom: 1px solid var(--border);
  background-color: var(--surface-subtle);
  padding: 0.5rem 0.75rem;
}

.portal-lights {
  display: flex;
  gap: 0.25rem;
}

.portal-lights i {
  width: 0.625rem;
  height: 0.625rem;
  border-radius: 999px;
  background-color: var(--neutral-300);
}

.portal-url {
  min-width: 0;
  flex: 1 1 auto;
  color: var(--muted-foreground);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
}

.portal-live {
  flex-shrink: 0;
  font-size: var(--text-2xs);
  color: var(--muted-foreground);
}

.portal-live.is-live {
  color: var(--success-700);
}

.portal-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  border-bottom: 1px solid var(--border);
  background-color: var(--surface);
  padding: 0.5rem 0.75rem;
}

.portal-hint {
  min-width: 0;
  flex: 1 1 12rem;
  font-size: var(--text-xs);
  text-wrap: pretty;
}

.mode-toggle {
  display: inline-flex;
  border: 1px solid var(--border);
  border-radius: 0.5rem;
  overflow: hidden;
}

.mode-toggle button {
  border: 0;
  background: transparent;
  padding: 0.375rem 0.625rem;
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--muted-foreground);
}

.mode-toggle button[aria-pressed="true"] {
  background-color: var(--primary-subtle);
  color: var(--primary-subtle-foreground);
}

.portal-surface {
  position: relative;
  width: 100%;
  margin-inline: auto;
  background-color: var(--neutral-950);
  aspect-ratio: 1280 / 800;
  max-height: min(74vh, 900px);
}

.portal-surface.is-interactive {
  cursor: crosshair;
}

/* The ring says the keyboard is pointed at the portal, not at this page. */
.portal-surface.is-focused {
  box-shadow: inset 0 0 0 2px var(--brand-500);
}

.portal-surface img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  user-select: none;
  -webkit-user-drag: none;
}

.portal-surface img.is-blank {
  visibility: hidden;
}

/* One transparent pixel, holding the focus so composition and paste events
   have a real editable element to land on. */
.portal-keys {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  border: 0;
  resize: none;
  cursor: inherit;
}

.portal-caption {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  margin: 0;
  background-color: color-mix(in oklab, var(--neutral-950) 78%, transparent);
  color: #fff;
  padding: 0.5rem 0.75rem;
  font-size: var(--text-sm);
  pointer-events: none;
}

.portal-reason {
  border-top: 1px solid var(--border);
  margin: 0;
  padding: 0.5rem 1rem;
  color: var(--muted-foreground);
  font-size: var(--text-sm);
}

/* --- The fill preview ----------------------------------------------------- */

.filled-list,
.learned-list,
.download-list,
.history-list {
  list-style: none;
  margin: 1rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.filled-row {
  display: flex;
  align-items: flex-start;
  gap: 0.625rem;
  border: 1px solid var(--border);
  border-radius: 0.625rem;
  background-color: var(--surface);
  padding: 0.625rem 0.75rem;
}

.filled-mark {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.25rem;
  height: 1.25rem;
  flex-shrink: 0;
  border-radius: 999px;
  font-size: 0.625rem;
  margin-top: 0.125rem;
}

.fill-ok .filled-mark {
  background-color: var(--success-50);
  color: var(--success-700);
}
.fill-skip .filled-mark {
  background-color: var(--surface-sunken);
  color: var(--muted-foreground);
}
.fill-bad .filled-mark {
  background-color: var(--danger-50);
  color: var(--danger-700);
}

.filled-label {
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--muted-foreground);
  margin: 0;
}

/* Deliberately not masked. The preview exists so the person can check that
   the Aadhaar number NiyuktiAI typed is their own, and a row of dots checks
   nothing. Masking stays where the value would be kept — the log. */
.filled-value {
  font-size: var(--text-base);
  font-weight: 500;
  margin: 0.125rem 0 0;
  word-break: break-word;
}

.filled-detail {
  color: var(--muted-foreground);
  font-size: var(--text-xs);
  margin: 0.125rem 0 0;
}

.filled-source {
  flex-shrink: 0;
  color: var(--muted-foreground);
  font-size: var(--text-2xs);
  white-space: nowrap;
}

.learned-list li,
.download-list li,
.history-list li {
  border: 1px solid var(--border);
  border-radius: 0.625rem;
  padding: 0.625rem 0.75rem;
}

.download-list li,
.history-list li {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.download-list a {
  color: var(--primary);
  font-size: var(--text-sm);
  font-weight: 500;
  margin-left: auto;
}

/* --- Steps and the log ---------------------------------------------------- */

.step-timeline {
  list-style: none;
  margin: 1rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.step {
  display: flex;
  align-items: flex-start;
  gap: 0.625rem;
}

.step-mark {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.25rem;
  height: 1.25rem;
  flex-shrink: 0;
  border-radius: 999px;
  font-size: 0.625rem;
  margin-top: 0.125rem;
  background-color: var(--surface-sunken);
  color: var(--muted-foreground);
}

.step-done .step-mark {
  background-color: var(--success-50);
  color: var(--success-700);
}
.step-running .step-mark {
  background-color: var(--primary-subtle);
  color: var(--primary-subtle-foreground);
}
.step-waiting .step-mark {
  background-color: var(--warning-50);
  color: var(--warning-700);
}
.step-failed .step-mark {
  background-color: var(--danger-50);
  color: var(--danger-700);
}

.step-title {
  font-size: var(--text-base);
  font-weight: 500;
  margin: 0;
}

.step-detail {
  color: var(--muted-foreground);
  font-size: var(--text-sm);
  margin: 0.125rem 0 0;
  text-wrap: pretty;
}

.activity-log {
  list-style: none;
  margin: 1rem 0 0;
  padding: 0;
  max-height: 18rem;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
}

.log-line {
  display: flex;
  gap: 0.5rem;
  font-size: var(--text-sm);
  text-wrap: pretty;
}

.log-time {
  flex-shrink: 0;
  color: var(--muted-foreground);
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  padding-top: 0.125rem;
}

.log-success {
  color: var(--success-700);
}
.log-warning {
  color: var(--warning-700);
}
.log-error {
  color: var(--destructive);
}

/* --- The question modal --------------------------------------------------- */

.question-image {
  display: block;
  max-width: 100%;
  border: 1px solid var(--border);
  border-radius: 0.5rem;
  margin: 0.75rem 0;
  background-color: #fff;
}

.amount {
  font-size: var(--text-xl);
  font-weight: 600;
  margin: 0.5rem 0;
}

/* ============================================================================
   My Documents
   ========================================================================== */

.doc-stats {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
}

.doc-stat {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background-color: var(--card);
  box-shadow: var(--elevation-xs);
  padding: 1rem 1.25rem;
}

.doc-stat-value {
  font-size: var(--text-2xl);
  font-weight: 600;
  letter-spacing: -0.02em;
  margin: 0.25rem 0;
}

.doc-grid {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
}

.doc-card {
  display: flex;
  gap: 0.875rem;
  border: 1px solid var(--border);
  border-radius: 0.75rem;
  background-color: var(--surface);
  padding: 0.875rem;
}

.doc-thumb {
  width: 3.5rem;
  height: 4.5rem;
  flex-shrink: 0;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: 0.375rem;
  background-color: var(--surface-sunken);
}

.doc-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.doc-thumb-fallback {
  display: flex;
  width: 100%;
  height: 100%;
  align-items: center;
  justify-content: center;
  color: var(--muted-foreground);
  font-size: var(--text-2xs);
  font-weight: 600;
}

.doc-name {
  font-size: var(--text-base);
  font-weight: 600;
  margin: 0;
}

/* --- What the documents say ----------------------------------------------- */

.summary-groups {
  display: grid;
  gap: 1.5rem;
  margin-top: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(22rem, 1fr));
}

.summary-group h3 {
  font-size: var(--text-sm);
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--muted-foreground);
  margin: 0 0 0.5rem;
}

.summary-group dl {
  margin: 0;
}

.summary-row {
  border-top: 1px solid var(--border);
  padding: 0.5rem 0;
}

.summary-row:first-child {
  border-top: 0;
}

.summary-row dt {
  color: var(--muted-foreground);
  font-size: var(--text-xs);
  font-weight: 500;
}

.summary-row dd {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0.125rem 0 0;
}

.summary-value {
  font-size: var(--text-base);
  font-weight: 500;
  word-break: break-word;
}

.summary-source {
  color: var(--muted-foreground);
  font-size: var(--text-2xs);
  white-space: nowrap;
}

/* The row's controls appear on hover on a mouse, and are always there for a
   keyboard — a control you can only reach by hovering is not reachable. */
.summary-actions {
  margin-left: auto;
  display: flex;
  gap: 0.125rem;
  opacity: 0;
  transition: opacity 120ms;
}

.summary-row:hover .summary-actions,
.summary-row:focus-within .summary-actions {
  opacity: 1;
}

@media (hover: none) {
  .summary-actions {
    opacity: 1;
  }
}

/* --- Upload --------------------------------------------------------------- */

.drop-zone {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.375rem;
  margin-top: 1rem;
  border: 2px dashed var(--border-strong);
  border-radius: 0.75rem;
  background-color: var(--surface-subtle);
  padding: 2rem 1rem;
  text-align: center;
  cursor: pointer;
  transition: border-color 150ms, background-color 150ms;
}

.drop-zone:hover,
.drop-zone.is-over {
  border-color: var(--primary);
  background-color: var(--primary-subtle);
}

.drop-zone .fa-solid {
  font-size: 1.5rem;
  color: var(--muted-foreground);
}

/* The bytes take under a second and the reading takes a minute, so a bar that
   measures the upload has nothing left to say for the part people actually
   wait through. Once it is reading it stops claiming a percentage and just
   shows that something is still happening. */
.progress.is-reading {
  margin-top: 1rem;
  overflow: hidden;
}

.progress.is-reading .progress-bar {
  width: 40%;
  animation: upload-reading 1.4s ease-in-out infinite;
}

@keyframes upload-reading {
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(250%);
  }
}

@media (prefers-reduced-motion: reduce) {
  .progress.is-reading .progress-bar {
    width: 100%;
    animation: none;
  }
}

.upload-stage {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0.75rem 0 0;
  font-size: var(--text-sm);
  color: var(--muted-foreground);
}

.upload-read {
  border: 1px solid var(--border);
  border-radius: 0.75rem;
  background-color: var(--surface-subtle);
  padding: 1rem;
}

.upload-read-title {
  font-weight: 600;
  margin: 0;
}

.upload-read-list {
  display: grid;
  gap: 0.5rem;
  margin: 0;
  max-height: 18rem;
  overflow-y: auto;
}

.upload-read-row {
  display: grid;
  grid-template-columns: minmax(0, 11rem) minmax(0, 1fr);
  gap: 0.75rem;
  align-items: baseline;
}

.upload-read-row dt {
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--muted-foreground);
  margin: 0;
}

.upload-read-row dd {
  font-size: var(--text-sm);
  margin: 0;
  overflow-wrap: anywhere;
}

/* A value the reader is not sure of is still shown — hiding it reads as "it
   never found my father's name" — but it is marked, because using it without
   looking is how a form goes in wrong. */
.upload-read-row.is-pending dd {
  border-left: 2px solid var(--warning);
  padding-left: 0.5rem;
}

@media (max-width: 30rem) {
  .upload-read-row {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.125rem;
  }
}

/* ============================================================================
   Applications, alerts, profile
   ========================================================================== */

.nav-tabs {
  --bs-nav-tabs-border-color: var(--border);
  --bs-nav-tabs-link-active-bg: var(--background);
  --bs-nav-tabs-link-active-color: var(--primary);
  --bs-nav-tabs-link-active-border-color: var(--border) var(--border) var(--background);
  --bs-nav-link-color: var(--muted-foreground);
  --bs-nav-link-hover-color: var(--foreground);
  --bs-nav-link-font-size: var(--text-base);
  font-weight: 500;
}

.application-row {
  display: flex;
  align-items: flex-start;
  gap: 0.875rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background-color: var(--card);
  box-shadow: var(--elevation-xs);
  padding: 1rem;
  transition: border-color 150ms, box-shadow 150ms;
}

.application-row:hover {
  border-color: var(--border-strong);
  box-shadow: var(--elevation-sm);
}

/* Zero basis, not auto: a long post title made this block wider than the row
   and, once the row could wrap, it dropped below the crest and left it
   sitting alone on a line of its own. */
.application-row-main {
  min-width: 0;
  flex: 1 1 0;
}

.application-row-actions {
  flex-shrink: 0;
}

@media (max-width: 575.98px) {
  .application-row {
    flex-wrap: wrap;
  }

  /* The two buttons take their own line rather than squeezing the title. */
  .application-row-actions {
    flex-basis: 100%;
  }
}

/* Alerts get their own card on the alerts page rather than a bare list. */
.alert-page li {
  border: 1px solid var(--border);
  border-top: 1px solid var(--border);
  border-radius: var(--radius);
  background-color: var(--card);
  box-shadow: var(--elevation-xs);
  padding: 1rem;
  margin-bottom: 0.75rem;
}

.alert-page li:first-child {
  padding-top: 1rem;
}

.profile-grid {
  display: grid;
  gap: 1.5rem;
  grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 992px) {
  .profile-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.profile-row dd {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  flex-wrap: wrap;
}

/* On its own line, always. Sharing the value's line, a long hint pushed the
   (invisible until hover) edit button onto a second one, so the Category row
   carried a blank line that looked like a rendering fault. */
.profile-row .detail-hint {
  flex: 1 0 100%;
  margin-top: 0;
  order: 1;
}

.profile-edit {
  margin-left: auto;
  opacity: 0;
  transition: opacity 120ms;
}

.profile-row:hover .profile-edit,
.profile-row:focus-within .profile-edit {
  opacity: 1;
}

@media (hover: none) {
  .profile-edit {
    opacity: 1;
  }
}

.education-list {
  display: grid;
  gap: 1rem;
  margin-top: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
}

.education-card {
  border: 1px solid var(--border);
  border-radius: 0.75rem;
  background-color: var(--surface-subtle);
  padding: 1rem;
}

/* ============================================================================
   The assistant
   ========================================================================== */

/* The thread scrolls; the window does not. The height has to come out at
   exactly what .app-main leaves over — its own padding included — or the
   window grows a second scrollbar behind the thread's own and the composer
   drifts off the bottom of the screen. Hence one figure per breakpoint,
   matching shell.css's padding there. */
.chat-layout {
  display: grid;
  gap: 1.25rem;
  grid-template-columns: minmax(0, 1fr);
  height: calc(100dvh - var(--topbar-height) - 7.5rem); /* 1.5rem + 6rem */
  min-height: 26rem;
}

/* More than the 4rem of padding .app-main has here, because the fixed bottom
   bar is still on screen at this width and is taller than the 2.5rem left for
   it — a composer behind that bar cannot be typed into. */
@media (min-width: 768px) {
  .chat-layout {
    height: calc(100dvh - var(--topbar-height) - 6.5rem);
  }
}

@media (min-width: 992px) {
  .chat-layout {
    grid-template-columns: 16rem minmax(0, 1fr);
    height: calc(100dvh - var(--topbar-height) - 4.5rem); /* 2rem + 2.5rem */
  }
}

/* --- Past conversations --------------------------------------------------- *
 * A column on a wide screen, a drawer on a narrow one, from one piece of
 * markup: .offcanvas-lg takes the aside out of flow below 992px, so the grid
 * never keeps a lane for it. It must not be display:none there — that is the
 * one thing that would stop the drawer opening.                              */

.chat-rail {
  display: flex;
  flex-direction: column;
  min-height: 0;
}

@media (max-width: 991.98px) {
  .chat-rail {
    --bs-offcanvas-width: min(20rem, 86vw);
    background-color: var(--surface);
    border-right: 1px solid var(--border);
  }
}

.chat-rail .offcanvas-header {
  justify-content: space-between;
  border-bottom: 1px solid var(--border);
}

.chat-rail-body {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 0.75rem;
  min-height: 0;
  padding: 0.875rem;
}

@media (min-width: 992px) {
  .chat-rail-body {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background-color: var(--card);
    box-shadow: var(--elevation-xs);
  }
}

.chat-rail-label {
  color: var(--muted-foreground);
  font-size: var(--text-2xs);
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin: 0.25rem 0 0;
}

.chat-history {
  list-style: none;
  margin: 0;
  padding: 0;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  /* Titles are ellipsised, never scrolled sideways. */
  overflow-x: hidden;
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
}

.chat-history li {
  /* The delete button rides over the row so the highlight covers the row. */
  position: relative;
  display: flex;
  align-items: center;
}

.chat-history-item {
  display: flex;
  min-width: 0;
  flex: 1 1 auto;
  flex-direction: column;
  /* Stretched, not flex-start: a definite width is what lets the title
     ellipsise instead of pushing the row sideways. */
  align-items: stretch;
  border: 0;
  border-radius: 0.5rem;
  background: transparent;
  padding: 0.5rem 2.25rem 0.5rem 0.625rem;
  text-align: left;
  font-size: var(--text-sm);
  color: var(--muted-foreground);
}

.chat-history-item:hover {
  background-color: var(--secondary);
  color: var(--foreground);
}

.chat-history-item.is-current {
  background-color: var(--primary-subtle);
  color: var(--primary-subtle-foreground);
}

.chat-history-when {
  color: var(--muted-foreground);
  font-size: var(--text-2xs);
  margin-top: 0.0625rem;
}

.chat-history li > .btn {
  position: absolute;
  right: 0.25rem;
  top: 50%;
  translate: 0 -50%;
}

/* Revealed on hover where there is a pointer; always there on a touch
   screen, which has no hover to reveal it with. */
@media (hover: hover) {
  .chat-history li > .btn {
    opacity: 0;
    transition: opacity 150ms;
  }

  .chat-history li:hover > .btn,
  .chat-history li:focus-within > .btn {
    opacity: 1;
  }
}

.chat-history-empty {
  color: var(--muted-foreground);
  font-size: var(--text-sm);
  padding: 0.5rem 0.625rem;
  margin: 0;
}

/* --- The conversation ----------------------------------------------------- */

.chat-main {
  display: flex;
  flex-direction: column;
  min-height: 0;
  padding: 0;
  overflow: hidden;
}

.chat-head {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  border-bottom: 1px solid var(--border);
  padding: 0.875rem 1.25rem;
}

@media (max-width: 575.98px) {
  /* On a phone the empty state says the same thing, and the thread needs
     every line it can get. */
  .chat-head .card-subtitle {
    display: none;
  }
}

.chat-scroll {
  position: relative;
  display: flex;
  flex: 1 1 auto;
  min-height: 0;
}

.chat-thread {
  flex: 1 1 auto;
  overflow-y: auto;
  /* A flick past the end of the thread must not drag the page behind it. */
  overscroll-behavior: contain;
  padding: 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.chat-jump {
  position: absolute;
  bottom: 0.75rem;
  left: 50%;
  translate: -50% 0;
  z-index: 2;
  border-radius: 999px;
  box-shadow: var(--elevation-md);
}

.chat-empty {
  margin: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  max-width: 32rem;
  padding: 1rem 0;
  text-align: center;
}

.chat-empty h2 {
  font-size: var(--text-lg);
  font-weight: 600;
  margin: 0.5rem 0 0.25rem;
}

.chat-empty p {
  margin: 0;
  text-wrap: pretty;
}

.chat-suggestions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem;
  margin-top: 1.25rem;
}

.chat-suggestions .btn {
  white-space: normal;
}

/* One centred column of messages, whatever the card is wide — a line of
   text that runs the full width of a 1440px screen is unreadable. */
.chat-turn {
  display: flex;
  gap: 0.625rem;
  width: 100%;
  max-width: 48rem;
  margin-inline: auto;
}

.chat-you {
  justify-content: flex-end;
}

.chat-you .chat-body {
  /* A long question is a bubble, not a wall. */
  max-width: min(85%, 34rem);
  background-color: var(--primary);
  color: var(--primary-foreground);
  border-radius: 1rem 1rem 0.25rem 1rem;
  padding: 0.625rem 0.875rem;
}

.chat-assistant .chat-body {
  min-width: 0;
  flex: 1 1 auto;
  /* An answer fills the column; "Thinking…" is two words and should look
     like two words. */
  background-color: var(--surface-subtle);
  border: 1px solid var(--border);
  border-radius: 1rem 1rem 1rem 0.25rem;
  padding: 0.75rem 1rem;
}

.chat-turn.is-pending .chat-body {
  flex: 0 1 auto;
}

.chat-body {
  overflow-wrap: anywhere;
}

.chat-body p {
  margin: 0 0 0.625rem;
  text-wrap: pretty;
}

.chat-body p:last-child,
.chat-body ul:last-child,
.chat-body ol:last-child {
  margin-bottom: 0;
}

.chat-body ul,
.chat-body ol {
  margin: 0 0 0.625rem;
  padding-left: 1.25rem;
}

.chat-body li + li {
  margin-top: 0.25rem;
}

.chat-body li::marker {
  color: var(--muted-foreground);
}

.chat-body h3 {
  font-size: var(--text-md);
  font-weight: 600;
  margin: 1rem 0 0.375rem;
}

.chat-body > h3:first-child {
  margin-top: 0;
}

.chat-body code {
  background-color: var(--surface-sunken);
  border-radius: 0.25rem;
  padding: 0.0625rem 0.3125rem;
  font-family: var(--font-mono);
  font-size: 0.9em;
  /* Bootstrap's own code colour is a pink from its default palette, and a
     file name in an answer is the only place in the app it would show. */
  color: var(--foreground);
}

.chat-you .chat-body code {
  background-color: color-mix(in oklab, var(--primary-foreground) 20%, transparent);
  color: inherit;
}

.chat-avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  flex-shrink: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, var(--brand-500), var(--brand-700));
  color: #fff;
  font-size: 0.75rem;
}

.chat-thinking {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--muted-foreground);
  margin: 0;
}

.chat-dots {
  display: inline-flex;
  align-items: center;
  gap: 0.1875rem;
}

.chat-dots span {
  width: 0.3125rem;
  height: 0.3125rem;
  border-radius: 999px;
  background-color: currentColor;
  animation: chat-dot 1.2s ease-in-out infinite;
}

.chat-dots span:nth-child(2) {
  animation-delay: 0.15s;
}

.chat-dots span:nth-child(3) {
  animation-delay: 0.3s;
}

@keyframes chat-dot {
  0%,
  60%,
  100% {
    opacity: 0.3;
    translate: 0 0;
  }
  30% {
    opacity: 1;
    translate: 0 -2px;
  }
}

.chat-composer {
  border-top: 1px solid var(--border);
  padding: 0.75rem 1.25rem;
}

.chat-composer-row {
  display: flex;
  align-items: flex-end;
  gap: 0.5rem;
  width: 100%;
  /* Same column as the messages, so the caret lines up with the thread. */
  max-width: 48rem;
  margin-inline: auto;
}

.chat-composer textarea {
  resize: none;
  max-height: 12.5rem;
}

.chat-composer .btn {
  flex-shrink: 0;
}

/* ============================================================================
   Settings
   ========================================================================== */

.switch-list {
  margin-top: 1rem;
}

.switch-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  border-top: 1px solid var(--border);
  padding: 0.875rem 0;
  cursor: pointer;
}

.switch-row:first-child {
  border-top: 0;
  padding-top: 0;
}

.switch-label {
  display: block;
  font-size: var(--text-base);
  font-weight: 500;
}

.switch-hint {
  display: block;
  color: var(--muted-foreground);
  font-size: var(--text-sm);
  margin-top: 0.125rem;
  text-wrap: pretty;
}

/* A switch, not a checkbox. Bootstrap's own .form-switch carries a 2.5em left
   gutter for a label that sits after the control; here the control is at the
   end of the row, so the shape is built rather than borrowed — and the knob is
   a gradient rather than an SVG so it can be drawn in the palette's own
   colours. Width and height alone left this a stretched rounded square with a
   tick in it, which says nothing about being on or off. */
.switch-row .form-check-input {
  --switch-knob: var(--muted-foreground);
  flex-shrink: 0;
  margin-top: 0.125rem;
  width: 2.25rem;
  height: 1.25rem;
  border-radius: 999px;
  background-color: var(--surface-sunken);
  background-image: radial-gradient(circle at center, var(--switch-knob) 42%, transparent 44%);
  background-size: 1.25rem 1.25rem;
  background-repeat: no-repeat;
  background-position: left center;
  cursor: pointer;
  transition: background-position 150ms ease-in-out, background-color 150ms;
}

.switch-row .form-check-input:checked {
  --switch-knob: #fff;
  background-color: var(--primary);
  border-color: var(--primary);
  background-position: right center;
}

.rule-list {
  list-style: none;
  margin: 1rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.875rem;
}

.rule-list li {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  font-size: var(--text-base);
  text-wrap: pretty;
}

.rule-list .fa-solid {
  margin-top: 0.1875rem;
  color: var(--primary);
}

/* --- Utility odds and ends the markup leans on --------------------------- */

/* A fact the board never printed, wherever one is shown. It reads as a
   pointer rather than as a figure, so it is never mistaken for one — and
   every screen says it the same way. */
.fact-unstated {
  color: var(--muted-foreground);
  font-size: var(--text-sm);
  font-weight: 400;
}

.text-muted-fg {
  color: var(--muted-foreground);
}
.text-success-fg {
  color: var(--success-700);
}
.text-warning-fg {
  color: var(--warning-700);
}
.text-danger-fg {
  color: var(--destructive);
}
.text-display {
  font-family: var(--font-display);
}
.tabular {
  font-variant-numeric: tabular-nums;
}
.truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.stack {
  display: flex;
  flex-direction: column;
}
.row-center {
  display: flex;
  align-items: center;
}
.visually-hidden-focusable:not(:focus):not(:focus-within) {
  position: absolute !important;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
}

/* The apply pre-flight: what will be typed, beside whether it may be. */
.apply-grid {
  display: grid;
  gap: 1.5rem;
  grid-template-columns: minmax(0, 1fr);
  margin-top: 1.5rem;
}

@media (min-width: 992px) {
  .apply-grid {
    grid-template-columns: minmax(0, 1fr) 23rem;
  }

  /* The verdict and "Open the portal" stay with the person as they read down
     the list of what will be typed — the column was stretching to the height
     of that list and standing empty for most of it. */
  .apply-grid > aside {
    position: sticky;
    top: 5.5rem;
    align-self: start;
  }
}

/* ============================================================================
   Onboarding
   ========================================================================== */

.onboard-shell {
  min-height: 100dvh;
  background-color: var(--background);
}

.onboard-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  border-bottom: 1px solid var(--border);
  background-color: var(--surface);
  padding: 1rem 1.5rem;
}

.onboard-main {
  margin-inline: auto;
  max-width: 44rem;
  padding: 2.5rem 1.5rem 4rem;
}

.onboard-progress {
  margin-bottom: 1.5rem;
}

.stepper {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.25rem;
  list-style: none;
  margin: 1rem 0 0;
  padding: 0;
}

.stepper li {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--muted-foreground);
  font-size: var(--text-xs);
}

.stepper li > span {
  display: grid;
  place-items: center;
  width: 1.375rem;
  height: 1.375rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: var(--text-2xs);
  font-weight: 600;
}

.stepper li.is-current {
  color: var(--foreground);
  font-weight: 500;
}

.stepper li.is-current > span {
  border-color: var(--primary);
  background-color: var(--primary-subtle);
  color: var(--primary-subtle-foreground);
}

.stepper li.is-done > span {
  border-color: var(--success-200);
  background-color: var(--success-50);
  color: var(--success-700);
}

.onboard-card {
  overflow: hidden;
}

.onboard-form {
  display: grid;
  gap: 1rem;
  margin-top: 1.5rem;
}

@media (min-width: 576px) {
  .onboard-form {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  /* A choice group and the empty state want the whole row. */
  .onboard-form > fieldset,
  .onboard-form > .empty-state {
    grid-column: 1 / -1;
  }
}

.onboard-field {
  min-width: 0;
  border: 0;
  margin: 0;
  padding: 0;
}

.onboard-field legend {
  float: none;
  width: auto;
  padding: 0;
}

.onboard-choices {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.25rem;
}

.onboard-actions {
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
  border-top: 1px solid var(--border);
  padding: 1rem 1.25rem;
}

.onboard-actions [data-next] {
  margin-left: auto;
}

.onboard-note {
  margin: 1.5rem 0 0;
  text-align: center;
  font-size: var(--text-sm);
  text-wrap: pretty;
}
