/* ==========================================================================
   Goal Tracker — semantic component layer
   ==========================================================================

   HOW TO USE THIS FILE

   1. DESIGN TOKENS (:root, below) are the knobs. Change the page
      background, fonts, surface colour, borders, radii or shadows in one
      place and every component follows.

   2. COMPONENT CLASSES describe what a thing *is* (.section-card,
      .page-title, .btn--primary) rather than how it looks. Templates use
      these instead of long Tailwind strings.

   3. TAILWIND UTILITIES ARE STILL USED for one-off layout — grid columns,
      flex alignment, spacing between specific elements. That's deliberate:
      naming every layout wrapper would trade one kind of noise for
      another. The rule of thumb is: appearance lives here, arrangement
      stays inline.

   Load order matters: Tailwind's CDN injects its stylesheet after this
   file, so a utility class in a template still overrides a component
   style when you need a one-off exception.
   ========================================================================== */

:root {
  /* Tells the browser which way to render scrollbars, form
     controls and other native chrome. Flipped by data-mode below. */
  color-scheme: light;

  /* ---- Typography ------------------------------------------------------ */
  --font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
               'Inter', sans-serif;
  --font-heading: var(--font-sans);
  --font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;

  /* ---- Surfaces -------------------------------------------------------- */
  --color-canvas: #e6eed8;          /* page background (soft pistachio) */
  --color-surface: #ffffff;         /* cards, sections, panels */
  --color-surface-sunken: #f8fafc;  /* nested panels inside a card */
  --color-surface-muted: #f1f5f9;   /* count pills, code, progress track */
  --color-surface-raised: #e2e8f0;  /* hover on an already-muted surface */

  /* ---- Lines ----------------------------------------------------------- */
  --color-border: #e2e8f0;          /* card borders */
  --color-border-subtle: #f1f5f9;   /* list dividers */
  --color-border-strong: #cbd5e1;   /* form inputs, habit-grid cells */

  /* ---- Brand accent ---------------------------------------------------- */
  --color-accent: #0f766e;          /* accent text */
  --color-accent-hover: #115e59;
  --color-accent-solid: #0d9488;    /* filled buttons */
  --color-accent-solid-hover: #0f766e;
  --color-accent-tint: #d8e6ee;     /* section header wash */
  --color-accent-ring: #14b8a6;     /* focus rings */
  --color-accent-edge: #2dd4bf;     /* hover borders */
  --color-accent-edge-soft: #5eead4; /* the "current" outline */
  --color-accent-line: #eed8e6;     /* section header border */

  /* ---- Text ------------------------------------------------------------ */
  --color-text: #1e293b;
  --color-text-strong: #0f172a;
  --color-text-muted: #64748b;
  --color-text-faint: #94a3b8;
  --color-text-on-accent: #ffffff;

  /* ---- Feedback -------------------------------------------------------- */
  --color-info-bg: #f0f9ff;         /* informational callouts */
  --color-info-text: #075985;
  --color-info-line: rgb(2 132 199 / 0.2);
  --color-tip-bg: #fffbeb;          /* "tip" callouts */
  --color-tip-text: #78350f;
  --color-tip-line: rgb(217 119 6 / 0.2);
  --color-today-bg: #fef3c7;        /* today's column in the habits grid */
  --color-today-text: #78350f;
  --color-success-bg: #ecfdf5;      /* success panels / headers */
  --color-success-text: #065f46;
  --color-success-line: #a7f3d0;
  --color-warning-solid: #f59e0b;   /* extend-deadline button */
  --color-warning-solid-hover: #d97706;
  --color-code-bg: #0f172a;
  --color-code-text: #e2e8f0;
  --color-danger: #e11d48;
  --color-danger-hover: #be123c;
  --color-danger-bg: #fff1f2;
  --color-danger-text: #be123c;
  --color-danger-line: #fecdd3;
  --color-success-solid: #059669;
  --color-success-solid-hover: #047857;

  /* ---- Shape & depth --------------------------------------------------- */
  --radius-section: 1rem;
  --radius-control: 0.375rem;
  --radius-pill: 9999px;
  --shadow-section: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
  --shadow-section-hover: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
  --shadow-control: 0 1px 2px 0 rgb(0 0 0 / 0.05);
  --shadow-overlay: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);

  /* ---- Branding -------------------------------------------------------- */
  --logo-size: 2.25rem;             /* header logo width/height */
  --radius-logo: 0.5rem;            /* app-icon style corner on the logo */

  /* ---- Habits grid ----------------------------------------------------- */
  --day-cell-size: 2.25rem;         /* toggle square AND its column width */
  --habit-name-col: 280px;          /* habit-name column */

  /* ---- Spacing --------------------------------------------------------- */
  --space-section-x: 1.25rem;
  --space-section-y: 0.75rem;
  --space-body: 1.5rem;
}

/* ==========================================================================
   Theme: Notebook  (light)

   After a Leuchtturm1917: a saffron cover, the cream belly band, warm
   charcoal print. The band is the page, the pages are the cards, and
   the saffron carries the accents — a full-bleed cover orange would
   shout, and this app is meant to be quiet.

   Only tokens change. Every component class above stays as it is.
   ========================================================================== */

:root[data-theme="notebook"] {
  --color-canvas: #e9dfc8;          /* the belly band */
  --color-surface: #fdfbf5;         /* paper */
  --color-surface-sunken: #f6f0e2;
  --color-surface-muted: #efe7d5;
  --color-surface-raised: #e4dac2;

  --color-border: #ddd1b6;
  --color-border-subtle: #ebe3d1;
  --color-border-strong: #c9bb9c;

  /* Saffron, darkened until it holds its own as text and as a button
     label's backing. The cover colour itself lives in the tint. */
  --color-accent: #a14a0a;
  --color-accent-hover: #7e3907;
  --color-accent-solid: #b25a0e;
  --color-accent-solid-hover: #8f460a;
  --color-accent-tint: #f7e8c6;
  --color-accent-line: #e9d5a8;
  --color-accent-ring: #c2660b;
  --color-accent-edge: #d9913a;
  --color-accent-edge-soft: #e0b070;

  --color-text: #2b2521;
  --color-text-strong: #16110d;
  --color-text-muted: #6b6053;
  --color-text-faint: #9c8f7c;

  --color-info-bg: #eaf2f7;
  --color-info-text: #1f4f6b;
  --color-info-line: rgb(31 79 107 / 0.2);
  --color-tip-bg: #fbf0d6;
  --color-tip-text: #7a4e09;
  --color-tip-line: rgb(178 90 14 / 0.25);
  --color-today-bg: #f7e3b0;
  --color-today-text: #7a4e09;
  --color-success-bg: #e8f0e2;
  --color-success-text: #3d5b2e;
  --color-success-line: #c3d6b4;
  --color-warning-solid: #d98c0c;
  --color-warning-solid-hover: #b4720a;
  --color-code-bg: #2b2521;
  --color-code-text: #efe7d5;

  /* A cooler crimson than the accent, so "behind" never reads as brand. */
  --color-danger: #b3261e;
  --color-danger-hover: #8e1d17;
  --color-danger-bg: #f9e8e4;
  --color-danger-text: #8e1d17;
  --color-danger-line: #e8c6bd;
  --color-success-solid: #4f7a3a;
  --color-success-solid-hover: #3d5f2d;
}

/* ==========================================================================
   Touch behaviour  (iOS / iPadOS)
   ========================================================================== */

/* Kill the grey flash on tap and the long-press callout menu on things
   that act as controls. */
