/* Self-hosted Geist (variable, weights 100–900). Vendored from vercel/geist-font. */
@font-face {
  font-family: "Geist";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/assets/GeistSans-Variable-68b1bdfa.woff2") format("woff2");
}

@font-face {
  font-family: "Geist Mono";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/assets/GeistMono-Variable-774df0a9.woff2") format("woff2");
}

:root {
  /* Warm paper background */
  --color-bg-primary: #e7e1d3;
  --color-bg-secondary: #ddd5c4;
  --color-surface: #efe9dd;

  /* Cream/beige card colors */
  --color-card: #f5efe6;
  --color-card-secondary: #ebe5dc;
  --color-card-muted: #e0dbd3;

  /* Text colors. "Inverted" is the heading/label tier — historically cream
     on the dark shell, now ink on paper; the name is kept to avoid a rename
     across every view. Muted/light are the quiet tiers but must still clear
     ~4.5:1 on --color-bg-primary — they carry small uppercase labels. */
  --color-text-primary: #16140f;
  --color-text-secondary: #56544a;
  --color-text-muted: #5f5d51;
  --color-text-inverted: #16140f;
  --color-text-light: #6e685a;

  /* Orange/coral accent. --color-accent is for FILLS (buttons, the check-in
     card, checkboxes) where ink text sits on top; it fails contrast as text
     on paper — use --color-accent-text for links/labels/icons. */
  --color-accent: #ff6b35;
  --color-accent-hover: #e55a2b;
  --color-accent-subtle: rgba(255, 107, 53, 0.15);
  --color-accent-subtle-hover: rgba(255, 107, 53, 0.25);
  --color-accent-text: #b3492a;
  --color-accent-text-hover: #9c3f24;

  /* Borders */
  --color-border: rgba(22, 20, 15, 0.14);
  --color-border-strong: rgba(22, 20, 15, 0.28);
  --color-border-card: #ddd5c4;

  /* Status colors */
  --color-success: #4a8f5a;
  --color-warning: #d4a03c;
  --color-error: #c55050;
  --color-gold: #d4af37;
}

html {
  font-family: "Geist", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-size: 18px;
  line-height: 1.5;
}

h1, h2, h3 {
  font-family: "Geist", -apple-system, BlinkMacSystemFont, sans-serif;
  letter-spacing: -0.02em;
  font-weight: 700;
}

.font-display {
  font-family: "Geist", -apple-system, BlinkMacSystemFont, sans-serif;
  font-weight: 700;
}

body {
  letter-spacing: -0.01em;
  background-color: var(--color-bg-primary);
}

/* Card with clipped corners. On the paper shell, card-vs-page contrast is
   subtle, so cards carry a 1px ring. The clip-path clips borders and shadows
   at the beveled corners, so the ring is drawn inside the polygon instead:
   ::before paints the ring color across the whole card, ::after re-paints
   the card's own background 1px inset (background: inherit keeps utility
   classes like bg-card and hover:bg-card-muted working). Both sit below
   content via negative z-index (clip-path makes the card a stacking
   context, so -1 stays within the card). */
.card-clipped {
  background: var(--color-card);
  position: relative;
  clip-path: polygon(
    0 12px,
    12px 0,
    calc(100% - 12px) 0,
    100% 12px,
    100% calc(100% - 12px),
    calc(100% - 12px) 100%,
    12px 100%,
    0 calc(100% - 12px)
  );
}

.card-clipped::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--color-border-card);
}

.card-clipped::after {
  content: '';
  position: absolute;
  inset: 1px;
  z-index: -1;
  background: inherit;
  clip-path: polygon(
    0 11.4px,
    11.4px 0,
    calc(100% - 11.4px) 0,
    100% 11.4px,
    100% calc(100% - 11.4px),
    calc(100% - 11.4px) 100%,
    11.4px 100%,
    0 calc(100% - 11.4px)
  );
}

/* The check-in card stays the loudest thing on the page, but as a frame,
   not a fill: cream surface inside a 4px accent ring. Same pseudo-element
   ring technique as the base card, just thicker and orange — ::after's
   inset widens to 4px and the corner run shortens to keep the bevel
   parallel (0.6px per 1px of inset). */
