:root{
  --bg:#0B0C10; --bg2:#16181F; --card:#16181F; --card-end:#131519; --card2:#242831;
  --line:#242831; --fg:#e8edf2; --muted:#8b94a3; --sub:var(--muted); --accent:#00E5FF;
  --accent2:#00C8E0; --green:#5ad19a; --danger:#ff6b81; --radius:16px;
  --accent-grad:linear-gradient(145deg,#3FF0FF,#00CDE6); --accent-glow:rgba(0,229,255,.40); --on-accent:#06222b;
  --g1:rgba(77,163,255,.16); --g2:rgba(90,209,154,.08);
  --nav-bg:rgba(11,12,16,.97); --nav-bg2:rgba(11,12,16,.99);
  --bar:#0B0C10; --tab-bg:rgba(11,12,16,.92);
  --mm-base:#5d6b77;
  /* "below MEV" needs its own colour: it used to be --muted, which is a near-twin of --mm-base
     ("not trained at all") as a fill — the two states the heatmap most needs to tell apart. Amber
     also makes the most actionable status the most visible one, in the list as well as the map. */
  --warn:#ffb454;
  /* muscle-heatmap fills — deliberately aliases of the .vl-status colours so the body diagram and
     the MEV/MAV/MRV list read as one system. Defined once: the indirection resolves against
     whatever --warn/--accent/--green/--danger the active theme sets. */
  --hm-none:var(--mm-base); --hm-low:var(--warn); --hm-ok:var(--accent);
  --hm-optimal:var(--green); --hm-high:var(--danger);
  --shimmer-hi:#363c48; /* loading-shimmer highlight — --card2/--line coincide in dark theme,
                           so the gif-shimmer gradient needs its own lighter stop for contrast */
  --safe-top:env(safe-area-inset-top);
  --safe-bot:env(safe-area-inset-bottom,0px);
}
/* --accent/--accent-grad are darker than they look like they "should" be at a glance — the
   obvious lighter blue (#2f7fe0, and the old #5cb0ff/#3b82f6 gradient) fails WCAG AA when used
   as text-on-neutral (tab labels, date-nav arrows) or white-text-on-fill (.primary buttons):
   both dropped below the 4.5:1 the app commits to. These values are the minimum darkening that
   clears 4.5:1 in both directions — don't lighten them back without re-checking contrast. */
:root[data-theme="light"]{
  --bg:#eef1f5; --bg2:#ffffff; --card:#f6f9fe; --card-end:#edf2fa; --card2:#eef1f5;
  --line:#dce1e8; --fg:#1a2230; --muted:#5f6b7a; --accent:#1e6bc8; --accent2:#1e6bc8; --accent-grad:linear-gradient(145deg,#0074e0,#144fa0); --accent-glow:rgba(59,130,246,.35); --on-accent:#fff;
  /* .quote-card's own tinted gradient background (not a neutral surface) drops --accent's text
     contrast to ~4.0:1 there specifically — verified by sampling the actual rendered pixel color,
     not computed from the gradient's nominal stops. This darker value is scoped to that one
     component via --quote-accent rather than darkening --accent globally (which already passes
     4.5:1+ everywhere else it's used). First pass (#1b62b6) landed right on the 4.5:1 line
     (4.3-4.6:1 measured) once the always-present .arny-bg decorative photo compositing under the
     card was accounted for — darkened one more notch for real headroom (5.8-6.2:1) instead of
     sitting exactly on the compliance boundary. */
  --quote-accent:#12518e;
  --green:#1fa971; --danger:#e0455e; --warn:#a86400;
  --g1:rgba(47,127,224,.10); --g2:rgba(31,169,113,.08);
  --nav-bg:rgba(247,249,252,.97); --nav-bg2:rgba(247,249,252,.99);
  --bar:#f7f9fc; --tab-bg:rgba(247,249,252,.92);
  --mm-base:#cdd6e0;
  --shimmer-hi:#dce1e8;
}
@media (prefers-color-scheme: light){
  :root[data-theme="system"]{
    --bg:#eef1f5; --bg2:#ffffff; --card:#f6f9fe; --card-end:#edf2fa; --card2:#eef1f5;
    --line:#dce1e8; --fg:#1a2230; --muted:#5f6b7a; --accent:#1e6bc8; --accent2:#1e6bc8; --accent-grad:linear-gradient(145deg,#0074e0,#144fa0); --accent-glow:rgba(59,130,246,.35); --on-accent:#fff;
    --quote-accent:#12518e; /* see the .quote-card comment on the other light-theme block above */
    --green:#1fa971; --danger:#e0455e; --warn:#a86400;
    --g1:rgba(47,127,224,.10); --g2:rgba(31,169,113,.08);
    --nav-bg:rgba(247,249,252,.97); --nav-bg2:rgba(247,249,252,.99);
    --bar:#f7f9fc; --tab-bg:rgba(247,249,252,.92);
    --mm-base:#cdd6e0;
    --shimmer-hi:#dce1e8;
  }
}
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent;
  -webkit-user-select:none;user-select:none}
input,textarea{-webkit-user-select:auto;user-select:auto}

/* PRODUCT.md commits to a prefers-reduced-motion alternative for every animation. Rather than
   annotate all ~14 @keyframes blocks + every transition individually (easy to miss one on the
   next addition), this is a global kill-switch: every animation/transition collapses to
   near-instant. State is still conveyed (the rest-timer ring still reaches its end position,
   modals still open, the PR-celebration bounce/trophy still appear) — only the motion itself is
   removed, which is exactly what this media query is for. */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation-duration:.01ms!important;
    animation-iteration-count:1!important;
    transition-duration:.01ms!important;
    scroll-behavior:auto!important;
  }
}
html,body,#app{touch-action:manipulation;}
button,a,input,select,textarea,[role="button"]{touch-action:manipulation;}
html{height:100%;overflow:hidden;margin:0;background-color:var(--bar);
  -webkit-text-size-adjust:100%;text-size-adjust:100%}

body{height:100%;overflow:hidden;margin:0;color:var(--fg);
  font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
  overscroll-behavior:none;
  background-color:var(--bg);
  background:
    radial-gradient(120% 60% at 50% -10%, var(--g1), transparent 60%),
    radial-gradient(90% 50% at 100% 0%, var(--g2), transparent 55%),
    var(--bg)}
h1{font-size:22px;margin:0;font-weight:700}
h2{font-size:20px;margin:0 0 14px;font-weight:700}
h3{font-size:15px;margin:0 0 10px;color:var(--muted);font-weight:600}
label{display:block;font-size:13px;color:var(--muted);margin:14px 0 6px;-webkit-user-select:none;user-select:none}
.hidden{display:none!important}

#app{position:fixed;inset:0;overflow:hidden;display:flex;flex-direction:column}
#arny-bg,.arny-bg{position:absolute;left:0;right:0;bottom:0;width:100%;height:calc(100% - 56px);object-fit:cover;object-position:65% top;opacity:.06;pointer-events:none;z-index:-1;filter:grayscale(60%)}
#exinfo-body .card:first-child{position:relative;z-index:1}
.view{position:absolute;inset:0;display:flex;flex-direction:column;
  padding-bottom:calc(57px + var(--safe-bot,0px));
  animation:viewfade .28s cubic-bezier(.25,.46,.45,.94)}
@keyframes viewfade{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}
.chart-card{position:relative}
.chart-note{text-align:right;font-size:10px;color:var(--muted);margin-top:6px;opacity:.75;letter-spacing:.02em}
/* measurement illustration (what is measured) */
.meas-illustration{display:flex;justify-content:center;margin:4px 0 14px}
.meas-illustration svg{width:100%;max-width:340px;height:210px}
#modal-meas-info,#modal-sess-gallery{align-items:center}
.meas-info-card{max-width:380px;border-radius:22px;animation:scalein .2s cubic-bezier(.2,.8,.2,1)}
#modal-meas-info .meas-illustration{margin:8px 0 4px}
#modal-meas-info .meas-illustration svg{max-width:100%;height:auto;min-height:360px}
/* A visible edge (not just a low-contrast fill) so the band lines clearly meet the silhouette —
   in light theme the pale fill on a pale card background was nearly invisible, making a
   mathematically correct line look like it was pointing at empty space. */
.mfig-body path{fill:var(--mm-base);opacity:.6;stroke:var(--muted);stroke-width:2;stroke-opacity:.5}
.mfig-band{stroke:var(--accent);stroke-width:6;stroke-dasharray:16 12;opacity:.9}
.mfig-label{fill:var(--fg);font-size:54px;font-family:inherit;font-weight:700}

/* workout month calendar */
.cal-card{max-width:360px;width:100%}
.cal-head{display:flex;align-items:center;justify-content:space-between;margin:2px 0 12px}
.cal-title{font-size:16px;font-weight:700}
.cal-grid{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:4px;width:100%}
.cal-wd{text-align:center;font-size:11px;color:var(--muted);padding:2px 0;font-weight:600;min-width:0}
.cal-wd.wknd{color:var(--accent);opacity:.8}
.cal-cell{aspect-ratio:1;min-width:0;border-radius:9px;background:var(--card2);display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:2px;position:relative;font-size:13px;color:var(--fg);overflow:hidden}
.cal-cell.empty{background:transparent}
.cal-cell.has{background:var(--card);border:1px solid var(--line);cursor:pointer}
.cal-cell.today{box-shadow:inset 0 0 0 2px var(--accent)}
.cal-cell.today .cal-num{color:var(--accent);font-weight:700}
.cal-dots{display:flex;gap:2px;height:6px;align-items:center}
.cal-dot{width:5px;height:5px;border-radius:50%}
#modal-calendar .ghost.wide{width:100%;margin-top:14px}

/* static labelled anatomy poster (CC BY-SA 4.0) — pinch/double-tap/drag to zoom, same
   interaction as the photo lightbox (wireZoomPan in workouts.js) */
.mm-chart-wrap{height:100%;overflow:hidden;touch-action:none;border-radius:10px;position:relative}
.mm-chart{width:100%;height:100%;object-fit:contain;display:block;border-radius:10px;
  transform-origin:center center;transition:transform .05s linear;will-change:transform}
.mm-attrib{color:var(--muted);font-size:11px;text-align:center;width:100%}
.mm-fig-wrap{display:flex;justify-content:center;align-items:flex-start;padding:8px 8px 16px;overflow:auto}
.mm-fig-wrap svg{width:78%;max-width:340px;height:auto;max-height:64vh;transition:width .2s;display:block;margin:0 auto}
.mm-fig-wrap.zoom{justify-content:flex-start}
.mm-fig-wrap.zoom svg{width:150%;max-height:none}
.mm-inert{fill:var(--mm-base);opacity:.55}
.mm-region{fill:var(--mm-base);cursor:pointer;transition:opacity .15s}
/* when a muscle is selected, spotlight it: outline it and dim the rest */
.mm-fig-wrap.has-sel .mm-region:not(.sel){opacity:.28}
.mm-fig-wrap.has-sel .mm-inert{opacity:.18}
.mm-region.sel{stroke:var(--fg);stroke-width:7;paint-order:stroke;stroke-linejoin:round}
/* fine anatomy map uses a tiny coordinate system (~35 units wide), so strokes must be small.
   thin dark separators between every muscle give the printed anatomy-chart look. */
.mm-fig-wrap.fine svg{width:62%;max-width:300px}
.mm-fig-wrap.fine.zoom svg{width:130%}
.mm-fig-wrap.fine .mm-region,.mm-fig-wrap.fine .mm-inert{stroke:#0b0c10;stroke-width:.3;stroke-linejoin:round;paint-order:stroke}
.mm-fig-wrap.fine .mm-region.sel{stroke:var(--fg);stroke-width:.35;paint-order:stroke}
.mm-footer{padding:12px 14px calc(14px + var(--safe-bot,0px));border-top:1px solid var(--line);
  display:flex;flex-direction:column;gap:4px;align-items:flex-start;background:var(--bg)}
.mm-hint{color:var(--muted);font-size:13px;padding:6px 0;width:100%;text-align:center}
.mm-sel-head{display:flex;align-items:center;gap:8px}
.mm-sel-dot{width:12px;height:12px;border-radius:50%;display:inline-block;flex:none}
.mm-sel-name{font-size:18px;font-weight:700}
.mm-sel-sub{font-size:13px;color:var(--muted)}
.mm-det-list{list-style:none;margin:0;padding:0;width:100%;display:flex;flex-direction:column;gap:7px;
  max-height:34vh;overflow-y:auto}
.mm-det-list li{display:flex;flex-direction:column;gap:1px;padding-left:12px;position:relative}
.mm-det-list li::before{content:'';position:absolute;left:0;top:6px;width:8px;height:8px;border-radius:50%;background:var(--dot,var(--accent))}
.mm-det-nm{font-size:14px;font-weight:600;color:var(--fg)}
.mm-det-lat{font-size:12px;color:var(--muted)}
.mm-footer .primary.wide{width:100%}
/* unified inline loader — same dumbbell-wave as the full-screen loader */
.inline-loader{display:flex;align-items:center;justify-content:center;color:var(--accent)}
.inline-loader .loader-dumbbell{width:84px;height:28px}
.sess-loading{display:flex;align-items:center;justify-content:center;padding:60px 0}
.card-loader{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  background:var(--card);border-radius:var(--radius);opacity:.94;z-index:2}
/* Portrait lock (see #rotate-lock in index.html). Only a short landscape viewport (a phone held
   sideways) triggers it — max-height:500px keeps tablets/desktop untouched. */
#rotate-lock{display:none;position:fixed;inset:0;z-index:10000;flex-direction:column;
  align-items:center;justify-content:center;gap:16px;background:var(--bg);color:var(--fg);
  text-align:center;padding:24px;font-size:16px;font-weight:600}
#rotate-lock svg{width:56px;height:56px;color:var(--accent);animation:rotate-hint 2.6s ease-in-out infinite}
@keyframes rotate-hint{0%,55%,100%{transform:rotate(0)}28%{transform:rotate(-90deg)}}
@media (prefers-reduced-motion:reduce){#rotate-lock svg{animation:none;transform:rotate(-90deg)}}
@media screen and (orientation:landscape) and (max-height:500px){
  #rotate-lock{display:flex}
  #app,#splash,#login-gate{display:none!important}
}
.sheet .topbar{padding:calc(4px + var(--safe-top)) 14px 10px}
.topbar{padding:calc(6px + var(--safe-top)) 14px 10px;
  background:var(--bar);
  border-bottom:1px solid var(--line);position:sticky;top:0;z-index:5}.scroll{flex:1;overflow-y:auto;padding:8px;padding-bottom:calc(8px + env(safe-area-inset-bottom,0px));-webkit-overflow-scrolling:touch}

/* cards */
.card{background:linear-gradient(180deg,var(--card),var(--card-end));border:1px solid var(--line);
  border-radius:var(--radius);padding:16px;margin-bottom:7px;
  box-shadow:0 2px 10px rgba(0,0,0,.18)}
.garmin-recovery-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(90px,1fr));gap:10px;margin-top:10px}
.grec-stat{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:4px;background:var(--card2);border-radius:12px;padding:12px 10px}
/* Sleep stage breakdown: one proportional bar, segments sized by minutes. A single accent ramp
   rather than four hues (DESIGN.md's One Accent Rule) — these are slices of one measurement. */
