/* Self-hosted instead of fonts.googleapis.com/fonts.gstatic.com: one variable-weight
   file per subset (400-700 in a single woff2), same two files Google's CSS pointed to,
   just served from this app's own origin so a blocked/slow Google domain can no longer
   delay or break the page. */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/inter-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/fonts/inter-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/fonts/inter-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/fonts/inter-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/inter-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/fonts/inter-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/fonts/inter-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/fonts/inter-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  color-scheme: light dark;
  --bg: #f5f3ef;
  --card: #ffffff;
  --card-2: #ece9e1;
  --card-rgb: 255,255,255;
  --text: #23221e;
  --text-2: #86847c;
  --text-3: #b5b2a8;
  --separator: #e3e0d8;
  --border: #e3e0d8;
  --accent: #c1633f;
  --accent-rgb: 193,99,63;
  --accent-strong: #a84f2f;
  --danger: #d5455f;
  --warn: #ff9500;
  --good: #17a37a;
  --overdue: #7a2419;
  --radius: 18px;
  --radius-sm: 12px;
  --shadow: 0 1px 2px rgba(32,28,52,0.05), 0 10px 28px rgba(32,28,52,0.07);
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  /* Shared motion language: one decelerate curve for anything sliding/fading in,
     one overshoot curve for anything that should feel like it has a bit of spring. */
  --ease-out: cubic-bezier(.22,1,.36,1);
  --ease-spring: cubic-bezier(.34,1.56,.64,1);
}

:root[data-theme="dark"] {
  --bg: #1c1b18;
  --card: #23221e;
  --card-2: #39372f;
  --card-rgb: 35,34,30;
  --text: #f2f0ea;
  --text-2: #a6a399;
  --text-3: #726f64;
  --separator: #39372f;
  --border: #39372f;
  --accent: #d9772e;
  --accent-rgb: 217,119,46;
  --accent-strong: #e8903f;
  --danger: #f0748c;
  --good: #4fd6a8;
  --shadow: 0 1px 2px rgba(0,0,0,0.25), 0 10px 28px rgba(0,0,0,0.35);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #1c1b18;
    --card: #23221e;
    --card-2: #39372f;
    --card-rgb: 35,34,30;
    --text: #f2f0ea;
    --text-2: #a6a399;
    --text-3: #726f64;
    --separator: #39372f;
    --border: #39372f;
    --accent: #d9772e;
    --accent-rgb: 217,119,46;
    --accent-strong: #e8903f;
    --danger: #f0748c;
    --good: #4fd6a8;
    --shadow: 0 1px 2px rgba(0,0,0,0.25), 0 10px 28px rgba(0,0,0,0.35);
  }
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

html, body {
  height: 100%;
  margin: 0;
}

/* no system scrollbar anywhere — scroll still works, just without the visible track */
html, body { scrollbar-width: none; }
html::-webkit-scrollbar, body::-webkit-scrollbar { display: none; }

body {
  font-family: "Inter", -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto, sans-serif;
  background: var(--bg);
  color: var(--text);
  overscroll-behavior-y: none;
}

#app {
  max-width: 640px;
  margin: 0 auto;
  padding-bottom: calc(72px + var(--safe-bottom));
  min-height: 100vh;
}

.topbar {
  position: sticky;
  top: 0;
  z-index: 8;
  padding: calc(12px + var(--safe-top)) 20px 8px;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  background: rgba(var(--card-rgb), 0);
  transition: background .25s ease, padding .25s cubic-bezier(0.32,0.72,0,1), border-color .25s ease;
  border-bottom: 1px solid transparent;
  /* own compositing layer: without this, Safari repaints the blurred backdrop
     against the whole scrolling page behind it on every frame, which is what
     made the sticky header stutter on long scrolls (Month view especially). */
  transform: translateZ(0);
  will-change: transform;
}
.topbar.scrolled {
  /* Solid background instead of backdrop-filter: blur — WebKit/Safari (the engine behind
     the Mac app's WKWebView) recomposites a blurred backdrop every scroll frame, which is
     the most common cause of sticky-header scroll jank on that engine specifically. A
     near-opaque solid color reads almost identically without that per-frame cost. See
     TZ_FIXES3.md §10 — could not be confirmed with a profiler trace against the real
     WKWebView from here (only reproducible in Chromium, which showed 0 jank either way,
     i.e. this environment can't prove or disprove it); verify on the actual Mac .app. */
  background: rgba(var(--card-rgb), 0.97);
  border-bottom-color: var(--separator);
  padding-top: calc(8px + var(--safe-top));
  padding-bottom: 8px;
}

