/* RepseShield — the stylesheet. "El expediente es el escudo."

   One design, on paper, for every surface: the app behind the login, the
   public guides and tools, the founders' wiki, the error sheet. Kit "Grana y
   Oro" (approved 2026-08-17): Cal de Papel ground, Tinta Ferrogálica text,
   Grana Cochinilla as the one accent per view, Vino Profundo as the one dark
   surface (the wine bars), flat Oro only ever inside the mark. EB Garamond
   for display and legal italic, Archivo for UI; both self-hosted (SIL OFL).

   Light only, by decision (Austin, 2026-08-29): the product is a printed
   instrument, and an instrument has one face. There is no dark theme, no
   theme-aware token, and `color-scheme: light` pins the native controls too.
   Semáforo colours are STATUS colours owned by the compliance semáforo and
   are never decoration.

   Contents
     1. Fonts
     2. Tokens
     3. Base — document, columns, type scale, lists, rules, quotes, code
     4. Signatures — kicker, shield title, legal citation, file glyph, seal
     5. Wine chrome — lockup, app header, tabs, session, section nav,
        public masthead, hero, CTA band, footers
     6. Surfaces — card, zero state, semáforo rails, sunken/folder/instrument
     7. Controls — fields, form grid, buttons, disclosures, switcher,
        dropzone, notices
     8. Records — roster tables and variants, record facts, postings, filed
        documents, row actions, phone stacking
     9. Status — pills, chips, period picker, view tabs, progress
    10. Screens — dashboard, materiality, review queue, contracts, access
        request, verify + diagnóstico, guide library, wiki, problem sheet,
        document viewer, telegram, obra (SIROC) capture, provider tablero
    11. Print
*/

/* ═══ 1. Fonts ═══════════════════════════════════════════════════════════ */

@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url("/static/fonts/archivo-latin-variable.woff2") format("woff2");
}

@font-face {
  font-family: "EB Garamond";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("/static/fonts/ebgaramond-latin-variable.woff2") format("woff2");
}

@font-face {
  font-family: "EB Garamond";
  font-style: italic;
  font-weight: 400 800;
  font-display: swap;
  src: url("/static/fonts/ebgaramond-italic-latin-variable.woff2") format("woff2");
}

/* ═══ 2. Tokens ══════════════════════════════════════════════════════════ */

:root {
  color-scheme: light;

  /* Papel / Tinta neutrals: warm, never pure gray. */
  --page: #f2eee6;
  --surface: #fbf9f4;
  --surface-sunken: #eae4d8;
  --ink: #241d22;
  --muted: #6d6058;
  --line: #dbd3c4;
  --line-soft: #e8e2d6;   /* row separators inside a table sit lighter than a panel edge */
  --field: #eae4d8;
  --hover: rgba(110, 42, 80, 0.05);

  /* Brand. */
  --vino-profundo: #361027;   /* the one dark surface: every wine bar */
  --grana: #6e2a50;           /* the accent, one per view; also links, buttons, focus */
  --grana-tint: rgba(110, 42, 80, 0.06);
  --oro-marca: #c9993c;       /* flat gold: lives ONLY inside the mark */
  --interactive: var(--grana);
  --primary: var(--grana);
  --primary-ink: #f2eee6;
  --focus-ring: var(--grana);

  /* Ink on the wine bars. Stated as tokens so no element on a bar ever
     inherits a colour meant for paper (the wordmark once rendered at 1:1
     contrast that way). */
  --papel-on-wine: #f2eee6;
  --papel-on-wine-soft: #d9c9d2;
  --papel-on-wine-dim: rgba(242, 238, 230, 0.72);
  --wine-rule: rgba(242, 238, 230, 0.22);
  --wine-control: rgba(242, 238, 230, 0.1);
  --wine-control-edge: rgba(242, 238, 230, 0.24);
  --oro-on-wine: #d8ae55;

  /* Semáforo (status only). */
  --ok: #3d6b4c;
  --ok-bg: #e3eade;
  --warn: #8a5a14;
  --warn-bg: #f1e7d2;
  --bad: #a83a24;
  --bad-bg: #f3e1da;

  /* Shape. Two radii: controls and chips take --radius, anything panel-sized
     takes --radius-panel. */
  --radius: 4px;
  --radius-panel: 6px;
  --shadow: 0 1px 2px rgba(36, 29, 34, 0.05);

  /* Columns. The app page, the wine bars and the section nav all share one
     measure so the lockup, the tabs and the page title sit on one left edge;
     prose (guides, wiki) reads at a book measure inside it. */
  --measure: 60rem;
  --measure-prose: 46rem;
  --measure-narrow: 32rem;

  /* Type. */
  --font-ui: "Archivo", -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
  --font-display: "EB Garamond", Georgia, serif;
  --font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;

  /* The mark as a page-title glyph: flat gold shield, three vino filed bars.
     The foil gradient lives only in the large inline SVG lockups. */
  --shield-mark: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 96 112'%3E%3CclipPath id='c'%3E%3Cpath d='M16 6 H80 Q88 6 88 14 V56 C88 79 71 95 48 106 C25 95 8 79 8 56 V14 Q8 6 16 6 Z'/%3E%3C/clipPath%3E%3Cg clip-path='url(%23c)'%3E%3Crect x='0' y='6' width='96' height='106' fill='%23C9993C'/%3E%3Crect x='0' y='46' width='96' height='11' fill='%23361027'/%3E%3Crect x='0' y='63' width='96' height='11' fill='%23361027'/%3E%3Crect x='0' y='80' width='96' height='11' fill='%23361027'/%3E%3C/g%3E%3C/svg%3E");

  /* The same shield as a one-colour silhouette, used as a MASK so it paints
     in currentColor (the nothing-to-do seal). */
  --shield-silhouette: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 96 112'%3E%3Cpath d='M16 6 H80 Q88 6 88 14 V56 C88 79 71 95 48 106 C25 95 8 79 8 56 V14 Q8 6 16 6 Z' fill='%23000'/%3E%3C/svg%3E");

  /* A filed page, as a mask: the glyph beside every document link. */
  --file-glyph: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 30'%3E%3Cpath d='M3 1.5h11.5L21 8v20.5H3z' fill='none' stroke='%23000' stroke-width='2.4'/%3E%3Cpath d='M14.5 1.5V8H21' fill='none' stroke='%23000' stroke-width='2.4'/%3E%3C/svg%3E");

  /* The caret drawn into wine-bar selects, so the bar needs no icon font. */
  --wine-caret: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23f2eee6' stroke-width='1.4' stroke-linecap='round'/%3E%3C/svg%3E");
}

/* ═══ 3. Base ════════════════════════════════════════════════════════════ */

* { box-sizing: border-box; }

/* iPadOS inflates text it deems small, and inside table cells that inflation
   feeds the table's intrinsic widths — it blew the documentos checklist past
   its card on an iPad (2026-08-12). 100% pins the sizes this sheet asked for. */
html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

/* A column that fills the viewport, so a short page can pin its closing seal
   to the bottom instead of ending mid-air. */
body {
  margin: 0;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  background: var(--page);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: 16px;
  line-height: 1.55;
}

/* Wide enough for a roster with controls, narrow enough that prose in a card
   still stops at a readable measure. Top padding is smaller than the bottom:
   the wine bar already supplies the hard edge above the title. */
main {
  flex: 1 0 auto;
  width: 100%;
  max-width: var(--measure);
  margin: 0 auto;
  padding: 1.25rem 1.5rem 4rem;
}

/* Logged-out pages hold one narrow card; at app width the login form read
   as a banner. */
main.public { max-width: var(--measure-narrow); }

/* Any page that closes with the seal pins it to the bottom of the viewport. */
main:has(.page-seal) {
  display: flex;
  flex-direction: column;
}

/* ── Type scale ──
   Garamond for everything that names a thing (titles, panel heads, figures);
   Archivo for everything that operates it. A panel head closes with a
   hairline so a panel visibly has a head and a body; h3/h4 carry no rule —
   the h2's hairline is what separates head from body, and repeating it one
   level down turns a panel into a stack of panels. */
h1 {
  margin: 0 0 1.1rem;
  padding-bottom: 0.9rem;
  border-bottom: 1px solid var(--line);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.8rem;
  line-height: 1.2;
  letter-spacing: -0.021em;
  text-wrap: balance;
}

h2 {
  margin: 0 0 0.9rem;
  padding-bottom: 0.75rem;
  border-bottom: 1px solid var(--line);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.28rem;
  letter-spacing: -0.012em;
}

h3 {
  margin: 1.4rem 0 0.6rem;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.1rem;
  letter-spacing: -0.008em;
}

h4 {
  margin: 1.1rem 0 0.4rem;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.02rem;
  letter-spacing: -0.006em;
}

/* A lede or hint that follows a heading belongs to it: it sits back up
   against the rule instead of floating in the gap the rule opened. */
h1 + .lede, h1 + .muted,
h2 + .lede, h2 + .muted { margin-top: -0.45rem; }

h3 + .lede, h3 + .muted,
h4 + .lede, h4 + .muted { margin-top: 0; }

.lede { margin: 0 0 1.25rem; }

.muted { color: var(--muted); font-size: 0.9rem; }

.danger { color: var(--bad); }

a { color: var(--interactive); }

/* ── Lists: the ordered part of a legal argument ──
   Quiet marker, text holding the paragraph's edge as closely as a hanging
   indent allows. The square is `list-style-type`, NOT `::marker { content }`:
   a content declaration on ::marker outranks `list-style: none`, so every
   componentised list below would draw a square NEXT TO its own marker. */
ul, ol {
  margin: 0.7rem 0 1rem;
  padding-left: 1.35rem;
}

li { margin: 0.3rem 0; }

li > p { margin: 0.35rem 0; }

ul { list-style-type: "▪  "; }

ul > li::marker {
  color: var(--muted);
  font-size: 0.85em;
}

/* Numbered items are numbered evidence: tabular figures in the display face. */
ol > li::marker {
  color: var(--muted);
  font-family: var(--font-display);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

li > ul, li > ol {
  margin: 0.3rem 0 0.45rem;
  padding-left: 1.15rem;
}

li > ul { list-style-type: "–  "; }

/* Every list built as a component owns its own layout and marker. One
   registry, so a new component is added here rather than rediscovered as a
   stray 40px indent. */
.pendientes-list,
.first-run-steps,
.finding-list,
.expediente-chip-slots,
.evidence-categories,
.evidence-files,
.clause-findings,
.verify-match-list,
.verify-activity-list,
.bundle-list,
.door-grid,
.guide-toc-list,
.guide-related ul,
.diagram-flow,
.diagram-layers {
  padding-left: 0;
  list-style: none;
}

/* ── Rules, quoted matter, identifiers ── */

/* An engraved break: a hairline that fades at both ends reads as the printed
   rule on an instrument, where a full-bleed line reads as a box that lost
   three sides. */
hr {
  height: 1px;
  margin: 1.8rem 0;
  border: 0;
  background: linear-gradient(90deg, transparent, var(--line) 12%, var(--line) 88%, transparent);
}

/* Quoted statute: the rule in the gutter, the text upright — this is matter
   a compliance officer reads closely, not skims. */
blockquote {
  margin: 1rem 0;
  padding: 0.15rem 0 0.15rem 1rem;
  border-left: 2px solid var(--grana);
  color: var(--muted);
}

blockquote > :first-child { margin-top: 0; }
blockquote > :last-child { margin-bottom: 0; }

/* An identifier quoted inline — an RFC, a folio, a CURP — is compared
   character by character. */
code {
  padding: 0.05em 0.3em;
  font-family: var(--font-mono);
  font-size: 0.88em;
  font-variant-numeric: tabular-nums;
  background: var(--surface-sunken);
  border-radius: 3px;
}

/* A block a machine reads — a request line, a JSON body, a freshly minted
   key: the same sunken ground as inline code, scrolling sideways rather
   than breaking a value. */
pre {
  margin: 0.8rem 0;
  padding: 0.75rem 0.9rem;
  overflow-x: auto;
  font-family: var(--font-mono);
  font-size: 0.85rem;
  line-height: 1.5;
  background: var(--surface-sunken);
  border-radius: var(--radius);
}

pre code { padding: 0; background: none; font-size: inherit; }

/* Screen-reader-only labels. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ═══ 4. Signatures ══════════════════════════════════════════════════════
   The few gestures that repeat on every screen and make it read as one
   instrument. Each is defined ONCE here; the components that wear one are
   grouped onto the rule rather than restating it. */

/* The kicker: a small tracked capital line in grana that opens a section of
   a document — the pendientes queue, "Más guías", a diagram node's kind, the
   índice of a wiki page. One rule for all of them, including the h2s that
   wear it (which must also drop the panel-head hairline). */
.kicker,
.pendientes > h2,
.pendientes-fold-label,
.sheet-kicker,
.guide-tool-kicker,
.guide-related > h2,
.verify-about > h2,
.wiki-toc > h2,
.diagram-node-kicker {
  margin: 0 0 0.5rem;
  padding: 0;
  border-bottom: 0;
  font-family: var(--font-ui);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--grana);
}

