:root {
  color-scheme: light;
  --font-ui: "Aptos", "Segoe UI Variable", "Segoe UI", "Inter", "Noto Sans", sans-serif;
  --font-data: "Aptos Mono", "Cascadia Mono", "SFMono-Regular", "Roboto Mono", monospace;
  --canvas: #eef1f4;
  --surface: #ffffff;
  --surface-muted: #f8f9fb;
  --surface-rail: #f3f5f7;
  --line: #d6dce3;
  --line-strong: #aeb8c4;
  --text: #17202a;
  --text-muted: #4e5b68;
  --text-subtle: #667382;
  --accent: #2f6f4e;
  --accent-hover: #275d42;
  --accent-pressed: #214d38;
  --accent-blue: #2952cc;
  --danger: #b42318;
  --warning: #8a4b00;
  --success: #1d6a43;
  --focus: #174ea6;
  --shadow-sm: 0 1px 2px rgb(18 28 45 / 0.08);
  --shadow-md: 0 12px 32px rgb(18 28 45 / 0.14);
  --radius-xs: 3px;
  --radius-sm: 5px;
  --radius-md: 8px;
  --topbar-height: 52px;
  --ribbon-height: 142px;
  --rail-width: 292px;
}

* {
  box-sizing: border-box;
}

html {
  min-block-size: 100%;
  background: var(--canvas);
  font-family: var(--font-ui);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

body {
  min-block-size: 100%;
  margin: 0;
  color: var(--text);
  background: var(--canvas);
}

button,
input,
select {
  font: inherit;
}

button {
  cursor: pointer;
}

button:disabled {
  cursor: not-allowed;
}

[hidden] {
  display: none !important;
}

.skip-link {
  position: fixed;
  inset-block-start: 8px;
  inset-inline-start: 8px;
  z-index: 1000;
  padding: 10px 14px;
  color: #ffffff;
  background: var(--focus);
  border-radius: var(--radius-sm);
  transform: translateY(-140%);
}

.skip-link:focus-visible {
  transform: translateY(0);
  outline: 3px solid #ffffff;
  outline-offset: 2px;
}

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

.app-shell {
  min-block-size: 100vh;
}

.topbar {
  position: sticky;
  inset-block-start: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-block-size: var(--topbar-height);
  padding-inline: 14px 18px;
  color: var(--text);
  background: var(--surface);
  border-block-end: 1px solid var(--line);
}

.brand-lockup {
  display: flex;
  align-items: center;
  gap: 10px;
  min-inline-size: 0;
}

.brand-mark {
  display: grid;
  place-items: center;
  inline-size: 34px;
  block-size: 30px;
  color: #ffffff;
  background: var(--accent);
  border: 1px solid var(--accent-pressed);
  border-radius: var(--radius-xs);
  font-family: var(--font-data);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
}

.brand-kicker,
.section-label {
  margin: 0;
  color: var(--text-subtle);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.brand-lockup h1,
.login-card h2,
.workbook-topline h2,
.inspector h3 {
  margin: 0;
  color: var(--text);
  font-weight: 700;
  letter-spacing: -0.02em;
}

.brand-lockup h1 {
  font-size: 18px;
  line-height: 1.1;
}

.topbar-meta {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  min-inline-size: 0;
}

.state-chip,
.version-chip,
.user-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-block-size: 28px;
  padding-inline: 10px;
  color: var(--text-muted);
  background: #ffffff;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font-size: 12px;
  white-space: nowrap;
}

.state-chip::before {
  content: "";
  inline-size: 7px;
  block-size: 7px;
  background: var(--warning);
  border-radius: 999px;
}

.state-chip[data-state="ready"]::before {
  background: var(--success);
}

.state-chip[data-state="error"]::before {
  background: var(--danger);
}

.login-panel {
  display: grid;
  place-items: center;
  min-block-size: calc(100vh - var(--topbar-height));
  padding: 24px;
}

.login-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 340px;
  gap: 32px;
  inline-size: min(860px, 100%);
  padding: 28px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
}

.login-card h2 {
  margin-block-start: 8px;
  font-size: clamp(28px, 4vw, 44px);
  line-height: 1;
}

.panel-copy {
  max-inline-size: 520px;
  margin-block: 14px 0;
  color: var(--text-muted);
  font-size: 16px;
  line-height: 1.55;
}

.login-form {
  display: grid;
  align-content: start;
  gap: 8px;
  padding: 16px;
  background: var(--surface-muted);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}

.login-form label,
.field label {
  color: var(--text-muted);
  font-size: 12px;
  font-weight: 700;
}

input,
select {
  inline-size: 100%;
  min-block-size: 38px;
  color: var(--text);
  background: #ffffff;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-xs);
}

input {
  padding-inline: 10px;
}

select {
  padding-inline: 10px 34px;
}

input:hover,
select:hover {
  border-color: #7f8a99;
}

input:focus-visible,
select:focus-visible,
button:focus-visible,
.drop-zone:focus-visible,
.sheet-scroller:focus-visible {
  outline: 3px solid color-mix(in srgb, var(--focus) 72%, white);
  outline-offset: 2px;
}