.topbar h1 {
  font-family: inherit;
  font-size: 30px;
  font-weight: 700;
  margin: 0;
  letter-spacing: -0.01em;
  line-height: 38px;
  transform-origin: left center;
  /* transform:scale instead of animating font-size directly — scaling a rasterized glyph
     run is GPU-compositor-only, while interpolating font-size forces the browser to
     re-shape and re-measure the text on every frame (TZ_FIXES4.md §6, причина №1). Only
     line-height still changes here, a much cheaper layout-only box-height adjustment
     that doesn't touch text shaping. */
  transition: transform .25s cubic-bezier(0.32,0.72,0,1), line-height .25s cubic-bezier(0.32,0.72,0,1);
}
.topbar.scrolled h1 { transform: scale(0.625); line-height: 24px; } /* 20/32 = 0.625 */

.icon-btn {
  background: none;
  border: none;
  color: var(--accent);
  padding: 6px;
  cursor: pointer;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform .1s ease;
}
.icon-btn:active { transform: scale(0.96); }
.icon-btn:disabled { opacity: 0.5; }
.icon-btn.spinning svg { animation: spin 0.8s linear infinite; }
@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }

.screen { display: none; padding: 4px 16px 24px; }
.screen.active { display: block; }
.screen.active.slide-right { animation: screenInRight .32s var(--ease-out); }
.screen.active.slide-left { animation: screenInLeft .32s var(--ease-out); }

@keyframes screenInRight { from { opacity: 0; transform: translateX(10px); } to { opacity: 1; transform: none; } }
@keyframes screenInLeft { from { opacity: 0; transform: translateX(-10px); } to { opacity: 1; transform: none; } }

.card {
  background: var(--card);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  margin-bottom: 16px;
  overflow: hidden;
}

.card-header {
  padding: 16px 16px 6px;
  font-size: 13px;
  font-weight: 640;
  color: var(--text-2);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

.list-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--separator);
  font-size: 17px;
  transition: transform .12s var(--ease-out);
}
.list-row:last-child { border-bottom: none; }
.list-row:active { transform: scale(0.985); }

/* Newly-created row (task/goal just added) eases into the list instead of appearing
   already-there — see App.justAdded in ui.js, which marks only the one new row. */
.row-enter { animation: rowEnter .32s var(--ease-out); }
@keyframes rowEnter { from { opacity: 0; transform: translateY(-6px) scale(.98); } to { opacity: 1; transform: none; } }

.row-later { opacity: 0.5; }

.later-toggle { color: var(--text-3); flex-shrink: 0; padding: 4px; cursor: pointer; }
.later-toggle.active { color: var(--accent); }

.sphere-group-header { display: flex; align-items: center; gap: 8px; padding: 12px 16px 4px; }
.sphere-group-header span:last-child { font-size: 12px; font-weight: 700; color: var(--text-2); text-transform: uppercase; letter-spacing: .03em; }
.sphere-group-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }

.week-goal-line { display: flex; align-items: center; gap: 7px; padding: 2px 16px 10px; color: var(--text-3); }
.week-goal-text {
  font-size: 13px; color: var(--text-2); outline: none; flex: 1; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.week-goal-text:focus { white-space: normal; color: var(--text); }
.week-goal-text:empty::before { content: attr(data-placeholder); color: var(--text-3); }

.pending-inline { flex: none; font-size: 12px; color: var(--text-3); font-variant-numeric: tabular-nums; }

.sphere-honeycomb { display: block; width: 100%; max-width: 300px; margin: 8px auto; filter: saturate(1.6) contrast(1.08); }
.hex-cell { cursor: pointer; }
.hex-level, .hex-name { pointer-events: none; }
.hex-level { font-size: 13px; font-weight: 700; }
.hex-name { font-size: 7px; font-weight: 600; }
.hex-legend { display: flex; gap: 16px; justify-content: center; padding: 2px 16px 12px; }
.hex-legend-item { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-2); }
.hex-legend-swatch { width: 13px; height: 13px; border-radius: 3px; }
.hex-legend-up { border: 2.5px solid #5DCAA5; }

.checkbox {
  width: 25px;
  height: 25px;
  border-radius: 50%;
  border: 2px solid var(--text-3);
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  font-size: 14px;
  color: transparent;
  transition: transform .1s ease, background .15s ease, border-color .15s ease;
}
.checkbox.done {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--bg);
}
.checkbox.missed {
  border-color: var(--danger);
  color: var(--danger);
  opacity: 0.8;
}
.checkbox:active { transform: scale(0.96); }
.checkbox.pop { animation: checkPop .38s var(--ease-out); }
@keyframes checkPop { 0% { transform: scale(1); } 35% { transform: scale(1.22); } 60% { transform: scale(0.94); } 100% { transform: scale(1); } }

.row-title { flex: 1; font-size: 17px; min-width: 0; }
.row-title.done { color: var(--text-2); text-decoration: line-through; }

/* ---- drag-and-drop reordering (tasks/habits/spheres/goals) ---- */
.drag-handle {
  display: flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; flex-shrink: 0;
  color: var(--text-3); cursor: grab;
  touch-action: none; /* let the handle own vertical drags instead of the page scroller */
  opacity: 0; pointer-events: none; transition: opacity .15s ease;
}
[data-list].handles-visible .drag-handle { opacity: 1; pointer-events: auto; }
.drag-handle:active { cursor: grabbing; }
[data-drag-id] { transition: transform .15s ease; }
[data-drag-id].dragging {
  transition: none;
  position: relative;
  z-index: 5;
  opacity: 0.92;
  background: var(--card);
  box-shadow: 0 6px 18px rgba(0,0,0,0.18);
  border-radius: 10px;
}

