/* Calm UI tokens + base styles — house design system.
   Source of record: docs/DESIGN_frontend_style_2026-08-14.md (Alpaca).
   Copy this whole file into the page (inline <style> or the app stylesheet).
   Build ONLY from these tokens; a literal color/size/spacing elsewhere is a defect.

   Profiles:
     A Document — light-first; sections alternate --bg / --bg-alt. Pin the page light with
                  <html data-theme="light"> unless it has a reason to follow the viewer.
     B Console  — add class "dark" (or data-profile="console") on <html>; dark ladder.
     C Artifact — light-pinned. DELETE both dark blocks below — the @media one AND the
                  [data-theme="dark"] one — before pasting. An artifact's <html> belongs to
                  the harness, so the attribute pin is not available and the ground has to
                  come from the CSS that is left. Also keep `color-scheme: light`, or the
                  host's own `light dark` declaration paints the UA widgets (scrollbars,
                  <select> popups) dark inside a white page. SKILL.md §3d.               */

:root {
  /* type */
  --font-sans: system-ui, -apple-system, "Segoe UI Variable Text", "Segoe UI",
               Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-mono: ui-monospace, "Cascadia Code", Consolas, "SF Mono", Menlo, monospace;

  /* Declare the ground to the UA as well as to the CSS. Without this the browser renders
     scrollbars, date pickers and <select> popups from whatever the HOST page declared,
     which on a light-pinned page inside a dark host is a black widget on white. */
  color-scheme: light;

  /* light (Profile A default) */
  --bg: #ffffff;        --bg-alt: #f5f5f7;      --bg-raised: #ffffff;
  --text: #1d1d1f;      --text-2: #6e6e73;      --text-3: #86868b;
  --accent: #0071e3;    --link: #0066cc;        --on-accent: #ffffff;
  --ok: #1d8a3a;        --warn: #b25b00;        --err: #d70015;
  --hairline: rgba(0,0,0,.10);

  /* geometry */
  --radius-s: 8px;  --radius-m: 12px;  --radius-l: 18px;  --radius-xl: 28px;
  --content-max: 1080px;   /* 1260px only for marketing-scale pages */
  --space-1: 4px;  --space-2: 8px;  --space-3: 12px; --space-4: 16px;
  --space-5: 24px; --space-6: 32px; --space-7: 48px; --space-8: 64px; --space-9: 96px;

  /* motion */
  --t-color: 100ms linear;
  --t-move: 300ms cubic-bezier(0, 0, 0.5, 1);
  --t-reveal: 400ms ease-in-out;   /* document entrance reveals only */
}

/* dark ladder — Profile B always; Profile A when it follows the viewer.
   Profile C (artifact) DELETES both of these blocks: see the header. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --bg: #0b0e14;      --bg-alt: #12151c;      --bg-raised: #1a1f28;
    --text: #e6e8ec;    --text-2: #98a0ab;      --text-3: #6a7280;
    --accent: #2997ff;  --link: #2997ff;        --on-accent: #ffffff;
    --ok: #32d74b;      --warn: #ff9f0a;        --err: #ff453a;
    --hairline: rgba(255,255,255,.08);
  }
}
:root[data-theme="dark"], :root.dark, :root[data-profile="console"] {
  color-scheme: dark;
  --bg: #0b0e14;        --bg-alt: #12151c;      --bg-raised: #1a1f28;
  --text: #e6e8ec;      --text-2: #98a0ab;      --text-3: #6a7280;
  --accent: #2997ff;    --link: #2997ff;        --on-accent: #ffffff;
  --ok: #32d74b;        --warn: #ff9f0a;        --err: #ff453a;
  --hairline: rgba(255,255,255,.08);
}

/* ---- base ---- */
* { margin: 0; box-sizing: border-box; }
body {
  background: var(--bg);            /* always painted — never transparent */
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 17px; line-height: 25px; font-weight: 400; letter-spacing: -0.022em;
  -webkit-font-smoothing: antialiased;
}
/* Profile B density: put class "console" on body */
body.console { font-size: 13px; line-height: 20px; letter-spacing: 0; }

.wrap { max-width: var(--content-max); margin: 0 auto; padding: 0 max(24px, 6%); }
.sec { padding: var(--space-9) 0; }
.sec--alt { background: var(--bg-alt); }
@media (max-width: 734px) { .sec { padding: var(--space-7) 0; } }

/* ---- type ramp (Profile A) ---- */
.display { font-size: 56px; line-height: 60px; font-weight: 600; letter-spacing: -0.005em; text-wrap: balance; }
.title   { font-size: 40px; line-height: 44px; font-weight: 600; letter-spacing: 0;        text-wrap: balance; }
.heading { font-size: 28px; line-height: 32px; font-weight: 600; letter-spacing: 0.007em;  text-wrap: balance; }
.subhead { font-size: 21px; line-height: 25px; font-weight: 600; letter-spacing: 0.011em; }
.caption { font-size: 12px; line-height: 16px; color: var(--text-2); letter-spacing: -0.01em; }
.eyebrow { font-size: 12px; line-height: 16px; font-weight: 600; letter-spacing: 0.06em;
           text-transform: uppercase; color: var(--text-3); }
