/* ═══════════════════════════════════════════════════════════
 * 07 · Estimate figures
 *
 * A file of its own rather than an addition to 05_features.css, which another
 * stream owns. Propshaft's `stylesheet_link_tag :app` picks up every file in
 * this directory in alphabetical order, so 07 lands after 05 and needs no
 * registration.
 *
 * Only tokens from 01_tokens.css. There are no colour literals anywhere
 * outside that file and this one does not start a second place for them.
 * ═══════════════════════════════════════════════════════════ */

/* The estimate table's section rows carry the section title in a single `th`
 * plus six empty cells, instead of one cell spanning the table. See the note
 * in projects/_estimate_breakdown.html.erb: a spanning cell is one element in
 * every column of axe's grid, and it hands the header list it resolved for the
 * first column back to all the others, which is the th-has-data-cells finding
 * this shape fixes.
 *
 * That leaves the six fillers to be dressed, or the band reads as one styled
 * cell followed by six body cells: the fill and the rule above the section
 * would both stop after the title. Three declarations, taken from
 * `.estimate-table__section th` in 05_features.css, and no more - the eyebrow
 * treatment stays on the `th`, which is the only cell holding text.
 *
 * No padding here on purpose. `.estimate-table tbody td` already gives these
 * the same 16px it gives the `th` beside them - it outweighs the section rule
 * there, which is pre-existing and not this file's business - so setting the
 * section padding on the fillers alone would be the one declaration that made
 * the row disagree with itself.
 *
 * `.estimate-table tbody` is in the selector for weight rather than matching,
 * the same trick and the same reason as the chain row's rule. */
.estimate-table tbody .estimate-table__section td {
  border-top: 1px solid var(--border-default);
  border-bottom: 1px solid var(--border-default);
  background: var(--bg-canvas);
}

/* Matches the `th` rule beside it: the first section opens the table body and
 * has the thead's own bottom border above it already. */
.estimate-table tbody .estimate-table__section:first-child td {
  border-top: 0;
}

/* The band is the headline figure in the KPI tiles now, and a band is two
 * numbers and a dash where there used to be one number - "US$ 2,733 – US$
 * 4,099" against "US$ 3,416". At the tile's own type size that wraps, which is
 * fine and expected; these two declarations only keep it legible when it does.
 *
 * Tabular figures so the low and the high line up on their digits, and a
 * balanced wrap so a band that breaks over two lines breaks near the middle
 * rather than leaving one number stranded on a line of its own. */
.scenario-kpi__value[data-scenario-figure="price-band"],
.scenario-kpi__value[data-scenario-figure="billable-band"] {
  font-variant-numeric: tabular-nums;
  text-wrap: balance;
}

/* The elapsed clock under the generating copy. Laid out as a row so the label
 * and the figure sit on one line, and the figure is tabular so the tile does
 * not shift sideways every time the seconds tick over from 9 to 10. */
.estimate-elapsed {
  display: flex;
  gap: var(--space-2);
  align-items: baseline;
  margin: 0;
}

.estimate-elapsed span {
  font-variant-numeric: tabular-nums;
}

/* The run-to-run variance sentence above the comparison table. Constrained
 * rather than full width: the table beside it is twelve columns wide and a
 * sentence measured against that is a sentence nobody finishes. */
.scenario-comparison__variance {
  max-width: 68ch;
  margin: 0 0 var(--space-3);
}

/* ═══════════════════════════════════════════════════════════
 * The result
 *
 * The thesis of this whole review in one block: the product was printing its
 * answer with the same visual weight as its decoration. `Total: entre 208.8 y
 * 313.2 h · punto medio 261 h · 43.5 puntos ajustados` rendered as one running
 * 16px sentence at weight 400 in the secondary colour, inside the metadata
 * strip, to the right of "Generada hace alrededor de 2 horas" - underneath a
 * 48px <h1> reading "Estimación del proyecto", which informs nobody of
 * anything. The reader's eye went to the label and had to hunt for the answer.
 *
 * The fix is not volume, it is range. Three steps now separate the answer from
 * its qualifiers - size (h1-scale against body-sm), weight (700 against 400)
 * and colour (primary against tertiary) - where before there were none at all.
 * Both estimate modes render this same block, so a reader learns to find the
 * figure once.
 * ═══════════════════════════════════════════════════════════ */

.estimate-result {
  display: grid;
  gap: var(--space-1);
  margin: 0;
}