.sleep-stages{margin-top:12px}
.sleep-bar{display:flex;height:8px;border-radius:4px;overflow:hidden;background:var(--card2)}
.sleep-bar span{display:block;min-width:2px}
.sleep-legend{display:flex;flex-wrap:wrap;gap:6px 14px;margin-top:8px}
.sleep-key{display:inline-flex;align-items:center;gap:5px;font-size:11px;color:var(--muted);
  font-variant-numeric:tabular-nums}
.sleep-key i{width:8px;height:8px;border-radius:2px;flex:none}
/* Garmin's own coaching sentence (garmin_readiness.feedback) plus HRV / hours-to-recovered. */
.garmin-note{margin-top:12px;padding-top:10px;border-top:1px solid var(--line)}
.gn-text{font-size:13px;color:var(--fg);line-height:1.45}
.gn-sub{font-size:11px;color:var(--muted);margin-top:4px;font-variant-numeric:tabular-nums}
.grec-ico{width:20px;height:20px;color:var(--accent);flex:none}
.grec-val{font-size:15px;font-weight:700;color:var(--fg)}
.grec-lbl{font-size:11px;color:var(--muted)}
.card-info-btn{background:none;border:none;padding:0;color:var(--muted);display:flex;align-items:center;cursor:pointer;flex:none}
.card-info-btn:active{color:var(--accent)}
.card-info-btn svg{width:18px;height:18px}
.ginfo-item{margin-bottom:14px}
.ginfo-item:last-child{margin-bottom:0}
.ginfo-term{display:flex;align-items:center;gap:8px;font-weight:700;font-size:14px;margin-bottom:3px}
.ginfo-term .gi-ico{display:flex;flex:none}
.ginfo-term .gi-ico .grec-ico{width:16px;height:16px}
.ginfo-desc{font-size:13px;color:var(--muted);line-height:1.45}
/* An icon named inline in explanation copy ("the {icon} badge shows…"). Accent-coloured and
   optically sunk to the text baseline so it reads as a reference to the real UI element. */
.ginfo-inline-ico{display:inline-flex;vertical-align:-2px;color:var(--accent)}
.ginfo-inline-ico svg{width:14px;height:14px}
.session-card{display:flex;justify-content:space-between;align-items:center;
  cursor:pointer;transition:.15s;active:scale(.98);margin-bottom:4px}
.session-card:active{transform:scale(.985);background:var(--card2)}
.session-card .meta{font-size:13px;color:var(--muted);margin-top:4px}
.session-card .group{font-weight:600;font-size:16px}
.session-card .arrow{color:var(--muted);display:flex;align-items:center;flex:none}
/* Journal search results: same title/date text styling as .session-card, but not tappable (no
   arrow, no press feedback) — the row already shows the exercise's sets directly, unlike a plain
   session-card which only names the day and requires opening it to see anything more. */
.search-result-card{margin-bottom:4px}
.search-result-card .group{font-weight:600;font-size:16px}
.search-result-card .meta{font-size:13px;color:var(--muted);margin-top:4px}
.search-result-card .sr-sets{font-size:13px;color:var(--fg);margin-top:6px}
/* Unified "nothing here yet" state: full-size by default (icon + generous spacing), with a
   .compact modifier for smaller inline contexts (lists inside modals/panels). Replaces what
   used to be four near-duplicate classes (.empty, .empty-sm, .rec-empty, .inbox-empty). */
.empty-state{color:var(--muted);text-align:center;margin-top:60px;font-size:15px;line-height:1.6}
.empty-state.compact{margin-top:0;padding:20px;font-size:13px}
.empty-state-hint{opacity:.7;font-size:.9em;margin-top:6px}
.nutri-copy-prev{display:inline-flex;align-items:center;gap:7px;margin-top:16px}
.nutri-copy-prev svg{width:16px;height:16px}
/* Recovery vs performance card */
.recovery-list{display:flex;flex-direction:column;gap:6px;margin-top:12px}
.rec-row{width:100%;text-align:left;background:var(--card2);border:1px solid transparent;
  border-radius:12px;padding:10px 12px;cursor:pointer;transition:border-color .15s,background .15s}
.rec-row:active{background:var(--line)}
.rec-row.active{border-color:var(--accent);background:var(--card2)}
.rec-row-main{display:flex;align-items:center;justify-content:space-between;gap:10px}
.rec-lbl{font-weight:600;font-size:14px;color:var(--fg)}
.rec-r{font-variant-numeric:tabular-nums;font-weight:700;font-size:13px;padding:2px 8px;border-radius:999px}
.rec-r.pos{color:var(--accent);background:var(--accent-glow)}
.rec-r.neg{color:var(--danger);background:color-mix(in srgb,var(--danger) 16%,transparent)}
.rec-r.weak{opacity:.55}
.rec-verdict{color:var(--muted);font-size:12px;margin-top:3px}
/* Volume landmarks (MEV/MAV/MRV) */
.vl-row{margin-bottom:14px}
.vl-row:last-child{margin-bottom:0}
.vl-label{display:flex;align-items:center;gap:6px;font-size:13px;font-weight:600;color:var(--fg);margin-bottom:5px}
.vl-dot{width:8px;height:8px;border-radius:50%;flex:none}
.vl-track{position:relative;height:8px;border-radius:999px;background:var(--card2)}
.vl-zone-mav{position:absolute;top:0;bottom:0;border-radius:999px;background:color-mix(in srgb,var(--green) 35%,transparent)}
.vl-marker{position:absolute;top:-3px;width:3px;height:14px;border-radius:2px;background:var(--fg);
  transform:translateX(-1.5px)}
.vl-value{display:flex;align-items:center;justify-content:space-between;gap:8px;font-size:12px;color:var(--muted);margin-top:5px}
.vl-status{font-weight:700;font-size:11px;text-transform:uppercase;letter-spacing:.03em}
.vl-status.vl-none{color:var(--muted)}
.vl-status.vl-low{color:var(--warn)}
.vl-status.vl-ok{color:var(--accent)}
.vl-status.vl-optimal{color:var(--green)}
.vl-status.vl-high{color:var(--danger)}
/* Strength standards (bench/squat/deadlift/press vs bodyweight) */
.ss-row{display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:9px 0;border-top:1px solid var(--line)}
.ss-row:first-child{border-top:none;padding-top:0}
.ss-l{min-width:0}
.ss-name{font-size:14px;font-weight:600;color:var(--fg)}
.ss-sub{font-size:12px;color:var(--muted);margin-top:2px}
.ss-badge{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.03em;
  padding:3px 9px;border-radius:999px;flex:none}