/* The muted kicker: the same register, spent without the accent — a public
   page's statute eyebrow, a field name set over an instrument. */
.kicker-muted,
.public-kicker,
.verify-search-label,
.verify-activities-heading,
.obra-vignette figcaption {
  display: block;
  margin: 0 0 0.45rem;
  font-family: var(--font-ui);
  font-size: 0.76rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}

.public-kicker { letter-spacing: 0.2em; }

/* The shield title: every screen is titled like a stamped expediente, the
   mark beside the page name. Only page titles wear it; panel heads stay
   quiet under them. A real company logo replaces it (see .profile-head). */
.page-head h1,
.guide-index h1,
.verify-tool h1 {
  display: flex;
  align-items: baseline;
  gap: 0.55rem;
}

.page-head h1::before,
.guide-index h1::before,
.verify-tool h1::before {
  content: "";
  flex: 0 0 auto;
  width: 0.72em;
  height: 0.84em;
  transform: translateY(0.06em);
  background: var(--shield-mark) no-repeat center / contain;
}

/* The legal citation: why the product asks for a thing, ending in a link to
   the statute (Cámara de Diputados is the only permitted target — Michelle
   2026-08-05). Set as a citation, in the § + small-caps register a statute
   is quoted in anywhere else, so the page's most defensible content does not
   read as its most disposable. Closed by default: the reference is the line,
   the explanation unfolds. */
.legal-basis {
  display: block;
  margin: 0.15rem 0 0.2rem;
  max-width: 46rem;
  color: var(--muted);
  font-size: 0.78rem;
}

.legal-basis a { white-space: nowrap; }

details.legal-basis > summary {
  display: inline-flex;
  align-items: baseline;
  gap: 0.3em;
  cursor: pointer;
  list-style: none;
  font-size: 0.95em;
  font-variant-caps: all-small-caps;
  letter-spacing: 0.055em;
  text-decoration: underline dotted;
  text-underline-offset: 2px;
  text-decoration-color: var(--line);
}

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

/* The § says "statute" before the words are read, and takes the accent on
   hover so the whole citation does not have to light up. */
details.legal-basis > summary::before {
  content: "§";
  flex: 0 0 auto;
  font-family: var(--font-display);
  font-variant-caps: normal;
  letter-spacing: 0;
  color: var(--grana);
  opacity: 0.75;
}

details.legal-basis > summary:hover {
  color: var(--ink);
  text-decoration-color: var(--muted);
}

details.legal-basis > summary:hover::before { opacity: 1; }

/* Opened, the citation becomes quoted matter: the same gutter rule as
   blockquote, because that is what it is. */
details.legal-basis[open] {
  padding: 0.5rem 0.7rem 0.55rem;
  background: var(--surface-sunken);
  border-left: 2px solid var(--grana);
  border-radius: 0 var(--radius) var(--radius) 0;
}

details.legal-basis .legal-basis-text { margin: 0.3rem 0 0; }

/* The file glyph: a filed page beside every document link, masked so it
   takes the link's colour and hover without a second asset. */
.doc-file,
.bundle-client {
  display: inline-flex;
  align-items: baseline;
  gap: 0.45rem;
  min-width: 0;
  font-weight: 600;
  text-decoration: none;
}

.doc-file::before,
.bundle-client::before {
  content: "";
  flex: 0 0 auto;
  align-self: center;
  width: 0.72em;
  height: 0.92em;
  background-color: currentColor;
  opacity: 0.5;
  mask: var(--file-glyph) no-repeat center / contain;
  -webkit-mask: var(--file-glyph) no-repeat center / contain;
}

.doc-file:hover { text-decoration: underline; }
.doc-file:hover::before { opacity: 1; }

/* The page seal: the guilloché stamp over the product's one-line thesis,
   closing the dashboard, every public page and every guide. Decorative only:
   no semáforo colour, nothing clickable — it says the page ends here. */
.page-seal {
  margin-top: auto;
  padding-top: 3.5rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.6rem;
  color: var(--muted);
}

.page-seal-svg {
  width: 10.5rem;
  height: auto;
  opacity: 0.85;
}

.page-seal-line {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 1rem;
  letter-spacing: 0.02em;
  opacity: 0.85;
}

/* Privacy-notice link at the foot of every logged-out page: reachable where
   data is collected (LFPDPPP), set quiet because it is plumbing. */
.public-legal {
  margin: 0.75rem 0 0;
  text-align: center;
  font-size: 0.85rem;
}

.public-legal a { color: var(--muted); }

/* ═══ 5. Wine chrome ═════════════════════════════════════════════════════
   Vino Profundo is the one dark surface per view: the app header and its
   section nav, the public masthead, the landing hero and the CTA band.
   Every colour on a wine bar is STATED from the --papel-on-wine family,
   never inherited from the page's link or text colour. */

/* The lockup: foil mark beside the two-tone wordmark, one rule for the app
   header (.brand) and the public bars (.brand-word), so they cannot drift.
   No flex gap — it would also split "Repse" from "Shield"; the space is the
   mark's own margin. */
.brand,
.guide-top .brand-word,
.landing-top .brand-word {
  display: inline-flex;
  align-items: center;
  color: var(--papel-on-wine);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.3rem;
  letter-spacing: 0.01em;
  text-decoration: none;
}

.brand svg,
.guide-top .brand-word svg,
.landing-top .brand-word svg {
  flex: 0 0 auto;
  display: block;
  margin-right: 0.6rem;
}

.brand .brand-shield,
.guide-top .brand-shield,
.landing-top .brand-shield { color: var(--oro-on-wine); }

/* ── App header ──
   Two clusters: brand + tabs on the left, who-you-are + controls on the
   right. The bar is full-bleed wine. Its LEFT edge is the page column's, so
   the lockup, the section nav and the page title share one edge; the
   account controls stay pinned to the window's right corner, because boxing
   both clusters into the column made the bar wrap at laptop width. */
.app-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.4rem 2rem;
  padding: 0.55rem 1.5rem 0.55rem max(1.5rem, calc((100% - var(--measure)) / 2));
  background: var(--vino-profundo);
  border-bottom: 1px solid var(--wine-rule);
}

.header-left {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 2.25rem;
}

/* Three tabs, and only three (Michelle 2026-08-04). The papel underline is
   the "where you are" gesture; inactive tabs are papel at reduced ink. */
.nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  font-size: 0.85rem;
  font-weight: 500;
  letter-spacing: 0.015em;
}

.nav a {
  padding: 0.25rem 0.6rem 0.3rem;
  color: var(--papel-on-wine-dim);
  text-decoration: none;
  border-bottom: 2px solid transparent;
}

.nav a:hover { color: var(--papel-on-wine); }

.nav a.active {
  color: var(--papel-on-wine);
  border-bottom-color: var(--papel-on-wine);
}

.session {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
  font-size: 0.85rem;
  color: var(--papel-on-wine-soft);
}

.session .company {
  font-weight: 600;
  color: var(--papel-on-wine);
}

.session .role {
  padding: 0.1rem 0.55rem;
  border: 1px solid rgba(242, 238, 230, 0.28);
  border-radius: 999px;
  font-size: 0.78rem;
}

/* A rule separates identity (which company, in what role) from controls
   (language, leaving), so the right cluster is not five undifferentiated items. */
.session-actions {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  margin-left: 0.35rem;
  padding-left: 1.1rem;
  border-left: 1px solid rgba(242, 238, 230, 0.2);
}

/* Controls on a wine bar: the neutral paper border would read as a stray
   light box, so they borrow a translucent papel edge. */
.app-header .link-button,
.guide-top .link-button {
  color: var(--papel-on-wine-soft);
  border-color: var(--wine-control-edge);
}

.app-header .link-button:hover,
.guide-top .link-button:hover {
  color: var(--papel-on-wine);
  border-color: rgba(242, 238, 230, 0.5);
  background: var(--wine-control);
}

/* appearance:none drops the OS control (a light widget punched into the
   bar); the caret is inlined. Padding is set on the two-class selector on
   purpose: `.switcher select` sets a padding SHORTHAND at one class, and a
   bare `.app-header select` padding-right would lose on source order. */
.app-header select,
.guide-top select {
  appearance: none;
  color: var(--papel-on-wine);
  background-color: var(--wine-control);
  background-image: var(--wine-caret);
  background-repeat: no-repeat;
  background-position: right 0.55rem center;
  background-size: 9px 6px;
  border-color: var(--wine-control-edge);
}

.app-header .switcher select,
.guide-top .switcher select { padding: 0.3rem 1.8rem 0.3rem 0.65rem; }

.app-header select:hover,
.guide-top select:hover { background-color: rgba(242, 238, 230, 0.16); }

/* ── Section nav: the second level of the three tabs ──
   The sections of whichever profile you are inside, one row under the
   header: same wine, quieter type, the current section carrying grana. */
.section-nav {
  background: var(--vino-profundo);
  border-bottom: 1px solid var(--wine-rule);
}

.section-nav-inner {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 0 1.5rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0 1.25rem;
}

.section-nav a {
  display: inline-block;
  padding: 0.5rem 0;
  font-size: 0.85rem;
  color: var(--papel-on-wine-dim);
  text-decoration: none;
  border-bottom: 2px solid transparent;
}

.section-nav a:hover { color: var(--papel-on-wine); }

.section-nav a.active {
  color: var(--papel-on-wine);
  border-bottom-color: var(--grana);
}

/* ── Phone header ──
   Brand row, then a horizontally scrolling tab strip, then one compact
   identity + controls line. Nothing wraps to a second line of its own. Sits
   AFTER every base header rule on purpose: equal specificity, source order. */
@media (max-width: 40rem) {
  .app-header { padding: 0.5rem 1rem; gap: 0.25rem 1rem; }
  .header-left { width: 100%; justify-content: space-between; gap: 0.25rem 1rem; }
  .brand,
  .guide-top .brand-word,
  .landing-top .brand-word { font-size: 1.15rem; }
  .nav { flex-wrap: nowrap; overflow-x: auto; max-width: 100%; scrollbar-width: none; }
  .nav::-webkit-scrollbar { display: none; }
  .nav a { white-space: nowrap; }
  .session { width: 100%; font-size: 0.8rem; gap: 0.45rem; flex-wrap: nowrap; }
  .session .company {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
  }
  .session .role { border: 0; padding: 0; font-size: 0.74rem; opacity: 0.85; white-space: nowrap; }
  .session-actions { margin-left: auto; padding-left: 0.8rem; gap: 0.55rem; flex-shrink: 0; border-left-color: rgba(242, 238, 230, 0.14); }
  .app-header .switcher select { padding: 0.2rem 1.6rem 0.2rem 0.5rem; font-size: 0.78rem; }
  .app-header .link-button { padding: 0.2rem 0.55rem; font-size: 0.76rem; }

  .section-nav-inner {
    padding: 0 1rem;
    gap: 0 1rem;
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .section-nav-inner::-webkit-scrollbar { display: none; }
  .section-nav a { white-space: nowrap; }
}

/* ── Public masthead (.guide-top) ──
   The guides, the wiki and every logged-out layout.html page wear this bar.
   Full-bleed wine, content in the page column. */
.guide-top {
  padding: 0 1.5rem;
  background: var(--vino-profundo);
  border-bottom: 1px solid var(--wine-rule);
}

.guide-top-inner {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 1.05rem 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.35rem 1rem;
}

.guide-top-nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.2rem;
  row-gap: 0.2rem;
}

.guide-top-nav a {
  color: var(--papel-on-wine);
  font-weight: 600;
  font-size: 0.95rem;
  text-decoration: none;
}

/* Grana vanishes on wine, so the underline carries the hover, not a colour. */
.guide-top-nav a:hover {
  text-decoration: underline;
  text-underline-offset: 4px;
}

.guide-top .switcher select {
  padding: 0.25rem 1.7rem 0.25rem 0.6rem;
  font-size: 0.82rem;
}

/* Long nav labels have a short twin for phones; only one twin renders. */
.nav-when-narrow { display: none; }

/* On a phone the masthead is two deliberate rows: the lockup, a faint
   hairline, then the nav with its short labels. */
@media (max-width: 40rem) {
  .guide-top-inner { padding: 0.75rem 0 0.6rem; }
  .guide-top-nav {
    flex-basis: 100%;
    margin-top: 0.15rem;
    padding-top: 0.55rem;
    border-top: 1px solid rgba(242, 238, 230, 0.14);
    gap: 1.4rem;
  }
  .guide-top-nav a { font-size: 0.85rem; }
  .nav-when-wide { display: none; }
  .nav-when-narrow { display: inline; }
}

