@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Outfit:wght@400;600;700;800&family=DM+Mono:wght@400;500&family=Geist:wght@400;500;600;700&family=Manrope:wght@400;500;600;700;800&family=IBM+Plex+Sans:wght@400;500;600;700&family=Source+Sans+3:wght@400;500;600;700&family=Atkinson+Hyperlegible:wght@400;700&display=swap');

:root {
  /* ===== Brand reference palette ===== */
  --brand-green:      #39D353;
  --brand-green-dark: #1A7F2E;
  --brand-purple:     #7C3AED;
  --brand-gold:       #F0C94E;
  --brand-pale:       #EAF1F4;
  --brand-black:      #1C2733;

  /* ===== Semantic color tokens =====
     Brand direction: black / purple / gold / white. --brand (primary,
     interactive — buttons/links/active states) is now purple. Green moved
     to --success, a distinct token, on purpose: "done"/checkmarks/progress
     reading green is a strong enough UX convention that folding it into the
     purple primary would make completion states harder to scan, not just
     recolor them. --secondary (gold) is the premium/highlight accent. */
  --bg:               #1C2733;
  --surface:          #283848;
  --surface-raised:   #22303E;
  --text:             #EAF1F4;
  --text-muted:       #A9C3D4;
  --brand:            #7C3AED;
  --brand-dim:        #6D28D9;
  --brand-light:      #8B5CF6;
  --brand-dark:       #5B21B6;
  --brand-rgb:        124, 58, 237;
  --brand-gradient:   linear-gradient(135deg, var(--brand-light), var(--brand), var(--brand-dark));
  --accent:           var(--brand);
  --accent-dim:       var(--brand-dim);
  --accent-light:     var(--brand-light);
  --accent-rgb:       var(--brand-rgb);
  --success:          #39D353;
  --success-dim:      #2AA841;
  --success-light:    #5CE075;
  --success-dark:     #1A7F2E;
  --success-rgb:      57, 211, 83;
  --secondary:        #F0C94E;
  --secondary-dim:    #D4AD32;
  --secondary-light:  #F5DA7E;
  --secondary-rgb:    240, 201, 78;
  --danger:           #e11d48;
  --danger-rgb:       225, 29, 72;
  --warning:          #F0C94E;
  --border:           #35485A;
  --border-highlight: #455C72;
  --grid-line:        #243342;
  --glow-primary:     var(--brand);
  --glow-secondary:   var(--secondary);
  --glow-opacity:     0.15;
  --nav-bg:           rgba(10, 10, 12, 0.7);

  /* ===== Legacy aliases (migration — remove in Phase 2+) ===== */
  --fg:               var(--text);
  --fg-muted:         var(--text-muted);
  --bg-card:          var(--surface);
  --bg-raised:        var(--surface-raised);
  --gold:             var(--secondary);
  --accent-gradient:  var(--brand-gradient);
  --accent-dark:      var(--brand-dark);

  /* ===== Type scale =====
     Bumped up from the original (base 1rem/16px, xl 1.8rem) — the app read
     as too small/flat. --text-md/--text-3xl are new steps filling gaps that
     forced components to reach for one-off rem values. */
  --text-xs:      0.8125rem;  /* 13px */
  --text-sm:      0.9375rem;  /* 15px */
  --text-base:    1.0625rem;  /* 17px */
  --text-md:      1.1875rem;  /* 19px */
  --text-lg:      1.375rem;   /* 22px */
  --text-xl:      1.75rem;    /* 28px */
  --text-2xl:     2.25rem;    /* 36px */
  --text-3xl:     2.75rem;    /* 44px */
  --text-display: 4rem;       /* 64px */

  /* ===== Line heights ===== */
  --leading-tight:   1.15;
  --leading-snug:    1.3;
  --leading-normal:  1.55;
  --leading-relaxed: 1.75;

  /* ===== Spacing scale ===== */
  --space-1:  4px;
  --space-2:  8px;
  --space-3:  12px;
  --space-4:  16px;
  --space-5:  20px;
  --space-6:  24px;
  --space-8:  32px;
  --space-10: 40px;
  --space-12: 48px;
  --space-16: 64px;

  /* ===== Content widths =====
     Single-column form/card width, standardized across settings, the
     checklist builder, and the danger-zone/actions-zone panels — was
     five separate hardcoded 640px literals that happened to agree.
     Widened modestly (640->720) to cut down on unused whitespace beside
     these cards on large displays, without stretching single-line text
     inputs uncomfortably wide. */
  --content-width-form: 720px;

  /* ===== Radii ===== */
  --radius-sm:   6px;
  --radius-md:   8px;
  --radius-lg:   12px;
  --radius-xl:   16px;
  --radius-2xl:  20px;
  --radius-full: 100px;

  /* ===== Shadows ===== */
  --shadow-sm:  0 4px 15px rgba(var(--brand-rgb), 0.3);
  --shadow-md:  0 8px 24px rgba(0, 0, 0, 0.28);
  --shadow-lg:  0 8px 32px rgba(0, 0, 0, 0.2);
  --shadow-xl:  0 24px 64px rgba(0, 0, 0, 0.4);

  /* ===== Font families (selectable — see public/css/fonts.css) =====
     --font-body/--font-heading are the ACTIVE selection; a [data-font-theme]
     attribute on <html> repoints them to one of the families below. Never
     reference --font-inter etc. directly in component CSS — use
     --font-body/--font-heading/--font-mono so a user's font choice applies
     everywhere automatically. */
  --font-inter:        'Inter', sans-serif;
  --font-geist:         'Geist', sans-serif;
  --font-manrope:       'Manrope', sans-serif;
  --font-outfit:        'Outfit', sans-serif;
  --font-ibm-plex:      'IBM Plex Sans', sans-serif;
  --font-source-sans:   'Source Sans 3', sans-serif;
  --font-atkinson:      'Atkinson Hyperlegible', sans-serif;
  /* Branding/headings only (hero titles, optional dashboard headings) — not
     a body-text option. No font file is bundled yet, so this deliberately
     falls back to the heading font rather than 404ing on a missing asset. */
  --font-beyonders:     'Beyonders', var(--font-heading);

  --font-body:    var(--font-inter);
  --font-heading: var(--font-outfit);
  --font-mono:    'DM Mono', monospace;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

/* Keyboard-focus fallback for interactive elements that don't already
   define their own focus treatment (buttons, links, custom controls).
   Deliberately excludes input/textarea/select — those already carry a
   border+box-shadow focus ring per component, and adding this outline
   on top would double up rather than fill a gap. :focus-visible (not
   :focus) so mouse/touch activation doesn't show a ring a keyboard user
   didn't ask for. */
a:focus-visible,
button:focus-visible,
[role="button"]:focus-visible,
[tabindex]:focus-visible,
summary:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

html { scroll-behavior: smooth; }

body {
  /* Grid-line backdrop (matches the Squared Away site): faint lines every
     48px drawn with two gradients, layered over the base background color. */
  background-color: var(--bg);
  background-image:
    linear-gradient(var(--grid-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
  background-size: 48px 48px;
  color: var(--text);
  font-family: var(--font-body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  position: relative;
}

/* Background glows.
   Decorative background glow intentionally extends beyond the viewport.
   overflow-x:hidden prevents any horizontal scrolling.
   Expected behavior. */
body::before, body::after {
  content: '';
  position: absolute;
  width: 600px;
  height: 600px;
  border-radius: 50%;
  filter: blur(120px);
  z-index: -1;
  opacity: var(--glow-opacity);
  pointer-events: none;
}
body::before {
  top: -100px;
  left: -200px;
  background: var(--glow-primary);
}
body::after {
  top: 400px;
  right: -200px;
  background: var(--glow-secondary);
}

.container {
  max-width: 1120px;
  margin: 0 auto;
  padding: 0 24px;
}

/* ===== APP SHELL (shared across authenticated dashboard views) =====
   Identical across app.ejs, team.ejs, history.ejs, errors/404.ejs,
   checklist-new.ejs, checklist-edit.ejs, auth/login.ejs, auth/signup.ejs
   before this migration — moved here as Step 1 of the shared-CSS
   migration (UX audit item #7) so a fix here no longer needs to be
   copy-pasted into every view. */
.app-layout { min-height: 100vh; }
.header-logo { font-family: var(--font-mono); font-size: 1rem; font-weight: 500; color: var(--brand); letter-spacing: 0.08em; text-transform: uppercase; text-decoration: none; display: inline-flex; align-items: center; }
/* Banner logo bakes in its own dark backdrop — round it so it reads as a badge */
.header-logo-img { display: block; height: 40px; width: auto; border-radius: 8px; }
.header-left { display: flex; align-items: center; gap: 24px; }
.header-nav a:hover { color: var(--fg); }

/* ===== UTILITIES ===== */
.gradient-text {
  background: var(--accent-gradient);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  display: inline-block;
}
/* Branding/hero/optional-dashboard-heading font — never body text. Falls
   back to --font-heading until a Beyonders font file is bundled. */
.font-brand { font-family: var(--font-beyonders); }
.glass-panel {
  background: var(--bg-raised);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
  border: 1px solid var(--border);
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
}

/* ===== NAV ===== */
.nav {
  position: sticky;
  top: 0;
  z-index: 100;
  padding: 20px 0;
  border-bottom: 1px solid var(--border);
  background: var(--nav-bg);
  -webkit-backdrop-filter: blur(20px);
  backdrop-filter: blur(20px);
}
.nav .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.nav-logo {
  font-family: var(--font-heading);
  font-size: 1.5rem;
  font-weight: 800;
  color: var(--text);
  letter-spacing: -0.02em;
  display: inline-flex;
  align-items: center;
}
.nav-logo span {
  color: var(--gold);
}
.nav-logo img {
  display: block;
}

.btn-primary {
  background: var(--accent-gradient);
  color: #fff;
  font-family: var(--font-heading);
  font-size: 0.95rem;
  font-weight: 600;
  padding: 10px 22px;
  border-radius: 100px;
  text-decoration: none;
  transition: all 0.3s ease;
  box-shadow: 0 4px 15px rgba(var(--brand-rgb), 0.3);
  position: relative;
  overflow: hidden;
  z-index: 1;
}
.btn-primary::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  background: linear-gradient(135deg, var(--brand-dark), var(--brand), var(--brand-light));
  z-index: -1;
  transition: opacity 0.3s ease;
  opacity: 0;
}
.btn-primary:hover::before {
  opacity: 1;
}
.btn-primary:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 20px rgba(var(--brand-rgb), 0.4);
}

.btn-secondary {
  font-family: var(--font-body);
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--fg-muted);
  text-decoration: none;
  transition: color 0.2s;
}
.btn-secondary:hover {
  color: var(--text);
}

/* ===== HERO ===== */
.hero {
  padding: 120px 0 100px;
}
.hero-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 80px;
  align-items: center;
}
.hero-label {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  color: var(--brand);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-bottom: 24px;
  padding: 6px 14px;
  border-radius: 100px;
  background: rgba(var(--brand-rgb), 0.1);
  border: 1px solid rgba(var(--brand-rgb), 0.2);
}
.hero h1 {
  font-family: var(--font-heading);
  font-size: 4rem;
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -0.04em;
  margin-bottom: 24px;
}
.hero-desc {
  font-size: 1.25rem;
  color: var(--fg-muted);
  line-height: 1.6;
  max-width: 480px;
  margin-bottom: 40px;
}
.hero-actions {
  display: flex;
  align-items: center;
  gap: 24px;
}

