/* ============================================================================
   Primitives. The container and type vocabulary built on css/tokens.css.

   Import tokens.css before this file. Every colour here is a token reference
   and every font-size is a scale step; tests/test_tokens.py fails on a literal
   of either kind, because a literal is how drift re-enters once a token file
   exists.

   Three containers, each with a job:
     .plate       full width, ruled, no radius. The primary structural device.
     .card        peer items in a grid. Demoted, and no longer the only option.
     .record      dense ruled rows for things that have state.

   Rules carry structure. A one pixel line is the main organising device here,
   replacing the reflex of drawing a border around every box.
   ========================================================================= */

/* --- Type ---------------------------------------------------------------- *
 * Nine steps replacing 74 ad-hoc sizes. Every step below is used by something
 * in this file; a step nobody uses is just a number someone picked.          */

.t-display {
  font-family: var(--font-sans);
  font-size: var(--text-display);
  font-weight: 700;
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-tight);
}
.t-h1 {
  font-size: var(--text-h1);
  font-weight: 700;
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-tight);
}
.t-h2 {
  font-size: var(--text-h2);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: var(--leading-snug);
}
.t-h3 {
  font-size: var(--text-h3);
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: var(--leading-snug);
}
.t-lead {
  font-size: var(--text-lead);
  color: var(--ink-mid);
  line-height: var(--leading-body);
}
.t-body   { font-size: var(--text-body);   line-height: var(--leading-body); }
.t-small  { font-size: var(--text-small);  color: var(--ink-mid);
            line-height: var(--leading-body); }
.t-caption{ font-size: var(--text-caption); color: var(--ink-quiet);
            line-height: var(--leading-snug); }

/* --- Metadata ------------------------------------------------------------ *
 * The ONLY place JetBrains Mono is permitted. It carries owner, source,
 * version, date, and state, in that order, and nothing else. The mono stops
 * being decoration the moment it always carries the same class of
 * information. It takes --ink-quiet, not a faded value: it is small and
 * letterspaced, and that is what makes it recede.                           */
.meta {
  font-family: var(--font-mono);
  font-size: var(--text-meta);
  font-weight: 700;
  letter-spacing: var(--tracking-meta);
  text-transform: uppercase;
  color: var(--ink-quiet);
}

/* --- Plate --------------------------------------------------------------- *
 * Full width, ruled top and bottom, no radius and no shadow. Content sits on
 * the page ground rather than inside a box; the rule does the containing.    */
.plate {
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  border-radius: var(--radius-plate);
  padding: var(--space-6) 0;
  background: transparent;
}
.plate + .plate { border-top: none; }

/* The metadata rail. Renders ONLY fields backed by a real value. No
 * placeholder, no invented field. A plate with no backing metadata renders
 * without a rail rather than with an empty one, because a rail of
 * governed-looking typography with nothing behind it is decoration wearing
 * the costume of evidence, which is a more sophisticated version of the thing
 * this system was built to correct. */
.plate__rail {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-5);
  padding-bottom: var(--space-3);
  margin-bottom: var(--space-4);
  border-bottom: 1px solid var(--rule);
}
.plate__rail > * {
  font-family: var(--font-mono);
  font-size: var(--text-meta);
  font-weight: 700;
  letter-spacing: var(--tracking-meta);
  text-transform: uppercase;
  color: var(--ink-quiet);
}
.plate__rail b { color: var(--ink); font-weight: 700; }

/* Lead variant. Three containers mapped to three content types would be a
 * taxonomy, not a hierarchy, and two plates on a page would still be equally
 * weighted. This is the emphasis dimension: at most one per page. */
.plate--lead {
  border-top-width: 3px;
  border-top-color: var(--ink);
  padding: var(--space-8) 0 var(--space-6);
}
.plate--lead .plate__title { font-size: var(--text-display); }
.plate__title {
  font-size: var(--text-h1);
  font-weight: 700;
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-tight);
  margin-bottom: var(--space-2);
}

/* --- Card ---------------------------------------------------------------- *
 * .card and .card-grid are defined in css/site.css, which already owned those
 * selectors. Defining them here as well produced a real collision: both files
 * load together on the newsletter page with different radius and hover values,
 * so a bare class="card" resolved to whichever loaded last. The demotion this
 * layer wanted (tighter radius, no hover lift) was applied to site.css's
 * definition instead, so it reaches every page rather than fighting one.
 * ------------------------------------------------------------------------- */

/* --- Record row ---------------------------------------------------------- *
 * Ruled, borderless, dense. For lists of things that have state.             */
.record {
  display: grid;
  grid-template-columns: 1fr auto auto auto;
  align-items: baseline;
  gap: var(--space-4);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--rule);
}
.record:last-child { border-bottom: none; }
.record__name { font-size: var(--text-body); font-weight: 500; }
.record__meta {
  font-family: var(--font-mono);
  font-size: var(--text-meta);
  font-weight: 700;
  letter-spacing: var(--tracking-meta);
  text-transform: uppercase;
  color: var(--ink-quiet);
}

/* --- Empty, loading, failed ---------------------------------------------- *
 * Stated in the same ruled and typographic vocabulary as the containers.
 * Profile Base's pattern for this was a centred icon in a coloured circle,
 * which is the generic treatment being replaced. Replacing it with nothing
 * would mean the first person who needs an empty state reaches for the
 * pattern they already know.                                                */
.is-empty, .is-loading, .is-failed {
  padding: var(--space-6) 0;
  font-size: var(--text-small);
  color: var(--ink-quiet);
  border-bottom: 1px solid var(--rule);
}
.is-empty::before, .is-loading::before, .is-failed::before {
  font-family: var(--font-mono);
  font-size: var(--text-meta);
  font-weight: 700;
  letter-spacing: var(--tracking-meta);
  display: block;
  margin-bottom: var(--space-2);
}
.is-empty::before   { content: "NOTHING HERE YET"; color: var(--ink-quiet); }
.is-loading::before { content: "READING";          color: var(--signal-source); }
.is-failed::before  { content: "COULD NOT READ";   color: var(--state-error); }

/* --- Focus --------------------------------------------------------------- *
 * The focus treatment lives in css/site.css, not here. primitives.css is
 * linked by three pages; site.css is linked by all twelve, including the two
 * that still had outline:none. A fix in this file would not have reached them.
 * ------------------------------------------------------------------------- */

/* --- Targets ------------------------------------------------------------- */
.tap {
  min-height: var(--target-min);
  min-width: var(--target-min);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* --- Narrow viewports ---------------------------------------------------- *
 * The rail wraps. It is never hidden. The existing answer to this problem in
 * this codebase was display:none on the portal tier below 600px, and applying
 * that reflex here would delete the evidence the system exists to make
 * visible, on the majority of traffic, while still passing a
 * no-horizontal-scroll check.                                               */
@media (max-width: 600px) {
  .plate__rail { gap: var(--space-1) var(--space-3); }
  .record {
    grid-template-columns: 1fr auto;
    row-gap: var(--space-1);
  }
  .card-grid { grid-template-columns: 1fr; }
}

/* --- Motion -------------------------------------------------------------- *
 * .reveal animates 24px of translate over 0.65s on every page and the shared
 * stylesheet had no guard, while four individual pages had written their own.
 * The guard belongs in the shared layer.                                    */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .reveal { opacity: 1 !important; transform: none !important; }
}