a, button, [role="button"], summary, label {
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

/* Removes the 300ms delay browsers reserve for double-tap-to-zoom. */
a, button, [role="button"], input, select, textarea {
  touch-action: manipulation;
}

/* Hover styles latch on after a tap on touch screens, leaving controls
   stuck in a highlighted state. Only apply them where hover is real. */
@media (hover: none) {
  .section-card--link:hover { box-shadow: var(--shadow-section); }
  .section-row--link:hover { background-color: transparent; }
  .btn--secondary:hover { border-color: var(--color-border); color: var(--color-text); }
  .quick-habit:hover { border-color: var(--color-border); background-color: var(--color-surface); }
  .quick-habit--done:hover { background-color: var(--color-accent-solid); }
}

/* Minimum comfortable touch target (Apple HIG is 44pt). Applied to the
   controls that were smallest. */
@media (pointer: coarse) {
  .btn { min-height: 2.75rem; }
  .btn--sm { min-height: 2.5rem; }
  .nav-link { padding-block: 0.25rem; }
  /* 44pt targets in the habits grid — moving the token keeps the columns
     in step with the squares. */
  :root { --day-cell-size: 2.75rem; }
}

/* Narrow phones: give the day columns room by shrinking the name column
   (the grid scrolls horizontally; quick-log is the better phone surface). */
@media (max-width: 640px) {
  :root { --habit-name-col: 170px; }
}

/* Keep horizontal scroll (the habits grid) from chaining to the page and
   triggering back-swipe navigation. */
.overflow-x-auto { overscroll-behavior-x: contain; }

/* ==========================================================================
   App shell
   ========================================================================== */

.app-canvas {
  background-color: var(--color-canvas);
}

.app-body {
  font-family: var(--font-sans);
  color: var(--color-text);
  -webkit-font-smoothing: antialiased;
}

/* Safe-area padding keeps content clear of the notch, Dynamic Island and
   home indicator when launched standalone from the iOS home screen.
   env() resolves to 0 everywhere else, so this is inert in a browser. */
.app-container {
  margin-inline: auto;
  max-width: 72rem;
  padding-top: calc(2rem + env(safe-area-inset-top));
  padding-bottom: calc(2rem + env(safe-area-inset-bottom));
  padding-left: calc(1rem + env(safe-area-inset-left));
  padding-right: calc(1rem + env(safe-area-inset-right));
}

@media (min-width: 640px) {
  .app-container {
    padding-left: calc(1.5rem + env(safe-area-inset-left));
    padding-right: calc(1.5rem + env(safe-area-inset-right));
  }
}

@media (min-width: 1024px) {
  .app-container {
    padding-left: calc(2rem + env(safe-area-inset-left));
    padding-right: calc(2rem + env(safe-area-inset-right));
  }
}

/* Large iPads in landscape: use the extra width rather than leaving deep
   empty margins. */
@media (min-width: 1400px) { .app-container { max-width: 84rem; } }

/* Below --nav-breakpoint the nav collapses behind a menu button; above
   it, brand and links share one row as before. */
.app-topbar {
  margin-bottom: 1.5rem;
  padding-bottom: 0.75rem;
  border-bottom: 1px solid var(--color-accent-line);
}

.app-topbar-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.nav-toggle {
  margin-left: auto;
  display: inline-flex;
  height: 2.75rem;
  width: 2.75rem;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-control);
  color: var(--color-text-muted);
}

/* The menu icon's two states are toggled with Alpine x-show on <g>
   elements, deliberately not x-if. A template element parsed inside an
   svg is not an HTMLTemplateElement, so Alpine has no content fragment
   to clone and the icon renders as nothing at all. */
.nav-toggle svg { height: 1.5rem; width: 1.5rem; }
.nav-toggle:hover { color: var(--color-accent); background-color: var(--color-surface-sunken); }

/* Collapsed: hidden until toggled, then a stacked list. */
.app-nav {
  display: none;
  flex-direction: column;
  gap: 0.125rem;
  margin-top: 0.5rem;
  font-size: 0.9375rem;
  color: var(--color-text-muted);
}

.app-nav--open { display: flex; }

/* `contents` keeps the logout <form> from breaking the flex/stack flow. */
.contents { display: contents; }

.app-nav .nav-link {
  border-radius: var(--radius-control);
  padding: 0.625rem 0.5rem;
}

.app-nav .nav-link:hover { background-color: var(--color-surface-sunken); }

.nav-link--button {
  width: 100%;
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
}

@media (min-width: 768px) {
  .app-topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 2rem;
    padding-bottom: 1rem;
  }

  .app-topbar-row { gap: 1.5rem; }
  .nav-toggle { display: none; }

  .app-nav {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: 1rem;
    margin-top: 0;
    font-size: 0.875rem;
  }

  .app-nav .nav-link { padding: 0; border-radius: 0; }
  .app-nav .nav-link:hover { background-color: transparent; }
  .nav-link--button { width: auto; }
}

.app-brand {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-heading);
  font-size: 1.125rem;
  font-weight: 600;
  letter-spacing: -0.015em;
  color: var(--color-text-strong);
}

/* Site logo. A square badge with its own background, so it gets the
   rounded-square mask an app icon expects — a circle cut the corners off
   and clipped the target rings. Adjust --logo-size to scale it. */
.app-brand-mark {
  display: inline-block;
  height: var(--logo-size);
  width: var(--logo-size);
  flex-shrink: 0;
  border-radius: var(--radius-logo);
  object-fit: cover;
}

.app-greeting {
  display: none;
  font-size: 0.875rem;
  color: var(--color-text-muted);
}

@media (min-width: 1024px) { .app-greeting { display: inline; } }

/* Superseded by the collapsible nav rules above — kept only the hover. */
.nav-link:hover,
.app-nav button:hover { color: var(--color-accent); }

.app-footer {
  margin-top: 4rem;
  text-align: center;
  font-size: 0.75rem;
  color: var(--color-text-faint);
}

/* Django messages */
.flash {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-control);
  background-color: var(--color-surface);
  padding: 0.5rem 1rem;
  font-size: 0.875rem;
  color: #334155;
  box-shadow: var(--shadow-control);
}

.flash--error { color: #be123c; }

/* ==========================================================================
   Page headers  (the title block at the top of a view)
   ========================================================================== */

.page-header { margin-bottom: 1.5rem; }
@media (min-width: 640px) { .page-header { margin-bottom: 2rem; } }

.page-header--split {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem 1rem;
}

.page-title {
  font-family: var(--font-heading);
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--color-text-strong);
}

@media (min-width: 640px) { .page-title { font-size: 1.875rem; } }

.page-subtitle {
  margin-top: 0.25rem;
  font-size: 0.875rem;
  color: var(--color-text-muted);
}

.back-link {
  font-size: 0.875rem;
  color: var(--color-text-muted);
}

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

/* ==========================================================================
   Sections  (the primary card surface)
   ========================================================================== */

.section-card {
  overflow: hidden;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-section);
  background-color: var(--color-surface);
  box-shadow: var(--shadow-section);
}

/* Card with no header bar — content sits directly inside. */
.section-card--padded { padding: var(--space-body); }

/* Interactive card (e.g. a project tile that links somewhere). */
.section-card--link { display: block; transition: box-shadow 150ms, border-color 150ms; }
.section-card--link:hover { box-shadow: var(--shadow-section-hover); }

.section-header {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  padding: var(--space-section-y) var(--space-section-x);
  border-bottom: 1px solid var(--color-accent-line);
  background-color: color-mix(in srgb, var(--color-accent-tint) 50%, transparent);
}

.section-title {
  font-family: var(--font-heading);
  font-size: 0.875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-accent);
}

/* Small print sitting beside a section title. */
.section-meta {
  font-size: 0.75rem;
  color: var(--color-text-muted);
}

.section-body { padding: var(--space-body); }

/* Success-tinted header (Achievements). */
.section-header--success {
  border-bottom-color: var(--color-success-line);
  background-color: color-mix(in srgb, var(--color-success-bg) 60%, transparent);
}

.section-header--success .section-title { color: var(--color-success-text); }

/* A heading for a block *inside* a section body. */
.subsection-title {
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-muted);
}

/* Divided list inside a section. */
.section-list > * + * { border-top: 1px solid var(--color-border-subtle); }

