/* The page, set like ardana.ai's catalog: a heavy Onest title over a gray lede, then the state on the left in a
   terminal-gray box and the questions on the right as hairline rows, each answer an ink bar among gray ones with its
   exact figure in Geist Mono, then the raw exchange and the snippets, which open on the landing's arrow. */

.page {
  width: 100%;
  max-width: 1400px;
  margin: 0 auto;
  padding: var(--space-7) var(--gutter) 20vh;
  display: grid;
  gap: var(--space-8);
}

/* ---- Title ---- */

.page-title {
  display: grid;
  gap: 14px;
}

/* With enlarged text on the narrowest phones a word of the title is wider than the page: it breaks, hyphenated where
   the language allows, rather than widen the page. */
.page-heading {
  font-size: clamp(2rem, 3.2vw, 2.75rem);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.035em;
  overflow-wrap: anywhere;
  hyphens: auto;
}

.page-lede {
  max-width: 60ch;
  color: var(--muted);
  font-size: var(--text-17);
  line-height: 1.45;
  text-wrap: pretty;
}

/* ---- Columns: state left, questions right ---- */

.columns {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: var(--space-7);
  align-items: start;
}

/* A block head: a heading with something beside it. */
.block-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
  min-height: 28px;
}

.block-heading {
  font-size: var(--text-22);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.02em;
}

.block-heading label {
  cursor: text;
}

/* ---- State block ---- */

.state {
  display: grid;
  gap: var(--space-3);
  min-width: 0;
}

.state-meta {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* Code blocks: the state, the questions JSON, the wire panes and the snippet, all in the landing's command box. */
.code-block {
  display: block;
  width: 100%;
  border: 0;
  border-radius: var(--radius);
  background: var(--code-bg);
  color: var(--code-ink);
  font-family: var(--mono);
  font-size: var(--text-13);
  line-height: 1.6;
  tab-size: 2;
}

/* The two editors are boxes you type in: the field's 1px code-gray ring (controls.css). */
textarea.code-block {
  padding: var(--space-4) 18px;
  resize: vertical;
  box-shadow: inset 0 0 0 1px var(--code-muted);
  transition: box-shadow var(--fast) ease;
}

textarea.code-block::placeholder {
  color: var(--muted);
  opacity: 1;
}

textarea.code-block[aria-invalid="true"] {
  box-shadow: inset 0 0 0 1px var(--danger);
}

.state-text {
  min-height: clamp(280px, 52vh, 600px);
}

.state-text::placeholder {
  font-family: var(--font);
  font-size: var(--text-15);
}

.state-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-3);
  color: var(--muted);
  font-size: var(--text-13);
  line-height: 1.4;
}

.state-foot .fault-line {
  flex: 1 1 100%;
}

/* ---- Questions column ---- */

/* The questions column is the container its answer rows measure themselves against. */
.questions {
  display: grid;
  gap: var(--space-4);
  min-width: 0;
  container-type: inline-size;
}

/* The last run's line: model, latency, tokens, and the stale note. */
.last-run {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 6px;
  color: var(--muted);
  font-size: var(--text-13);
  line-height: 1.4;
}

.last-run [data-field="/model"] {
  color: var(--ink);
  font-family: var(--mono);
  font-size: var(--text-12);
  overflow-wrap: anywhere;
}

/* The questions, as the landing's catalog rows: a hairline above the list and under each row. */
.question-list {
  display: grid;
  border-top: 1px solid var(--line);
}

.question {
  display: grid;
  gap: 14px;
  padding: 26px 0;
  border-bottom: 1px solid var(--line);
}

/* The head: the id and the controls on one line (the controls drop under it when the row is narrow), then the
   instructions across the whole row. */
.question-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
}

.question-id {
  flex: 1 1 12rem;
  min-width: 0;
  font-size: var(--text-22);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.02em;
  overflow-wrap: anywhere;
}

