/* Tailorbird - design system. Vanilla CSS, no build step. */

/* Dark is the only theme, deliberately - not conditional on the browser's
   prefers-color-scheme, which is why Chrome and Safari could disagree on
   this same page before (each reads its own OS-level appearance setting). */
:root {
  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

  --color-bg: #12151C;
  --color-surface: #1B2029;
  --color-surface-2: #232935;
  --color-border: #323A48;
  --color-ink: #EDF0F5;
  --color-body: #C0C8D4;
  --color-muted: #8A93A3;

  --color-primary: #6B9BFF;
  --color-primary-hover: #86ADFF;
  --color-primary-contrast: #0E1420;
  --color-primary-tint: #1E2A47;

  --color-success: #6FCB9F;
  --color-success-bg: #17321F;
  --color-success-border: #2C5A3C;

  --color-error: #F0897E;
  --color-error-bg: #3B1D1A;
  --color-error-border: #6B322C;

  --color-warning: #E4BF6C;
  --color-warning-bg: #362B12;
  --color-warning-border: #5C4A20;

  /* Extra accent hues, dashboard KPIs only - same lightness/saturation family
     as the palette above so a colorful grid still reads as one system. */
  --color-purple: #C29CFF;
  --color-purple-bg: #241B3D;
  --color-teal: #5FD2C8;
  --color-teal-bg: #123330;
  --color-pink: #F193C8;
  --color-pink-bg: #38182C;
  --color-cyan: #6FD8E8;
  --color-cyan-bg: #103539;
  --color-indigo: #8DA3F2;
  --color-indigo-bg: #1C2340;

  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 16px;
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
  --shadow-md: 0 6px 20px rgba(0, 0, 0, 0.4);
}

* { box-sizing: border-box; }
[x-cloak] { display: none !important; }

html { color-scheme: dark; scroll-behavior: smooth; }

/* Page-to-page navigation: a forward move slides the new page in from the
   right while the old one recedes left, like a real app's push. A Back move
   plays the mirror image (old recedes right, new enters from the left) - the
   head script in base.html adds .nav-back to <html> for exactly the span of a
   history-back transition. Browsers without View Transitions (anything but
   Chrome/Edge right now) just skip straight to the new page, no error. */
::view-transition-group(root) {
  animation-duration: 0.32s;
  animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
::view-transition-old(root) {
  animation-name: tb-slide-out-left;
}
::view-transition-new(root) {
  animation-name: tb-slide-in-right;
}
:root.nav-back::view-transition-old(root) {
  animation-name: tb-slide-out-right;
}
:root.nav-back::view-transition-new(root) {
  animation-name: tb-slide-in-left;
}
@keyframes tb-slide-out-left {
  to { transform: translateX(-30%); opacity: 0.4; }
}
@keyframes tb-slide-in-right {
  from { transform: translateX(100%); }
}
@keyframes tb-slide-out-right {
  to { transform: translateX(30%); opacity: 0.4; }
}
@keyframes tb-slide-in-left {
  from { transform: translateX(-100%); }
}

/* Quick nav: the dashboard / intake top action-row links (Start a tailoring
   run, Manage accounts, Pending requests, ...). No push, no dim - just a
   fast crossfade, the same feel as switching dashboard tabs. base.html adds
   .nav-quick to <html> for the span of the transition. Placed after the
   .nav-back rules so it wins on equal specificity if both ever coincide. */
:root.nav-quick::view-transition-group(root) {
  animation-duration: 0.12s;
  animation-timing-function: ease;
}
:root.nav-quick::view-transition-old(root) {
  animation-name: tb-fade-out;
}
:root.nav-quick::view-transition-new(root) {
  animation-name: tb-fade-in;
}
@keyframes tb-fade-out { to { opacity: 0; } }
@keyframes tb-fade-in { from { opacity: 0; } }

body {
  margin: 0;
  overflow-x: hidden;
  font-family: var(--font-sans);
  background: var(--color-bg);
  color: var(--color-ink);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

.page {
  max-width: 720px;
  margin: 0 auto;
  padding: 2.5rem 1.25rem 4rem;
}
.page.page-wide { max-width: 1020px; }
.page.page-dashboard { max-width: 1360px; }

/* --- left-hand nav layout (intake form) --- */

.layout {
  display: flex;
  align-items: flex-start;
  gap: 2rem;
}
.sidenav {
  flex: none;
  width: 200px;
  position: sticky;
  top: 2rem;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}
.sidenav button {
  all: unset;
  display: block;
  box-sizing: border-box;
  width: 100%;
  padding: 0.65rem 0.9rem;
  border-radius: var(--radius-sm);
  font-weight: 600;
  font-size: 0.92rem;
  color: var(--color-body);
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease;
}
.sidenav button .nav-tag {
  display: block;
  font-weight: 400;
  font-size: 0.75rem;
  color: var(--color-muted);
  margin-top: 0.1rem;
}
.sidenav button .nav-icon { margin-right: 0.45rem; }
.sidenav button .nav-label { vertical-align: middle; }
.sidenav button:hover { background: var(--color-surface-2); }
.sidenav button.active { background: var(--color-primary-tint); color: var(--color-primary); }
.sidenav button.active .nav-tag { color: var(--color-primary); opacity: 0.8; }

.main-content { flex: 1; min-width: 0; }

@media (max-width: 760px) {
  /* align-items: flex-start (set for the desktop row layout, so the sidenav
     doesn't stretch as tall as main-content) means something completely
     different once flex-direction flips to column here - it stops every
     child from stretching to full WIDTH instead, which is what was
     shrinking cards like "Recent activity" down to their content width
     instead of spanning the page. stretch is the correct cross-axis
     behavior once the axis itself has rotated. */
  .layout { flex-direction: column; gap: 1rem; align-items: stretch; }

  /* A real app-style bottom tab bar, not a top row that scrolls out of
     view - floating, rounded, icon-over-label, pinned above the home
     indicator. Leaves room for as many tabs as a page has (intake's 4,
     the dashboard's 7) by staying horizontally scrollable internally
     rather than trying to cram everything into ~5 fixed slots; the edge
     fade below still hints when there's more than fits on screen. */
  .sidenav {
    position: fixed;
    left: 0.75rem;
    /* leaves the bottom-right corner for the chat button so the two sit
       side by side instead of on top of each other */
    right: 4.4rem;
    bottom: calc(0.75rem + env(safe-area-inset-bottom, 0px));
    top: auto;
    z-index: 40;
    width: auto;
    flex-direction: row;
    gap: 0.2rem;
    overflow-x: auto;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
    padding: 0.35rem;
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 20px), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 20px), transparent);
  }
  .sidenav button {
    flex: 1 1 0;
    min-width: 4.6rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.2rem;
    padding: 0.5rem 0.35rem;
    text-align: center;
  }
  .sidenav button .nav-icon { margin-right: 0; font-size: 1.45rem; line-height: 1; }
  .sidenav button .nav-label { font-size: 0.7rem; line-height: 1.1; }
  .sidenav button .nav-tag { display: none; }

  /* Clears the fixed bottom tab bar so it never covers the page's last card. */
  .page { padding-bottom: calc(6.75rem + env(safe-area-inset-bottom, 0px)); }

  /* The chat button sits in the bottom-right corner the tab bar now leaves
     open, so the two are side by side and neither covers the other. The
     panel opens upward from it. */
  .faq-fab {
    right: 0.7rem;
    bottom: calc(1.1rem + env(safe-area-inset-bottom, 0px));
    left: auto;
    top: auto;
    width: 3rem;
    height: 3rem;
    font-size: 1.4rem;
  }
  .faq-panel {
    right: 0.7rem;
    left: 0.7rem;
    bottom: calc(4.9rem + env(safe-area-inset-bottom, 0px));
    top: auto;
    width: auto;
    max-height: min(480px, calc(100vh - 8rem));
  }
}

