/* ==========================================================================
   base.css — reset, typography and the app frame
   --------------------------------------------------------------------------
   Every value used here comes from tokens.css. This file owns the reset, the
   type defaults, the page shell and the scroll behaviour; it does not invent
   colours or spacing.
   ========================================================================== */

/* ---------- reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }

html, body { height: 100%; }

body {
  background: var(--bg);
  color: var(--txt);
  font-family: var(--sans);
  font-size: var(--t-body);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow: hidden;                 /* the stage never scrolls; panes do */
  overscroll-behavior: none;
}

img, canvas, svg { display: block; max-width: 100%; }
button, input, select, textarea { font: inherit; color: inherit; }
button { background: none; border: none; cursor: pointer; }

/* a class with display:flex otherwise beats the UA [hidden] rule */
[hidden] { display: none !important; }

::selection { background: var(--accent-dim); color: var(--txt); }

/* One focus ring for the whole app, with a dark halo so it stays visible on
   the L*≈50 stage as well as on the dark chrome. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  box-shadow: 0 0 0 4px rgba(0, 0, 0, .45);
  border-radius: 5px;
}
:focus:not(:focus-visible) { outline: none; }

/* ---------- scrollbars ---------- */
.scroll { overflow-y: auto; scrollbar-width: thin; scrollbar-color: var(--line-2) transparent; }
.scroll::-webkit-scrollbar { width: 10px; height: 10px; }
.scroll::-webkit-scrollbar-track { background: transparent; }
.scroll::-webkit-scrollbar-thumb {
  background: var(--line-2); border-radius: 99px; border: 3px solid var(--bg);
}
.scroll::-webkit-scrollbar-thumb:hover { background: var(--line-3); }

/* ---------- typography ----------
   Sizes come from the scale in tokens.css; nothing here invents one. */
h1, h2, h3, h4 { font-weight: 560; letter-spacing: -0.018em; line-height: var(--lh-tight); text-wrap: balance; }
h1 { font-size: var(--t-display); letter-spacing: -0.032em; }
h2 { font-size: var(--t-title);   letter-spacing: -0.026em; }
h3 { font-size: var(--t-head);    letter-spacing: -0.014em; }
h4 { font-size: var(--t-small); }

p { text-wrap: pretty; }

.lede    { font-size: var(--t-lede); color: var(--txt-2); line-height: var(--lh-body); max-width: 62ch; }
.muted   { color: var(--txt-2); }
.faint   { color: var(--txt-3); }
.small   { font-size: var(--t-small); }
.tiny    { font-size: var(--t-tiny); }
.mono    { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.nowrap  { white-space: nowrap; }
.center  { text-align: center; }

.eyebrow {
  font-size: var(--t-micro); font-weight: 620; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--txt-3);
}

strong, b { font-weight: 600; color: var(--txt); }

a { color: var(--accent); text-decoration-color: color-mix(in srgb, var(--accent) 40%, transparent); text-underline-offset: 2px; }
a:hover { text-decoration-color: currentColor; }

/* ---------- app frame ---------- */
#app {
  display: flex; flex-direction: column;
  height: 100dvh; width: 100vw;
  background:
    radial-gradient(120% 80% at 50% -10%, #16191d 0%, transparent 60%),
    var(--bg);
}

.appbar {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: var(--s-4);
  /* viewport-fit=cover lets content sit under a notch; keep the chrome clear
     of it on both sides, since a landscape phone puts the notch beside the
     brand rather than above it */
  height: var(--bar);
  padding: 0 max(var(--s-4), env(safe-area-inset-right))
           0 max(var(--s-4), env(safe-area-inset-left));
  border-bottom: 1px solid var(--line);
  background: color-mix(in srgb, var(--bg-1) 82%, transparent);
  backdrop-filter: blur(14px);
  position: relative; z-index: 40;
}

.brand { display: flex; align-items: center; gap: var(--s-2); flex: 0 0 auto; }
.brand-mark {
  width: 1.5rem; height: 1.5rem; border-radius: var(--radius-sm); flex: 0 0 auto;
  background: conic-gradient(from 210deg,
    #d4646a, #d0a24e, #b6c257, #62c088, #55bcc4, #7fa8e0, #b48fd6, #d4646a);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.16), 0 0 14px rgba(255,255,255,.06);
}
/* Two lines, set tight enough to sit inside the bar's height together. The
   subtitle carries the one thing the name cannot: what the thing actually
   measures. It stays up during the test as well — a wordmark with nothing
   under it in the corner of a nine-module run tells you less than it costs. */
.brand-name {
  font-weight: 600; letter-spacing: -0.02em;
  font-size: var(--t-body); line-height: 1.2;
}
.brand-sub  {
  color: var(--txt-3); font-size: var(--t-micro); letter-spacing: .04em;
  line-height: 1.3; text-transform: uppercase; font-weight: 560;
}
@media (max-width: 720px) { .brand-sub { display: none; } }

.appbar-spacer { flex: 1 1 auto; min-width: 0; }

/* The About button sits beside the icon group, not in it: it is a
   destination rather than an action, and it is the only control up here that
   is worth reading rather than recognising. */
.appbar > .btn { flex: 0 0 auto; }
@media (max-width: 560px) { .appbar > .btn { display: none; } }

/* One control, three segments — not three floating glyphs.
   Bare icon buttons on a dark bar have no edge until you hover them, so they
   read as decoration rather than as things you can press, and the eye has to
   find each one separately. Wrapping them in a single bordered group gives
   the set one silhouette, states the hit area up front, and lets the hairline
   rules between segments do the work that gaps were doing badly. */
.appbar-actions {
  display: flex; align-items: center; flex: 0 0 auto;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--bg-2) 70%, transparent);
  overflow: hidden;
}
/* Square segments. A wider-than-tall segment holding a square glyph leaves
   the icon adrift in a landscape box; matching the two axes means the icon
   is centred in something the same shape as itself. */