/* Floating animation for the visual */
@keyframes float {
  0% { transform: translateY(0px); }
  50% { transform: translateY(-15px); }
  100% { transform: translateY(0px); }
}

.hero-visual {
  border-radius: 20px;
  padding: 32px;
  font-family: var(--font-body);
  font-size: 0.95rem;
  animation: float 6s ease-in-out infinite;
  border: 1px solid var(--border-highlight);
  position: relative;
  background: linear-gradient(180deg, rgba(30, 30, 35, 0.8) 0%, rgba(20, 20, 24, 0.8) 100%);
  -webkit-backdrop-filter: blur(20px);
  backdrop-filter: blur(20px);
  box-shadow: 0 20px 40px rgba(0,0,0,0.4), inset 0 1px 0 rgba(255,255,255,0.1);
}
.hero-visual::after {
  content: '';
  position: absolute;
  top: -1px; left: -1px; right: -1px; bottom: -1px;
  border-radius: 20px;
  background: var(--accent-gradient);
  z-index: -1;
  opacity: 0.3;
  filter: blur(10px);
}

.checklist-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 24px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--border);
}
.checklist-title {
  color: var(--text);
  font-weight: 600;
  font-size: 1.1rem;
}
.checklist-badge {
  color: var(--brand);
  font-size: 0.75rem;
  font-weight: 600;
  background: rgba(var(--accent-rgb), 0.15);
  padding: 4px 12px;
  border-radius: 100px;
}
.checklist-item {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 12px 0;
  color: var(--fg-muted);
  transition: transform 0.2s, background 0.2s;
  border-radius: 8px;
}
.checklist-item:hover {
  background: rgba(255, 255, 255, 0.03);
  transform: translateX(4px);
  padding-left: 8px;
}
.checklist-item.done {
  color: var(--text);
}
.check-box {
  width: 22px;
  height: 22px;
  border: 2px solid var(--border-highlight);
  border-radius: 6px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.2s;
}
.checklist-item.done .check-box {
  background: var(--brand);
  border-color: var(--brand);
  box-shadow: 0 0 10px rgba(var(--brand-rgb), 0.4);
}
.check-mark {
  color: #fff;
  font-size: 0.85rem;
  font-weight: 800;
}
.checklist-time {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: var(--fg-muted);
  background: rgba(255, 255, 255, 0.05);
  padding: 2px 8px;
  border-radius: 4px;
}