/* Water tracker card (Nutrition) */
.water-card{padding:14px 16px}
.water-head{display:flex;align-items:center;justify-content:space-between;gap:10px}
.water-title{display:flex;align-items:center;gap:8px;font-weight:600;font-size:15px;color:var(--fg)}
.water-title svg{width:20px;height:20px;color:#4da3ff}
.water-goal-btn{background:var(--card2);color:var(--muted);border:1px solid var(--line);
  border-radius:999px;padding:4px 11px;font-size:12px;cursor:pointer}
.water-amount{margin:10px 0 7px;font-size:14px;color:var(--muted)}
.water-amount b{color:var(--fg);font-size:20px;font-variant-numeric:tabular-nums}
.water-bar{height:9px;border-radius:999px;background:var(--card2);overflow:hidden}
.water-fill{height:100%;border-radius:999px;background:linear-gradient(90deg,#4da3ff,#5ad1ff);
  transition:width .28s ease}
.water-fill.full{background:linear-gradient(90deg,#5ad19a,#4da3ff)}
.water-actions{display:flex;gap:8px;margin-top:12px}
.water-add{flex:1;background:var(--card2);color:var(--fg);border:1px solid var(--line);
  border-radius:12px;padding:10px 0;font-size:14px;font-weight:600;cursor:pointer;
  font-variant-numeric:tabular-nums;transition:background .15s}
.water-add:active{background:var(--line)}
.water-add.water-undo{flex:0 0 auto;padding:10px 14px;color:var(--muted)}
.water-add:disabled{opacity:.4;pointer-events:none}
.settings-version{text-align:center;color:var(--muted);opacity:.6;font-size:12px;
  padding:18px 0 26px;font-variant-numeric:tabular-nums}
/* Workout duration chip under the session header */
.sess-duration{display:flex;align-items:center;justify-content:center;gap:6px;
  color:var(--muted);font-size:13px;font-variant-numeric:tabular-nums;padding:4px 0 2px}
.sess-duration svg{width:15px;height:15px;color:var(--accent)}
.sess-duration .live{color:var(--fg);font-weight:600}
/* density sits after the clock, separated by a hairline so it reads as a second stat */
.sess-density{padding-left:9px;margin-left:3px;border-left:1px solid var(--line);color:var(--muted)}
.sess-kcal{padding-left:9px;margin-left:3px;border-left:1px solid var(--line);color:var(--muted)}
/* Per-exercise e1RM sparkline inside the exercise card */
.ex-spark{display:none;align-items:center;gap:12px;margin-top:9px}
.ex-spark.has-data{display:flex}
.spark-svg{flex:1;height:30px;min-width:0;overflow:visible}
.spark-meta{display:flex;flex-direction:column;align-items:flex-end;gap:1px;
  font-variant-numeric:tabular-nums;white-space:nowrap}
.spark-e1rm{font-size:11px;color:var(--muted)}
.spark-delta{font-size:12.5px;font-weight:700}
.spark-delta.up{color:var(--accent)}
.spark-delta.down{color:var(--danger)}
.spark-info-btn{flex:none}
.spark-info-btn svg{width:15px;height:15px}
.empty-ico{width:52px;height:52px;color:var(--accent);opacity:.5;margin:0 auto 14px;display:block}

/* FAB */
.fab{position:fixed;right:18px;bottom:calc(64px + var(--safe-bot,0px));width:58px;height:58px;
  border-radius:50%;border:none;background:var(--accent-grad);color:var(--on-accent);font-size:30px;
  box-shadow:0 10px 26px var(--accent-glow);z-index:20;transition:transform .15s}
.fab:active{transform:scale(.92)}

/* tabbar: 52px icons + safe-area padding for the home indicator.
   With status-bar-style:default the viewport reaches the physical bottom,
   so this padding holds the home-indicator zone (no empty chin). */
.tabbar{position:fixed;left:0;right:0;bottom:0;
  height:calc(57px + var(--safe-bot,0px));
  padding-top:5px;
  padding-bottom:var(--safe-bot,0px);
  background:var(--bar);
  box-shadow:0 -1px 0 var(--line), 0 -6px 18px rgba(0,0,0,.05);
  display:flex;align-items:flex-start;z-index:30}
.tab{flex:1;height:50px;background:none;border:none;color:var(--muted);font-size:10px;font-weight:500;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
  position:relative;transition:color .18s;padding:0}
.tab .ico{width:21px;height:21px;transition:transform .18s}
.tab.active{color:var(--accent)}
.tab.active .ico{transform:translateY(-1px) scale(1.06)}
.tab.active::before{content:"";position:absolute;top:-2px;width:30px;height:3px;border-radius:3px;
  background:var(--accent);box-shadow:0 0 12px var(--accent-glow)}

/* buttons */
.primary{background:var(--accent-grad);color:var(--on-accent);border:none;border-radius:12px;
  padding:13px 20px;font-size:16px;font-weight:600;box-shadow:0 4px 14px var(--accent-glow)}
.primary:active{filter:brightness(.92)}
.primary:disabled{opacity:.45;box-shadow:none;cursor:default;filter:grayscale(.3)}
.primary.wide{margin:0 14px calc(16px + var(--safe-bot,0px));width:calc(100% - 28px)}
/* Unlike .primary.wide's other uses (login, sheets) this button sits above the persistent
   tabbar, and .view already reserves safe-bot space for the tabbar itself (see .view's own
   padding-bottom) — adding safe-bot again here double-counts it, leaving a huge gap under the
   button on notched phones. Plain 14px matches the app's standard outer padding instead. */
#nutri-add-btn{margin-bottom:14px}
/* width:100% alone (not display:block) — buttons default to inline-block, which already
   respects an explicit width; forcing display:block here would out-specificity .btn-with-ico's
   display:flex (two classes beat one) on buttons combining both, collapsing the icon/text gap */
.primary.block{width:100%;text-align:center;margin:0}
.ghost{background:var(--card2);color:var(--fg);border:1px solid var(--line);
  border-radius:12px;padding:12px 18px;font-size:15px}
.ghost.small{padding:9px 13px;font-size:13px}
.primary.small{padding:9px 13px;font-size:13px;border-radius:10px;box-shadow:none}

/* header icon buttons — SVG-based, same size as tab icons */
.iconbtn{background:none;border:none;color:var(--accent);
  width:42px;height:42px;display:flex;align-items:center;justify-content:center;
  border-radius:10px;flex:none;font-size:28px;line-height:1}
.iconbtn:active{background:var(--card2)}
.iconbtn .ico{width:22px;height:22px}
.iconbtn .chevron{width:24px;height:24px;color:inherit}
.topbar-row{display:flex;align-items:center;justify-content:space-between}
/* h1 defaults to flex-shrink:1 but min-width:auto (its own text width), so on screens with a
   long title + 4 header icons the row doesn't actually fit inside the 18px side padding and
   overflows to the right — eating into that padding by a different amount per screen depending
   on title length/icon count, which reads as "icons don't have the same right inset everywhere".
   Letting h1 shrink+ellipsis instead keeps .header-actions pinned at a fixed width so every
   screen's icons sit at the same 18px inset no matter what. */
.topbar-row h1{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.header-actions{flex:none}
/* Journal search open/close: title, icon row and search field all cross-fade+resize together
   instead of snapping via the shared .hidden (display:none, which can't be transitioned) —
   #journal-title/.header-actions collapse to 0 via .jh-collapsed as .journal-search-wrap grows
   into the freed space via .jsw-open, so it reads as the field expanding into the row rather
   than three unrelated things popping in/out. */
#journal-title,#journal-header .header-actions{
  overflow:hidden;opacity:1;transition:opacity .18s ease,max-width .18s ease}
#journal-title{max-width:160px}                   /* generous over its ~128px natural width at 22px */
#journal-header .header-actions{max-width:220px}  /* generous over 5×42px = 210px natural width */
#journal-title.jh-collapsed,#journal-header .header-actions.jh-collapsed{
  opacity:0;max-width:0;pointer-events:none}
/* .search-wrap.journal-search-wrap (not just .journal-search-wrap): needs to out-specificity the
   later .search-wrap{padding:8px 14px} rule below, since same-specificity + later-in-file would
   otherwise win over a single-class selector here regardless of source order intent. */
/* Spans the full header row once open (title/icons have collapsed to 0, freeing the space) — not
   display:none while closed, so the max-width/opacity transition can actually play. */
.search-wrap.journal-search-wrap{flex:1;min-width:0;display:flex;align-items:center;gap:6px;
  padding:0;overflow:hidden;opacity:0;max-width:0;pointer-events:none;
  transition:opacity .18s ease,max-width .18s ease}
.journal-search-wrap.jsw-open{opacity:1;max-width:1000px;pointer-events:auto}
.journal-search-wrap .search{flex:1;height:36px}
.journal-search-wrap .iconbtn{flex:none}
.ghost.block{width:100%;text-align:center;text-decoration:none;margin:0}
.stack{display:flex;flex-direction:column;gap:9px}
.segmented{display:flex;gap:6px;background:var(--card2);border:1px solid var(--line);
  border-radius:12px;padding:4px}
.segmented button{position:relative;flex:1;background:none;border:none;color:var(--muted);
  border-radius:9px;padding:10px 4px;font-size:13px;font-weight:500}
/* Inactive segments share the container's background, so without a divider they visually run
   together into one bar (only the active pill's own background sets it apart). A ::before pill
   (not a full-height border) so the divider reads as a short rounded capsule floating in the
   gap, not a hard edge-to-edge line. Suppressed on either side of the active pill so no divider
   ever touches its colored background — a line of --line drawn over --accent would look like a
   rendering glitch. --line is NOT used for the divider color itself: in the dark theme --line
   (#242831) is identical to --card2 (#242831), so a --line divider is invisible there; --muted
   has real contrast against --card2 in both themes. */
.segmented button+button::before{content:"";position:absolute;left:-4px;top:22%;bottom:22%;
  width:2px;border-radius:2px;background:color-mix(in srgb,var(--muted) 55%,transparent)}
.segmented button.active{background:var(--accent);color:var(--on-accent)}
.segmented button.active::before,.segmented button.active+button::before{background:transparent}
.segmented.mini{padding:3px;gap:4px}
.segmented.mini button{padding:6px 10px;font-size:12px}
/* progress sub-tabs: sit between header and scroll */
.pr-seg{margin:10px 14px 2px}
.nutri-seg{margin:4px 14px 2px}
.exinfo-link.primary{margin-top:12px;display:block;text-align:center}

/* inputs */
.input-wrap{position:relative}
.input-wrap .search{padding-right:34px}
/* hide native type=search clear (✕) — we use the custom .input-clear button */
.search::-webkit-search-cancel-button{-webkit-appearance:none;appearance:none}
.input-clear{position:absolute;right:0;top:50%;transform:translateY(-50%);
  width:36px;height:36px;display:none;align-items:center;justify-content:center;
  background:none;border:none;color:var(--muted);font-size:18px;line-height:1;
  cursor:pointer;border-radius:50%}
.input-clear:active{background:var(--line)}
.input-wrap .search:not(:placeholder-shown)~.input-clear{display:flex}
.search{width:100%;background:var(--card2);border:1px solid var(--line);
  color:var(--fg);border-radius:12px;padding:12px 14px;font-size:15px;outline:none}
.search:focus{border-color:var(--accent)}
/* date input — styled to match text inputs */
.select{width:100%;background:var(--card2);border:1px solid var(--line);color:var(--fg);
  border-radius:12px;padding:12px 14px;font-size:15px;font-family:inherit;outline:none;cursor:pointer}
.select:focus{border-color:var(--accent)}
.select::-webkit-calendar-picker-indicator{opacity:.55;cursor:pointer}
.search-wrap{padding:8px 14px}
/* the clear ✕ mirrors the 14px text inset on the left; offset by the wrap's 14px side padding */
.search-wrap .input-clear{right:14px}

/* ---- universal custom dropdown ---- */
.cdd-wrap{position:relative;margin-bottom:12px}
.cdd-btn{display:flex;justify-content:space-between;align-items:center;gap:10px;
  width:100%;padding:10px 14px;border-radius:12px;border:1px solid var(--line);
  background:var(--card);color:var(--fg);font-size:14px;font-family:inherit;
  text-align:left;cursor:pointer;touch-action:manipulation}
.cdd-btn>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.cdd-btn .chevron{flex-shrink:0;width:20px;height:20px;transition:transform .2s;color:var(--muted)}
.cdd-btn.open .chevron{transform:rotate(180deg)}
.cdd-menu{position:absolute;left:0;right:0;top:calc(100% + 2px);
  background:var(--card);border:1px solid var(--line);border-radius:12px;
  z-index:120;overflow:hidden;overflow-y:auto;
  max-height:calc(5 * 48px);
  box-shadow:0 8px 24px rgba(0,0,0,.22);animation:dropfade .15s ease}
.cdd-search{position:sticky;top:0;background:var(--card);padding:8px;border-bottom:1px solid var(--line);z-index:1}
.cdd-search-input{width:100%;background:var(--card2);border:1px solid var(--line);color:var(--fg);
  border-radius:9px;padding:9px 12px;font-size:14px;font-family:inherit;outline:none}
.cdd-search-input:focus{border-color:var(--accent)}
.cdd-opt{display:block;width:100%;padding:12px 14px;background:none;border:none;
  border-bottom:1px solid var(--line);color:var(--fg);font-size:14px;
  font-family:inherit;text-align:left;cursor:pointer;touch-action:manipulation;
  min-height:48px;box-sizing:border-box}
.cdd-opt:last-child{border-bottom:none}
.cdd-opt.active{color:var(--accent);font-weight:600}
.cdd-opt:active{background:var(--card2)}

/* chips */
.chips{display:flex;flex-wrap:wrap;gap:8px;padding:8px 14px}
.chip{background:var(--card2);border:1px solid var(--line);color:var(--fg);
  border-radius:20px;padding:8px 14px;font-size:14px}
.chips.row-scroll{flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;
  scrollbar-width:none;padding-bottom:10px;min-height:52px}
.chips.row-scroll::-webkit-scrollbar{display:none}
.chips.row-scroll .chip{flex:none;white-space:nowrap}
.chip.active{background:var(--accent);border-color:var(--accent);color:var(--on-accent)}

/* library */
.lib-item{display:flex;justify-content:space-between;align-items:center;
  background:linear-gradient(180deg,var(--card),var(--card-end));
  border:1px solid var(--line);border-radius:var(--radius);
  padding:16px;margin-bottom:7px;cursor:pointer;transition:.15s;
  box-shadow:0 2px 10px rgba(0,0,0,.18)}
.lib-item:active{transform:scale(.985);background:var(--card2)}
.lib-item .nm{font-weight:600;font-size:16px}
.lib-item .eq{font-size:13px;color:var(--muted);margin-top:4px}
.lib-item .mg{font-size:12px;color:var(--accent);background:rgba(77,163,255,.12);
  padding:4px 9px;border-radius:8px;white-space:nowrap}

/* session detail */
.sheet{position:fixed;inset:0;background:var(--bar);z-index:40;display:flex;flex-direction:column;overflow:hidden;overscroll-behavior:none}
.sheet-bar{display:flex;align-items:center;gap:8px}
.sheet-bar h2{flex:1;margin:0;text-align:center;font-size:15px;white-space:normal;word-break:break-word;line-height:1.3}
/* small gap between the workout header action icons — 0 made them feel cramped/touching */
#session-screen .sheet-bar{gap:2px}
#session-screen .sheet-bar .iconbtn{width:38px}
#session-screen .sheet-bar #session-back{margin-right:auto}
.ex-block{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);
  padding:12px 14px;margin-bottom:5px}
/* Flash the exercise a record links to (Progress → Records → tap a value), so it's easy to spot
   in a long session. A fading accent ring — doesn't touch the muscle-tint or "done" states. */
@keyframes ex-flash{0%,22%{box-shadow:0 0 0 2px var(--accent),0 0 18px var(--accent-glow)}
  100%{box-shadow:0 0 0 0 transparent}}
.ex-block.ex-flash{animation:ex-flash 2.6s ease-out;position:relative;z-index:1}
@media (prefers-reduced-motion:reduce){
  .ex-block.ex-flash{animation:none;box-shadow:0 0 0 2px var(--accent)}}
/* tint the left edge by muscle group; the "done" state (green) overrides this below */
.ex-block[data-muscle]{box-shadow:inset 4px 0 0 var(--ex-muscle)}
.ss-block{border-left:3px solid var(--accent);border-radius:var(--radius);margin-bottom:11px;padding-left:10px}
.ss-block .ex-block{margin-bottom:6px;border-left-color:transparent}
.ss-block .ex-block:last-child{margin-bottom:0}
.ss-label{font-size:11px;font-weight:700;color:var(--accent);letter-spacing:.06em;text-transform:uppercase;margin-bottom:6px;padding-left:2px}
.ex-block .ex-head{display:flex;justify-content:space-between;align-items:flex-start}
.ex-block .ex-name{font-weight:600;font-size:16px;flex:1}
.ex-block .ex-actions{display:flex;gap:6px}
.ex-block .ex-actions button{background:none;border:none;padding:4px;-webkit-appearance:none;appearance:none;color:var(--sub);opacity:.8;transition:opacity .15s;cursor:pointer;display:flex;align-items:center;justify-content:center}
.ex-block .ex-actions button:hover{opacity:1}
.ex-block .ex-actions [data-info]{color:var(--accent);opacity:.7}
.ex-block .ex-actions [data-info]:disabled{opacity:.3;pointer-events:none;cursor:default}
.ex-block .ex-actions [data-ss]{color:var(--accent);opacity:.6}
.ex-block .ex-actions [data-ss].linked{opacity:1}
.ex-block .ex-actions [data-edit]{color:var(--accent);opacity:.85}
.ex-block .ex-actions [data-del]{color:var(--danger)}
#session-delete{color:var(--danger)}
.ex-block .ex-sets{margin-top:8px;display:flex;flex-wrap:wrap;gap:6px}
.set-pill{background:var(--card2);border:1px solid var(--line);border-radius:8px;
  padding:5px 10px;font-size:13px;color:var(--fg)}
.set-pill b{color:var(--accent)}
/* set tags: warm-ups are dimmed because they're excluded from every volume/PR number we report */
.set-tag{font-style:normal;font-weight:700;font-size:10px;margin-right:5px;letter-spacing:.02em}
.set-pill.st-warmup{opacity:.6}
.set-tag.st-warmup{color:var(--muted)}
.set-tag.st-failure{color:var(--danger)}
.set-tag.st-drop{color:#ffb454}

/* reorder buttons */
.drag-handle{color:var(--muted);padding:4px 10px 4px 2px;display:flex;align-items:center;flex-shrink:0;cursor:grab;touch-action:none}
.drag-handle:active{cursor:grabbing;color:var(--accent)}
.ex-drag-origin{opacity:.25}

/* custom badge */
.ex-warn-ico{color:#ffb454;vertical-align:middle;margin-left:5px;flex-shrink:0;display:inline-block}

/* note */
.ex-note{font-size:12px;color:var(--sub);margin-top:6px;font-style:italic;padding:0 2px}

/* timed set pill */
.set-pill.timed{background:color-mix(in srgb,var(--accent) 12%,transparent)}

/* modal toggle (reps/time) */
.mode-toggle{display:flex;border:1px solid var(--line);border-radius:10px;overflow:hidden;margin:12px 0}
.mode-toggle button{flex:1;background:none;border:none;padding:8px;font-size:13px;color:var(--sub);cursor:pointer;-webkit-appearance:none;appearance:none;transition:.12s}
.mode-toggle button.active{background:var(--accent);color:var(--on-accent);font-weight:600}

/* note textarea in modal */
.note-area{width:100%;border:1px solid var(--line);border-radius:10px;background:var(--card2);color:var(--fg);padding:10px 12px;font-size:14px;resize:none;font-family:inherit;margin-top:4px;box-sizing:border-box}
.note-area:focus{outline:none;border-color:var(--accent)}

/* sets editor */
#sets-editor{display:flex;flex-direction:column;gap:8px}
.set-row{display:grid;grid-template-columns:auto minmax(0,1fr) minmax(0,1fr) auto;align-items:center;gap:6px}
/* the set number doubles as the set-type toggle (tap to cycle warm-up/failure/drop), so it needs
   a real tap target while still reading as a plain index when untagged */
.set-row .idx{width:26px;height:26px;padding:0;color:var(--muted);font-size:12px;text-align:center;
  flex:none;background:none;border:1px solid transparent;border-radius:8px;cursor:pointer;
  display:flex;align-items:center;justify-content:center;font-family:inherit}
.set-row .idx:active{background:var(--card2)}
.set-row .idx.tagged{font-weight:700;font-size:11px;border-color:var(--line);background:var(--card2)}
.set-row .idx.tagged.st-warmup{color:var(--muted)}
.set-row .idx.tagged.st-failure{color:var(--danger)}
.set-row .idx.tagged.st-drop{color:#ffb454}
.stepper{display:flex;align-items:center;background:var(--card2);border:1px solid var(--line);
  border-radius:10px;overflow:hidden;flex:1;height:48px}
.stepper button{background:none;border:none;color:var(--accent);font-size:22px;touch-action:manipulation;
  width:30px;height:48px;flex:none;padding:0;line-height:1}
.stepper input{flex:1;min-width:0;background:none;border:none;color:var(--fg);
  text-align:center;font-size:16px;font-weight:600;padding:0 2px;outline:none;
  height:48px;-moz-appearance:textfield}
.dur-lbl{font-size:12px;color:var(--sub);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.stepper input::-webkit-outer-spin-button,.stepper input::-webkit-inner-spin-button{
  -webkit-appearance:none;margin:0}
.stepper .unit{color:var(--muted);font-size:11px;padding:0 4px 0 0;flex:none}
.set-row .del{background:none;border:none;color:var(--danger);font-size:15px;
  width:28px;height:48px;flex:none;display:flex;align-items:center;justify-content:center}
.set-row .del:disabled{opacity:.35;color:var(--muted);cursor:default}
.w-input{flex:1;min-width:0;background:var(--card2);border:1px solid var(--line);
  border-radius:10px;height:48px;padding:0 10px;color:var(--fg);font-size:16px;
  text-align:center;font-family:inherit;-webkit-appearance:none}
.w-input::-webkit-outer-spin-button,.w-input::-webkit-inner-spin-button{-webkit-appearance:none}
/* add/dup set buttons — side by side as icon+text pills */
.sets-actions{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:12px}
.sets-actions .ghost.small{display:flex;align-items:center;justify-content:center;
  gap:5px;padding:10px 8px;font-size:13px}

/* suggestions — absolute inside #modal-ex (which is position:fixed;inset:0),
   so coordinates here equal viewport coords; not clipped by .modal-card overflow */
.suggestions{position:absolute;z-index:9000;display:none;flex-direction:column;gap:0;
  -webkit-overflow-scrolling:touch}
.suggestions.show{display:flex}
.suggestions .sg{padding:13px 14px;border:1px solid var(--line);border-top:none;
  background:var(--card2);font-size:15px;cursor:pointer;touch-action:manipulation}
.suggestions .sg:first-child{border-top:1px solid var(--line);border-radius:12px 12px 0 0}
.suggestions .sg:last-child{border-radius:0 0 12px 12px}
.suggestions .sg:active{background:var(--card)}
.suggestions .sg .sgm{color:var(--accent);font-size:12px;margin-left:8px}
/* workout filter row (dropdown + clear chip) */
.workout-filter-wrap{padding:0}
.filter-row{display:flex;align-items:center;gap:8px}
#meas-filter .filter-row .cdd-wrap{flex:1;min-width:0;position:relative}
.filter-row .cdd-wrap{flex:1;min-width:0}
.filter-row .year-cdd-wrap.cdd-wrap{flex:0 0 110px}
.filter-clear{display:flex;align-items:center;justify-content:center;flex:none;
  width:44px;height:42px;align-self:stretch;
  border-radius:12px;border:1px solid var(--accent);
  background:rgba(77,163,255,.1);color:var(--accent);font-size:17px;font-weight:600;
  font-family:inherit;cursor:pointer;touch-action:manipulation;
  transition:opacity .15s, border-color .15s, background .15s, color .15s}
.filter-clear:active{background:rgba(77,163,255,.2)}
.filter-clear:disabled{opacity:.45;border-color:var(--line);background:transparent;
  color:var(--muted);cursor:default}
.filter-clear:disabled:active{background:transparent}
@keyframes dropfade{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}

/* splash screen */
.login-gate{position:fixed;inset:0;z-index:10000;display:flex;align-items:center;justify-content:center;
  background:var(--bg);padding:24px;padding-top:env(safe-area-inset-top)}
.login-card{display:flex;flex-direction:column;align-items:center;gap:14px;width:100%;max-width:300px}
.login-icon{width:56px;height:56px;color:var(--accent)}
.login-title{font-size:22px;font-weight:800;letter-spacing:.02em}
.login-card .search{width:100%;text-align:center}
.login-card .primary.wide{width:100%}
.login-err{color:var(--danger);font-size:13px;margin-top:-6px}
#splash{position:fixed;top:0;left:0;right:0;bottom:0;z-index:9999;display:flex;align-items:center;justify-content:center;
  background:var(--bg);opacity:1;transition:opacity .45s ease;pointer-events:auto;
  padding-top:env(safe-area-inset-top);padding-bottom:env(safe-area-inset-bottom)}
#splash.splash-out{opacity:0;pointer-events:none}
#splash::after{content:'';position:absolute;top:0;left:0;right:0;height:calc(env(safe-area-inset-top,0px) + 40px);background:linear-gradient(to bottom,var(--bar),transparent);z-index:2;pointer-events:none}
.splash-bg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:65% top;opacity:.18;filter:grayscale(60%);pointer-events:none}.splash-inner{position:relative;display:flex;flex-direction:column;align-items:center;gap:14px}
.splash-icon{width:72px;height:72px;color:var(--accent);filter:drop-shadow(0 0 18px var(--accent-glow))}
.splash-title{font-size:26px;font-weight:800;letter-spacing:.5px;color:var(--fg)}
.splash-bar-wrap{width:140px;height:3px;border-radius:2px;background:var(--line);overflow:hidden;margin-top:8px}
.splash-bar-fill{height:100%;border-radius:2px;background:var(--accent);width:0%;transition:width .15s linear}
@keyframes splash-pulse{0%,100%{opacity:.7}50%{opacity:1}}
.splash-icon{animation:splash-pulse 1.6s ease-in-out infinite}

/* app loader overlay — fades in/out via opacity; hidden state uses pointer-events:none */
.app-loader{position:fixed;inset:0;background:var(--bg);z-index:200;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:24px;
  opacity:1;transition:opacity .35s ease;pointer-events:auto}
.app-loader.fading{opacity:0;pointer-events:none}
.loader-dumbbell{width:110px;height:38px;color:var(--accent)}
.loader-dumbbell rect{animation:db-wave 1.4s ease-in-out infinite}
.loader-dumbbell rect:nth-child(1){animation-delay:0s}
.loader-dumbbell rect:nth-child(2){animation-delay:.07s}
.loader-dumbbell rect:nth-child(3){animation-delay:.14s}
.loader-dumbbell rect:nth-child(4){animation-delay:.21s}
.loader-dumbbell rect:nth-child(5){animation-delay:.14s}
.loader-dumbbell rect:nth-child(6){animation-delay:.07s}
.loader-dumbbell rect:nth-child(7){animation-delay:0s}
@keyframes db-wave{
  0%,100%{transform:translateY(0);opacity:.5}
  50%{transform:translateY(-5px);opacity:1}
}
.loader-text{color:var(--muted);font-size:13px;letter-spacing:.08em;margin:0;text-transform:uppercase;
  animation:loader-fade 1.4s ease-in-out infinite}
@keyframes loader-fade{0%,100%{opacity:.4}50%{opacity:.9}}

/* modals — all bottom sheets by default */
.modal{position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:50;display:flex;
  align-items:flex-end;justify-content:center;animation:fade .15s;touch-action:manipulation}
.modal-card{background:var(--card);border:1px solid var(--line);border-radius:22px 22px 0 0;
  width:100%;max-width:520px;padding:20px 18px calc(22px + var(--safe-bot,0px));
  max-height:90vh;overflow-y:auto;animation:slideup .22s cubic-bezier(.2,.8,.2,1);
  touch-action:manipulation}
.modal-card h2{font-size:18px;font-weight:700;margin:0 0 16px}
.modal-card>label,.modal-card .m-grid>div>label,.meas-group>label{
  display:block;font-size:13px;color:var(--muted);font-weight:500;margin:12px 0 6px}
.modal-card>label:first-of-type{margin-top:0}
.modal-card .search,.modal-card .select,.search-sm{
  padding:12px 14px;font-size:15px;border-radius:12px}
.modal-actions{display:flex;gap:10px;margin-top:20px}
.modal-actions .primary,.modal-actions .ghost{flex:1}
.modal-card .hint{font-size:12px;color:var(--muted);margin:8px 0 0;line-height:1.4}
@keyframes slideup{from{transform:translateY(100%)}to{transform:translateY(0)}}
@keyframes fade{from{opacity:0}to{opacity:1}}
/* exercise modal: top-anchored — keeps name input high, suggestions open downward */
#modal-ex{align-items:flex-start}
#modal-ex .modal-card{border-radius:0 0 22px 22px;
  padding:calc(18px + var(--safe-top)) 18px 22px;
  animation:slidedown .22s cubic-bezier(.2,.8,.2,1)}
@keyframes slidedown{from{transform:translateY(-100%)}to{transform:translateY(0)}}

/* exercise demo / how-to */
.demo-stage{position:relative;width:100%;aspect-ratio:16/9;border-radius:var(--radius);
  overflow:hidden;background:#fff;border:1px solid var(--line)}
.demo-stage img{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;
  transition:opacity .55s ease-in-out}
.demo-stage img.hide{opacity:0}
.demo-canvas{width:100%;height:100%;display:block;border-radius:var(--radius);background:#fff;border:1px solid var(--line)}
.demo-img{width:100%;height:100%;border-radius:var(--radius);background:#fff;object-fit:contain;border:1px solid var(--line)}
.demo-no-img{display:flex;flex-direction:column;align-items:center;justify-content:center;
  aspect-ratio:16/9;border-radius:var(--radius);background:var(--card2);border:1px solid var(--line);
  color:var(--muted);font-size:13px;gap:8px}
.demo-no-img span{font-size:48px}

/* media tabs (GIF / YouTube) */
.demo-action-row{display:flex;gap:10px;margin-top:14px}
.demo-action-btn{flex:1;display:flex;flex-direction:column;align-items:center;gap:5px;padding:12px 4px 10px;border-radius:14px;font-size:12px;font-weight:600;text-decoration:none;transition:.15s;border:1.5px solid var(--line);color:var(--muted);background:var(--card2)}
.demo-action-btn .site-icon{width:36px;height:36px;border-radius:8px;object-fit:contain}
.demo-action-btn:active{opacity:.7;transform:scale(.95)}
.media-tabs{display:flex;gap:0;margin-bottom:14px;border-bottom:2px solid var(--line)}
.media-tab{flex:1;background:transparent;border:none;border-bottom:2px solid transparent;margin-bottom:-2px;
  color:var(--muted);padding:10px 8px;font-size:14px;font-weight:600;
  display:flex;align-items:center;justify-content:center;cursor:pointer;
  transition:color .15s,border-color .15s;user-select:none}
.media-tab.active{color:var(--accent);border-bottom-color:var(--accent)}

/* media content — fixed height so card doesn't jump when switching tabs */
#media-gif,#media-video{height:240px}
#media-gif{display:flex;align-items:center;justify-content:center;position:relative;
  border-radius:var(--radius);overflow:hidden;
  background:linear-gradient(100deg,var(--card2) 30%,var(--shimmer-hi) 50%,var(--card2) 70%);
  background-size:200% 100%;animation:gif-shimmer 1.1s linear infinite}
#media-gif.loaded{animation:none;background:#fff}
#media-gif.gif-failed{animation:none;background:var(--card2)}
#media-gif.gif-failed img{display:none}
#media-gif.gif-failed::after{content:attr(data-failmsg);color:var(--muted);font-size:13px}
#media-gif img,#media-gif canvas{max-height:240px;width:100%;object-fit:contain}
#media-gif img.demo-gif{transition:opacity .25s ease-in;opacity:0}
#media-gif.loaded img.demo-gif{opacity:1}
@keyframes gif-shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}

/* YouTube embed */
.yt-wrap{position:relative;width:100%;height:100%;border-radius:var(--radius);overflow:hidden;background:#000}
.yt-frame{position:absolute;inset:0;width:100%;height:100%;border:none}
/* YouTube search fallback button */
.yt-open-btn{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;
  width:100%;height:100%;border-radius:var(--radius);background:rgba(255,0,0,.1);
  color:#ff4444;text-decoration:none;font-size:15px;font-weight:600}
.yt-open-btn:active{opacity:.7}
/* bottom-sheet option icon alignment */
.bs-option{display:flex;align-items:center;justify-content:center}

/* muscle map */
.muscle-map{width:75%;max-width:280px;height:auto;display:block;overflow:visible;margin:0 auto}
.muscle-map path{stroke:var(--bg2);stroke-width:1.2;transition:fill .2s}
.mm-legend{display:flex;gap:14px;justify-content:center;margin-top:10px;font-size:11px;color:var(--muted)}
.mm-legend i{display:inline-block;width:10px;height:10px;border-radius:3px;margin-right:4px;vertical-align:-1px}
/* heatmap legend: five keys, so unlike .mm-legend's two it has to wrap on a narrow phone.
   A wrapping flex row centers each row independently — with 3 items on row 1 and 2 on row 2,
   the two rows end up with different centers and visibly don't line up as one block. A 2-column
   grid instead centers the whole block at once, so every row shares the same left/right edges. */
.hm-legend{display:grid;grid-template-columns:repeat(2,auto);justify-content:center;
  gap:6px 16px;margin:12px auto 0;font-size:11px;color:var(--muted)}
.hm-key i{display:inline-block;width:10px;height:10px;border-radius:3px;margin-right:4px;vertical-align:-1px}
.demo-cap{text-align:center;color:var(--muted);font-size:12px;margin-top:6px}
.musclewiki-btn{display:flex;align-items:center;justify-content:center;gap:8px;margin-top:12px;padding:11px 16px;border-radius:var(--radius);border:1.5px solid var(--accent);color:var(--accent);font-size:14px;font-weight:600;text-decoration:none;transition:.15s}
.musclewiki-btn:hover{background:var(--accent);color:var(--on-accent)}
.exinfo-section-title{display:flex;align-items:center;gap:8px;font-size:11px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--accent);margin:0 0 10px;padding-bottom:8px;border-bottom:1px solid var(--line)}
.exinfo-howto{font-size:14px;line-height:1.6;margin:0;color:var(--fg)}
.exinfo-tags{display:flex;flex-wrap:wrap;gap:6px;margin-top:10px}
.exinfo-tag{background:rgba(77,163,255,.12);color:var(--accent);border-radius:8px;padding:4px 10px;font-size:12px}
.exinfo-steps{margin:0;padding-left:18px;line-height:1.55;color:var(--fg)}
.exinfo-steps li{margin-bottom:10px;font-size:14px}
.exinfo-steps li:last-child{margin-bottom:0}
.exinfo-src{color:var(--muted);font-size:11px;margin-top:10px;font-style:italic}
.exinfo-link{display:block;text-align:center;text-decoration:none}
.demo-name{font-weight:700;font-size:15px;margin:0 0 8px}

/* charts */
.chart-card{overflow:hidden}
.chart-card canvas{width:100%!important;height:220px!important}
.chart-empty{display:flex;align-items:center;justify-content:center;height:220px;color:var(--muted);font-size:14px;text-align:center}
/* Scatter plot with axis titles on both axes needs a little more vertical room than the default
   line/bar charts (220px) so the titles don't feel cramped against the plotted points — but the
   320px this used before was overcorrecting: with typically under a dozen points, that much
   height read as mostly empty space ("stretched").
   Wrapped (like .donut-canvas-wrap) rather than sized directly on the canvas: this card's canvas
   has siblings (the card-head title above, #recovery-corr-list below) inside the same parent, and
   Chart.js's responsive engine measures the canvas's *parent* content-box to decide the canvas's
   internal render resolution — with no dedicated wrapper it counted those siblings' height as
   canvas space too (395px card minus 32px padding = 363px), while CSS then clipped the rendered
   box to 250px, squashing every point and label vertically. The wrapper isolates the canvas in a
   parent that is exactly its own intended size, so Chart.js's internal resolution and the CSS
   box agree. */
.recovery-canvas-wrap{position:relative;height:250px}
.recovery-canvas-wrap canvas{position:absolute!important;inset:0;width:100%!important;height:100%!important}
.donut-wrap{display:flex;align-items:center;gap:16px}
.donut-canvas-wrap{width:160px;height:160px;flex-shrink:0;position:relative}
.donut-canvas-wrap canvas{position:absolute!important;inset:0;width:100%!important;height:100%!important}
.donut-legend{flex:1;display:flex;flex-direction:column;gap:6px}
.dl-row{display:flex;align-items:center;gap:7px;font-size:13px}
.dl-dot{width:9px;height:9px;border-radius:50%;flex-shrink:0}
.dl-lbl{flex:1;color:var(--fg)}
.dl-val{color:var(--muted);font-size:12px;display:flex;align-items:baseline;gap:5px}
.dl-pct{color:var(--accent);font-weight:600}
.dl-head{margin-bottom:2px;padding-bottom:5px;border-bottom:1px solid var(--line)}
.dl-head .dl-dot{background:none}
.dl-head .dl-lbl,.dl-head .dl-val{color:var(--muted);font-size:10px;font-weight:700;
  text-transform:uppercase;letter-spacing:.03em}

/* header actions + bell badge */
.header-actions{display:flex;align-items:center;gap:0}
.bell{position:relative}
.badge{position:absolute;top:2px;right:2px;min-width:16px;height:16px;padding:0 3px;
  background:var(--danger);color:#fff;border-radius:8px;font-size:10px;font-weight:700;
  display:flex;align-items:center;justify-content:center;line-height:1;pointer-events:none}
.badge.hidden{display:none}

/* notifications inbox */
.inbox-list{max-height:60vh;overflow-y:auto}
.inbox-item{padding:12px 2px;border-bottom:1px solid var(--line)}
.inbox-item:last-child{border-bottom:none}
.inbox-item.unread{position:relative;padding-left:14px}
.inbox-item.unread::before{content:"";position:absolute;left:0;top:16px;width:7px;height:7px;
  border-radius:50%;background:var(--accent)}
.inbox-item .it{font-size:14px;line-height:1.45;font-style:italic}
.inbox-item .ia{font-size:12px;color:var(--muted);margin-top:4px}
.inbox-item[data-export-id]{cursor:pointer}
.inbox-item .it.export-it{font-style:normal;font-weight:600;color:var(--accent)}

/* AI sheet */
.ai-field{margin-bottom:10px}
.ai-field label{margin:0 0 5px}
.ai-field-dd{position:relative}
.ai-field .cdd-wrap{margin-bottom:0}
.ai-answer{white-space:pre-wrap;line-height:1.55;font-size:15px}
.ai-insights-in{animation:viewfade .28s cubic-bezier(.25,.46,.45,.94)}
.ai-insights-loading{padding:16px 0;display:flex;align-items:center;justify-content:center}
.ai-banner{background:rgba(255,180,84,.1);border:1px solid rgba(255,180,84,.3);border-radius:12px;
  padding:12px 14px;font-size:13px;color:var(--fg);margin-bottom:12px;
  display:flex;align-items:center;gap:10px;line-height:1.4}
.ai-banner-ico{flex:none;color:rgba(255,180,84,.9);width:20px;height:20px}
.plateau-item{margin-bottom:10px}
.plateau-item:last-child{margin-bottom:0}
textarea.search{resize:vertical;min-height:70px;font-family:inherit}

/* daily quote */
.quote-card{background:linear-gradient(135deg,rgba(77,163,255,.12),rgba(90,209,154,.08));
  border:1px solid var(--line);border-radius:var(--radius);padding:10px 14px;margin-bottom:6px}
.quote-card.hidden{display:none}
.quote-card .qt{font-size:13px;line-height:1.45;font-style:italic;color:var(--fg)}
.quote-card .qa{font-size:11px;color:var(--muted);margin-top:5px;text-align:right}
.quote-card .qh{font-size:10px;color:var(--quote-accent,var(--accent));font-weight:600;letter-spacing:.5px;margin-bottom:4px;display:flex;align-items:center;gap:4px}

/* records */
/* records screen */
.rec-chips{display:flex;gap:7px;overflow-x:auto;padding:14px 14px 6px;scrollbar-width:none;-webkit-overflow-scrolling:touch}
.rec-chips::-webkit-scrollbar{display:none}
.rec-chip{flex-shrink:0;background:var(--card2);border:1px solid var(--line);border-radius:20px;
  padding:6px 14px;font-size:13px;color:var(--muted);cursor:pointer;-webkit-appearance:none;appearance:none;transition:.12s}
.rec-chip.active{background:var(--accent);border-color:var(--accent);color:var(--on-accent);font-weight:600}
.rec-group{margin-bottom:16px}
.rec-group-hdr{display:flex;align-items:center;gap:8px;font-size:12px;font-weight:700;
  text-transform:uppercase;letter-spacing:.06em;color:var(--muted);padding:0 0 8px}
.rec-group-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}
.rec-group-ct{margin-left:auto;font-weight:400;font-size:11px}
/* Same gradient, elevation, radius, padding AND 4px row gap as .card/.session-card (journal) and
   .mrow (exercises) — every list in the app spaces its rows identically. */
.rec-card{display:flex;justify-content:space-between;align-items:center;
  background:linear-gradient(180deg,var(--card),var(--card-end));
  border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:0 2px 10px rgba(0,0,0,.18);
  padding:16px;margin:0 0 4px;
  border-left:3px solid var(--mc,var(--accent))}
.rec-card-l{flex:1;min-width:0}
.rec-card-name{font-size:14px;font-weight:600;color:var(--fg);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rec-card-sub{font-size:11px;color:var(--muted);margin-top:3px}
.rec-card-r{text-align:right;flex-shrink:0;margin-left:12px;display:flex;flex-direction:column;gap:6px}
.rec-card-w{font-size:22px;font-weight:800;color:var(--fg);line-height:1}
.rec-card-kg{font-size:13px;font-weight:400;color:var(--muted);margin-left:2px}
.rec-card-reps{font-size:12px;color:var(--muted);margin-top:2px}
.rec-card-pr,.rec-card-max{border-radius:8px;margin:-4px -6px;padding:4px 6px}
.rec-card-pr.linked,.rec-card-max.linked{cursor:pointer}
.rec-card-pr.linked:active,.rec-card-max.linked:active{background:var(--card2)}
.rec-card-max{border-top:1px solid var(--line);padding-top:8px}
.rec-card-max-lbl{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--muted)}
.rec-card-max-w{font-size:14px;font-weight:700;color:var(--fg);margin-top:1px}
/* keep old .rec-sub for other uses */
.rec-sub{font-size:12px;color:var(--muted);margin-top:2px}

/* card head */
.card-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}
.card-head h3{margin:0}
.card-head-title{display:flex;align-items:center;gap:6px;min-width:0}

/* measurements */
.meas-filter-wrap{margin-bottom:10px;position:relative}
.meas-filter-wrap .cdd-wrap{position:relative}
.measure-list{margin-top:0}
.meas-rec{background:var(--card2);border-radius:12px;padding:14px 14px;margin-bottom:7px}
.meas-rec-top{display:flex;align-items:center;gap:8px}
.meas-cols{display:flex;gap:28px;flex:1}
.meas-col{display:flex;flex-direction:column;gap:1px}
.meas-col-label{font-size:10px;color:var(--muted);font-weight:500;text-transform:lowercase}
.meas-col-val{font-size:13px;font-weight:600;color:var(--fg)}
.meas-act{display:flex;gap:4px;margin-left:auto;align-items:center}
.meas-act .icon-btn{width:36px;height:36px;border-radius:8px;background:none;border:none;display:flex;align-items:center;justify-content:center;cursor:pointer;opacity:.65;transition:opacity .15s}
.meas-act .icon-btn:hover{opacity:1}
.meas-act .minfo{color:var(--accent)}
.meas-act .medit{color:var(--accent)}
.meas-act .mdel{color:var(--danger)}
.meas-detail{margin-top:10px;padding-top:10px;border-top:1px solid var(--line)}
.meas-detail.hidden{display:none}
/* one measurement per line (column), label left + value right */
.mdet-items{display:flex;flex-direction:column;gap:0;margin-bottom:10px}
.mdet-item{display:flex;align-items:center;justify-content:space-between;gap:8px;font-size:13px;
  padding:7px 2px;border-bottom:1px solid var(--line)}
.mdet-item:last-child{border-bottom:none}
.mdet-label{color:var(--muted)}
.mdet-val{color:var(--fg);font-weight:600}
/* left/right body sides colour-coded (like the macro pills) */
.mlr-l{color:#4da3ff}
.mlr-r{color:#ff9d5c}
.mdet-media{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:10px}
.mdet-thumb{position:relative;width:80px;height:80px;border-radius:8px;overflow:hidden;background:var(--card);flex-shrink:0}
.mdet-thumb-inner{width:100%;height:100%;object-fit:cover;cursor:pointer}
.mdet-del-media{position:absolute;top:2px;right:2px;width:26px;height:26px;border-radius:50%;background:rgba(0,0,0,.6);border:none;color:#fff;font-size:14px;line-height:1;display:flex;align-items:center;justify-content:center;cursor:pointer;padding:0}
.mdet-cam-btn{color:var(--accent);cursor:pointer;width:36px;height:36px;border-radius:8px;display:flex;align-items:center;justify-content:center;opacity:.65;transition:opacity .15s;flex-shrink:0}
.mdet-cam-btn:active{opacity:.5}
/* .scroll already gives 14px on every side, so this section needs no extra top padding.
   The camera button only ADDS photos (fixed height, never grows); a separate gallery icon —
   disabled until a photo exists — opens a dedicated modal to view/delete them, so the workout
   screen's height never depends on how many photos were taken. */
/* .scroll's 14px top padding made the gap above the photo row noticeably bigger than the gap
   below it (~4px) — pull the row up so both gaps match. */
#session-body .sess-photos{display:flex;align-items:stretch;gap:8px;margin:-4px 0 10px}
.sess-note-wrap{margin:0 0 10px}
.sess-note-wrap .note-area{margin-top:0}
/* .primary supplies the button's actual look (gradient, radius, shadow, :disabled state) — same
   as every other button in the app; this just positions the small instance at the field's right. */
.sess-note-save{display:block;margin:8px 0 0 auto;padding:8px 18px;font-size:14px}
.sess-note-save:active{opacity:.8}
.sess-cam-btn{position:relative;display:flex;align-items:center;justify-content:center;gap:8px;
  flex:1;color:var(--accent);background:var(--card2);
  border:1px dashed var(--line);border-radius:12px;padding:10px 14px;font-size:14px;font-weight:600;
  cursor:pointer}
.sess-cam-btn:active{opacity:.7}
.sess-cam-btn:disabled{opacity:.6;cursor:default}
.sess-cam-btn .inline-loader{color:var(--accent)}
.sess-gallery-btn{position:relative;flex:none;width:44px;color:var(--accent);background:var(--card2);
  border:1px solid var(--line);border-radius:12px;display:flex;align-items:center;justify-content:center;
  cursor:pointer}
.sess-gallery-btn:active{opacity:.7}
.sess-gallery-btn:disabled{color:var(--muted);opacity:.4;cursor:default}
.sess-gallery-count{position:absolute;top:-6px;right:-6px;min-width:18px;height:18px;padding:0 3px;
  border-radius:9px;background:var(--accent);color:var(--on-accent);font-size:11px;font-weight:800;
  line-height:18px;text-align:center}
/* Sits next to "+ Додати вправу" (see .sess-bottom-bar) rather than as its own full-width row —
   two stacked full-width buttons for one screen was more vertical space than the choice needed. */
.sess-bottom-bar{display:flex;gap:8px;margin:0 14px calc(16px + var(--safe-bot,0px))}
/* Fixed height + identical horizontal padding (not each button's own default padding) so
   toggling done/not-done — which swaps in an icon and a shorter label — never resizes either
   button. flex:1 alone isn't enough for a true 50/50 split: with box-sizing:border-box and
   flex-basis:0%, a flex item's hypothetical size floors at its own horizontal padding+border
   (content can't go negative), so mismatched padding (e.g. .primary's 13px 20px vs a tighter
   secondary button) skews the split even with min-width:0. Equal padding here is what actually
   makes the two buttons equal width. */
.sess-bottom-bar>button{flex:1;min-width:0;height:48px;display:flex;align-items:center;
  justify-content:center;gap:6px;padding:0 10px;border-radius:12px;font-size:14px;font-weight:600;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sess-bottom-bar #add-exercise-btn:disabled{opacity:.45;box-shadow:none;cursor:default;filter:grayscale(.3)}
.sess-complete-btn{color:var(--accent);background:var(--card2);border:1px dashed var(--line);cursor:pointer}
.sess-complete-btn:active{opacity:.7}
.sess-complete-btn.done{color:var(--green);background:color-mix(in srgb,var(--green) 12%,transparent);
  border-style:solid;border-color:var(--green)}
.sess-gallery-card{max-width:420px;border-radius:22px;animation:scalein .2s cubic-bezier(.2,.8,.2,1)}
.sess-gallery-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;max-height:60vh;overflow-y:auto}
.sess-gallery-thumb-inner{cursor:pointer}
.lightbox{position:fixed;inset:0;background:rgba(0,0,0,.92);z-index:70;
  display:flex;align-items:center;justify-content:center;animation:fade .15s}
.lightbox-close{position:absolute;top:calc(14px + env(safe-area-inset-top,0px));right:14px;z-index:1}
.lightbox-body{width:100%;height:100%;display:flex;align-items:center;justify-content:center;padding:14px;touch-action:none}
.lightbox-body img,.lightbox-body video{max-width:100%;max-height:100%;object-fit:contain;border-radius:10px}
.lightbox-body img{transform-origin:center center;transition:transform .05s linear;will-change:transform}
.sess-gallery-thumb{position:relative;aspect-ratio:1;border-radius:10px;overflow:hidden;background:var(--card2)}
.sess-gallery-thumb-inner{width:100%;height:100%;object-fit:cover}
.sess-gallery-thumb-del{position:absolute;bottom:4px;right:4px;width:34px;height:34px;border-radius:8px;
  background:rgba(0,0,0,.55);border:none;color:#fff;display:flex;align-items:center;justify-content:center;
  cursor:pointer}
.sess-gallery-thumb-del:active{background:rgba(0,0,0,.75)}
.meas-show-more{display:block;width:100%;background:none;border:1px solid var(--line);border-radius:10px;color:var(--sub);font-size:13px;padding:9px;cursor:pointer;margin-top:4px}
.meas-show-more:hover{color:var(--fg)}
.meas-month{margin-bottom:6px}
.meas-month-hdr{width:100%;display:flex;align-items:center;gap:8px;background:var(--card2);border:1px solid var(--line);border-radius:12px;padding:10px 14px;cursor:pointer;-webkit-appearance:none;appearance:none;color:var(--fg);font-size:14px;font-weight:600}
.meas-month-hdr:active{opacity:.7}
.meas-month-meta{margin-left:auto;font-size:12px;font-weight:400;color:var(--sub)}
.meas-month-chev{color:var(--sub);flex-shrink:0;transition:transform .2s;transform:rotate(-90deg)}
.meas-month-chev.open{transform:rotate(0deg)}
.meas-month-body{padding-top:6px}
.meas-month-body.hidden{display:none}
.measure-row{display:flex;justify-content:space-between;align-items:center;font-size:13px;
  padding:8px 0;border-top:1px solid var(--line);color:var(--muted)}
.measure-row b{color:var(--fg)}
.measure-row .mdel{background:none;border:none;color:var(--danger);font-size:15px}
.m-grid{display:grid;grid-template-columns:1fr 1fr;gap:4px 10px}

.meas-header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:14px}
.meas-header h2{margin:0;font-size:18px}
/* h2's own 16px bottom margin (.modal-card h2) makes it a much taller flex item than its visible
   text, so align-items:center here centered on that invisible extra height below the text instead
   of the text itself — the (i) button ended up floating above the title instead of level with it. */
.meas-title-wrap{display:flex;align-items:center;gap:8px}
.meas-title-wrap h2{margin:0}
/* Unlike #modal-measure's .meas-header (which already supplies its own margin-bottom around
   .meas-title-wrap + the date input side by side), #modal-1rm uses .meas-title-wrap bare as the
   first child of .modal-card, so it must supply its own gap to the next section now that h2's
   own margin was zeroed out above. */
#modal-1rm .meas-title-wrap{margin-bottom:16px}
.meas-info-btn{background:none;border:none;padding:0;color:var(--muted);display:flex;align-items:center;cursor:pointer;transition:color .15s}
.meas-info-btn.on,.meas-info-btn:active{color:var(--accent)}
.meas-date{background:var(--card2);border:1px solid var(--line);color:var(--fg);
  border-radius:12px;padding:8px 12px;font-size:14px;font-family:inherit;outline:none;cursor:pointer;flex-shrink:0}
.meas-date:focus{border-color:var(--accent)}
/* Nutrition: the date picker lives on its own slim row, so the header keeps just the title +
   goals/settings icons — identical layout and icon position to every other screen. */
.nutri-datebar{position:relative;display:flex;align-items:center;justify-content:center;gap:10px;padding:6px 14px 2px}
.day-nav{background:var(--card2);border:1px solid var(--line);color:var(--accent);
  width:34px;height:34px;border-radius:10px;font-size:20px;line-height:1;display:flex;
  align-items:center;justify-content:center;cursor:pointer;flex:none}
.day-nav:active{background:var(--card)}
.day-nav:disabled{opacity:.28;pointer-events:none}
/* tappable date label that opens the native calendar (month/year jumps) */
.date-display{position:relative;display:flex;align-items:center;gap:8px;background:var(--card2);border:1px solid var(--line);
  color:var(--fg);border-radius:12px;padding:8px 16px;font-size:14px;font-weight:600;cursor:pointer;
  font-family:inherit;min-width:128px;justify-content:center}
.date-display:active{background:var(--card)}
.date-display svg{width:16px;height:16px;color:var(--accent);flex:none}
/* the real date input overlays the styled button → tapping reliably opens the native calendar */
.date-overlay{position:absolute;inset:0;width:100%;height:100%;opacity:0;border:none;background:none;
  margin:0;padding:0;cursor:pointer;-webkit-appearance:none;appearance:none}
.nutri-today-btn{position:absolute;right:12px;top:50%;transform:translateY(-50%);background:none;border:none;
  color:var(--accent);cursor:pointer;padding:0;width:34px;height:34px;display:flex;align-items:center;justify-content:center}
/* manual product entry */
.manual-toggle{background:none;border:none;color:var(--accent);font-size:13px;font-weight:600;
  padding:6px 2px;cursor:pointer;align-self:flex-start}
.food-manual{display:flex;flex-direction:column;gap:8px;margin-top:4px}
.manual-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.manual-grid label{display:block;font-size:12px;color:var(--muted);margin-bottom:3px}
.manual-hint{font-size:11px;color:var(--muted);text-align:center;margin-top:-2px}
.meas-date::-webkit-calendar-picker-indicator{opacity:.55;cursor:pointer}
.search-sm{padding:12px 14px;font-size:15px}
.meas-group{margin-top:10px}
.meas-group>label{display:block;font-size:12px;color:var(--muted);margin:0 0 5px}
/* iOS-style toggle row */
.meas-bi-row{display:flex;align-items:center;justify-content:space-between;
  padding:10px 0;margin:6px 0 2px;border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.meas-bi-row span{font-size:14px;color:var(--fg)}
.ios-toggle{width:44px;height:26px;background:var(--card2);border:1.5px solid var(--line);
  border-radius:13px;position:relative;cursor:pointer;flex-shrink:0;
  transition:background .22s,border-color .22s}
.ios-toggle.active{background:var(--accent);border-color:var(--accent)}
.ios-thumb{position:absolute;top:2px;left:2px;width:18px;height:18px;
  background:#fff;border-radius:50%;box-shadow:0 1px 4px rgba(0,0,0,.3);
  transition:transform .22s}
.ios-toggle.active .ios-thumb{transform:translateX(18px)}

/* rest timer — centered modal with dimmed backdrop */
.rest-overlay{position:fixed;inset:0;z-index:80;display:flex;align-items:center;justify-content:center;
  padding:24px;background:rgba(0,0,0,.62);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);
  animation:fade .18s}
.rest-card{width:100%;max-width:320px;background:var(--card);border:1px solid var(--line);border-radius:24px;
  padding:22px 22px 18px;box-shadow:0 20px 60px rgba(0,0,0,.55);text-align:center;
  animation:rt-pop .22s cubic-bezier(.18,.9,.32,1.2)}
@keyframes rt-pop{from{opacity:0;transform:translateY(12px) scale(.94)}to{opacity:1;transform:none}}
.rt-title{font-size:13px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);margin-bottom:14px}
.rt-ring{position:relative;width:200px;height:200px;margin:0 auto 6px}
.rt-ring svg{width:100%;height:100%;transform:rotate(-90deg)}
.rt-ring-bg{fill:none;stroke:var(--line);stroke-width:8}
.rt-ring-fg{fill:none;stroke:var(--accent);stroke-width:8;stroke-linecap:round;
  stroke-dasharray:339.292;stroke-dashoffset:0;transition:stroke-dashoffset .5s linear,stroke .3s}
.rt-count{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  font-size:48px;font-weight:700;font-variant-numeric:tabular-nums;color:var(--fg);letter-spacing:1px}
.rest-card.done .rt-ring-fg{stroke:var(--green)}
.rest-card.done .rt-count{color:var(--green);animation:rt-flash .6s ease-in-out 3}
@keyframes rt-flash{0%,100%{opacity:1}50%{opacity:.35}}
.rt-adjust{display:flex;gap:10px;justify-content:center;margin:14px 0 10px}
.rt-adj-btn{flex:1;background:var(--card2);border:1px solid var(--line);color:var(--fg);
  border-radius:12px;padding:11px 0;font-size:14px;font-weight:600;cursor:pointer}
.rt-adj-btn:active{background:var(--accent);color:var(--on-accent);border-color:var(--accent)}
.rt-presets{display:flex;gap:6px;justify-content:center;margin:0 0 14px}
.rt-presets button{flex:1;background:none;border:1px solid var(--line);color:var(--muted);
  border-radius:10px;padding:8px 0;font-size:13px;font-weight:600;cursor:pointer}
.rt-presets button:active{background:var(--accent);color:var(--on-accent);border-color:var(--accent)}
.rt-stop-btn{width:100%;background:var(--danger);color:#fff;border:none;border-radius:14px;
  padding:13px 0;font-size:15px;font-weight:700;cursor:pointer}
.rt-stop-btn:active{filter:brightness(.9)}

/* toast */
.toast{position:fixed;left:50%;bottom:calc(64px + var(--safe-bot,0px));transform:translateX(-50%);
  background:#222c38;color:#fff;padding:11px 18px;border-radius:12px;font-size:14px;
  display:flex;align-items:center;gap:14px;
  text-align:center;white-space:pre-line;max-width:calc(100vw - 32px);width:max-content;
  z-index:99;box-shadow:0 6px 18px rgba(0,0,0,.4);animation:fade .2s}
.toast-undo{background:none;border:none;color:var(--accent2);font-weight:700;font-size:14px;
  padding:0;cursor:pointer;flex:none}

/* confirm + PR modals: centered, not bottom-sheet */
#modal-confirm,#modal-pr{align-items:center;padding:0 20px}
#modal-confirm .modal-card{border-radius:22px;padding:28px 22px calc(22px + var(--safe-bot,0px));animation:scalein .2s cubic-bezier(.2,.8,.2,1)}
#modal-pr .modal-card{border-radius:22px;padding:16px 22px calc(22px + var(--safe-bot,0px));animation:scalein .2s cubic-bezier(.2,.8,.2,1);overflow:hidden}
@keyframes scalein{from{transform:scale(.92);opacity:0}to{transform:scale(1);opacity:1}}

/* confirm modal */
.confirm-card{text-align:center}
.confirm-icon-wrap{width:58px;height:58px;border-radius:50%;background:color-mix(in srgb,var(--danger) 14%,transparent);
  display:flex;align-items:center;justify-content:center;margin:0 auto 16px;color:var(--danger)}
.confirm-card h3{font-size:18px;font-weight:700;margin:0 0 8px;color:var(--fg)}
.confirm-card p{font-size:14px;color:var(--sub);margin:0;line-height:1.45;white-space:pre-line}
.danger-btn{flex:1;background:var(--danger);color:#fff;border:none;border-radius:12px;
  padding:13px;font-size:15px;font-weight:600;cursor:pointer;-webkit-appearance:none;appearance:none;transition:.12s}
.danger-btn:active{opacity:.8}

/* personal record modal */
.pr-card{text-align:center}
.pr-coach-wrap{height:160px;display:flex;align-items:flex-end;justify-content:center;
  margin:0 0 8px;pointer-events:none}
.pr-coach{height:170px;width:auto;object-fit:contain;
  animation:coachBounce .6s cubic-bezier(.2,.8,.2,1) both}
@keyframes coachBounce{
  0%{transform:translateY(60px) scale(.85);opacity:0}
  60%{transform:translateY(-10px) scale(1.04);opacity:1}
  80%{transform:translateY(4px) scale(.98)}
  100%{transform:translateY(0) scale(1);opacity:1}
}
.pr-trophy{font-size:52px;line-height:1;margin:12px 0 8px;
  animation:trophyPop .5s .15s cubic-bezier(.2,.8,.2,1) both}
@keyframes trophyPop{
  0%{transform:scale(0) rotate(-15deg);opacity:0}
  70%{transform:scale(1.18) rotate(5deg);opacity:1}
  100%{transform:scale(1) rotate(0deg);opacity:1}
}
.pr-label-top{font-size:12px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
  color:var(--accent);margin-bottom:10px}
.pr-weight{font-size:32px;font-weight:800;color:var(--fg);letter-spacing:-.5px;line-height:1.2;margin-bottom:6px}
.pr-exname{font-size:14px;color:var(--sub);margin-bottom:24px}
.pr-close-btn{width:100%;padding:14px;font-size:15px}

/* settings screen */
/* ---- achievements / badge wall ---- */
.ach-summary{text-align:center;padding:6px 0 16px}
.ach-sum-num{font-size:44px;font-weight:800;color:var(--fg);line-height:1;letter-spacing:-.02em}
.ach-sum-of{font-size:24px;font-weight:700;color:var(--muted)}
.ach-sum-lbl{font-size:12px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--muted);margin-top:6px}
.ach-sum-bar{height:6px;border-radius:3px;background:var(--card2);margin:12px auto 0;max-width:280px;overflow:hidden}
.ach-sum-fill{height:100%;border-radius:3px;background:var(--accent);box-shadow:0 0 10px var(--accent-glow);transition:width .4s ease}
.ach-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(102px,1fr));gap:10px;padding-bottom:8px}
.ach-card{background:var(--card2);border:1px solid var(--line);border-radius:14px;padding:12px 8px 10px;
  display:flex;flex-direction:column;align-items:center;text-align:center;gap:4px;position:relative}
.ach-card.earned{border-color:color-mix(in srgb,var(--accent) 45%,transparent);
  box-shadow:0 0 0 1px color-mix(in srgb,var(--accent) 30%,transparent),0 4px 14px rgba(0,0,0,.2)}
.ach-ico{position:relative;width:46px;height:46px;border-radius:50%;display:flex;align-items:center;justify-content:center;
  background:var(--card);color:var(--muted);margin-bottom:2px}
.ach-ico svg{width:24px;height:24px}
.ach-card.earned .ach-ico{background:color-mix(in srgb,var(--accent) 16%,transparent);color:var(--accent)}
.ach-check{position:absolute;right:-3px;bottom:-3px;width:18px;height:18px;border-radius:50%;background:var(--accent);
  color:var(--on-accent);display:flex;align-items:center;justify-content:center;border:2px solid var(--bar)}
.ach-check svg{width:10px;height:10px}
.ach-target{font-size:16px;font-weight:800;color:var(--fg)}
.ach-card:not(.earned) .ach-target{color:var(--muted)}
.ach-lbl{font-size:11px;color:var(--muted);line-height:1.2}
.ach-earned-at{font-size:10px;color:var(--accent);font-weight:600;margin-top:2px}
.ach-prog{height:4px;width:100%;border-radius:2px;background:var(--card);overflow:hidden;margin-top:4px}
.ach-prog-fill{height:100%;border-radius:2px;background:var(--muted)}
.ach-prog-txt{font-size:10px;color:var(--muted);margin-top:2px}
.settings-list{padding:8px 0 0}
.settings-section{font-size:12px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--muted);padding:16px 4px 6px}
.settings-item{display:flex;align-items:center;justify-content:space-between;
  padding:16px 18px;border-bottom:1px solid var(--line);cursor:pointer;transition:.12s}
