/* Atelier · app/public/app.css — the visual system (S-24 §5 UI-0).
 *
 * ONE static stylesheet, custom-property tokens, no preprocessor (S-24 AC-S1 / S-2 §4: a served
 * asset like index.html itself, not a frontend dependency — no build step, no CDN). This is the
 * CONTRACT §5 describes: a spacing scale, a type scale, color roles (RED reserved exclusively for
 * owed/overdue/failure semantics — the radar's meaning must stay unmistakable), and the component
 * classes (nav / card / table / badge / form-grid / empty-state) the pure views adopt.
 *
 * UI-0 SCOPE (class adoption only, no recomposition — that is UI-1+): this sheet defines every
 * token and component named in §5. The existing pure views (views.mjs) adopt `form-grid` on every
 * form that carries a visible label, `card` on every top-level section, `badge` on status/verdict
 * spans, `empty-state` on the calm empty paragraphs, and `red` on every failure/error surface. The
 * `nav` and `table` components are defined here ready for UI-1 (the shell/router) and UI-2/UI-3
 * (the recomposed list/detail tables) to adopt onto the elements they introduce.
 */

:root {
  color-scheme: light dark;
  font-family: system-ui, sans-serif;

  /* spacing scale (base 0.5rem) */
  --s1: 0.5rem;
  --s2: 1rem;
  --s3: 1.5rem;
  --s4: 2rem;

  /* type scale: page title / section title / body / meta */
  --text-title: 1.5rem;
  --text-section: 1.17rem;
  --text-body: 1rem;
  --text-meta: 0.85rem;

  /* color roles — RED is reserved EXCLUSIVELY for owed/overdue/failure semantics (S-24 AC-S1) */
  --bg: #ffffff;
  --surface: #f6f7f9;
  --border: #d9dde2;
  --text: #1a1d21;
  --text-muted: #6b7280;
  --accent: #2563eb;
  --red: #b00020;
  --green: #1a7f37;
  --amber: #b45309;

  /* touch target — the ONE declared floor every interactive control meets, at EVERY viewport
     (G_A-72 AC-1). It is a TOKEN, not a literal repeated per control, so "the touch target the CSS
     declares" has a single source the paired verification reads rather than a number it re-states.
     44px is the smallest target a finger hits reliably; the floor is not narrowed on a phone — a
     phone is exactly where it matters. */
  --touch: 44px;
}

/* ── theme — the member's own choice, stamped as `data-theme` on <html> (G_A-104) ────────────────
 * The palette above is the LIGHT theme; this block is the DARK one, and it is the ONE place the dark
 * values are stated. The `@media (prefers-color-scheme: dark)` copy that used to hold them is
 * deliberately GONE rather than kept alongside: the entry resolves the OS preference exactly once at
 * boot (i18n.mjs `preferencesFrom`) and stamps the resolved theme onto the root element, so a media
 * query would be a second store of this same palette — one that drifts the first time a token moves,
 * and one that would silently outrank a member who chose light on a dark-set laptop. The cockpit
 * renders entirely from JS (there is no server-rendered paint), so nothing is lost by resolving in JS.
 *
 * `color-scheme` travels with the tokens so the browser's OWN chrome — form controls, scrollbars, the
 * canvas behind an overscroll — follows the theme instead of fighting it. */

:root[data-theme='light'] {
  color-scheme: light;
}

:root[data-theme='dark'] {
  color-scheme: dark;
  --bg: #14161a;
  --surface: #1c1f24;
  --border: #30343b;
  --text: #e7e9ec;
  --text-muted: #9aa1ab;
  --accent: #60a5fa;
  --red: #ff6b6b;
  --green: #4ade80;
  --amber: #fbbf24;
}

/* ── base + hierarchy rules (§5: one h1-equivalent per view, section-title for sections, meta for
   counts/dates/actors) ─────────────────────────────────────────────────────────────────────── */