.section-row {
  display: block;
  padding: 0.625rem var(--space-section-x);
}

.section-row--link { transition: background-color 150ms; }
.section-row--link:hover { background-color: color-mix(in srgb, var(--color-surface-sunken) 70%, transparent); }

/* Nested panel inside a card (habit cards, expanded journal entries). */
.surface-sunken {
  border: 1px solid var(--color-border);
  border-radius: 0.75rem;
  background-color: var(--color-surface-sunken);
}

/* ==========================================================================
   Quarter tracker  (the scrolling quarter row at the top of the dashboard)
   ========================================================================== */

.horizon-card {
  background-image: linear-gradient(
    to bottom right,
    var(--color-surface),
    color-mix(in srgb, var(--color-accent-tint) 30%, var(--color-surface))
  );
}

.horizon-figure {
  margin-top: 0.25rem;
  font-family: var(--font-heading);
  font-size: 1.25rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--color-text-strong);
}

@media (min-width: 640px) { .horizon-figure { font-size: 1.5rem; } }

.quarter-tile {
  border: 1px solid var(--color-border);
  border-radius: 0.5rem;
  background-color: var(--color-surface-sunken);
  padding: 0.875rem 0.75rem;
}

.quarter-tile--current {
  border-color: var(--color-accent-edge-soft);
  background-color: var(--color-accent-tint);
}

/* A past quarter is only on screen because something is still sitting
   in it, so it reads as a leftover rather than part of the run ahead. */
.quarter-tile--past {
  border-style: dashed;
  background-color: transparent;
}

/* The quarter row scrolls sideways. The scrollbar is hidden because the
   arrows are the control — free-scrolling still works for anyone who
   prefers it, but reaching another quarter is a deliberate act. */
.quarter-track {
  display: flex;
  gap: 0.5rem;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  overscroll-behavior-x: contain;
}
.quarter-track::-webkit-scrollbar { display: none; }

/* Grows to fill when there are only a few. Where the row is a little
   too narrow the tiles give up some width first, so a near miss — three
   of them on a tablet — settles without the arrows appearing at all;
   past the floor the row scrolls instead of squeezing them further.
   An explicit min-width also replaces the automatic min-content floor
   on a flex item, which would otherwise let one long goal name stretch
   its tile wider than the rest. */
.quarter-track > .quarter-tile {
  flex: 1 1 14rem;
  min-width: 13rem;
  scroll-snap-align: start;
}

.track-arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 1.75rem;
  width: 1.75rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-control);
  background-color: var(--color-surface);
  color: var(--color-text-muted);
  transition: color 150ms, border-color 150ms, opacity 150ms;
}
.track-arrow svg { height: 1rem; width: 1rem; }
.track-arrow:hover:not(:disabled) { border-color: var(--color-accent-edge); color: var(--color-accent); }
.track-arrow:disabled { opacity: 0.35; cursor: not-allowed; }

@media (pointer: coarse) {
  .track-arrow { height: 2.75rem; width: 2.75rem; }
}

/* ==========================================================================
   Buttons & links
   ========================================================================== */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.375rem;
  border-radius: var(--radius-control);
  padding: 0.5rem 1rem;
  font-size: 0.875rem;
  font-weight: 500;
  box-shadow: var(--shadow-control);
  transition: background-color 150ms, border-color 150ms, color 150ms;
  cursor: pointer;
}

.btn--primary {
  background-color: var(--color-accent-solid);
  color: var(--color-text-on-accent);
}
.btn--primary:hover { background-color: var(--color-accent-solid-hover); }

.btn--success {
  background-color: var(--color-success-solid);
  color: var(--color-text-on-accent);
}
.btn--success:hover { background-color: var(--color-success-solid-hover); }

.btn--secondary {
  border: 1px solid var(--color-border);
  background-color: var(--color-surface);
  color: var(--color-text);
}
.btn--secondary:hover { border-color: var(--color-accent-edge); color: var(--color-accent); }

.btn--warning {
  background-color: var(--color-warning-solid);
  color: #fff;
}
.btn--warning:hover { background-color: var(--color-warning-solid-hover); }

.btn--sm { padding: 0.375rem 0.75rem; font-size: 0.75rem; }

/* Inert placeholder button (e.g. a disabled "next period" arrow). */
.btn--muted {
  border: 1px solid var(--color-border-subtle);
  background-color: var(--color-surface-sunken);
  color: #cbd5e1;
  box-shadow: none;
  cursor: default;
}

/* Category colour stripe down the left edge of a project card. */
.project-stripe {
  position: absolute;
  inset-block: 0;
  left: 0;
  width: 1rem;
}

.btn:disabled { cursor: not-allowed; opacity: 0.5; }

/* Text links */
.link-accent { color: var(--color-accent); font-weight: 500; }
.link-accent:hover { color: var(--color-accent-hover); }

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

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

/* ==========================================================================
   Segmented control

   Two or three mutually exclusive view options, e.g. the card/row layout
   switch on the projects list. Icon-only: the labels live in aria-label.
   ========================================================================== */

.segmented {
  display: inline-flex;
  gap: 0.125rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-control);
  background-color: var(--color-surface);
  padding: 0.125rem;
}

.segmented-item {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: calc(var(--radius-control) - 2px);
  padding: 0.3125rem 0.5rem;
  color: var(--color-text-muted);
  cursor: pointer;
  transition: background-color 150ms, color 150ms;
}
.segmented-item:hover { color: var(--color-accent); }
.segmented-item svg { height: 1rem; width: 1rem; }

.segmented-item--active {
  background-color: var(--color-accent-tint);
  color: var(--color-accent);
}

@media (pointer: coarse) {
  .segmented-item { min-height: 2.75rem; min-width: 2.75rem; }
}

/* ==========================================================================
   Row lists

   The dense alternative to a grid of cards — same information, one line
   per item on a wide screen, stacked below 768px. Shared by the projects
   list and the high-altitude board; the trailing column's width differs
   between them, so each list sets --row-status-w for itself.
   ========================================================================== */

.row-list {
  /* Deliberately not overflow:hidden. A row's Actions menu is positioned
     inside the row, so clipping the list would cut the menu off whenever
     it was taller than the rows below it — which, with two or three rows,
     is always. The edge rows carry the corner rounding instead. */
  border: 1px solid var(--color-border);
  border-radius: var(--radius-section);
  background-color: var(--color-surface);
  box-shadow: var(--shadow-section);
}

/* Everything that paints at a corner has to be rounded itself now: the
   row (its hover and flagged backgrounds) and the category stripe.
   `template + *` is the first row of an Alpine-rendered list, where the
   x-for <template> is the real first child and :first-child would land
   on something that never paints. */
.row-list > :first-child,
.row-list > template + *,
.row-list > :first-child > .row-item,
.row-list > template + * > .row-item {
  border-top-left-radius: var(--radius-section);
  border-top-right-radius: var(--radius-section);
}
.row-list > :last-child,
.row-list > :last-child > .row-item {
  border-bottom-left-radius: var(--radius-section);
  border-bottom-right-radius: var(--radius-section);
}
.row-list > :first-child .row-item-stripe,
.row-list > template + * .row-item-stripe { border-top-left-radius: var(--radius-section); }
.row-list > :last-child .row-item-stripe { border-bottom-left-radius: var(--radius-section); }

.row-item {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.875rem;
  padding: 0.75rem 1rem 0.75rem 1.75rem;
  transition: background-color 150ms;
}
.row-item:hover { background-color: var(--color-surface-sunken); }
.row-list > * + * { border-top: 1px solid var(--color-border-subtle); }

.row-item-stripe {
  position: absolute;
  inset-block: 0;
  left: 0;
  width: 0.5rem;
}

/* Below 900px each part takes its own line; above, they share one. */
.row-item-head { flex: 1 1 100%; min-width: 0; }

.row-item-name {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--color-text-strong);
}
a.row-item:hover .row-item-name { color: var(--color-accent); }

