/* ============================================================
 * Base — reset, elements, type scale, a11y utilities
 * ============================================================ */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

html,
body {
  margin: 0;
  min-height: 100%;
  background: var(--bg-canvas);
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: var(--text-body);
  font-weight: var(--weight-book);
  line-height: var(--leading-body);
  letter-spacing: var(--tracking-normal);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

/* ── Headings ───────────────────────────────────────────────
 * design.md sets every heading to Book (400). Headings read as
 * large-and-light, never bold; hierarchy comes from size. */

h1,
h2,
h3,
h4,
h5,
h6 {
  margin: 0;
  font-weight: var(--weight-book);
  color: var(--text-primary);
}

h1 {
  font-size: var(--text-h1);
  line-height: var(--leading-heading);
  letter-spacing: var(--tracking-tight);
}

h2 {
  font-size: var(--text-h2);
  line-height: var(--leading-heading);
  letter-spacing: var(--tracking-tight);
}

h3 {
  font-size: var(--text-h3);
  line-height: var(--leading-snug);
}

h4,
h5,
h6 {
  font-size: var(--text-h4);
  line-height: var(--leading-snug);
}

p {
  margin: 0;
}

/* ── Links ──────────────────────────────────────────────────
 * Underline on hover, colour unchanged. */

a {
  color: var(--link-color);
  text-decoration: none;
  transition: color var(--motion-fast) var(--ease-out);
}

a:hover {
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* A link INSIDE running prose is underlined at rest, which the rule above
 * deliberately does not do for links in general.
 *
 * The general rule is right for this product: most links here are not in prose
 * at all - they are sidebar rows, breadcrumb steps, tabs, a whole table row, or
 * an <a> wearing .button - and underlining those would be noise on controls
 * that already read as controls. But a link sitting mid-sentence has no shape
 * of its own, so colour is the only thing marking it, and colour alone fails
 * WCAG 1.4.1: anybody reading in greyscale, or who cannot separate this blue
 * from the text beside it, has no way to know the word is a link at all.
 * Measured: axe reported `link-in-text-block` (serious) on the one such link
 * the app has today, #deep-estimate-locked-reason > a on a project with no
 * approved context.
 *
 * Scoped to prose containers by name rather than to `p a`, because a <p> in
 * this codebase is as often a layout row holding a badge or a button as it is a
 * sentence - `.estimate-status`, `.badge`, and the panel's action rows are all
 * paragraphs. Naming the three prose classes keeps the rule where sentences
 * actually are, and .button is excluded because an <a> that has been made into
 * a button is a control and not a word.
 *
 * Hover keeps its own underline from the rule above; what changes here is the
 * resting state. */
.muted-text a:not(.button),
.project-context-markdown a:not(.button),
.message-card__markdown a:not(.button) {
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* ── Rich-text content ──────────────────────────────────── */

strong,
b {
  font-weight: var(--weight-medium);
}

code,
kbd,
samp,
pre {
  font-family: var(--font-mono);
  font-size: 0.9em;
}

hr {
  height: 1px;
  margin: 0;
  border: 0;
  background: var(--border-default);
}

ul,
ol {
  margin: 0;
  padding-left: var(--space-5);
}

table {
  border-collapse: collapse;
}

/* Turbo's custom elements are inline by default, which breaks any
 * grid or flex layout that treats them as the item wrapper. */
turbo-frame {
  display: block;
}

/* ── Type utilities ─────────────────────────────────────── */

.text-body-sm {
  font-size: var(--text-body-sm);
  line-height: var(--leading-body);
}

.caption {
  font-size: var(--text-caption);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-caption);
  color: var(--text-secondary);
}

/* The single eyebrow in the system: 13px Medium in the secondary
 * colour, 4% tracking. Every previous variant
 * (.app-sidebar__section-label, .message-card__role,
 * .resource-row__hint, …) resolves here.
 *
 * No longer ALL-CAPS, and not because caps are wrong for an
 * eyebrow. The class is shared, so it has to serve its longest
 * caller, and its longest caller is a sentence: "No queda nada por
 * revisar" is 25 characters, past the ~20 where caps stop reading
 * as a label and start costing the word shapes that make a line
 * scannable. Caps also priced the sidebar's own label out of its
 * box - CONVERSACIONES measures 132px of a 119px column at 8%
 * tracking, and the sidebar rule ellipsised it - and the tracking
 * is not enough to blame on its own: at 0% it measures exactly
 * 119px, a fit with nothing left for a longer translation.
 *
 * line-height: 1 was the second, quieter half of it: 13px of
 * leading for a 14px glyph box left every eyebrow in the app 1px
 * taller than the box it was given. --leading-snug holds them.
 *
 * Size, weight and colour still separate it from body text, and 4%
 * tracking still reads as a label. */
.eyebrow {
  margin: 0;
  font-size: var(--text-eyebrow);
  font-weight: var(--weight-medium);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-caption);
  color: var(--text-secondary);
}

/* ── Reading measure ────────────────────────────────────────
 * The estimate surfaces were measured at 100 to 178 characters a
 * line across thirteen screens, against the 45-75 that keeps a line
 * findable from the end of the one above it. --measure (65ch) fixes
 * that, and it is applied BY NAME to the prose utilities rather than
 * to `p` or to a container.
 *
 * `p` was the tempting rule and it is the wrong one. A paragraph in
 * this app is not always prose: .estimate-meta is a flex row of four
 * `p`s, the roadmap prints figures in them, and a capped one inside a
 * grid cell stops filling its column. Tables, the roadmap and code
 * blocks are all laid out to their content - a max-width there either
 * clips them or starts a horizontal scroll - so none of them is
 * reached from here.
 *
 * .muted-text and .empty-state are the two utilities that only ever
 * carry sentences, so they are the two that take the cap. On an
 * inline `span.muted-text` - the delivery rows use several - a
 * max-width is inert, which is the correct outcome and not a
 * coincidence worth working around. */

.muted-text {
  max-width: var(--measure);
  margin: 0;
  color: var(--text-secondary);
}

.empty-state {
  max-width: var(--measure);
  margin: 0;
  color: var(--text-secondary);
}

.numeric {
  font-variant-numeric: tabular-nums;
}

/* ── Focus ──────────────────────────────────────────────────
 * Visible on every interactive element, including a and summary,
 * which the previous stylesheet excluded. primary-500 is 4.5:1 on
 * the surface and 4.3:1 on the canvas, clearing the 3:1 that
 * WCAG 1.4.11 asks of a focus indicator. */

:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
  border-radius: var(--radius-xs);
}

/* ── A11y utilities ─────────────────────────────────────── */

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  top: -4rem;
  left: var(--space-4);
  z-index: 200;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-xs);
  background: var(--primary-700);
  color: var(--text-on-primary);
  font-size: var(--text-body-sm);
  transition: top var(--motion-base) var(--ease-out);
}

.skip-link:focus {
  top: var(--space-3);
  text-decoration: none;
}