.question-instructions {
  max-width: 65ch;
  color: var(--muted);
  font-size: var(--text-15);
  line-height: 1.45;
  overflow-wrap: anywhere;
}

.question-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
}

.question > .tag {
  justify-self: start;
}

/* ---- Rows: one per option, name, bar, exact figure. The answer is the one ink line; once a run has answered, the
   other options speak in the gray, the landing's second tone. ---- */

.bars {
  display: grid;
  gap: 4px;
}

/* A score level's fit figure sits tight under its own level, a clear gap before the next. */
.bars:has(.bar-fit) {
  gap: 10px;
}

.bar-row {
  display: grid;
  grid-template-columns: 16px minmax(6rem, 12rem) minmax(0, 1fr) auto;
  grid-template-areas: "mark name bar value";
  align-items: center;
  gap: 2px var(--space-3);
  min-height: 28px;
}

/* The answer's mark: an ink disc with a paper check, the landing's check glyph. */
.bar-mark {
  grid-area: mark;
  display: inline-grid;
  place-items: center;
  width: 16px;
  height: 16px;
  border-radius: var(--radius-pill);
  color: var(--on-accent);
  background: transparent;
}

.bar-row.lit .bar-mark {
  background: var(--accent);
}

.bar-mark .icon {
  width: 11px;
  height: 11px;
  stroke-width: 2.2;
  opacity: 0;
}

.bar-row.lit .bar-mark .icon {
  opacity: 1;
}

/* A noul row is a probability, not a pick: no mark. */
.bar-row.unmarked .bar-mark {
  visibility: hidden;
}

.bar-name {
  grid-area: name;
  min-width: 0;
  font-size: var(--text-15);
  line-height: 1.3;
  overflow-wrap: anywhere;
}

.bar-row.lit .bar-name {
  font-weight: 600;
}

.bar-row:not(.lit, .unmarked):has(.readout:not(.idle)) .bar-name,
.bar-row:not(.lit, .unmarked) .readout:not(.idle),
.bar-row:not(.lit, .unmarked) .bar-fit .fit {
  color: var(--muted);
}

.bar-note {
  display: block;
  color: var(--muted);
  font-size: var(--text-13);
  font-weight: 400;
}

/* The bar: a 6px pill on the hairline gray, the fill reaching the returned probability. */
.bar {
  grid-area: bar;
  height: 6px;
  border-radius: var(--radius-pill);
  background: var(--track);
  overflow: hidden;
}

/* The fill is as long as its track and slides in from the left until its rounded end stands at the level: the track
   clips it to its own pill, and only a transform moves, so a growing bar costs no layout. */
.bar-fill {
  display: block;
  height: 100%;
  border-radius: var(--radius-pill);
  background: var(--bar);
  transform: translateX(calc((var(--level, 0) - 1) * 100%));
  animation: bar-grow 600ms var(--ease-out);
}

/* The answer's bar is ink: the picked option, or a noul's probability, which is the whole answer. */
.bar-row.lit .bar-fill,
.bar-row.unmarked .bar-fill {
  background: var(--accent);
}

@keyframes bar-grow {
  from {
    transform: translateX(-100%);
  }
}

/* The exact figure, in the terminal's voice, tabular and right-aligned. */
.readout {
  grid-area: value;
  min-width: 4.5rem;
  text-align: right;
  color: var(--ink);
  font-family: var(--mono);
  font-size: var(--text-14);
  font-variant-numeric: tabular-nums;
}

.readout.idle {
  color: var(--muted);
}

.bar-row.lit .readout,
.bar-row.unmarked .readout:not(.idle) {
  font-weight: 600;
}

/* A score level's fit sits in its own figure's cell, under the figure, so it can only belong to that level. */
.bar-row:has(.bar-fit) {
  min-height: 44px;
}

.bar-row:has(.bar-fit) .readout {
  align-self: start;
}