/* ===== INTERACTIVE DEMO CHECKLIST ===== */
.checklist-item[data-item] {
  cursor: pointer;
  -webkit-user-select: none;
  user-select: none;
  outline: none;
}
.checklist-item[data-item]:focus-visible {
  background: rgba(255, 255, 255, 0.05);
  box-shadow: 0 0 0 2px rgba(var(--brand-rgb), 0.5);
}
/* checkmark hidden until the item is done, then pops in */
.check-mark {
  transform: scale(0);
  transition: transform 0.18s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.checklist-item.done .check-mark { transform: scale(1); }
.checklist-time { transition: opacity 0.2s; }

.hero-hint {
  margin-top: 18px;
  font-size: 0.85rem;
  color: var(--fg-muted);
  transition: opacity 0.4s;
}
#demoChecklist.all-done .checklist-badge {
  background: rgba(var(--brand-rgb), 0.25);
}

/* ===== HERO VIDEO ===== */
.hero-video {
  margin: 56px auto 0;
  max-width: 900px;
}
.hero-video video {
  width: 100%;
  display: block;
  border-radius: 16px;
  border: 1px solid var(--border-highlight);
  box-shadow: 0 20px 50px rgba(0,0,0,0.45);
  background: #000;
}

/* ===== PROBLEM ===== */
.problem {
  padding: 100px 0;
  position: relative;
}
.section-label {
  font-family: var(--font-mono);
  font-size: 0.85rem;
  color: var(--brand);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-bottom: 24px;
  display: block;
  text-align: center;
}
.problem-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
  margin-top: 40px;
}
.problem-card {
  padding: 40px 32px;
  border-radius: 16px;
  transition: all 0.3s;
  border: 1px solid var(--border);
  position: relative;
  overflow: hidden;
}
.problem-card:hover {
  transform: translateY(-5px);
  border-color: var(--border-highlight);
  box-shadow: 0 10px 30px rgba(0,0,0,0.5);
}
.problem-card::before {
  content: '';
  position: absolute;
  top: 0; left: 0; width: 100%; height: 2px;
  background: var(--accent-gradient);
  opacity: 0;
  transition: opacity 0.3s;
}
.problem-card:hover::before {
  opacity: 1;
}
.problem-num {
  font-family: var(--font-heading);
  font-size: 3rem;
  font-weight: 800;
  color: rgba(255, 255, 255, 0.05);
  position: absolute;
  top: 20px;
  right: 24px;
  line-height: 1;
}
.problem-card h3 {
  font-family: var(--font-heading);
  font-size: 1.3rem;
  font-weight: 600;
  margin-bottom: 12px;
  color: var(--text);
}
.problem-card p {
  font-size: 1rem;
  color: var(--fg-muted);
}

