/* ============================================================
   system.css — the design system for MyPotential.

   theme.css owns COLOUR (three dark themes + legacy colour aliases).
   This file owns everything colour can't express: the spacing scale,
   the radius scale, the type scale, and the handful of components
   every page is allowed to use.

   WHY THIS EXISTS
   Before this file, `theme.css` was 6.3 KB of colour tokens and the
   pages carried ~340 KB of inline CSS between them. There were no
   spacing, radius or type tokens at all, so each page invented its
   own: ~29 distinct font sizes and up to 20 radii PER PAGE, none of
   them shared. That is the mechanical reason the app reads as five
   different products. Everything here exists to collapse that.

   RULES
   1. New CSS uses these tokens. A raw px font-size or radius in a
      page's <style> is a bug unless it is genuinely one-off art.
   2. Selectors are `html:root` for the same reason theme.css uses it —
      specificity (0,1,1) beats a page's own `:root` block (0,1,0), so
      pages keep their local definitions as harmless fallbacks and
      these win, with no need to gut each page's stylesheet first.
      That is what makes this file safe to land BEFORE the migration.
   3. Component classes are prefixed `lm-` so they can never collide
      with a page's existing class names during the migration.
   4. faith.html is deliberately EXCLUDED from this system — it is a
      separate sub-app by decision, and it keeps its gold and its own
      chrome. Do not "fix" it to match.
   ============================================================ */

html:root {
  /* ---- type faces -------------------------------------------------
     These were previously declared in index/health/gym only; finance
     and calories declared neither and fell back to the UA default,
     which is a large part of why they look foreign. Declared once,
     here, so every page gets them including the ones that never
     asked. ---------------------------------------------------------- */
  --font: -apple-system, BlinkMacSystemFont, "Inter", "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  /* ---- type scale -------------------------------------------------
     MEASURED, not invented. The first version of this scale was written
     before counting anything, and the count said it was wrong: across
     the 14 non-faith pages there are 929 font-size declarations using
     44 distinct values, and the most common single size is 11px (123
     uses) followed by 13px (112) and 12px (94) — all BELOW the old
     scale's smallest rung of 12px. Snapping the app's densest text
     upward would have inflated every metadata row in the product.
     The old 12 / 12.5 / 13.5 rungs were also half a pixel apart, which
     is noise rather than a scale, and there was no rung at all for the
     44px ring numbers on the calorie and screen-time heroes.

     Every rung here is at least 2px from its neighbours, and
     test/unit/tokenDiscipline.test.js enforces that — it is what caught
     --fs-h3 sitting at 16px against a 15px body, which was the same
     indistinguishable-step problem in a different part of the ramp.

     These nine are the real working set, so migrating a page moves most
     declarations by 1px or less. Sized for a 375px phone; the display
     sizes step up past 480px (media query below) rather than being
     fluid, so vertical rhythm stays predictable.

     11px is deliberate at the bottom. WCAG sets no minimum font size —
     the readability problem this system fixes was CONTRAST (see
     --text-label: those labels were 4.25:1 and are now 9.8:1). A dense
     instrument panel is allowed small type; it is not allowed grey. */
  --fs-hero: 44px;      /* the one huge number in a ring (kcal left, hours) */
  --fs-display: 32px;   /* page-level headline number */
  --fs-h1: 26px;        /* page title */
  --fs-h2: 20px;        /* card title */
  --fs-h3: 17px;        /* sub-head, list-row title */
  --fs-body: 15px;      /* body copy, inputs */
  --fs-sm: 13px;        /* secondary copy, buttons */
  --fs-micro: 11px;     /* mono eyebrow labels, dense metadata */

  /* NOTE: there is deliberately no rung between 11 and 13, or 13 and 15.
     The app had 11, 12, 13, 14, 15 AND 16 all in live use — 495 declarations
     across six sizes inside a 5px span, which is not a hierarchy, it is
     mush: nobody can see a 1px step, so the sizes carried no meaning and
     every page drifted. Three rungs 2px apart in the small band are
     actually distinguishable, and that is the whole point of a scale. */

  --lh-tight: 1.15;     /* display + h1 */
  --lh-snug: 1.3;       /* h2/h3 */
  --lh-body: 1.5;       /* body copy */

  --fw-regular: 400;
  --fw-medium: 500;
  --fw-semibold: 600;
  --fw-bold: 700;

  /* Tabular figures for anything that counts. A number that changes
     must not reflow the text around it. */
  --num: 1;

  /* ---- spacing scale ----------------------------------------------
     4px base. Every margin/padding/gap in new CSS comes from here. --- */
  --s-1: 4px;
  --s-2: 8px;
  --s-3: 12px;
  --s-4: 16px;
  --s-5: 20px;
  --s-6: 24px;
  --s-7: 32px;
  --s-8: 48px;

  /* ---- radius scale ------------------------------------------------
     Also measured: 449 declarations across 22 distinct values. These six
     rungs are placed so that every existing value moves by AT MOST 2px,
     which at these radii is imperceptible — that is what makes a
     wholesale migration safe to do mechanically. The old four rungs
     would have moved some corners by 6px, which is not. */
  --r-xs: 6px;          /* progress bars, tiny chips */
  --r-sm: 10px;         /* inputs, small buttons */
  --r-md: 12px;         /* nested/inner cards, icon badges */
  --r-lg: 16px;         /* the standard card */
  --r-xl: 20px;         /* large cards */
  --r-2xl: 24px;        /* hero cards */
  --r-pill: 999px;

  /* ---- layout ------------------------------------------------------ */
  --page-max: 560px;    /* content never gets wider than this, even on iPad */
  --page-pad: var(--s-4);
  --tap-min: 44px;      /* Apple HIG minimum. Enforced on .lm-btn. */

  /* ---- accessible label colour -------------------------------------
     MEASURED: --text-tertiary (#76746E) is 4.25:1 on the app
     background — it passes AA only for large text, and every mono
     eyebrow in the app was using it at 11px. That is the app's worst
     readability problem and it is systemic, not per-page.
     --text-label points at --text-secondary (9.8:1) instead. Micro
     labels use THIS, never --text-tertiary. -------------------------- */
  --text-label: var(--text-secondary);
}

