/* Oxygon design tokens, read off the SwiftUI source.
 *
 * Colours are Theme.swift + AccentColorPreference.swift; the ink/separator values
 * are UIKit's semantic colours, which the app uses via `.primary`/`.secondary` and
 * so never spells out itself. Type sizes are Apple's text-style metrics at Dynamic
 * Type Large. Layout caps are Theme.readableWidth and the fixed regular-width
 * columns. Every screen ported to the web reads from here rather than re-deriving.
 */
:root {
  color-scheme: light dark;

  /* --- surfaces --- */
  --bg:              #E8F0FC;                 /* Theme.swift:13 */
  --card:            rgba(255,255,255,0.65);  /* Theme.swift:17 — translucent in light */
  /* A modal is a surface ABOVE the page, and in dark it has to say so. `--bg` on
     `--bg` is one flat field with a dialog somewhere in it — the cards inside
     read, the dialog itself does not. Web-only: the phones push a screen where
     the desktop opens a modal, so there is no `Theme.swift` twin to match.

     **In LIGHT it cannot be #FFFFFF**, which is what it was: `--card` is
     translucent white at 65%, so a white dialog made every card inside it
     disappear — a page of figures floating on one flat field, which is what he
     photographed on 3 Sep. Raising is the shadow and the backdrop's job here;
     the surface only has to stay UNDER the cards, a hair above the page. */
  --bg-raised:       #EDF3FD;

  /* --- the coach's workout types ---
     `WorkoutType.tint` (WorkoutType.swift:13-96). They lived in `coach.html`
     alone, so a Strength session on the Activities board reached for a colour
     that did not exist in that file and fell back to the generic workout green.
     A vocabulary two screens speak belongs in the file both of them load. */
  --wt-green:  #34C759;
  --wt-purple: #AF52DE;
  --wt-amber:  #FFBF00;
  --wt-orange: #FF9500;
  --wt-teal:   #30B0C7;
  --wt-gray:   #8E8E93;
  --chip-unselected: rgba(0,0,0,0.06);        /* Theme.swift:21 */
  /* `.ultraThinMaterial` — the iPad Splits panel. */
  --material-thin:   rgba(255,255,255,0.45);

  /* --- ink (UIKit semantics) --- */
  --ink:             #000000;
  --ink-secondary:   rgba(60,60,67,0.60);
  --ink-tertiary:    rgba(60,60,67,0.30);   /* tertiaryLabel — section headers, chevrons */
  --separator:       rgba(60,60,67,0.29);
  /* UISegmentedControl's selected segment (Theme.kt:191 measured the pair). */
  --seg-thumb:       #FFFFFF;

  /* --- accent: blue is the default; swap the pair to switch --- */
  --accent:          #007AFF;                 /* AccentColorPreference.swift:20 */
  --on-accent:       #FFFFFF;                 /* AccentColorPreference.swift:31 */
  --accent-hairline: rgba(0,122,255,0.40);    /* the .opacity(0.4) card stroke */
  --accent-area-top: rgba(0,122,255,0.25);    /* SplitsView chart gradient */
  --accent-area-bot: rgba(0,122,255,0.02);

  /* --- fixed semantics: never tint these with the accent (Theme.swift:27-49) --- */
  --race-type:       #C92129;
  --workout-type:    #5DCAA5;
  --connected:       #17A863;
  --attention:       #CC800D;

  /* `Theme.sportTint` (Theme.swift:64-72) — a chain rather than five new
     colours, because four of the five ARE the semantics above and must follow
     them into dark mode. Only strength has a value of its own. */
  --sport-run:       var(--workout-type);
  --sport-ride:      var(--attention);
  --sport-swim:      var(--race-type);
  --sport-strength:  #8C7DD9;
  --sport-other:     var(--ink-secondary);

  /* --- type --- */
  --font-stack: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto, sans-serif;
  --font-rounded: ui-rounded, "SF Pro Rounded", -apple-system, system-ui, sans-serif;
  --font-caption2:    11px;
  --font-caption:     12px;
  --font-footnote:    13px;
  --font-subheadline: 15px;   /* the workhorse */
  --font-body:        17px;
  --font-headline:    17px;   /* weight 600 baked in */
  --font-title3:      20px;
  --font-title2:      22px;
  --font-title:       28px;
  --font-large-title: 34px;   /* .navigationTitle's large mode */
  --weight-regular:  400;
  --weight-medium:   500;
  --weight-semibold: 600;
  --weight-bold:     700;
  --weight-heavy:    800;

  /* --- spacing --- */
  --space-1:  2px;  --space-2:  4px;  --space-3:  6px;
  --space-4:  8px;  --space-5: 10px;  --space-6: 12px;
  --space-7: 14px;  --space-8: 16px;  --space-9: 20px;

  /* --- radii (SwiftUI .continuous squircles; plain radius here) --- */
  --radius-md:   10px;
  --radius-xl:   14px;
  --radius-card: 18px;   /* .cardStyle() — Theme.swift:70 */
  --radius-panel: 22px;
  --radius-pill: 9999px;

  /* --- strokes --- */
  --stroke-hairline: 1px;
  --stroke:          1.5px;
  --stroke-chart:    2.5px;

  /* --- layout caps (Theme.readableWidth) --- */
  --width-default: 640px;   /* Theme.swift:82 */
  --width-tools:   820px;   /* regular width only — MoreToolsView.swift:90 */
  --width-library: 900px;   /* regular width only — LibraryView.swift:69 */

  /* --- fixed columns, regular width only --- */
  --col-splits: 380px;      /* CalculatorView.swift:36 */
  --col-chat:   400px;
  --col-day:    460px;      /* CoachPlannerView.swift:254 */
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg:              #0B0F19;                    /* Theme.swift:14 */
    --card:            #212630;                    /* Theme.swift:18 — opaque in dark */
    /* Between the page (#0B0F19) and a card (#212630), so the dialog lifts off
       the page and its own cards still lift off IT. */
    --bg-raised:       #151B27;

    --wt-green:  #30D158;
    --wt-purple: #BF5AF2;
    --wt-amber:  #FFBF00;
    --wt-orange: #FF9F0A;
    --wt-teal:   #40C8E0;
    --wt-gray:   #8E8E93;
    --chip-unselected: rgba(255,255,255,0.10);     /* Theme.swift:22 */
    --material-thin:   rgba(30,36,48,0.55);

    --ink:             #FFFFFF;
    --ink-secondary:   rgba(235,235,245,0.60);
    --ink-tertiary:    rgba(235,235,245,0.30);
    --separator:       rgba(84,84,88,0.60);
    --seg-thumb:       rgba(255,255,255,0.16);

    --accent:          #0A84FF;
    --accent-hairline: rgba(10,132,255,0.40);
    --accent-area-top: rgba(10,132,255,0.25);
    --accent-area-bot: rgba(10,132,255,0.02);

    --race-type:       #FF5961;
    --connected:       #3DD47A;
    --attention:       #FFB53D;
  }
}