body {
  margin: 0;
  padding: var(--s3);
  line-height: 1.5;
  background: var(--bg);
  color: var(--text);
  /* a long unbroken token (a URL pasted into `próximo paso`, a client name with no spaces) is the
     one non-tabular way prose can push the page wider than the viewport — it breaks instead
     (G_A-72 AC-1). This is NOT the cure for wide TABLES: those genuinely cannot shrink, so they get
     their own scroll box (.table-scroll) rather than mangled columns. */
  overflow-wrap: break-word;
}

h1 {
  font-size: var(--text-title);
  margin: 0 0 var(--s2);
}

h2 {
  font-size: var(--text-section);
  margin: var(--s3) 0 var(--s2);
}

h3 {
  font-size: var(--text-section);
  margin: 0 0 var(--s2);
}

.meta {
  font-size: var(--text-meta);
  color: var(--text-muted);
}

section {
  margin: var(--s3) 0;
}

/* ── color roles as checkable classes — RED is the radar's own semantic (AC-S1) ────────────────── */

.red {
  color: var(--red);
  font-weight: 600;
}

.green {
  color: var(--green);
}

.amber {
  color: var(--amber);
}

/* every *-error surface across the pure views carries this class alongside its own (S-24 AC-S1:
   failure is a RED semantic, never a styling nuance the human has to notice unaided) */
.form-error {
  color: var(--red);
  font-size: var(--text-meta);
}

/* ── nav — the shell component (adopted by UI-1's router/nav header) ───────────────────────────── */

.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* WRAP, not scroll (G_A-72 AC-1): the shell's four destinations + the session line + Salir do not
     fit across 390px, and a nav is not wide content that "cannot shrink" — it is a list, so it
     reflows onto a second line. Without this the nav is the single widest box on the page and the
     BODY scrolls, which is exactly what AC-1 forbids. */
  flex-wrap: wrap;
  gap: var(--s2);
  padding: var(--s2) var(--s3);
  margin: 0 0 var(--s3);
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}

.nav .nav-active {
  color: var(--accent);
  font-weight: 600;
}

/* the destinations themselves (UI-1 adopts .nav onto the shell it introduces). They are real anchors,
   so the list chrome is reset here rather than worked around in the view. */
.nav-brand {
  font-weight: 600;
}

.nav-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s3);
  list-style: none;
  margin: 0;
  padding: 0;
}

.nav-link {
  color: var(--text-muted);
  text-decoration: none;
}

/* ── the two preference toggles in the shell (G_A-104) ─────────────────────────────────────────
   A segmented pair per axis: the chosen option carries the accent the active destination carries, so
   "where I am" and "what I chose" speak one visual language. The buttons inherit the --touch floor
   from the bare `button` selector below, so a thumb reaches them at every viewport. */

.nav-prefs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
}

.nav-pref-group {
  display: flex;
  gap: var(--s1);
}

.nav-pref {
  padding: 0 var(--s2);
  font-size: var(--text-meta);
  color: var(--text-muted);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 4px;
  cursor: pointer;
}

/* The CHOSEN option, and it must be unmistakable: a segmented control whose two halves look alike is
   a control that never tells the member what is currently on. Colour is not the only carrier (weight
   and border move too), so the state survives a member who cannot distinguish the two hues. */
.nav-pref.pref-active {
  color: var(--accent);
  border-color: var(--accent);
  font-weight: 600;
}

/* The STANDALONE link controls — a nav destination, the project name that opens its detail, and the
   two "volver" back-links. Each is a thing the member AIMS AT, not prose they read. An INLINE box
   ignores min-height, so the touch floor below would be INERT on a bare <a>; giving them a flex box
   is what makes the declared floor real rather than decorative. (G_A-72 AC-1) */

.nav-link,
.project-card-link,
.project-detail-link,
.project-detail-not-found-back,
.not-found-home,
/* the specifications download link (A6 / G_C-61) — a file the member AIMS AT, so it takes the same
   inline-flex box its siblings do, without which the touch floor below is inert on a bare <a>. */
.specification-download {
  display: inline-flex;
  align-items: center;
}

