/* site/public/site.css — layout and structure for the one page at ifiok.app.
 *
 * THIS FILE NAMES VARIABLES AND NEVER VALUES. Every colour, every space, every
 * type size comes from tokens.css, which site/build.mjs generates out of
 * theme/tokens.ts — the one owner of all of them (CLAUDE.md §12). If you find
 * yourself typing a hex code here, the value belongs in theme/tokens.ts.
 *
 * THE EXCEPTIONS ARE NAMED RATHER THAN SMUGGLED. Two kinds of number appear
 * below that the token system does not own, because they are properties of a
 * WIDE SCREEN and the app has none:
 *   - the page's maximum width, in rem, which is also the reading measure
 *   - hairline border widths, in px
 * A phone-shaped app never needed a column that stops growing. Each is marked
 * `/* layout, untokened *\/` where it appears.
 */

/* ---- the one layout measure the app does not own ----------------------- */
:root {
  /* THE COLUMN IS THE MEASURE, which is why there is one number here and not
     two. The first draft set a 46rem page and capped paragraphs at 66ch inside
     it, so body copy stopped short of the column it sat in; the fix is to
     narrow the page until the comfortable measure IS the column, after which
     nothing needs a max-width and no block can look part-filled.

     MEASURED, NOT ESTIMATED, and the first attempt at this number was wrong in
     a way worth recording. `66ch` is 66 ZERO-widths — and a zero is 0.497em in
     Source Sans 3 (theme/tokens.ts records the advance), while average text
     with its spaces runs about 0.34em. So a column set to "66ch" actually
     carried ~100 characters per line, half as much again as intended, and a
     comment claiming 72 was measuring the wrong unit. Counted off the rendered
     line boxes instead, by walking a Range through the text node and watching
     the line-box top change: 608px of text gave 98-103 characters per line.
     30rem - the two 16px gutters = 448px. Counted off the rendered page after
     setting it: a median of 79 characters per line. That is a little over
     Bringhurst's upper bound and is kept, because tightening further starts
     to starve the step cards. 79 is the measured number, not the predicted
     one — the prediction was 74, and the gap is the point. */
  --page-max: 30rem; /* layout, untokened */
  --hairline: 1px; /* layout, untokened */
}

/* ---- reset, kept to what this page actually needs ---------------------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

body,
h1,
h2,
h3,
p,
ul,
ol,
li,
dl,
dt,
dd,
figure {
  margin: 0;
  padding: 0;
}

ul,
ol {
  list-style: none;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  /* An explicit background, so the page never inherits the browser's white
     behind a dark palette. */
  background: var(--color-ground);
  color: var(--color-ink);
  font-family: var(--type-body-family);
  font-size: var(--type-body-size);
  line-height: var(--type-body-line);
  /* The app's body size is 17px and is the hard floor for field-read content
     (theme/tokens.ts). A website is read at arm's length on a desk, but the
     floor is kept rather than second-guessed — it is the founder's ratified
     reading size for this product's voice. */
  -moz-osx-font-smoothing: grayscale;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* ---- the single column ------------------------------------------------- */
.wrap {
  width: 100%;
  max-width: var(--page-max);
  margin-inline: auto;
  padding-inline: var(--space-screen-margin);
}

/* ---- links ------------------------------------------------------------- */
a {
  color: var(--color-primary);
  text-decoration-color: var(--color-primary-tint);
  text-decoration-thickness: from-font;
  text-underline-offset: 0.15em;
}

a:hover {
  text-decoration-color: currentColor;
}

a:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 3px;
  border-radius: var(--radius-mark);
}

/* ---- masthead ---------------------------------------------------------- */
.masthead {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-row);
  padding-block: var(--space-section);
  border-bottom: var(--hairline) solid var(--color-line-faint);
}

.wordmark {
  /* The brand is Ifiok or IFIOK, never iFiok (CLAUDE.md §1) — so the letter
     spacing does the work that a logo would, and no mark is invented here.
     The app has no brand mark yet; site/README.md records that as owed. */
  font-family: var(--type-heading-family);
  font-size: var(--type-heading-size);
  line-height: var(--type-heading-line);
  letter-spacing: 0.08em; /* layout, untokened: wordmark tracking */
  text-transform: uppercase;
  color: var(--color-ink);
}

.masthead .tagline {
  color: var(--color-ink-muted);
}