.form-error {
  margin: 2px 0 0;
  color: var(--danger);
  font-size: 13px;
  font-weight: 700;
}

.workspace {
  display: grid;
  grid-template-columns: var(--rail-width) minmax(0, 1fr);
  min-block-size: calc(100vh - var(--topbar-height));
  overflow: hidden;
  transition: grid-template-columns 220ms cubic-bezier(0.2, 0, 0.38, 0.9);
}

.workspace.rail-collapsed {
  grid-template-columns: 0 minmax(0, 1fr);
}

.rail {
  display: flex;
  flex-direction: column;
  inline-size: var(--rail-width);
  min-inline-size: 0;
  min-block-size: calc(100vh - var(--topbar-height));
  overflow: hidden;
  background: var(--surface-rail);
  border-inline-end: 1px solid var(--line);
  transform: translateX(0);
  transition: transform 220ms cubic-bezier(0.2, 0, 0.38, 0.9), opacity 160ms ease, border-color 160ms ease;
}

.workspace.rail-collapsed .rail {
  pointer-events: none;
  opacity: 0;
  border-inline-end-color: transparent;
  transform: translateX(-100%);
}

.rail-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  min-block-size: 48px;
  padding-inline: 14px;
  border-block-end: 1px solid var(--line);
}

.rail-header-actions {
  display: flex;
  align-items: center;
  gap: 4px;
}

.job-list {
  display: grid;
  gap: 6px;
  padding: 10px;
  overflow: auto;
}

.job-card {
  display: grid;
  gap: 5px;
  inline-size: 100%;
  padding: 10px 11px;
  text-align: start;
  color: var(--text);
  background: #ffffff;
  border: 1px solid var(--line);
  border-inline-start: 4px solid transparent;
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-sm);
}

.job-card:hover {
  border-color: var(--line-strong);
}

.job-card.is-active {
  border-inline-start-color: var(--accent-blue);
  box-shadow: inset 0 0 0 1px var(--accent-blue);
}

.job-card-title {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  font-weight: 700;
}

.job-card-meta,
.job-card-status,
.empty-panel span,
.ribbon-help,
.drop-zone p,
.validation-summary,
.formula-input {
  color: var(--text-muted);
  font-size: 13px;
}

.job-card-status {
  display: flex;
  align-items: center;
  gap: 6px;
}

.status-dot {
  inline-size: 7px;
  block-size: 7px;
  flex: 0 0 auto;
  background: var(--text-subtle);
  border-radius: 999px;
}

.status-dot.ready {
  background: var(--success);
}

.status-dot.rejected,
.status-dot.error {
  background: var(--danger);
}

.status-dot.warning {
  background: var(--warning);
}

.empty-panel {
  display: grid;
  gap: 4px;
  margin: 10px;
  padding: 14px;
  color: var(--text);
  background: #ffffff;
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius-sm);
}

.workbook {
  display: grid;
  /* topline, stage rail, ribbon, banner, then the active pane fills the rest. */
  grid-template-rows: auto auto auto auto minmax(0, 1fr);
  min-inline-size: 0;
  background: var(--canvas);
}

/* The active pane scrolls on its own so the ribbon and stages stay put. */
.pane {
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-block-size: 0;
  padding-block-end: 16px;
  overflow-y: auto;
}

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

#paneData {
  gap: 0;
}

.workbook-topline {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  padding: 14px 16px;
  background: var(--surface);
  border-block-end: 1px solid var(--line);
}

.workbook-title-row {
  display: flex;
  align-items: center;
  gap: 10px;
  min-inline-size: 0;
}

.rail-toggle-button {
  flex: 0 0 auto;
}

.workbook-topline h2 {
  margin-block-start: 3px;
  font-size: 22px;
}

.period-readout {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  flex-wrap: wrap;
}

.period-readout span {
  padding: 6px 10px;
  color: var(--text-muted);
  background: var(--surface-muted);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font-size: 12px;
  font-weight: 700;
}

.ribbon {
  background: var(--surface);
  border-block-end: 1px solid var(--line-strong);
}

.ribbon-tabs {
  display: flex;
  align-items: end;
  gap: 2px;
  min-block-size: 34px;
  padding-inline: 12px;
  border-block-end: 1px solid var(--line);
}

.ribbon-tab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-block-size: 30px;
  padding-inline: 14px;
  color: var(--text-muted);
  background: none;
  border: 1px solid transparent;
  border-block-end: 0;
  border-radius: var(--radius-xs) var(--radius-xs) 0 0;
  font-size: 13px;
  font-weight: 700;
  transition: color 120ms ease, background-color 120ms ease;
}

.ribbon-tab:hover {
  color: var(--text);
  background: var(--surface-muted);
}

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

.ribbon-tab[aria-selected="true"] {
  color: var(--accent-pressed);
  background: var(--surface-muted);
  border-color: var(--line);
}

