/* ==========================================================================
   Pulse — whole screens: loading, sign-in, and the move between them and the app.
   ========================================================================== */

:root {
  --spring: cubic-bezier(0.34, 1.45, 0.64, 1);
  --qlooq-grad: linear-gradient(135deg, #6366f1 0%, #8b5cf6 50%, #06b6d4 100%);
  --qlooq: #8b5cf6;
}

/* --------------------------------------------------------------------------
   Screens
   -------------------------------------------------------------------------- */

.screen[hidden] {
  display: none !important;
}

.screen {
  transition: opacity 0.45s var(--ease), transform 0.55s var(--ease);
}

.screen.entering,
.screen.leaving {
  opacity: 0;
}

/* Leaving is quicker than arriving, and finishes before the screen is hidden (300 ms),
   so it never cuts off half-faded. */
.screen.leaving {
  transition-duration: 0.26s, 0.26s;
}

/* A new page fades in while its sections rise one by one (enhance.css → .route-enter);
   the page itself only fades, so the two movements don't stack into one big jump. */
@keyframes view-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* The app only fades: its sidebar and nav are position: fixed, and a transform on an
   ancestor would pin them to it for the length of the transition. */
.login.entering,
.login.leaving {
  transform: scale(0.985);
}

@keyframes rise {
  from { opacity: 0; transform: translateY(10px); }
}

@keyframes ping {
  0% { transform: scale(1); opacity: 0.6; }
  70%, 100% { transform: scale(2.8); opacity: 0; }
}

/* --------------------------------------------------------------------------
   The Pulse mark (drawn by js/logo.js): a glossy accent tile with a heartbeat
   trace. `.is-live` adds a ring that ripples out like a pulse.
   -------------------------------------------------------------------------- */

.pulse-logo {
  position: relative;
  flex: none;
  display: inline-grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border-radius: 29%;
  color: #fff;
  background:
    radial-gradient(120% 85% at 28% 6%, rgba(255, 255, 255, 0.34), transparent 52%),
    linear-gradient(150deg,
      color-mix(in srgb, var(--accent) 68%, #fff) 0%,
      var(--accent) 46%,
      color-mix(in srgb, var(--accent) 62%, #02140e) 100%);
  box-shadow:
    0 10px 24px -10px rgba(var(--accent-rgb), 0.8),
    inset 0 0 0 1px rgba(255, 255, 255, 0.18),
    inset 0 -8px 14px -8px rgba(0, 0, 0, 0.3);
}

.pulse-logo svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.pulse-logo .pl-line {
  fill: none;
  stroke: currentColor;
  stroke-width: 3.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.pulse-logo .pl-base {
  opacity: 0.3;
}

.pulse-logo .pl-head {
  fill: currentColor;
  filter: drop-shadow(0 0 2.5px rgba(255, 255, 255, 0.95));
}

.pulse-logo.is-live::before,
.pulse-logo.is-live::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  border: 2px solid rgba(var(--accent-rgb), 0.6);
  pointer-events: none;
  animation: logo-ring 2.6s cubic-bezier(0.2, 0.8, 0.2, 1) infinite;
}

.pulse-logo.is-live::after {
  animation-delay: 1.3s;
}

@keyframes logo-ring {
  0% { transform: scale(1); opacity: 0.75; }
  100% { transform: scale(1.65); opacity: 0; }
}

.mobile-brand .pulse-logo.sm {
  width: 32px;
  height: 32px;
}

@media (prefers-reduced-motion: reduce) {
  .pulse-logo.is-live::before,
  .pulse-logo.is-live::after {
    display: none;
  }
}

/* --------------------------------------------------------------------------
   Loading
   -------------------------------------------------------------------------- */

.boot {
  position: fixed;
  inset: 0;
  z-index: 330;
  display: grid;
  place-items: center;
  padding: 16px;
  background:
    radial-gradient(900px 520px at 50% -10%, rgba(var(--accent-rgb), 0.08), transparent 62%),
    var(--bg);
  color: var(--muted);
  font-size: 13.5px;
  transition: opacity 0.45s var(--ease), visibility 0.45s;
}

.boot.done {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

.boot.done .boot-card {
  transform: scale(1.04);
  filter: blur(2px);
}

.boot.overlay {
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

/* Only shows if loading takes a moment, so fast reloads don't flicker. */
.boot-card {
  display: grid;
  justify-items: center;
  gap: 6px;
  animation: rise 0.6s var(--ease) 0.25s both;
  transition: transform 0.45s var(--ease), filter 0.45s var(--ease);
}

.boot-logo {
  width: 76px;
  height: 76px;
  margin: 14px 0 18px;
}

.boot-line {
  display: flex;
  align-items: baseline;
  min-height: 1.5em;
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 600;
  color: var(--text);
}

#boot-msg {
  display: inline-block;
}

.boot-dots {
  display: inline-flex;
  gap: 3px;
  margin-left: 3px;
}

.boot-dots i {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.25;
  animation: boot-dot 1.2s var(--ease) infinite;
}

.boot-dots i:nth-child(2) { animation-delay: 0.15s; }
.boot-dots i:nth-child(3) { animation-delay: 0.3s; }

@keyframes boot-dot {
  0%, 60%, 100% { opacity: 0.25; transform: none; }
  30% { opacity: 1; transform: translateY(-3px); }
}

/* Step checklist: every step stays readable — upcoming, current and finished. */
.boot-steps {
  list-style: none;
  margin: 14px 0 4px;
  padding: 14px 16px;
  display: grid;
  gap: 10px;
  min-width: 300px;
  max-width: min(380px, calc(100vw - 48px));
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: 14px;
  box-shadow: var(--shadow-pop);
  animation: rise 0.45s var(--ease) both;
}

/* Keep the empty step container out of the loading card until there are steps. */
.boot-steps[hidden] {
  display: none;
}

.boot-steps li {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  line-height: 1.4;
  color: var(--faint);
  transition: color 0.35s var(--ease);
}

.step-label {
  min-width: 0;
  overflow-wrap: anywhere;
}

.step-mark {
  position: relative;
  flex: none;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  border: 1.5px solid var(--border-strong);
  color: transparent;
  transition: background 0.35s var(--ease), border-color 0.35s var(--ease), color 0.35s var(--ease), transform 0.35s var(--spring);
}

.step-mark .material-symbols-outlined {
  font-size: 13px;
  font-weight: 700;
}

.boot-steps li[data-state='active'] {
  color: var(--text);
  font-weight: 600;
}

.boot-steps li[data-state='active'] .step-mark {
  border-color: rgba(var(--accent-rgb), 0.25);
  border-top-color: var(--accent);
  animation: spin 0.8s linear infinite;
}

.boot-steps li[data-state='done'] {
  color: var(--muted);
}

.boot-steps li[data-state='done'] .step-mark {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-contrast);
  animation: step-pop 0.4s var(--spring);
}

@keyframes step-pop {
  from { transform: scale(0.6); }
}

/* --------------------------------------------------------------------------
   Sign in
   -------------------------------------------------------------------------- */

.login {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: grid;
  place-items: center;
  overflow: hidden auto;
  padding: 64px 16px 24px;
}

.login-theme {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 1;
  animation: rise 0.7s var(--ease) 0.3s both;
}

.orbs {
  position: fixed;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}

.orbs span {
  position: absolute;
  width: 48vmax;
  height: 48vmax;
  border-radius: 50%;
  filter: blur(70px);
  opacity: 0.55;
  pointer-events: none;
  animation: drift 22s var(--ease) infinite alternate;
}

.orbs span:nth-child(1) {
  background: radial-gradient(circle, rgba(var(--accent-rgb), 0.22), transparent 65%);
  top: -18vmax;
  left: -10vmax;
}

.orbs span:nth-child(2) {
  background: radial-gradient(circle, rgba(99, 102, 241, 0.18), transparent 65%);
  bottom: -22vmax;
  right: -12vmax;
  animation-delay: -7s;
}

/* QLOOQ's violet → cyan */
.orbs span:nth-child(3) {
  background: radial-gradient(circle, rgba(139, 92, 246, 0.14), rgba(6, 182, 212, 0.06) 40%, transparent 65%);
  top: 30%;
  left: 45%;
  width: 30vmax;
  height: 30vmax;
  animation-delay: -14s;
}

@keyframes drift {
  0% { transform: translate(0, 0) scale(1); }
  50% { transform: translate(4vmax, 3vmax) scale(1.08); }
  100% { transform: translate(-3vmax, 5vmax) scale(0.96); }
}

.login-card {
  position: relative;
  width: min(380px, 100%);
  padding: 22px 32px;
  text-align: center;
  background: color-mix(in srgb, var(--surface) 82%, transparent);
  backdrop-filter: blur(24px) saturate(1.2);
  -webkit-backdrop-filter: blur(24px) saturate(1.2);
  border: 1px solid var(--border-strong);
  border-radius: 22px;
  box-shadow: var(--shadow-pop);
}

.login-card > * { animation: rise 0.7s var(--ease) both; }
.login-card > :nth-child(2) { animation-delay: 0.05s; }
.login-card > :nth-child(3) { animation-delay: 0.1s; }
.login-card > :nth-child(4) { animation-delay: 0.16s; }
.login-card > :nth-child(n + 5) { animation-delay: 0.22s; }

.login-logo {
  width: 76px;
  height: 76px;
  margin: 18px auto 18px;
}

.login h1 {
  margin: 0;
  font-family: var(--font-display);
  font-size: 27px;
  font-weight: 700;
  letter-spacing: -0.03em;
  color: var(--text);
}

.tagline {
  margin: 6px 0 26px;
  color: var(--muted);
  font-size: 14px;
}

.btn-google {
  position: relative;
  width: 100%;
  height: 46px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  background: var(--surface-2);
  color: var(--text);
  font-weight: 600;
  font-size: 14px;
  cursor: pointer;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
  transition: transform 0.2s var(--spring), box-shadow 0.25s var(--ease), border-color 0.2s, background 0.2s;
}

.btn-google:hover:not(:disabled) {
  border-color: rgba(var(--accent-rgb), 0.5);
  box-shadow: 0 10px 26px -12px rgba(var(--accent-rgb), 0.55);
  transform: translateY(-1px);
}

.btn-google:active:not(:disabled) {
  transform: scale(0.98);
}

.btn-google:disabled {
  opacity: 0.55;
  cursor: default;
}

.btn-google.busy:disabled {
  opacity: 0.85;
  cursor: progress;
}

.g-icon {
  width: 18px;
  height: 18px;
}

.btn-spinner {
  position: absolute;
  right: 16px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 2px solid var(--border-strong);
  border-top-color: var(--accent);
  opacity: 0;
  animation: spin 0.8s linear infinite;
  transition: opacity 0.2s;
}

.btn-google.busy .btn-spinner {
  opacity: 1;
}

.login-note {
  margin: 0;
  font-size: 12.5px;
  color: var(--muted);
}

.login-note:not(:empty) {
  margin-top: 12px;
}

.login-note.error {
  color: var(--rose);
}

.link-btn {
  margin-top: 14px;
  padding: 4px 6px;
  border: 0;
  border-radius: 6px;
  background: none;
  font-size: 13px;
  color: var(--muted);
  cursor: pointer;
  transition: color 0.2s;
}

.link-btn:hover {
  color: var(--text);
}

.login-points {
  list-style: none;
  margin: 20px 0 20px;
  padding: 13px 14px;
  border: 1px solid var(--border);
  border-radius: 13px;
  background: rgba(var(--tint-rgb), 0.025);
  display: grid;
  gap: 11px;
  text-align: left;
}

.login-points li {
  display: flex;
  gap: 11px;
  align-items: flex-start;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--muted);
}

.login-points .material-symbols-outlined {
  flex: none;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  margin-top: -2px;
  border-radius: 7px;
  font-size: 15px;
  color: var(--accent-bright);
  background: rgba(var(--accent-rgb), 0.11);
}

/* QLOOQ (qlooq.cfd — the family of apps Pulse belongs to): an indigo → violet → cyan tile
   with the "oo" mark, and the "QLOOQ .cfd" wordmark. */
.qlooq-mark {
  flex: none;
  width: 24px;
  height: 24px;
  border-radius: 7px;
  display: grid;
  place-items: center;
  background: var(--qlooq-grad);
  box-shadow: 0 4px 12px -5px rgba(139, 92, 246, 0.7);
}

.qlooq-mark svg {
  width: 64%;
  height: 64%;
  fill: none;
  stroke: #fff;
  stroke-width: 2.6;
  stroke-linecap: round;
}

.qlooq-mark.sm {
  width: 16px;
  height: 16px;
  border-radius: 5px;
  box-shadow: none;
}

.qlooq-mark.sm svg {
  stroke-width: 3;
}

.qlooq-word {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: -0.02em;
}

.qlooq-tld {
  font: 600 10.5px/1 var(--font-mono);
  padding: 3px 5px;
  border-radius: 6px;
  color: var(--qlooq);
  background: rgba(139, 92, 246, 0.14);
}

.qlooq-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 34px;
  padding: 0 10px 0 5px;
  border-radius: 11px;
  color: var(--text);
  text-decoration: none;
  font-size: 13.5px;
  background: color-mix(in srgb, var(--surface) 75%, transparent);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid var(--border-strong);
  transition: transform 0.25s var(--spring), box-shadow 0.25s, border-color 0.25s;
}

.qlooq-chip:hover {
  transform: translateY(-1px);
  border-color: rgba(139, 92, 246, 0.45);
  box-shadow: 0 8px 22px -10px rgba(139, 92, 246, 0.6);
}

.login-qlooq {
  position: absolute;
  top: 14px;
  left: 14px;
  z-index: 1;
  animation: rise 0.7s var(--ease) 0.3s both;
}

.login-foot {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 4px 8px;
  margin: 0;
  font-size: 12px;
  color: var(--faint);
}

.login-foot a {
  color: var(--muted);
  text-decoration: none;
  border-radius: 4px;
  transition: color 0.2s;
}

.login-foot a:hover {
  color: var(--text);
}

.login-foot-brand {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-weight: 500;
}

.login-foot-brand:hover {
  color: var(--qlooq) !important;
}

html[data-theme='light'] .orbs span {
  opacity: 0.7;
}

html[data-theme='light'] .btn-google {
  background: var(--surface);
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.06);
}

@media (max-width: 480px) {
  .login-card {
    padding: 18px 20px;
    border-radius: 20px;
  }
}

/* --------------------------------------------------------------------------
   Sync chip: "Reconnect" asks for attention with a pulsing dot
   -------------------------------------------------------------------------- */

.drive-status.is-auth {
  border-color: rgba(245, 158, 11, 0.42);
  background: rgba(245, 158, 11, 0.1);
  color: var(--amber-bright);
}

.drive-status.is-auth:hover {
  transform: translateY(-1px);
  border-color: rgba(245, 158, 11, 0.6);
  box-shadow: 0 8px 20px -10px rgba(245, 158, 11, 0.55);
}

.drive-status.is-auth .drive-status-dot,
.drive-status.is-error .drive-status-dot {
  position: relative;
}

.drive-status.is-auth .drive-status-dot::after,
.drive-status.is-error .drive-status-dot::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: inherit;
  animation: ping 2s var(--ease) infinite;
}