/* The one place in the product that spends --weight-strong. The Bold face has
 * been downloaded on every page load since the font was installed and applied
 * to nothing: before this rule, the only 700 in the stylesheet directory was
 * its own @font-face. If a second figure on a screen ever takes this weight,
 * neither of them is the answer any more.
 *
 * clamp() rather than a fixed --text-h1, because the content is a band and not
 * a word: "208,8 – 313,2 h" is fifteen glyphs of tabular figures, and at a
 * flat 48px it wraps on a phone into two lines that each look like a separate
 * number. The floor is --text-h2 (30px), which still clears the <h1> below it,
 * and the ceiling is --text-h1.
 *
 * PROPORTIONAL figures, deliberately, where this rule used to ask for tabular.
 * PP Neue Montreal's tabular set is 25% wider than its proportional one -
 * measured in the browser, `208,8 – 313,2 h` at 48px/700 renders 391,0px
 * tabular against 313,5px proportional - because every digit is padded out to
 * the width of the widest. The `1` is the worst of them: it sits alone in the
 * middle of its slot, and the app's loudest figure read `2 0 8,8 – 3 1 3,2 h`.
 *
 * The two reasons this rule gave for tabular were both checked against this
 * block and neither holds here. Aligning the low and the high digit for digit
 * needs them stacked in a column; they are side by side on one line, split by
 * a dash. And holding the width steady under a Turbo poll matters to a box of
 * fixed width; this is a grid cell, and two bands differ by a few proportional
 * pixels that reflow nothing around them.
 *
 * Tabular figures are therefore reserved for COLUMNS - the numeric cells of
 * the estimate tables in 05_features.css - where the digits really do stack
 * and the extra width buys the alignment it costs. */
.estimate-result__range {
  margin: 0;
  color: var(--text-primary);
  font-size: clamp(var(--text-h2), 4.5vw, var(--text-h1));
  font-weight: var(--weight-strong);
  line-height: var(--leading-heading);
  letter-spacing: var(--tracking-tight);
  font-variant-numeric: normal;
}

/* Everything that qualifies the band rather than being it. Small and tertiary:
 * on dark that is a genuine third colour step (5.7:1, still AA for small text),
 * on light it resolves to the secondary grey and the separation is carried by
 * size and weight alone - see the --text-tertiary note in 01_tokens.css.
 *
 * A flex row rather than three stacked lines: the midpoint and the points are
 * two short fragments and stacking them would rebuild, one tier down, the
 * ragged list this block exists to replace. */
.estimate-result__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-6);
  max-width: var(--measure);
  margin: 0;
  color: var(--text-tertiary);
  font-size: var(--text-body-sm);
  line-height: var(--leading-body);
}

/* No tabular rule here either, for the reason given on __range above: this
 * line is a wrapping row of short fragments - "punto medio 261 h", "43,5
 * puntos ajustados" - and not one column of figures under another, so the 25%
 * that PP Neue Montreal's tabular set costs buys nothing and spaces out every
 * `1` in the line. The exception below, which had to turn tabular back off for
 * the closing sentence, is gone with it. */

/* The caveat is the last child and it is a sentence, not a fragment. Forcing
 * its own line keeps it from reading as a third figure beside the two that are
 * figures, and costs nothing when the row has already wrapped. */
.estimate-result__meta > :last-child {
  flex-basis: 100%;
}

/* The <h1> comes DOWN rather than the figure being asked to beat it at 48px.
 * "Estimación del proyecto" is the largest thing on the screen and says the
 * least on it: it repeats the breadcrumb directly above it and the browser tab
 * above that. It is still the page's first heading and still the biggest text
 * in the states where no figure exists - a failed estimate prints
 * failed_title here, and an in-flight one prints title with only the
 * generating copy and the elapsed clock beneath it - so it keeps a heading's
 * size, just not the headline's. */
.estimate-card > .section-heading-row h1 {
  font-size: var(--text-h2);
}

/* ── Ballpark facts ─────────────────────────────────────────
 * The four qualifiers that are left after the range is lifted out. One
 * bordered group with dividers instead of four loose paragraphs, so they read
 * as a set of facts about the figure above rather than as four more
 * sentences competing with it. Same grey as the deep estimate's __meta, for
 * the same reason: these qualify the answer, they are not the answer. */
.ballpark-facts {
  display: grid;
  max-width: var(--measure);
  margin: var(--space-4) 0 var(--space-3);
  padding: 0;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sm);
  background: var(--bg-surface);
  color: var(--text-secondary);
  font-size: var(--text-body-sm);
}

/* Term column, then value column, with every value on one edge. The term
 * column is sized to the longer of the two terms rather than to a fraction,
 * so a translation that runs longer than "Calendario" widens the column
 * instead of wrapping inside it. */
.ballpark-facts__row {
  display: grid;
  grid-template-columns: minmax(6rem, max-content) 1fr;
  gap: var(--space-1) var(--space-4);
  padding: var(--space-2) var(--space-4);
}

.ballpark-facts__row + .ballpark-facts__row {
  border-top: 1px solid var(--border-default);
}

.ballpark-facts dt {
  color: var(--text-tertiary);
}

/* The value reads as the answer to its term. All four rows are complete pairs,
 * so this is every value in the group. */
.ballpark-facts dd {
  margin: 0;
  color: var(--text-primary);
  font-weight: var(--weight-medium);
  font-variant-numeric: tabular-nums;
}

/* Below the tablet breakpoint the two columns have nowhere to go: "Calendario"
 * and "8 a 14 días hábiles" would each get about half of a 300px row. Stack
 * them, and let the divider keep the rows apart. */
@media (max-width: 640px) {
  .ballpark-facts__row {
    grid-template-columns: 1fr;
  }
}