/* Count of produced artefacts; the number is the point, so it reads as data. */
.tab-count {
  min-inline-size: 18px;
  padding-inline: 5px;
  color: var(--surface);
  background: var(--accent);
  border-radius: 9px;
  font-family: var(--font-data);
  font-size: 11px;
  text-align: center;
}

.ribbon-groups {
  display: grid;
  grid-template-columns: minmax(420px, 1.4fr) minmax(280px, 0.9fr) minmax(280px, 0.9fr);
}

.ribbon-groups[data-pane="data"],
.ribbon-groups[data-pane="results"] {
  grid-template-columns: minmax(0, 1fr);
}

.ribbon-body {
  min-block-size: 106px;
  padding: 8px 12px;
}

.ribbon-group {
  display: flex;
  align-items: end;
  gap: 10px;
  padding: 6px 12px;
  border-inline-end: 1px solid var(--line);
}

.ribbon-group:last-child {
  border-inline-end: 0;
}

.ribbon-form {
  display: grid;
  grid-template-columns: minmax(180px, 1fr) 94px 96px auto;
  align-items: end;
}

.field {
  display: grid;
  gap: 5px;
  min-inline-size: 0;
}

.field-wide {
  min-inline-size: 180px;
}

.upload-group,
.validation-group {
  align-items: center;
  flex-wrap: wrap;
}

.ribbon-help {
  flex-basis: 100%;
  margin: -2px 0 0;
}

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-block-size: 38px;
  padding-inline: 14px;
  color: var(--text);
  background: #ffffff;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-xs);
  font-weight: 700;
  white-space: nowrap;
  transition-property: background-color, border-color, color, box-shadow;
  transition-duration: 150ms;
  transition-timing-function: cubic-bezier(0.2, 0, 0.38, 0.9);
}

.button:hover:not(:disabled) {
  background: var(--surface-muted);
  border-color: #7f8a99;
}

.button:active:not(:disabled) {
  background: #e8ecef;
}

.button:disabled {
  color: #7b8794;
  background: #eef1f4;
  border-color: #d8dde3;
}

.button-primary {
  color: #ffffff;
  background: var(--accent);
  border-color: var(--accent-pressed);
}

.button-primary:hover:not(:disabled) {
  color: #ffffff;
  background: var(--accent-hover);
  border-color: var(--accent-pressed);
}

.button-primary:active:not(:disabled) {
  color: #ffffff;
  background: var(--accent-pressed);
}

.button-secondary {
  color: var(--accent-pressed);
  background: #ffffff;
  border-color: var(--accent);
}

.button-secondary:hover:not(:disabled) {
  color: var(--accent-pressed);
  background: #f3f6f4;
  border-color: var(--accent-pressed);
}

.button-quiet {
  min-block-size: 32px;
  padding-inline: 10px;
  color: var(--text-muted);
  background: transparent;
  border-color: transparent;
}

.button-quiet:hover:not(:disabled) {
  color: var(--text);
  background: var(--surface-muted);
  border-color: var(--line);
}

.button-small {
  min-block-size: 30px;
  font-size: 12px;
}

.drop-zone {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin: 12px 16px;
  padding: 14px 16px;
  color: var(--text);
  background: var(--surface);
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius-sm);
}

.drop-zone.is-over {
  border-color: var(--accent-blue);
  box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--accent-blue) 35%, white);
}

.drop-zone p {
  margin: 3px 0 0;
}

.drop-zone-action {
  color: var(--accent-pressed);
  font-size: 13px;
  font-weight: 700;
  white-space: nowrap;
}

.formula-bar {
  display: grid;
  grid-template-columns: 72px minmax(0, 1fr);
  gap: 8px;
  padding: 0 16px 12px;
}

.name-box,
.formula-input {
  display: flex;
  align-items: center;
  min-block-size: 36px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-xs);
}

.name-box {
  justify-content: center;
  color: var(--text-muted);
  font-family: var(--font-data);
  font-size: 12px;
  font-weight: 700;
}

.formula-input {
  min-inline-size: 0;
  padding-inline: 12px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sheet-panel {
  min-block-size: 0;
  margin: 0 16px 12px;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}

.sheet-scroller {
  inline-size: 100%;
  block-size: 100%;
  overflow: auto;
}

.sheet-grid {
  inline-size: 100%;
  min-inline-size: 920px;
  border-collapse: separate;
  border-spacing: 0;
  font-size: 13px;
}

.sheet-grid th,
.sheet-grid td {
  block-size: 34px;
  padding: 7px 10px;
  border-inline-end: 1px solid var(--line);
  border-block-end: 1px solid var(--line);
  text-align: start;
  vertical-align: middle;
}

.sheet-grid th {
  position: sticky;
  inset-block-start: 0;
  z-index: 1;
  color: var(--text-muted);
  background: #f1f3f5;
  font-size: 12px;
  font-weight: 700;
}

.sheet-grid .row-handle {
  inline-size: 44px;
  padding-inline: 0;
  color: var(--text-subtle);
  text-align: center;
  background: #f1f3f5;
  font-family: var(--font-data);
  font-size: 12px;
}

.sheet-grid td[data-kind="number"],
.sheet-grid td[data-kind="hash"] {
  font-family: var(--font-data);
}

.sheet-grid td[data-kind="number"] {
  text-align: end;
}

.sheet-grid tbody tr:hover td:not(.row-handle) {
  background: #f9fbff;
}

.sheet-grid tbody tr.is-selected td:not(.row-handle) {
  box-shadow: inset 0 0 0 1px var(--accent-blue);
}

.status-cell {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  color: var(--text);
  font-weight: 700;
}

.remedy-text {
  color: var(--text-muted);
}

.inspector {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 12px 16px;
  background: var(--surface);
  border-block-start: 1px solid var(--line);
}

.inspector h3 {
  margin-block-start: 2px;
  font-size: 16px;
}

.validation-summary {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  flex-wrap: wrap;
}

.summary-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-block-size: 30px;
  padding-inline: 10px;
  color: var(--text-muted);
  background: #ffffff;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font-size: 12px;
  font-weight: 700;
}