/* small colored dot used to indicate a sphere, instead of a colored chip */
.sphere-dot {
  width: 9px; height: 9px; border-radius: 50%;
  flex-shrink: 0; display: inline-block;
}

.chip {
  font-size: 12px;
  padding: 3px 9px;
  border-radius: 20px;
  background: var(--card-2);
  color: var(--text-2);
  white-space: nowrap;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
}

.empty-hint {
  padding: 24px 16px;
  text-align: center;
  color: var(--text-3);
  font-size: 15px;
}

.banner {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 16px; margin-bottom: 16px;
  background: var(--card); border-radius: var(--radius);
  font-size: 14px; color: var(--text-2);
}

.segment {
  display: flex;
  background: var(--card-2);
  border-radius: 9px;
  padding: 2px;
  margin: 8px 16px 16px;
  gap: 2px;
}
.segment button {
  flex: 1;
  border: none;
  background: transparent;
  padding: 6px 0;
  font-size: 13px;
  font-weight: 640;
  color: var(--text);
  border-radius: 7px;
  cursor: pointer;
  transition: transform .1s ease;
}
.segment button:active { transform: scale(0.96); }
.segment button.active {
  background: var(--card);
}

.tabbar {
  position: fixed;
  bottom: 0; left: 0; right: 0;
  display: flex;
  /* solid, no blur — same reasoning as .topbar.scrolled above */
  background: rgba(var(--card-rgb), 0.97);
  border-top: 1px solid var(--separator);
  padding-bottom: var(--safe-bottom);
  z-index: 10;
  /* own compositing layer, same reasoning as .topbar — this bar is blurred
     unconditionally on every screen, so it's on the critical path for scroll jank too */
  transform: translateZ(0);
  will-change: transform;
}
.tab-item {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 8px 0 6px;
  background: none;
  border: none;
  color: var(--text-3);
  font-size: 10px;
  cursor: pointer;
  transition: transform .1s ease;
}
.tab-item:active { transform: scale(0.96); }
.tab-item .tab-icon { display: flex; }
.tab-item.active { color: var(--accent); }

.progress-track {
  height: 6px;
  border-radius: 3px;
  background: var(--card-2);
  overflow: hidden;
}
.progress-fill { height: 100%; background: linear-gradient(90deg, var(--accent), var(--accent-strong)); border-radius: 3px; transition: width .6s var(--ease-out); }

.stat-row { display:flex; padding: 12px 16px; gap: 16px; }
.stat { flex:1; text-align:center; }
.stat .num { font-size: 22px; font-weight: 680; font-variant-numeric: tabular-nums; }
.stat .label { font-size: 12px; color: var(--text-2); margin-top: 2px; }

/* ---- Spheres: 28-day activity bar chart (radar removed) ---- */
.sphere-chart-head { padding:15px 16px 4px; font-size:12px; font-weight:700; color:var(--text-2); text-transform:uppercase; letter-spacing:.03em; }
.sphere-chart-summary { padding:2px 16px 12px; font-size:13px; color:var(--text-2); line-height:1.55; border-bottom:1px solid var(--separator); }
.sphere-chart-summary b { color:var(--text); font-weight:700; }
.sphere-idle-line { color:var(--text-3); }