/* ===== HOW ===== */
.how {
  padding: 120px 0;
  text-align: center;
}
.how h2 {
  font-family: var(--font-heading);
  font-size: 3.5rem;
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -0.03em;
  margin-bottom: 60px;
}
.how-steps {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 40px;
  text-align: left;
}
.step {
  padding: 40px 32px;
  border-radius: 20px;
  background: rgba(255,255,255,0.02);
  border: 1px solid var(--border);
  position: relative;
}
.step-num {
  width: 48px;
  height: 48px;
  border-radius: 12px;
  background: rgba(var(--brand-rgb), 0.1);
  color: var(--brand);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-heading);
  font-size: 1.2rem;
  font-weight: 700;
  margin-bottom: 24px;
  border: 1px solid rgba(var(--brand-rgb), 0.2);
}
.step h3 {
  font-family: var(--font-heading);
  font-size: 1.25rem;
  font-weight: 600;
  margin-bottom: 12px;
}
.step p {
  font-size: 1rem;
  color: var(--fg-muted);
}

/* ===== AUDIENCE ===== */
.audience {
  padding: 100px 0;
}
.audience-list {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
  margin-top: 40px;
}
.audience-item {
  padding: 32px;
  border-radius: 16px;
  display: flex;
  align-items: flex-start;
  gap: 24px;
  transition: transform 0.2s, background 0.2s;
}
.audience-item:hover {
  background: rgba(255, 255, 255, 0.03);
  transform: translateX(4px);
}
.audience-icon {
  width: 56px;
  height: 56px;
  border-radius: 16px;
  background: linear-gradient(135deg, rgba(var(--brand-rgb), 0.25), rgba(var(--brand-rgb), 0.1));
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.8rem;
  flex-shrink: 0;
  border: 1px solid rgba(255, 255, 255, 0.1);
}
.audience-item h4 {
  font-family: var(--font-heading);
  font-size: 1.2rem;
  font-weight: 600;
  margin-bottom: 8px;
}
.audience-item p {
  font-size: 0.95rem;
  color: var(--fg-muted);
}