/* --- floating "ask about Tailorbird" chat widget (see partials/faq_answer.html,
   app/routes.py's help_ask) - shows on every page, signed in or not, since
   it never touches account-specific data. Sits above the sidenav's z-index
   (40) so it's never hidden behind the mobile bottom bar, but below the
   auth modal's (100) in case both are ever open at once. */

.faq-fab {
  position: fixed;
  right: 1.25rem;
  bottom: 1.25rem;
  z-index: 90;
  width: 3.75rem;
  height: 3.75rem;
  border-radius: 50%;
  background: var(--color-primary);
  color: var(--color-primary-contrast);
  border: none;
  font-size: 1.7rem;
  line-height: 1;
  box-shadow: var(--shadow-md);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.faq-fab:hover { background: var(--color-primary-hover); }

.faq-panel {
  position: fixed;
  right: 1.25rem;
  bottom: 5.5rem;
  z-index: 90;
  width: min(340px, calc(100vw - 2.5rem));
  max-height: min(480px, calc(100vh - 7rem));
  display: flex;
  flex-direction: column;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  overflow: hidden;
}
.faq-panel-header {
  padding: 0.85rem 1rem;
  border-bottom: 1px solid var(--color-border);
  background: var(--color-surface-2);
}
.faq-panel-body {
  padding: 0.85rem 1rem 1rem;
  overflow-y: auto;
}
.faq-panel-body input[type="text"] { margin-top: 0; }
.faq-panel-body .alert { font-size: 0.85rem; padding: 0.65rem 0.75rem; }

/* "Browse topics" drill-down chips (faq_topics.html/faq_questions.html) -
   horizontal wrap for the top-level category list, stacked full-width for
   the questions within one category (reads better as a menu than a wrap). */
.faq-chips { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.5rem; }
.faq-chips-vertical { flex-direction: column; }
.faq-chip {
  background: var(--color-surface-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  color: var(--color-body);
  font-size: 0.8rem;
  padding: 0.4rem 0.65rem;
  text-align: left;
  cursor: pointer;
}
.faq-chip:hover { border-color: var(--color-primary); color: var(--color-primary); }
.faq-back { margin-top: 0.5rem; }
.faq-contact { margin-top: 0.85rem; padding-top: 0.75rem; border-top: 1px solid var(--color-border); }
.faq-contact textarea { resize: vertical; }

/* --- brand header --- */

.brand {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  margin-bottom: 0.35rem;
}
a.brand {
  color: inherit;
  text-decoration: none;
  width: fit-content;
  transition: opacity 0.12s ease;
}
a.brand:hover { opacity: 0.82; text-decoration: none; }
.brand-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1.8rem;
  line-height: 1;
  flex: none;
}
.brand h1 {
  margin: 0;
  font-size: 1.5rem;
  letter-spacing: -0.01em;
}
.tagline {
  color: var(--color-body);
  margin: 0 0 1.75rem;
  font-size: 0.98rem;
}

h1, h2, h3, h4 { color: var(--color-ink); font-weight: 650; letter-spacing: -0.01em; }
h4 { font-size: 1.02rem; margin: 1.75rem 0 0.75rem; }

a { color: var(--color-primary); text-decoration: none; }
a:hover { text-decoration: underline; }

.muted { color: var(--color-muted); font-size: 0.9rem; }

/* --- horizontal tab bar (login page) --- */

.tabbar {
  display: inline-flex;
  gap: 0.2rem;
  margin-bottom: 1rem;
  background: var(--color-surface-2);
  border: 1px solid var(--color-border);
  border-radius: 999px;
  padding: 0.25rem;
}
/* Every real .tabbar button is type="button" (an Alpine-driven tab switch,
   never a real form submit - see login.html's auth tabs and
   account_dashboard.html's Daily/Weekly/Monthly toggles). The generic
   button[type="button"] rule further down (grey background at rest, an
   even greyer one on :hover) ties in CSS specificity with the plain
   ".tabbar button"/".tabbar button.active" selectors this used to be and
   wins on source order alone, since it's declared later in this file.
   Invisible on desktop (a mouse click doesn't leave :hover engaged), but a
   real, visible bug on mobile: a touch triggers :hover and leaves it
   "stuck" until the next tap elsewhere on the page, so the tab you just
   tapped renders the generic grey hover background instead of the
   intended blue active one, and the still-inactive tab renders the
   generic grey background instead of blending into the pill - both tabs
   read as "greyed out". Fixed by repeating [type="button"] in these
   selectors so they unconditionally out-specificity the generic rule
   instead of relying on source order - real bug, found 2026-09-02 from a
   mobile report, reproduced by working through the CSS cascade by hand. */
.tabbar button[type="button"] {
  all: unset;
  display: block;
  box-sizing: border-box;
  padding: 0.5rem 1.15rem;
  border-radius: 999px;
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--color-body);
  cursor: pointer;
  text-align: center;
}
.tabbar button[type="button"]:hover { color: var(--color-ink); }
.tabbar button[type="button"].active { background: var(--color-primary); color: var(--color-primary-contrast); }