/* ── touch targets — every interactive control meets --touch (G_A-72 AC-1) ─────────────────────
   ONE rule, ONE token: a control the member must hit with a thumb (a destination, a back-link, a
   transition button, the blocked-successor disclosure, every form field) is at least --touch tall.
   Stated at the base layer rather than inside the narrow media query on purpose: a target too small
   for a finger is too small on a tablet too, and a floor that only exists below a breakpoint is a
   floor nobody can assert. The paired verification reads THIS selector list and cross-checks it
   against every interactive element the views actually render — so a control added without a home
   in this list reds, rather than quietly shipping under the floor. */

button,
summary,
.nav-link,
.project-card-link,
.project-detail-link,
.project-detail-not-found-back,
.not-found-home,
.specification-download,
.form-grid label > input,
.form-grid label > select,
.form-grid label > textarea {
  min-height: var(--touch);
}

/* ── hover is an ENHANCEMENT, never the way to reach an action (G_A-72 AC-1) ───────────────────
   Every :hover rule in this sheet lives inside `@media (hover: hover)`. On a touch device :hover
   either never fires or STICKS to the last-tapped element, so a hover-gated affordance is either
   invisible or wrong there. The paired verification asserts BOTH halves: that no :hover rule sits
   outside this block, and that no :hover rule discloses content (display/visibility/opacity) —
   the machine-checkable form of "every action reachable without hover". `:focus-visible` below is
   the keyboard/switch equivalent that does NOT depend on a pointer at all. */

@media (hover: hover) {
  .nav-link:hover {
    color: var(--text);
  }

  .table tbody tr:hover {
    background: var(--surface);
  }

  /* underline on hover is a pure ENHANCEMENT: the link is already distinguished by --accent and is
     reachable without hovering, so nothing is disclosed here (no display/visibility/opacity). */
  .project-card-link:hover {
    text-decoration: underline;
  }
}

button:focus-visible,
summary:focus-visible,
.nav-link:focus-visible,
.project-card-link:focus-visible,
.project-detail-link:focus-visible,
.project-detail-not-found-back:focus-visible,
.not-found-home:focus-visible,
.specification-download:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ── route — the one view family rendered below the shell (S-24 AC-N1) ─────────────────────────── */

.route {
  display: block;
}

/* the pre-UI-1 `.app-header` rule is RETIRED here, in the same change that retired the header itself:
   `appView` now renders `.nav` (the shell) in its place, so the rule styled nothing. */

/* ── card — surface + border + radius + padding (S-24 §5) ──────────────────────────────────────── */

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0.5rem;
  padding: var(--s3);
  margin: var(--s3) 0;
}

/* ── table — real <table>, header row, row hover, consistent alignment (adopted by UI-2/UI-3) ──── */

.table {
  width: 100%;
  border-collapse: collapse;
}

.table th,
.table td {
  padding: var(--s1) var(--s2);
  border-bottom: 1px solid var(--border);
  text-align: left;
}

.table th {
  font-size: var(--text-meta);
  color: var(--text-muted);
  font-weight: 600;
}

.table td.numeric,
.table th.numeric {
  text-align: right;
}

/* ── archived rows — MUTED, never RED (S-27 RM-F) ──────────────────────────────────────────────
   An archived task is still there and still restorable (nothing vanishes from an append-only
   cockpit), but it owes nothing — so it must recede, not shout. RED is reserved EXCLUSIVELY for
   owed/overdue/failure semantics (AC-S1), and an archived row is the precise opposite of owed;
   painting it red would say the reverse of the truth. Muted text is the whole treatment: the row
   keeps its columns, its controls and its restore, and simply stops competing for attention with
   the work that is actually outstanding. */
.project-task-archived {
  color: var(--text-muted);
}

.project-task-archived-marker {
  margin-left: var(--s1);
  font-size: var(--text-meta);
  color: var(--text-muted);
}