/* Larger phones and up: step the display sizes, not the body. */
@media (min-width: 481px) {
  html:root {
    --fs-hero: 52px;
    --fs-display: 36px;
    --fs-h1: 28px;
    --fs-h2: 21px;
    --page-pad: var(--s-5);
  }
}

/* ============================================================
   Base
   ============================================================ */
.lm-page {
  max-width: var(--page-max);
  margin-inline: auto;
  padding-inline: var(--page-pad);
}

/* Vertical rhythm without per-child margins. Use on a page section
   or a card body and let the gap do the spacing. */
.lm-stack { display: flex; flex-direction: column; gap: var(--s-4); }
.lm-stack--tight { gap: var(--s-2); }
.lm-stack--loose { gap: var(--s-6); }

.lm-hairline { height: 1px; background: var(--hairline); border: 0; margin: 0; }

/* ============================================================
   Type
   ============================================================ */
.lm-display,
.lm-h1, .lm-h2, .lm-h3 { margin: 0; font-family: var(--font); color: var(--text-primary); }

.lm-display { font-size: var(--fs-display); line-height: var(--lh-tight); font-weight: var(--fw-bold); letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.lm-h1 { font-size: var(--fs-h1); line-height: var(--lh-tight); font-weight: var(--fw-bold); letter-spacing: -0.02em; }
.lm-h2 { font-size: var(--fs-h2); line-height: var(--lh-snug); font-weight: var(--fw-bold); letter-spacing: -0.01em; }
.lm-h3 { font-size: var(--fs-h3); line-height: var(--lh-snug); font-weight: var(--fw-semibold); }

.lm-body { margin: 0; font-size: var(--fs-body); line-height: var(--lh-body); color: var(--text-secondary); }
.lm-body--primary { color: var(--text-primary); }
.lm-sm { margin: 0; font-size: var(--fs-sm); line-height: var(--lh-body); color: var(--text-secondary); }
.lm-xs { margin: 0; font-size: var(--fs-micro); line-height: var(--lh-body); color: var(--text-tertiary); }

/* The mono eyebrow. One definition, app-wide, at an accessible size
   and colour. Tracking is tight enough to stay legible on a phone —
   the old 0.18em at 11px was the worst offender. */
.lm-eyebrow {
  display: flex; align-items: center; gap: var(--s-2);
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--text-label);
}
.lm-eyebrow--quiet { color: var(--text-tertiary); }  /* only for non-essential text */