.card-accent.card-clipped::before {
  background: var(--color-accent);
}

.card-accent.card-clipped::after {
  inset: 4px;
  clip-path: polygon(
    0 9.6px,
    9.6px 0,
    calc(100% - 9.6px) 0,
    100% 9.6px,
    100% calc(100% - 9.6px),
    calc(100% - 9.6px) 100%,
    9.6px 100%,
    0 calc(100% - 9.6px)
  );
}


/* Dotted separator */
.dotted-line {
  border: none;
  border-top: 1px dotted var(--color-text-muted);
  height: 0;
}

/* Diamond icon */
.diamond-icon {
  display: inline-block;
  width: 8px;
  height: 8px;
  background: currentColor;
  transform: rotate(45deg);
}

.diamond-icon-outline {
  display: inline-block;
  width: 8px;
  height: 8px;
  border: 1px solid currentColor;
  transform: rotate(45deg);
}

/* Section label style */
.section-label {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--color-accent-text);
}

.section-label::after {
  content: '';
  flex: 1;
  height: 0;
  border-top: 1px dotted var(--color-text-muted);
}

/* Card number badge */
.card-number {
  font-family: 'Inter', sans-serif;
  font-size: 0.65rem;
  color: var(--color-text-muted);
  letter-spacing: 0.05em;
}

/* Accent card (orange-framed; ring painted by the card-clipped overrides) */
.card-accent {
  background: var(--color-card);
}

/* Form inputs on cards */
.input-card {
  background: rgba(255, 255, 255, 0.5);
  border: 1px solid var(--color-border-card);
  color: var(--color-text-primary);
}

.input-card:focus {
  outline: none;
  border-color: var(--color-accent);
  background: rgba(255, 255, 255, 0.7);
}

/* Button on cards */
.btn-card {
  background: var(--color-text-primary);
  color: var(--color-card);
  font-weight: 500;
  transition: all 0.2s;
}

.btn-card:hover {
  background: var(--color-text-secondary);
}

/* Month navigation bar */
.month-nav {
  display: flex;
  gap: 0;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--color-text-light);
}

.month-nav a,
.month-nav span {
  position: relative;
  padding: 0.5rem 1rem;
  border-right: 1px solid var(--color-border);
  transition: color 0.15s;
}

.month-nav a:last-child,
.month-nav span:last-child {
  border-right: none;
}

.month-nav .active {
  color: var(--color-text-inverted);
}

/* Linked months (those overlapping a cycle) light up on hover. */
.month-nav a:hover {
  color: var(--color-text-inverted);
}

/* Months with no cycle data are dimmed and non-interactive. */
.month-nav .dim {
  opacity: 0.4;
  pointer-events: none;
}

/* Underline segment marking months inside a cycle; adjacent in-cycle
   months butt together so a cycle span reads as one contiguous run. */
.month-nav .in-cycle::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: var(--color-accent);
  opacity: 0.45;
}

/* Turbo's page-load progress bar, in the house accent instead of default blue.
   Text-tier accent: the fill orange washes out as a hairline on paper. */
.turbo-progress-bar {
  background: var(--color-accent-text);
}

/* 12-week journey track */
.week-journey {
  display: flex;
  align-items: center;
  gap: 4px;
}

.week-journey__stop {
  flex: 1;
  height: 4px;
  border-radius: 2px;
  background: var(--color-border);
  transition: background-color 0.15s, height 0.15s;
}

/* Weeks already behind the displayed week: subtle accent fill. */
.week-journey__stop.completed {
  background: color-mix(in srgb, var(--color-accent) 35%, transparent);
}

/* The displayed week: emphasized, taller, full accent. */
.week-journey__stop.current {
  height: 10px;
  background: var(--color-accent);
}

/* Weeks still ahead: dim outline only. */
.week-journey__stop.future {
  background: transparent;
  border: 1px solid var(--color-border);
}

/* Progress card: the current tier breathes a soft glow in its own color. */
.tier-current {
  animation: tier-breathe 3.2s ease-in-out infinite;
}