/* ===== PRICING ===== */
.pricing {
  padding: 100px 0;
  text-align: center;
}
.pricing h2 {
  font-family: var(--font-heading);
  font-size: 3.5rem;
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -0.03em;
  margin-bottom: 48px;
}
.pricing-card {
  max-width: 440px;
  margin: 0 auto;
  padding: 48px;
  border-radius: 20px;
  text-align: center;
}
.pricing-price {
  font-family: var(--font-heading);
  font-size: 3rem;
  font-weight: 800;
}
.pricing-price span {
  font-size: 1rem;
  color: var(--fg-muted);
  font-weight: 400;
}
.pricing-sub {
  color: var(--fg-muted);
  font-size: 0.95rem;
  margin: 8px 0 28px;
}
.pricing-features {
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-bottom: 32px;
}
.pricing-feature {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 0.95rem;
}
.pricing-feature span {
  color: var(--brand);
}
.pricing-cta {
  display: block;
  width: 100%;
  text-align: center;
}

/* ===== CLOSING ===== */
.closing {
  padding: 120px 0;
  text-align: center;
  position: relative;
}
.closing::before {
  content: '';
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 800px; height: 400px;
  background: var(--accent-gradient);
  filter: blur(150px);
  opacity: 0.1;
  z-index: -1;
  border-radius: 50%;
}
.closing h2 {
  font-family: var(--font-heading);
  font-size: 3.5rem;
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -0.03em;
  margin-bottom: 24px;
}
.closing p {
  font-size: 1.2rem;
  color: var(--fg-muted);
  max-width: 540px;
  margin: 0 auto 40px;
}

/* ===== FOOTER ===== */
.footer {
  padding: 40px 0;
  border-top: 1px solid var(--border);
  background: rgba(0,0,0,0.2);
}
.footer .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.footer-brand {
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 1.2rem;
  color: var(--fg-muted);
}
.footer-built {
  font-size: 0.85rem;
  color: var(--fg-muted);
  opacity: 0.7;
}

/* ===== RESPONSIVE ===== */
@media (max-width: 900px) {
  .hero-grid { grid-template-columns: 1fr; gap: 60px; }
  .hero h1 { font-size: 3rem; }
  .how-steps { grid-template-columns: 1fr; }
  .problem-grid { grid-template-columns: 1fr; }
  .audience-list { grid-template-columns: 1fr; }
  .closing h2 { font-size: 2.8rem; }
}

/* =====================================================================
   APP MOTION LANGUAGE — one shared "grammar" for every authenticated
   view (dashboard, checklist builder, team, history, stats…), so an
   action always produces the same kind of motion no matter which page
   it happens on. Transform/opacity only; every keyframe below runs
   once and stops — nothing here loops. Respects prefers-reduced-motion
   via the block at the bottom.

   Action            → class                  → effect
   Page loads        .app-page-enter           fade + 20px rise
   Cards (hover)      .app-card-motion          250ms lift, no bounce
   Buttons (hover)    .app-btn-motion           scale to 1.02
   Success            .app-pulse-success        green pulse, once
   Errors             .app-shake                gentle horizontal shake
   Notifications      .app-toast                slide in from top-right
   Skeleton/loading   .app-skeleton             shimmer sweep
   Counters/rings     (see JS helpers)          animate once on load
   ===================================================================== */

