/* ============================================================
   Vita 365 — v2 design system ("clean & airy", Apple-Health tone)

   Source: the prototype at `design/ui-redesign-prototype:demo/tokens.css`.
   Migration plan: docs/PLAN_UI_REDESIGN_MIGRATION.md (PR-1 of 12).

   ── Why every name carries a `--v2-` prefix ───────────────────────
   The prototype declared its tokens unprefixed (`--bg`, `--ink`,
   `--brand`, `--line`, `--font`, `--ok/warn/bad`, …) because it was a
   sandbox that loaded nothing else. In the app those names are already
   taken: `assets/styles.css` defines `--ink: #1B1F18` and
   `--ink-2: #3A3F35`, and roughly fifteen call sites across
   `mypage/*.html`, `mypage/mypage.css` and `admin/` read them. Dropping
   the prototype file in as-is would have re-pointed `--ink-2` from
   #3A3F35 to #5E6764 on every page that loads it — a silent, sitewide
   text-color shift, and one that no screen asked for.

   So: this file only ever declares `--v2-*`. It is purely additive.
   The legacy `--ink/--forest/--cream` family in styles.css is untouched,
   exactly as the `--vh-*` family was additive over it before. That one
   is gone now: every screen that read it carries `.v2`, whose bridge
   below re-declared all 26 of its tokens, so assets/vh-tokens.css was
   deleted once disabling it changed nothing on any of them.

   `api/ui/tokens.test.js` enforces the prefix, so PR-2..6 cannot
   reintroduce the collision while extending this file.

   ── Why the behavioral rules are scoped to `.v2` ──────────────────
   The prototype also shipped global rules: a focus ring on every
   interactive element, a reduced-motion block, and hit-area helpers.
   Those are correct for v2 screens and wrong to impose on legacy ones —
   PR-2 links this file into `mypage/index.html`, a shell that still
   renders old widgets, and an unscoped `a:focus { outline: … }` with
   `!important` would restyle all of them in a PR whose subject is the
   home screen. Everything below `:root` therefore requires an ancestor
   carrying `class="v2"`. Opting a subtree in is one attribute.
   ============================================================ */