@media (max-width: 734px) {
  .display { font-size: 40px; line-height: 44px; }
  .title   { font-size: 32px; line-height: 36px; }
}
/* Profile B ramp */
.panel-title { font-size: 15px; line-height: 20px; font-weight: 600; }
.page-title  { font-size: 20px; line-height: 26px; font-weight: 600; }
.label       { font-size: 11px; line-height: 16px; font-weight: 600; letter-spacing: 0.06em;
               text-transform: uppercase; color: var(--text-3); }

p { max-width: 42rem; }
.muted { color: var(--text-2); }
.quiet { color: var(--text-3); }
a { color: var(--link); text-decoration: none; }
a:hover { text-decoration: underline; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
code, .mono { font-family: var(--font-mono); font-size: 0.85em; letter-spacing: 0; }

/* ---- surfaces: cards invert against their section; ONE separator per boundary ----
   radius roles: .card--xl 28px hero/section-scale, .card 18px standard cards/tiles,
   .panel 12px console panels, inputs/chips 8px */
.card { background: var(--bg-alt); border-radius: var(--radius-l); padding: var(--space-5); }
.sec--alt .card { background: var(--bg); }
.card--xl { border-radius: var(--radius-xl); padding: var(--space-6); }
.panel { background: var(--bg-alt); border-radius: var(--radius-m); padding: var(--space-4); }

/* ---- tables: hairline rows only ---- */
table { border-collapse: collapse; width: 100%; font-variant-numeric: tabular-nums; }
th { font-size: 12px; line-height: 16px; font-weight: 600; letter-spacing: 0.06em;
     text-transform: uppercase; color: var(--text-3); text-align: left;
     padding: 0 var(--space-4) 10px 0; }
td { padding: 10px var(--space-4) 10px 0; border-top: 1px solid var(--hairline); }
td.num, th.num { text-align: right; padding-right: 0; }
.tablebox { overflow-x: auto; }

/* ---- controls ---- */
.pill { display: inline-block; background: var(--accent); color: var(--on-accent); font-weight: 600;
        font-size: 14px; line-height: 20px; padding: 8px 18px; border-radius: 980px;
        border: 0; cursor: pointer; transition: opacity var(--t-color); }
.pill:hover { opacity: .9; }
.btn-quiet { background: none; border: 1px solid var(--hairline); color: var(--text);
             font-size: 14px; line-height: 20px; padding: 7px 17px; border-radius: 980px;
             cursor: pointer; }

/* ---- status: color DERIVES from the status text; only on status ---- */
.verdict { display: inline-flex; align-items: center; gap: 6px; font-weight: 600; }
.verdict::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: currentColor; }
.v-ok { color: var(--ok); }  .v-warn { color: var(--warn); }  .v-err { color: var(--err); }

/* ---- motion hygiene ---- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* ============================================================================
   PROFILE A-M — MARKETING SCALE
   Optional. Load it for a front page, product page, or pitch: a document that has
   to make an impression in one screen and carries photography. A report, board, or
   console does not need any of this and should not use it.

   Everything here is derived from a shipped implementation (Alpaca personal-site,
   2026-08-16) rather than proposed, including the three traps noted inline. SKILL.md
   section 3b is the doctrine; this is its CSS, so a page does not re-derive it and
   re-hit the same bugs.
   ============================================================================ */

/* Marketing width. The document max is 1080; a hero picture may run to 1260.
   Nothing else should. */
.wrap--wide { max-width: 1260px; }

/* One step above the ramp's 56/60 top, for the hero line of a front page ONLY.
   Every other heading on the page stays on the ramp, or the step means nothing.
   The breakpoints are chosen so the line count does not change as it shrinks. */
.display--xl { font-size: 72px; line-height: 76px; font-weight: 600;
               letter-spacing: -0.015em; text-wrap: balance; max-width: 24ch; }
@media (max-width: 1000px) { .display--xl { font-size: 56px; line-height: 60px; } }
@media (max-width: 734px)  { .display--xl { font-size: 40px; line-height: 44px;
                                            letter-spacing: -0.005em; max-width: none; } }

/* ---- grids ---- */
.grid { display: grid; gap: var(--space-4); }
.grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

/* ---- the record, in numbers ----
   .numbers--lead takes the display size: a front page's lead strip is read at a
   glance, not scanned in a table. */
.numbers { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: var(--space-4); }
.num__v { font-size: 40px; line-height: 44px; font-weight: 600; font-variant-numeric: tabular-nums; }
.num__k { font-size: 12px; line-height: 16px; color: var(--text-2); margin-top: var(--space-2); }
.numbers--lead .num__v { font-size: 56px; line-height: 60px; letter-spacing: -0.005em; }
.numbers--lead .num__k { font-size: 14px; line-height: 20px; margin-top: var(--space-3); }