.summary-item strong {
  color: var(--text);
  font-family: var(--font-data);
}

/* ---------------------------------------------------------------------------
   Stage rail

   Answers "where am I and what do I do next" from real job state. Each stage
   carries its state as text as well as colour, because a colour-only step
   indicator is unreadable to a third of the reasons people fail this task.
   --------------------------------------------------------------------------- */

.stage-rail {
  padding: 10px 16px;
  background: var(--surface);
  border-block-end: 1px solid var(--line);
}

.stage-list {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin: 0;
  padding: 0;
  list-style: none;
}

.stage {
  display: flex;
  align-items: center;
  gap: 8px;
  min-inline-size: 0;
  flex: 1 1 150px;
  padding: 7px 10px;
  background: var(--surface-muted);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}

.stage-index {
  display: grid;
  place-items: center;
  inline-size: 22px;
  block-size: 22px;
  flex: none;
  color: var(--text-muted);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  font-family: var(--font-data);
  font-size: 12px;
  font-weight: 700;
}

.stage-text {
  min-inline-size: 0;
}

.stage-name {
  display: block;
  color: var(--text);
  font-size: 13px;
  font-weight: 700;
  line-height: 1.2;
}

.stage-state {
  display: block;
  color: var(--text-subtle);
  font-size: 11.5px;
  line-height: 1.3;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.stage[data-state="done"] {
  background: var(--surface);
  border-color: var(--success);
}

.stage[data-state="done"] .stage-index {
  color: var(--surface);
  background: var(--success);
  border-color: var(--success);
}

.stage[data-state="current"] {
  background: var(--surface);
  border-color: var(--accent-blue);
  box-shadow: inset 0 0 0 1px var(--accent-blue);
}

.stage[data-state="current"] .stage-index {
  color: var(--surface);
  background: var(--accent-blue);
  border-color: var(--accent-blue);
}

.stage[data-state="blocked"] {
  background: var(--surface);
  border-color: var(--danger);
}

.stage[data-state="blocked"] .stage-index {
  color: var(--surface);
  background: var(--danger);
  border-color: var(--danger);
}

.stage[data-state="running"] .stage-index {
  color: var(--surface);
  background: var(--warning);
  border-color: var(--warning);
}

/* ---------------------------------------------------------------------------
   Terminal state banner
   --------------------------------------------------------------------------- */

.job-banner {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin: 12px 16px 0;
  padding: 12px 14px;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-inline-start: 4px solid var(--text-subtle);
  border-radius: var(--radius-sm);
}

.job-banner[data-tone="error"] {
  border-inline-start-color: var(--danger);
}

.job-banner[data-tone="success"] {
  border-inline-start-color: var(--success);
}

.job-banner[data-tone="working"] {
  border-inline-start-color: var(--warning);
}

.job-banner[data-tone="info"] {
  border-inline-start-color: var(--accent-blue);
}

.banner-body {
  min-inline-size: 0;
  flex: 1 1 auto;
}

.banner-title {
  margin: 0;
  font-size: 14px;
  font-weight: 700;
}

.banner-detail {
  margin: 3px 0 0;
  color: var(--text-muted);
  font-size: 13px;
}

.banner-code {
  display: inline-block;
  margin-inline-end: 6px;
  padding: 1px 6px;
  color: var(--text);
  background: var(--surface-muted);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-xs);
  font-family: var(--font-data);
  font-size: 11.5px;
}

/* ---------------------------------------------------------------------------
   Panels and record lists

   Replaces the old grid-of-status-text. A file, a check, and an artefact are
   records with a name and facts, not spreadsheet cells.
   --------------------------------------------------------------------------- */

.panel {
  margin: 0 16px;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-sm);
}

.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  padding: 10px 14px;
  border-block-end: 1px solid var(--line);
}