/* ── Forced theme — the Settings Theme row ───────────────────────────────────
   The blocks above answer only `prefers-color-scheme`, so a chosen Light or
   Dark needs these: the palette re-asserted under `html[data-theme]`, whose
   specificity beats the media query either way round. Every page sets the
   attribute before first paint from `themePreference` (the inline head script
   settings.html introduced), so the preference holds on all of them.

   Neither block touches `--accent`: a `html[data-theme]` declaration would
   outrank the bare `[data-accent]` selectors below and paint every chosen
   accent blue. The only accent that differs by theme is the default blue, and
   the `:not([data-accent])` pair handles it — which cannot collide, because a
   chosen accent always sets the attribute. */
html[data-theme="light"]{
  color-scheme:light;
  --bg:#E8F0FC; --card:rgba(255,255,255,0.65); --chip-unselected:rgba(0,0,0,0.06);
  /* Same reason as `:root` — white here hid every card in the workout dialog. */
  --bg-raised:#EDF3FD;
  --wt-green:#34C759; --wt-purple:#AF52DE; --wt-amber:#FFBF00;
  --wt-orange:#FF9500; --wt-teal:#30B0C7; --wt-gray:#8E8E93;
  --material-thin:rgba(255,255,255,0.45);
  --ink:#000000; --ink-secondary:rgba(60,60,67,0.60); --ink-tertiary:rgba(60,60,67,0.30);
  --separator:rgba(60,60,67,0.29); --seg-thumb:#FFFFFF;
  --race-type:#C92129; --connected:#17A863; --attention:#CC800D;
}
html[data-theme="dark"]{
  color-scheme:dark;
  --bg:#0B0F19; --card:#212630; --chip-unselected:rgba(255,255,255,0.10);
  --bg-raised:#151B27;
  --wt-green:#30D158; --wt-purple:#BF5AF2; --wt-amber:#FFBF00;
  --wt-orange:#FF9F0A; --wt-teal:#40C8E0; --wt-gray:#8E8E93;
  --material-thin:rgba(30,36,48,0.55);
  --ink:#FFFFFF; --ink-secondary:rgba(235,235,245,0.60); --ink-tertiary:rgba(235,235,245,0.30);
  --separator:rgba(84,84,88,0.60); --seg-thumb:rgba(255,255,255,0.16);
  --race-type:#FF5961; --connected:#3DD47A; --attention:#FFB53D;
}
html[data-theme="light"]:not([data-accent]){
  --accent:#007AFF; --accent-hairline:rgba(0,122,255,.40);
  --accent-area-top:rgba(0,122,255,.25); --accent-area-bot:rgba(0,122,255,.02);
}
html[data-theme="dark"]:not([data-accent]){
  --accent:#0A84FF; --accent-hairline:rgba(10,132,255,.40);
  --accent-area-top:rgba(10,132,255,.25); --accent-area-bot:rgba(10,132,255,.02);
}