/* --- card --- */

.card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: 1.75rem;
}

/* --- forms --- */

label {
  display: block;
  font-weight: 600;
  font-size: 0.92rem;
  margin: 1.1rem 0 0.35rem;
  color: var(--color-ink);
}
label > span, label .muted { font-weight: 400; display: block; margin-top: 0.15rem; }

input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"],
select,
textarea {
  width: 100%;
  font-family: inherit;
  font-size: 0.97rem;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  color: var(--color-ink);
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
input[type="file"] {
  width: 100%;
  font-size: 0.9rem;
  color: var(--color-body);
}
textarea { resize: vertical; min-height: 6rem; }

input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px var(--color-primary-tint);
}

input[type="range"] { width: 100%; accent-color: var(--color-primary); margin-top: 0.35rem; }

.password-field { position: relative; }
.password-field input { padding-right: 2.75rem; }
.password-toggle {
  all: unset;
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  /* The tap target spans the input's full height and a comfortably wide
     strip, not just the icon's own small footprint - the icon-sized hit
     area was the actual usability complaint (fine on a mouse, easy to miss
     with a thumb). Roughly 44px tall on this app's input sizing, matching
     the standard mobile touch-target guideline. */
  width: 2.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  color: var(--color-muted);
}
.password-toggle svg { width: 19px; height: 19px; flex: none; }
.password-toggle:hover { color: var(--color-body); }
input[type="checkbox"], input[type="radio"] { accent-color: var(--color-primary); margin-right: 0.4rem; }

fieldset {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 0.9rem 1rem 1rem;
  margin: 1.1rem 0;
}
legend {
  font-weight: 600;
  font-size: 0.88rem;
  padding: 0 0.4rem;
  color: var(--color-body);
}
fieldset label { margin: 0.5rem 0; font-weight: 400; }

/* radio/checkbox rows read better inline-block with their input */
fieldset label input, .checkbox-row input { margin-right: 0.45rem; }

/* --- buttons --- */

button, .btn {
  font-family: inherit;
  font-size: 0.95rem;
  font-weight: 600;
  padding: 0.65rem 1.15rem;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.05s ease;
}
button:active { transform: translateY(1px); }

button[type="submit"], button:not(.secondary):not([type="button"]) {
  background: var(--color-primary);
  color: var(--color-primary-contrast);
  width: 100%;
  margin-top: 1.5rem;
  padding: 0.75rem 1.15rem;
  font-size: 1rem;
}
button[type="submit"]:hover, button:not(.secondary):not([type="button"]):hover {
  background: var(--color-primary-hover);
}

button.secondary, button[type="button"] {
  background: var(--color-surface-2);
  color: var(--color-ink);
  border-color: var(--color-border);
}
button.secondary:hover, button[type="button"]:hover { background: var(--color-border); }

/* A type="button" element that should still read as the primary action -
   e.g. a wizard's "Next" step, which can't be type="submit" without
   actually submitting the form early. Same colors as the real submit
   button, sized by its own layout context rather than the full-width/
   margin-top the bare submit rule above assumes. */
button.btn-primary { background: var(--color-primary); color: var(--color-primary-contrast); border-color: transparent; }
button.btn-primary:hover { background: var(--color-primary-hover); }

button:disabled { opacity: 0.5; cursor: not-allowed; }

/* plain text-link button, e.g. "Forgot password?" - escapes the generic
   button[type="button"] chip styling above via all:unset */
.link-button {
  all: unset;
  display: inline;
  color: var(--color-primary);
  font-size: 0.88rem;
  font-weight: 600;
  cursor: pointer;
}
.link-button:hover { text-decoration: underline; }

/* the run-settings toggle summary line acts like a button */
details > summary {
  cursor: pointer;
  font-weight: 600;
  list-style: none;
}
details > summary::-webkit-details-marker { display: none; }
details > summary::before {
  content: "▸ ";
  color: var(--color-muted);
}
details[open] > summary::before { content: "▾ "; }

/* --- panels within the card --- */

#run-settings-panel > details,
#api-key-box > details {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 0.9rem 1.1rem;
  margin: 1.25rem 0;
  background: var(--color-surface-2);
}

.cost-box {
  background: var(--color-primary-tint);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 0.85rem 1.1rem;
  margin: 1rem 0 0.6rem;
}
.cost-box b { font-size: 1.15rem; color: var(--color-ink); }

.job-row {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 1.1rem 1.2rem;
  margin-bottom: 0.85rem;
  background: var(--color-surface);
}

/* --- stat cards / data tables (dashboard) --- */

.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 1rem;
  margin: 1rem 0 1.5rem;
}
.stat-card {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.85rem;
  min-height: 5.75rem;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--color-primary);
  border-radius: var(--radius-md);
  padding: 1rem 1.1rem;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.stat-card > div { min-width: 0; }