.panel-head h3 {
  margin: 2px 0 0;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.panel-meta {
  margin: 0;
  color: var(--text-subtle);
  font-family: var(--font-data);
  font-size: 12px;
}

.record-list {
  display: flex;
  flex-direction: column;
}

.record {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  padding: 10px 14px;
  border-block-end: 1px solid var(--line);
}

.record:last-child {
  border-block-end: 0;
}

.record-main {
  min-inline-size: 0;
  flex: 1 1 260px;
}

.record-name {
  display: block;
  color: var(--text);
  font-size: 13.5px;
  font-weight: 700;
  overflow-wrap: anywhere;
}

.record-detail {
  display: block;
  margin-block-start: 2px;
  color: var(--text-muted);
  font-size: 12.5px;
}

.record-facts {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}

.fact {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.fact-label {
  color: var(--text-subtle);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.fact-value {
  color: var(--text);
  font-family: var(--font-data);
  font-size: 12.5px;
}

.record-empty {
  padding: 14px;
  color: var(--text-subtle);
  font-size: 13px;
}

/* ---------------------------------------------------------------------------
   Reconciliation: the arithmetic must be readable, not summarised
   --------------------------------------------------------------------------- */

.recon-panel {
  padding: 12px 14px;
}

.recon-row {
  padding-block: 8px;
  border-block-end: 1px solid var(--line);
}

.recon-row:last-child {
  border-block-end: 0;
}

.recon-name {
  margin: 0 0 4px;
  font-size: 13px;
  font-weight: 700;
}

.recon-sum {
  display: flex;
  align-items: baseline;
  gap: 6px;
  flex-wrap: wrap;
  font-family: var(--font-data);
  font-size: 13px;
}

.recon-term {
  color: var(--text);
}

.recon-term span {
  color: var(--text-subtle);
  font-size: 11px;
}

.recon-op {
  color: var(--text-subtle);
}

.recon-balanced {
  color: var(--success);
  font-weight: 700;
}

.recon-unbalanced {
  color: var(--danger);
  font-weight: 700;
}

.recon-note {
  margin: 6px 0 0;
  color: var(--text-muted);
  font-size: 12.5px;
}

.pane-note {
  margin: 0 16px;
  color: var(--text-subtle);
  font-size: 12.5px;
}

.toast {
  position: fixed;
  inset-inline: auto 16px;
  /* Clears the assistant launcher, which is pinned to the same corner. Covering it would
     hide the control at the moment a result toast makes an operator want to ask about it. */
  inset-block-end: 66px;
  z-index: 100;
  max-inline-size: min(460px, calc(100vw - 32px));
  padding: 12px 14px;
  color: #ffffff;
  background: #1f293a;
  border: 1px solid #101015;
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md);
  font-weight: 700;
}

.toast[data-tone="error"] {
  background: var(--danger);
  border-color: #7a1a12;
}

.toast[data-tone="success"] {
  background: var(--success);
  border-color: #104329;
}

@media (max-width: 1120px) {
  :root {
    --rail-width: 248px;
  }

  .ribbon-groups {
    grid-template-columns: 1fr;
  }

  .ribbon-group {
    border-inline-end: 0;
    border-block-end: 1px solid var(--line);
  }

  .ribbon-group:last-child {
    border-block-end: 0;
  }
}

@media (max-width: 820px) {
  .topbar {
    position: static;
    align-items: flex-start;
    gap: 10px;
    flex-direction: column;
    padding-block: 12px;
  }

  .topbar-meta {
    justify-content: flex-start;
    flex-wrap: wrap;
  }

  .login-card {
    grid-template-columns: 1fr;
    padding: 20px;
  }

  .workspace {
    grid-template-columns: 1fr;
    overflow: hidden;
  }

  .workspace.rail-collapsed {
    grid-template-columns: 1fr;
  }

  .rail {
    inline-size: 100%;
    max-block-size: 320px;
    min-block-size: auto;
    border-inline-end: 0;
    border-block-end: 1px solid var(--line);
    transform: translateY(0);
    transition: max-block-size 220ms cubic-bezier(0.2, 0, 0.38, 0.9), transform 220ms cubic-bezier(0.2, 0, 0.38, 0.9), opacity 160ms ease;
  }

  .workspace.rail-collapsed .rail {
    max-block-size: 0;
    opacity: 0;
    border-block-end: 0;
    transform: translateY(-16px);
  }

  .job-list {
    grid-auto-flow: column;
    grid-auto-columns: minmax(220px, 1fr);
    overflow-x: auto;
  }

  .empty-panel {
    margin-block-start: 0;
  }

  .workbook-topline,
  .drop-zone,
  .record {
    align-items: stretch;
    flex-direction: column;
  }

  /* Stages stack rather than shrinking below a readable label. */
  .stage {
    flex: 1 1 100%;
  }

  .record-facts {
    gap: 12px;
  }

  .period-readout,
  .validation-summary {
    justify-content: flex-start;
  }

  .ribbon-form {
    grid-template-columns: 1fr;
  }

  .button,
  input,
  select {
    min-block-size: 44px;
  }

  .drop-zone-action {
    white-space: normal;
  }

  .formula-bar {
    grid-template-columns: 58px minmax(0, 1fr);
  }
}

@media (max-width: 480px) {
  .login-panel {
    padding: 12px;
  }

  .workbook-topline,
  .ribbon-tabs,
  .ribbon-body,
  .drop-zone,
  .formula-bar,
  .stage-rail {
    padding-inline: 10px;
  }

  .sheet-panel,
  .panel,
  .job-banner,
  .pane-note {
    margin-inline: 10px;
  }

  .brand-lockup h1 {
    font-size: 16px;
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    scroll-behavior: auto !important;
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
}

/* ---------------------------------------------------------------------------
   Spreadsheet host

   The grid bundle is optional and large, so it is fetched only when the Data
   tab is first opened. Until then, and if it never arrives, the table preview
   below it stays the interface. The host reserves its own height so switching
   tabs does not reflow the pane.
   --------------------------------------------------------------------------- */

/* The panel owns the frame; the host is only the canvas surface. Expanding is then
   one element changing size, so the grid keeps its state and never remounts. */
.grid-panel {
  display: flex;
  flex-direction: column;
  margin: 0 16px 12px;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}

.grid-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  padding: 7px 10px 7px 12px;
  background: var(--surface-muted);
  border-block-end: 1px solid var(--line);
}

.grid-toolbar-title {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-inline-size: 0;
  margin: 0;
  font-size: 13px;
  font-weight: 700;
}

.grid-hint {
  color: var(--text-subtle);
  font-size: 11.5px;
  font-weight: 400;
}

.grid-toolbar-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: none;
}

.grid-host {
  block-size: min(560px, 60vh);
  overflow: hidden;
}

/* Full screen is the same panel at viewport size - same chrome, same tokens, same
   grid instance - so nothing is relearned and no state is lost on the way in or out. */
.grid-panel--expanded {
  position: fixed;
  inset: 0;
  z-index: 200;
  margin: 0;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

.grid-panel--expanded .grid-toolbar {
  padding-inline: 16px;
}

/* The wrapper is the flex child that grows, not the host inside it. Targeting the host
   alone left it 27px tall behind a full-height panel: the toolbar rendered and the sheet
   did not, which reads as a broken viewer rather than a layout bug. */
.grid-panel--expanded .grid-host-wrap {
  display: flex;
  flex: 1 1 auto;
  min-block-size: 0;
}

.grid-panel--expanded .grid-host {
  block-size: auto;
  flex: 1 1 auto;
  min-block-size: 0;
}

body:has(.grid-panel--expanded) {
  overflow: hidden;
}

/* ---------------------------------------------------------------------------
   Job assistant

   Answers from the same APIs the operator can already read. It is docked rather
   than floating over the grid, because covering the numbers being discussed is
   the one thing it must not do.
   --------------------------------------------------------------------------- */

.assistant {
  position: fixed;
  inset-inline-end: 16px;
  inset-block-end: 16px;
  z-index: 90;
  display: flex;
  align-items: flex-end;
  flex-direction: column;
  gap: 8px;
}

.assistant-toggle {
  min-block-size: 38px;
  padding-inline: 14px;
  color: var(--surface);
  background: var(--accent);
  border: 1px solid var(--accent-pressed);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md);
  font-size: 13px;
  font-weight: 700;
  transition: background-color 120ms ease;
}

.assistant-toggle:hover {
  background: var(--accent-hover);
}

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

.assistant-panel {
  display: flex;
  flex-direction: column;
  inline-size: min(400px, calc(100vw - 32px));
  block-size: min(460px, 60vh);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  overflow: hidden;
}

.assistant-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 12px;
  border-block-end: 1px solid var(--line);
}