.row-item-sub {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.75rem;
  color: var(--color-text-muted);
}

.row-item-meta {
  display: flex;
  flex: 1 1 100%;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.375rem;
}

.row-item-progress {
  display: flex;
  flex: 1 1 7rem;
  align-items: center;
  gap: 0.5rem;
}

.row-item-pct {
  min-width: 2.25rem;
  text-align: right;
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
  color: var(--color-text-muted);
}

.row-item-status {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 0.5rem;
}

.row-item-aside { font-size: 0.75rem; color: var(--color-text-faint); }

/* Trailing controls — an actions menu on rows that aren't links. */
.row-item-actions { display: flex; flex: 0 0 auto; align-items: center; gap: 0.25rem; }

/* An item wanting attention (a landed high-altitude goal). A left inset
   would sit behind the category stripe, so the cue is a background wash;
   the hover rule is repeated because the two have equal specificity. */
.row-item--flagged { background-color: var(--color-tip-bg); }
.row-item--flagged:hover {
  background-color: color-mix(in srgb, var(--color-tip-bg) 85%, var(--color-text-faint));
}

/* Expanded description under a row. */
.row-item-detail { padding: 0 1rem 0.875rem 1.75rem; }

/* One line per item. The gain over a card is only worth having when
   everything fits without squeezing, so in the middle band the exact due
   date gives way — the chip beside it already says how long is left —
   and the progress column runs narrow. */
@media (min-width: 768px) {
  .row-item { flex-wrap: nowrap; padding-top: 0.625rem; padding-bottom: 0.625rem; }
  .row-item-head { display: flex; flex: 1 1 auto; align-items: baseline; gap: 0.5rem; }
  /* The name absorbs the shrinking; the goal keeps its width so it never
     truncates down to a meaningless stub. */
  .row-item-name { flex: 0 1 auto; }
  .row-item-sub { flex: 0 0 auto; max-width: 10rem; }
  .row-item-meta { flex: 0 0 auto; }
  .row-item-progress { flex: 0 0 6rem; }
  .row-item-aside { display: none; }
  /* Fixed width, contents right-aligned: that pins the left edge of the
     column before it, so bars, percentages and chips line up down the
     list instead of drifting with each row's chip widths. */
  .row-item-status { flex: 0 0 var(--row-status-w, auto); justify-content: flex-end; }
  /* Fixed too, or a row without notes shifts everything before it. */
  .row-item-actions { flex: 0 0 var(--row-actions-w, auto); justify-content: flex-end; }
  .row-list--hags { --row-actions-w: 9.5rem; }
  .row-list--projects { --row-status-w: 7rem; }
  .row-list--hags { --row-status-w: 11rem; }
}

@media (min-width: 1100px) {
  .row-item-progress { flex: 0 0 10rem; }
  .row-item-aside { display: block; }
  .row-list--projects { --row-status-w: 13.5rem; }
  .row-list--hags { --row-status-w: 19rem; }
}

/* ==========================================================================
   Action menu

   One trigger that drops the page's actions into a list, for headers that
   would otherwise carry a row of buttons competing for the same attention.
   ========================================================================== */

.menu { position: relative; }

.menu-panel {
  position: absolute;
  right: 0;
  top: calc(100% + 0.375rem);
  z-index: 30;
  min-width: 12rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-control);
  background-color: var(--color-surface);
  padding: 0.25rem;
  box-shadow: var(--shadow-overlay);
}

.menu-item {
  display: flex;
  width: 100%;
  align-items: center;
  gap: 0.5rem;
  border-radius: calc(var(--radius-control) - 1px);
  padding: 0.5rem 0.625rem;
  text-align: left;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--color-text);
  cursor: pointer;
}
.menu-item:hover { background-color: var(--color-surface-sunken); color: var(--color-accent); }

/* The action the page is really for — kept green, as the standalone button
   was, so it still reads as the primary move. */
.menu-item--success { color: var(--color-success-text); }
.menu-item--success:hover { background-color: var(--color-success-bg); color: var(--color-success-text); }

.menu-sep { margin: 0.25rem 0; border-top: 1px solid var(--color-border-subtle); }

.menu-chevron { height: 0.875rem; width: 0.875rem; transition: transform 150ms; }
.menu-chevron--open { transform: rotate(180deg); }

@media (pointer: coarse) {
  .menu-item { padding: 0.75rem; }
}

/* ==========================================================================
   Forms
   ========================================================================== */

.form-label {
  font-size: 0.75rem;
  font-weight: 500;
  color: #475569;
}

.form-input {
  margin-top: 0.25rem;
  display: block;
  width: 100%;
  border: 1px solid #cbd5e1;
  border-radius: var(--radius-control);
  background-color: var(--color-surface);
  padding: 0.5rem 0.75rem;
  font-size: 0.875rem;
  color: var(--color-text-strong);
  box-shadow: var(--shadow-control);
}

.form-input:focus {
  outline: none;
  border-color: var(--color-accent-ring);
  box-shadow: 0 0 0 1px var(--color-accent-ring);
}

.form-input--mono { font-family: var(--font-mono); }

/* iOS Safari zooms the page when focusing a field whose text is under
   16px, and our controls are 14px. Bump to 16px on touch devices only.
   Must come after .form-input above, or that 14px wins on cascade order. */
@media (pointer: coarse) {
  .form-input,
  input[type="text"], input[type="password"], input[type="number"],
  input[type="date"], input[type="datetime-local"], input[type="time"],
  input[type="url"], input[type="email"], select, textarea {
    font-size: 16px;
  }
}

/* Safari lays date inputs out as content-box and ignores box-sizing on
   them, so a full-width date field ends up its own padding wider than its
   container and runs into the edge (seen on the journal modal). It also
   centres the date text, which reads oddly next to our left-aligned
   fields. Opting out of the native appearance fixes both, and is a no-op
   in Chrome/Firefox where these already behave. */
input[type="date"],
input[type="datetime-local"],
input[type="time"] {
  -webkit-appearance: none;
  appearance: none;
  box-sizing: border-box;
  max-width: 100%;
}

input[type="date"]::-webkit-datetime-edit,
input[type="datetime-local"]::-webkit-datetime-edit,
input[type="time"]::-webkit-datetime-edit { text-align: left; }

.form-checkbox {
  height: 1rem;
  width: 1rem;
  border-radius: 0.25rem;
  border: 1px solid #cbd5e1;
  accent-color: var(--color-accent-solid);
}

.form-help {
  margin-top: 0.25rem;
  font-size: 0.75rem;
  color: var(--color-text-muted);
}

.form-error {
  margin-top: 0.25rem;
  font-size: 0.75rem;
  color: var(--color-danger);
}

.form-error-banner {
  margin-bottom: 1rem;
  border: 1px solid #fecdd3;
  border-radius: var(--radius-control);
  background-color: #fff1f2;
  padding: 0.5rem 0.75rem;
  font-size: 0.875rem;
  color: #be123c;
}

/* Footer row of a form: cancel on the left, submit on the right. */
.form-actions {
  margin-top: 1.5rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  border-top: 1px solid var(--color-border-subtle);
  padding-top: 1.25rem;
}

/* ==========================================================================
   Chips  (status pills)

   Geometry lives here; the colours come from template filters in
   tracker_extras.py (pace_class, deadline_class, category_badge_class…)
   so status colour stays defined in one place per concept.
   ========================================================================== */

.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  border-radius: var(--radius-pill);
  padding: 0.125rem 0.625rem;
  font-size: 0.75rem;
  font-weight: 500;
  white-space: nowrap;
}

.chip--xs { padding: 0.125rem 0.5rem; font-size: 0.625rem; }

/* --- Chip colours -------------------------------------------------------
   Emitted by the filters in tracker_extras.py (pace_class, deadline_class,
   category_badge_class). Change a status colour once, here.            */