/* ---- hero -------------------------------------------------------------- */
.hero {
  padding-block: var(--space-band) var(--space-section);
}

.eyebrow {
  color: var(--color-primary);
  margin-bottom: var(--space-gap);
}

.promise {
  /* The product promise, in the founder's exact wording (CLAUDE.md §1 — "note
     the precise wording"). It is the headline because it is the outcome, which
     is what DESIGN.md §14 asks a headline to be. */
  font-family: var(--type-display-family);
  font-size: var(--type-display-size);
  line-height: var(--type-display-line);
  letter-spacing: var(--type-display-tracking);
  max-width: 28ch; /* layout, untokened: display measure, tighter than body */
  text-wrap: balance;
}

.lead {
  margin-top: var(--space-gap);
  color: var(--color-ink-muted);
}

/* ---- the status panel -------------------------------------------------- */
.status {
  margin-top: var(--space-section);
  padding: var(--space-card-pad);
  background: var(--color-raised);
  /* A BRASS RULE, NOT A CAUTION COLOUR, and the choice is deliberate: in this
     system `caution` and `hazard` are the severity ladder and carry fixed
     meanings (DESIGN.md §5, D53). "Not released yet" is not a severity, and
     dressing it as one would spend an ink the app needs elsewhere. */
  border-left: 3px solid var(--color-primary); /* layout, untokened */
  border-radius: var(--radius-container);
}

.status p + p {
  margin-top: var(--space-snug);
}

.status .muted {
  color: var(--color-ink-muted);
}

/* ---- sections ---------------------------------------------------------- */
section {
  padding-block: var(--space-section);
}

section + section {
  border-top: var(--hairline) solid var(--color-line-faint);
}

h2 {
  font-family: var(--type-heading-family);
  font-size: var(--type-heading-size);
  line-height: var(--type-heading-line);
  letter-spacing: var(--type-heading-tracking);
  margin-bottom: var(--space-gap);
  text-wrap: balance;
}

.section-lead {
  color: var(--color-ink-muted);
  margin-bottom: var(--space-section);
}

/* ---- the loop: three steps -------------------------------------------- */
/* STACKED, NOT SIDE BY SIDE. Three cards across a column this narrow would be
   ~133px each, and a card whose content cannot fill it is the one layout fault
   the founder has called out more than once. Full-width rows fill. */
.steps {
  display: grid;
  gap: var(--space-row);
}

.step {
  padding: var(--space-card-pad);
  background: var(--color-surface);
  border-radius: var(--radius-container);
}

.step .num {
  display: block;
  color: var(--color-primary);
  margin-bottom: var(--space-snug);
}

.step h3 {
  font-family: var(--type-title-family);
  font-size: var(--type-title-size);
  line-height: var(--type-title-line);
  margin-bottom: var(--space-tight);
}

.step p {
  color: var(--color-ink-muted);
  font-family: var(--type-caption-family);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-line);
}

/* ---- feature rows ------------------------------------------------------ */
.features {
  display: grid;
  gap: var(--space-section);
}

.feature h3 {
  font-family: var(--type-title-family);
  font-size: var(--type-title-size);
  line-height: var(--type-title-line);
  margin-bottom: var(--space-snug);
}

.feature p + p {
  margin-top: var(--space-snug);
}

/* A qualification that the app is required to carry on screen — tides are
   astronomical only, the barometer is a trend not a forecast, the library is
   reference for the already-trained (CLAUDE.md §8). It travels with the claim
   here for the same reason it does there, and is not a footnote. */
.qualify {
  color: var(--color-ink-muted);
  font-family: var(--type-caption-family);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-line);
}

/* ---- price ------------------------------------------------------------- */
.tiers {
  display: grid;
  gap: var(--space-row);
  margin-bottom: var(--space-section);
}

.tier {
  padding: var(--space-card-pad);
  background: var(--color-surface);
  border-radius: var(--radius-container);
}

.tier.unlock {
  background: transparent;
  border: var(--hairline) solid var(--color-line);
}

.tier .amount {
  font-family: var(--type-data-md-family);
  font-size: var(--type-data-md-size);
  line-height: var(--type-data-md-line);
  display: block;
}

.tier .amount-note {
  display: block;
  color: var(--color-ink-muted);
  font-family: var(--type-caption-family);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-line);
  margin-bottom: var(--space-gap);
}