.assistant-head h2 {
  margin: 0;
  font-size: 14px;
  font-weight: 700;
}

.assistant-log {
  display: flex;
  flex-direction: column;
  gap: 10px;
  flex: 1 1 auto;
  padding: 12px;
  overflow-y: auto;
}

.assistant-message {
  max-inline-size: 90%;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  font-size: 13px;
  line-height: 1.45;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.assistant-message[data-role="user"] {
  align-self: flex-end;
  color: var(--surface);
  background: var(--accent-pressed);
}

.assistant-message[data-role="assistant"] {
  align-self: flex-start;
  background: var(--surface-muted);
  border: 1px solid var(--line);
}

.assistant-message[data-role="error"] {
  align-self: stretch;
  color: var(--danger);
  background: var(--surface);
  border: 1px solid var(--danger);
}

/* Tool activity is shown, not hidden: an answer's grounding is the point. */
.assistant-tool {
  align-self: flex-start;
  color: var(--text-subtle);
  font-family: var(--font-data);
  font-size: 11.5px;
}

.assistant-form {
  display: flex;
  gap: 8px;
  padding: 10px 12px;
  border-block-start: 1px solid var(--line);
}

.assistant-form input {
  min-inline-size: 0;
  flex: 1 1 auto;
}

.assistant-empty {
  color: var(--text-subtle);
  font-size: 12.5px;
}

@media (max-width: 820px) {
  .grid-host {
    block-size: min(420px, 55vh);
  }

  .assistant {
    inset-inline: 10px;
    inset-block-end: 10px;
  }

  .assistant-panel {
    inline-size: 100%;
  }
}

/* A saved correction changes nothing until the job is processed again, so the
   count says what is outstanding rather than implying the fix has landed. */
.edit-badge {
  margin: 0 16px 8px;
  padding: 8px 12px;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--warning);
  border-inline-start: 4px solid var(--warning);
  border-radius: var(--radius-sm);
  font-size: 13px;
  font-weight: 700;
}