@keyframes tier-breathe {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--tier-color) 0%, transparent); filter: brightness(1); }
  50%      { box-shadow: 0 0 10px 1px color-mix(in srgb, var(--tier-color) 55%, transparent); filter: brightness(1.08); }
}

@media (prefers-reduced-motion: reduce) {
  .tier-current { animation: none; }
}

/* Weeks with a score take their tier color (pace for the week in progress,
   the final result for finished weeks). Set per stop as --stop-color. */
.week-journey__stop.scored {
  background: var(--stop-color);
  border: none;
}

.week-journey__stop:hover {
  background: var(--color-text-light);
}

.week-journey__stop.current:hover {
  background: var(--color-accent-hover);
}

.week-journey__stop.scored:hover {
  background: color-mix(in srgb, var(--stop-color) 80%, var(--color-text-primary));
}

@media (max-width: 639px) {
  .dashboard-header {
    margin-bottom: 0.5rem;
    padding-bottom: 0.5rem;
  }
}

/* Every weekday shares fixed label, goal-cell, and total tracks. Large goal
   sets scroll as one grid instead of shrinking each row by its text width. */
.daily-completion-scroll { min-width: 0; max-width: 100%; overflow-x: auto; }
.daily-completion-grid { width: max-content; min-width: 100%; }
.daily-completion-row {
  display: grid;
  grid-template-columns: 1.75rem max-content 2.5rem;
  align-items: center;
  gap: 0.375rem;
  margin-block: 0.3rem;
}
.daily-completion-cells { display: flex; gap: 0.125rem; }
.daily-completion-cell { display: block; flex: 0 0 0.375rem; width: 0.375rem; height: 0.375rem; }
.daily-completion-total { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ── Today's Check-in: checkbox and celebrations ─────────────────────────────
   Ink outline that fills accent when done, so completed habits read as bursts
   of orange on the cream surface. The check draws via a masked ::before so it
   can animate. Everyday ticks get
   one of glow / pop / draw at random; celebrate-moment is for meeting a weekly
   target or finishing the day. See celebrate_controller.js. */
.check-box {
  appearance: none;
  -webkit-appearance: none;
  position: relative;
  flex: none;
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  margin: 0;
  border: 2px solid var(--color-text-primary);
  border-radius: 3px;
  background: transparent;
  cursor: pointer;
  transition: background-color 0.15s, border-color 0.15s;
}

.check-box::before {
  content: "";
  width: 13px;
  height: 13px;
  background: var(--color-text-primary);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Cpath d='M2.5 7.4l3 3 6-6.6' fill='none' stroke='black' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Cpath d='M2.5 7.4l3 3 6-6.6' fill='none' stroke='black' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
  clip-path: inset(0 100% 0 0);
}

.check-box:checked {
  background: var(--color-accent);
  border-color: var(--color-accent);
}

.check-box:checked::before {
  clip-path: inset(0 0 0 0);
}

.check-box:focus-visible {
  outline: 2px solid var(--color-accent-text);
  outline-offset: 2px;
}

.check-box::after {
  content: "";
  position: absolute;
  inset: -2px;
  border: 2px solid var(--color-accent);
  border-radius: 4px;
  opacity: 0;
  pointer-events: none;
}

.celebrate-row {
  position: relative;
  isolation: isolate;
  overflow: hidden;
}

/* Glow: a soft halo and a ring that expands and fades. */
.celebrate-glow .check-box { animation: celebrate-halo 0.55s ease-out; }
.celebrate-glow .check-box::after { animation: celebrate-ring 0.55s ease-out; }

/* Pop: the box springs past full size and settles (sparks come from JS). */
.celebrate-pop .check-box { animation: celebrate-pop 0.45s cubic-bezier(0.34, 1.56, 0.64, 1); }

/* Draw: the check draws itself while a sheen crosses the row. */
.celebrate-draw .check-box { animation: celebrate-settle 0.34s ease-out; }
.celebrate-draw .check-box::before { animation: celebrate-draw 0.34s 0.06s ease-out both; }
.celebrate-row::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(100deg, transparent 20%, rgba(255, 255, 255, 0.75) 50%, transparent 80%);
  transform: translateX(-110%);
  pointer-events: none;
}
.celebrate-draw::before { animation: celebrate-sheen 0.75s ease-out; }