/* The confidencial strap in the wiki masthead: quiet, unmistakable, never
   a button. */
.wiki-confidential {
  align-self: center;
  padding: 0.15rem 0.6rem;
  border: 1px solid currentColor;
  border-radius: 999px;
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--papel-on-wine-soft);
  white-space: nowrap;
}

/* ── Landing hero ── */
.hero {
  padding: 0 1.5rem 4rem;
  background: var(--vino-profundo);
  color: var(--papel-on-wine);
}

.landing-top {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 1.1rem 0 3.5rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.landing-top-nav {
  display: flex;
  align-items: center;
  gap: 1.2rem;
}

.landing-top .top-enter {
  padding: 0.45rem 1.1rem;
  color: var(--papel-on-wine);
  font-size: 0.9rem;
  font-weight: 600;
  text-decoration: none;
  border: 1px solid rgba(242, 238, 230, 0.35);
  border-radius: var(--radius);
}

.landing-top .top-enter:hover { border-color: var(--papel-on-wine); }

@media (max-width: 40rem) {
  .landing-top { flex-wrap: wrap; padding-bottom: 2.4rem; }
  .landing-top-nav { gap: 0.6rem; }
  .landing-top .top-enter { padding: 0.35rem 0.85rem; font-size: 0.85rem; }
}

.hero-inner {
  max-width: 46rem;
  margin: 0 auto;
  text-align: center;
}

/* A law tool cites its statute before it speaks: the strapline as an
   engraved eyebrow between the mark and the title. */
.hero-kicker {
  margin: 1.6rem 0 0;
  font-family: var(--font-ui);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(242, 238, 230, 0.6);
}

.hero h1 {
  margin: 0.7rem 0 0.9rem;
  font-size: clamp(1.9rem, 5vw, 3rem);
  line-height: 1.15;
  color: var(--papel-on-wine);
  border-bottom-color: var(--wine-rule);
}

.hero .hero-tagline {
  margin: 0 auto;
  max-width: 52ch;
  font-size: 1.1rem;
  line-height: 1.6;
  color: var(--papel-on-wine-soft);
}

/* The one filled control on wine: papel on vino, the inverse of the app's
   grana submit. */
.hero-cta {
  display: inline-block;
  margin-top: 2rem;
  padding: 0.75rem 2rem;
  font-weight: 600;
  color: var(--vino-profundo);
  background: var(--papel-on-wine);
  border-radius: var(--radius);
  text-decoration: none;
}

.hero-cta:hover { filter: brightness(1.08); }

.hero-secondary { margin-top: 0.9rem; }

.hero-secondary a {
  color: var(--papel-on-wine);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.hero-secondary a:hover { text-decoration-thickness: 2px; }

.hero-secondary-hint {
  display: block;
  margin-top: 0.25rem;
  font-size: 0.85rem;
  color: rgba(242, 238, 230, 0.75);
}

/* ── CTA band: the binding tape on a closed file ── */
.cta-band {
  margin-top: 4rem;
  padding: 3rem 1.5rem;
  background: var(--vino-profundo);
  color: var(--papel-on-wine);
  text-align: center;
}

.landing-sheet + .cta-band { margin-top: 0; }

.cta-band h2 {
  max-width: 40ch;
  margin: 0 auto 0.5rem;
  font-size: clamp(1.3rem, 3.5vw, 1.7rem);
  color: var(--papel-on-wine);
  border-bottom-color: var(--wine-rule);
}

.cta-band .hero-cta { margin-top: 1.25rem; }

.guide-cta-band p {
  max-width: 34rem;
  margin: 0.6rem auto 1rem;
}

/* ── Footers ── */
.landing-footer {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 2rem 1.5rem 3rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  font-size: 0.85rem;
  color: var(--muted);
}

.guide-footer {
  flex-direction: column;
  gap: 0.4rem;
}

.guide-disclaimer {
  font-size: 0.8rem;
  color: var(--muted);
}

/* ═══ 6. Surfaces ════════════════════════════════════════════════════════ */

/* ── The page head ──
   The title belongs to the PAGE, not to the first panel: out here it names
   the screen, and the panels below are the records. */
.page-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 0.5rem 1.5rem;
  margin-bottom: 1rem;
}

.page-head h1 {
  margin: 0;
  padding: 0;
  border-bottom: 0;
  font-size: clamp(1.85rem, 1.35rem + 1.6vw, 2.3rem);
}

.page-head .lede,
.page-head .muted { margin: 0.3rem 0 0; }

.page-head > div { min-width: 0; }

/* A page head that follows a panel (/empresa opens with the claim-this-RFC
   card) otherwise starts flush against that card's bottom edge. */
.card + .page-head { margin-top: 1.75rem; }

/* Profile heads carry the company logo beside the name, constrained to a
   badge so an uploaded banner cannot push the title off the screen. A real
   logo replaces the shield glyph — two marks beside one name is clutter. */
.profile-head {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  min-width: 0;
}

.company-logo {
  max-height: 3.25rem;
  max-width: 7rem;
  object-fit: contain;
  border-radius: var(--radius-panel);
  flex-shrink: 0;
}

.profile-head:has(.company-logo) h1::before { display: none; }

/* The service-kind form under the provider's name (client lens): one quiet
   line — label, select, Guardar — sized to its words, never a field block. */
.provider-service-kind-form { margin-top: 0.55rem; font-size: 0.9rem; }

.provider-service-kind-form label {
  margin: 0;
  font-weight: 500;
  color: var(--muted);
}

/* Managing the logo: the current mark sits beside its replace and remove
   controls so "Cambiar" visibly acts on the image it will replace. */
.logo-manage {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.9rem;
}

/* ── The card: a record printed onto the page, not a widget floating above it ── */
.card {
  margin-top: 1.25rem;
  padding: 1.6rem 1.75rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-panel);
}

.card:first-child { margin-top: 0; }

/* The eye goes where the work is: a panel holding anything amber or red
   carries the semáforo on its left edge, the file-folder-tab gesture. Red
   outranks amber by source order. */
.card:has(.pill-warn) { border-left: 3px solid var(--warn); }
.card:has(.pill-bad),
.card:has(.notice-error) { border-left: 3px solid var(--bad); }

/* ── Zero states ──
   A panel whose whole content is one muted line is not a record: it drops
   its chrome, and the first of a run is sealed with the debossed shield so
   an empty queue reads as a clear desk rather than a screen that failed to
   load. "Nothing is asked of you" is precisely the state the kit forbids
   colouring. A panel that also carries an action keeps its box. */
.card:has(> p.muted:only-child) {
  margin-top: 0.75rem;
  padding: 0;
  background: none;
  border-color: transparent;
}

.card:has(> p.muted:only-child) > p.muted {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.9rem;
  margin: 0;
  padding: 2.5rem 1rem 2.75rem;
  text-align: center;
  text-wrap: pretty;
}

.card:has(> p.muted:only-child) > p.muted::before {
  content: "";
  width: 2.6rem;
  height: 3.05rem;
  background-color: currentColor;
  opacity: 0.22;
  mask: var(--shield-silhouette) no-repeat center / contain;
  -webkit-mask: var(--shield-silhouette) no-repeat center / contain;
}

/* Consecutive zero states are one short list of nothing-to-do, not two
   panels, and only the first wears the seal. */
.card:has(> p.muted:only-child) + .card:has(> p.muted:only-child) { margin-top: 0.3rem; }

.card:has(> p.muted:only-child) + .card:has(> p.muted:only-child) > p.muted {
  display: block;
  padding: 0;
  text-align: left;
}

.card:has(> p.muted:only-child) + .card:has(> p.muted:only-child) > p.muted::before { display: none; }

/* ── The instrument: a raised panel with a grana top rule ──
   The one thing on a public page a visitor operates — the padrón search, the
   diagnóstico form, the tool card on /guias. Same dress in all three places. */
.instrument,
.verify-form,
.guide-tool-card {
  display: block;
  padding: 1.2rem 1.4rem 1.15rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-top: 3px solid var(--grana);
  border-radius: var(--radius-panel);
  box-shadow: var(--shadow);
  text-decoration: none;
}

/* ── The sunken section: a part OF a panel, not another panel ── */
.client-evidence,
.verify-source {
  background: var(--surface-sunken);
  border-radius: var(--radius);
}

/* ── The area-responsible strip (Michelle Q5): who feeds this page ──
   Metadata, not a record: a dashed one-liner that answers "who do I chase". */
.card.area-responsible {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.3rem 1rem;
  margin-top: 0.9rem;
  padding: 0.55rem 0.9rem;
  background: none;
  border: 1px dashed var(--line);
}

.card.area-responsible p { margin: 0; font-size: 0.82rem; }

.card.area-responsible .waive-disclosure { margin: 0; }

/* ── Definition lists (company facts) ── */
.facts { margin: 0; }

.facts dt {
  margin-top: 0.9rem;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
}

.facts dd { margin: 0.15rem 0 0; }

/* ═══ 7. Controls ════════════════════════════════════════════════════════ */

/* ── Fields ── */
label {
  display: block;
  margin-bottom: 0.35rem;
  font-size: 0.85rem;
  font-weight: 600;
}

/* A label wrapping a checkbox is one inline control, not a field with a
   caption above it. Matched structurally so every checkbox in the app gets
   it — the import-review flag, the días-hábiles switch, the next one. */
label:has(> input[type="checkbox"]) {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin-bottom: 0;
  font-weight: 500;
}

label:has(> input[type="checkbox"]) input[type="checkbox"] {
  width: auto;
  margin: 0;
  accent-color: var(--primary);
}

/* Sunken, not surface-coloured: a field painted the panel's colour vanished
   into it. Matched by EXCLUSION so an untyped <input>, a date, a textarea and
   whatever comes next are correct by default. */
input:not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="button"]),
select,
textarea {
  width: 100%;
  padding: 0.6rem 0.75rem;
  font: inherit;
  color: var(--ink);
  background: var(--field);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  transition: border-color 0.12s ease;
}

input:not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="button"]):hover,
select:hover,
textarea:hover { border-color: var(--muted); }

/* Vertical only: a textarea dragged wider than its card breaks the page. */
textarea { resize: vertical; }

input::placeholder,
textarea::placeholder { color: var(--muted); opacity: 1; }

/* The file input's inner "Choose File" control gets the quiet bordered
   treatment the app's other secondary controls wear. */
input[type="file"]::file-selector-button {
  margin-right: 0.7rem;
  padding: 0.3rem 0.7rem;
  font: inherit;
  font-size: 0.82rem;
  font-weight: 500;
  color: var(--ink);
  background: none;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  cursor: pointer;
  transition: border-color 0.12s ease, color 0.12s ease, background-color 0.12s ease;
}

input[type="file"]::file-selector-button:hover {
  color: var(--interactive);
  border-color: var(--interactive);
  background: var(--hover);
}

/* One focus ring for everything that takes focus. */
:is(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}

input + label,
select + label,
.field-hint + label,
p + label { margin-top: 1rem; }

.field-hint { margin: 0.35rem 0 0; }

/* Fields for fixed-length values are sized to the value: a CURP is always 18
   characters, a date is dd/mm/yyyy plus the picker. */
.field-code { max-width: 16rem; }
.field-short { max-width: 9rem; }
.field-date { max-width: 12rem; }

/* Forms read best at input-line width even inside a wide panel. */
.card > form { max-width: 30rem; }

/* A form that follows a table in the same panel needs air, or its first
   label reads as another table cell. */
.card > .table-scroll + form,
.card > .table-scroll + h3 { margin-top: 1.4rem; }

/* ── The form grid ──
   Long data-entry forms flow into as many columns as fit. Each field is a
   subgrid so label, control and hint line up ACROSS a row: a label that
   wraps no longer pushes its own input half a line below its neighbours'.
   A field spans as many shared tracks as it has children — the subgrid has
   no implicit rows, so a fourth child (a legal citation, a checkbox) would
   otherwise land on top of the third. */
.card > form.form-grid {
  max-width: 46rem;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: 0.85rem 1.5rem;
  align-items: start;
}

.form-grid .field {
  display: grid;
  grid-template-rows: subgrid;
  grid-row: span 3;
  row-gap: 0.3rem;
}

.form-grid .field:has(> :nth-child(4)) { grid-row: span 4; }
.form-grid .field:has(> :nth-child(5)) { grid-row: span 5; }

.form-grid .field > label { margin-bottom: 0; }

.form-grid .field-span { grid-column: 1 / -1; }

.form-grid .field > :first-child { margin-top: 0; }

.form-grid .field > input,
.form-grid .field > select { width: 100%; }