.edit-list {
  display: flex;
  flex-direction: column;
  margin: 0 16px 12px;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}

.edit-list[hidden] {
  display: none;
}

.edit-list-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  padding: 9px 12px;
  border-block-end: 1px solid var(--line);
}

.edit-list-row:last-child {
  border-block-end: 0;
}
/* ---------------------------------------------------------------------------
   Modal

   Used only where an action needs to be finished or abandoned before anything
   else happens. Changing a password ends the session, so starting one and
   wandering off would leave the operator confused about whether it took effect.
   --------------------------------------------------------------------------- */

.modal {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: grid;
  place-items: center;
  padding: 20px;
  background: rgb(15 23 42 / 45%);
}

.modal-card {
  inline-size: min(420px, 100%);
  padding: 20px 22px 18px;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
}

.modal-card h2 {
  margin: 0 0 6px;
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.modal-copy {
  margin: 0 0 16px;
  color: var(--text-muted);
  font-size: 13px;
  line-height: 1.5;
}

.modal-form {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.modal-form label {
  margin-block-start: 8px;
  font-size: 12.5px;
  font-weight: 700;
}

.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-block-start: 18px;
}

/* A job card and its delete control sit side by side. The card stays a single large
   target; the delete is deliberately small and quiet, because it is the destructive
   one and should never be the easier thing to hit. */
.job-card-row {
  position: relative;
  display: flex;
  align-items: stretch;
}

.job-card-row .job-card {
  flex: 1 1 auto;
  min-inline-size: 0;
}

.job-card-delete {
  position: absolute;
  /* Bottom-right, level with the status line. Top-right sits on top of the job number,
     so hovering a card hid the one value that tells two attempts at a month apart. */
  inset-block-end: 8px;
  inset-inline-end: 8px;
  padding: 3px 8px;
  color: var(--text-subtle);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-xs);
  font-size: 11.5px;
  opacity: 0;
  transition: opacity 120ms ease, color 120ms ease;
}

.job-card-row:hover .job-card-delete,
.job-card-delete:focus-visible {
  opacity: 1;
}

.job-card-delete:hover {
  color: var(--danger);
  background: var(--surface);
  border-color: var(--danger);
}

.job-card-delete:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 1px;
}

/* Someone else's month. Stated once, near the controls it explains, rather than
   repeated on every disabled button. */
.read-only-notice {
  margin: 12px 16px 0;
  padding: 9px 12px;
  color: var(--text-muted);
  background: var(--surface-muted);
  border: 1px solid var(--line-strong);
  border-inline-start: 4px solid var(--accent-blue);
  border-radius: var(--radius-sm);
  font-size: 13px;
}

/* Months in the workbook list.
   A flat list of every job stops being scannable after a few weeks of use, and operators
   talk about the work by invoice month. The month being worked on is open; the rest fold
   away but stay one click from view. */
.job-month + .job-month {
  margin-block-start: 10px;
}

.job-month-heading {
  display: flex;
  align-items: center;
  gap: 8px;
  inline-size: 100%;
  padding: 6px 4px;
  text-align: start;
  color: var(--muted);
  background: none;
  border: 0;
  border-block-end: 1px solid var(--line);
  border-radius: 0;
  cursor: pointer;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.job-month-heading:hover,
.job-month-heading:focus-visible {
  color: var(--text);
}

.job-month-caret {
  flex: none;
  inline-size: 0.75em;
  font-size: 0.7rem;
  line-height: 1;
}

.job-month-name {
  flex: 1 1 auto;
  min-inline-size: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.job-month-count {
  flex: none;
  font-weight: 500;
  text-transform: none;
  letter-spacing: 0;
}

.job-month-body {
  display: grid;
  gap: 8px;
  margin-block-start: 8px;
}

/* Spreadsheet loading.
   The viewer bundle is a few megabytes and the sheet can be large, so opening Data can
   sit blank long enough to look broken. The bar reports the step it is genuinely on. */
.grid-host-wrap {
  position: relative;
}

/* The viewer paints its own canvas, which wins any stacking contest with an overlay.
   Hiding it while loading avoids that fight; visibility keeps the box, so the viewer can
   still measure itself and mount at the right size behind the progress panel. */
.grid-host-wrap.is-loading #gridHost {
  visibility: hidden;
}

/* Centred over the empty canvas rather than below the card, where a page-height grid
   pushes it out of view at exactly the moment it has something to say. */
.grid-loading {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: grid;
  align-content: center;
  justify-items: center;
  gap: 10px;
  padding: 14px 16px;
  background: #ffffff;
}

.grid-loading[hidden] {
  display: none;
}

.grid-loading-bar {
  inline-size: min(260px, 60vw);
  block-size: 6px;
  overflow: hidden;
  background: var(--line);
  border-radius: 999px;
}

#gridLoadingFill {
  display: block;
  inline-size: 0;
  block-size: 100%;
  background: var(--accent);
  border-radius: inherit;
  transition: inline-size 240ms ease-out;
}

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