.sphere-bar-row { padding:13px 16px; border-bottom:1px solid var(--separator); cursor:pointer; transition: background .12s ease; }
.sphere-bar-row:last-of-type { border-bottom:none; }
.sphere-bar-row:active { background:var(--card-2); }
.sphere-bar-row.idle { padding:10px 16px; }
.sphere-bar-row.idle .sphere-bar-name { font-weight:600; color:var(--text-2); }
.sphere-bar-head { display:flex; align-items:center; gap:9px; }
.sphere-bar-dot { width:10px; height:10px; border-radius:3px; flex-shrink:0; }
.sphere-bar-row.idle .sphere-bar-dot { opacity:0.45; }
.sphere-bar-name { flex:1; min-width:0; font-size:15px; font-weight:640; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.sphere-bar-up { flex-shrink:0; display:inline-flex; align-items:center; gap:3px; font-size:10.5px; font-weight:700; color:var(--accent); background:rgba(var(--accent-rgb),0.14); padding:2px 8px; border-radius:11px; }
.sphere-bar-count { flex-shrink:0; font-size:15px; font-weight:680; font-variant-numeric:tabular-nums; }
.sphere-bar-lvl { flex-shrink:0; font-size:11px; color:var(--text-3); font-variant-numeric:tabular-nums; }
.sphere-bar-track { height:8px; border-radius:4px; background:var(--card-2); overflow:hidden; margin-top:9px; }
.sphere-bar-fill { height:100%; border-radius:4px; transition: width .3s ease; }

/* ---- Settings: local snapshot list ---- */
.snapshot-row { display:flex; align-items:center; gap:12px; padding:9px 0; border-bottom:1px solid var(--separator); }
.snapshot-row:last-child { border-bottom:none; }
.snapshot-info { flex:1; min-width:0; }
.snapshot-date { font-size:14px; font-weight:640; font-variant-numeric:tabular-nums; }
.snapshot-counts { font-size:11.5px; color:var(--text-3); margin-top:2px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.snapshot-btn {
  flex:none; padding:7px 14px; border:none; border-radius:9px;
  background:var(--card-2); color:var(--accent); font:inherit; font-size:13px; font-weight:640;
  cursor:pointer; white-space:nowrap;
}
.snapshot-btn:active { transform:scale(0.96); }

/* ---- transient toast (sphere level-ups) ---- */
.app-toast {
  position: fixed; left:50%; bottom: calc(74px + var(--safe-bottom));
  transform: translate(-50%, 12px) scale(.9);
  background: var(--text); color: var(--bg);
  font-size: 13.5px; font-weight: 640; line-height: 1.3;
  padding: 10px 16px; border-radius: 13px; max-width: 80vw; text-align: center;
  z-index: 200; opacity: 0; pointer-events: none;
  box-shadow: 0 10px 34px rgba(0,0,0,0.28);
  transition: opacity .22s var(--ease-out), transform .32s var(--ease-spring);
}
.app-toast.visible { opacity: 1; transform: translate(-50%, 0) scale(1); }

.form-field { padding: 12px 16px; border-bottom: 1px solid var(--separator); }
.form-field:last-child { border-bottom:none; }
.form-field label { display:block; font-size:12px; color:var(--text-2); margin-bottom:4px; }
.form-field input[type=text], .form-field input[type=date], .form-field select, .form-field textarea {
  width:100%; border:none; background:transparent; font-size:16px; color:var(--text); outline:none; font-family: inherit;
}
.form-field textarea { resize: vertical; min-height: 60px; }
.hint { font-size: 12px; color: var(--text-3); margin-top: 6px; line-height: 1.4; }
.hint code { font-size: 11px; background: var(--card-2); padding: 1px 4px; border-radius: 4px; }

.btn {
  display:block; width:100%; padding:14px; text-align:center;
  border-radius: 12px; border:none; font-size:16px; font-weight:640; cursor:pointer;
  transition: transform .1s ease;
}
.btn:active { transform: scale(0.96); }
.btn:disabled { opacity: 0.4; pointer-events: none; }
.btn-primary { background: var(--accent); color: var(--bg); }
.btn-secondary { background: var(--card-2); color: var(--text); }
.btn-danger { background: transparent; color: var(--danger); }

.modal-overlay {
  position: fixed; inset:0; background: rgba(0,0,0,0);
  display:none; align-items:flex-end; justify-content:center; z-index: 100;
  transition: background .2s cubic-bezier(0.4,0,1,1);
}
.modal-overlay.open { display:flex; }
.modal-overlay.open.visible { background: rgba(0,0,0,0.4); transition: background .22s cubic-bezier(0.32,0.72,0,1); }
.modal-sheet {
  background: var(--bg);
  width:100%; max-width:640px;
  border-radius: 20px 20px 0 0;
  padding: 8px 0 calc(16px + var(--safe-bottom));
  max-height: 88vh;
  overflow-y: auto;
  animation: sheetup .32s var(--ease-out);
}
.modal-sheet.leaving { animation: sheetdown .22s cubic-bezier(0.4,0,1,1) forwards; }
@keyframes sheetup { from { transform: translateY(40px) scale(.98); opacity:0 } to { transform:none; opacity:1 } }
@keyframes sheetdown { from { transform: translateY(0); opacity:1 } to { transform: translateY(40px); opacity:0 } }
.modal-header {
  display:flex; justify-content:space-between; align-items:center;
  padding: 10px 16px;
}
.modal-header h2 { font-size:17px; margin:0; }
.modal-body { padding: 0 16px; }

/* shared prev/next month (or week) header — plans picker, habit detail calendar */
.cal-nav { display:flex; align-items:center; gap:8px; padding: 4px 0 12px; font-weight:600; font-size:14px; }
.cal-nav > div { flex:1; text-align:center; }
.modal-body .cal-nav { padding-top:12px; }

.gratitude-q { padding: 12px 16px; border-bottom: 1px solid var(--separator); }
.gratitude-q:last-child{border-bottom:none;}
.gratitude-q label { display:block; font-size:14px; color:var(--text-2); margin-bottom:6px; }
.gratitude-input {
  width:100%; display:block; box-sizing:border-box;
  border:1px solid var(--separator); border-radius:var(--radius-sm);
  padding:10px 12px; background:var(--card-2); color:var(--text);
  font-size:15px; line-height:1.4; font:inherit;
  resize:none; overflow:hidden; min-height:62px;
  outline:none; -webkit-appearance:none;
  transition: border-color .15s ease, box-shadow .15s ease;
  field-sizing: content;
}
.gratitude-input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.15);
}