.settings-item:active{background:var(--card2)}
.settings-item:last-child{border-bottom:none}
.settings-item>span,.settings-left>span{font-size:16px;font-weight:500}
.settings-left{display:flex;align-items:center;gap:12px}
.settings-ico{width:20px;height:20px;color:var(--accent);flex:none}
.settings-right{display:flex;align-items:center;gap:6px}
.chart-ico{width:16px;height:16px;vertical-align:middle;color:var(--accent);margin-right:4px;flex:none}
.settings-value{font-size:14px;color:var(--muted)}
.settings-sep{height:1px;background:linear-gradient(90deg,transparent,var(--line) 20%,var(--line) 80%,transparent);margin:6px 0}
.data-backup-card{border:1px solid var(--line);border-radius:14px;overflow:hidden;margin:8px 0}
.data-backup-header{display:flex;align-items:center;gap:10px;padding:11px 16px;color:var(--muted);font-size:14px}
.data-backup-header .settings-ico{width:18px;height:18px;flex-shrink:0}
/* The icon is absolutely positioned (not an inline flex item before the text) specifically so it
   doesn't consume space that would push the message text to the right — .data-backup-sub's own
   44px left padding is what actually lines the text up with "Керування даними" above it; an
   inline icon+gap ahead of the text was eating ~18px out of that budget, leaving the message
   start 18px further right than the header's text above it. */