.tier ul {
  display: grid;
  gap: var(--space-snug);
}

.tier li {
  padding-left: var(--space-gap);
  position: relative;
  font-family: var(--type-caption-family);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-line);
}

.tier li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 5px; /* layout, untokened: list marker */
  height: 5px;
  border-radius: var(--radius-pill);
  background: var(--color-primary);
}

.rules {
  display: grid;
  gap: var(--space-row);
}

.rules dt {
  font-family: var(--type-body-strong-family);
  font-size: var(--type-body-strong-size);
  line-height: var(--type-body-strong-line);
}

.rules dd {
  color: var(--color-ink-muted);
}

/* ---- what it is not ---------------------------------------------------- */
.nots {
  display: grid;
  gap: var(--space-row);
}

.nots li {
  /* `band` (48) left the dash visibly adrift from the sentence it marks; at
     `section` (32) the two read as one unit. */
  padding-left: var(--space-section);
  position: relative;
}

.nots li::before {
  /* An en dash, not a cross or an icon: the list is a set of honest absences,
     not failures, and a red mark would read as the severity ladder again. */
  content: '\2014';
  position: absolute;
  left: 0;
  color: var(--color-ink-muted);
}

.nots strong {
  font-family: var(--type-body-strong-family);
}

/* ---- footer ------------------------------------------------------------ */
footer {
  padding-block: var(--space-section) var(--space-page);
  border-top: var(--hairline) solid var(--color-line);
  color: var(--color-ink-muted);
  font-family: var(--type-caption-family);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-line);
}

footer .rows {
  display: grid;
  gap: var(--space-row);
}

footer .name-note {
  color: var(--color-ink);
}

/* ---- reduced motion ---------------------------------------------------- */
/* There is no motion on this page to reduce. The block is absent on purpose
   rather than written empty — nothing here animates, and a page that declares
   a motion preference it never uses invites belief in a mechanism that is not
   there (the reasoning theme/tokens.ts records for the tabular-figures
   no-op). */

/* ---- the privacy policy page ------------------------------------------- */
/* Shares this stylesheet with the landing page rather than carrying its own,
   so the two cannot drift apart. Everything below is structure the landing
   page has no use for: a document with numbered sections and real lists. */

.policy h1 {
  font-family: var(--type-heading-family);
  font-size: var(--type-heading-size);
  line-height: var(--type-heading-line);
  letter-spacing: var(--type-heading-tracking);
  margin-bottom: var(--space-snug);
}

.policy .updated {
  color: var(--color-ink-muted);
  font-family: var(--type-caption-family);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-line);
  margin-bottom: var(--space-section);
}

.policy section {
  padding-block: 0;
  border: 0;
  margin-bottom: var(--space-section);
}

.policy h2 {
  font-family: var(--type-title-family);
  font-size: var(--type-title-size);
  line-height: var(--type-title-line);
  letter-spacing: normal;
  margin-bottom: var(--space-snug);
}

.policy p + p,
.policy p + ul,
.policy ul + p {
  margin-top: var(--space-row);
}

.policy ul {
  display: grid;
  gap: var(--space-snug);
  margin-top: var(--space-row);
}

.policy li {
  padding-left: var(--space-gap);
  position: relative;
}

.policy li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 5px; /* layout, untokened: list marker, as .tier li */
  height: 5px;
  border-radius: var(--radius-pill);
  background: var(--color-primary);
}

/* A term being defined inside a list item — the three prep-time calls. */
.policy li strong {
  font-family: var(--type-body-strong-family);
}

.backlink {
  display: inline-block;
  margin-bottom: var(--space-section);
  font-family: var(--type-caption-family);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-line);
}

/* ---- strong ------------------------------------------------------------ */
/* WEIGHT RIDES ON THE FAMILY NAME in this system, and there is deliberately no
   fontWeight token (D53, theme/tokens.ts: every face is selected by name, e.g.
   SourceSans3_600SemiBold). So `font-weight: bold` would have the browser
   SYNTHESISE a bold by smearing the regular face, rather than use the semibold
   that is actually shipped. Name the face and turn the synthesis off.

   Global, because `strong` appears in the status panel, the absences list and
   the policy's prose, and three selectors that each had to remember this is
   how one of them ends up faux-bold. */
strong,
b {
  font-family: var(--type-body-strong-family);
  font-weight: normal;
}