@keyframes app-fade-rise {
  from { opacity: 0; transform: translateY(20px); }
  to   { opacity: 1; transform: translateY(0); }
}
.app-page-enter {
  animation: app-fade-rise 500ms cubic-bezier(0.22, 1, 0.36, 1) both;
}

/* Cards: a restrained lift, not a jump — "information moves, the
   interface stays still." Apply alongside a card's existing styles. */
.app-card-motion {
  transition: transform 260ms cubic-bezier(0.22, 1, 0.36, 1), box-shadow 260ms cubic-bezier(0.22, 1, 0.36, 1), border-color 260ms ease;
}
.app-card-motion:hover {
  transform: translateY(-2px);
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.28);
}

.app-btn-motion { transition: transform 200ms cubic-bezier(0.22, 1, 0.36, 1), background 150ms ease, box-shadow 200ms ease; }
.app-btn-motion:hover { transform: scale(1.02); }
.app-btn-motion:active { transform: scale(0.98); transition-duration: 100ms; }

@keyframes app-pulse-success {
  0%   { box-shadow: 0 0 0 0 rgba(var(--brand-rgb), 0.5); }
  70%  { box-shadow: 0 0 0 10px rgba(var(--brand-rgb), 0); }
  100% { box-shadow: 0 0 0 0 rgba(var(--brand-rgb), 0); }
}
.app-pulse-success { animation: app-pulse-success 700ms ease-out; }

@keyframes app-shake {
  10%, 90%       { transform: translateX(-1px); }
  20%, 80%       { transform: translateX(2px); }
  30%, 50%, 70%  { transform: translateX(-4px); }
  40%, 60%       { transform: translateX(4px); }
}
.app-shake { animation: app-shake 400ms ease-in-out; }

/* Notifications: slide in from the top-right, not the bottom — this is
   the shared toast entrance used across the app. */
@keyframes app-toast-in {
  from { opacity: 0; transform: translate(16px, -12px); }
  to   { opacity: 1; transform: translate(0, 0); }
}
.app-toast { animation: app-toast-in 220ms cubic-bezier(0.22, 1, 0.36, 1) both; }

/* Skeleton / loading shimmer */
@keyframes app-skeleton-shimmer {
  0%   { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}
.app-skeleton {
  background: linear-gradient(90deg, var(--bg-raised) 25%, var(--border) 50%, var(--bg-raised) 75%);
  background-size: 200% 100%;
  animation: app-skeleton-shimmer 1.6s ease-in-out infinite;
  border-radius: 6px;
}

/* ===== EMPTY STATES ===== */
/* One shared component for "nothing here yet" moments across the app —
   dashboard, history, team, stats. A friendly icon, a plain-language
   heading, one line of guidance, and a clear next action. */
.empty-state-panel {
  text-align: center;
  padding: 64px 32px;
  max-width: 440px;
  margin: 0 auto;
}
.empty-state-panel__icon {
  width: 64px; height: 64px;
  margin: 0 auto 20px;
  border-radius: 16px;
  background: color-mix(in srgb, var(--brand) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--brand) 25%, transparent);
  color: var(--brand);
  display: flex; align-items: center; justify-content: center;
}
.empty-state-panel h3 {
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--text);
  margin-bottom: 8px;
}
.empty-state-panel p {
  font-size: 0.9rem;
  color: var(--fg-muted);
  line-height: 1.6;
  margin-bottom: 24px;
}
.empty-state-panel__actions {
  display: flex;
  gap: 10px;
  justify-content: center;
  flex-wrap: wrap;
}

@media (prefers-reduced-motion: reduce) {
  .app-page-enter, .app-pulse-success, .app-shake, .app-toast, .app-skeleton {
    animation: none !important;
  }
  .app-page-enter { opacity: 1; transform: none; }
  .app-card-motion:hover { transform: none; }
  .app-btn-motion:hover, .app-btn-motion:active { transform: none; }
}

/* =====================================================================
   TRUST PHASE — session expiration, and the shared error-recovery UI
   that goes with it (public/js/session-guard.js). A friendly modal
   instead of a dead page or a cryptic JSON parse error, plus a small
   connection-lost banner for transient network failures.
   ===================================================================== */