:root {
  /* ── Surfaces ─────────────────────────────────────────────── */
  --v2-bg:            #F6F7F6;   /* app canvas — quiet warm-neutral gray */
  --v2-surface:       #FFFFFF;   /* cards */
  --v2-surface-2:     #F4F6F5;   /* inset / subtle fills */
  --v2-surface-sunken:#ECEEEC;

  /* ── Muted green accent (the one hero color) ──────────────────
     Calmer than a neon mint: desaturated, closer to eucalyptus.
     Used sparingly — primary action, active tab, key figures.

     CONTRAST RULE — white-on-`--v2-brand` is only 3.95:1, which passes
     the 3:1 bar for icons/graphics but FAILS the 4.5:1 bar for text.
     So: `--v2-brand` for fills that carry no text (rings, bars, dots,
     check glyphs, FAB), `--v2-brand-btn` for any surface with a white
     LABEL on it (5.39:1). */
  --v2-brand:         #3E8E72;   /* graphic fills only */
  --v2-brand-btn:     #33765E;   /* filled buttons with white text */
  --v2-brand-strong:  #33765E;   /* pressed / text-on-light */
  --v2-brand-ink:     #2A6250;   /* accent text that must pass contrast */
  --v2-brand-tint:    #EBF2EF;   /* soft fill behind brand elements */
  --v2-brand-tint-2:  #DCE9E4;

  /* ── Supporting data tints ────────────────────────────────────
     Deliberately low-chroma so three metrics side by side read as
     one calm family rather than a traffic light.

     Rings and macro bars carry meaning, so each must clear the 3:1
     non-text bar on white (WCAG 1.4.11). Measured on white:
     cal 3.95:1, move 3.96:1, body 3.51:1 — and near-equal luminance
     keeps them reading as one family. */
  --v2-c-cal:   #3E8E72;   /* nutrition = brand */
  --v2-c-move:  #AD7340;   /* activity — muted clay */
  --v2-c-body:  #6E8CA8;   /* body/weight — muted slate blue */
  --v2-c-cal-tint:  #EBF2EF;
  --v2-c-move-tint: #F5EDE5;
  --v2-c-body-tint: #EDF1F5;

  /* ── Text ─────────────────────────────────────────────────────
     Every value here clears WCAG AA (4.5:1) on both --v2-surface and
     --v2-bg. Measured: ink 16.4:1, ink-2 5.83:1, ink-3 5.09:1 / 4.74:1.
     Do not lighten --v2-ink-3 again — it was #909794 (2.98:1) and failed. */
  --v2-ink:         #1A211E;   /* soft near-black — easier than pure #000 */
  --v2-ink-2:       #5E6764;   /* secondary */
  --v2-ink-3:       #68706C;   /* tertiary / captions */
  --v2-ink-inv:     #FFFFFF;
  --v2-ink-on-brand:#123829;

  /* ── Borders / lines ──────────────────────────────────────── */
  --v2-line:       #EAEDEB;
  --v2-line-2:     #DFE3E1;

  /* ── Status — AA-safe as text on white (5.0:1 / 6.1:1) ────── */
  --v2-ok:   #33765E;
  --v2-warn: #96652F;
  --v2-bad:  #A34433;

  /* ── Radii — big & rounded = friendly/native ──────────────── */
  --v2-r-xl: 28px;   /* hero cards */
  --v2-r-lg: 22px;   /* standard cards */
  --v2-r-md: 16px;   /* inner blocks, buttons */
  --v2-r-sm: 12px;
  --v2-r-pill: 999px;

  /* ── Shadows — whisper-soft; cards mostly float on a hairline ─ */
  --v2-sh-card: 0 1px 2px rgba(20,35,30,.03), 0 4px 14px rgba(20,35,30,.035);
  --v2-sh-pop:  0 8px 28px rgba(20,35,30,.10);
  --v2-sh-tab:  0 -1px 0 var(--v2-line);

  /* ── Type ─────────────────────────────────────────────────────
     Noto Sans for Latin, Noto Sans KR for Hangul. Two families, not
     one: the browser resolves the family list per GLYPH, so Latin
     takes the first entry that has it (Noto Sans) and Hangul falls
     through to the second (Noto Sans KR). Ordering IS the rule —
     swapping them would render English in the KR face's Latin, which
     is a different, wider design.

     This replaced Pretendard, which covered both scripts in one file
     but is not what the brand runs on. The v2 direction drops the
     serif entirely, so there is no `--v2-font-serif` counterpart to
     `--vh-font-serif`.

     Neither Noto family ships Simplified-Chinese glyph forms. Noto
     Sans KR *does* carry many of the same code points as Hanja, so
     Chinese copy would silently render in Korean letterforms — a
     native reader sees that immediately. `--v2-font-zh` puts the
     system's own CJK face first for zh; mypage.css and styles.css
     switch onto it from `html[lang="zh"]`. */
  --v2-font: 'Noto Sans', 'Noto Sans KR', -apple-system, BlinkMacSystemFont,
             'SF Pro Text', 'Apple SD Gothic Neo', system-ui, sans-serif;
  --v2-font-zh: 'Noto Sans', 'PingFang SC', 'Hiragino Sans GB',
                'Microsoft YaHei', -apple-system, BlinkMacSystemFont,
                system-ui, sans-serif;
  /* Reference numbers, tracking numbers, code in a coach reply — the
     places where character alignment carries meaning. System faces
     only; there is no third webfont to download for six call sites.
     styles.css aliases this as --mono for the pages already reading
     that name. */
  --v2-mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace;
  /* numeric display — tight tracking, tabular where useful */
  --v2-num-tracking: -0.02em;

  /* ── Type scale ───────────────────────────────────────────────
     Nine steps, one per ROLE. Before this the app carried 35 distinct
     font-sizes — including 9.5, 10.5, 11.5, 12.5, 13.5, 14.5, 15.5
     and 16.5 — and the same role drew at a different size on nearly
     every screen: a page title was 24px on Workout, 26px on six
     screens, 28px on Weight Tracker, 32px on Home, and a clamp() to
     36px in the shell. Section headings ran 17/18/19/20/22/26.
     Nothing chose those numbers; they accumulated.

     The values are the ones the app already used most, so this is a
     de-drift, not a resize: body copy stays at 15, captions at 13.
     Anything half-pixel snaps up to the nearest whole step — a
     half-pixel is invisible as design and visible as inconsistency.

     Sizes are px, not rem. The shell pins `html` to 16px and several
     screens hardcode control sizes against that; rem here would only
     add a second unit without adding user-scaling we do not yet
     honour end to end.

     Eleven steps, named for the role rather than the size, so a call
     site says what it is. Read them top to bottom as a hierarchy:
     one hero figure per screen, one title per screen, then sections.

     Why 22 exists between 18 and 26: without it the scale jumped
     straight from a section heading to a page title, and the ~19 call
     sites that sit between them (sheet and modal titles, the headline
     figure on a stat card) had nowhere to land. A step that is missing
     is how drift starts. */
  --v2-fs-hero:     44px;  /* the one number a screen is about (weight, BMI) */
  --v2-fs-display:  32px;  /* secondary figures — ring centres, totals */
  --v2-fs-title:    26px;  /* screen title, one per screen (h1) */
  --v2-fs-subtitle: 22px;  /* sheet / modal title, stat-card headline figure */
  --v2-fs-section:  18px;  /* section and card heading (h2) */
  --v2-fs-h3:       16px;  /* heading inside a card, list-row title */
  --v2-fs-body:     15px;  /* body copy, primary list text */
  --v2-fs-sm:       14px;  /* secondary body, dense rows, buttons */
  --v2-fs-caption:  13px;  /* the 보조글 under a title — meta, hints */
  --v2-fs-label:    12px;  /* field labels, badges, overlines */
  --v2-fs-micro:    11px;  /* tab-bar labels, tracking numbers — the floor */

  /* Text-entry controls. Not a step on the scale above — a browser
     constant. iOS Safari zooms the whole page when a focused control
     renders under 16px, and the zoom does not undo itself: the user is
     left on a magnified, side-scrolling screen. So every input,
     textarea and select sits here regardless of how dense its screen
     is, and this must never drop below 16px.

     It happens to equal --v2-fs-h3 today. Keep them separate anyway:
     one is a design decision and the other is not ours to make. */
  --v2-fs-control:  16px;

  /* ── Icon sizes ───────────────────────────────────────────────
     A separate axis on purpose. Tabler icons are a webfont, so their
     size is `font-size` too, and normalising them onto the text scale
     would either shrink glyphs meant to be tappable or inflate copy.

     These are for the repeated CHROME roles only — the tab bar, a
     list row's leading icon, a disclosure chevron — which had drifted
     to 18/19/20/21/23px for the same job across five screens.

     An icon set inline with a sentence is NOT one of these: it scales
     with the text beside it, so a 13px glyph next to a 13px caption is
     correct and forcing it to 16 would be worse. Leave those as
     literals. Not every number wants to be a token. */
  --v2-ic-sm: 16px;   /* inline with body copy */
  --v2-ic-md: 18px;   /* list-row leading icon, chevrons */
  --v2-ic-lg: 20px;   /* section icon, sheet items */
  --v2-ic-xl: 24px;   /* tab bar, FAB, primary actions */

  /* ── Line height ──────────────────────────────────────────────
     Korean needs more leading than Latin at the same size — the
     syllable blocks are denser. These are tuned for KR and read as
     merely generous in English.

     --v2-lh-tight is for headings, where the extra leading of body
     copy makes a two-line title look like two separate lines. */
     Five steps against the fifteen distinct values the app carried
     (1.1, 1.15, 1.2, 1.22, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6,
     1.65, 1.7). Each absorbs its neighbours, so nothing moves by more
     than 0.1 — this straightens the rhythm, it does not re-space the
     app. A bare `line-height: 1` stays literal where it appears: that
     means "no leading at all" on a numeral or a glyph, which is a
     different intent from any step here. */
  --v2-lh-num:   1.15;  /* big figures — leading would just add gaps */
  --v2-lh-tight: 1.25;  /* screen and sheet titles */
  --v2-lh-snug:  1.4;   /* section headings, single-line rows, labels */
  --v2-lh-body:  1.55;  /* body and captions — matches the global body */
  --v2-lh-loose: 1.6;   /* long-form prose — legal, articles */

  /* ── Weight ───────────────────────────────────────────────────
     Four, matching what the Noto webfonts load. 600 is the workhorse
     for headings; 700 is reserved for figures and h1 so that "bold"
     still means something. */
  --v2-fw-regular:  400;
  --v2-fw-medium:   500;
  --v2-fw-semibold: 600;
  --v2-fw-bold:     700;

  /* ── Spacing scale ────────────────────────────────────────── */
  --v2-sp-1: 4px;  --v2-sp-2: 8px;  --v2-sp-3: 12px; --v2-sp-4: 16px;
  --v2-sp-5: 20px; --v2-sp-6: 24px; --v2-sp-7: 32px; --v2-sp-8: 40px;

  /* Safe-area (native feel on notched phones) */
  --v2-safe-top: env(safe-area-inset-top, 0px);
  --v2-safe-bot: env(safe-area-inset-bottom, 0px);
}