/* The label slides in when the status changes (Saving → Synced …). */
.drive-status-label.is-swapping {
  animation: label-swap 0.32s var(--ease);
}

@keyframes label-swap {
  from { opacity: 0; transform: translateY(6px); }
}

/* --------------------------------------------------------------------------
   QLOOQ + developer: badges in the sidebar's brand row, cards in Settings → About
   -------------------------------------------------------------------------- */

.brand-badges {
  display: flex;
  align-items: center;
  gap: 5px;
  margin-left: auto;
}

.qlooq-badge,
.dev-badge {
  width: 22px;
  height: 22px;
  border-radius: 7px;
  display: grid;
  place-items: center;
  text-decoration: none;
  color: var(--muted);
  background: rgba(var(--tint-rgb), 0.04);
  box-shadow: inset 0 0 0 1px var(--border);
  transition: color 0.2s, background 0.25s, box-shadow 0.25s, transform 0.25s var(--spring);
}

.qlooq-badge .qlooq-mark {
  width: 14px;
  height: 14px;
  border-radius: 5px;
  box-shadow: none;
  filter: saturate(0.7);
  transition: filter 0.25s;
}

.dev-badge .material-symbols-outlined {
  font-size: 13px;
}

.qlooq-badge:hover {
  transform: translateY(-1px) scale(1.06);
  box-shadow: 0 6px 16px -6px rgba(139, 92, 246, 0.7), inset 0 0 0 1px rgba(139, 92, 246, 0.4);
}