/* ── table-scroll — the OWN container wide tabular content scrolls inside (G_A-72 AC-2) ────────
   The timetables are the one surface that GENUINELY cannot shrink to 390px: the project detail's
   six columns end in an `acciones` cell holding a transition form, an assignee picker, a
   next-action field and the timeline disclosure. The choice is therefore not "narrow or wide" but
   "which box scrolls" — and the answer is this one, never the page body. Every `.table` in the
   cockpit is rendered inside a `.table-scroll` (views.mjs), and the paired verification asserts
   that containment for every table the four surfaces render.

   The mechanism is exactly two declarations: the box takes the parent's width and refuses to grow
   past it (`max-width: 100%`), and its own overflow scrolls (`overflow-x: auto`). The table inside
   keeps its min-content width — nothing is squeezed, nothing is truncated, and the header row
   scrolls WITH its columns because it is still the same table. */

.table-scroll {
  max-width: 100%;
  overflow-x: auto;
}

/* ── badge — status/stage/verdict pills, bound to the color roles (S-24 §5) ────────────────────── */

.badge {
  display: inline-block;
  padding: 0 var(--s1);
  margin-left: var(--s1);
  border: 1px solid currentColor;
  border-radius: 0.3rem;
  font-size: var(--text-meta);
}

/* ── form-grid — label ABOVE input, aligned columns, grouped submit (S-24 §5 / AC-S1) ──────────── */

.form-grid {
  display: grid;
  gap: var(--s2);
  max-width: 28rem;
}

.form-grid label {
  display: grid;
  gap: 0.25rem;
  font-size: var(--text-body);
}

.form-grid label > input,
.form-grid label > select,
.form-grid label > textarea {
  padding: var(--s1);
  border: 1px solid var(--border);
  border-radius: 0.3rem;
  background: var(--bg);
  color: var(--text);
  font: inherit;
}

.form-grid button[type='submit'] {
  justify-self: start;
  padding: var(--s1) var(--s2);
  border-radius: 0.3rem;
  border: 1px solid var(--accent);
  background: var(--accent);
  color: #fff;
  cursor: pointer;
}

.login.form-grid {
  max-width: 20rem;
}

/* ── empty-state — calm, muted, distinct from a read-error (which renders in --red, AC-D1) ─────── */

.empty-state {
  color: var(--text-muted);
  font-style: italic;
}

/* ── project cards — the S-33 landing surface (HA-1) ───────────────────────────────────────────
   The home screen is one card per project in the SERVER'S health rank. This section styles every
   class that surface emits; it introduces NO token, palette or spacing scale of its own — every
   value below is one of the §5 custom properties declared on :root.

   THE THREE-STATE VISUAL GRAMMAR IS THE LOAD-BEARING PART, not the chrome. views.mjs is built
   throughout on the refusal to let three different facts render alike, and CSS is where that
   refusal either survives or quietly dies:

     · KNOWN      — the real answer. Plain body text, no decoration.
     · ABSENT     — the server said "there is none" (`sin próximo hito`, `sin asignar`, no projects
                    yet). CALM: muted + italic, the same language `.empty-state` already speaks.
     · UNKNOWN    — we could not read it at all. AMBER + upright + medium weight, so it is legible
                    at a glance as "this is not an answer" and can never be mistaken for the calm
                    absence above. A degraded card must not look like a tended one.

   WHY AMBER AND NOT RED for the cell-level unknowns: AC-S1 reserves RED exclusively for
   owed/overdue/failure semantics, and it is the radar's own meaning — spending it on "we don't
   know" would blunt the one color the member must never misread. Amber was declared in §5 and is
   the honest middle: not an alarm, not calm. RED is used at exactly ONE place here, the section
   border below, because a FAILED READ genuinely is the failure semantic, and it renders alongside
   the error paragraphs that already carry `.red`. */

/* the section itself. It already carries `.card` in the same class list (views.mjs), so surface,
   border, radius and padding come from there — this rule adds only what is the card SURFACE's own
   concern, and deliberately does not restate a single one of those four. */
.project-cards {
  display: block;
}

/* the calm, EARNED empty state: the reads SUCCEEDED and answered "no projects". It also carries
   `.empty-state`, which is where its muted italic comes from; distinct from `.project-cards-unknown`
   below by construction — this one is quiet, that one is marked. */