.data-backup-sub{position:relative;padding:0 16px 11px 44px;margin-top:-4px;font-size:12px;color:var(--muted);
  border-bottom:1px solid var(--line)}
/* Amber, not red — this is a gentle nudge ("you might want to back up"), not an error state. */
.data-backup-sub.warn{color:var(--warn)}
.data-backup-sub svg{position:absolute;left:16px;top:2px;width:13px;height:13px}
.data-backup-actions{display:flex}
.data-backup-btn{flex:1;display:flex;flex-direction:column;align-items:center;gap:5px;padding:14px 8px;background:none;border:none;border-right:1px solid var(--line);color:var(--fg);font-size:14px;font-weight:500;cursor:pointer}
.data-backup-btn:last-child{border-right:none}
.data-backup-btn:active{background:var(--card2)}
.data-backup-btn svg{color:var(--muted)}
/* Sits under the action row, above the card's own border, stating plainly what the JSON backup
   does NOT contain — the binaries are excluded on purpose (see routers/data_transfer.py). */
.data-backup-note{padding:10px 16px 12px;border-top:1px solid var(--line);
  font-size:11px;color:var(--muted);line-height:1.4}
.btn-with-ico{display:flex;align-items:center;justify-content:center;gap:8px}
.chevron{width:20px;height:20px;color:var(--muted);flex:none;stroke-linecap:round;stroke-linejoin:round}