.appbar-actions > .btn-icon {
  border: 0; border-radius: 0;
  width: var(--ctl); height: var(--ctl);
}
/* A real divider, not a shadow: `overflow: hidden` on the group clips the
   rounded corners, and an inset shadow on a hovered segment fights with the
   hover fill drawn underneath it. */
.appbar-actions > .btn-icon + .btn-icon { border-left: 1px solid var(--line); }
/* Hover has to be visible against a group that already has its own fill, so
   it goes a step brighter than the surface below rather than matching it. */
.appbar-actions > .btn-icon:hover { background: var(--bg-3); color: var(--txt); }
.appbar-actions > .btn-icon:active { background: var(--line); }
/* The ring would be clipped by the group's own overflow, so draw it inside. */
.appbar-actions > .btn-icon:focus-visible {
  outline: none; box-shadow: inset 0 0 0 2px var(--accent);
}
@media (pointer: coarse) {
  .appbar-actions > .btn-icon { width: var(--tap); height: var(--tap); }
  /* the bar has to grow to hold a tap-sized control, not clip it */
  .appbar { height: max(var(--bar), calc(var(--tap) + var(--s-3))); }
}

/* ---------- pages ---------- */
.pages { flex: 1 1 auto; position: relative; min-height: 0; }

.page {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  opacity: 0;
  pointer-events: none;
  transform: translateY(10px);
  transition: opacity .34s var(--ease-out), transform .34s var(--ease-out);
}
.page.is-active {
  opacity: 1; pointer-events: auto; transform: none;
}
.page.is-leaving { transform: translateY(-8px); }

/* a page that holds its own scroll region */
.page-scroll { flex: 1 1 auto; min-height: 0; overflow-y: auto; }

.wrap { width: min(72rem, 100% - 3rem); margin-inline: auto; }
.wrap-narrow { width: min(50rem, 100% - 3rem); margin-inline: auto; }

@media (max-width: 640px) {
  .wrap, .wrap-narrow { width: calc(100% - 1.6rem); }
}

/* ---------- layout primitives ----------
   These exist so that a page can be built without a single inline style.
   Before them the two page modules carried a hundred-odd one-off `marginTop`
   values, which is what a design system is for: the same relationship
   expressed a hundred slightly different ways is not a system.

   `stack`   — vertical rhythm between siblings, gap from the scale
   `cluster` — a wrapping row of small things (chips, buttons)
   `row`/`col` — a flex line with no opinion about spacing
   `grid`    — an auto-fitting grid with a settable minimum column
   `bleed-*` — the only sanctioned way to open space above a block */
.row  { display: flex; align-items: center; gap: var(--s-3); }
.col  { display: flex; flex-direction: column; }
.cluster { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); }
.wrap-row { flex-wrap: wrap; }
.grow { flex: 1 1 auto; min-width: 0; }
.center-both { display: grid; place-items: center; }

.gap-1 { gap: var(--s-1); } .gap-2 { gap: var(--s-2); }
.gap-3 { gap: var(--s-3); } .gap-4 { gap: var(--s-4); }
.gap-5 { gap: var(--s-5); } .gap-6 { gap: var(--s-6); }
/* kept as aliases so existing call sites stay valid */
.gap-s { gap: var(--s-2); } .gap-m { gap: var(--s-4); } .gap-l { gap: var(--s-5); }

.stack { display: flex; flex-direction: column; gap: var(--stack, var(--s-4)); }
.stack-1 { --stack: var(--s-1); } .stack-2 { --stack: var(--s-2); }
.stack-3 { --stack: var(--s-3); } .stack-4 { --stack: var(--s-4); }
.stack-5 { --stack: var(--s-5); } .stack-6 { --stack: var(--s-6); }
.stack-s { --stack: var(--s-2); } .stack-l { --stack: var(--s-5); }

.grid { display: grid; gap: var(--s-3); grid-template-columns: repeat(auto-fit, minmax(var(--col, 16rem), 1fr)); }

/* The full scale, not just the top half. The four steps that existed covered
   section-sized gaps, so every smaller gap in the app was written as an inline
   `marginTop` instead — nine different values doing one job, none of them
   visible to the scale lint. */
.bleed-1 { margin-top: var(--s-1); } .bleed-2 { margin-top: var(--s-2); }
.bleed-3 { margin-top: var(--s-3); } .bleed-4 { margin-top: var(--s-4); }
.bleed-5 { margin-top: var(--s-5); } .bleed-6 { margin-top: var(--s-6); }
.bleed-7 { margin-top: var(--s-7); } .bleed-8 { margin-top: var(--s-8); }

/* A row whose contents sit at one end. Written as an inline
   `justifyContent: 'flex-end'` seven times over. */
.row-end { justify-content: flex-end; }
.row-between { justify-content: space-between; }

/* A block of running prose, held to a readable measure. */
.prose { max-width: 68ch; line-height: var(--lh-body); color: var(--txt-2); }

/* ---------- reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  .page { transform: none !important; }
}