/* Any number the user reads as a measurement. */
.lm-num { font-variant-numeric: tabular-nums; }

/* ============================================================
   Section header — the "LABEL ————— action" row above a group
   ============================================================ */
.lm-sec {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--s-3);
  margin-bottom: var(--s-3);
}
.lm-sec-action {
  font-family: var(--font-mono); font-size: var(--fs-micro);
  color: var(--text-tertiary); text-decoration: none;
  letter-spacing: 0.08em; text-transform: uppercase;
  padding: var(--s-2) 0; /* keeps the tap target honest without moving the baseline */
}
.lm-sec-action:hover { color: var(--text-primary); }

/* ============================================================
   Card
   ============================================================ */
.lm-card {
  background: var(--surface);
  border: 1px solid var(--surface-border);
  border-radius: var(--r-lg);
  padding: var(--s-5);
}
.lm-card--tight { padding: var(--s-4); }
.lm-card--hero { border-radius: var(--r-2xl); padding: var(--s-6); }
.lm-card--inner { background: var(--surface-2); border-radius: var(--r-md); padding: var(--s-4); }
.lm-card--accent { border-color: var(--accent-border); background: var(--accent-soft); }

/* A card that is also a link. */
a.lm-card { display: block; text-decoration: none; color: inherit; transition: border-color 0.15s, background 0.15s; }
a.lm-card:hover { border-color: var(--surface-hover); background: var(--surface-2); }

/* ============================================================
   Stat tile — the health.html pattern, promoted to the system.
   This is the app's default way to show a number. Label on top,
   value large, unit small beside it, optional sub-line underneath.
   ============================================================ */
.lm-tile {
  display: block; text-decoration: none; color: inherit;
  background: var(--surface);
  border: 1px solid var(--surface-border);
  border-radius: var(--r-md);
  padding: var(--s-4);
  transition: border-color 0.15s, background 0.15s;
}
a.lm-tile:hover, button.lm-tile:hover { border-color: var(--surface-hover); background: var(--surface-2); }
button.lm-tile { width: 100%; text-align: left; font-family: inherit; cursor: pointer; }

.lm-tile-label {
  display: flex; align-items: center; gap: var(--s-2);
  font-family: var(--font-mono); font-size: var(--fs-micro);
  font-weight: var(--fw-semibold); letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--text-label);
  margin-bottom: var(--s-3);
}
.lm-tile-label svg, .lm-tile-label i { width: 14px; height: 14px; flex: none; }

.lm-tile-value {
  font-size: var(--fs-h1); font-weight: var(--fw-bold);
  color: var(--text-primary); line-height: 1;
  letter-spacing: -0.02em; font-variant-numeric: tabular-nums;
}
.lm-tile-unit { font-size: var(--fs-sm); font-weight: var(--fw-medium); color: var(--text-tertiary); margin-left: 2px; }
.lm-tile-sub { margin-top: var(--s-2); font-size: var(--fs-sm); color: var(--text-tertiary); }

/* Empty tile: the value slot holds a dash, not a zero. A zero is a
   measurement; a dash is an absence. The app was showing 0 and
   0-day streaks for things that had never been logged, which reads
   as failure rather than as "nothing here yet". */
.lm-tile--empty .lm-tile-value { color: var(--text-tertiary); font-weight: var(--fw-semibold); }

.lm-grid-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-3); }
.lm-grid-4 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--s-2); }
/* minmax(0,1fr) not 1fr: `1fr` is minmax(auto,1fr) and a long word or a
   <select> inside will blow the track out past the viewport. That exact
   bug made finance.html 484px wide in a 390px viewport. */