/* generic bottom sheet options */
.bs-options{display:flex;flex-direction:column;gap:8px;margin-bottom:4px}
.bs-option{background:var(--card2);border:1px solid var(--line);color:var(--fg);
  border-radius:12px;padding:14px 16px;font-size:16px;text-align:left}
.bs-option.active{border-color:var(--accent);color:var(--accent)}
.bs-option:active{background:var(--card)}
.bs-option.info{opacity:.65;pointer-events:none;font-size:13px;cursor:default}

/* ===== Week strip ===== */
#week-strip{display:block;overflow:hidden;width:100%;
  background:var(--nav-bg);border-bottom:1px solid var(--line);flex-shrink:0;padding:4px 0}
#week-strip table{width:100%;table-layout:fixed;border-collapse:collapse}
.wday{text-align:center;cursor:pointer;padding:4px 0;vertical-align:top}
.wday-label{font-size:10px;font-weight:600;color:var(--muted);line-height:1.3;display:block}
.wday-num{font-size:15px;font-weight:700;color:var(--muted);
  width:30px;height:28px;line-height:28px;text-align:center;border-radius:8px;
  display:block;margin:1px auto;transition:.12s}
.wday.today .wday-num{color:var(--accent)}
.wday.selected .wday-num{background:var(--accent);color:var(--on-accent)}
.wday-dot{width:4px;height:4px;border-radius:50%;background:var(--accent);margin:2px auto;display:block}
.wday-dot.empty{visibility:hidden}

/* ===== Month accordion ===== */
details.month-group,#workouts-list details{list-style:none}
#workouts-list details+details{margin-top:4px}
.month-summary{display:flex;align-items:center;gap:8px;
  padding:10px 4px;cursor:pointer;user-select:none;-webkit-user-select:none;
  border-radius:10px;margin-bottom:4px}
.month-summary::-webkit-details-marker{display:none}
.month-summary::marker{display:none}
.month-name{font-size:13px;font-weight:700;color:var(--fg);text-transform:capitalize;flex:1}
.month-count{font-size:12px;color:var(--muted);flex-shrink:0}
.month-chev{transition:transform .22s;flex-shrink:0}
details[open]>.month-summary .month-chev{transform:rotate(90deg)}