.stat-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); }
.stat-card .stat-icon {
  flex: none;
  width: 2.4rem;
  height: 2.4rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-md);
  font-size: 1.2rem;
  background: var(--color-primary-tint);
}
.stat-card .stat-value { font-size: 1.5rem; font-weight: 700; color: var(--color-ink); line-height: 1.15; }
.stat-card .stat-label { font-size: 0.8rem; color: var(--color-muted); margin-top: 0.2rem; }

/* Color variants - same shape, different accent per KPI category so a busy
   grid still reads at a glance rather than as one flat wall of cards. */
.stat-card--blue { border-left-color: var(--color-primary); }
.stat-card--blue .stat-icon { background: var(--color-primary-tint); }
.stat-card--green { border-left-color: var(--color-success); }
.stat-card--green .stat-icon { background: var(--color-success-bg); }
.stat-card--purple { border-left-color: var(--color-purple); }
.stat-card--purple .stat-icon { background: var(--color-purple-bg); }
.stat-card--teal { border-left-color: var(--color-teal); }
.stat-card--teal .stat-icon { background: var(--color-teal-bg); }
.stat-card--amber { border-left-color: var(--color-warning); }
.stat-card--amber .stat-icon { background: var(--color-warning-bg); }
.stat-card--pink { border-left-color: var(--color-pink); }
.stat-card--pink .stat-icon { background: var(--color-pink-bg); }
.stat-card--cyan { border-left-color: var(--color-cyan); }
.stat-card--cyan .stat-icon { background: var(--color-cyan-bg); }
.stat-card--indigo { border-left-color: var(--color-indigo); }
.stat-card--indigo .stat-icon { background: var(--color-indigo-bg); }

/* Billing ledger cost figures (account_dashboard.html's two usage tables) -
   color tied to real meaning, not decoration: green once a number is a real
   Batches-API-sourced actual cost, amber while it's still cost_model.py's
   pre-run estimate, cyan for a duplicate_saved row (money NOT spent, kept
   visually distinct from an actual charge - same cyan as the Overview tab's
   "Saved by skipping N duplicates" stat card). */
.cost-actual { color: var(--color-success); font-weight: 600; }
.cost-estimated { color: var(--color-warning); font-weight: 600; }
.cost-saved { color: var(--color-cyan); font-weight: 600; }

.table-scroll { overflow-x: auto; }
.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.88rem;
}
.data-table th, .data-table td {
  text-align: left;
  padding: 0.55rem 0.7rem;
  border-bottom: 1px solid var(--color-border);
  white-space: nowrap;
}
.data-table th { color: var(--color-muted); font-weight: 600; font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.03em; }
/* A cell that can hold long free text (a failure reason, a note) needs to
   wrap and stay capped in width - otherwise one long value stretches that
   column indefinitely and pushes every column after it out of view. */
.data-table td.wrap { white-space: normal; max-width: 280px; }
.data-table tr:last-child td { border-bottom: none; }
.data-table tbody tr { transition: background 0.1s ease; }
.data-table tbody tr:hover { background: var(--color-surface-2); }

/* Applications tracker table: a frozen header, and on a real screen a fixed
   column layout so all nine columns fit at a glance with no left/right
   scroll to reach Status. Scoped to this one table - every other .data-table
   (billing, run history, admin) is untouched.

   Real bug, fixed 2026-09-03: the Fit column (added earlier the same week)
   was inserted into the header and the row template but this width table
   was never updated for the 9th column. table-layout: fixed then divided
   the row's real width across the 8 percentages below for what is now 9
   columns, so the last one (Status, no rule at all) collapsed to almost
   nothing - its header text wrapped one letter per line and the colored
   .status-select shrank to just its native arrow, hiding the label
   entirely. That is also what forced scrolling to reach it at all. */
.applications-scroll {
  max-height: 72vh;
  overflow: auto;
}
.applications-table thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--color-surface);
  box-shadow: inset 0 -1px 0 var(--color-border);
}
@media (min-width: 900px) {
  .applications-table {
    table-layout: fixed;
    width: 100%;
  }
  .applications-table th,
  .applications-table td {
    white-space: normal;
    overflow-wrap: anywhere;
    padding: 0.5rem 0.55rem;
    vertical-align: top;
  }
  /* Date, Company, Role, Fit, Job description, Resume, Cover letter,
     Interview prep, Status - 9 columns, must sum to 100%. Status is
     deliberately generous (wider than any column but Role) so its colored
     pill and label always render in full with no horizontal scroll. */
  .applications-table thead th:nth-child(1) { width: 7%; }
  .applications-table thead th:nth-child(2) { width: 10%; }
  .applications-table thead th:nth-child(3) { width: 13%; }
  .applications-table thead th:nth-child(4) { width: 11%; }
  .applications-table thead th:nth-child(5) { width: 7%; }
  .applications-table thead th:nth-child(6) { width: 10%; }
  .applications-table thead th:nth-child(7) { width: 12%; }
  .applications-table thead th:nth-child(8) { width: 12%; }
  .applications-table thead th:nth-child(9) { width: 18%; }
  .applications-table select {
    width: 100%;
    max-width: 100%;
    font-size: 0.8rem;
  }
  .applications-table .link-button,
  .applications-table button { font-size: 0.8rem; }
  /* The expandable View / Why? panels are capped to their cell instead of a
     fixed 420px that would blow the fixed layout back open. */
  .applications-table details > div { max-width: 100% !important; }
}

.badge {
  display: inline-block;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 600;
}
.badge-actual { background: var(--color-success-bg); color: var(--color-success); }
.badge-estimated { background: var(--color-surface-2); color: var(--color-muted); }
.badge-done { background: var(--color-success-bg); color: var(--color-success); }
.badge-running { background: var(--color-primary-tint); color: var(--color-primary); }
.badge-error { background: var(--color-error-bg); color: var(--color-error); }
.badge-mail_failed { background: var(--color-warning-bg); color: var(--color-warning); }