/* The four non-default accents have no light/dark variant.
   Set --accent and --on-accent together; nothing else changes. */
[data-accent="orange"]  { --accent:#FF6B00; --on-accent:#000; --accent-hairline:rgba(255,107,0,.40);
                          --accent-area-top:rgba(255,107,0,.25); --accent-area-bot:rgba(255,107,0,.02); }
[data-accent="green"]   { --accent:#6BFF00; --on-accent:#000; --accent-hairline:rgba(107,255,0,.40);
                          --accent-area-top:rgba(107,255,0,.25); --accent-area-bot:rgba(107,255,0,.02); }
[data-accent="magenta"] { --accent:#FF00A3; --on-accent:#FFF; --accent-hairline:rgba(255,0,163,.40);
                          --accent-area-top:rgba(255,0,163,.25); --accent-area-bot:rgba(255,0,163,.02); }
[data-accent="yellow"]  { --accent:#FEC600; --on-accent:#000; --accent-hairline:rgba(254,198,0,.40);
                          --accent-area-top:rgba(254,198,0,.25); --accent-area-bot:rgba(254,198,0,.02); }

/* Every ticking number in the app uses monospacedDigit(). */
.tabular { font-variant-numeric: tabular-nums; }

/* ── Tab bar ─────────────────────────────────────────────────────────────────
   The iOS app's bottom tab bar — the same five destinations in
   RootTabView.swift:409's order. The Calculator is not one of them on any
   platform: it is the first row inside Tools (MoreToolsView.swift), so
   index.html keeps its URL and lights the Tools item. Each web screen
   was built standalone by a different agent, so this is the one shared piece:
   the same markup in every page, styled once here. Fixed, so it survives a long
   scroll the way the native bar does.

   `body { padding-bottom }` is what stops the bar sitting on top of the last
   row of a long list — iOS never needs it because the system TabView reserves
   its own height. It was written as `body`, and every one of the five pages
   overrode it: each screen's own <style> opens with `html,body{margin:0;padding:0}`,
   which comes after this file and wins on equal specificity. So the reservation
   was 0 everywhere and the Library's last card scrolled under the bar. `html body`
   outranks the page rule without editing five files.

   The number is the bar's measured height (8 + 22 icon + 2 + 14 label + 8 = 54,
   plus its 1px border), and the home-indicator inset is on top of it — 0 on a
   desktop, 34 on the phone this is now expected to open on. */