/* ============================================================
   Buttons — three weights, one size system, always >= 44px tall.
   ============================================================ */
.lm-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s-2);
  min-height: var(--tap-min);
  padding: 0 var(--s-5);
  border-radius: var(--r-pill);
  border: 1px solid transparent;
  font-family: var(--font); font-size: var(--fs-sm); font-weight: var(--fw-semibold);
  cursor: pointer; text-decoration: none;
  -webkit-tap-highlight-color: transparent;
  transition: background 0.15s, border-color 0.15s, transform 0.1s, opacity 0.15s;
}
.lm-btn:active { transform: scale(0.985); }
.lm-btn:disabled, .lm-btn[aria-disabled="true"] { opacity: 0.45; cursor: not-allowed; }
.lm-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Primary is ALWAYS the accent. The app previously had a white primary
   on po-water.html and green everywhere else; there is now one answer. */
.lm-btn--primary { background: var(--accent); color: var(--accent-contrast); }
.lm-btn--primary:hover { background: color-mix(in srgb, var(--accent) 88%, #fff); }

.lm-btn--secondary { background: var(--surface-2); color: var(--text-primary); border-color: var(--surface-border); }
.lm-btn--secondary:hover { background: var(--surface-3); border-color: var(--surface-hover); }

.lm-btn--ghost { background: transparent; color: var(--text-secondary); }
.lm-btn--ghost:hover { color: var(--text-primary); background: var(--surface); }

.lm-btn--block { display: flex; width: 100%; }
.lm-btn--sm { min-height: 36px; padding: 0 var(--s-4); font-size: var(--fs-sm); }

/* ============================================================
   Back control — the most-tapped thing in the app, and it had
   ELEVEN implementations: .back-btn, .back, .exit, .exitbtn,
   .page-exit, .app-back, .nova-back, .r-back, .q-back,
   .form-back-btn, .lm-exit. Several disagreed on the same page's
   neighbours, and calories/screentime/onboarding rendered theirs at
   38x38 and 36x36 — under the 44px minimum tap target, on the one
   control every user hits on every page.

   Two shapes, one definition: with a label, or icon-only when the
   header has no room. Both are 44px tall regardless of what they
   look like, because the touch target is not a styling decision.
   ============================================================ */
.lm-back {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--s-2);
  min-height: var(--tap-min);
  padding: 0 var(--s-4) 0 var(--s-3);
  border-radius: var(--r-pill);
  border: 1px solid var(--surface-border);
  background: var(--surface);
  color: var(--text-secondary);
  font-family: var(--font); font-size: var(--fs-sm); font-weight: var(--fw-semibold);
  text-decoration: none; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  flex: none;
  transition: background 0.15s, border-color 0.15s;
}
.lm-back:hover { background: var(--surface-2); border-color: var(--surface-hover); }
.lm-back:active { transform: scale(0.97); }
.lm-back:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Icon-only: still 44x44, never the 38px square it used to be. */
.lm-back--icon { width: var(--tap-min); padding: 0; }
.lm-back svg, .lm-back :is(i) { width: 17px; height: 17px; flex: none; }

/* The row a page title sits in, beside its back control. Four pages
   defined this with gaps of 10 vs 12 and bottom margins of 16/18/20 —
   differences nobody chose, which is what makes pages feel unrelated. */
.lm-pagehead {
  display: flex; align-items: center; gap: var(--s-3);
  margin-bottom: var(--s-5);
  padding-top: var(--s-2);
}
.lm-pagehead-title {
  flex: 1; min-width: 0;
  margin: 0;
  font-size: var(--fs-h2); font-weight: var(--fw-bold);
  color: var(--text-primary); letter-spacing: -0.02em;
  display: flex; align-items: center; gap: var(--s-2);
}

/* ============================================================
   Chip / pill
   ============================================================ */
.lm-chip {
  display: inline-flex; align-items: center; gap: var(--s-2);
  padding: var(--s-2) var(--s-3);
  border-radius: var(--r-pill);
  border: 1px solid var(--surface-border);
  background: var(--surface);
  font-size: var(--fs-sm); font-weight: var(--fw-semibold);
  color: var(--text-secondary);
}
.lm-chip--accent { border-color: var(--accent-border); background: var(--accent-soft); color: var(--accent); }
.lm-chip--quiet { border-color: transparent; background: var(--surface-2); color: var(--text-tertiary); }

/* ============================================================
   Inputs
   ============================================================ */
.lm-input {
  width: 100%;
  min-height: var(--tap-min);
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-sm);
  border: 1px solid var(--surface-border);
  background: var(--surface);
  color: var(--text-primary);
  font-family: var(--font); font-size: var(--fs-body);
  transition: border-color 0.15s, background 0.15s;
}
/* 16px minimum on iOS or Safari zooms the whole page on focus. --fs-body
   is 15px, so inputs get their own floor rather than inflating the scale. */