/* A grid item stretches to its area, which would undo "sized to its label"
   below and turn the submit into a full-width slab. */
.form-grid .field > button[type="submit"] { justify-self: start; }

/* ── Buttons ──
   Three registers: the primary submit (grana fill, sized to its label, never
   a slab), the quiet bordered control (.link-button — row actions, header
   controls), and the wine CTA (.hero-cta, in §5).

   The :not(.link-button) guard is load-bearing: without it this selector
   outweighs .link-button and every text-style submit half-inherits the
   filled look. Any future primary variant must repeat the guard. */
button[type="submit"]:not(.link-button) {
  margin-top: 1.25rem;
  width: auto;
  min-width: 11rem;
  padding: 0.7rem 1.6rem;
  font: inherit;
  font-weight: 600;
  color: var(--primary-ink);
  background: var(--primary);
  border: 0;
  border-radius: var(--radius);
  cursor: pointer;
}

button[type="submit"]:not(.link-button):hover { filter: brightness(1.12); }

/* A single-purpose card on a narrow page — sign in, accept an invitation —
   is the one place a full-bleed button is right: it IS the page's action. */
main.public button[type="submit"]:not(.link-button) { width: 100%; }

@media (max-width: 34rem) {
  button[type="submit"]:not(.link-button) { width: 100%; }
}

/* Quiet bordered controls: a row of them stays calm, and each is still
   obviously a button rather than prose. Takes colour only on hover. Also the
   dress of a <summary> that sits among row actions, so a fold ("Suspender")
   and a button ("Contratos") in the same cluster read as one family. */
.link-button,
.row-actions .waive-disclosure > summary,
.pdf-pager-controls button,
.verify-match-button {
  width: auto;
  margin: 0;
  padding: 0.3rem 0.7rem;
  font: inherit;
  font-size: 0.82rem;
  font-weight: 500;
  color: var(--ink);
  background: none;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
  transition: border-color 0.12s ease, color 0.12s ease, background-color 0.12s ease;
}

.link-button:hover,
.row-actions .waive-disclosure > summary:hover,
.pdf-pager-controls button:hover,
.verify-match-button:hover {
  color: var(--interactive);
  border-color: var(--interactive);
  background: var(--hover);
}

/* Destructive actions stay recessive until reached for. */
.link-button.danger { color: var(--muted); }

.link-button.danger:hover {
  color: var(--bad);
  border-color: var(--bad);
  background: transparent;
}

/* ── Inline forms: controls in a row, sized to content ── */
.inline-form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}

.inline-form button[type="submit"]:not(.link-button),
.inline-form select {
  margin-top: 0;
  width: auto;
}

.inline-form input:not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="button"]) {
  width: auto;
  flex: 0 1 auto;
}

/* `width: auto` on a select means "as wide as the longest option", and it
   will not shrink inside a flex row unless told it may: a 437px picker inside
   a 390px phone scrolled the whole page sideways (2026-08-17). */
.inline-form select {
  min-width: 0;
  max-width: 100%;
}

form > select { margin-bottom: 0.5rem; }

/* Added by page-behaviors.js, never written in markup: a row's "Guardar"
   hides until a value differs from what is saved; with JS off nothing hides.
   visibility, not display, so the row does not jump when it appears. */
form.save-awaits-change button[type="submit"] { visibility: hidden; }

/* ── The switcher (company, language) ── */
.switcher {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.switcher select {
  width: auto;
  padding: 0.3rem 0.5rem;
  font-size: 0.85rem;
}

/* Its submit is the no-JS fallback for an auto-submitting select; it must
   never read as a second primary button. */
.switcher .link-button { color: var(--muted); }
.app-header .switcher .link-button,
.guide-top .switcher .link-button { color: var(--papel-on-wine-soft); }

/* ── Disclosures ──
   Three folds, one idiom: a muted underlined summary at rest, ink on hover,
   and the opened content kept compact. `.waive-disclosure` holds a per-row
   form (waivers, suspend/terminate with a reason, assign a worker);
   `.inline-note` folds an explanation and its form under the row it
   explains; `.pendientes-fold` is in §10. */
.waive-disclosure { margin-top: 0.4rem; }

.waive-disclosure > summary,
details.inline-note > summary {
  display: inline-block;
  cursor: pointer;
  list-style: none;
  font-size: 0.85rem;
  color: var(--muted);
  text-decoration: underline;
  text-underline-offset: 2px;
}

details.inline-note > summary { text-decoration-style: dotted; }

.waive-disclosure > summary::-webkit-details-marker,
details.inline-note > summary::-webkit-details-marker { display: none; }

.waive-disclosure > summary:hover,
details.inline-note > summary:hover { color: var(--ink); }

/* The opened form stays compact and left-aligned even inside a right-aligned
   actions column; the margin-left:auto that parks it right is applied ONLY
   there — in a full-width panel it shoved the fields to the far edge. */
.waive-form {
  margin-top: 0.5rem;
  max-width: 22rem;
  text-align: left;
}

.actions-column .waive-form { margin-left: auto; }

.waive-form label { font-size: 0.85rem; }

.waive-form textarea,
.waive-form input:not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="button"]) {
  margin-top: 0.25rem;
  padding: 0.5rem 0.65rem;
  font-size: 0.9rem;
}

.waive-form button[type="submit"]:not(.link-button) {
  margin-top: 0.5rem;
  min-width: 0;
  padding: 0.45rem 1rem;
  font-size: 0.85rem;
}

details.inline-note {
  margin-top: 0.4rem;
  font-size: 0.9rem;
}

details.inline-note[open] {
  margin-top: 0.5rem;
  padding: 0.6rem 0.7rem;
  background: var(--surface-sunken);
  border-radius: var(--radius);
}

details.inline-note[open] > summary { color: var(--ink); font-weight: 600; }
details.inline-note p { margin: 0.4rem 0 0.6rem; }
details.inline-note form { margin: 0; }

/* width before max-width: under 34rem the roster's cells become blocks, and
   a fixed 22rem input inside one overflows a phone. */
details.inline-note input[type="date"],
details.inline-note input[type="text"] { width: 100%; max-width: 22rem; }

/* ── The drop zone ──
   Dashed, because a dashed edge already means "put something here"; a plain
   file input works underneath, so the zone is decoration over a control. */
.dropzone {
  padding: 0.7rem 0.75rem;
  background: var(--field);
  border: 1px dashed var(--line);
  border-radius: var(--radius);
  transition: border-color 0.12s ease, background-color 0.12s ease;
}

.dropzone input[type="file"] {
  padding: 0;
  background: none;
  border: 0;
  font-size: 0.9rem;
}

.dropzone-hint {
  margin: 0.35rem 0 0;
  font-size: 0.82rem;
  overflow-wrap: anywhere;
}

.dropzone.is-dragging {
  border-color: var(--interactive);
  border-style: solid;
  background: var(--hover);
}

/* A chosen file is a small success and the semáforo owns that colour — the
   edge and the hint go green, not a filled panel. */
.dropzone.has-file { border-color: var(--ok); }

.dropzone.has-file .dropzone-hint {
  color: var(--ok);
  font-weight: 600;
}

/* ── Notices ── */
.notice {
  padding: 0.7rem 0.85rem;
  border-radius: var(--radius);
  font-size: 0.9rem;
}

.notice-ok {
  color: var(--ok);
  background: var(--ok-bg);
  border: 1px solid color-mix(in srgb, var(--ok) 30%, transparent);
}

.notice-warn {
  color: var(--warn);
  background: var(--warn-bg);
  border: 1px solid color-mix(in srgb, var(--warn) 30%, transparent);
}

.notice-error {
  color: var(--bad);
  background: var(--bad-bg);
  border: 1px solid color-mix(in srgb, var(--bad) 30%, transparent);
}

/* Floating forms use the native popover attribute (light dismiss, Esc, no
   JS). Author CSS beats the browser's hidden state, so the closed state is
   restated; the open one centres on the page as a paper sheet. */
[popover]:not(:popover-open) { display: none; }
.popover-form {
  margin: auto;
  inset: 0;
  width: min(34rem, calc(100vw - 2rem));
  padding: 1.25rem 1.5rem;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  box-shadow: 0 1rem 2rem rgba(36, 29, 34, 0.18);
}
.popover-form::backdrop { background: rgba(36, 29, 34, 0.35); }
.popover-form h3 { margin-top: 0; }
.popover-form .field { margin-bottom: 0.9rem; }
.popover-form .actions { display: flex; gap: 0.75rem; align-items: center; }
.payment-hold-override {
  margin: 1rem 0;
  padding: 0.9rem 1rem;
  border-left: 3px solid var(--grana);
  background: var(--grana-tint);
}
.payment-hold-override p { margin: 0.25rem 0; }
.payment-hold-override form { margin-top: 0.75rem; }

/* ═══ 8. Records ═════════════════════════════════════════════════════════
   The table is the product on most screens: a firm rule under the column
   heads, hairlines between records, a hover band so the eye tracks a row to
   its actions. Variants declare column shares as HINTS to auto layout, never
   `table-layout: fixed` and never a min-width on the <table> — a long-lived
   WebKit bug lays such a table out at its PREFERRED width, which pushed the
   documentos checklist 40% past its card on an iPad. Cells never shrink
   below min-content, so .table-scroll catches the overflow anyway. */

.roster {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9rem;
  font-variant-numeric: tabular-nums;
}

.roster th,
.roster td {
  padding: 0.85rem 0.75rem;
  text-align: left;
}

.roster th:first-child,
.roster td:first-child { padding-left: 0; }

.roster th:last-child,
.roster td:last-child { padding-right: 0; }

/* Centred: a person cell is two lines while its controls are one, and top
   alignment hung Guardar at a different height than the name it acts on. */
.roster td {
  vertical-align: middle;
  border-top: 1px solid var(--line-soft);
}

.roster th {
  vertical-align: bottom;
  padding-bottom: 0.6rem;
  border-bottom: 1px solid var(--line);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}

/* A headless table would otherwise open with a stray rule. */
.roster tbody tr:first-child td { border-top: 0; }

.roster tbody tr { transition: background-color 0.12s ease; }
.roster tbody tr:hover { background: var(--hover); }

/* The record's name is the row's anchor: solid, underlined only on reach.
   overflow-wrap keeps a 40-character filename from inflating its column. */
.roster td a {
  font-weight: 600;
  text-decoration: none;
  overflow-wrap: anywhere;
}

.roster td a:hover { text-decoration: underline; }

.roster td .muted { font-size: 0.83rem; }

/* Controls inside a row are sized to their content, not to the column. */
.roster td select { width: auto; max-width: 100%; }

/* ── A record's facts: labelled, not narrated ──
   Each fact is a labelled pair that cannot break; wrapping happens BETWEEN
   facts. The label is the same tiny tracked caps the table heads and the
   .facts list use, so a record cell, a column head and a company fact all
   name a field the same way. */
.record-name {
  display: block;
  margin-bottom: 0.25rem;
}

.record-facts {
  display: flex;
  flex-wrap: wrap;
  gap: 0.1rem 0.9rem;
  color: var(--muted);
  font-size: 0.82rem;
  line-height: 1.5;
}

.record-fact { min-width: 0; }