.grid-loading-bar > span {
  display: block;
  block-size: 100%;
  inline-size: 0;
  background: var(--accent, #2f6feb);
  border-radius: inherit;
  transition: inline-size 240ms ease-out;
}

.grid-loading-step {
  margin: 0;
  color: var(--muted);
  font-size: 0.82rem;
}

@media (prefers-reduced-motion: reduce) {
  .grid-loading-bar > span {
    transition: none;
  }
}

/* The next action.
   The stage rail says which stage you are on but not which control that means. This
   marks the one button that moves the job forward, and explains it on hover. Never
   applied to a disabled control, and never while a run is in flight. */
.is-next-action {
  position: relative;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent, #2f6feb) 28%, transparent);
}

.is-next-action::after {
  content: "\25b2";
  position: absolute;
  inset-block-start: calc(100% + 2px);
  inset-inline-start: 50%;
  color: var(--accent, #2f6feb);
  font-size: 0.7rem;
  line-height: 1;
  pointer-events: none;
  translate: -50% 0;
  animation: next-action-nudge 1.6s ease-in-out infinite;
}

@keyframes next-action-nudge {
  0%, 100% { translate: -50% 0; opacity: 0.55; }
  50% { translate: -50% 3px; opacity: 1; }
}

/* The explanation, shown on hover and on keyboard focus. */
.is-next-action:hover::before,
.is-next-action:focus-visible::before {
  content: attr(data-next-action);
  position: absolute;
  inset-block-end: calc(100% + 10px);
  inset-inline-start: 50%;
  z-index: 5;
  inline-size: max-content;
  max-inline-size: 230px;
  padding: 7px 10px;
  color: #ffffff;
  font-size: 0.76rem;
  font-weight: 400;
  line-height: 1.35;
  text-align: start;
  white-space: normal;
  background: #1f2430;
  border-radius: var(--radius-sm);
  pointer-events: none;
  translate: -50% 0;
}

/* An animation nobody can switch off is a usability failure, not a flourish. */
@media (prefers-reduced-motion: reduce) {
  .is-next-action::after {
    animation: none;
    opacity: 1;
  }
}

/* Assistant data scope
   ------------------------------------------------------------------------- */

.sr-only {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.scope-set {
  display: grid;
  gap: 10px;
  margin: 0;
  padding: 0;
  border: 0;
}

.scope-option {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 10px;
  align-items: start;
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: border-color 120ms ease, background-color 120ms ease;
}

.scope-option:hover {
  border-color: var(--accent);
}

/* The chosen option carries the emphasis, so the current state is legible before
   reading either description. */
.scope-option:has(input:checked) {
  background: var(--surface-muted, #f6f8f7);
  border-color: var(--accent);
}

.scope-option:has(input:focus-visible) {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.scope-option > span {
  display: grid;
  gap: 3px;
}

.scope-copy {
  color: var(--muted);
  font-size: 0.84rem;
  line-height: 1.45;
}

.scope-meta {
  margin: 0;
  color: var(--muted);
  font-size: 0.8rem;
}

/* Assistant docked beside an expanded sheet
   -------------------------------------------------------------------------
   Full screen is where transforming a sheet actually happens, so there the
   assistant stops being a floating bubble over the data and becomes a column
   beside it. The grid gives up the width rather than being covered: a panel
   sitting on top of the rows you asked it to highlight defeats the point. */

body:has(.grid-panel--expanded) .assistant {
  inset-block: 0;
  inset-inline-end: 0;
  z-index: 210;
  justify-content: flex-end;
  padding: 0;
}

body:has(.grid-panel--expanded) .assistant-panel {
  inline-size: min(400px, 92vw);
  block-size: 100vh;
  border-radius: 0;
  border-block: 0;
  border-inline-end: 0;
  box-shadow: -8px 0 24px rgb(15 23 42 / 12%);
}

/* Docked, the panel has its own Close button, so the floating toggle is redundant and
   sat directly on top of the question field. It returns the moment the panel closes. */
body:has(.grid-panel--expanded):has(.assistant-panel:not([hidden])) .assistant-toggle {
  display: none;
}

/* The sheet yields the width the docked panel occupies. */
body:has(.grid-panel--expanded):has(.assistant-panel:not([hidden])) .grid-panel--expanded {
  inset-inline-end: min(400px, 92vw);
}

@media (prefers-reduced-motion: no-preference) {
  .assistant-panel {
    animation: assistant-slide-in 180ms ease-out;
  }
}

@keyframes assistant-slide-in {
  from {
    opacity: 0;
    transform: translateX(12px);
  }

  to {
    opacity: 1;
    transform: translateX(0);
  }
}

/* A note is the assistant reporting what it did to the sheet, not prose. */
.assistant-message[data-role="note"] {
  color: var(--text);
  background: var(--surface-muted);
  border-inline-start: 3px solid var(--accent);
}