/* Moment: weekly target met or the whole day done. */
.celebrate-moment { animation: celebrate-flash 0.9s ease-out; }
.celebrate-moment .check-box { animation: celebrate-pop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1); }
.celebrate-moment .check-box::after { animation: celebrate-ring 0.6s ease-out; }

.celebrate-spark {
  position: fixed;
  z-index: 60;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  pointer-events: none;
}
.celebrate-spark--bar { width: 3px; height: 8px; border-radius: 1px; }

.celebrate-banner {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  border: 1px solid color-mix(in srgb, var(--color-gold) 55%, transparent);
  background: linear-gradient(100deg,
    color-mix(in srgb, var(--color-gold) 16%, transparent),
    color-mix(in srgb, var(--color-gold) 30%, transparent),
    color-mix(in srgb, var(--color-gold) 16%, transparent));
  background-size: 200% 100%;
  color: #6b5410;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.celebrate-banner svg { width: 14px; height: 14px; flex: none; fill: var(--color-gold); }
.celebrate-banner.is-arriving {
  animation: celebrate-banner-in 0.5s cubic-bezier(0.34, 1.56, 0.64, 1), celebrate-shimmer 2.4s 0.5s ease-in-out 2;
}

@keyframes celebrate-halo {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--color-accent) 55%, transparent); }
  100% { box-shadow: 0 0 14px 6px transparent; }
}
@keyframes celebrate-ring {
  0%   { opacity: 0.8; transform: scale(1); }
  100% { opacity: 0; transform: scale(2.2); }
}
@keyframes celebrate-pop {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.32); }
  65%  { transform: scale(0.94); }
  100% { transform: scale(1); }
}
@keyframes celebrate-settle { from { transform: scale(0.85); } to { transform: scale(1); } }
@keyframes celebrate-draw { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes celebrate-sheen { to { transform: translateX(110%); } }
@keyframes celebrate-flash {
  from { background-color: color-mix(in srgb, var(--color-gold) 45%, transparent); }
}
@keyframes celebrate-banner-in {
  from { opacity: 0; transform: translateY(6px) scale(0.97); }
  to   { opacity: 1; transform: none; }
}
@keyframes celebrate-shimmer {
  0%, 100% { background-position: 0% 0; }
  50%      { background-position: 100% 0; }
}

@media (prefers-reduced-motion: reduce) {
  .check-box, .check-box::before, .check-box::after, .celebrate-row, .celebrate-row::before, .celebrate-banner {
    animation: none !important;
    transition: none !important;
  }
}

/* ── Cycle lifecycle: plan next, final stretch ──────────────────────────────
   Choice cards on "Plan your next 12 weeks". The chosen card takes the
   accent ring (the card-clipped ::before) and a faint accent wash, which the
   ::after re-paints via background: inherit. */
.plan-choice__radio {
  width: 1rem;
  height: 1rem;
  accent-color: var(--color-accent-text);
}
.plan-choice:has(.plan-choice__radio:checked) {
  background: color-mix(in srgb, var(--color-accent) 7%, var(--color-card));
}
.plan-choice:has(.plan-choice__radio:checked)::before,
.plan-choice:has(.plan-choice__radio:focus-visible)::before {
  background: var(--color-accent-text);
}
/* "Start blank" hides the carry-over checklist without any JS. */
.plan-next-goals:has(input[name="goals"][value="blank"]:checked) .plan-next-goals__list {
  display: none;
}

/* The countdown beside the week number in the cycle's last fourteen days. */
.final-stretch-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.15rem 0.5rem;
  border: 1px solid color-mix(in srgb, var(--color-accent-text) 45%, transparent);
  background: var(--color-accent-subtle);
  /* The darker accent: plain accent-text on the orange wash is only 3.6:1. */
  color: var(--color-accent-text-hover);
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  white-space: nowrap;
}
.final-stretch-chip::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--color-accent);
}