/* Needs-attention count, e.g. pending account requests - solid red, not the
   softer tinted badges above, so it actually reads as "look at this" rather
   than blending in with the rest of the nav. */
.badge-alert {
  display: inline-block;
  min-width: 1.2rem;
  padding: 0.05rem 0.4rem;
  border-radius: 999px;
  background: var(--color-error);
  color: var(--color-primary-contrast);
  font-size: 0.75rem;
  font-weight: 700;
  text-align: center;
  line-height: 1.3;
}

/* Application tracker statuses - one accent per stage of the pipeline. */
/* Fit verdict from the pre-tailoring read (app/runs.py record_job_scores).
   Reuses the same token palette as the application-status badges so the
   Applications table reads as one system. */
.badge-strong-fit { background: var(--color-success-bg); color: var(--color-success); }
.badge-good-fit   { background: var(--color-primary-tint); color: var(--color-primary); }
.badge-stretch    { background: var(--color-warning-bg); color: var(--color-warning); }
.badge-poor-fit   { background: var(--color-error-bg); color: var(--color-error); }

.badge-not_applied { background: var(--color-surface-2); color: var(--color-muted); }
.badge-applied { background: var(--color-primary-tint); color: var(--color-primary); }
.badge-interview { background: var(--color-purple-bg); color: var(--color-purple); }
.badge-offer { background: var(--color-success-bg); color: var(--color-success); }
.badge-rejected { background: var(--color-error-bg); color: var(--color-error); }
.badge-withdrawn { background: var(--color-warning-bg); color: var(--color-warning); }
.badge-not_applying { background: var(--color-surface-2); color: var(--color-muted); }

.status-select {
  width: auto;
  padding: 0.3rem 1.8rem 0.3rem 0.6rem;
  font-size: 0.82rem;
  font-weight: 600;
  border-radius: 999px;
}
.status-select.status-not_applied { background: var(--color-surface-2); color: var(--color-muted); border-color: var(--color-border); }
.status-select.status-applied { background: var(--color-primary-tint); color: var(--color-primary); border-color: var(--color-primary); }
.status-select.status-interview { background: var(--color-purple-bg); color: var(--color-purple); border-color: var(--color-purple); }
.status-select.status-offer { background: var(--color-success-bg); color: var(--color-success); border-color: var(--color-success-border); }
.status-select.status-rejected { background: var(--color-error-bg); color: var(--color-error); border-color: var(--color-error-border); }
.status-select.status-withdrawn { background: var(--color-warning-bg); color: var(--color-warning); border-color: var(--color-warning-border); }
.status-select.status-not_applying { background: var(--color-surface-2); color: var(--color-muted); border-color: var(--color-border); }

/* --- section headers / dashboard chrome --- */

.dash-hero {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin: 0 0 1.25rem;
}
.dash-hero h3 { margin: 0; font-size: 1.3rem; }
.dash-hero .muted { margin: 0.2rem 0 0; }
.dash-section-title {
  font-size: 0.78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-muted);
  margin: 1.75rem 0 0.75rem;
}
.dash-section-title:first-child { margin-top: 0; }

/* --- Help tab --- */

.help-toc {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.25rem;
  margin: 0 0 1.5rem;
  padding: 0;
  list-style: none;
}
.help-toc a { font-size: 0.9rem; font-weight: 600; }

.help-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 1rem;
  margin: 1rem 0 1.5rem;
}
.help-grid .feature-card { margin: 0; }

.help-flow {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin: 1.25rem 0 2rem;
  text-align: center;
}
.help-flow-step {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: 1.1rem 1.3rem;
  min-width: 130px;
}
.help-flow-icon { font-size: 1.8rem; display: block; margin-bottom: 0.4rem; }
.help-flow-label { font-weight: 700; font-size: 0.9rem; }
.help-flow-arrow { color: var(--color-muted); font-size: 1.3rem; }