/* ===== Muscle grid (Library) ===== */
.mrow-list{display:flex;flex-direction:column;gap:0;padding:0 0 12px}
/* Same background gradient + shadow as the shared .card (session cards etc. use it directly) —
   .mrow couldn't just use the .card class itself since it needs a fixed-width image column the
   generic card doesn't have, but it still has to read as the same kind of card everywhere else. */
.mrow{display:flex;align-items:center;gap:0;background:linear-gradient(180deg,var(--card),var(--card-end));
  border:1px solid var(--line);box-shadow:0 2px 10px rgba(0,0,0,.18);
  border-radius:var(--radius);margin-bottom:4px;overflow:hidden;cursor:pointer;
  transition:transform .12s,background .12s;-webkit-tap-highlight-color:transparent}
.mrow:active{transform:scale(.98);background:var(--card2)}
/* No left padding: with justify-content:center already centering the svg in the full 56px width,
   a one-sided 6px left padding just shrank the centered box asymmetrically — 8px of visual gap on
   the left vs 2px on the right, reading as the figure being shoved off-center. */
.mrow-fig{width:56px;flex-shrink:0;display:flex;align-items:center;justify-content:center;
  padding:4px 0;align-self:stretch;background:linear-gradient(135deg,var(--card) 0%,rgba(0,229,255,.04) 100%)}
.mrow-fig svg{width:46px;height:auto;display:block}
.mrow-info{flex:1;padding:8px 8px 8px 10px;min-width:0}
.mrow-name{font-size:16px;font-weight:700;color:var(--fg);line-height:1.2}
.mrow-count{font-size:12px;color:var(--muted);margin-top:3px}
.mrow-chev{padding-right:14px;color:var(--muted);flex-shrink:0}

/* ===== Muscle percentage breakdown ===== */
.mm-pct-list{margin-top:14px;display:flex;flex-direction:column;gap:7px;border-top:1px solid var(--line);padding-top:12px}
.mm-pct-row{display:grid;grid-template-columns:1fr 36px 80px;align-items:center;gap:8px}
.mm-pct-name{font-size:13px;color:var(--fg);text-transform:capitalize}
.mm-pct-val{font-size:12px;color:var(--muted);text-align:right;font-variant-numeric:tabular-nums}
.mm-pct-track{height:5px;background:var(--card2);border-radius:3px;overflow:hidden}
.mm-pct-fill{height:100%;background:var(--accent);border-radius:3px}
.mm-pct-fill.sec{background:color-mix(in srgb,var(--accent) 45%,var(--card2))}

/* ===== Consistency heatmap ===== */
.heatmap-wrap{padding-top:4px}
.heatmap{display:flex;gap:4px;align-items:flex-start}
.hm-labels{display:flex;flex-direction:column;gap:3px;flex-shrink:0;margin-top:0}
.hm-day-label{font-size:9px;color:var(--muted);height:14px;line-height:14px;width:22px;text-align:right;padding-right:4px}
.hm-day-label.hm-weekend{color:var(--accent);opacity:.85}
.hm-grid{display:flex;gap:3px;flex:1;overflow:visible;padding-right:2px}
.hm-col{display:flex;flex-direction:column;gap:3px;align-items:stretch;flex:1;min-width:0}
.hm-cell{width:100%;height:14px;border-radius:2px}
.hm-cell.lv0{background:var(--card2)}
.hm-cell.lv1{background:color-mix(in srgb,var(--accent) 45%,var(--card2))}
.hm-cell.lv2{background:var(--accent)}
.hm-cell.hm-today{box-shadow:0 0 0 1.5px var(--accent)}
.hm-month{font-size:9px;color:var(--muted);margin-top:2px;height:12px;line-height:12px;white-space:nowrap}
/* Renamed from .hm-legend (which the muscle-heatmap card's status-key legend also uses, just
   above) — sharing that class name pulled in its flex-wrap:wrap, and .hm-cell's width:100% (sized
   for a full-width grid column) then forced each of the 3 swatches onto its own wrapped line
   instead of sitting inline next to "Менше"/"Більше". */
/* space-between (not flex-end) so the legend spans the full card width — "Менше" flush left,
   "Більше" flush right, swatches centred between them — instead of hugging the right edge. */
.hm-freq-legend{display:flex;align-items:center;margin-top:8px;font-size:11px;color:var(--muted);gap:8px}
.hm-freq-scale{display:flex;align-items:center;gap:2px;flex:1;min-width:0}
.hm-freq-legend .hm-cell{display:block;width:auto;height:8px;flex:1;border-radius:0}
.hm-freq-legend .hm-cell:first-child{border-radius:4px 0 0 4px}
.hm-freq-legend .hm-cell:last-child{border-radius:0 4px 4px 0}

/* ===== RPE input (set editor) ===== */
.rpe-input{width:50px;min-width:0;background:var(--card2);border:1px solid var(--line);
  border-radius:10px;height:48px;padding:0 4px;color:var(--fg);font-size:14px;
  text-align:center;font-family:inherit;-webkit-appearance:none}
.rpe-input::-webkit-outer-spin-button,.rpe-input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.rpe-input::placeholder{color:var(--muted);font-size:11px}

/* ===== last-time / overload hint ===== */
.lasttime{display:flex;align-items:flex-start;gap:8px;background:var(--card2);
  border:1px solid var(--line);border-radius:12px;padding:8px 10px;margin:4px 0 12px;
  font-size:13px;color:var(--muted);line-height:1.35}
.lasttime .lt-ico{color:var(--accent);font-size:15px;line-height:1.2;flex:none;display:inline-flex;align-items:center;margin-top:2px}
.lasttime .lt-txt b{color:var(--fg);font-weight:600}
/* swap-exercise suggestions: a quiet toggle that expands into same-muscle alternatives */
.ex-alts{margin:4px 0 12px}
.alts-toggle{background:none;border:none;color:var(--accent);font:inherit;font-size:13px;
  font-weight:600;padding:2px 0;cursor:pointer}
.alts-chips{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}
.alts-chip{display:inline-flex;flex-direction:column;align-items:flex-start;gap:1px;
  background:var(--card2);border:1px solid var(--line);border-radius:10px;padding:6px 10px;
  color:var(--fg);font:inherit;font-size:12.5px;text-align:left;cursor:pointer}
.alts-chip:active{background:var(--line)}
.alts-chip .alts-eq{font-size:10.5px;color:var(--muted)}
.ai-apply-btn{display:inline-block;margin-top:6px;background:var(--accent);color:var(--on-accent);border:none;
  font:inherit;font-size:12px;font-weight:600;padding:5px 14px;border-radius:14px;cursor:pointer}
.ai-apply-btn:active{opacity:.85}
/* button-triggered AI suggestion — no request fires until this is tapped */
.ai-suggest-btn{display:inline-flex;align-items:center;gap:6px;background:var(--card2);
  color:var(--accent);border:1px solid var(--line);border-radius:14px;padding:7px 14px;
  font:inherit;font-size:13px;font-weight:600;cursor:pointer;margin:4px 0 12px}
.ai-suggest-btn:active{background:var(--line)}
.ai-suggest-btn:disabled{opacity:.6;cursor:default}
.ai-suggest-btn svg{flex:none}

/* ===== tools button + plate/warm-up modal ===== */
/* opened from within #modal-ex (also z-index:50) — must sit above it so its inputs are reachable */
#modal-tools{z-index:60}
#open-tools{grid-column:1/-1}
.tools-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin:8px 0 4px}
.tool-plates{margin:12px 0 4px}
.tool-perside{font-size:12px;color:var(--muted);margin-bottom:8px;text-align:center}
.plate-chips{display:flex;flex-wrap:wrap;gap:8px;justify-content:center}
.plate-chip{display:inline-flex;align-items:center;gap:3px;background:var(--accent);
  color:#fff;border-radius:10px;padding:6px 11px;font-weight:700;font-size:15px}
.plate-chip .px{font-weight:500;opacity:.85;font-size:12px}
.tool-empty{color:var(--muted);font-size:13px;text-align:center;padding:8px}
.tool-warmup{display:flex;flex-direction:column;gap:6px}
.warmup-row{display:grid;grid-template-columns:48px 1fr 40px;align-items:center;gap:8px;
  background:var(--card2);border:1px solid var(--line);border-radius:10px;padding:8px 12px}
.warmup-row .wu-pct{color:var(--muted);font-size:13px}
.orm-result{text-align:center;padding:14px 0 4px;font-size:28px;font-weight:700;color:var(--accent)}
.orm-result .orm-unit{font-size:15px;font-weight:500;color:var(--muted);margin-left:4px}
.orm-result.empty{font-size:13px;font-weight:500;color:var(--muted);padding:14px 0}
.orm-table{margin-top:6px;display:flex;flex-direction:column;gap:6px}
.orm-table-cap{font-size:12px;color:var(--muted);margin-bottom:2px;text-align:center}
.orm-row{display:flex;justify-content:space-between;align-items:center;
  background:var(--card2);border:1px solid var(--line);border-radius:10px;padding:8px 12px;font-size:14px}
.orm-row-reps{color:var(--muted)}
.orm-row-w{font-weight:700}
.warmup-row b{font-size:15px}
.warmup-row .wu-reps{color:var(--muted);text-align:right;font-size:13px}

/* ===== streak + weekly-goal widget ===== */
/* Streak / weekly goal. Follows DESIGN.md's hierarchy rather than decorating: the streak count is
   the "display moment" (big bold tabular number), everything around it drops to Label weight, and
   the only colour is the accent on the flame — signal, not ornament. The (i) moves to the card's
   top-right like every other card-level info button instead of sitting between the number and its
   own label, where it broke the number/label pairing. */
.streak-widget{position:relative;display:flex;align-items:center;gap:16px;
  background:linear-gradient(135deg,var(--card),var(--card-end));
  border:1px solid var(--line);border-radius:16px;padding:14px 16px;margin-bottom:10px}
/* flex:none + nowrap label: sized to its own content rather than a guessed min-width, so the
   uppercase label can't wrap onto a second line and the meta column takes whatever is left.
   Centred, so the number, its label and the freeze chip stack on a shared axis. */
.streak-fire{display:flex;flex-direction:column;align-items:center;flex:none}
.streak-num-row{display:flex;align-items:center;gap:5px;color:var(--accent)}
.streak-ico{width:17px;height:17px;flex:none}
.streak-fire .streak-num{font-size:26px;font-weight:800;line-height:1;letter-spacing:-.5px;
  color:var(--fg);font-variant-numeric:tabular-nums}
.streak-fire .streak-lbl{font-size:10px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;
  color:var(--muted);line-height:1.1;margin-top:6px;white-space:nowrap}
.streak-freeze-badge{display:inline-flex;align-items:center;gap:4px;font-size:11px;font-weight:600;
  color:var(--muted);background:var(--card2);border:1px solid var(--line);border-radius:7px;
  padding:2px 7px;margin-top:7px;white-space:nowrap;cursor:pointer;font-variant-numeric:tabular-nums}
.sfb-ico{width:11px;height:11px;flex:none}
.streak-info-btn{position:absolute;top:9px;right:9px;background:none;border:none;padding:4px;
  color:var(--muted);cursor:pointer;display:flex;line-height:0}
.streak-info-btn svg{width:14px;height:14px}
.streak-goal{position:relative;width:48px;height:48px;flex:none;cursor:pointer}
.goal-ring{width:48px;height:48px;transform:rotate(-90deg)}
.goal-ring .gr-bg{fill:none;stroke:var(--line);stroke-width:4}
.goal-ring .gr-fg{fill:none;stroke:var(--accent);stroke-width:4;stroke-linecap:round;transition:stroke-dashoffset .4s ease}
.gr-text{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  font-size:12px;font-weight:700;font-variant-numeric:tabular-nums}
.streak-goal.met .goal-ring .gr-fg{stroke:var(--green)}
.streak-goal.met .gr-text{color:var(--green)}
.streak-meta{display:flex;flex-direction:column;gap:3px;flex:1;min-width:0;padding-right:16px}
.streak-meta b{font-size:11px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--fg)}
.streak-meta .sub{color:var(--muted);font-size:12px;line-height:1.35}

/* ===== today's training suggestion (inside #modal-new — informational, not a nav target) ===== */
/* margin-bottom, not just top: the label right after this (Група мʼязів) is
   `.modal-card>label:first-of-type`, which zeroes its OWN margin-top — that rule assumed the
   label would always be the first visual thing in the modal, which broke the moment this card
   was moved to sit above it, leaving them flush against each other with no gap at all. Supplying
   the gap here instead doesn't depend on what happens to follow. */
.tds-widget{margin:12px 0 14px}
.tds-card{display:flex;align-items:center;gap:12px;background:linear-gradient(135deg,var(--card),var(--card-end));
  border:1px solid var(--line);border-radius:16px;padding:12px 14px}
.tds-dot{width:10px;height:10px;border-radius:50%;flex:none}
.tds-body{flex:1;min-width:0}
.tds-title{font-size:11px;color:var(--muted);font-weight:600}
.tds-main{font-size:16px;font-weight:700;margin-top:1px}
.tds-sub{font-size:12px;color:var(--muted);margin-top:2px}

/* ===== days since last trained (Progress→Аналітика card; title is the card's static <h3>) ===== */
/* Wrapping grid, not a horizontal scroller — with up to 9 muscles a scroll strip only ever showed
   2-3 chips and hid the rest off-screen with no visual hint more existed. */
.dst-chips{display:grid;grid-template-columns:repeat(auto-fill,minmax(96px,1fr));gap:8px}
.dst-chip{display:flex;flex-direction:column;gap:2px;background:var(--card);
  border:1px solid var(--line);border-radius:12px;padding:8px 12px}
.dst-chip b{font-size:12px;display:flex;align-items:center;gap:6px}
.dst-dot{width:8px;height:8px;border-radius:50%;flex:none}
.dst-days{font-size:11px;color:var(--muted)}

/* ===== body fat (Navy formula) ===== */
.bf-latest{margin-top:10px;text-align:center;font-size:13px;color:var(--muted)}
.bf-hint{font-size:13px;color:var(--muted);margin:0 0 12px;text-align:center}
.height-hint{font-size:12px;color:var(--muted);margin:10px 0 0}

/* ===== measurement reminder ===== */
.mr-sub{font-size:13px;color:var(--muted);margin:0 0 12px}

/* ===== on this day ===== */
.otd-card{margin-bottom:10px}
.otd-head{font-weight:700;font-size:14px;margin-bottom:8px}
.otd-row{display:flex;align-items:center;justify-content:space-between;gap:8px;
  padding:8px 0;border-top:1px solid var(--line);cursor:pointer}
.otd-row:first-of-type{border-top:none}
.otd-sub{font-size:12px;color:var(--muted);margin-top:2px}
.otd-row .chevron{width:18px;height:18px;color:var(--muted);flex:none}
.ext-act-del{background:none;border:none;color:var(--danger);flex:none;padding:6px;cursor:pointer;display:flex;align-items:center;justify-content:center}
/* Cardio activity row (Garmin + manual "Інше кардіо"): icon tile · name+date+delete · chips.
   The date and the delete button share one right-aligned group on the title line, so they line
   up cleanly instead of the date floating top-right while the trash sat mid-row. */
.act-row{display:flex;align-items:flex-start;gap:11px;padding:10px 0;border-top:1px solid var(--line)}
.act-row:first-of-type{border-top:none}
.act-ico{flex:none;width:38px;height:38px;border-radius:11px;background:var(--card2);
  display:flex;align-items:center;justify-content:center;line-height:1;color:var(--accent)}