/* ── Review ceremony: "12 weeks. Done." ───────────────────────────────────────
   Opens the review once a cycle has ended (cycle_wrap_controller.js). The
   card carries a gold ring; bars take their tier color via --bar-color and
   rise in order via --i. Timings here match the controller's constants. */
.cycle-wrap::before {
  background: color-mix(in srgb, var(--color-gold) 55%, var(--color-border-card));
}
.cycle-wrap__title {
  font-size: clamp(3rem, 11vw, 5.25rem);
  line-height: 0.92;
  letter-spacing: -0.045em;
}
.cycle-wrap__count {
  font-size: clamp(4rem, 14vw, 6.5rem);
  letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums;
}
.cycle-wrap__bars {
  display: grid;
  gap: 4px;
  height: 7.5rem;
  align-items: end;
}
.cycle-wrap__track {
  display: flex;
  align-items: flex-end;
  height: 100%;
  background: var(--color-card-secondary);
}
.cycle-wrap__track--empty {
  background: transparent;
  border: 1px dashed var(--color-border-card);
}
.cycle-wrap__bar {
  display: block;
  width: 100%;
  height: var(--h);
  background: var(--bar-color);
  transform-origin: bottom;
}

@media (prefers-reduced-motion: no-preference) {
  .cycle-wrap.is-landed .cycle-wrap__grade { animation: cycle-wrap-land 0.55s cubic-bezier(0.34, 1.56, 0.64, 1); }
  .cycle-wrap__title { animation: cycle-wrap-enter 0.7s cubic-bezier(0.2, 0.7, 0.3, 1) both; }
  .cycle-wrap__count { animation: cycle-wrap-fade 0.3s 0.12s both; }
  .cycle-wrap__bar {
    animation: cycle-wrap-rise 0.6s cubic-bezier(0.2, 0.8, 0.3, 1.12) both;
    animation-delay: calc(350ms + var(--i) * 90ms);
  }
}

@keyframes cycle-wrap-enter {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}
@keyframes cycle-wrap-fade { from { opacity: 0; } }
@keyframes cycle-wrap-rise {
  from { transform: scaleY(0); }
  to   { transform: scaleY(1); }
}
@keyframes cycle-wrap-land {
  0%   { transform: scale(1); box-shadow: 0 0 0 0 color-mix(in srgb, var(--color-gold) 60%, transparent); }
  40%  { transform: scale(1.18); }
  100% { transform: scale(1); box-shadow: 0 0 0 10px transparent; }
}

/* ── Start fresh: "Begin again." ─────────────────────────────────────────────
   The /fresh_start page (fresh_start_controller.js). The markup is the end
   state: the running cycle's weeks filed away as a small archived stack, and
   a fresh row of twelve empty weeks with week one aglow. On load the story
   plays in order, all from CSS: the old bars rise at full width, settle into
   the stack, then the fresh row draws in and week one lights. Reduced motion
   (and no-JS) sees the end state as-is.

   The settle is a transform, not a layout change: the archived bars take
   --archive-w percent of the stage, so scaling them by 100 / --archive-w
   from their top-left corner fills the stage exactly, at any width. Every
   delay derives from --bars (the old cycle's weeks). */
.fresh-start {
  background:
    radial-gradient(90% 55% at 50% 0%, color-mix(in srgb, var(--color-accent) 9%, transparent), transparent 70%);
}
.fresh-start__title {
  font-size: clamp(3rem, 12.5vw, 5.75rem);
  line-height: 0.92;
  letter-spacing: -0.045em;
}

.fresh-start__stage {
  --archive-w: 38;
  --archive-h: 2.5rem;
  --intro-y: 3;
  --rise-at: 420ms;
  --rise-step: 70ms;
  --rise: 560ms;
  --settle-at: calc(var(--rise-at) + (var(--bars) - 1) * var(--rise-step) + var(--rise) + 600ms);
  --settle: 1000ms;
  --draw-at: calc(var(--settle-at) + 650ms);
  --draw-step: 55ms;
  --light-at: calc(var(--draw-at) + 11 * var(--draw-step) + 360ms);
  position: relative;
  display: block;
  margin-inline: 0;
  padding: 1.5rem 1.25rem 1.25rem;
}
@media (min-width: 640px) {
  .fresh-start__stage {
    --archive-w: 30;
    --archive-h: 2.75rem;
    padding: 2rem 2rem 1.5rem;
  }
}