/* The value inside a figure sentence, marked by
 * EstimateFiguresHelper#figure_sentence. The row is a label and a value even
 * where the locale wrote them as one sentence, so the value carries the text
 * colour and the words around it stay secondary - the same label/value
 * relation the rest of the product uses, reached without splitting a frozen
 * translation. Deliberately not bold: --weight-strong belongs to the one
 * figure the screen exists to report, which is the band above these rows. */
.figure-value {
  color: var(--text-primary);
  font-weight: var(--weight-medium);
}

/* The aggregate risk score joins __meta through this same class and adds no
 * rule of its own, which is the point: the score is decoration of the band,
 * not the band, so it takes the label/value treatment the other qualifiers
 * already have and none of the three steps - size, weight, colour - that
 * separate the answer from them. No tabular rule either, for the reason given
 * on __meta above: `1,43` is one short fragment in a wrapping row, not a
 * column of figures under another, and PP Neue Montreal's tabular set would
 * only space out its `1`. */

/* ── Delivery: two projections, not two scenarios ───────────
 * The panel showed "Equipo humano · 3 flujos en paralelo · entre 108 y 162 h"
 * and "Con agentes · 6 flujos en paralelo · entre 96 y 144 h" as two cards of
 * equal weight, side by side. Two equal cards is the shape of a choice, and
 * this is not one: neither card is selectable, nothing on either says what
 * "Con agentes" means, and the Escenarios tab next door genuinely does offer
 * four scenarios under four other names - so the reader arrives at that tab
 * looking for these two and finds neither.
 *
 * They are one scenario projected against two teams. ProjectEstimates::Delivery
 * runs [Team::HUMAN, Team::AGENT_ASSISTED] over the same figures and the same
 * schedule; the second differs only in that Team multiplies the same head count
 * by the agents_per_dev supervision ratio, so the same work lands on more
 * streams. So: one bordered group, one divider, two rows - the shape of a
 * comparison of one thing, not of two things. delivery_axis_note says the rest
 * in words, above the group.
 *
 * These selectors restate .estimate-delivery__scenarios and __scenario, which
 * are declared in 05_features.css and belong to another stream. Nothing there
 * is edited: 07 loads after 05 and wins on the cascade, which is the same
 * override route the contract gives 06_curation.css. */
.estimate-delivery__scenarios {
  grid-template-columns: 1fr;
  gap: 0;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sm);
  background: var(--bg-surface);
}

.estimate-delivery__scenario {
  grid-template-columns: minmax(8rem, auto) minmax(8rem, 1fr) auto;
  align-items: baseline;
  gap: var(--space-1) var(--space-4);
  padding: var(--space-3) var(--space-4);
  border: 0;
  border-radius: 0;
  background: transparent;
}

.estimate-delivery__scenario + .estimate-delivery__scenario {
  border-top: 1px solid var(--border-default);
}

/* The figures are the only column a reader scans downward, so they end on a
 * common edge instead of starting on a ragged one. */
.estimate-delivery__scenarios .estimate-delivery__hours {
  text-align: right;
}

/* Below the tablet breakpoint the three columns have nowhere to go: the team
 * name and the band would each get about 100px and both would wrap. Stack
 * them, and let the divider keep the two rows apart. */
@media (max-width: 640px) {
  .estimate-delivery__scenario {
    grid-template-columns: 1fr;
  }

  .estimate-delivery__scenarios .estimate-delivery__hours {
    text-align: left;
  }
}

/* ── The prose lists ────────────────────────────────────────
 * The measured line length on these screens ran to 178 characters, and these
 * three lists are where most of that was: a risk, an open question or an
 * assumption is a full sentence of model output, set across the whole
 * 1,100px content column. --measure caps them at the reading width the
 * utilities in 02_base.css already use for paragraphs.
 *
 * On the <li> rather than on the list, so the bullet keeps its own indent and
 * the cap measures the text - a max-width on the <ul> would move the marker
 * column instead.
 *
 * These are prose lists only. The breakdown table, the roadmap and the
 * scenario grids are laid out to their content and are deliberately not
 * reached from here; see the --measure note in 01_tokens.css. */
.estimate-notes ul li,
.ballpark-list li,
.estimate-delivery__assumptions li {
  max-width: var(--measure);
}

/* The confirmation before a detailed estimate from the estimate's own page
 * (project_estimates/_deep_generate_button). Dressed like the conversation
 * header's one (.thread-estimate-dialog): a native modal <dialog> in the top
 * layer with the .app-modal overlay pair, width, radius and scrim. */
.estimate-confirm {
  display: contents;
}

.estimate-confirm-dialog {
  width: min(calc(100vw - 2 * var(--space-4)), var(--alert-dialog-w));
  max-height: min(90vh, 46rem);
  padding: var(--space-6);
  border: 1px solid var(--border-overlay);
  border-radius: var(--radius-sm);
  background: var(--bg-overlay);
  color: var(--text-primary);
  box-shadow: var(--shadow-dialog);
}

.estimate-confirm-dialog::backdrop {
  background: var(--scrim);
}

.estimate-confirm-dialog h2 {
  margin: 0;
  font-size: var(--text-h4);
}

.estimate-confirm-dialog p {
  margin: 0;
}