html body { padding-bottom: calc(55px + env(safe-area-inset-bottom)); }

/* The phones' floating "● Activity ›" while an activity runs (RootTabView's pill;
   shell.js draws it). Phone: above the tab bar, right. Sidebar: above the account
   chip — his call, 9 Sep 2026. */
.live-pill {
  position: fixed; right: 14px; bottom: calc(55px + env(safe-area-inset-bottom) + 14px); z-index: 60;
  display: inline-flex; align-items: center; gap: 8px; padding: 10px 14px 10px 12px;
  border-radius: var(--radius-pill, 999px); background: var(--bg-raised); color: var(--ink);
  border: 1px solid var(--separator); box-shadow: 0 6px 20px rgba(0,0,0,.3);
  font-size: var(--font-subheadline); font-weight: var(--weight-semibold); text-decoration: none;
}
.live-pill .dot { width: 9px; height: 9px; border-radius: 50%; background: #FF453A;
                  box-shadow: 0 0 0 3px rgba(255,69,58,.25); animation: live-dot 1.6s ease-in-out infinite; }
.live-pill .chev { opacity: .7; font-size: 18px; line-height: 1; margin-left: 2px; }
@keyframes live-dot { 50% { box-shadow: 0 0 0 6px rgba(255,69,58,.10); } }

.tabbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 50;
  display: flex; justify-content: center; gap: 4px;
  padding: 8px 12px calc(8px + env(safe-area-inset-bottom));
  background: var(--material-thin, var(--card));
  backdrop-filter: saturate(180%) blur(20px);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  border-top: 1px solid var(--accent-hairline, transparent);
}
.tabbar a {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  min-width: 72px; padding: 6px 10px; border-radius: var(--radius-pill, 999px);
  /* `font:` is a shorthand and needs a family, so `font: 12px` was invalid and
     dropped — the labels inherited the page's 17px body size and the four of
     them ran off the right edge of a phone. */
  font-size: var(--font-caption); color: var(--ink-secondary);
  text-decoration: none; -webkit-tap-highlight-color: transparent;
}
.tabbar a[aria-current="page"] { color: var(--on-accent); background: var(--accent); }
.tabbar svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.8; }

/* Five items still don't fit a phone at 72px apiece (5×72 + gaps + padding = 400),
   so on compact they shrink evenly and the label drops to caption2 — the size
   the native bar uses anyway. */
@media (max-width: 699px) {
  .tabbar a { min-width: 0; flex: 0 1 72px; font-size: var(--font-caption2); }
}

/* ── Regular width: the bar becomes a left rail ──────────────────────────────
   iPad-audit #1. iOS gets this from `.tabViewStyle(.sidebarAdaptable)`
   (RootTabView.swift:454-459) — destinations in a left sidebar, collapsible to
   an icon rail. The rail is the web's form: the item markup is already an icon
   over a caption, so the bar only changes axis. Apple's sidebar width is
   Apple's (web-design-tokens.md §4.4 — "a web port must pick its own number");
   96px is 72px of item plus the bar's own 12px padding either side, and the
   700px boundary is the same compact/regular line the Calculator splits on.
   The body reservation moves from bottom to left with it. */
@media (min-width: 700px) {
  html body { padding-bottom: 0; padding-left: calc(96px + env(safe-area-inset-left)); }
  .tabbar {
    top: 0; right: auto; width: calc(96px + env(safe-area-inset-left));
    flex-direction: column; justify-content: flex-start; gap: var(--space-4);
    padding: var(--space-9) var(--space-6) var(--space-9) calc(var(--space-6) + env(safe-area-inset-left));
    border-top: none; border-right: 1px solid var(--accent-hairline, transparent);
  }
}