/* The archived stack: small filed bars beside their label. */
.fresh-start__archive {
  display: flex;
  align-items: center;
  gap: 1.1rem;
  min-height: var(--archive-h);
}
.fresh-start__file {
  position: relative;
  flex: 0 0 calc(var(--archive-w) * 1%);
  height: var(--archive-h);
}
/* Two sheets under the filed card: kept, not gone. */
.fresh-start__file::before {
  content: "";
  position: absolute;
  inset: -6px -7px;
  background: var(--color-card-secondary);
  border: 1px solid var(--color-border-card);
  box-shadow:
    3px 3px 0 -1px var(--color-card), 3px 3px 0 0 var(--color-border-card),
    6px 6px 0 -1px var(--color-card), 6px 6px 0 0 var(--color-border-card);
}
.fresh-start__bars {
  position: relative;
  display: grid;
  gap: 2px;
  align-items: end;
  height: 100%;
  transform-origin: 0 0;
  filter: saturate(0.72);
}
.fresh-start__track {
  display: flex;
  align-items: flex-end;
  height: 100%;
  background: color-mix(in srgb, var(--color-card) 55%, var(--color-card-secondary));
}
/* Weeks with no check-ins stay hollow. */
.fresh-start__track--missed {
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--color-border-strong);
}
.fresh-start__bar {
  display: block;
  width: 100%;
  height: var(--h);
  background: var(--bar-color);
  transform-origin: bottom;
}
.fresh-start__archive-label {
  min-width: 0;
  font-size: 0.7rem;
  line-height: 1.45;
  letter-spacing: 0.02em;
  color: var(--color-text-secondary);
}
.fresh-start__archive-dates {
  display: block;
  margin-top: 0.15rem;
  font-size: 0.6rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}

/* The fresh twelve weeks, week one aglow with day one filled in. */
.fresh-start__fresh {
  position: relative;
  margin-top: 2rem;
}
/* Dawn behind week one. */
.fresh-start__fresh::before {
  content: "";
  position: absolute;
  left: -3rem;
  top: -2.5rem;
  width: 12rem;
  height: 8.5rem;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--color-accent) 18%, transparent), transparent);
  pointer-events: none;
}
.fresh-start__row {
  position: relative;
  display: grid;
  gap: 4px;
  margin: 0;
  padding: 0;
  list-style: none;
}
@media (min-width: 640px) {
  .fresh-start__row { gap: 6px; }
}
.fresh-start__week {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.35rem;
}
.fresh-start__cell {
  position: relative;
  display: block;
  height: 3rem;
  border: 1px solid var(--color-border-strong);
  background: color-mix(in srgb, var(--color-card) 70%, transparent);
}
.fresh-start__week--first .fresh-start__cell {
  border-color: var(--color-accent);
  background: var(--color-accent-subtle);
  box-shadow: 0 0 12px 1px color-mix(in srgb, var(--color-accent) 35%, transparent);
}
.fresh-start__day {
  position: absolute;
  inset: auto 0 0 0;
  height: calc(100% / 7);
  background: var(--color-accent);
  transform-origin: bottom;
}
.fresh-start__num {
  font-size: 0.55rem;
  text-align: center;
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}
.fresh-start__week--first .fresh-start__num {
  color: var(--color-accent-text);
  font-weight: 700;
}
.fresh-start__caption {
  position: relative;
  margin-top: 1rem;
  font-size: 0.65rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}
.fresh-start__today {
  font-weight: 600;
  color: var(--color-accent-text);
}
/* Only seen while the old bars stand at full size. */
.fresh-start__so-far {
  position: absolute;
  left: 1.25rem;
  bottom: 1.25rem;
  margin: 0;
  font-size: 0.65rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--color-text-muted);
  opacity: 0;
  pointer-events: none;
}
@media (min-width: 640px) {
  .fresh-start__so-far { left: 2rem; bottom: 1.5rem; }
}
.fresh-start__note {
  padding-left: 1rem;
  border-left: 2px solid color-mix(in srgb, var(--color-accent) 55%, transparent);
}