.record-fact-id {
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.record-fact-label {
  margin-right: 0.35rem;
  font-size: 0.86em;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.75;
}

/* ── One assignment is one posting ── */
.assignment { margin-bottom: 0.7rem; }

.assignment:last-child { margin-bottom: 0; }

.assignment-where {
  display: block;
  font-size: 0.88rem;
  font-weight: 600;
}

.assignment-meta {
  display: block;
  margin: 0.05rem 0 0.25rem;
  color: var(--muted);
  font-size: 0.8rem;
  font-variant-numeric: tabular-nums;
}

/* ── Roster variants: declared shares, top-aligned stacked cells ── */
.roster-records td,
.roster-documents td,
.roster-audience td { vertical-align: top; }

.roster-records td:first-child { width: 58%; }
.roster-records td + td { width: 42%; }

/* The file column carries the longest unbreakable content (filenames), so it
   gets the largest share; the shares are hints and a filename's min-content
   still wins when a share would squeeze it into a mid-name wrap. */
.roster-documents td:first-child { width: 34%; }
.roster-documents td:nth-child(2) { width: 36%; }
.roster-documents td:last-child { width: 30%; }

.roster-audience td:first-child { width: 45%; }

.audience-note { text-align: left; }

/* The client's RFC rides the same line as its name — a one-fact row stays
   one line tall. */
.audience-rfc {
  margin-left: 0.6rem;
  font-size: 0.83rem;
  font-variant-numeric: tabular-nums;
}

/* ── A filed document ──
   overflow-wrap only: a filename breaks mid-name solely when its container
   truly cannot fit it. word-break: break-word was here once and is what
   squeezed file columns on the iPad — it zeroes the name's min-content, so
   table auto-layout gave the width to neighbouring prose and every filename
   wrapped around a floating glyph while a gutter sat empty beside it. */
.doc-file-name {
  min-width: 0;
  overflow-wrap: break-word;
}

/* Inside a roster the anchor's own anywhere-wrap (see .roster td a) would
   re-zero the name's min-content; break-word restores the filename's claim
   to one line. */
.roster td a.doc-file { overflow-wrap: break-word; }

.doc-file-size {
  display: block;
  margin-top: 0.15rem;
  color: var(--muted);
  font-size: 0.8rem;
  font-variant-numeric: tabular-nums;
}

/* A file that follows a citation or a hint is the answer to the row above. */
.legal-basis + .doc-file,
.field-hint + .doc-file { margin-top: 0.35rem; }

/* The grupo-empresarial line under the requisitos table: pill, citation and
   toggle read as one quiet row. */
.grupo-empresarial {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.9rem;
}

.grupo-empresarial .legal-basis { margin: 0; }

/* Congruence lines on the vault checklist: sentence-length derived facts,
   one per line, wrapping (a .pill is nowrap and a 300-char pill forced a
   horizontal scroll). */
.congruence-note {
  display: inline-block;
  max-width: 34rem;
  white-space: normal;
  font-size: 0.85rem;
  color: var(--muted);
}

.congruence-warn { color: var(--warn); }

/* ── Row actions ──
   One flex row owns the gaps and the alignment of a cell holding several
   actions; every child is a control. Right-aligned only in the actions
   column, which `text-align` cannot reach for flex items. */
.actions-column { text-align: right; }

.actions-column .inline-form { justify-content: flex-end; }

.row-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 0.4rem;
}

.row-actions form { margin: 0; }

.row-actions .waive-disclosure { margin-top: 0; }

/* ── Scrolling and stacking ──
   The roster scrolls inside its own box so the page never does. Below a
   phone's width the rows stop being a grid: each record becomes a small
   block, and the column heads carry nothing once a row is one record. */
.table-scroll {
  overflow-x: auto;
  overscroll-behavior-x: contain;
}

@media (max-width: 34rem) {
  .roster,
  .roster tbody,
  .roster tr,
  .roster td {
    display: block;
    width: 100%;
  }

  .roster thead { display: none; }

  .roster tbody tr {
    padding: 0.85rem 0;
    border-top: 1px solid var(--line-soft);
  }

  .roster tbody tr:first-child { padding-top: 0; }

  .roster td,
  .roster tbody tr:first-child td {
    padding: 0.2rem 0;
    border-top: 0;
  }

  .actions-column { text-align: left; }

  .actions-column .row-actions,
  .actions-column .inline-form { justify-content: flex-start; }

  .actions-column .waive-form { margin-left: 0; }
}

/* ═══ 9. Status ══════════════════════════════════════════════════════════ */

/* ── Semáforo pills: status wears its colour as form ──
   Filled pills are reserved for states with a colour to mean; neutral means
   "nothing asked of you" and wears no fill and no dot. The chip families that
   reuse the shape (period picker, carpeta nav, view tabs) build on neutral. */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.15rem 0.65rem 0.15rem 0.5rem;
  border-radius: 999px;
  font-size: 0.8rem;
  font-weight: 600;
  white-space: nowrap;
}

.pill::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
}

.pill-ok { color: var(--ok); background: var(--ok-bg); }
.pill-warn { color: var(--warn); background: var(--warn-bg); }
.pill-bad { color: var(--bad); background: var(--bad-bg); }

.pill-neutral {
  padding: 0.12rem 0.6rem;
  color: var(--muted);
  background: transparent;
  border: 1px solid var(--line);
}

.pill-neutral::before { display: none; }

/* ── Chip rows ──
   A row of chips is one line of state, not a paragraph. */
.chip-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 0.75rem;
  margin: 0 0 0.75rem;
}

.chip-row + .chip-row { margin-top: -0.3rem; }

/* ── Chips that navigate: period picker, view tabs, carpeta nav ──
   Quiet at rest, bordered on hover, never underlined; the selected one
   inverts, which is unambiguous and spends no accent. */
.period-chip,
.view-tab,
.carpeta-nav a {
  text-decoration: none;
  border: 1px solid transparent;
  transition: border-color 0.12s ease, color 0.12s ease;
}

.carpeta-nav a { border-color: var(--line); }

a.period-chip:hover,
a.view-tab:hover {
  color: var(--ink);
  border-color: var(--line);
}

.carpeta-nav a:hover {
  color: var(--ink);
  border-color: var(--muted);
}

.period-chip.is-selected,
.view-tab.is-selected {
  color: var(--page);
  background: var(--ink);
  border-color: var(--ink);
}

/* View tabs sit under the page head and above the first card. */
.view-tabs { margin: 0 0 1.1rem; }

/* ── Expediente chip: the standing opens onto its reasons ──
   On the relationships list the expediente pill is a <summary>: clicking it
   unfolds the slots that are missing, undated or lapsed. */
.expediente-chip > summary {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  cursor: pointer;
  list-style: none;
}

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

.expediente-chip > summary::after {
  content: "▾";
  font-size: 0.85rem;
  color: var(--muted);
}

.expediente-chip[open] > summary::after { content: "▴"; }

.expediente-chip > summary:hover::after { color: var(--ink); }

.expediente-chip-slots {
  margin: 0.4rem 0 0.35rem;
  display: grid;
  gap: 0.3rem;
  font-size: 0.85rem;
}

.expediente-chip-slots li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
}

/* ── Expediente completeness (weighted %) ── */
.expediente-progress {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 0.9rem;
}

.expediente-progress-label {
  font-size: 0.85rem;
  font-weight: 600;
  white-space: nowrap;
}

.expediente-progress-track {
  flex: 1;
  height: 8px;
  border-radius: 999px;
  background: var(--surface-sunken);
  overflow: hidden;
}

.expediente-progress-fill {
  height: 100%;
  border-radius: 999px;
  background: var(--warn);
  transition: width 0.3s ease;
}

.expediente-progress-fill.is-complete { background: var(--ok); }

/* ═══ 10. Screens ════════════════════════════════════════════════════════
   Components that belong to one screen. Each builds on the primitives above
   and adds only what that screen's job requires. */

/* ── Dashboard: the three doors (Michelle 2026-08-12) ──
   My file / my clients / my providers, each with one figure, one line, and a
   dot only when work waits behind it. Everything heavier is one click away. */
.door-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: 1rem;
  margin: 1.4rem 0 0;
}

.door {
  position: relative;
  display: block;
  padding: 1.5rem 1.6rem 1.35rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-panel);
  color: var(--ink);
  text-decoration: none;
  transition: border-color 0.12s ease, transform 0.12s ease;
}

.door:hover {
  border-color: var(--grana);
  transform: translateY(-1px);
}

.door:hover .door-go { color: var(--grana); transform: translateX(3px); }

.door-figure {
  display: block;
  margin-bottom: 0.55rem;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 2.2rem;
  line-height: 1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}

.door-title {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.08rem;
  letter-spacing: -0.01em;
}

.door-dot {
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 50%;
  flex-shrink: 0;
}

.door-dot.pill-warn { background: var(--warn); }
.door-dot.pill-bad { background: var(--bad); }

.door-line {
  display: block;
  margin-top: 0.25rem;
  color: var(--muted);
  font-size: 0.85rem;
  line-height: 1.45;
}

.door-go {
  position: absolute;
  top: 1.25rem;
  right: 1.3rem;
  color: var(--muted);
  font-size: 1.15rem;
  line-height: 1;
  transition: transform 0.12s ease, color 0.12s ease;
}

@media (min-width: 64rem) {
  .door { padding: 1.9rem 1.9rem 1.7rem; }
  .door-figure { font-size: 2.6rem; }
}

/* The own-file door draws its percentage inside a ring: the completeness
   bar bent into a circle. pathLength=100 makes stroke-dasharray percent-
   based, so the template writes the server's integer into an attribute. */
.door-ring {
  position: relative;
  display: inline-grid;
  place-items: center;
  width: 4.9rem;
  height: 4.9rem;
  margin-bottom: 0.55rem;
}

.door-ring svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transform: rotate(-90deg);   /* the arc starts at 12 o'clock */
}

.door-ring circle { fill: none; stroke-width: 3; }

.door-ring-track { stroke: var(--line); }

.door-ring-fill {
  stroke: var(--grana);
  stroke-linecap: round;
}

.door-ring-fill.is-complete { stroke: var(--ok); }

.door-ring .door-figure {
  margin-bottom: 0;
  font-size: 1.4rem;
}

/* ── Dashboard: pendientes ──
   The action queue leads the dashboard, so it is the one panel per view that
   wears the accent: grana rail, kicker, a wash behind it. Rows stay
   semáforo-coloured — the accent frames the queue, never a status. Folded:
   the closed line is the whole panel until clicked. */
.card.pendientes {
  border-left: 3px solid var(--grana);
  background-image: linear-gradient(var(--grana-tint), transparent 4.5rem);
}

.card.pendientes:has(.pendientes-fold:not([open])) { padding: 0.95rem 1.3rem; }

.pendientes-fold > summary {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  cursor: pointer;
  list-style: none;
}

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

.pendientes-fold-label { margin: 0; }

.pendientes-fold-count {
  font-weight: 700;
  font-size: 0.9rem;
  font-variant-numeric: tabular-nums;
}

.pendientes-fold-caret { margin-left: auto; color: var(--muted); }

.pendientes-fold[open] .pendientes-fold-caret { transform: rotate(180deg); }

.pendientes-fold[open] > summary { margin-bottom: 0.45rem; }

.pendientes-list { margin: 0; }

.pendiente-row {
  display: flex;
  align-items: baseline;
  gap: 0.7rem;
  padding: 0.7rem 0.15rem;
  border-top: 1px solid var(--line-soft);
}

.pendiente-row:first-child { border-top: 0; }

.pendiente-dot {
  flex: 0 0 0.6rem;
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 50%;
  align-self: center;
}

.pendiente-dot.pill-warn { background: var(--warn); }
.pendiente-dot.pill-bad { background: var(--bad); }

.pendiente-body {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.15rem 0.6rem;
  min-width: 0;
}

.pendiente-action {
  font-weight: 600;
  text-decoration: none;
}

.pendiente-action:hover { text-decoration: underline; }

.pendiente-detail {
  color: var(--muted);
  font-size: 0.85rem;
}

.pendiente-go {
  margin-left: auto;
  align-self: center;
  color: var(--muted);
  font-size: 1.1rem;
  transition: transform 0.12s ease, color 0.12s ease;
}

.pendiente-row:hover .pendiente-go { color: var(--ink); transform: translateX(3px); }

.pendientes-clear {
  margin: 0.35rem 0 0.1rem;
  color: var(--muted);
}

.pendientes-clear-mark {
  margin-right: 0.3rem;
  color: var(--ok);
  font-weight: 700;
}

/* ── Dashboard: first run ──
   The one thing on an empty account worth reading; it removes itself as soon
   as that stops being true. Once a pendientes queue exists on the same page,
   the queue is the lead — two accent rails is none. */
.first-run { border-left: 3px solid var(--grana); }

.first-run:has(~ .pendientes) { border-left-color: var(--line); }

.first-run-steps { margin: 1rem 0 0; }

.first-run-step {
  display: flex;
  align-items: baseline;
  gap: 0.65rem;
  padding: 0.55rem 0;
  border-top: 1px solid var(--line-soft);
}

.first-run-step:first-child { border-top: 0; }

.first-run-mark {
  flex: 0 0 1.25rem;
  color: var(--ok);
  font-weight: 700;
  text-align: center;
}

.first-run-step-done .first-run-body > span:first-child { color: var(--muted); }

.first-run-body {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem;
}

.first-run-detail { font-variant-numeric: tabular-nums; }

/* ── Mi mes: materiality evidence ──
   A work queue, not a report: per client, what is still owed and where to
   drop it. Depth is carried by ONE edge per level — card, client (sunken),
   folder (rail), category (hairline) — never by a fourth box. */
.materiality-status {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem 1rem;
  margin-bottom: 1.25rem;
}

.materiality-progress {
  font-size: 0.9rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.client-evidence {
  margin-top: 1.1rem;
  padding: 1.1rem 1.25rem 1.25rem;
  border: 1px solid var(--line-soft);
}

.client-evidence-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1rem;
  margin-bottom: 0.9rem;
}

.client-evidence-head h3 {
  margin: 0;
  font-size: 1rem;
  letter-spacing: -0.01em;
}

/* A folder keeps the tab-like left edge and drops the other three sides;
   one with something outstanding takes the semáforo on that same edge. */