.bar-fit {
  grid-area: value;
  align-self: end;
  justify-self: end;
  color: var(--muted);
  font-size: var(--text-12);
  line-height: 1.4;
}

.bar-fit .fit {
  color: var(--ink);
  font-family: var(--mono);
}

/* Stale: the answer came from other inputs. The figures stay; the ink of the answer goes gray. */
.question.stale .bar-row.lit .bar-fill,
.question.stale .bar-row.unmarked .bar-fill,
.question.stale .bar-row.lit .bar-mark {
  background: var(--bar);
}

.question.stale .readout {
  color: var(--muted);
}

/* ---- The facts under the bars: the landing's fact row, gray names over values ---- */

.properties {
  display: flex;
  flex-wrap: wrap;
  gap: 20px var(--space-8);
  padding-top: 6px;
}

.property {
  display: grid;
  align-content: start;
  gap: 4px;
  min-width: 0;
}

/* A fact's name breaks, hyphenated, only when enlarged text makes it wider than its column on the narrowest phones. */
.property dt {
  color: var(--muted);
  font-size: var(--text-13);
  line-height: 1.4;
  overflow-wrap: anywhere;
  hyphens: auto;
}

.property dd {
  font-size: var(--text-15);
  line-height: 1.4;
  overflow-wrap: anywhere;
}

.property .answer {
  font-weight: 600;
}

/* Every fact after the first opens its meaning leftwards, over the row, so the tooltip never runs off the page however
   the row wraps (the first fact sits at the column's start and opens rightwards). */
.property:nth-child(n + 2) .tip-start::after {
  left: auto;
  right: -6px;
}

.raw-answer {
  display: grid;
  gap: var(--space-2);
}

.raw-answer p {
  color: var(--muted);
  font-size: var(--text-13);
}

.raw-answer pre {
  padding: var(--space-3) 14px;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* ---- Callouts: the empty list, a row of its own; the fault, the one red box ---- */

.callout {
  display: grid;
  gap: 10px;
  padding: 18px 0;
  border-block: 1px solid var(--line);
  color: var(--muted);
}

.callout-row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
}

.callout-row .icon {
  margin-top: 3px;
}

.callout p {
  max-width: 60ch;
  line-height: 1.5;
}

.callout-danger {
  padding: var(--space-4) 18px;
  border: 0;
  border-radius: var(--radius);
  background: var(--danger-tint);
  color: var(--ink);
}

.callout-danger .callout-row > .icon,
.callout-danger .fault-title {
  color: var(--danger);
}

.fault-title {
  font-weight: 600;
}

.fault-issues {
  display: grid;
  gap: 6px;
}

.fault-issues li,
.callout-danger p {
  display: flex;
  flex-wrap: wrap;
  gap: 4px var(--space-3);
  align-items: baseline;
}

/* Specific enough to win over `code`. */
.callout .fault-loc {
  background: var(--danger-tint-2);
  color: var(--danger);
}

.fault-msg {
  color: var(--ink);
}

.fault-raw {
  padding: var(--space-3) 14px;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* A fault on its question: the message under the head, in the fault's colours. */
.question-fault {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-inner);
  background: var(--danger-tint);
  color: var(--ink);
  font-size: var(--text-14);
}

.question-fault .icon {
  margin-top: 2px;
  color: var(--danger);
}

/* "Add question" at the end of the list, as the landing's forward links read: ink, with its glyph. */
.add-row {
  justify-self: start;
  width: auto;
  padding: 0;
  color: var(--ink);
  font-weight: 500;
}

/* ---- Builder: the fields under a hairline inside the question row ---- */

.program-panel {
  display: grid;
  gap: var(--space-4);
  padding-top: 18px;
  border-top: 1px solid var(--line);
}

.criteria {
  display: grid;
  gap: var(--space-2);
}

.criteria-legend {
  color: var(--muted);
  font-size: var(--text-13);
  font-weight: 500;
}

.criteria-rows {
  display: grid;
  gap: var(--space-2);
}