@media (prefers-reduced-motion: no-preference) {
  .fresh-start.is-playing .fresh-start__eyebrow { animation: fresh-rise-in 0.6s both; }
  .fresh-start.is-playing .fresh-start__title { animation: fresh-rise-in 0.8s 0.06s cubic-bezier(0.2, 0.7, 0.3, 1) both; }
  .fresh-start.is-playing .fresh-start__lede { animation: fresh-rise-in 0.7s 0.18s both; }
  .fresh-start.is-playing .fresh-start__stage { animation: fresh-fade 0.5s 0.2s both; }

  /* 1. The old weeks rise at full width, one by one. */
  .fresh-start.is-playing .fresh-start__bar {
    animation: fresh-bar-rise var(--rise) calc(var(--rise-at) + var(--i) * var(--rise-step)) cubic-bezier(0.2, 0.8, 0.3, 1.12) both;
  }
  .fresh-start.is-playing .fresh-start__track--missed {
    animation: fresh-fade var(--rise) calc(var(--rise-at) + var(--i) * var(--rise-step)) both;
  }
  .fresh-start.is-playing .fresh-start__so-far {
    animation: fresh-fade-out 0.35s var(--settle-at) both;
  }

  /* 2. They settle into the small archived stack, filed and labeled. */
  .fresh-start.is-playing .fresh-start__bars {
    animation: fresh-settle var(--settle) var(--settle-at) cubic-bezier(0.65, 0, 0.25, 1) both;
  }
  .fresh-start.is-playing .fresh-start__file::before {
    animation: fresh-file 0.55s calc(var(--settle-at) + var(--settle) - 200ms) cubic-bezier(0.2, 0.7, 0.3, 1) both;
  }
  .fresh-start.is-playing .fresh-start__archive-label {
    animation: fresh-rise-in 0.6s calc(var(--settle-at) + var(--settle) - 100ms) both;
  }

  /* 3. A fresh row of twelve draws in, and week one lights up. */
  .fresh-start.is-playing .fresh-start__week {
    animation: fresh-draw 0.42s calc(var(--draw-at) + var(--c) * var(--draw-step)) cubic-bezier(0.2, 0.7, 0.3, 1) both;
  }
  .fresh-start.is-playing .fresh-start__week--first .fresh-start__cell {
    animation:
      fresh-light 0.7s var(--light-at) cubic-bezier(0.34, 1.56, 0.64, 1) both,
      fresh-glow 3.2s calc(var(--light-at) + 700ms) ease-in-out infinite;
  }
  .fresh-start.is-playing .fresh-start__day {
    animation: fresh-fill 0.5s calc(var(--light-at) + 180ms) cubic-bezier(0.2, 0.7, 0.3, 1) both;
  }
  .fresh-start.is-playing .fresh-start__fresh::before,
  .fresh-start.is-playing .fresh-start__caption {
    animation: fresh-fade 0.8s var(--light-at) both;
  }

  /* Settled: week one keeps breathing. */
  .fresh-start:not(.is-playing) .fresh-start__week--first .fresh-start__cell {
    animation: fresh-glow 3.2s ease-in-out infinite;
  }

  /* Committing: the fresh row redraws quickly and week one lights again
     (the controller bursts sparks from it, then submits). */
  .fresh-start__stage.is-committing .fresh-start__week {
    animation: fresh-draw 0.3s calc(var(--c) * 35ms) cubic-bezier(0.2, 0.7, 0.3, 1) both;
  }
  .fresh-start__stage.is-committing .fresh-start__week--first .fresh-start__cell {
    animation: fresh-light 0.6s 0.45s cubic-bezier(0.34, 1.56, 0.64, 1) both, fresh-glow 1.6s 1.05s ease-in-out infinite;
  }
  .fresh-start__stage.is-committing .fresh-start__day {
    animation: fresh-fill 0.4s 0.6s cubic-bezier(0.2, 0.7, 0.3, 1) both;
  }
}