.project-cards-empty {
  margin: var(--s2) 0 0;
}

/* THE DEGRADED BOARD. At least one of the two feeding reads failed, so the verdicts and/or the
   names on screen are incomplete. The left border makes that legible from across the room, before
   any individual cell is read — which is the whole point of an honest-read surface: the member must
   not have to notice a missing value to learn the board is not trustworthy. */
.project-cards-unknown {
  border-left: 4px solid var(--red);
}

.project-card-list {
  display: grid;
  gap: var(--s2);
  margin: var(--s2) 0 0;
  padding: 0;
  list-style: none;
}

/* one project. It sits on --bg INSIDE the surface-colored `.card` section, so each project reads as
   its own object rather than as a row in an undifferentiated block. Flex-wrap, not a fixed grid: the
   five slots reflow onto a second line on a narrow screen instead of being truncated or hidden. */
.project-card {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s1) var(--s2);
  padding: var(--s2);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 0.3rem;
}

/* the name takes the row and pushes the meta slots right; it grows and shrinks but never below a
   readable basis, at which point the remaining slots wrap under it. */
.project-card-name {
  flex: 1 1 12rem;
  font-size: var(--text-body);
  font-weight: 600;
}

.project-card-link {
  color: var(--accent);
  text-decoration: none;
}

.project-card-salud {
  display: inline-flex;
  align-items: center;
}

/* THE OWED COUNT IS DELIBERATELY NOT RED. It is always present, including on a green card where it
   reads `0 pendiente(s)` (HOME-4a) — and CSS cannot branch on the number, so a red rule here would
   paint "nothing is owed" in the alarm color and state the opposite of the truth. The verdict badge
   in `.project-card-salud` is what carries the red/green semantic, from the SERVER's own health
   field, which is the single place that judgement is made. */
.project-card-owed {
  font-size: var(--text-meta);
  color: var(--text-muted);
}

.project-card-holders {
  font-size: var(--text-meta);
  color: var(--text-muted);
}

.project-card-milestone {
  font-size: var(--text-meta);
  color: var(--text-muted);
}

/* ABSENT (calm) — the server told us there is no next milestone. Italic, like every other earned
   emptiness in this sheet. */
.project-card-milestone-none {
  font-style: italic;
}

/* UNKNOWN (marked) — we could not read the row at all. These two rules are what make a degraded
   cell impossible to mistake for the calm absence directly above: upright, amber, medium weight.
   Delete either one and the cockpit starts rendering ignorance as if it were a tended answer. */
.project-card-milestone-unknown,
.project-card-owed-unknown {
  font-style: normal;
  font-weight: 600;
  color: var(--amber);
}

/* ── the narrow (phone) viewport (G_A-72 AC-1) ─────────────────────────────────────────────────
   The reference device is 390px — the width the team's phones actually report. The breakpoint is
   480px so that reference sits INSIDE the block with room either side, rather than exactly on a
   boundary where a 1px rounding difference decides whether the cockpit is usable.

   What changes here is CHROME ONLY — padding and gaps, the space the cockpit spends on itself. At
   390px the base `--s3` padding costs 48px of the 390 (12%) before a single character of the
   member's work renders. Nothing about the CONTENT changes: no column is hidden, no control is
   shrunk below --touch, no surface is replaced by a phone-only variant. A responsive pass that
   deletes columns on a phone is a different (worse) product, not the same cockpit made usable. */

@media (max-width: 480px) {
  body {
    padding: var(--s2);
  }

  .nav {
    padding: var(--s2);
  }

  .nav-links {
    gap: var(--s2);
  }

  .card {
    padding: var(--s2);
  }

  /* CHROME ONLY, exactly as the block's contract says: the cards keep every slot and every control
     at full size — only the space the surface spends on itself shrinks. */
  .project-card {
    padding: var(--s1) var(--s2);
  }

  .project-card-list {
    gap: var(--s1);
  }

  .table th,
  .table td {
    padding: var(--s1);
  }
}