@supports (-webkit-touch-callout: none) { .lm-input { font-size: 16px; } }
.lm-input:focus { outline: none; border-color: var(--accent-border); background: var(--surface-2); }
.lm-input::placeholder { color: var(--text-tertiary); }

/* ============================================================
   iOS zoom guard — applies to EVERY input on every page, not just
   .lm-input, because the pages have their own.

   Mobile Safari zooms the whole viewport when a focused form control's
   font-size is under 16px, and there is no way to zoom back out except
   pinching. The app is full of 13-14px inputs (calories' search and
   goal fields, screentime's hour boxes, the quick-add rows), so tapping
   almost any field on an iPhone threw the layout sideways. This is a
   real bug in the shipped iOS app, not a preference.

   Scoped to touch-capable WebKit so desktop keeps the designed size.
   ============================================================ */
@supports (-webkit-touch-callout: none) {
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
  select,
  textarea { font-size: 16px; }
}

/* ============================================================
   Empty state — one pattern, replacing the ad-hoc dead zones
   (medications.html rendered a bare "—%" above 500px of black).
   ============================================================ */
.lm-empty { text-align: center; padding: var(--s-7) var(--s-4); }
.lm-empty-title { font-size: var(--fs-h3); font-weight: var(--fw-semibold); color: var(--text-secondary); margin: 0 0 var(--s-2); }
.lm-empty-sub { font-size: var(--fs-sm); color: var(--text-tertiary); margin: 0 0 var(--s-4); line-height: var(--lh-body); }

/* ============================================================
   Tap targets

   MEASURED across the app at 375px: the home screen's own primary
   actions were 38-41px tall (#btlAction, #scoreLever, #btlShare),
   health's 26 check-in rating buttons were 35x36, calories had a
   19x23 delete control, settings had ~24 controls at 29-31px, and
   main's exit link was 15px tall. Apple's minimum is 44x44 and the
   app is shipping as a native iPhone app.

   Two tools, because there are two situations:

   .lm-tap-min  — the control is already full-width or free to grow,
                  so just grow it. Layout-safe.
   .lm-tap-hit  — the control must STAY small (an icon button in a
                  dense row, a chip). A centred pseudo-element
                  extends the touch area to 44x44 without changing
                  a single pixel of what is drawn, which is the only
                  way to fix a 19px delete button without redesigning
                  the row around it.
   ============================================================ */
.lm-tap-min { min-height: var(--tap-min); }

.lm-tap-hit { position: relative; }
.lm-tap-hit::after {
  content: '';
  position: absolute;
  top: 50%; left: 50%;
  width: max(100%, var(--tap-min));
  height: max(100%, var(--tap-min));
  transform: translate(-50%, -50%);
  /* Nothing visual — and pointer-events must stay auto, since this
     pseudo-element IS the enlarged hit area. */
}

/* ============================================================
   Utilities
   ============================================================ */
.lm-mt-0 { margin-top: 0; }
.lm-visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

@media (prefers-reduced-motion: reduce) {
  .lm-btn, a.lm-card, .lm-tile { transition: none; }
  .lm-btn:active { transform: none; }
}