.criteria-row {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 3fr) auto;
  align-items: center;
  gap: var(--space-2);
}

.level-row {
  grid-template-columns: 1.5rem minmax(0, 1fr) auto;
}

.level-number {
  color: var(--muted);
  font-family: var(--mono);
  font-size: var(--text-13);
  text-align: center;
}

.criteria-error {
  grid-column: 1 / -1;
}

.criteria-foot,
.program-foot {
  display: flex;
  justify-content: flex-start;
}

.criteria-foot .button {
  margin-left: -8px;
}

.program-foot {
  justify-content: flex-end;
}


/* ---- Questions JSON ---- */

.program {
  display: grid;
  gap: var(--space-2);
}

.program-text {
  min-height: 200px;
}

/* ---- Toggle blocks: the raw exchange and the snippets, opened on the landing's arrow ---- */

.toggle {
  display: grid;
  gap: var(--space-4);
  min-width: 0;
}

.toggle > summary {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px var(--space-3);
  width: fit-content;
  list-style: none;
  cursor: pointer;
  border-radius: 3px;
}

.toggle > summary::-webkit-details-marker {
  display: none;
}

.toggle-marker {
  display: inline-grid;
  place-items: center;
  align-self: center;
  width: 20px;
  height: 20px;
  color: var(--muted);
  transition:
    transform var(--normal) var(--ease-out),
    color var(--fast) ease;
}

.toggle > summary:hover .toggle-marker {
  color: var(--ink);
}

.toggle[open] > summary .toggle-marker {
  transform: rotate(90deg);
}

.toggle-heading {
  font-size: var(--text-22);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.02em;
}

.toggle-caption {
  color: var(--muted);
  font-size: var(--text-15);
  font-weight: 400;
}

/* The block's content sits in one box of its own (a `details` element's), so the grid's gap stops above it: the
   language row keeps the same 16px from the snippet. */
.toggle-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-3);
  margin-bottom: var(--space-4);
}

/* Wire panes: the sent and received bodies, side by side. */
.exchange-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-5);
}

.exchange-side {
  display: grid;
  align-content: start;
  gap: 10px;
  min-width: 0;
}

.exchange-side h3 {
  color: var(--muted);
  font-size: var(--text-13);
  font-weight: 500;
  line-height: 1.4;
}

.wire {
  padding: var(--space-4) 18px;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* An empty pane is a sentence, not a box: the terminal gray waits for bytes to copy. */
.wire-empty {
  color: var(--muted);
  font-size: var(--text-15);
  line-height: 1.45;
}

/* The snippet: one command box, its copy key in the corner as on the landing. */
.snippet-box {
  position: relative;
  min-width: 0;
}

.snippet-box > .copy {
  position: absolute;
  top: 6px;
  right: 6px;
}

.snippet {
  padding-right: 56px;
}

/* The curl snippet, the ardana commands and the install line are shell lines: the landing's gray prompt in front of
   each, drawn but never copied or read out. */
.snippet[data-language="curl"]::before,
.snippet[data-language="ardana"]::before,
.command-row > code::before {
  content: "$ " / "";
  color: var(--code-muted);
  user-select: none;
}

/* ---- The ardana CLI: the request for a model this server does not run, after `ardana pull` or the install line ---- */

.cli {
  display: grid;
  gap: var(--space-5);
  min-width: 0;
}

.cli-lede {
  max-width: 65ch;
  color: var(--muted);
  font-size: var(--text-15);
  line-height: 1.45;
}

/* A step: its label over its command box, a note under it. */
.cli-step {
  display: grid;
  gap: 6px;
  min-width: 0;
}

.cli-step .field-note {
  overflow-wrap: anywhere;
}

/* The Windows line moves under its words whole when it fits there, rather than splitting its gray ground. */
.cli-step .field-note code {
  display: inline-block;
  max-width: 100%;
}

/* `ardana pull` and the install line: the landing's small command box (as `ardana pull` sits on ardana.ai), its copy
   key at the end. */
.command-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 40px;
  padding: 0 4px 0 14px;
  border-radius: var(--radius);
  background: var(--code-bg);
  color: var(--code-ink);
}