.code-chip {
  display: inline-block;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.85rem;
  background: var(--color-surface-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: 0.1rem 0.45rem;
  color: var(--color-primary);
}

.help-section { scroll-margin-top: 1rem; }

/* --- mini bar chart (spend trend) - vanilla CSS, no chart library --- */

.bar-chart {
  display: flex;
  align-items: flex-end;
  gap: 0.6rem;
  height: 110px;
  padding: 0 0.25rem;
  margin: 0.5rem 0 0.25rem;
}
.bar-chart .bar-col {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  height: 100%;
  justify-content: flex-end;
  gap: 0.4rem;
}
.bar-chart .bar {
  width: 100%;
  max-width: 34px;
  border-radius: 4px 4px 0 0;
  background: linear-gradient(180deg, var(--color-primary) 0%, var(--color-primary-hover) 100%);
  min-height: 3px;
  transition: opacity 0.15s ease;
}
.bar-chart .bar-col:hover .bar { opacity: 0.8; }
.bar-chart .bar-value { font-size: 0.72rem; color: var(--color-muted); }
.bar-chart .bar-label { font-size: 0.72rem; color: var(--color-muted); white-space: nowrap; }

/* On a phone the daily view has far more bars than fit - let the chart
   overflow inside its .table-scroll wrapper and swipe sideways, same as the
   Recent activity table right below it, instead of crushing every bar to a
   sliver. Desktop is unchanged: no min-width, bars flex to fill. */
@media (max-width: 760px) {
  .table-scroll > .bar-chart { min-width: max-content; padding-bottom: 0.35rem; }
  .table-scroll > .bar-chart .bar-col { flex: 0 0 2rem; }
}

/* --- alerts / status messages --- */

.alert {
  border-radius: var(--radius-md);
  padding: 0.7rem 1rem 0.8rem;
  margin: 1rem 0;
  border: 1px solid;
  border-left-width: 4px;
  font-size: 0.95rem;
}
/* A short uppercase category label on every alert so an error is never
   mistaken for a note (a soft-red box and a soft-blue box can blur together
   at a glance; the label plus the thick left border make the kind explicit). */
.alert::before {
  display: block;
  margin-bottom: 0.25rem;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.alert-success { background: var(--color-success-bg); border-color: var(--color-success-border); color: var(--color-success); }
.alert-success::before { content: "Done"; }
.alert-error { background: var(--color-error-bg); border-color: var(--color-error-border); color: var(--color-error); }
.alert-error::before { content: "Error"; }
.alert-warning { background: var(--color-warning-bg); border-color: var(--color-warning-border); color: var(--color-warning); }
.alert-warning::before { content: "Heads up"; }
.alert-info { background: var(--color-primary-tint); border-color: var(--color-primary); color: var(--color-body); }
.alert-info::before { content: "Note"; color: var(--color-primary); }
.alert b { color: inherit; }

/* One-line dashboard notification (Needs attention, "N batches running/
   completed") - added 2026-09-04 after the default .alert (category label
   on its own line, a heading, a bulleted list, a separate footer paragraph)
   read as a small essay per notification and, with several of them stacked,
   made the page feel far busier than the one line of real information each
   one actually carries. The category label collapses into the bold lead-in
   text instead of its own ::before row, and everything else - counts,
   company names, the action link - flows as one wrapped paragraph rather
   than a heading plus a <ul>. Still wraps normally on a narrow screen; the
   point is one paragraph of prose per notification, not one physical line
   no matter the content length. */
.alert-compact { padding: 0.55rem 0.9rem; }
.alert-compact::before { display: none; }
.alert-compact .link-button { margin-left: 0.4rem; white-space: nowrap; }

/* Inline per-field validation hint (see intake.html) - a plain character
   count while it's fine, red and bold once the value is actually invalid. */
.field-hint { font-size: 0.8rem; color: var(--color-muted); margin: 0.3rem 0 0.2rem; }
.field-hint-bad { color: var(--color-error); font-weight: 600; }

hr { border: none; border-top: 1px solid var(--color-border); margin: 1.75rem 0; }

.top-link { display: inline-block; margin-bottom: 1.25rem; font-size: 0.9rem; }

@media (max-width: 480px) {
  /* bottom value must stay in step with the 760px rule above - it clears the
     fixed tab bar, and this shorthand would otherwise reset it to 3rem */
  .page { padding: 1.5rem 1rem calc(6.75rem + env(safe-area-inset-bottom, 0px)); }
  .card { padding: 1.25rem; border-radius: var(--radius-md); }
  .job-row { padding: 0.9rem 1rem; }
  fieldset { padding: 0.75rem 0.85rem 0.85rem; }
}

/* --- portal (home) page --- */

.portal-hero {
  text-align: center;
  padding: 3rem 0 2.5rem;
  animation: portal-fade-up 0.6s ease both;
}
.portal-eyebrow {
  color: var(--color-muted);
  font-size: 0.95rem;
  margin: 0 0 0.25rem;
  letter-spacing: 0.02em;
}
.portal-heading {
  font-size: 2rem;
  margin: 0 0 0.5rem;
}

.app-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 1.25rem;
  animation: portal-fade-up 0.6s ease 0.15s both;
}

.app-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 0.5rem;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: 2rem 1.25rem;
  color: var(--color-ink);
  text-decoration: none;
  transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}
.app-tile:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-md);
  border-color: var(--color-primary);
  text-decoration: none;
}
.app-tile-icon { font-size: 2.5rem; line-height: 1; }
.app-tile-name { font-weight: 700; font-size: 1.05rem; color: var(--color-ink); }
.app-tile-desc { color: var(--color-body); font-size: 0.85rem; }

.app-tile.app-tile--soon {
  cursor: default;
  border-style: dashed;
  background: transparent;
}
.app-tile.app-tile--soon:hover {
  transform: none;
  box-shadow: none;
  border-color: var(--color-border);
}
.app-tile.app-tile--soon .app-tile-icon { opacity: 0.6; }
.app-tile.app-tile--soon .app-tile-name { color: var(--color-body); }
.app-tile-badge {
  display: inline-block;
  padding: 0.15rem 0.6rem;
  border-radius: 999px;
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  background: var(--color-primary-tint);
  color: var(--color-primary);
}

@keyframes portal-fade-up {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: translateY(0); }
}

/* --- landing page (login.html) - full-bleed marketing bands ---

   login.html sets pageclass="page-flush" so the landing page opts out of
   base.html's centered .page column entirely: its section backgrounds run
   edge to edge like a real marketing site, and each band re-centres its own
   content in .lp-inner. Every band shares one vertical rhythm (the .lp-band
   padding) so sections sit an even distance apart instead of one block up
   top and the next far below it. */

.page.page-flush {
  max-width: none;
  padding: 0;
  margin: 0;
}

.lp-inner {
  max-width: 1280px;
  margin: 0 auto;
  padding: 0 clamp(1.25rem, 5vw, 3rem);
}

.lp-band { padding: clamp(2rem, 4vw, 3rem) 0; }
.lp-band-alt {
  background: var(--color-surface);
  border-top: 1px solid var(--color-border);
  border-bottom: 1px solid var(--color-border);
}

.lp-nav-band {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(18, 21, 28, 0.9);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--color-border);
}
.site-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.8rem 0;
}
.site-nav .brand { margin-bottom: 0; }
.btn-nav {
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--color-ink);
  padding: 0.5rem 1.1rem;
  border: 1px solid var(--color-border);
  border-radius: 999px;
}
.btn-nav:hover { background: var(--color-surface-2); text-decoration: none; }

/* A page's top action buttons (dashboard, intake): every button the same
   size, wrapping to the next row as a block rather than each one hugging its
   own label width. */