/* ── Keyboard focus ───────────────────────────────────────────────
   Every interactive element inside a `.v2` subtree gets a visible ring.

   `!important` is deliberate. Screens set `outline: none` on inputs and
   lean on a `:focus-within` border instead, and those page rules load
   after this file — a low-specificity rule (e.g. `:where(...)`) loses to
   them and the ring silently disappears. The focus indicator is an
   accessibility floor, so it has to be the one thing pages cannot
   accidentally remove.

   Three rules, in this order, so a ring is guaranteed on every engine:
     1. `:focus`                    — always draws (works on old WebKit,
                                      which the iOS WebView can be).
     2. `:focus:not(:focus-visible)`— modern engines take the ring back
                                      off for pointer users.
     3. `:focus-visible`            — and put it back for keyboard users.
   An engine that does not know `:focus-visible` simply ignores 2 and 3
   and keeps the always-on ring: over-showing, never under-showing. */
.v2 a:focus,
.v2 button:focus,
.v2 input:focus,
.v2 textarea:focus,
.v2 select:focus,
.v2 summary:focus,
.v2 [tabindex]:focus {
  outline: 2.5px solid var(--v2-brand-strong) !important;
  outline-offset: 2px !important;
}
.v2 a:focus:not(:focus-visible),
.v2 button:focus:not(:focus-visible),
.v2 input:focus:not(:focus-visible),
.v2 textarea:focus:not(:focus-visible),
.v2 select:focus:not(:focus-visible),
.v2 summary:focus:not(:focus-visible),
.v2 [tabindex]:focus:not(:focus-visible) {
  outline: none !important;
}
.v2 a:focus-visible,
.v2 button:focus-visible,
.v2 input:focus-visible,
.v2 textarea:focus-visible,
.v2 select:focus-visible,
.v2 summary:focus-visible,
.v2 [tabindex]:focus-visible {
  outline: 2.5px solid var(--v2-brand-strong) !important;
  outline-offset: 2px !important;
}
/* Green would vanish on a dark surface — the workout rest timer is the
   one the prototype hit (`.rest`). Mark any such block `v2-on-dark`
   rather than naming screen-specific classes here. */
.v2 .v2-on-dark a:focus,
.v2 .v2-on-dark button:focus,
.v2 .v2-on-dark a:focus-visible,
.v2 .v2-on-dark button:focus-visible {
  outline-color: #FFFFFF !important;
}

/* ── Touch targets ───────────────────────────────────────────────
   iOS HIG asks for 44x44pt. Several controls are deliberately small
   for visual rhythm (steppers, close buttons, checkboxes), so this
   grows only the INVISIBLE hit area and leaves the drawn size alone.

   `.v2-hit` must sit on the control itself: the rule needs its own
   `::after`, and a shared one (`.a, .b::after { … }`) would hand the
   absolute positioning to `.a` and break the layout instead. */
.v2 .v2-hit { position: relative; }
.v2 .v2-hit::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: max(44px, 100%);
  height: max(44px, 100%);
}

/* Visible to screen readers only — for naming an icon-only control
   where an aria-label would fight with a nested tooltip/label. */
.v2 .v2-sr {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Respect users who ask for less motion. */
@media (prefers-reduced-motion: reduce) {
  .v2, .v2 *, .v2 *::before, .v2 *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}