.command-row > code {
  flex: 1;
  min-width: 0;
  padding: 10px 0;
  border-radius: 0;
  background: transparent;
  font-size: var(--text-13);
  line-height: 1.45;
  overflow-wrap: anywhere;
}

/* ---- Responsive ---- */

/* A questions column narrower than 30rem (a phone, or a small laptop beside the sidebar) gives each bar its own line
   under the option's name and figure, so the bar keeps a readable length. */
@container (max-width: 30rem) {
  .bar-row {
    grid-template-columns: 16px minmax(0, 1fr) auto;
    grid-template-areas:
      "mark name value"
      ". bar bar";
    gap: 4px 10px;
  }

  /* Room for a level's figure and its fit, one over the other, even when the level has no legend. */
  .bar-row:has(.bar-fit) {
    grid-template-rows: minmax(40px, auto) auto;
  }
}

@media (max-width: 960px) {
  .columns {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-7);
  }

  /* The questions column starts at the page's edge here and runs wide: facts open rightwards, the fifth on leftwards
     (`:nth-child(n)` matches every fact, at the specificity of the wide-screen rule it overrides). */
  .property:nth-child(n) .tip-start::after {
    left: -6px;
    right: auto;
  }

  .property:nth-child(n + 5) .tip-start::after {
    left: auto;
    right: -6px;
  }

  .state-text {
    min-height: 220px;
  }
}

@media (max-width: 720px) {
  .page {
    padding: var(--space-5) var(--gutter) 20vh;
    gap: var(--space-7);
  }

  .page-heading {
    font-size: 1.875rem;
  }

  .page-lede {
    font-size: var(--text-15);
  }

  .block-heading,
  .toggle-heading,
  .question-id {
    font-size: 1.25rem;
  }

  .question-controls {
    justify-content: flex-start;
  }

  .properties {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-4) var(--space-5);
  }

  .property:nth-child(odd) .tip-start::after {
    left: -6px;
    right: auto;
  }

  .property:nth-child(even) .tip-start::after {
    left: auto;
    right: -6px;
  }

  .criteria-row {
    grid-template-columns: minmax(0, 1fr) auto;
  }

  .criteria-row > .field-input:nth-of-type(2) {
    grid-column: 1 / -1;
    grid-row: 2;
  }

  .level-row {
    grid-template-columns: 1.5rem minmax(0, 1fr) auto;
  }

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

/* Under a coarse pointer a toggle block's heading reaches 44px tall past its words (WCAG 2.5.5; see controls.css), and
   what sits under a small control leaves room for both reaches: 24px under a heading, 16px between the parts of a
   question's criteria. */
@media (pointer: coarse) {
  .toggle {
    gap: var(--space-5);
  }

  .toggle > summary {
    position: relative;
  }

  .toggle > summary::before {
    content: "";
    position: absolute;
    inset: min(0px, (100% - 44px) / 2);
  }

  .criteria {
    gap: var(--space-4);
  }
}

@media (prefers-reduced-motion: reduce) {
  .bar-fill {
    animation: none;
  }

  .toggle-marker,
  textarea.code-block {
    transition: none;
  }
}

@media (forced-colors: active) {
  .callout-danger,
  .code-block,
  .command-row,
  .question-fault {
    border: 1px solid CanvasText;
  }

  .bar {
    border: 1px solid CanvasText;
  }

  .bar-fill {
    forced-color-adjust: none;
    background: GrayText;
  }

  .bar-row.lit .bar-fill {
    background: Highlight;
  }

  .bar-row.lit .bar-mark {
    forced-color-adjust: none;
    background: Highlight;
    color: HighlightText;
  }
}