.evidence-folder {
  margin: 0.9rem 0 0;
  padding: 0.1rem 0 0.1rem 0.9rem;
  border-left: 2px solid var(--line);
}

.evidence-folder:first-of-type { margin-top: 0; }

.evidence-folder:has(.pill-warn) { border-left-color: var(--warn); }
.evidence-folder:has(.pill-bad) { border-left-color: var(--bad); }

.evidence-folder-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
  margin-bottom: 0.15rem;
}

.evidence-folder-head h4 {
  margin: 0;
  font-size: 0.95rem;
  letter-spacing: -0.01em;
}

.evidence-folder .evidence-hint { margin: 0 0 0.5rem; }

.evidence-categories { margin: 0; }

.evidence-category {
  padding: 0.75rem 0;
  border-top: 1px solid var(--line-soft);
}

.evidence-category:first-child { border-top: 0; padding-top: 0; }

.evidence-category-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
}

.evidence-category-name {
  font-size: 0.95rem;
  font-weight: 600;
}

/* State and count are one reading: the pill says green-or-not, the count
   says how far off. */
.evidence-count {
  margin-right: auto;
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}

.evidence-hint { margin: 0.2rem 0 0; }

.evidence-files { margin: 0.6rem 0 0; }

.evidence-files li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 0.65rem;
  padding: 0.35rem 0;
  font-size: 0.9rem;
}

.evidence-file-meta { font-size: 0.82rem; }

.evidence-upload {
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid var(--line);
}

/* Kind and file side by side: they are one decision. The kind picker gets
   the wider column because its options are full sentences. */
.evidence-upload-fields {
  display: grid;
  grid-template-columns: minmax(15rem, 1.25fr) minmax(12rem, 1fr);
  gap: 0.75rem 1rem;
}

@media (max-width: 44rem) {
  .evidence-upload-fields { grid-template-columns: 1fr; }
}

.evidence-upload .field-hint { margin-top: 0.5rem; }

.evidence-upload button[type="submit"]:not(.link-button) {
  margin-top: 0.9rem;
  min-width: 0;
  padding: 0.55rem 1.3rem;
  font-size: 0.9rem;
}

/* ── Mi mes: the defense-file list ──
   One row per client; the verb small and repeated because the client name
   is the only thing that differs between rows. */
.bundle-list { margin: 0.5rem 0 0; }

.bundle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.55rem 0;
  border-top: 1px solid var(--line);
}

.bundle-row:first-child { border-top: 0; }

/* ── Revisión: the legal review queue ──
   The summary is what the reviewer reads, at body weight and full measure;
   the machine metadata around it stays muted. The excerpt is the model's
   evidence for its own claim, set apart from its reading of it. */
.review-summary {
  margin: 0.6rem 0 0.9rem;
  white-space: pre-line;
}

.finding-list {
  margin: 0 0 0.9rem;
  display: grid;
  gap: 0.7rem;
}

.finding-list > li {
  margin: 0;
  padding: 0.7rem 0.85rem;
  background: var(--surface);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius);
}

.finding-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.6rem;
  margin-bottom: 0.35rem;
}

.finding-check { font-weight: 600; font-size: 0.95rem; }

.finding-quote { margin: 0.35rem 0 0; font-size: 0.85rem; }

.finding-quote q { font-style: italic; }

/* The case facts the model read sit folded under the summary: a reviewer who
   already knows the client opens them only to check what the model was told.
   The unevaluated list and the two notes stay open — silence must never read
   as a pass. */
.case-facts { margin: 0 0 0.9rem; }
.case-facts > summary { cursor: pointer; font-size: 0.9rem; }
.case-facts-list { margin: 0.4rem 0 0; padding-left: 1.2rem; font-size: 0.88rem; }
.case-facts-list > li { margin: 0.2rem 0; }
.case-facts-note { margin: 0 0 0.9rem; }
.case-facts-unevaluated { margin: 0 0 0.2rem; font-size: 0.9rem; }

.decision-form { max-width: 34rem; }

.decision-form label { font-size: 0.85rem; }

.decision-form input[type="text"] {
  margin-top: 0.25rem;
  padding: 0.5rem 0.65rem;
  font-size: 0.9rem;
}

.decision-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1rem;
  margin-top: 0.6rem;
}

.decision-actions button[type="submit"]:not(.link-button) {
  margin-top: 0;
  width: auto;
}

/* ── Contratos: the LFT art. 14 clause reading on a contract row ──
   Each clause states its verdict and quotes what the machine found: a
   verdict with no quote is an accusation. */
.clause-findings { margin: 0; }

.clause-finding {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4rem;
  padding: 0.45rem 0;
  border-top: 1px solid var(--line-soft);
}

.clause-finding:first-child { border-top: 0; }

.clause-name { font-weight: 600; }

.clause-reference { font-size: 0.85em; }

.clause-quote {
  flex-basis: 100%;
  margin: 0.25rem 0 0;
  padding-left: 0.6rem;
  border-left: 2px solid var(--line);
  color: var(--muted);
  font-style: italic;
  overflow-wrap: anywhere;
}

/* ── Document viewer ── */
/* The head stays pinned while the reader scrolls a canvas taller than the
   viewport: the ✕ is the way out and must never leave the screen. The page
   background (not a panel surface) keeps the pin invisible until it earns
   its keep. */
.viewer-head {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--page);
  padding: 0.4rem 0 0.6rem;
  margin-bottom: 0.4rem;
}

.viewer-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

/* The frame takes the viewport's height minus the chrome above it: a PDF
   you scroll the PAGE to read defeats viewing in place. */
.document-viewer-frame {
  width: 100%;
  height: 78vh;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-sunken);
}

.pdf-pager canvas {
  display: block;
  max-width: 100%;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: #ffffff;
}

.pdf-pager-controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  margin: 0 0 0.6rem;
}

.pdf-pager-controls button {
  padding: 0.45rem 1.1rem;
  font-size: 1.15rem;
  line-height: 1;
}

.pdf-pager-controls button:disabled {
  color: var(--muted);
  cursor: default;
  opacity: 0.5;
}

.pdf-page-indicator {
  min-width: 4.5rem;
  text-align: center;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}

/* ── Telegram link code: read off this screen, typed on a phone ── */
.telegram-link-code {
  margin: 0.6rem 0;
  font-family: var(--font-mono);
  font-size: 1.8rem;
  letter-spacing: 0.35rem;
}

/* ── Solicitar acceso: the front door ──
   The one form a stranger fills in before they are a customer, so it gets
   room and warmth the app's data-entry grids do not: the qualifying
   questions are cards and pills that can be read before they are chosen,
   and only the email is required — the top hint says so, and it is the
   page's single accent. */
main.public:has(.access-request-card) { max-width: 46rem; }

.access-request-card { padding: 1.6rem 1.75rem 1.9rem; }

.card > form.access-form {
  max-width: none;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.1rem 1.4rem;
  align-items: start;
}

.access-form-hint {
  grid-column: 1 / -1;
  margin: 0 0 0.2rem;
  padding: 0.6rem 0.85rem;
  font-size: 0.9rem;
  background: var(--grana-tint);
  border-left: 3px solid var(--grana);
  border-radius: var(--radius);
}

.access-form fieldset {
  grid-column: 1 / -1;
  margin: 0;
  padding: 0;
  border: 0;
  min-width: 0;
}

.access-form legend {
  display: block;
  padding: 0;
  margin-bottom: 0.45rem;
  font-size: 0.85rem;
  font-weight: 600;
}

.role-card-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.7rem;
}

/* The radio is the card: the input is visually hidden but keeps focus and
   keyboard behaviour; the card restates its state. */
.role-card {
  position: relative;
  display: flex;
  margin: 0;
  padding: 0.75rem 0.85rem;
  font-size: 0.85rem;
  font-weight: 500;
  line-height: 1.4;
  background: var(--field);
  border: 1px solid var(--line);
  border-radius: var(--radius-panel);
  cursor: pointer;
  transition: border-color 0.12s ease, background-color 0.12s ease;
}

.role-card input,
.band-option input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.role-card:hover { border-color: var(--muted); }

.role-card:has(input:checked) {
  border-color: var(--interactive);
  background: var(--hover);
  box-shadow: inset 0 0 0 1px var(--interactive);
  font-weight: 600;
}

.role-card:has(input:focus-visible),
.band-option:has(input:focus-visible) {
  outline: 2px solid var(--focus-ring);
  outline-offset: 1px;
  z-index: 1;
}

.access-field { min-width: 0; }

.access-field-required > label::after {
  content: " *";
  color: var(--muted);
}

.band-segment {
  display: inline-flex;
  flex-wrap: wrap;
}

.band-option {
  position: relative;
  margin: 0;
  padding: 0.5rem 1.1rem;
  font-size: 0.88rem;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  background: var(--field);
  border: 1px solid var(--line);
  border-left-width: 0;
  cursor: pointer;
  transition: background-color 0.12s ease, color 0.12s ease;
}

.band-option:first-child {
  border-left-width: 1px;
  border-radius: var(--radius) 0 0 var(--radius);
}

.band-option:last-child { border-radius: 0 var(--radius) var(--radius) 0; }

.band-option:hover { background: var(--hover); }

.band-option:has(input:checked) {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--primary-ink);
  font-weight: 600;
}

.access-note,
.access-submit { grid-column: 1 / -1; }

.access-submit button[type="submit"] { margin-top: 0.2rem; }

@media (max-width: 38rem) {
  .card > form.access-form { grid-template-columns: 1fr; }
  .role-card-row { grid-template-columns: 1fr; }
  .access-request-card { padding: 1.2rem 1.1rem 1.4rem; }
}

/* ── /verificar-repse and /diagnostico: the public tools ──
   One outcome block renders per submit; the rail colour IS the verdict, so
   the eye lands on vigente / por vencer / sin registro before reading a
   word. Colour lives where it means something — rail, chip, heading,
   vigencia — and the record sits on the same paper as the page. */
.verify-form { margin: 1.6rem 0 2rem; }

.verify-form-row {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 0.6rem;
}

.verify-form-row input {
  flex: 1 1 16rem;
  padding: 0.7rem 0.9rem;
  font-size: 1.02rem;
}

.verify-form-row button[type="submit"] {
  flex: 0 0 auto;
  margin-top: 0;
  min-width: 9.5rem;
}

@media (max-width: 34rem) {
  .verify-form-row button[type="submit"] { flex: 1 1 100%; }
}

.verify-form .field-hint {
  margin: 0.8rem 0 0;
  font-size: 0.88rem;
  color: var(--muted);
}

.diagnostico-form label {
  display: block;
  margin: 1rem 0 0.35rem;
  font-weight: 600;
}

.diagnostico-form label:first-child { margin-top: 0; }

.diagnostico-form button[type="submit"] { margin-top: 1.1rem; }

.verify-outcome {
  margin: 1.6rem 0;
  padding: 1.3rem 1.5rem 1.2rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 5px solid var(--line);
  border-radius: var(--radius-panel);
  box-shadow: var(--shadow);
}

.verify-outcome h2 { margin-top: 0; }

.verify-outcome-ok { border-left-color: var(--ok); }
.verify-outcome-warn { border-left-color: var(--warn); }
.verify-outcome-danger { border-left-color: var(--bad); }
.verify-outcome-neutral { border-left-color: var(--line); }

/* Headings are large enough (WCAG large-text 3:1) to carry the status
   colour the body text cannot. */
.verify-outcome-ok h2 { color: var(--ok); border-bottom-color: var(--ok-bg); }
.verify-outcome-warn h2 { color: var(--warn); border-bottom-color: var(--warn-bg); }
.verify-outcome-danger h2 { color: var(--bad); border-bottom-color: var(--bad-bg); }

.verify-status-chip {
  display: inline-block;
  margin: 0 0 0.55rem;
  padding: 0.14rem 0.65rem;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  border-radius: 999px;
}

.verify-outcome-ok .verify-status-chip { color: var(--ok); background: var(--ok-bg); }
.verify-outcome-warn .verify-status-chip { color: var(--warn); background: var(--warn-bg); }
.verify-outcome-danger .verify-status-chip { color: var(--bad); background: var(--bad-bg); }

.verify-verdict { font-size: 1.05rem; }

/* Provenance: who answered and when, answered before the data is read. */
.verify-source {
  margin: 0.9rem 0 1.2rem;
  padding: 0.6rem 0.9rem;
  font-size: 0.88rem;
  line-height: 1.5;
}

/* The registration as a ficha: label column in quiet caps, values in ink,
   the vigencia row carrying the verdict's colour and weight. */
.verify-ficha { margin: 0 0 0.4rem; }

.verify-ficha > div {
  display: grid;
  grid-template-columns: 11rem 1fr;
  gap: 0.2rem 1.2rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--line-soft);
}