/* ---- imagery: THREE shapes, and only three ----
   figure = inside the content column · band = full bleed · gallery = grid of equals.
   A page with nine ways to place a picture stops reading as one system.

   TRAP 1 (silent): put width/height ATTRIBUTES on every <img> so nothing reflows as
   images arrive — but the browser maps them to presentational height, which BEATS
   `aspect-ratio`. Every cropped image therefore needs an explicit `height: auto`.
   Without it a 4:3 cell renders at the image's full natural height; a page of them
   came out 16220px tall before this was found.

   TRAP 3 (silent, and it eats the SUBJECT): every fixed-aspect slot below crops with
   `object-fit: cover`, so a picture whose subject uses the full frame — an exploded
   stack, a tall assembly, a wide board — loses exactly the part that carries the meaning.
   Do NOT solve it in CSS with `contain`: that leaves the image floating in a box at a
   size nothing else on the page shares. Pad the SOURCE image to the slot's aspect ratio
   on #ffffff in the pipeline, and the letterbox is invisible on a light-pinned page.
   This is the reason the ground pin and the imagery rules are one decision, not two. */
.fig { margin: 0; }
.fig__img { width: 100%; height: auto; display: block; border-radius: var(--radius-xl); }
.figcap { font-size: 12px; line-height: 16px; color: var(--text-3);
          margin-top: var(--space-3); max-width: 42rem; }
/* A figure that OPENS a section, with the section's content following it. */
.fig--wide { margin-bottom: var(--space-7); }

/* Full bleed. The loudest thing on a page — one or two per page, never a run. */
.band { margin: 0; }
.band__img { width: 100%; height: auto; display: block; max-height: 460px; object-fit: cover; }
/* A band's caption sits in a .wrap below it, so it needs its own top gap. */
.figcap--band { margin-top: var(--space-4); }

.gal { display: grid; gap: var(--space-4); }
.gal--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.gal--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.gal__cell { margin: 0; }
.gal__img { width: 100%; height: auto; aspect-ratio: 4 / 3; object-fit: cover; display: block;
            border-radius: var(--radius-l); background: var(--bg-alt); }
.sec--alt .gal__img { background: var(--bg); }

/* Image beside prose. Alternate `flip` down the page so blocks do not all march
   the same direction. */
.split { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
         gap: var(--space-7); align-items: center; }
.split__text { min-width: 0; }

/* Picture-led card: image edge to edge on top, body padded.
   The image is TEXTURE, not evidence — it carries no caption, because a caption on a
   card reads as an assertion about that card's subject.

   TRAP 2 (silent): `.mcard` and `.card` have equal specificity, so whichever is
   declared LAST wins. A project that redefines `.card` in its own stylesheet (loaded
   after this file) would win the padding back and inset every card image by the card
   fill. `.card.mcard` is used deliberately to make the reset order-independent. */
.card.mcard { padding: 0; overflow: hidden; gap: 0; }
.mcard__art { display: block; }
.mcard__img { width: 100%; height: auto; aspect-ratio: 16 / 10; object-fit: cover; display: block; }
.mcard__body { padding: var(--space-5); display: flex; flex-direction: column; gap: var(--space-3); }

/* ---- clips: the FOURTH shape, and the only one that is not a picture ----
   A demo clip needs a control surface and arrives at whatever aspect it was shot at, so
   it does not fit the three picture shapes. One fixed 16/9 box with `contain` is what
   lets a landscape bench clip and a portrait phone clip sit in one grid without either
   being cropped — `cover` here would throw away the top and bottom of the portrait one,
   which on a phone demo is the control bar, i.e. the subject. The box also reserves its
   own height, so nothing reflows when a clip's metadata lands.

   TRAP 3 does NOT apply: a clip is letterboxed live inside the element (its ground is the
   --bg-alt fill below), not padded in a pipeline. Upstreamed from the personal-site
   2026-08-17 pass. Two rules that live outside CSS and still decide whether this works:
   every <video> carries a `poster` (a preload="none" clip without one paints as a black
   rectangle, indistinguishable from a broken one), and the encode is size-capped by the
   host's limit — an oversize clip builds clean, deploys clean, and 404s inside an element
   that still looks like it is loading. */
.vids { display: grid; gap: var(--space-4); }
.vids--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.vid { margin: 0; }
.vid__el { width: 100%; aspect-ratio: 16 / 9; display: block;
           object-fit: contain; background: var(--bg-alt);
           border-radius: var(--radius-l); }
.sec--alt .vid__el { background: var(--bg); }

@media (max-width: 1000px) { .grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 900px) {
  .grid--2, .grid--3 { grid-template-columns: minmax(0, 1fr); }
  .gal--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .split { grid-template-columns: minmax(0, 1fr); gap: var(--space-6); }
  .numbers { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .numbers--lead .num__v { font-size: 40px; line-height: 44px; }
  .band__img { max-height: 320px; }
  .vids--2 { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 734px) {
  .grid--4, .gal--3 { grid-template-columns: minmax(0, 1fr); }
  .fig__img { border-radius: var(--radius-l); }
}