.qlooq-badge:hover .qlooq-mark {
  filter: none;
}

.dev-badge:hover {
  color: #fff;
  transform: translateY(-1px) scale(1.06);
  background: linear-gradient(135deg, var(--accent), color-mix(in srgb, var(--accent) 55%, #ec4899));
  box-shadow: 0 6px 16px -6px rgba(var(--accent-rgb), 0.7);
}

.qlooq-badge:active,
.dev-badge:active {
  transform: scale(0.94);
}

.qlooq-mark.lg {
  width: 38px;
  height: 38px;
  border-radius: 11px;
}

.about-dev,
.about-qlooq-card {
  display: flex;
  align-items: center;
  gap: 12px;
  color: var(--text);
  text-decoration: none;
}

.about-dev {
  margin-top: 14px;
  padding: 10px 12px;
  border-radius: 12px;
  background: rgba(var(--tint-rgb), 0.025);
  border: 1px solid var(--border);
  transition: border-color 0.2s, background 0.2s, transform 0.25s var(--spring);
}

.about-dev:hover {
  border-color: rgba(var(--accent-rgb), 0.4);
  background: rgba(var(--accent-rgb), 0.06);
  transform: translateY(-1px);
}

.about-dev-mark {
  flex: none;
  width: 38px;
  height: 38px;
  border-radius: 11px;
  display: grid;
  place-items: center;
  color: #fff;
  background: linear-gradient(135deg, var(--accent), color-mix(in srgb, var(--accent) 55%, #ec4899));
}

.about-dev-mark .material-symbols-outlined {
  font-size: 19px;
}

.about-dev-copy {
  flex: 1;
  min-width: 0;
  display: grid;
  gap: 2px;
  line-height: 1.35;
}

.about-dev-copy b {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  font-weight: 600;
}

.about-dev-copy small {
  font-size: 11.5px;
  color: var(--muted);
}

.about-go {
  font-size: 17px;
  color: var(--faint);
  transition: color 0.2s, transform 0.25s var(--spring);
}

.about-dev:hover .about-go {
  color: var(--accent-bright);
  transform: translate(2px, -2px);
}

.about-qlooq-card:hover .about-go {
  color: var(--qlooq);
  transform: translate(2px, -2px);
}

.about-qlooq {
  margin-top: 10px;
  padding: 12px 14px;
  border-radius: 13px;
  border: 1px solid rgba(139, 92, 246, 0.24);
  background: linear-gradient(135deg, rgba(99, 102, 241, 0.07), rgba(6, 182, 212, 0.06));
}

.about-qlooq-links {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 10px;
}

.about-qlooq-links a {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 28px;
  padding: 0 10px;
  border-radius: 8px;
  font-size: 11.5px;
  color: var(--muted);
  text-decoration: none;
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--border);
  transition: color 0.2s, box-shadow 0.2s;
}

.about-qlooq-links a .material-symbols-outlined {
  font-size: 14px;
}

.about-qlooq-links a:hover {
  color: var(--text);
  box-shadow: inset 0 0 0 1px rgba(139, 92, 246, 0.45);
}

/* --------------------------------------------------------------------------
   Sidebar account area: a soft tinted panel instead of bare text
   -------------------------------------------------------------------------- */

.account-mini {
  background:
    radial-gradient(140% 120% at 0% 0%, rgba(var(--accent-rgb), 0.07), transparent 60%),
    rgba(var(--tint-rgb), 0.03);
  border-color: var(--border);
  box-shadow: inset 0 1px 0 rgba(var(--tint-rgb), 0.04);
  transition: background 0.2s, border-color 0.2s, transform 0.25s var(--spring);
}

.account-mini:hover {
  background:
    radial-gradient(140% 120% at 0% 0%, rgba(var(--accent-rgb), 0.11), transparent 60%),
    rgba(var(--tint-rgb), 0.05);
  border-color: var(--border-strong);
}

.account-mini:active {
  transform: scale(0.985);
}
/* --------------------------------------------------------------------------
   Dark theme legibility
   Category and habit colours come from your data and are set inline (e.g. indigo #6366f1),
   which is too dim as small text on the dark surfaces — lift them a little. Shared greys are
   lifted in base.css (--dim, --faint, --muted).
   -------------------------------------------------------------------------- */

html[data-theme='dark'] .tag-chip[style],
html[data-theme='dark'] .chip[style],
html[data-theme='dark'] .habit-card-meta .chip[style],
html[data-theme='dark'] .habit-detail-head .chip[style] {
  filter: brightness(1.32) saturate(0.92);
}

html[data-theme='dark'] strong[style*='color'],
html[data-theme='dark'] .habit-card-rate strong[style],
html[data-theme='dark'] .rel-rate-top strong[style] {
  filter: brightness(1.3);
}

html[data-theme='dark'] .qlooq-tld {
  color: #b9a5fb;
  background: rgba(139, 92, 246, 0.2);
}

html[data-theme='dark'] .task-row.is-done {
  opacity: 0.8;
}

html[data-theme='dark'] .week-day .wd-label {
  color: var(--dim);
}

html[data-theme='dark'] .chip-muted {
  color: var(--muted);
}
/* --------------------------------------------------------------------------
   Smooth changes (view transitions)
   A change to a habit, activity or task slides the cards into place, fades new ones in and
   removed ones out. The page itself only cross-fades briefly; clicks keep working during it.
   -------------------------------------------------------------------------- */

html.vt-data::view-transition,
html.vt-data::view-transition-group(*),
html.vt-data::view-transition-image-pair(*),
html.vt-data::view-transition-old(*),
html.vt-data::view-transition-new(*) {
  pointer-events: none;
}

html.vt-data::view-transition-old(root) {
  animation: none;
}

html.vt-data::view-transition-new(root) {
  animation: vt-root-in 0.22s ease both;
}

@keyframes vt-root-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

html.vt-data::view-transition-group(*) {
  animation-duration: 0.38s;
  animation-timing-function: cubic-bezier(0.2, 0.8, 0.2, 1);
}

html.vt-data::view-transition-old(*),
html.vt-data::view-transition-new(*) {
  animation-duration: 0.3s;
  animation-timing-function: ease;
}

/* The rest of the page (hero, counts, rings) must not be re-captured as a moving layer. */
html.vt-data::view-transition-group(root) {
  animation-duration: 0.01s;
}

/* --------------------------------------------------------------------------
   Opening and closing: dialogs, pop-ups and menus ease out of place with a little overshoot
   and leave quicker than they arrive.
   -------------------------------------------------------------------------- */

:root {
  --ease-out-back: cubic-bezier(0.2, 0.9, 0.25, 1.08);
  --ease-in-soft: cubic-bezier(0.4, 0, 0.7, 0.2);
}

.modal-backdrop {
  transition: opacity 0.24s ease;
}

.modal {
  opacity: 0;
  transform: translateY(18px) scale(0.97);
  transition: transform 0.4s var(--ease-out-back), opacity 0.24s ease;
}

.modal-backdrop.open .modal {
  opacity: 1;
  transform: none;
}

.modal-backdrop:not(.open) {
  transition-duration: 0.2s;
}

.modal-backdrop:not(.open) .modal {
  opacity: 0;
  transform: translateY(10px) scale(0.985);
  transition: transform 0.2s var(--ease-in-soft), opacity 0.16s ease;
}

.palette {
  transition: transform 0.34s var(--ease-out-back), opacity 0.2s ease;
}

.palette-backdrop:not(.open) .palette {
  opacity: 0;
  transform: translateY(-8px) scale(0.99);
  transition: transform 0.18s var(--ease-in-soft), opacity 0.14s ease;
}

.drive-pop,
.streak-banner,
.cards-pop,
.menu-pop,
.control-pop {
  transition: opacity 0.2s ease, transform 0.34s var(--ease-out-back);
}

.drive-pop-backdrop:not(.open) .drive-pop,
.streak-banner-backdrop:not(.open) .streak-banner,
.cards-pop-backdrop:not(.open) .cards-pop,
.menu-pop.menu-out,
.control-pop:not(.is-open) {
  transition: opacity 0.14s ease, transform 0.16s var(--ease-in-soft);
}

/* Sections that expand and collapse (task stacks): the list slides while it fades, and the
   arrow turns with it. */
.task-list-wrap {
  transition: grid-template-rows 0.34s cubic-bezier(0.2, 0.8, 0.2, 1);
}

.task-list {
  transition: opacity 0.26s ease 0.04s, transform 0.34s cubic-bezier(0.2, 0.8, 0.2, 1);
}

.task-group.is-collapsed .task-list {
  opacity: 0;
  transform: translateY(-8px);
  transition: opacity 0.14s ease, transform 0.3s cubic-bezier(0.2, 0.8, 0.2, 1);
}

.task-group-chevron {
  transition: transform 0.3s var(--ease-out-back), color 0.16s;
}

@media (prefers-reduced-motion: reduce) {
  .modal,
  .modal-backdrop:not(.open) .modal,
  .palette,
  .drive-pop,
  .streak-banner,
  .cards-pop,
  .menu-pop,
  .control-pop,
  .task-list-wrap,
  .task-list {
    transition-duration: 0.01ms !important;
  }
}
/* --------------------------------------------------------------------------
   Page and tab switches (view transitions, see smoothSwap in ui.js)
   -------------------------------------------------------------------------- */

html[class*='vt-']::view-transition,
html[class*='vt-']::view-transition-group(*),
html[class*='vt-']::view-transition-image-pair(*),
html[class*='vt-']::view-transition-old(*),
html[class*='vt-']::view-transition-new(*) {
  pointer-events: none;
}

/* Another page: the old one fades away as the new one comes up (its sections then rise in
   one by one, see .route-enter). */
/* Only the content area animates. The sidebar, top bar and bottom bar are their own layers
   that stay put (and keep their stacking), and the page behind them doesn't move at all. */
html.vt-page::view-transition-old(root),
html.vt-page::view-transition-new(root) {
  animation: none;
}

html.vt-page #view {
  view-transition-name: vt-page;
}

html.vt-page .topbar {
  view-transition-name: vt-topbar;
}

html.vt-page .sidebar {
  view-transition-name: vt-sidebar;
}

html.vt-page .mobile-nav {
  view-transition-name: vt-mnav;
}

html.vt-page::view-transition-group(vt-page) {
  animation: none;
  overflow: clip;
}

html.vt-page::view-transition-group(vt-topbar),
html.vt-page::view-transition-group(vt-sidebar),
html.vt-page::view-transition-group(vt-mnav) {
  animation-duration: 0.01s;
}

/* The old page is shown where the viewer was looking (scrolled), then fades out; the new
   page comes up from its top. */
html.vt-page::view-transition-old(vt-page) {
  transform: translateY(calc(-1 * var(--vt-scroll, 0px)));
  animation: vt-page-out 0.16s ease both;
}

html.vt-page::view-transition-new(vt-page) {
  animation: vt-page-in 0.34s ease 0.04s both;
}

@keyframes vt-page-out {
  to { opacity: 0; }
}

@keyframes vt-page-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* The highlighted menu item glides from the old item to the new one. */
html.vt-page .nav-item.active {
  view-transition-name: nav-active;
}

html.vt-page .mobile-nav-item.active {
  view-transition-name: mnav-active;
}

html.vt-page::view-transition-group(nav-active),
html.vt-page::view-transition-group(mnav-active) {
  animation-duration: 0.42s;
  animation-timing-function: cubic-bezier(0.2, 0.9, 0.25, 1.08);
}

/* A panel inside a page (overview tabs): the old panel drifts out and fades while the new one
   glides in from the other side, overlapping so there is never an empty frame; the height
   eases on the same long, soft curve. */
html.vt-tab::view-transition-group(vt-tab) {
  animation-duration: 0.48s;
  animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
}

html.vt-tab::view-transition-old(vt-tab) {
  animation: vt-tab-out-fwd 0.26s cubic-bezier(0.4, 0, 1, 1) both;
}

html.vt-tab::view-transition-new(vt-tab) {
  animation: vt-tab-in-fwd 0.48s cubic-bezier(0.22, 1, 0.36, 1) 0.06s both;
}

html.vt-tab[data-vt-dir='-1']::view-transition-old(vt-tab) {
  animation-name: vt-tab-out-back;
}

html.vt-tab[data-vt-dir='-1']::view-transition-new(vt-tab) {
  animation-name: vt-tab-in-back;
}

@keyframes vt-tab-out-fwd { to { opacity: 0; transform: translateX(-14px); } }
@keyframes vt-tab-in-fwd { from { opacity: 0; transform: translateX(16px); } }
@keyframes vt-tab-out-back { to { opacity: 0; transform: translateX(14px); } }
@keyframes vt-tab-in-back { from { opacity: 0; transform: translateX(-16px); } }

/* Page switches: the old page fades a little longer and the new one's sections rise on a
   softer curve with a tighter stagger, so the whole change reads as one movement. */
html.vt-page::view-transition-old(vt-page) {
  animation: vt-page-out 0.22s cubic-bezier(0.4, 0, 1, 1) both;
}

html.vt-page::view-transition-new(vt-page) {
  animation: vt-page-in 0.42s cubic-bezier(0.22, 1, 0.36, 1) 0.05s both;
}

.route-enter .page > * {
  animation: pulse-rise 0.52s cubic-bezier(0.22, 1, 0.36, 1) both;
}

.route-enter .page > *:nth-child(1) { animation-delay: 0.03s; }
.route-enter .page > *:nth-child(2) { animation-delay: 0.065s; }
.route-enter .page > *:nth-child(3) { animation-delay: 0.1s; }
.route-enter .page > *:nth-child(4) { animation-delay: 0.135s; }
.route-enter .page > *:nth-child(5) { animation-delay: 0.17s; }
.route-enter .page > *:nth-child(6) { animation-delay: 0.2s; }
.route-enter .page > *:nth-child(7) { animation-delay: 0.23s; }

/* --------------------------------------------------------------------------
   Check boxes: the pressed box fills and pops at once (js: optimisticCheck), the tick
   scales in, a ring ripples out; the row then glows softly once the data is saved.
   -------------------------------------------------------------------------- */

.habit-check {
  position: relative;
  transition:
    background-color 0.3s cubic-bezier(0.22, 1, 0.36, 1),
    border-color 0.3s cubic-bezier(0.22, 1, 0.36, 1),
    color 0.22s ease,
    box-shadow 0.4s ease,
    transform 0.22s cubic-bezier(0.22, 1, 0.36, 1);
}

.habit-check .material-symbols-outlined {
  transition: transform 0.34s cubic-bezier(0.34, 1.5, 0.64, 1), opacity 0.2s ease;
}

.habit-check:not(.checked):not(.partial) .material-symbols-outlined {
  transform: scale(0.45) rotate(-14deg);
  opacity: 0;
}

.habit-check.check-pop {
  animation: check-pop 0.36s cubic-bezier(0.34, 1.4, 0.64, 1);
}

.habit-check.check-unpop {
  animation: check-unpop 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}

.habit-check.check-pop::after {
  content: '';
  position: absolute;
  inset: -2px;
  border-radius: inherit;
  border: 2px solid rgba(var(--accent-rgb), 0.5);
  pointer-events: none;
  animation: check-ring 0.42s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

@keyframes check-pop {
  0% { transform: scale(0.88); }
  55% { transform: scale(1.08); }
  100% { transform: scale(1); }
}

@keyframes check-unpop {
  0% { transform: scale(0.92); }
  100% { transform: scale(1); }
}

@keyframes check-ring {
  from { opacity: 1; transform: scale(1); }
  to { opacity: 0; transform: scale(1.65); }
}

/* After the save, the row brightens and settles back (no jump: it starts from its own colour). */
.just-completed {
  animation: row-complete-soft 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}

.just-uncompleted {
  animation: row-uncomplete-soft 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}

/* The tick already animated before the save, so it stays still when the row glows. */
.just-completed .habit-check:not(.just-completed),
.just-uncompleted .habit-check:not(.just-uncompleted) {
  animation: none;
}

@keyframes row-complete-soft {
  0% { box-shadow: inset 0 0 0 1px rgba(var(--accent-rgb), 0); }
  30% { box-shadow: inset 0 0 0 1px rgba(var(--accent-rgb), 0.38), 0 8px 24px -18px rgba(var(--accent-rgb), 0.5); }
  100% { box-shadow: inset 0 0 0 1px rgba(var(--accent-rgb), 0); }
}

@keyframes row-uncomplete-soft {
  0% { box-shadow: inset 0 0 0 1px rgba(var(--tint-rgb), 0); }
  35% { box-shadow: inset 0 0 0 1px rgba(var(--tint-rgb), 0.16); }
  100% { box-shadow: inset 0 0 0 1px rgba(var(--tint-rgb), 0); }
}

@media (prefers-reduced-motion: reduce) {
  .habit-check.check-pop,
  .habit-check.check-unpop,
  .habit-check.check-pop::after,
  .just-completed,
  .just-uncompleted {
    animation: none !important;
  }
}

/* Segmented controls, chips and menu items change colour and lift softly. */
.seg-btn,
.filter-chip,
.nav-item,
.overview-tab,
.view-tab,
.preset-btn,
.day-preset {
  transition:
    background-color 0.28s ease,
    border-color 0.28s ease,
    color 0.28s ease,
    box-shadow 0.28s ease,
    transform 0.28s var(--ease-out-back);
}

.seg-btn:active,
.filter-chip:active,
.nav-item:active,
.overview-tab:active {
  transform: scale(0.96);
}

.overview-tab-indicator {
  transition:
    transform 0.46s cubic-bezier(0.2, 0.9, 0.25, 1.08),
    width 0.4s cubic-bezier(0.2, 0.8, 0.2, 1),
    height 0.4s cubic-bezier(0.2, 0.8, 0.2, 1);
}

/* --------------------------------------------------------------------------
   Habit calendar: a compact month, centred
   -------------------------------------------------------------------------- */

.protocol-calendar {
  max-width: 330px;
  margin-left: auto;
  margin-right: auto;
}

.pcal-label {
  font-size: 15px;
}

.pcal-head {
  margin-bottom: 8px;
}

.pcal-nav {
  width: 22px;
  height: 22px;
}

.pcal-weekdays,
.pcal-grid {
  gap: 3px;
}

.pcal-weekdays {
  margin-bottom: 3px;
}

.pcal-weekdays span {
  padding-left: 0;
  text-align: center;
  font-size: 7.5px;
}

.pcal-day {
  height: 32px;
  padding: 0;
  justify-content: center;
  border-radius: 8px;
  font-size: 10px;
}

.pcal-day.is-done::after,
.pcal-day.is-partial::after {
  top: 4px;
  right: 4px;
  width: 4px;
  height: 4px;
}

.pcal-foot {
  margin-top: 8px;
  padding-top: 7px;
}

@media (max-width: 640px) {
  .protocol-calendar {
    max-width: 300px;
  }

  .pcal-day {
    height: 30px;
    padding: 0;
    font-size: 10px;
  }
}

/* --------------------------------------------------------------------------
   Stopwatch on timer cards (js/stopwatch.js)
   -------------------------------------------------------------------------- */

.sw {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-width: 0;
}

.sw-main,
.sw-stop {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 28px;
  padding: 0 10px 0 7px;
  border-radius: 8px;
  border: 1px solid rgba(var(--accent-rgb), 0.3);
  background: rgba(var(--accent-rgb), 0.1);
  color: var(--accent-bright);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease, transform 0.25s var(--ease-out-back);
}

.sw-main .material-symbols-outlined,
.sw-stop .material-symbols-outlined {
  font-size: 17px;
}

.sw-main:hover,
.sw-stop:hover {
  background: rgba(var(--accent-rgb), 0.18);
  border-color: rgba(var(--accent-rgb), 0.5);
}

.sw-main:active,
.sw-stop:active {
  transform: scale(0.95);
}

.sw-time {
  min-width: 4.2ch;
  text-align: left;
  font-variant-numeric: tabular-nums;
}

.sw[data-state='idle'] .sw-time {
  min-width: 0;
  font-family: var(--font-body);
  font-weight: 600;
}

.sw[data-state='running'] .sw-main {
  background: rgba(var(--accent-rgb), 0.2);
  border-color: rgba(var(--accent-rgb), 0.6);
  box-shadow: 0 0 0 0 rgba(var(--accent-rgb), 0.45);
  animation: sw-glow 1.8s ease-out infinite;
}

.sw[data-state='paused'] .sw-main {
  background: rgba(245, 158, 11, 0.12);
  border-color: rgba(245, 158, 11, 0.4);
  color: var(--amber-bright);
}

.sw-stop {
  padding: 0 9px 0 6px;
  background: rgba(var(--tint-rgb), 0.05);
  border-color: var(--border-strong);
  color: var(--text-soft);
  animation: sw-in 0.26s var(--ease-out-back) both;
}

.sw-stop:hover {
  background: rgba(var(--accent-rgb), 0.14);
  color: var(--accent-bright);
}

@keyframes sw-glow {
  0% { box-shadow: 0 0 0 0 rgba(var(--accent-rgb), 0.4); }
  70%, 100% { box-shadow: 0 0 0 7px rgba(var(--accent-rgb), 0); }
}

@keyframes sw-in {
  from { opacity: 0; transform: scale(0.85); }
}

.habit-card-actions {
  flex-wrap: wrap;
}

@media (max-width: 720px) {
  /* Phone overview rows: the stopwatch gets a full-width line under the chips. */
  .overview-panel .habit-row:has(.sw) {
    grid-template-columns: 30px minmax(0, 1fr);
    grid-template-areas:
      'check name'
      'check tags'
      'check prog'
      'check meta';
  }

  .overview-panel .habit-row:has(.sw) .habit-meta {
    flex-wrap: wrap;
    justify-content: flex-start;
    align-self: stretch;
    margin-top: 10px;
  }

  .overview-panel .activity-row .habit-meta:has(.sw) {
    grid-auto-flow: row;
    grid-auto-columns: auto;
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .overview-panel .habit-meta .sw {
    grid-column: 1 / -1;
  }

  .overview-panel .habit-meta .sw .sw-main {
    flex: 1;
    height: 34px;
    justify-content: center;
  }

  .overview-panel .habit-meta .sw .sw-stop {
    height: 34px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .sw[data-state='running'] .sw-main,
  .sw-stop {
    animation: none;
  }
}
/* --------------------------------------------------------------------------
   Habit calendar (detail window): a small month, centred
   -------------------------------------------------------------------------- */

.protocol-calendar,
.protocol-calendar .pcal-head,
.protocol-calendar .pcal-foot {
  max-width: 252px;
}

.protocol-calendar {
  margin-left: auto;
  margin-right: auto;
}

.habit-detail-chart:has(.protocol-calendar) {
  padding: 12px 16px;
}

.pcal-label {
  font-size: 13px;
}

.pcal-head {
  margin-bottom: 6px;
}

.pcal-count {
  font-size: 7px;
}

.pcal-nav {
  width: 20px;
  height: 20px;
  border-radius: 5px;
}

.pcal-nav .material-symbols-outlined {
  font-size: 14px;
}

.pcal-weekdays,
.pcal-grid {
  gap: 2px;
}

.pcal-weekdays {
  margin-bottom: 2px;
}

.pcal-weekdays span {
  font-size: 6.5px;
  letter-spacing: 0.03em;
}

.pcal-day {
  height: 24px;
  border-radius: 6px;
  font-size: 9px;
}

.pcal-day.is-done::after,
.pcal-day.is-partial::after {
  top: 3px;
  right: 3px;
  width: 3px;
  height: 3px;
  box-shadow: none;
}

.pcal-foot {
  margin-top: 6px;
  padding-top: 6px;
  gap: 6px;
}

.pcal-note,
.pcal-legend {
  font-size: 6.5px;
}

.pcal-note .material-symbols-outlined {
  font-size: 11px;
}

.pcal-legend .pcal-day {
  width: 9px;
  height: 9px;
  border-radius: 3px;
}

@media (max-width: 640px) {
  .protocol-calendar,
  .protocol-calendar .pcal-head,
  .protocol-calendar .pcal-foot {
    max-width: 252px;
  }

  .pcal-day {
    height: 24px;
    font-size: 9px;
  }
}

/* --------------------------------------------------------------------------
   Session timer row inside dialogs
   -------------------------------------------------------------------------- */

.sw-panel {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: rgba(var(--accent-rgb), 0.04);
}

.habit-detail-head + .habit-detail-stats + .sw-panel,
.habit-detail-stats + .sw-panel {
  margin-top: 12px;
}

.sw-panel-copy {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.sw-panel-copy small {
  font-size: 11px;
  color: var(--dim);
  line-height: 1.35;
}

.sw-panel .sw-main,
.sw-panel .sw-stop {
  height: 34px;
}

/* --------------------------------------------------------------------------
   Rows and cards that open something read as clickable, never as editable text:
   a pointer all over them (the text cursor only shows inside real fields).
   -------------------------------------------------------------------------- */

.habit-row,
.habit-row *,
.habit-card,
.habit-card *,
.activity-card,
.task-row,
.task-row *,
.open-loop,
.open-loop *,
.template-card,
.template-card *,
.type-card,
.type-card *,
.week-day,
.week-day *,
.session-item,
.tl-item,
.rel-row,
.rel-row * {
  cursor: pointer;
}

.habit-row,
.habit-card,
.task-row,
.open-loop,
.template-card,
.type-card,
.week-day,
.rel-row {
  -webkit-user-select: none;
  user-select: none;
}

.habit-row .habit-check:disabled,
.habit-row .habit-check:disabled * {
  cursor: default;
}

.habit-row input,
.habit-row textarea,
.habit-card input,
.task-row input {
  cursor: text;
}
.habit-detail-chart:has(.protocol-calendar) {
  max-width: 292px;
  margin: 12px auto 0;
}

.sw-panel {
  margin-bottom: 0;
}
/* --------------------------------------------------------------------------
   Habit calendar: month cards in a strip across the window; scrolls sideways past the edge
   -------------------------------------------------------------------------- */

.habit-detail-chart:has(.protocol-calendar) {
  max-width: none;
  margin: 14px 0 0;
  padding: 12px 14px 8px;
}

.protocol-calendar,
.protocol-calendar .pcal-head,
.protocol-calendar .pcal-foot {
  max-width: none;
}

.protocol-calendar {
  margin: 0;
}

.pcal-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 10px;
}

.pcal-bar .pcal-legend {
  margin-left: auto;
}

.pcal-bar .pcal-meta {
  gap: 4px;
}

.pcal-strip {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scroll-padding-inline: 2px;
  padding: 2px 2px 10px;
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
  outline: none;
}

.pcal-strip:focus-visible {
  box-shadow: 0 0 0 2px rgba(var(--accent-rgb), 0.4);
  border-radius: 10px;
}

.pcal-strip::-webkit-scrollbar {
  height: 6px;
}

.pcal-strip::-webkit-scrollbar-thumb {
  background: var(--border-strong);
  border-radius: 99px;
}

/* Each month grows to share the width when there's room, and never gets narrower than a
   readable calendar — so a few months fill the window and more of them scroll. */
.pcal-month {
  flex: 1 0 252px;
  min-width: 252px;
  scroll-snap-align: end;
  padding: 10px 10px 8px;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: rgba(var(--tint-rgb), 0.02);
}

.pcal-month-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 6px;
}

.pcal-month-head .pcal-count {
  margin: 0;
}

.pcal-month .pcal-day {
  height: 28px;
  font-size: 9.5px;
}

.pcal-nav:disabled {
  opacity: 0.3;
}

/* --------------------------------------------------------------------------
   Timer next to a dialog's title
   -------------------------------------------------------------------------- */

.modal-head {
  flex-wrap: wrap;
}

.modal-heading {
  flex: 1 1 200px;
}

.modal-head-extra {
  display: flex;
  align-items: center;
  align-self: center;
  margin: 8px 6px 0 auto;
}

.modal-head-extra .sw-main,
.modal-head-extra .sw-stop {
  height: 36px;
  font-size: 12px;
}

@media (max-width: 720px) {
  .modal-head-extra {
    order: 3;
    flex: 1 0 100%;
    margin: 10px 0 0;
  }

  .modal-head-extra .sw {
    width: 100%;
  }

  .modal-head-extra .sw-main {
    flex: 1;
    justify-content: center;
    height: 40px;
  }

  .modal-head-extra .sw-stop {
    height: 40px;
  }

  .modal-close {
    order: 2;
  }
}
/* The fixed menus don't fade or flicker: only their new state is shown. */
html.vt-page::view-transition-old(vt-topbar),
html.vt-page::view-transition-old(vt-sidebar),
html.vt-page::view-transition-old(vt-mnav) {
  display: none;
}

html.vt-page::view-transition-new(vt-topbar),
html.vt-page::view-transition-new(vt-sidebar),
html.vt-page::view-transition-new(vt-mnav) {
  animation: none;
  mix-blend-mode: normal;
}