.verify-ficha > div:last-child { border-bottom: 0; }

.verify-ficha dt {
  margin: 0;
  align-self: center;
  font-size: 0.76rem;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted);
}

.verify-ficha dd { margin: 0; font-weight: 500; }

.verify-ficha-vigencia dd {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.05rem;
}

.verify-outcome-ok .verify-ficha-vigencia dd { color: var(--ok); }
.verify-outcome-warn .verify-ficha-vigencia dd { color: var(--warn); }
.verify-outcome-danger .verify-ficha-vigencia dd { color: var(--bad); }

@media (max-width: 34rem) {
  .verify-ficha > div { grid-template-columns: 1fr; padding: 0.45rem 0; }
}

.verify-activities-heading { margin: 1.5rem 0 0.2rem; }

.verify-match-list { margin: 0; }

.verify-match-list li { margin: 0 0 0.5rem; }

.verify-match-button {
  width: 100%;
  padding: 0.65rem 0.9rem;
  font-size: inherit;
  font-weight: 600;
  text-align: left;
  white-space: normal;
  background: var(--surface);
}

/* The padrón numbers its own activities, so the list drops its marker and
   separates entries with hairlines: rows of a registry, not a bullet wall. */
.verify-activity-list { margin: 0.4rem 0 0; }

.verify-activity-list li {
  margin: 0;
  padding: 0.55rem 0;
  border-top: 1px solid var(--line-soft);
  font-size: 0.92rem;
}

.verify-activity-list li:first-child { border-top: 0; }

.verify-activities-hint { font-size: 0.9rem; color: var(--muted); }

.verify-evidence-line {
  margin-top: 1.2rem;
  padding-top: 0.7rem;
  border-top: 1px solid var(--line);
  font-size: 0.85rem;
  color: var(--muted);
}

.verify-followup {
  margin: 1.6rem 0;
  padding: 1.1rem 1.3rem;
  background: var(--surface);
  border: 2px solid var(--grana);
  border-radius: var(--radius);
}

.verify-followup h2 {
  padding-bottom: 0;
  border-bottom: 0;
}

.verify-followup .hero-cta { display: inline-block; margin-top: 0.4rem; }

/* "Sobre esta herramienta" and "Más guías": the article's secondary
   sections, kicker over hairline, one family. */
.verify-about,
.guide-related {
  margin-top: 3rem;
  padding-top: 1.1rem;
  border-top: 1px solid var(--line);
}

.verify-about > h2,
.guide-related > h2 { margin-bottom: 0.35rem; }

.verify-about p { font-size: 0.92rem; color: var(--muted); }

/* ── The guide library (/guias) and the wiki: article surfaces ── */
.guide-main {
  max-width: var(--measure-prose);
  margin: 0 auto;
  padding: 1.5rem 1.25rem 3rem;
}

/* guide-main is not a flex column, so the seal takes its air explicitly. */
.guide-main .page-seal { margin-top: 1.5rem; }

.guide-breadcrumb {
  margin: 0.7rem 0 1.8rem;
  font-size: 0.85rem;
  color: var(--muted);
}

.guide-breadcrumb a { color: var(--muted); }

.guide-article h1 {
  margin: 0 0 1rem;
  font-size: clamp(1.7rem, 4vw, 2.4rem);
}

.guide-article h2 {
  margin: 2.2rem 0 0.7rem;
  font-size: 1.3rem;
}

.guide-article p,
.guide-article li { line-height: 1.65; }

/* The lede holds a book measure rather than the full column, so the head
   keeps a visible hierarchy: title wide, standfirst narrower. */
.guide-lede {
  max-width: 40rem;
  font-size: 1.12rem;
}

.guide-callout {
  margin: 1.4rem 0;
  padding: 0.9rem 1.1rem;
  background: var(--surface);
  border-left: 4px solid var(--grana);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.guide-note { font-size: 0.9rem; color: var(--muted); }

/* The obra vignette: the construction page's engraved certificate scene,
   inked from currentColor like the seal. Its caption borrows the muted
   kicker (grouped above); only placement is stated here. */
.obra-vignette {
  margin: 1.7rem 0 0.5rem;
  color: var(--muted);
}

.obra-vignette svg { display: block; width: 100%; height: auto; }

.obra-vignette figcaption { margin: 0.55rem 0 0; text-align: center; }

.guide-steps li { margin-bottom: 0.7rem; }

.guide-table {
  width: 100%;
  margin: 1rem 0 1.4rem;
  border-collapse: collapse;
}

.guide-table th,
.guide-table td {
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--line);
  text-align: left;
  vertical-align: top;
  line-height: 1.5;
}

.guide-table thead th {
  background: var(--vino-profundo);
  color: var(--papel-on-wine);
}

.guide-table tbody tr:nth-child(even) { background: var(--surface); }

/* The related-reading rail: rows of a small index, a marker that points
   forward, a hairline between them. */
.guide-related ul { margin: 0; }

.guide-related li {
  margin: 0;
  border-top: 1px solid var(--line-soft);
}

.guide-related li:first-child { border-top: 0; }

.guide-related a {
  display: flex;
  align-items: baseline;
  gap: 0.55rem;
  padding: 0.6rem 0.1rem;
  font-weight: 600;
  text-decoration: none;
}

.guide-related a::before {
  content: "→";
  flex: 0 0 auto;
  color: var(--muted);
  transition: transform 0.12s ease, color 0.12s ease;
}

.guide-related a:hover { text-decoration: underline; }

.guide-related a:hover::before {
  color: var(--grana);
  transform: translateX(3px);
}

/* /guias: the library's title page. The live tool leads as the one raised
   instrument; the guides are the índice of a bound expediente — ruled rows,
   roman folios in grana, Garamond titles. */
.guide-tool-card { margin: 1.9rem 0 0; }

.guide-tool-card h2 {
  margin: 0 0 0.4rem;
  padding: 0;
  border-bottom: 0;
  font-size: 1.35rem;
  color: var(--ink);
}

.guide-tool-desc {
  margin: 0 0 0.7rem;
  color: var(--muted);
  line-height: 1.55;
}

.guide-card-more {
  color: var(--grana);
  font-weight: 600;
  font-size: 0.92rem;
}

.guide-tool-card:hover h2 { color: var(--grana); }

.guide-tool-card:hover .guide-card-more {
  text-decoration: underline;
  text-underline-offset: 3px;
}

.guide-toc { margin-top: 2.7rem; }

.guide-toc-list {
  margin: 0;
  counter-reset: guia;
}

.guide-toc-list li {
  margin: 0;
  counter-increment: guia;
  border-top: 1px solid var(--line-soft);
}

.guide-toc-list li:first-child { border-top: 0; }

.guide-toc-list a {
  display: grid;
  grid-template-columns: 2.8rem 1fr;
  padding: 1.05rem 0.2rem;
  text-decoration: none;
}

/* The folio numeral spans both rows of its entry, like the margin numbering
   of a bound index. */
.guide-toc-list a::before {
  content: counter(guia, upper-roman) ".";
  grid-row: 1 / span 2;
  font-family: var(--font-display);
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.25;
  color: var(--grana);
}

.guide-toc-title {
  font-family: var(--font-display);
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.25;
  color: var(--ink);
}

.guide-toc-desc {
  grid-column: 2;
  margin-top: 0.3rem;
  color: var(--muted);
  font-size: 0.95rem;
  line-height: 1.55;
}

.guide-toc-list a:hover .guide-toc-title { color: var(--grana); }

/* The FAQ: marker suppressed, a chevron at the end of the row that turns
   when the answer opens, the answer under a hairline. */