@keyframes fresh-rise-in {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: none; }
}
@keyframes fresh-fade { from { opacity: 0; } }
@keyframes fresh-fade-out {
  from { opacity: 1; }
  to   { opacity: 0; }
}
@keyframes fresh-bar-rise {
  from { transform: scaleY(0); }
  to   { transform: scaleY(1); }
}
@keyframes fresh-settle {
  from { transform: scale(calc(100 / var(--archive-w)), var(--intro-y)); filter: saturate(1); }
  to   { transform: none; filter: saturate(0.72); }
}
@keyframes fresh-file {
  from { opacity: 0; transform: translate(-4px, -4px); }
  to   { opacity: 1; transform: none; }
}
@keyframes fresh-draw {
  from { opacity: 0; transform: translateY(10px) scaleY(0.5); }
  to   { opacity: 1; transform: none; }
}
@keyframes fresh-light {
  0% {
    border-color: var(--color-border-strong);
    background-color: transparent;
    box-shadow: 0 0 0 0 color-mix(in srgb, var(--color-accent) 70%, transparent);
    transform: scale(1);
  }
  45% { transform: scale(1.14); }
  100% {
    border-color: var(--color-accent);
    background-color: var(--color-accent-subtle);
    box-shadow: 0 0 28px 8px transparent;
    transform: scale(1);
  }
}
@keyframes fresh-glow {
  0%, 100% { box-shadow: 0 0 6px 0 color-mix(in srgb, var(--color-accent) 25%, transparent); }
  50%      { box-shadow: 0 0 18px 3px color-mix(in srgb, var(--color-accent) 50%, transparent); }
}
@keyframes fresh-fill {
  from { transform: scaleY(0); }
  to   { transform: scaleY(1); }
}

/* Dashboard: the gentle lapse banner (a row of twelve, the first aglow), and
   the one-time "Week 1 · Day 1" arrival after a restart begins. */
.fresh-start-banner__weeks {
  display: none;
  flex: none;
  gap: 3px;
}
@media (min-width: 640px) {
  .fresh-start-banner__weeks { display: flex; }
}
.fresh-start-banner__weeks span {
  width: 5px;
  height: 22px;
  border: 1px solid var(--color-border-strong);
}
.fresh-start-banner__weeks span:first-child {
  border-color: var(--color-accent);
  background: var(--color-accent);
}

.fresh-arrival {
  background: color-mix(in srgb, var(--color-accent) 8%, var(--color-card));
}
.fresh-arrival.card-clipped::before {
  background: color-mix(in srgb, var(--color-accent) 70%, var(--color-border-card));
}
.fresh-arrival__badge {
  display: grid;
  place-items: center;
  flex: none;
  width: 2.75rem;
  height: 2.75rem;
  background: var(--color-accent);
  color: var(--color-text-primary);
  font-weight: 700;
  font-size: 1.25rem;
  font-variant-numeric: tabular-nums;
  box-shadow: 0 0 14px 2px color-mix(in srgb, var(--color-accent) 40%, transparent);
}
@media (prefers-reduced-motion: no-preference) {
  .fresh-start-banner__weeks span:first-child { animation: fresh-glow 3.2s ease-in-out infinite; }
  .fresh-arrival.is-arriving { animation: celebrate-banner-in 0.55s cubic-bezier(0.34, 1.56, 0.64, 1) both; }
  .fresh-arrival.is-arriving .fresh-arrival__badge {
    animation: fresh-pop 0.6s 0.2s cubic-bezier(0.34, 1.56, 0.64, 1) both, fresh-glow 3.2s 0.9s ease-in-out infinite;
  }
}
@keyframes fresh-pop {
  0%   { opacity: 0; transform: scale(0.5); }
  55%  { opacity: 1; transform: scale(1.18); }
  100% { opacity: 1; transform: scale(1); }
}

/* A cycle closed by Start fresh, wherever cycles are listed. */
.ended-early-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.15rem 0.5rem;
  border: 1px solid var(--color-border-strong);
  color: var(--color-text-secondary);
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  white-space: nowrap;
}
.ended-early-chip::before {
  content: "";
  width: 6px;
  height: 6px;
  border: 1px solid currentColor;
  border-radius: 50%;
}