.life-widget {
  display:flex; align-items:center; justify-content:space-between;
  padding: 10px 16px; font-size: 13px; color: var(--text-2);
}
.life-widget .num { color: var(--text); font-weight:680; font-variant-numeric: tabular-nums; }

.week-bar-row { display:flex; align-items:center; gap:10px; padding:10px 16px; }
.week-bar-row .day-label { width:34px; font-size:13px; color:var(--text-2); }


/* Taken clean out of document flow — a height reservation (even a fixed one) still only
   works if nothing else ever changes; this instead makes it structurally impossible for
   the sync line to move anything else, ever. Absolutely positioned against .topbar
   (which is already position:sticky, so it's a valid containing block) and pinned to
   its bottom edge via top:100%. It now overlays the top of whatever's underneath while
   visible instead of reserving space — an intentional trade for a zero-shift guarantee. */
.sync-status {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 9;
  box-sizing: border-box;
  font-size: 11px;
  line-height: 15px;
  color: var(--text-2);
  text-align: left;
  white-space: pre-line;
  padding: 5px 12px 7px;
  background: rgba(var(--card-rgb), .97);
  box-shadow: 0 3px 8px rgba(0,0,0,.08);
  pointer-events: none;
}

a { color: var(--accent); }

.swipe-actions { display:flex; }
.link-btn { background:none; border:none; color:var(--accent); font-size:15px; padding:6px 4px; cursor:pointer; }
.link-btn.danger { color: var(--danger); }

/* ---- tap feedback: light scale-down on interactive elements, no cursor-tracking motion ---- */
.tap { transition: transform .1s ease; }
.tap:active { transform: scale(0.96); }

/* ---- life widget (compact, secondary on Today screen) ---- */
.life-card { padding: 12px 16px; cursor: pointer; transition: transform .1s ease; }
.life-card:active { transform: scale(0.98); }
.life-card .life-top { display:flex; justify-content:space-between; align-items:baseline; margin-bottom:8px; }
.life-card .life-label { font-size: 12px; color: var(--text-2); }
.life-card .life-num { font-size: 17px; font-weight: 680; font-variant-numeric: tabular-nums; }
.life-bricks { display: flex; gap: 2px; height: 22px; margin: 2px 0 8px; }
.life-seg { flex: 1; min-width: 2px; border-radius: 2px; background: var(--card-2); }
.life-seg.lived { background: var(--accent); }
.life-seg.current { background: linear-gradient(to top, var(--accent) var(--fill, 0%), var(--card-2) var(--fill, 0%)); }
.life-bottom { display: flex; align-items: baseline; justify-content: space-between; }
.life-remaining { font-size: 15px; font-weight: 680; font-variant-numeric: tabular-nums; }
.life-remaining-label { font-size: 12px; color: var(--text-2); font-weight: 400; }
.life-year-pct { font-size: 12px; color: var(--text-2); font-variant-numeric: tabular-nums; }

/* ---- plans: week strip + date label ---- */
.plans-nav { padding-bottom: 6px; }
.plans-date-btn {
  flex: 1; min-width: 0; background: none; border: 0; color: var(--text);
  font: inherit; font-weight: 640; font-size: 15px; cursor: pointer; padding: 6px 4px;
  border-radius: 9px; transition: background .12s ease;
}
.plans-date-btn:active { background: var(--card-2); }
.week-strip { position:relative; display:flex; gap:4px; padding: 0 8px 14px; }
/* Positioned/animated from JS (positionWeekPill in ui.js) — replaces a flat per-button
   "selected" background with one element that physically slides to the tapped day. */
.wk-sel-pill { position:absolute; top:0; left:0; background: var(--card); border-radius:12px; z-index:0; pointer-events:none; transition: transform .32s var(--ease-out); }
.wk-sel-pill.snap { transition: none; }
.wk-day {
  position:relative; z-index:1;
  flex: 1 1 0; min-width: 0; display:flex; flex-direction:column; align-items:center; gap:5px;
  background:none; border:0; padding:6px 0; cursor:pointer; color: var(--text);
  border-radius: 12px; transition: transform .1s ease;
}
.wk-day:active { transform: scale(0.96); }
.wk-dow { font-size:10px; text-transform:uppercase; letter-spacing:.02em; color: var(--text-3); }
.wk-day.sel .wk-dow { color: var(--accent); font-weight:700; }
.wk-day.today .ring { box-shadow: 0 0 0 2px var(--accent); }