/* ── Desktop shell: the sidebar ──────────────────────────────────────────────
   The rail above is the iPad's answer — a 96px column that can only ever show a
   glyph, because that is all `.sidebarAdaptable` collapses to. A desktop window
   has the width to say the word, so from 960px up a page that opts in
   (`<body class="shell">` + the `<aside class="side">` markup) trades the rail
   for a 240px labelled sidebar and the tab bar disappears.

   Opt-in, not automatic: the pages still on the ported iPad layout keep the
   rail, and each moves over as it is rebuilt. `html body.shell` outranks the
   rail's `html body` on specificity, so the 96px reservation goes with it.

   **Every selector below is `aside.side`, and the element must be the aside.**
   A bare `.side` also matched the navbar's own leading/trailing slots, which
   two pages spell `<span class="side">` — those pages set `display` and `width`
   on them, so the collision was invisible until it wasn't: the sidebar's
   `position:sticky; height:100vh` landed on a navbar slot, the bar grew to the
   full height of the window, and the whole screen came down with it. */
aside.side { display: none; }

@media (min-width: 960px) {
  html body.shell {
    padding-left: 0; padding-bottom: 0;
    display: grid; grid-template-columns: 240px 1fr; min-height: 100vh;
  }
  body.shell .tabbar { display: none; }

  aside.side {
    position: sticky; top: 0; height: 100vh;
    display: flex; flex-direction: column; gap: var(--space-4);
    padding: var(--space-9) var(--space-6);
    border-right: 1px solid var(--separator);
  }
  aside.side .brand { display: flex; align-items: center; gap: var(--space-5);
                 padding: 0 var(--space-5) var(--space-9); }
  aside.side .brand svg { width: 26px; height: 26px; }
  aside.side .brand b { font-size: var(--font-title3); font-weight: var(--weight-bold);
                   letter-spacing: -.3px; }
  aside.side nav { display: flex; flex-direction: column; gap: 2px; }
  aside.side nav a {
    display: flex; align-items: center; gap: var(--space-6); height: 40px;
    padding: 0 var(--space-5); border-radius: var(--radius-md);
    font-size: var(--font-subheadline); font-weight: var(--weight-medium);
    color: var(--ink-secondary); text-decoration: none;
  }
  aside.side nav a svg { width: 19px; height: 19px; fill: none; stroke: currentColor;
                    stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
  aside.side nav a:hover { background: var(--chip-unselected); }
  aside.side nav a[aria-current="page"] { background: var(--accent); color: var(--on-accent);
                                     font-weight: var(--weight-semibold); }
  /* The account, where every desktop app keeps it. iOS reaches this from
     Settings; the web has had only the Calculator header's person button. */
  aside.side .live-pill { position: static; margin: auto 0 4px var(--space-5); align-self: flex-start; box-shadow: none; }
  aside.side .live-pill + .who { margin-top: 0; }
  aside.side .who { margin-top: auto; display: flex; align-items: center; gap: var(--space-5);
               padding: var(--space-5); border-radius: var(--radius-md);
               text-decoration: none; }
  aside.side .who:hover { background: var(--chip-unselected); }
  aside.side .who .av { width: 28px; height: 28px; border-radius: 50%; background: var(--accent);
                   color: var(--on-accent); display: grid; place-items: center;
                   font-size: var(--font-caption); font-weight: var(--weight-bold); }
  aside.side .who span { font-size: var(--font-caption); color: var(--ink-secondary);
                    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}

/* ── 44pt hit area for the bare glyph buttons ────────────────────────────────
   `.icon-btn` is the same control on all four pages — a lone glyph in a header
   or nav bar — painted 36px on the Calculator and 38px everywhere else. On iOS
   that paint is the *label*: a Button's frame is what you hit, and a bar button
   gets 44pt whatever it draws (HeaderView.swift:62-73 draws 36 into a bar item).
   The web has no such floor, so a thumb misses by 3-4px on every one of them.

   An ::after overlay rather than a bigger box, so nothing about the layout or
   the paint moves — the same trick the Calculator already used for the unit
   pill and the favourite star, hoisted here so the four pages can't drift.
   The overhang (3-4px a side) is never more than the gap between two of them. */
.icon-btn { position: relative; }
.icon-btn::after {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: 44px; height: 44px; transform: translate(-50%, -50%);
}