.guide-faq-item {
  margin-bottom: 0.6rem;
  padding: 0.1rem 1.1rem;
  background: var(--surface);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.guide-faq-item summary {
  display: flex;
  align-items: baseline;
  gap: 1rem;
  padding: 0.8rem 0;
  cursor: pointer;
  list-style: none;
  font-weight: 600;
  color: var(--ink);
}

.guide-faq-item summary::-webkit-details-marker { display: none; }

.guide-faq-item summary::after {
  content: "＋";
  flex: 0 0 auto;
  margin-left: auto;
  color: var(--muted);
  font-weight: 400;
  transition: color 0.12s ease;
}

.guide-faq-item summary:hover,
.guide-faq-item summary:hover::after,
.guide-faq-item[open] summary { color: var(--interactive); }

.guide-faq-item[open] summary::after { content: "－"; color: var(--grana); }

.guide-faq-item[open] > p {
  padding-top: 0.75rem;
  border-top: 1px solid var(--line-soft);
}

.guide-faq-item p { margin: 0; padding-bottom: 0.9rem; }

/* ── The landing sheet: everything between the hero and the CTA band is one
   paper document — numbered clauses, rail-marked parties, the statute line,
   the seal. ── */
.landing-sheet {
  padding-bottom: 0.5rem;
  background: var(--page);
  color: var(--ink);
}

.landing-section {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 3.5rem 1.5rem 0;
}

/* A document's section head: the kicker with the rule running to the margin. */
.sheet-kicker {
  display: flex;
  align-items: center;
  gap: 1.1rem;
  margin-bottom: 1.7rem;
  letter-spacing: 0.16em;
}

.sheet-kicker::after {
  content: "";
  flex: 1;
  border-top: 1px solid var(--line);
}

/* Each capability is a numbered clause: hairline over, roman numeral in
   grana, Garamond head, quiet body. */
.pillars {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 2.2rem 3rem;
  counter-reset: clause;
}

.pillar {
  padding-top: 1.1rem;
  border-top: 1px solid var(--line);
  counter-increment: clause;
}

/* A card's title is a title, not a panel head: no hairline under it. The
   h3 is the same gesture one level down: a pillar row that sits under a
   section h2 (the construction page) keeps the heading order honest. */
.pillar h2,
.pillar h3,
.side-card h2 {
  margin-bottom: 0.45rem;
  padding-bottom: 0;
  border-bottom: 0;
}

.pillar h2,
.pillar h3 { font-size: 1.3rem; }

.pillar h2::before,
.pillar h3::before {
  content: counter(clause, upper-roman) ".";
  margin-right: 0.5rem;
  color: var(--grana);
}

.pillar p,
.side-card p {
  margin: 0;
  font-size: 0.95rem;
  line-height: 1.65;
  color: var(--muted);
}

.sides {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
  gap: 2rem 3rem;
}

/* The two parties, each held by a grana rail in the binding margin. */
.side-card {
  padding: 0.2rem 0 0.2rem 1.3rem;
  border-left: 3px solid var(--grana);
}

.side-card h2 { font-size: 1.2rem; }

/* The instrument names its statutes before it is sealed. */
.legal-basis-line {
  max-width: 44rem;
  margin: 0 auto;
  padding: 3.2rem 1.5rem 0;
  text-align: center;
  font-family: var(--font-display);
  font-style: italic;
  font-size: 1.05rem;
  color: var(--muted);
}

.landing-sheet .page-seal {
  margin: 0;
  padding: 2.6rem 1.5rem 3.2rem;
}

/* The link between a section and its English twin. Deliberately quiet: it
   sits under the h1 as a note about the document, not as navigation. */
.wiki-lang-switch {
  margin: -0.4rem 0 1.4rem;
  font-family: var(--font-ui);
  font-size: 0.88rem;
  color: var(--muted);
}

/* ── Wiki: the índice of a long section, two columns where there is room ── */
.wiki-toc {
  margin: 1.6rem 0 2rem;
  padding: 0.2rem 0 0.9rem;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.wiki-toc > h2 { margin: 0.9rem 0 0.6rem; }

.wiki-toc ol {
  margin: 0;
  padding-left: 1.4rem;
  columns: 2;
  column-gap: 2rem;
}

.wiki-toc li {
  margin: 0 0 0.35rem;
  break-inside: avoid;
  font-size: 0.93rem;
  line-height: 1.4;
}

@media (max-width: 34rem) { .wiki-toc ol { columns: 1; } }

/* ── Wiki diagrams: the law drawn as a system ──
   One notation for every figure: a NODE is a box with a kicker and a body,
   an EDGE the labelled line between two nodes, a CLOCK the chip naming a
   statutory term, an OPEN marker what the corpus does not settle. The
   semáforo keeps its status meaning; an unresolved question is a dashed
   muted rule, never amber. */
.diagram-figure { margin: 1.6rem 0 1.9rem; }

/* A systems diagram needs the page, not the book measure, so it breaks out
   of the article column on wide screens and scrolls inside itself on narrow. */
@media (min-width: 60rem) {
  .diagram-figure {
    width: min(56rem, 90vw);
    margin-left: calc(50% - min(56rem, 90vw) / 2);
  }
}

/* Wide content scrolls inside its own box; the page body never scrolls
   sideways. A three-column legal table hits this on a phone exactly as a
   diagram does, so both names share the one rule. */
.diagram-scroll,
.table-scroll { overflow-x: auto; }
.diagram-scroll > svg { display: block; width: 100%; min-width: 40rem; height: auto; }
.diagram-scroll > table { min-width: 46rem; }

.diagram-caption {
  margin: 0.55rem 0 0;
  padding-top: 0.5rem;
  border-top: 1px solid var(--line-soft);
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--muted);
}

.diagram-flow { margin: 0; }
.diagram-flow > li { margin: 0; }

.diagram-node {
  padding: 0.7rem 0.9rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 4px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.diagram-node > h3 {
  margin: 0;
  font-size: 1.05rem;
  line-height: 1.3;
}

.diagram-node > p {
  margin: 0.3rem 0 0;
  font-size: 0.93rem;
  line-height: 1.55;
}

.diagram-node-kicker {
  display: block;
  margin-bottom: 0.15rem;
  font-size: 0.68rem;
}

.diagram-node--accent { border-left-color: var(--grana); background: var(--grana-tint); }
.diagram-node--ok { border-left-color: var(--ok); background: var(--ok-bg); }
.diagram-node--warn { border-left-color: var(--warn); background: var(--warn-bg); }
.diagram-node--bad { border-left-color: var(--bad); background: var(--bad-bg); }

/* The connector: a rule with an arrowhead and room for the label that says
   WHY the flow moves. */
.diagram-edge {
  position: relative;
  margin: 0;
  padding: 0.45rem 0 0.45rem 1.7rem;
  font-size: 0.85rem;
  line-height: 1.45;
  color: var(--muted);
}

.diagram-edge::before {
  content: "";
  position: absolute;
  left: 0.6rem;
  top: 0;
  bottom: 0;
  border-left: 2px solid var(--line);
}

.diagram-edge::after {
  content: "";
  position: absolute;
  left: 0.25rem;
  bottom: -1px;
  border: 5px solid transparent;
  border-bottom: 0;
  border-top-color: var(--line);
}

.diagram-clock {
  display: inline-block;
  padding: 0.1rem 0.5rem;
  font-family: var(--font-ui);
  font-size: 0.73rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface-sunken);
  color: var(--ink);
  white-space: nowrap;
}

/* Statutory terms wear the wine, so a reader can tell which clocks come
   from the text and which we invented. */
.diagram-clock--statutory {
  background: var(--vino-profundo);
  border-color: var(--vino-profundo);
  color: var(--papel-on-wine);
}

.diagram-open {
  display: block;
  margin-top: 0.5rem;
  padding-left: 0.65rem;
  border-left: 2px dashed var(--line);
  font-size: 0.86rem;
  line-height: 1.5;
  color: var(--muted);
}

.diagram-open strong { color: var(--ink); }

.diagram-columns {
  display: grid;
  gap: 0.85rem;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  margin: 1rem 0;
}

.diagram-layers {
  display: grid;
  gap: 0.55rem;
  margin: 1.1rem 0 1.4rem;
  counter-reset: diagram-layer;
}

.diagram-layers > li {
  position: relative;
  margin: 0;
  padding-left: 2.5rem;
}

.diagram-layers > li::before {
  counter-increment: diagram-layer;
  content: counter(diagram-layer);
  position: absolute;
  left: 0;
  top: 0.5rem;
  display: grid;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 50%;
  background: var(--vino-profundo);
  color: var(--papel-on-wine);
  font-family: var(--font-ui);
  font-size: 0.82rem;
  font-weight: 600;
}

/* SVG only where the flow genuinely branches; these classes let one drawing
   read the tokens. */
.diagram-svg-node { fill: var(--surface); stroke: var(--line); stroke-width: 1.2; }
.diagram-svg-node--accent { fill: var(--grana-tint); stroke: var(--grana); }
.diagram-svg-node--ok { fill: var(--ok-bg); stroke: var(--ok); }
.diagram-svg-node--warn { fill: var(--warn-bg); stroke: var(--warn); }
.diagram-svg-node--bad { fill: var(--bad-bg); stroke: var(--bad); }

.diagram-svg-title {
  fill: var(--ink);
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: 600;
}

.diagram-svg-text { fill: var(--ink); font-family: var(--font-ui); font-size: 12px; }
.diagram-svg-muted { fill: var(--muted); font-family: var(--font-ui); font-size: 11.5px; }

.diagram-svg-edge { fill: none; stroke: var(--line); stroke-width: 1.6; }
.diagram-svg-edge--dashed { stroke-dasharray: 5 4; }
.diagram-svg-arrow { fill: var(--line); stroke: none; }

.diagram-svg-edge-label {
  fill: var(--muted);
  font-family: var(--font-ui);
  font-size: 11px;
}

/* ── The problem sheet (404, 403, 400, 405, 409, 500, 503) ──
   The status set as a rubber stamp: an office seal is what a refused
   document wears in the world this product lives in. The view's one grana. */
.problem-sheet {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 1.4rem 1.9rem;
  padding: 2rem 1.9rem 2.1rem;
}

.problem-stamp {
  flex: 0 0 auto;
  padding: 0.55rem 1.05rem 0.6rem;
  border: 2px solid currentColor;
  box-shadow: inset 0 0 0 1px currentColor;   /* security printing doubles every frame */
  border-radius: 5px;
  color: var(--grana);
  text-align: center;
  transform: rotate(-4deg);                   /* stamped, not printed */
  opacity: 0.92;
}

.problem-stamp-code {
  display: block;
  font-family: var(--font-display);
  font-size: 3.1rem;
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.01em;
}

.problem-stamp-label {
  display: block;
  margin-top: 0.28rem;
  font-family: var(--font-ui);
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.17em;
  text-transform: uppercase;
}

/* 18rem is the narrowest the prose stays readable at; below that the stamp
   sits above the text, which is the phone layout and the logged-out one. */
.problem-body { flex: 1 1 18rem; min-width: 0; }

.problem-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 1.3rem;
  margin: 1.3rem 0 0;
}

.problem-contact { margin: 0.9rem 0 0; }

/* ── Obra registrada (SIROC) capture ──
   The portal only asks the CompraNet number of obra pública, so the field
   folds away while the class select says privada. One rule, :has-gated on
   purpose: an engine without :has() simply always shows the field (its hint
   says to leave it empty), and the server refuses privada + número either
   way. */
form.siroc-registration-form:has(select[name="work_class"] option[value="privada"]:checked) .field-only-obra-publica {
  display: none;
}

/* ── Tablero de proveedores ──
   RECSA's one-screen ask. The tiles borrow the door figures' display face;
   a tile at zero renders quiet (faint figure, no dot) because color belongs
   only to the states that have work. Pills, chips and the completeness
   track are the shared §9 gestures, restated nowhere. */
.tablero-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
  gap: 1rem;
  margin: 0 0 1.1rem;
}

.tablero-tile {
  padding: 1rem 1.2rem 0.9rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-panel);
}

.tablero-tile-figure {
  display: block;
  margin-bottom: 0.3rem;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 2rem;
  line-height: 1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}

.tablero-tile.is-zero .tablero-tile-figure { color: var(--muted); font-weight: 600; }

.tablero-tile-label {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  color: var(--muted);
  font-size: 0.85rem;
}

.tablero-tile-dot {
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 50%;
  flex-shrink: 0;
}

.tablero-tile-dot.pill-ok { background: var(--ok); }
.tablero-tile-dot.pill-warn { background: var(--warn); }
.tablero-tile-dot.pill-bad { background: var(--bad); }

/* Count and clear are one pill: the inverted surface says "clickable", the
   ✕ says what the click does — ending the filtered state. */
.tablero-filter-clear {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.12rem 0.6rem;
  border-radius: 999px;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--page);
  background: var(--ink);
  text-decoration: none;
  white-space: nowrap;
}

/* ── Semáforo de cartera (the band on /proveedores) ──
   RECSA's "de 100 proveedores, 90 en verde" on the list itself: a headline
   in the display face, one stacked bar, and the four states as legend and
   filter chips in the shared §9 pills. The bar's fills are the pill tokens;
   a 2px surface stroke painted UNDER each fill is the gap between segments,
   so red beside amber never reads as one block (the labelled chips, not the
   colour, carry identity). Light only, like everything else. */
.semaforo-band {
  margin: 0 0 1.1rem;
  padding: 1rem 1.2rem 0.9rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-panel);
}

.semaforo-band-headline {
  margin: 0 0 0.7rem;
  font-family: var(--font-display);
  font-size: 1.15rem;
  letter-spacing: -0.01em;
}

.semaforo-band-headline strong {
  font-size: 1.7rem;
  font-weight: 700;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.semaforo-band-track {
  line-height: 0;
  border-radius: 999px;
  overflow: hidden;
  background: var(--page);
}

.semaforo-band-bar { display: block; width: 100%; height: 12px; }

.semaforo-band-seg {
  stroke: var(--surface);
  stroke-width: 2px;
  paint-order: stroke;
}

.semaforo-band-seg.pill-ok { fill: var(--ok); }
.semaforo-band-seg.pill-warn { fill: var(--warn); }
.semaforo-band-seg.pill-bad { fill: var(--bad); }
.semaforo-band-seg.pill-neutral { fill: var(--line); }

.semaforo-band-legend { margin: 0.75rem 0 0; }

.semaforo-band-legend a.pill { text-decoration: none; }

.semaforo-band-legend .pill.is-selected {
  outline: 2px solid var(--ink);
  outline-offset: 1px;
}

.semaforo-band-pending { font-size: 0.8rem; }

.tablero-progress { margin: 0.35rem 0 0; min-width: 8.5rem; }

.tablero-progress .expediente-progress-label { font-variant-numeric: tabular-nums; }

.tablero-risk-lines {
  margin: 0;
  display: grid;
  gap: 0.3rem;
  font-size: 0.85rem;
  color: var(--bad);
  max-width: 26rem;
}

/* ═══ 11. Print ══════════════════════════════════════════════════════════
   A printed expediente is what an inspector is handed, so printing is a
   product surface. Everything here is either "this is chrome, it does not
   belong on paper" or "this must survive a printer that drops backgrounds". */
@media print {
  :root {
    --page: #ffffff;
    --surface: #ffffff;
    --surface-sunken: #ffffff;
    --field: #ffffff;
    --hover: transparent;
    --shadow: none;
    --muted: #4a5751;
    --line: #b4b4ac;
    --line-soft: #d2d2c8;
    --ok: #1f6b40;
    --warn: #8a5606;
    --bad: #97281a;
  }

  @page { margin: 16mm 14mm; }

  body { background: #fff; font-size: 10.5pt; }

  main { max-width: none; padding: 0; }

  /* Navigation, controls and anything that only makes sense to a cursor. */
  .app-header,
  .section-nav,
  .guide-top,
  .cta-band,
  .view-tabs,
  .carpeta-nav,
  .switcher,
  .link-button,
  button[type="submit"],
  .hero-cta,
  .evidence-upload,
  .dropzone,
  .inline-form,
  .waive-disclosure,
  .field-hint,
  .door-go,
  .pendiente-go { display: none; }

  /* Flat on paper: panel borders are ink for nothing once each panel is a
     block of text on white. The semáforo rail is the one border that means
     something, and even it goes — the pill carries the state. */
  .card {
    margin-top: 1.4rem;
    padding: 0;
    background: none;
    border: 0;
    border-radius: 0;
  }

  .card:has(.pill-warn),
  .card:has(.pill-bad),
  .card:has(.notice-error) { border-left: 0; }

  /* A record, a document row or a folder is one thing; a page break through
     the middle of one is what makes a printed expediente look unreliable. */
  .roster tr,
  .client-evidence,
  .evidence-folder,
  .evidence-category,
  .finding-list > li,
  .door,
  .pendiente-row { break-inside: avoid; }

  h1, h2, h3, h4 { break-after: avoid; }

  /* A pill's meaning is its fill, and a printer drops fills by default. */
  .pill,
  .notice,
  .expediente-progress-fill,
  .card:has(> p.muted:only-child) > p.muted::before { print-color-adjust: exact; -webkit-print-color-adjust: exact; }

  a { color: var(--ink); text-decoration: none; }

  /* The legal citation is the reason a document is in the file, so on paper
     it is stated rather than offered: the reference always prints, and where
     the browser lets a stylesheet open a closed disclosure, so does the text. */
  details::details-content { content-visibility: visible; }

  details.legal-basis > summary { text-decoration: none; }

  details.legal-basis[open] { background: none; padding-left: 0.6rem; }
}

/* SIROC calendar, a superseded obligation (ledger step 5b): the old row is
   lineage, struck through beside its successor; its estado pill says when
   it was replaced and when the successor is due. */
.is-superseded td { text-decoration: line-through; color: var(--muted); }
.is-superseded td .pill { text-decoration: none; }