/* selected day inside the month picker / habit calendar */
.cal-cell.sel { box-shadow: inset 0 0 0 2.5px var(--accent); font-weight: 680; }
.cal-cell.on { background: var(--accent); color:#fff; }
.cal-cell.off { background: transparent; box-shadow: inset 0 0 0 2px var(--danger); color: var(--danger); }
.cal-cell.future { opacity: 0.3; pointer-events: none; }

/* ---- donut ring (pure CSS conic-gradient) ---- */
.ring { width:34px; height:34px; border-radius:50%; display:flex; align-items:center; justify-content:center;
  background: conic-gradient(var(--accent) calc(var(--pct, 0) * 3.6deg), var(--card-2) 0deg); flex-shrink:0; }
.ring-inner { width:26px; height:26px; border-radius:50%; background:var(--card); display:flex; align-items:center; justify-content:center; font-size:11px; font-weight:640; font-variant-numeric: tabular-nums; }
.ring-lg { width:46px; height:46px; }
.ring-lg .ring-inner { width:36px; height:36px; font-size:13px; }

/* ---- month calendar grid ---- */
.cal-grid { display:grid; grid-template-columns: repeat(7, 1fr); gap:4px; padding: 10px 16px 16px; }
.cal-dow { text-align:center; font-size:11px; color:var(--text-3); padding-bottom:4px; }
.cal-cell {
  aspect-ratio: 1; border-radius:8px; display:flex; align-items:center; justify-content:center;
  font-size:13px; cursor:pointer; background: var(--card-2); color: var(--text);
  transition: transform .1s ease;
}
.cal-cell:active { transform: scale(0.94); }
.cal-cell.empty { visibility:hidden; cursor:default; }
.cal-cell.today { box-shadow: inset 0 0 0 2.5px var(--accent); color: var(--accent); font-weight: 680; }

/* ---- habits: one-off habit rows (no weekly grid — periodic, shown with their bounds) ---- */
.habit-row { padding: 12px 16px; border-bottom:1px solid var(--separator); }
.habit-row:last-child { border-bottom:none; }
.habit-row-top { display:flex; align-items:center; gap:12px; }
.streak-badge { display:inline-flex; align-items:center; gap:3px; font-size:12px; color: var(--text-2); font-variant-numeric: tabular-nums; }
.streak-badge.small { font-size:10px; }
.freeze-icon { display:inline-flex; color: var(--accent); opacity: 0.9; }
.freeze-icon.used { color: var(--text-3); opacity: 0.35; }
.habit-period-label { font-size:12px; color: var(--text-3); margin-top:6px; margin-left:37px; }

.habit-week-nav {
  display:flex; align-items:center; justify-content:center; gap:12px;
  padding: 10px 16px 4px; font-size:12px; color: var(--text-2);
}
.habit-week-nav button {
  width:26px; height:26px; flex-shrink:0; border:0; border-radius:7px;
  background: var(--card-2); color: var(--text-2); cursor:pointer;
  display:inline-flex; align-items:center; justify-content:center;
}
.habit-week-nav button:disabled { opacity:.3; cursor:default; }
.habit-week-nav .wk-label { min-width:150px; text-align:center; font-variant-numeric: tabular-nums; }

/* ---- habits: table-tracker (all daily habits x all week days in one grid) ---- */
.ht-row { display:flex; align-items:center; gap:6px; padding:8px 16px; border-bottom:1px solid var(--separator); }
.ht-row:last-child { border-bottom:none; }
.ht-row.ht-header { padding-top:4px; padding-bottom:6px; }
.ht-label { flex:1 1 92px; min-width:0; max-width:150px; display:flex; flex-direction:column; align-items:flex-start; gap:2px; cursor:pointer; }
.ht-name {
  font-size:13.5px; line-height:1.25; max-width:100%; overflow-wrap:anywhere;
  display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:2; overflow:hidden;
}
.ht-cells { display:flex; flex:none; width:214px; gap:3px; }
.ht-cell-head { flex:1; max-width:28px; text-align:center; font-size:10px; text-transform:uppercase; color: var(--text-3); }
.ht-cell-head.today { color: var(--accent); font-weight: 680; }
.ht-cell {
  flex:1; max-width:28px; aspect-ratio:1; border-radius:5px; box-sizing:border-box;
  background: var(--card-2); color: transparent;
  display:flex; align-items:center; justify-content:center;
  cursor:pointer; border:none; transition: transform .1s ease;
}
.ht-cell:active { transform: scale(0.88); }
.ht-cell.on { color:#fff; }
/* "missed" reads as a quieter, slightly darker empty cell with a faint mark —
   not an alarm-red X, which got overwhelming once most habits had a few misses. */
.ht-cell.off { background: var(--border); color: var(--text-3); }
.ht-cell svg { width:10px; height:10px; }
.ht-cell.today { outline: 1.5px solid var(--accent); outline-offset: 1px; }
.ht-cell.future { opacity: .35; pointer-events: none; }
.habit-table .drag-handle { flex:none; }
.habit-table .habit-row .row-title { font-size: 14px; }

/* ---- hold-to-fill checkbox ring (TZ_V2_3 §1) ---- */
.checkbox { position: relative; touch-action: none; }
/* invisible hit-area so the tap target is >=44x44px even though the visible ring is smaller */
.checkbox::after { content:""; position:absolute; top:50%; left:50%; width:44px; height:44px; transform:translate(-50%,-50%); }
.hold-ring { position:absolute; inset:-6px; pointer-events:none; transform:rotate(-90deg); }
.hold-ring circle {
  fill:none; stroke: var(--accent); stroke-width:2;
  stroke-dasharray:100; stroke-dashoffset:100;
  transition: stroke-dashoffset .15s ease;
}
.checkbox.holding .hold-ring circle { stroke-dashoffset:0; transition: stroke-dashoffset .6s linear; }
.checkbox.missed .hold-ring circle { stroke: var(--danger); }

/* ---- habits: collapsible "Прогресс" wrapper around overview + ranking (TZ_V2_3B §1) ---- */
.progress-summary {
  display:flex; align-items:center; justify-content:space-between;
  cursor:pointer; list-style:none;
  /* Rounded on its own instead of relying purely on the parent <details>'s
     overflow:hidden to clip it — WKWebView (the real Mac app's engine) can fail to
     clip an interactive child like <summary> to that radius, leaving square corners. */
  border-radius: var(--radius);
  background: var(--card);
}
.progress-details[open] .progress-summary { border-radius: var(--radius) var(--radius) 0 0; }
.progress-summary::-webkit-details-marker { display:none; }
.progress-summary::marker { content:''; }
.progress-summary .chevron { display:flex; color: var(--text-3); transition: transform .15s ease; }
.progress-details[open] .progress-summary .chevron { transform: rotate(90deg); }

/* ---- habits overview: heatmap (TZ_V2_3 §2) ---- */
.heatmap-week { display:flex; gap:6px; padding: 4px 16px 6px; }
.heatmap-day { flex:1; display:flex; flex-direction:column; align-items:center; gap:4px; min-width:0; }
.heatmap-daylabel { font-size:10px; color: var(--text-3); }
.heat-cell { width:100%; aspect-ratio:1; border-radius:6px; background: var(--card-2); box-sizing:border-box; cursor: default; }
.heatmap-month { display:grid; grid-template-columns: repeat(auto-fill, 14px); gap:3px; padding: 4px 16px 6px; }
.heatmap-month .heat-cell { width:14px; height:14px; border-radius:3px; }
.heat-cell.level-empty { background: transparent; box-shadow: inset 0 0 0 1px var(--separator); }
.heat-cell.level-0 { background: var(--card-2); }
.heat-cell.level-1 { background: rgba(var(--accent-rgb), 0.28); }
.heat-cell.level-2 { background: rgba(var(--accent-rgb), 0.52); }
.heat-cell.level-3 { background: rgba(var(--accent-rgb), 0.76); }
.heat-cell.level-4 { background: rgba(var(--accent-rgb), 1); }

/* ---- habits overview: text summary (TZ_V2_3 §2) ---- */
.habits-summary { padding: 6px 16px 16px; display:flex; flex-direction:column; gap:6px; }
.summary-line { font-size:13px; color: var(--text-2); line-height:1.4; }
.summary-line strong { color: var(--text); font-weight:640; }

/* ---- habits ranking (TZ_V2_3 §3) ---- */
.rank-num { width:18px; flex-shrink:0; font-size:13px; color: var(--text-3); font-variant-numeric: tabular-nums; }
.rank-pct { font-size:14px; color: var(--text-2); flex-shrink:0; font-variant-numeric: tabular-nums; }
.rank-delta { display:inline-flex; align-items:center; gap:2px; font-size:12px; min-width:26px; justify-content:flex-end; flex-shrink:0; font-variant-numeric: tabular-nums; }
.rank-delta.up { color: var(--good); }
.rank-delta.down { color: var(--danger); }
.rank-delta.same { color: var(--text-3); }

/* ---- sphere icon / color pickers ---- */
.icon-picker { display:grid; grid-template-columns: repeat(6, 1fr); gap:8px; padding: 12px 16px; }
.icon-choice {
  aspect-ratio:1; border-radius:10px; background:var(--card-2); border:2px solid transparent;
  color: var(--text-2); display:flex; align-items:center; justify-content:center; cursor:pointer;
  transition: transform .1s ease;
}
.icon-choice:active { transform: scale(0.94); }
.icon-choice.selected { border-color: var(--accent); color: var(--accent); }

.color-picker { display:flex; flex-wrap:wrap; gap:10px; padding: 12px 16px; }
.color-choice {
  width:32px; height:32px; border-radius:50%; cursor:pointer; border:2px solid transparent;
  transition: transform .1s ease;
}
.color-choice:active { transform: scale(0.9); }
.color-choice.selected { border-color: var(--text); box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--text-3); }

.gratitude-summary-chip { color: var(--accent); display:flex; align-items:center; }

/* ---- goal status badge (list is grouped by these, not by raw date) ---- */
.status-badge { font-size:11px; font-weight:640; padding:3px 9px; border-radius:20px; white-space:nowrap; flex-shrink:0; }
.status-badge.onTrack { color: var(--good); background: rgba(23,163,122,0.14); }
.status-badge.behind { color: var(--warn); background: rgba(255,149,0,0.14); }
.status-badge.urgent { color: var(--danger); background: rgba(213,69,95,0.14); }
.status-badge.overdue { color: #fff; background: var(--overdue); }

/* Decisions (TZ_V2_8): deliberately a single neutral style for every status — no
   color-coding by "good/bad" outcome, per the tool's no-scoring/no-judgment constraint. */
.decision-badge { font-size:11px; font-weight:640; padding:3px 9px; border-radius:20px; white-space:nowrap; flex-shrink:0; background: var(--card-2); color: var(--text-2); }
.goal-deadline-text { font-size:12px; color: var(--text-2); white-space:nowrap; flex-shrink:0; font-variant-numeric: tabular-nums; }

/* Goal rows: title spans the full row width and wraps by word; status badge +
   deadline drop to a second line under it so nothing squeezes the title into a
   one-word-per-line column on narrow widths (desktop window or iPhone). */
.goal-row { align-items: flex-start; }
.goal-row-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 7px; cursor: pointer; }
.goal-row-body .row-title { flex: none; line-height: 1.3; overflow-wrap: break-word; }
.goal-row-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; }
.goal-row > .checkbox { margin-top: 1px; }
.goal-row > .sphere-dot, .goal-row > .drag-handle { margin-top: 4px; }