.act-ico-svg{width:20px;height:20px}
.act-main{flex:1;min-width:0}
.act-top{display:flex;align-items:center;justify-content:space-between;gap:8px;min-height:20px}
.act-title{flex:1;min-width:0;font-size:14px;font-weight:600;color:var(--fg);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.act-right{display:flex;align-items:center;gap:2px;flex:none}
.act-date{font-size:12px;color:var(--muted);flex:none}
.act-metrics{display:flex;flex-wrap:wrap;gap:6px;margin-top:6px}
.act-metric{background:var(--card2);border-radius:8px;padding:2px 8px;font-size:12px;color:var(--muted)}
.act-metric b{color:var(--fg);font-weight:700;margin-right:2px}
.act-note{font-size:12px;color:var(--muted);margin-top:5px;line-height:1.35}
.act-del{background:none;border:none;color:var(--danger);flex:none;margin:-4px -6px -4px 2px;padding:6px;cursor:pointer;display:flex;align-items:center;justify-content:center}
.act-del svg{width:17px;height:17px}
.list-show-more{display:block;width:100%;text-align:center;font-size:12px;color:var(--accent);
  background:none;border:none;margin-top:10px;padding:6px;cursor:pointer}
.card .hint{font-size:12px;color:var(--muted);line-height:1.4;margin:2px 0 10px}

/* ===== routines (templates) in new-workout modal ===== */
.routines-head{font-size:12px;color:var(--muted);margin:14px 0 8px;text-transform:uppercase;letter-spacing:.04em}
.routine-row,.pg-row{display:flex;align-items:center;gap:8px;background:var(--card2);
  border:1px solid var(--line);border-radius:12px;padding:8px 10px;margin-bottom:8px}
.routine-info{flex:1;min-width:0;display:flex;flex-direction:column}
.routine-info b{font-size:14px}
.routine-sub{font-size:12px;color:var(--muted)}
.routine-del{flex:none;color:var(--danger)}
.routine-start{flex:none}
.pg-row{cursor:pointer}
.pg-row .chevron{width:18px;height:18px;color:var(--muted);flex:none}

/* ===== nutrition ===== */
.nutri-hdr-right{display:flex;align-items:center;gap:6px}
.nutri-summary{display:flex;flex-direction:column;gap:10px}
.ns-top{display:flex;align-items:center;gap:16px}
.kcal-ring{position:relative;width:104px;height:104px;flex:none}
.kcal-ring svg{width:104px;height:104px;transform:rotate(-90deg)}
.kcal-ring .kr-bg{fill:none;stroke:var(--line);stroke-width:9}
.kcal-ring .kr-fg{fill:none;stroke:var(--accent);stroke-width:9;stroke-linecap:round;transition:stroke-dashoffset .45s ease}
.kcal-ring .kr-fg.over{stroke:var(--danger)}
.kr-center{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center}
.kr-num{font-size:24px;font-weight:800;line-height:1}
.kr-num.over{color:var(--danger)}
.kr-lbl{font-size:11px;color:var(--muted);margin-top:2px}
.ns-macros{flex:1;min-width:0;display:flex;flex-direction:column;gap:10px}
.macro-bar{display:flex;flex-direction:column;gap:4px}
.mb-top{display:flex;justify-content:space-between;font-size:12px}
.mb-lbl{color:var(--fg);font-weight:600}
.mb-val{color:var(--muted)}
.mb-track{height:7px;border-radius:4px;background:var(--line);overflow:hidden}
.mb-fill{height:100%;border-radius:4px;transition:width .45s ease}
.mb-fill.mb-prot{background:#4da3ff}
.mb-fill.mb-carb{background:#ffb454}
.mb-fill.mb-fat{background:#ff7a90}
.mb-fill.over{background:var(--danger)}
.ns-kcal-line{font-size:13px;color:var(--muted);text-align:center;border-top:1px solid var(--line);padding-top:8px}
/* estimated training burn — informational, never subtracted from the goal above */
.ns-burned{font-size:12px;color:var(--muted);text-align:center;padding-top:8px}
.ns-burned+.ns-kcal-line{border-top:none;padding-top:4px}
.ns-kcal-line b{color:var(--fg);font-size:15px}
.ns-setgoal{display:inline-flex;align-items:center;gap:5px;margin-left:8px;background:var(--accent);color:var(--on-accent);border:none;
  font:inherit;font-size:12px;font-weight:600;padding:5px 14px;border-radius:14px;cursor:pointer;vertical-align:middle}
.ns-setgoal:active{opacity:.85}
.ns-setgoal svg{width:13px;height:13px}
/* Once goals exist the button is a subtle edit affordance, not a shouting accent CTA. */
.ns-setgoal.ghost{background:var(--card2);color:var(--accent);padding:5px 12px}
.goals-clear{display:block;width:100%;margin:4px 0 2px;background:none;border:none;
  color:var(--danger);font:inherit;font-size:13px;font-weight:600;cursor:pointer;padding:8px}
.goals-clear:active{opacity:.7}
.nutri-list{display:flex;flex-direction:column;gap:0;padding-top:4px;padding-bottom:4px}
.nutri-row{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:9px 0;border-top:1px solid var(--line)}
.nutri-row:first-child{border-top:none}
.nutri-info{display:flex;flex-direction:column;min-width:0}
.nutri-info b{font-size:14px;font-weight:600}
.nutri-sub{font-size:12px;color:var(--muted)}
.iconbtn-sm{flex:none;width:38px;height:38px;display:flex;align-items:center;justify-content:center;background:none;border:none;color:var(--danger);cursor:pointer;border-radius:9px}
.iconbtn-sm svg{width:19px;height:19px}
.iconbtn-sm:active{background:var(--card2)}
.nutri-row-actions{display:flex;align-items:center;gap:2px;flex:none}
.nutri-row-actions .nutri-edit{color:var(--accent)}
.nutri-row-actions .nutri-edit svg{width:16px;height:16px}
.goals-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin:8px 0 4px}
.food-results{max-height:240px;overflow-y:auto;margin:8px 0}
.food-opt{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:10px 8px;border-bottom:1px solid var(--line);cursor:pointer;font-size:14px}
.food-opt:last-child{border-bottom:none}
.food-kcal{color:var(--muted);font-size:12px;white-space:nowrap}
.food-per{opacity:.7;margin-left:4px}
.food-chosen-name{font-weight:700;margin:8px 0 4px}
.food-macros-preview{display:flex;gap:12px;color:var(--muted);font-size:13px;margin-top:8px;justify-content:center}

/* ===== programs ===== */
.pg-list{margin-top:12px}
.pg-week{margin-bottom:10px}
.pg-week-sum{font-weight:700;font-size:15px;cursor:pointer;padding:4px 0}
.pg-day{border-top:1px solid var(--line);padding:10px 0}
.pg-day-head{display:flex;align-items:center;justify-content:space-between;font-size:14px;margin-bottom:6px}
.pg-done{color:var(--green);font-weight:800}
.pg-ex{font-size:13px;color:var(--muted);line-height:1.6;margin-bottom:8px}
.pg-ex-sets{color:var(--fg);font-weight:600}

/* ===== nutrition: meals, recent, scanner, trend ===== */
.food-search-row{display:flex;gap:8px;align-items:center;margin-bottom:8px}
.food-scan-btn{flex:none;width:46px;height:46px;border:1px solid var(--line);border-radius:12px;color:var(--fg)}
.food-scan-btn svg{width:22px;height:22px}
.meal-chips{display:flex;gap:6px;margin:6px 0 12px;flex-wrap:wrap}
.meal-chip{flex:1;min-width:0;padding:8px 6px;border:1px solid var(--line);border-radius:10px;background:var(--card2);
  color:var(--muted);font:inherit;font-size:13px;cursor:pointer;white-space:nowrap}
.meal-chip.active{background:var(--accent);border-color:var(--accent);color:var(--on-accent);font-weight:600}
.food-recent{margin-bottom:4px}
.recent-head{font-size:12px;color:var(--muted);text-transform:uppercase;letter-spacing:.04em;margin:4px 0 8px}
.recent-chips{display:flex;flex-wrap:wrap;gap:6px}
.recent-chip{padding:7px 12px;border:1px solid var(--line);border-radius:16px;background:var(--card2);
  color:var(--fg);font:inherit;font-size:13px;cursor:pointer}
.recent-chip:active{background:var(--accent);color:var(--on-accent)}
.meal-group{padding-top:8px;padding-bottom:8px;margin-bottom:10px}
.meal-head{display:flex;justify-content:space-between;align-items:center;font-weight:700;font-size:14px;
  padding-bottom:6px;margin-bottom:2px;border-bottom:1px solid var(--line)}
.meal-sub{color:var(--muted);font-weight:600;font-size:13px}
.nutri-trend canvas{height:150px!important}
/* barcode scanner overlay */
.scanner{position:fixed;inset:0;z-index:80;background:#000;display:flex;flex-direction:column;align-items:center;justify-content:center}
.scanner video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.scan-frame{position:relative;z-index:1;width:78%;max-width:340px;height:170px;border:3px solid #fff;border-radius:16px;box-shadow:0 0 0 100vmax rgba(0,0,0,.45)}
.scan-hint{position:relative;z-index:1;color:#fff;margin-top:24px;font-size:15px;text-align:center;padding:0 24px;text-shadow:0 1px 3px rgba(0,0,0,.6)}
.scan-cancel{position:absolute;bottom:calc(32px + var(--safe-bot,0px));z-index:2;background:rgba(255,255,255,.15);color:#fff;border:1px solid rgba(255,255,255,.3)}

/* ===== nutrition goals: auto-calc section ===== */
.goals-card{max-height:88vh;overflow-y:auto}
.goals-calc{background:var(--card2);border:1px solid var(--line);border-radius:12px;padding:12px;margin:6px 0 14px}
/* inputs share the panel's bg, so give them contrast + a clear border to read as fields */
.goals-calc .search-sm,.goals-calc .cdd-btn{background:var(--bg);border:1px solid var(--line)}
.calc-head{font-size:12px;color:var(--muted);text-transform:uppercase;letter-spacing:.04em;margin-bottom:10px;font-weight:600}
.calc-manual{text-align:center;font-size:12px;color:var(--muted);margin-top:12px}
.calc-dd-wrap{position:relative}

/* ===== nutrition: color-coded macro pills per food row ===== */
.macro-pills{display:flex;gap:6px;margin-top:5px}
.mpill{font-size:11px;font-weight:700;padding:2px 8px;border-radius:7px;line-height:1.5;white-space:nowrap}
.mpill.mp-p{color:#3b8fe6;background:rgba(77,163,255,.15)}
.mpill.mp-c{color:#d2891f;background:rgba(255,180,84,.18)}
.mpill.mp-f{color:#e8657d;background:rgba(255,122,144,.16)}
[data-theme="dark"] .mpill.mp-p{color:#7bbcff}
[data-theme="dark"] .mpill.mp-c{color:#ffc174}
[data-theme="dark"] .mpill.mp-f{color:#ff9aab}

/* ===== info icon (RPE hint) ===== */
.sets-label{display:flex;align-items:center;gap:8px}
.info-ico{width:15px;height:15px;border-radius:50%;border:1.3px solid var(--muted);color:var(--muted);
  background:none;font-size:9px;font-weight:700;font-style:italic;line-height:1;cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center;padding:0;margin-left:8px;flex:none}
.info-ico:active{background:var(--accent);color:var(--on-accent);border-color:var(--accent)}

/* ===== exercise completion (template workouts): tap name to toggle, green accent + corner badge ===== */
.ex-block{position:relative}
.ex-block .ex-name[data-done]{cursor:pointer}
.ex-done-badge{position:absolute;bottom:0;right:0;display:none;
  background:var(--green);color:#06251a;font-size:9px;font-weight:800;letter-spacing:.07em;
  padding:3px 8px;border-radius:10px 0 var(--radius) 0}
/* filled bookmark once the workout has been saved as a template */
#session-template.saved{color:var(--accent)}
#session-template.saved svg{fill:var(--accent)}
/* "done" = badge only; keep the muscle-colour accent and the normal name colour */
.ex-block.ex-done{padding-bottom:28px}
.ex-block.ex-done .ex-done-badge{display:block}
/* Completed workout: every data-editing control is locked (updateCompleteButton toggles this
   class). Read-only ones — the ⓘ info button, gallery viewing, share — stay fully live, and
   the name keeps normal opacity (it's the exercise title, only its mark-done tap is off). */
.sess-locked .ex-actions [data-edit],.sess-locked .ex-actions [data-del],
.sess-locked .ex-actions [data-ss],.sess-locked .drag-handle,
.sess-locked .sess-cam-btn{opacity:.35;pointer-events:none}
.sess-locked .ex-name[data-done]{pointer-events:none}

/* Progress photo comparison (before/after drag slider) */
.pc-modal-card{max-width:420px}
.pc-pickers{display:flex;gap:10px;margin-bottom:14px}
.pc-picker{flex:1;min-width:0}
.pc-picker label{display:block;font-size:12px;color:var(--muted);margin-bottom:5px}
.pc-slider{position:relative;width:100%;aspect-ratio:3/4;border-radius:var(--radius);
  overflow:hidden;background:var(--card2);touch-action:none;user-select:none;cursor:ew-resize}
.pc-img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block;pointer-events:none}
/* Sized identically to .pc-slider (not shrunk) — clip-path crops it, so the "after" image is
   never stretched/distorted by a shrinking wrapper width, only revealed up to the handle. */
.pc-after-clip{position:absolute;inset:0;clip-path:inset(0 50% 0 0)}
.pc-handle{position:absolute;top:0;bottom:0;left:50%;width:0;
  border-left:2px solid #fff;transform:translateX(-1px);pointer-events:none}
.pc-handle svg{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
  width:30px;height:30px;padding:5px;border-radius:50%;background:#fff;color:#111;
  box-shadow:0 2px 8px rgba(0,0,0,.35)}
.pc-tag{position:absolute;bottom:10px;font-size:11px;font-weight:700;color:#fff;
  background:rgba(0,0,0,.55);padding:3px 9px;border-radius:999px;pointer-events:none}
.pc-tag-before{left:10px}
.pc-tag-after{right:10px}
.pc-delta{text-align:center;margin-top:12px;font-size:15px;font-weight:700;color:var(--accent)}
.pc-delta.hidden{display:none}

/* Offline / pending-sync banner (core.js's offline mutation queue) */
#offline-banner{position:fixed;top:0;left:0;right:0;z-index:80;
  padding:calc(6px + var(--safe-top)) 14px 6px;text-align:center;
  font-size:12.5px;font-weight:600;color:#3a2b06;background:#ffcc4d;
  box-shadow:0 1px 6px rgba(0,0,0,.2)}
#offline-banner.hidden{display:none}

/* Achievement unlock modal — reuses .pr-card's layout and coach-bounce timing so a badge
   unlock lands with the same weight as a PR (PRODUCT.md principle 5: "show the effort"). */
.ach-card-modal{text-align:center}
.ach-pop-ico{width:96px;height:96px;margin:4px auto 14px;border-radius:50%;
  background:color-mix(in srgb,var(--accent) 14%,transparent);color:var(--accent);
  display:flex;align-items:center;justify-content:center;
  animation:coachBounce .6s cubic-bezier(.2,.8,.2,1) both}
.ach-pop-ico svg{width:52px;height:52px}
.ach-pop-target{font-size:32px;font-weight:800;letter-spacing:-.5px;line-height:1.2;
  color:var(--fg);font-variant-numeric:tabular-nums}