.session-modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2000;
  padding: 24px;
  animation: session-overlay-in 200ms ease-out;
}
@keyframes session-overlay-in { from { opacity: 0; } to { opacity: 1; } }

.session-modal {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 32px;
  max-width: 400px;
  width: 100%;
  text-align: center;
  box-shadow: 0 24px 64px rgba(0, 0, 0, 0.4);
  animation: session-modal-in 250ms cubic-bezier(0.22, 1, 0.36, 1);
}
@keyframes session-modal-in {
  from { opacity: 0; transform: translateY(12px) scale(0.98); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.session-modal__icon {
  width: 52px; height: 52px;
  margin: 0 auto 16px;
  border-radius: 14px;
  background: rgba(var(--danger-rgb), 0.12);
  color: var(--danger);
  display: flex; align-items: center; justify-content: center;
}
.session-modal h2 {
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--text);
  margin-bottom: 8px;
}
.session-modal p {
  font-size: 0.9rem;
  color: var(--fg-muted);
  line-height: 1.6;
  margin-bottom: 24px;
}
.session-modal__actions { display: flex; flex-direction: column; gap: 10px; }

/* Transient network-failure banner (auto-retry in progress) */
.network-banner {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 1900;
  background: rgba(var(--danger-rgb), 0.95);
  color: #fff;
  font-family: var(--font-body);
  font-size: 0.85rem;
  font-weight: 500;
  text-align: center;
  padding: 8px 16px;
  animation: network-banner-in 200ms ease-out;
}
@keyframes network-banner-in {
  from { opacity: 0; transform: translateY(-100%); }
  to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .session-modal-overlay, .session-modal, .network-banner { animation: none !important; }
}

/* =====================================================================
   AUTOSAVE INDICATOR — one shared component (public/js/autosave.js),
   fixed in place near the page title. Only its *content* changes
   between states; it never moves, resizes unpredictably, or stacks
   with a second indicator.
   ===================================================================== */

.autosave-indicator {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  color: var(--fg-muted);
  min-height: 1.5em;
  transition: color 400ms ease; /* the "Saved just now" → "Saved" color settles gently, not a snap */
}
.autosave-indicator[data-state="saved-just-now"] { color: var(--success); }
.autosave-indicator[data-state="error"] { color: var(--danger); }
.autosave-indicator[data-state="offline"] { color: var(--fg-muted); }

.autosave-dot { font-size: 0.9em; line-height: 1; }
.autosave-dot--success { color: var(--success); }
.autosave-dot--error { color: var(--danger); }

/* Small spinner for "Saving…" — a single ring, no bounce, stops the
   instant the state changes (it's swapped out of the DOM, not looped
   indefinitely in the background). */
.autosave-spinner {
  width: 11px; height: 11px;
  border-radius: 50%;
  border: 1.5px solid var(--border);
  border-top-color: var(--fg-muted);
  flex-shrink: 0;
  animation: autosave-spin 700ms linear infinite;
}
@keyframes autosave-spin { to { transform: rotate(360deg); } }

/* The "✓ Saved just now" fade to plain "Saved" is a content swap, not a
   layout shift — .autosave-indicator's min-height keeps the baseline
   steady so nothing above/below it reflows. */
.autosave-indicator .autosave-retry-btn {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--danger);
  background: rgba(var(--danger-rgb), 0.1);
  border: 1px solid rgba(var(--danger-rgb), 0.3);
  border-radius: 6px;
  padding: 2px 8px;
  cursor: pointer;
  transition: background 0.15s;
}
.autosave-indicator .autosave-retry-btn:hover { background: rgba(var(--danger-rgb), 0.18); }

@media (prefers-reduced-motion: reduce) {
  .autosave-spinner { animation: none; border-top-color: var(--border); }
  .autosave-indicator { transition: none; }
}

/* =====================================================================
   SHARED TOAST — for pages that don't already define their own (app.ejs
   and team.ejs have local copies of this same design; this is what
   session-guard.js's showToast() uses on every other authenticated page,
   so a failure never has to fall back to a native alert()).
   ===================================================================== */
.toast-stack {
  position: fixed;
  top: 24px;
  right: 24px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  z-index: 1000;
  max-width: 320px;
}
.toast {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-left: 3px solid var(--danger);
  border-radius: 8px;
  padding: 12px 16px;
  font-family: var(--font-body);
  font-size: 0.85rem;
  color: var(--text);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
}
.toast.success { border-left-color: var(--success); }