.action-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-bottom: 1.5rem;
}
.action-row > a {
  flex: 1 1 11rem;
  max-width: 17rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  margin: 0;
  padding: 0.55rem 1rem;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--color-ink);
  border: 1px solid var(--color-border);
  border-radius: 999px;
  text-align: center;
}
.action-row > a:hover { background: var(--color-surface-2); text-decoration: none; }

.lp-hero-band {
  background:
    radial-gradient(1100px 460px at 80% -10%, var(--color-primary-tint), transparent 68%),
    var(--color-bg);
  padding: clamp(2.25rem, 4.5vw, 3.25rem) 0;
}
.hero {
  display: grid;
  grid-template-columns: 1.15fr 0.85fr;
  align-items: center;
  gap: clamp(2rem, 5vw, 3.5rem);
  animation: portal-fade-up 0.7s ease both;
}
.hero-copy { min-width: 0; }
.hero-eyebrow {
  display: inline-block;
  color: var(--color-primary);
  background: var(--color-primary-tint);
  padding: 0.35rem 0.85rem;
  border-radius: 999px;
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  margin-bottom: 1.1rem;
}
.hero-heading {
  font-size: clamp(2.1rem, 4.6vw, 3.1rem);
  line-height: 1.12;
  margin: 0 0 1.1rem;
  letter-spacing: -0.02em;
}
.hero-sub {
  font-size: clamp(1rem, 1.6vw, 1.15rem);
  color: var(--color-body);
  margin: 0 0 1.9rem;
  max-width: 32rem;
}
.hero-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1.25rem;
}
.hero-visual {
  display: flex;
  justify-content: center;
}
.hero-illustration {
  width: min(100%, 420px);
  height: auto;
  animation: hero-float 5s ease-in-out infinite;
}
@keyframes hero-float {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-10px); }
}

/* Hero illustration: the primary-blue "matched" lines sweep in left to right,
   then the fit-score check draws on. Plain CSS animation (auto-runs on load,
   always completes - the hero is above the fold), disabled under
   prefers-reduced-motion above. */
.hi-line {
  transform: scaleX(0);
  transform-origin: left center;
  transform-box: fill-box;
  animation: hi-line-in 0.5s ease forwards;
}
.hi-line-1 { animation-delay: 0.35s; }
.hi-line-2 { animation-delay: 0.55s; }
.hi-line-3 { animation-delay: 0.75s; }
.hi-check {
  opacity: 0;
  transform: scale(0.4);
  transform-origin: center;
  transform-box: fill-box;
  animation: hi-check-in 0.45s cubic-bezier(0.34, 1.56, 0.64, 1) 1s forwards;
}
@keyframes hi-line-in { to { transform: scaleX(1); } }
@keyframes hi-check-in { to { opacity: 1; transform: scale(1); } }

/* Small application-tracker mock beside the "out the door" checklist. */
.lp-split {
  display: grid;
  grid-template-columns: 0.85fr 1fr;
  align-items: center;
  gap: clamp(1.5rem, 4vw, 3rem);
}
.lp-split .extras { column-count: 1; max-width: none; margin: 0; }
.tracker-illo {
  width: 100%;
  max-width: 380px;
  height: auto;
  justify-self: center;
}
/* The green "Offer" pill breathes gently to draw the eye. */
.tracker-illo .t-pulse { animation: t-pulse 2.4s ease-in-out infinite; }
@keyframes t-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }

/* button.btn-* (not bare .btn-*): these sit on <button type="button">
   elements, and the generic `button[type="button"]` chip rule above is
   specificity 0,1,1 - a bare .btn-cta (0,1,0) loses to it on background and
   colour. Matching that specificity here (and coming later in the file) is
   what lets the hero's primary button actually render primary. */
button.btn-cta {
  display: inline-flex;
  align-items: center;
  background: var(--color-primary);
  color: var(--color-primary-contrast);
  border-color: transparent;
  font-weight: 700;
  font-size: 1rem;
  padding: 0.8rem 1.6rem;
  border-radius: var(--radius-sm);
}
button.btn-cta:hover { background: var(--color-primary-hover); text-decoration: none; }
/* Secondary hero action: a plain text button, no box - nothing to mismatch
   the primary button's size against. Same vertical padding so the two align. */
button.btn-ghost {
  display: inline-flex;
  align-items: center;
  background: transparent;
  border-color: transparent;
  color: var(--color-body);
  font-weight: 600;
  font-size: 0.95rem;
  padding: 0.8rem 0.5rem;
}
button.btn-ghost:hover { background: transparent; color: var(--color-ink); text-decoration: underline; }

.reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}
/* transform: none (not translateY(0)) once revealed - a lingering transform
   value keeps establishing a containing block, which would trap any
   position: fixed descendant (the mobile bottom sidenav, the auth modal).
   The reveal is used app-wide now, not just on the landing page. */
.reveal.is-visible { opacity: 1; transform: none; }

/* Stagger: put "reveal reveal-stagger" on a grid/row and its direct children
   fade up one after another once the container scrolls into view. The base.html
   observer still only watches for .reveal, so this needs no extra JS, and the
   same 2s failsafe there force-reveals everything if the observer never fires. */
/* The stagger container itself only fades (no slide) - the per-child slide
   below carries the motion, so the two don't compound into a 40px jump. */
.reveal-stagger { transform: none; }
.reveal-stagger > * {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.55s ease, transform 0.55s ease;
}
.reveal-stagger.is-visible > * { opacity: 1; transform: none; }
.reveal-stagger.is-visible > *:nth-child(2) { transition-delay: 0.07s; }
.reveal-stagger.is-visible > *:nth-child(3) { transition-delay: 0.14s; }
.reveal-stagger.is-visible > *:nth-child(4) { transition-delay: 0.21s; }
.reveal-stagger.is-visible > *:nth-child(5) { transition-delay: 0.28s; }
.reveal-stagger.is-visible > *:nth-child(6) { transition-delay: 0.35s; }
.reveal-stagger.is-visible > *:nth-child(7) { transition-delay: 0.42s; }
.reveal-stagger.is-visible > *:nth-child(8) { transition-delay: 0.49s; }