/* ---- contacts: круг общения — real concentric circles, not a kanban board ---- */
.circle-diagram {
  position: relative; width: 100%; max-width: 420px; aspect-ratio: 1 / 1;
  margin: 12px auto 8px;
}
.circle-ring {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  border: 1px dashed var(--border); border-radius: 50%;
}
.circle-ring-support { width: 32%; height: 32%; }
.circle-ring-productivity { width: 64%; height: 64%; }
.circle-ring-development { width: 96%; height: 96%; }
.circle-center {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 13%; height: 13%; min-width: 32px; min-height: 32px;
  border-radius: 50%; background: var(--text); color: var(--bg);
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 680;
}
.circle-ring-pill {
  position: absolute; transform: translate(-50%, -50%);
  background: var(--card); border: 1px solid var(--border); border-radius: 20px;
  padding: 4px 10px; font-size: 11px; font-weight: 640; color: var(--text-2);
  white-space: nowrap; cursor: pointer; display: flex; align-items: center; gap: 6px;
  box-shadow: 0 1px 2px rgba(0,0,0,0.06);
}
.circle-ring-pill .plus { color: var(--accent); font-weight: 680; font-size: 14px; }
.circle-dot {
  position: absolute; transform: translate(-50%, -50%);
  max-width: 84px; height: 24px; border-radius: 13px; padding: 0 10px;
  background: var(--card); border: 1.5px solid var(--border);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; transition: transform .1s ease;
  box-shadow: 0 1px 2px rgba(0,0,0,0.06);
}
.circle-dot:active { transform: translate(-50%, -50%) scale(0.94); }
.circle-dot-name {
  font-size: 11px; font-weight: 640; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.circle-dot-stale {
  position: absolute; top: -3px; right: -3px; width: 9px; height: 9px;
  border-radius: 50%; background: var(--warn); border: 2px solid var(--card);
}

/* ---- contacts: per-ring horizontal name lanes below the diagram (TZ_V2_5) ---- */
.circle-strip { padding: 4px 0 10px; }
.circle-strip-label { font-size: 12px; font-weight: 640; color: var(--text-2); padding: 0 16px 8px; }
.circle-strip-lane { display: flex; gap: 10px; padding: 0 16px 4px; overflow-x: auto; }
.circle-strip-card {
  position: relative; flex: 0 0 auto; width: 76px; display: flex; flex-direction: column;
  align-items: center; gap: 6px; cursor: pointer; transition: transform .1s ease;
}
.circle-strip-card:active { transform: scale(0.96); }
.circle-strip-avatar {
  width: 48px; height: 48px; border-radius: 50%; border: 1.5px solid var(--border);
  background: var(--card); display: flex; align-items: center; justify-content: center;
  font-size: 15px; font-weight: 640;
}
.circle-strip-card.stale .circle-strip-avatar { border-style: dashed; }
.circle-strip-name {
  font-size: 12px; font-weight: 640; color: var(--text); text-align: center;
  line-height: 1.25; overflow-wrap: break-word; max-width: 100%;
}
.circle-strip-clock {
  position: absolute; top: -2px; right: 8px; color: var(--warn);
  background: var(--card); border-radius: 50%; display: flex; padding: 1px;
}

/* ---- privacy lock (hidden "private" task/goal rows) ---- */
.private-row { color: var(--text-3); cursor: pointer; }
.private-row .lock-ico { display:flex; flex-shrink:0; }
.lock-badge { display:inline-flex; align-items:center; color: var(--text-3); flex-shrink:0; }
.toggle-row { display:flex; align-items:center; justify-content:space-between; }
.toggle-row input[type=checkbox] { width:22px; height:22px; flex:none; }