.chip--done        { background: #d1fae5; color: #065f46; box-shadow: inset 0 0 0 1px rgb(5 150 105 / 0.2); }
.chip--ahead       { background: #ccfbf1; color: #115e59; box-shadow: inset 0 0 0 1px rgb(13 148 136 / 0.2); }
.chip--on          { background: #f0fdfa; color: #0f766e; box-shadow: inset 0 0 0 1px rgb(13 148 136 / 0.2); }
.chip--behind      { background: #fef3c7; color: #92400e; box-shadow: inset 0 0 0 1px rgb(217 119 6 / 0.2); }
.chip--well-behind { background: #ffe4e6; color: #9f1239; box-shadow: inset 0 0 0 1px rgb(225 29 72 / 0.2); }
.chip--pending     { background: #f1f5f9; color: #334155; box-shadow: inset 0 0 0 1px rgb(71 85 105 / 0.2); }
.chip--missed      { background: #ffe4e6; color: #9f1239; box-shadow: inset 0 0 0 1px rgb(225 29 72 / 0.2); }

.chip--due-ok    { background: #d1fae5; color: #065f46; box-shadow: inset 0 0 0 1px rgb(5 150 105 / 0.2); }
.chip--due-soon  { background: #fef3c7; color: #92400e; box-shadow: inset 0 0 0 1px rgb(217 119 6 / 0.2); }
.chip--due-past  { background: #ffe4e6; color: #9f1239; box-shadow: inset 0 0 0 1px rgb(225 29 72 / 0.2); }

.chip--completed { background: #d1fae5; color: #065f46; box-shadow: inset 0 0 0 1px rgb(5 150 105 / 0.2); }
.chip--extended  { background: #fef3c7; color: #92400e; box-shadow: inset 0 0 0 1px rgb(217 119 6 / 0.2); }
.chip--parked    { background: #fffbeb; color: #92400e; box-shadow: inset 0 0 0 1px rgb(217 119 6 / 0.2); }
.chip--alert     { background: #ffe4e6; color: #9f1239; box-shadow: inset 0 0 0 1px rgb(225 29 72 / 0.2); }

/* Project categories — colour per area of life. */
.chip--cat-personal { background: #e0f2fe; color: #075985; box-shadow: inset 0 0 0 1px rgb(2 132 199 / 0.2); }
.chip--cat-family   { background: #fce7f3; color: #9d174d; box-shadow: inset 0 0 0 1px rgb(219 39 119 / 0.2); }
.chip--cat-braw     { background: #ffedd5; color: #9a3412; box-shadow: inset 0 0 0 1px rgb(234 88 12 / 0.2); }
.chip--cat-cec      { background: #e0e7ff; color: #3730a3; box-shadow: inset 0 0 0 1px rgb(79 70 229 / 0.2); }

/* --- Dots (category / calendar colour markers) --- */
.dot {
  display: inline-block;
  height: 0.5rem;
  width: 0.5rem;
  flex-shrink: 0;
  border-radius: var(--radius-pill);
  background-color: #94a3b8;
}

.dot--sm { height: 0.375rem; width: 0.375rem; }
.dot--lg { height: 0.625rem; width: 0.625rem; }

.dot--cat-personal, .dot--sky     { background-color: #0ea5e9; }
.dot--cat-family,   .dot--pink    { background-color: #ec4899; }
.dot--cat-braw,     .dot--orange  { background-color: #f97316; }
.dot--cat-cec,      .dot--indigo  { background-color: #6366f1; }
.dot--teal    { background-color: #14b8a6; }
.dot--emerald { background-color: #10b981; }
.dot--amber   { background-color: #f59e0b; }
.dot--rose    { background-color: #f43f5e; }
.dot--violet  { background-color: #8b5cf6; }
.dot--slate   { background-color: #64748b; }

/* Category heading text colours (projects list). */
.cat-text-personal { color: #0369a1; }
.cat-text-family   { color: #be185d; }
.cat-text-braw     { color: #c2410c; }
.cat-text-cec      { color: #4338ca; }

/* Neutral count badge, e.g. "8" beside a section title. */
.count-pill {
  border-radius: var(--radius-pill);
  background-color: var(--color-surface-muted);
  padding: 0.125rem 0.5rem;
  font-size: 0.75rem;
  font-weight: 500;
  color: #475569;
  font-variant-numeric: tabular-nums;
}

/* ==========================================================================
   Text helpers
   ========================================================================== */

.text-strong { color: var(--color-text-strong); }
.text-body { color: var(--color-text); }
.text-muted { color: var(--color-text-muted); }
.text-faint { color: var(--color-text-faint); }
.text-accent { color: var(--color-accent); }
/* Alert text on a normal surface — the token lightens in dark mode,
   which a fixed rose-700 does not. */
.text-danger { color: var(--color-danger); }

/* Token-driven surface helpers, so dark mode follows automatically. */
.bg-surface { background-color: var(--color-surface); }
.bg-sunken { background-color: var(--color-surface-sunken); }
.bg-muted { background-color: var(--color-surface-muted); }
.border-line { border-color: var(--color-border); }
.divide-line > * + * { border-top: 1px solid var(--color-border-subtle); }
.row-hover:hover { background-color: var(--color-surface-sunken); }

/* Informational callout (e.g. the Google Calendar instructions). */
.info-panel {
  border-radius: var(--radius-control);
  background-color: var(--color-info-bg);
  padding: 0.75rem 1rem;
  font-size: 0.75rem;
  color: var(--color-info-text);
  box-shadow: inset 0 0 0 1px var(--color-info-line);
}

.info-panel--tip {
  background-color: var(--color-tip-bg);
  color: var(--color-tip-text);
  box-shadow: inset 0 0 0 1px var(--color-tip-line);
}

/* The same colourings without the panel's own padding and radius, for
   callouts that bring their own shape. Tokens rather than amber-50 and
   rose-50 utilities, which stayed light when the rest went dark. */
.tip-surface {
  border-color: var(--color-tip-line);
  background-color: var(--color-tip-bg);
  color: var(--color-tip-text);
}

.danger-surface {
  border-color: var(--color-danger-line);
  background-color: var(--color-danger-bg);
  color: var(--color-danger-text);
}

/* A note along the bottom edge of a section card. */
.section-note {
  border-top: 1px solid var(--color-tip-line);
  background-color: var(--color-tip-bg);
  padding: 0.5rem var(--space-section-x);
  font-size: 11px;
  color: var(--color-tip-text);
}

.code-block {
  overflow-x: auto;
  border-radius: var(--radius-control);
  background-color: var(--color-code-bg);
  padding: 0.75rem;
  font-size: 0.75rem;
  color: var(--color-code-text);
}

.meta-text {
  font-size: 0.75rem;
  color: var(--color-text-muted);
}

.empty-state {
  padding: 1.5rem var(--space-section-x);
  text-align: center;
  font-size: 0.875rem;
  font-style: italic;
  color: var(--color-text-faint);
}

.empty-state--boxed {
  border: 1px dashed #cbd5e1;
  border-radius: var(--radius-section);
  background-color: var(--color-surface);
  padding: 2.5rem;
}

/* ==========================================================================
   Progress bars
   ========================================================================== */

.progress-track {
  overflow: hidden;
  border-radius: var(--radius-pill);
  background-color: var(--color-surface-muted);
  height: 0.5rem;
}

.progress-track--slim { height: 0.375rem; }

.progress-fill {
  height: 100%;
  border-radius: var(--radius-pill);
  background-color: var(--color-accent-solid);
}

/* ==========================================================================
   Habit controls

   These are applied from Alpine :class bindings, so the done/missed/future
   states are named here rather than spelled out in JavaScript.
   ========================================================================== */

/* Grid view (habits_day). --day-cell-size drives both the toggle square
   and its table column, so they can't drift apart. */
.habit-grid {
  table-layout: fixed;
  width: 100%;
  /* The name column has no fixed width (it takes the spare room on wide
     screens), so a fixed-layout table would squash it to nothing on a
     phone. Never let the table get narrower than name column + day
     columns + spacing; the card scrolls horizontally instead.
     --habit-days is set inline from the number of days shown. */
  min-width: calc(
    var(--habit-name-col)
    + var(--habit-days, 14) * var(--day-cell-size)
    + (var(--habit-days, 14) + 2) * 3px
  );
  border-collapse: separate;
  border-spacing: 3px;
}

.habit-grid-day-col { width: var(--day-cell-size); }
.habit-grid-name-col { min-width: var(--habit-name-col); }
.habit-grid-sticky { background-color: var(--color-surface); }

/* Column header states. */
.habit-grid-today {
  border-radius: var(--radius-control);
  background-color: var(--color-today-bg);
  color: var(--color-today-text);
  font-weight: 700;
}

.habit-grid-weekend {
  border-radius: var(--radius-control);
  background-color: var(--color-surface-sunken);
  color: var(--color-text-faint);
}

/* Goal grouping rows inside the grid. */
.habit-grid-group {
  border-radius: var(--radius-control);
  background-color: color-mix(in srgb, var(--color-accent-tint) 60%, transparent);
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-accent);
}

.habit-grid-group--standalone {
  background-color: var(--color-surface-sunken);
  color: var(--color-text-muted);
  font-style: italic;
}

.day-cell {
  display: block;
  height: var(--day-cell-size);
  width: var(--day-cell-size);
  border: 1px solid transparent;
  border-radius: var(--radius-control);
  font-size: 0.875rem;
  font-weight: 700;
  line-height: 1;
  transition: background-color 150ms, border-color 150ms;
}

.day-cell--done {
  cursor: pointer;
  background-color: var(--color-accent-solid);
  border-color: var(--color-accent-solid-hover);
  color: #fff;
  box-shadow: var(--shadow-control);
}
.day-cell--done:hover { background-color: var(--color-accent-solid-hover); }

.day-cell--missed {
  cursor: pointer;
  background-color: var(--color-surface-muted);
  border-color: #cbd5e1;
}
.day-cell--missed:hover { background-color: #e2e8f0; border-color: #94a3b8; }

.day-cell--future {
  cursor: not-allowed;
  background-color: var(--color-surface-sunken);
  border-color: var(--color-border);
}

/* A scheduled habit's off day — still clickable for a bonus completion,
   but faded so the due days stand out. Token-only, so dark mode follows. */
.day-cell--off {
  cursor: pointer;
  background-color: transparent;
  border: 1px dashed var(--color-border);
}
.day-cell--off:hover { background-color: var(--color-surface-muted); }

/* Quick-log view — large tap targets. */
.quick-habit {
  display: flex;
  width: 100%;
  align-items: center;
  gap: 1rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-section);
  background-color: var(--color-surface);
  padding: 1rem;
  text-align: left;
  color: var(--color-text);
  box-shadow: var(--shadow-control);
  transition: background-color 150ms, border-color 150ms, transform 100ms;
}

@media (min-width: 640px) { .quick-habit { padding: 1.25rem; } }

.quick-habit:active { transform: scale(0.99); }
.quick-habit:hover { border-color: var(--color-accent-edge); background-color: var(--color-surface-sunken); }

.quick-habit--done {
  border-color: var(--color-accent-solid-hover);
  background-color: var(--color-accent-solid);
  color: #fff;
}
.quick-habit--done:hover { background-color: var(--color-accent-solid-hover); border-color: var(--color-accent-solid-hover); }

/* Scheduled habit that isn't due on the selected day. */
.quick-habit--off { opacity: 0.55; box-shadow: none; }

.quick-habit-icon {
  display: flex;
  height: 3rem;
  width: 3rem;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-pill);
  background-color: var(--color-surface-muted);
  color: var(--color-text-muted);
}

.quick-habit--done .quick-habit-icon {
  background-color: var(--color-accent-solid-hover);
  color: #fff;
}

.quick-habit-meta { margin-top: 0.125rem; font-size: 0.75rem; color: var(--color-text-muted); }
.quick-habit--done .quick-habit-meta { color: rgb(255 255 255 / 0.75); }

.quick-habit-check {
  display: flex;
  height: 2rem;
  width: 2rem;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-pill);
  border: 2px solid var(--color-border);
  font-size: 1.125rem;
}

.quick-habit--done .quick-habit-check {
  border-color: transparent;
  background-color: rgb(255 255 255 / 0.2);
}

/* Dashboard priority-habit "mark done" button. */
.habit-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.375rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-control);
  background-color: var(--color-surface);
  padding: 0.375rem 0.75rem;
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--color-text-muted);
  box-shadow: var(--shadow-control);
  transition: background-color 150ms, border-color 150ms, color 150ms;
}

.habit-action:hover { border-color: var(--color-accent-edge); color: var(--color-accent); }

.habit-action--done {
  border-color: transparent;
  background-color: var(--color-accent-solid);
  color: #fff;
}
.habit-action--done:hover { background-color: var(--color-accent-solid-hover); color: #fff; }

/* "Swap this one" under a priority habit. Deliberately quiet, so the
   tap target is grown on touch rather than the text, the same way the
   milestone checkbox is. */
.swap-link { position: relative; }
@media (pointer: coarse) {
  .swap-link::after { content: ''; position: absolute; inset: -0.875rem -1rem; }
}

/* Milestone completion checkbox. */
.milestone-check {
  display: flex;
  height: 1.5rem;
  width: 1.5rem;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  border: 1px solid #cbd5e1;
  border-radius: 0.25rem;
  background-color: var(--color-surface);
  transition: background-color 150ms, border-color 150ms;
}

.milestone-check:hover { border-color: var(--color-accent-edge); }

.milestone-check--done {
  border-color: var(--color-accent-solid-hover);
  background-color: var(--color-accent-solid);
  color: #fff;
}
.milestone-check--done:hover { background-color: var(--color-accent-solid-hover); }

@media (pointer: coarse) {
  .milestone-check { position: relative; height: 1.75rem; width: 1.75rem; }
  /* The box stays small so rows read as a list, but a 28px tap target is
     under the 44pt minimum — this grows the hit area, not the graphic. */
  .milestone-check::after { content: ''; position: absolute; inset: -0.5rem; }
}

/* Success confirmation panel. */
.notice--success {
  border: 1px solid var(--color-success-line);
  border-radius: var(--radius-section);
  background-color: var(--color-success-bg);
  padding: var(--space-body);
  color: var(--color-success-text);
  box-shadow: var(--shadow-section);
}

/* ==========================================================================
   Attachments

   The whole card is the drop target, so the cue has to read at card
   scale: a dashed accent border plus an overlay across the panel.
   ========================================================================== */

.dropzone--active {
  position: relative;
  border-color: var(--color-accent-solid);
  border-style: dashed;
}

.dropzone-overlay {
  position: absolute;
  inset: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-section);
  background-color: color-mix(in srgb, var(--color-surface) 88%, transparent);
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--color-accent);
  /* The overlay must not swallow the drop event it is announcing. */
  pointer-events: none;
}

/* Short file-type marker, e.g. PDF. Fixed width so names start on a line. */
.file-tag {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  border-radius: var(--radius-control);
  background-color: var(--color-surface-muted);
  padding: 0.1875rem 0.25rem;
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  color: var(--color-text-muted);
}

/* A URL shown truncated. One click takes the whole value, not the
   visible part, so it can be copied without dragging through an ellipsis. */
.selectable-url {
  user-select: all;
  -webkit-user-select: all;
  cursor: text;
}

/* ==========================================================================
   Two-factor setup
   ========================================================================== */

/* The QR needs a white quiet zone whatever the theme — scanners read the
   contrast, not the palette. */
.qr-frame {
  display: inline-block;
  border-radius: var(--radius-control);
  background: #fff;
  padding: 0.75rem;
}
.qr-frame svg { display: block; height: 12rem; width: 12rem; }

.recovery-codes {
  display: grid;
  gap: 0.5rem;
  grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
  border-radius: var(--radius-control);
  background-color: var(--color-surface-muted);
  padding: 1rem;
  font-family: var(--font-mono);
  font-size: 0.875rem;
  letter-spacing: 0.05em;
  color: var(--color-text-strong);
  user-select: all;
}

/* ==========================================================================
   Rendered markdown

   Typography for goal and project descriptions. These must live here, not
   in a <style> block in base.html: that block loads after this file, so an
   equal-specificity rule there would outrank the dark-mode overrides below.
   ========================================================================== */

.markdown { color: var(--color-text); font-size: 0.875rem; line-height: 1.6; }
.markdown h1 { font-size: 1.25rem; font-weight: 600; color: var(--color-text-strong); margin: 1.25rem 0 0.5rem; }
.markdown h2 { font-size: 1.125rem; font-weight: 600; color: var(--color-text-strong); margin: 1.1rem 0 0.5rem; }
.markdown h3 { font-size: 1rem; font-weight: 600; color: var(--color-text-strong); margin: 1rem 0 0.4rem; }
.markdown h4, .markdown h5, .markdown h6 { font-size: 0.95rem; font-weight: 600; color: var(--color-text-strong); margin: 0.9rem 0 0.3rem; }
.markdown p { margin: 0.5rem 0; }
.markdown ul, .markdown ol { margin: 0.5rem 0; padding-left: 1.5rem; }
.markdown ul { list-style: disc; }
.markdown ol { list-style: decimal; }
.markdown li { margin: 0.2rem 0; }
.markdown a { color: var(--color-accent); text-decoration: underline; }
.markdown a:hover { color: var(--color-accent-hover); }
.markdown code { background: var(--color-surface-muted); padding: 0.1rem 0.35rem; border-radius: 4px; font-size: 0.8125rem; font-family: var(--font-mono); }
.markdown pre { background: var(--color-surface-muted); padding: 0.75rem; border-radius: 6px; overflow-x: auto; margin: 0.75rem 0; }
.markdown pre code { background: transparent; padding: 0; }
.markdown blockquote { border-left: 3px solid var(--color-border-strong); padding-left: 0.75rem; color: var(--color-text-muted); margin: 0.75rem 0; }
.markdown hr { border: 0; border-top: 1px solid var(--color-border); margin: 1rem 0; }
.markdown table { border-collapse: collapse; margin: 0.75rem 0; }
.markdown th, .markdown td { border: 1px solid var(--color-border); padding: 0.35rem 0.6rem; text-align: left; }
.markdown th { background: var(--color-surface-sunken); font-weight: 600; }
.markdown :first-child { margin-top: 0; }
.markdown :last-child { margin-bottom: 0; }

/* Compact bulleted list for Django's password-validator help text. */
.help-list { color: var(--color-text-muted); font-size: 0.75rem; line-height: 1.15rem; margin-top: 0.375rem; }
.help-list ul { list-style: disc; padding-left: 1rem; }
.help-list li { margin-top: 0.125rem; }
.help-list :first-child { margin-top: 0; }

/* ==========================================================================
   Modal
   ========================================================================== */

.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 50;
  overflow-y: auto;
  background-color: rgb(15 23 42 / 0.4);
  padding: 1rem;
}

.modal-panel {
  width: 100%;
  max-width: 32rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-section);
  background-color: var(--color-surface);
  padding: var(--space-body);
  box-shadow: var(--shadow-overlay);
}

.modal-title {
  font-family: var(--font-heading);
  font-size: 1.125rem;
  font-weight: 600;
  letter-spacing: -0.015em;
  color: var(--color-text-strong);
}

/* ==========================================================================
   Appearance picker  (Settings)
   ========================================================================== */

.theme-option {
  display: block;
  width: 100%;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-control);
  background-color: var(--color-surface);
  padding: 0.75rem;
  text-align: left;
  transition: border-color 150ms, box-shadow 150ms;
}

.theme-option--on {
  border-color: var(--color-accent-solid);
  box-shadow: inset 0 0 0 1px var(--color-accent-solid);
}

/* A canvas with a card on it and an accent dot — the page in miniature,
   so each theme can be recognised without applying it. */
.theme-swatch {
  display: inline-flex;
  align-items: flex-end;
  justify-content: center;
  height: 2.25rem;
  width: 3rem;
  border: 1px solid var(--color-border);
  border-radius: 0.375rem;
  padding-top: 0.375rem;
  overflow: hidden;
}

.theme-swatch-card {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  width: 72%;
  border-top-left-radius: 0.25rem;
  border-top-right-radius: 0.25rem;
}

.theme-swatch-dot {
  height: 0.5rem;
  width: 0.5rem;
  border-radius: var(--radius-pill);
}

.mode-option {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-control);
  background-color: var(--color-surface);
  padding: 0.375rem 0.75rem;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--color-text);
  transition: border-color 150ms, background-color 150ms, color 150ms;
}

.mode-option--on {
  border-color: var(--color-accent-solid);
  background-color: var(--color-accent-solid);
  color: var(--color-text-on-accent);
}

@media (pointer: coarse) {
  .mode-option { padding: 0.625rem 1rem; }
}

/* ==========================================================================
   Dark mode

   Keyed off data-mode on <html>, which base.html's inline script sets
   before the first paint — from the saved choice, or from the device
   when that choice is "match device".

   Almost everything is a token override; the component classes above
   don't change. Chips and dots need their own values because a light
   tint with dark text inverts badly on a dark surface, and those are
   shared across themes: "behind" should mean the same amber whichever
   palette you are in.
   ========================================================================== */

:root[data-mode="dark"] {
  color-scheme: dark;

  /* Surfaces: a desaturated green-grey so the pistachio identity
     survives without glowing on a dark screen. */
  --color-canvas: #1b2118;
  --color-surface: #232a21;
  --color-surface-sunken: #1e251c;
  --color-surface-muted: #2b332a;
  --color-surface-raised: #3a4238;

  --color-border: #384034;
  --color-border-subtle: #2e352c;
  --color-border-strong: #454e41;

  /* Accents lighten so they stay legible on dark surfaces. */
  --color-accent: #5eead4;
  --color-accent-hover: #99f6e4;
  --color-accent-solid: #0d9488;
  --color-accent-solid-hover: #14b8a6;
  --color-accent-tint: #24352f;
  --color-accent-line: #2f3d35;
  --color-accent-ring: #14b8a6;
  --color-accent-edge: #2dd4bf;
  --color-accent-edge-soft: #0d9488;

  --color-text: #dbe3d6;
  --color-text-strong: #f1f5ef;
  --color-text-muted: #9aa694;
  --color-text-faint: #74806f;

  --color-info-bg: #17262f;
  --color-info-text: #a5d8f3;
  --color-info-line: rgb(56 189 248 / 0.25);
  --color-tip-bg: #2b2517;
  --color-tip-text: #fcd9a0;
  --color-tip-line: rgb(245 158 11 / 0.25);
  --color-today-bg: #3a2f14;
  --color-today-text: #fcd9a0;
  --color-success-bg: #16291f;
  --color-success-text: #86efac;
  --color-success-line: #2b4636;
  --color-code-bg: #12170f;
  --color-code-text: #dbe3d6;

  --color-danger: #fb7185;
  --color-danger-hover: #fda4af;
  --color-danger-bg: #3d1d24;
  --color-danger-text: #fda4af;
  --color-danger-line: rgb(253 164 175 / 0.25);

  /* Shadows do little on dark backgrounds — deepen them so cards still
     read as raised. */
  --shadow-section: 0 1px 3px 0 rgb(0 0 0 / 0.5), 0 1px 2px -1px rgb(0 0 0 / 0.4);
  --shadow-section-hover: 0 4px 8px -2px rgb(0 0 0 / 0.6);
  --shadow-control: 0 1px 2px 0 rgb(0 0 0 / 0.4);
  --shadow-overlay: 0 20px 25px -5px rgb(0 0 0 / 0.7);
}

/* ==========================================================================
   Theme: Notebook  (dark)

   The same cover-and-paper balance after dark: warm browns where the
   light theme has creams, the saffron lifted just enough to read. It
   dims the room rather than changing it — the relationship between
   canvas, card and accent is the one above.
   ========================================================================== */

:root[data-theme="notebook"][data-mode="dark"] {
  --color-canvas: #1e1912;
  --color-surface: #28221a;
  --color-surface-sunken: #221d16;
  --color-surface-muted: #332b20;
  --color-surface-raised: #41372a;

  --color-border: #403627;
  --color-border-subtle: #352d21;
  --color-border-strong: #4e4232;

  --color-accent: #f0b45e;
  --color-accent-hover: #f7cc8c;
  --color-accent-solid: #b25a0e;
  --color-accent-solid-hover: #c97012;
  --color-accent-tint: #3a2c16;
  --color-accent-line: #47351b;
  --color-accent-ring: #c97012;
  --color-accent-edge: #d9913a;
  --color-accent-edge-soft: #b25a0e;

  --color-text: #e6dcc9;
  --color-text-strong: #f7f1e4;
  --color-text-muted: #a89b85;
  --color-text-faint: #7e7462;

  --color-info-bg: #16262e;
  --color-info-text: #a5d0e8;
  --color-info-line: rgb(165 208 232 / 0.25);
  --color-tip-bg: #33280f;
  --color-tip-text: #f5ce8a;
  --color-tip-line: rgb(245 206 138 / 0.25);
  --color-today-bg: #3e2f12;
  --color-today-text: #f5ce8a;
  --color-success-bg: #1e2a18;
  --color-success-text: #afcf9b;
  --color-success-line: #39492e;
  --color-warning-solid: #d98c0c;
  --color-warning-solid-hover: #b4720a;
  --color-code-bg: #141009;
  --color-code-text: #e6dcc9;

  --color-danger: #f08a82;
  --color-danger-hover: #f5ada7;
  --color-danger-bg: #3a1f1b;
  --color-danger-text: #f5ada7;
  --color-danger-line: rgb(245 173 167 / 0.25);
  --color-success-solid: #4f7a3a;
  --color-success-solid-hover: #3d5f2d;
}

/* Form controls need explicit dark values (the browser default is white). */
[data-mode="dark"] .form-input { border-color: var(--color-border-strong); background-color: var(--color-surface-sunken); color: var(--color-text-strong); }
[data-mode="dark"] .form-input:focus { border-color: var(--color-accent-solid); box-shadow: 0 0 0 1px var(--color-accent-solid); }
[data-mode="dark"] .form-label { color: var(--color-text-muted); }
[data-mode="dark"] .btn--secondary { border-color: var(--color-border); background-color: var(--color-surface); color: var(--color-text); }
[data-mode="dark"] .btn--muted { border-color: var(--color-border-subtle); background-color: var(--color-surface-sunken); color: var(--color-text-faint); }
[data-mode="dark"] .flash { color: var(--color-text); }
[data-mode="dark"] .empty-state--boxed { border-color: var(--color-border); background-color: var(--color-surface); }

/* Date pickers render a light-on-light calendar glyph otherwise. */
[data-mode="dark"] input[type="date"],
[data-mode="dark"] input[type="datetime-local"],
[data-mode="dark"] input[type="time"] { color-scheme: dark; }

/* Status chips: darker tints, lighter text. */
[data-mode="dark"] .chip--done,
[data-mode="dark"] .chip--completed,
[data-mode="dark"] .chip--due-ok { background: #16341f; color: #86efac; box-shadow: inset 0 0 0 1px rgb(134 239 172 / 0.2); }
[data-mode="dark"] .chip--ahead { background: #123634; color: #5eead4; box-shadow: inset 0 0 0 1px rgb(94 234 212 / 0.2); }
[data-mode="dark"] .chip--on { background: #172a28; color: #5eead4; box-shadow: inset 0 0 0 1px rgb(94 234 212 / 0.18); }
[data-mode="dark"] .chip--behind,
[data-mode="dark"] .chip--due-soon,
[data-mode="dark"] .chip--extended { background: #3a2f14; color: #fcd34d; box-shadow: inset 0 0 0 1px rgb(252 211 77 / 0.2); }
[data-mode="dark"] .chip--parked { background: #332c18; color: #fcd34d; box-shadow: inset 0 0 0 1px rgb(252 211 77 / 0.18); }
[data-mode="dark"] .chip--well-behind,
[data-mode="dark"] .chip--missed,
[data-mode="dark"] .chip--due-past,
[data-mode="dark"] .chip--alert { background: #3d1d24; color: #fda4af; box-shadow: inset 0 0 0 1px rgb(253 164 175 / 0.2); }
[data-mode="dark"] .chip--pending { background: var(--color-surface-muted); color: var(--color-text); box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.08); }

[data-mode="dark"] .chip--cat-personal { background: #16293a; color: #7dd3fc; box-shadow: inset 0 0 0 1px rgb(125 211 252 / 0.2); }
[data-mode="dark"] .chip--cat-family { background: #34172a; color: #f9a8d4; box-shadow: inset 0 0 0 1px rgb(249 168 212 / 0.2); }
[data-mode="dark"] .chip--cat-braw { background: #37220f; color: #fdba74; box-shadow: inset 0 0 0 1px rgb(253 186 116 / 0.2); }
[data-mode="dark"] .chip--cat-cec { background: #1f1f3d; color: #a5b4fc; box-shadow: inset 0 0 0 1px rgb(165 180 252 / 0.2); }

[data-mode="dark"] .count-pill { background-color: var(--color-surface-muted); color: var(--color-text); }

/* Sunken is darker than surface here, so a hover would read as a hole. */
[data-mode="dark"] .menu-item:hover { background-color: var(--color-surface-muted); }
[data-mode="dark"] .row-item:hover { background-color: var(--color-surface-muted); }

/* Category heading text needs lifting off the dark surface. */
[data-mode="dark"] .cat-text-personal { color: #7dd3fc; }
[data-mode="dark"] .cat-text-family { color: #f9a8d4; }
[data-mode="dark"] .cat-text-braw { color: #fdba74; }
[data-mode="dark"] .cat-text-cec { color: #a5b4fc; }

/* Habit grid states. */
[data-mode="dark"] .day-cell--missed { background-color: var(--color-surface-muted); border-color: var(--color-border-strong); }
[data-mode="dark"] .day-cell--missed:hover { background-color: var(--color-surface-raised); border-color: var(--color-text-faint); }
[data-mode="dark"] .day-cell--future { background-color: var(--color-surface-sunken); border-color: var(--color-border-subtle); }

/* Markdown: the rest follows the tokens. A table header wants to be
   lighter than the surface here, where sunken is darker. */
[data-mode="dark"] .markdown th { background: var(--color-surface-muted); }

/* Quarter-tracker gradient and quarter tiles. */
[data-mode="dark"] .horizon-card {
  background-image: linear-gradient(to bottom right, var(--color-surface), var(--color-accent-tint));
}

/* ==========================================================================
   High-altitude board
   ========================================================================== */

/* Altitude marker — deliberately neutral so the category and ETA chips
   beside it carry the colour. */
.hag-altitude {
  background-color: var(--color-surface-muted);
  color: var(--color-text-muted);
  box-shadow: inset 0 0 0 1px rgb(100 116 139 / 0.2);
  font-variant-numeric: tabular-nums;
}

/* A HAG whose ETA has arrived: nudge it forward visually. */
.hag-card--landed {
  border-color: var(--color-warning-solid);
  box-shadow: var(--shadow-section), inset 3px 0 0 0 var(--color-warning-solid);
}

[data-mode="dark"] .hag-altitude {
  background-color: var(--color-surface-muted);
  color: var(--color-text);
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.1);
}