@media (prefers-reduced-motion: reduce) {
  .reveal,
  .reveal-stagger > *,
  .hero-illustration [class^="hi-"],
  .tracker-illo [class^="t-"] {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
    animation: none !important;
  }
}

.section-heading { text-align: center; font-size: clamp(1.5rem, 3vw, 2rem); margin: 0 0 0.4rem; }
.section-sub { text-align: center; color: var(--color-body); margin: 0 auto 1.75rem; max-width: 520px; }

.steps {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1rem, 2vw, 1.5rem);
}
.step {
  text-align: center;
  padding: clamp(1.35rem, 2.5vw, 1.9rem) 1.35rem;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
}
.step-icon {
  width: 3.25rem;
  height: 3.25rem;
  border-radius: 999px;
  background: var(--color-primary-tint);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.5rem;
  margin: 0 auto 1rem;
}
.step-num { font-size: 0.75rem; font-weight: 700; color: var(--color-muted); letter-spacing: 0.08em; margin: 0 0 0.4rem; }
.step-title { font-weight: 700; margin: 0 0 0.4rem; }
.step-desc { color: var(--color-body); font-size: 0.92rem; margin: 0; }

.features {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1rem, 2vw, 1.5rem);
}
.feature-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: 1.6rem;
  box-shadow: var(--shadow-sm);
}
.feature-icon { font-size: 1.7rem; margin-bottom: 0.6rem; display: block; }
.feature-title { font-weight: 700; margin: 0 0 0.35rem; }
.feature-desc { color: var(--color-body); font-size: 0.9rem; margin: 0; }

.extras {
  list-style: none;
  padding: 0;
  margin: 0 auto;
  max-width: 940px;
  column-count: 2;
  column-gap: 2.5rem;
}
.extras li {
  display: flex;
  align-items: start;
  gap: 0.6rem;
  margin-bottom: 0.9rem;
  break-inside: avoid;
  font-size: 0.95rem;
  color: var(--color-body);
  line-height: 1.45;
}
.extras li:last-child { margin-bottom: 0; }
.extra-mark {
  color: var(--color-primary);
  font-weight: 700;
  flex-shrink: 0;
}

.lp-cta-band {
  background:
    radial-gradient(680px 260px at 50% 45%, var(--color-primary-tint), transparent 75%),
    var(--color-bg);
  text-align: center;
  padding: clamp(2rem, 4vw, 2.75rem) 0;
}
.cta-heading { font-size: clamp(1.5rem, 3.2vw, 2rem); margin: 0 0 0.5rem; }
.cta-sub { color: var(--color-body); margin: 0 auto 1.4rem; max-width: 460px; }

.lp-footer-band {
  background: var(--color-surface);
  border-top: 1px solid var(--color-border);
  padding: 2.25rem 0;
}
.landing-footer {
  text-align: center;
  color: var(--color-muted);
  font-size: 0.85rem;
}

@media (max-width: 860px) {
  .features { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 760px) {
  .hero { grid-template-columns: 1fr; text-align: center; gap: 1.5rem; }
  .hero-sub { max-width: none; margin-left: auto; margin-right: auto; }
  .hero-actions { justify-content: center; }
  .hero-visual { order: -1; }
  .hero-illustration { width: min(42%, 170px); }
  .steps { grid-template-columns: 1fr; }
  .features { grid-template-columns: 1fr; }
  .extras { column-count: 1; max-width: 26rem; }
  .lp-split { grid-template-columns: 1fr; }
  .lp-split .extras { max-width: 26rem; margin: 0 auto; }
  .tracker-illo { max-width: 320px; }
  .site-nav .brand h1 { font-size: 1.25rem; }
  .lp-footer-band { padding-bottom: 7rem; }
}

@media (max-width: 480px) {
  .modal-backdrop { padding: 0.75rem; }
  .modal-card { padding: 1.75rem 1.25rem; max-height: 95vh; }
  .modal-close { top: 0.75rem; right: 0.85rem; }
  .auth-heading { font-size: 1.2rem; }
  .auth-links { flex-wrap: wrap; gap: 0.75rem 1.5rem; justify-content: flex-start; }
  .hero-eyebrow { font-size: 0.72rem; padding: 0.3rem 0.7rem; }
  button.btn-cta { width: 100%; justify-content: center; }
  button.btn-ghost { width: 100%; justify-content: center; }
}

/* --- auth modal (sign in / forgot password / reset password / status) --- */

.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(15, 18, 25, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  z-index: 100;
}
.modal-card {
  position: relative;
  background: var(--color-surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  padding: 2.5rem 2.25rem;
  width: 100%;
  max-width: 400px;
  max-height: 90vh;
  overflow-y: auto;
}
.modal-close {
  all: unset;
  position: absolute;
  top: 1rem;
  right: 1.15rem;
  cursor: pointer;
  color: var(--color-muted);
  font-size: 1.4rem;
  line-height: 1;
}
.modal-close:hover { color: var(--color-ink); }

.auth-logo { display: flex; justify-content: center; font-size: 2rem; margin-bottom: 0.75rem; }
.auth-heading { text-align: center; font-size: 1.35rem; margin: 0 0 0.35rem; }
.auth-subheading { text-align: center; color: var(--color-body); font-size: 0.9rem; margin: 0 0 1.5rem; }
.auth-links { display: flex; justify-content: space-between; margin-top: 1.25rem; font-size: 0.85rem; }
.auth-links-center { text-align: center; margin-top: 1.25rem; font-size: 0.85rem; }
.auth-tabs { justify-content: center; margin-bottom: 1.25rem; }
