/* ==========================================================================
   DBBackup — main stylesheet (mobile-first)
   Breakpoints: base <640px, tablet ≥640px, desktop ≥1024px
   ========================================================================== */

/* ---------- Reset & base ---------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--bg-primary);
  color: #ffffff;
  font-family: var(--font-sans);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

img,
svg {
  display: block;
  max-width: 100%;
}

/* Author display values (grid/flex) would otherwise beat the UA's
   [hidden] { display: none } — keep the attribute reliable. */
[hidden] {
  display: none !important;
}

a {
  color: inherit;
}

h1,
h2,
h3 {
  line-height: 1.15;
  margin: 0 0 0.5em;
  letter-spacing: -0.02em;
}

p {
  margin: 0 0 1em;
}

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

.container {
  width: 100%;
  max-width: var(--container-max);
  margin: 0 auto;
  padding: 0 1.25rem;
}

section {
  padding: 4rem 0;
}

.section-title {
  font-size: clamp(1.6rem, 4vw, 2.2rem);
  text-align: center;
}

.section-lede {
  color: var(--text-muted);
  text-align: center;
  max-width: 34rem;
  margin: 0 auto 3rem;
}

/* "Works with" compatibility strip (index.html, between the hero and
   "Why DBBackup?") -- deliberately compact/quiet: overrides the default
   `section { padding: 4rem 0; }` down to a thin divider-bordered band,
   text-only (no logos), same muted styling as the rest of the site's
   secondary/caption text (.hero-cta-note, .status-card .label) rather
   than a new visual treatment. */
.compat-strip {
  padding: 1.75rem 0;
  text-align: center;
  border-top: 1px solid var(--border-card);
  border-bottom: 1px solid var(--border-card);
}

.compat-strip-label {
  color: var(--text-muted);
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: 0.6rem;
}

.compat-strip-list {
  color: var(--text-muted);
  font-size: 0.85rem;
  max-width: 46rem;
  margin: 0 auto;
  line-height: 1.7;
}

/* ---------- Buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.8rem 1.6rem;
  border-radius: var(--radius-sm);
  border: none;
  font: 600 1rem var(--font-sans);
  text-decoration: none;
  cursor: pointer;
  transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}

/* scale(), not translateY(): a vertical shift moves the button's hit-test
   box under a cursor sitting near its top/bottom edge, which un-hovers it,
   which reverts the shift, which re-hovers it -- an infinite flicker loop.
   A center-origin scale-up only ever grows the box away from a cursor
   that's already inside it, so it can't re-trigger that loop. */
.btn:hover {
  transform: scale(1.02);
}

/* Filled green — used for the final CTA */
.btn-solid,
.btn-primary {
  background: var(--accent-primary);
  color: var(--bg-primary);
}

.btn-solid:hover,
.btn-primary:hover {
  box-shadow: 0 4px 24px color-mix(in srgb, var(--accent-primary) 35%, transparent);
}

/* Thin green outline — navbar "Sign up" */
.btn-outline {
  background: transparent;
  color: var(--accent-primary);
  border: 1px solid var(--accent-primary);
  padding: 0.5rem 1.1rem;
  font-size: 0.9rem;
}

.btn-outline:hover {
  background: color-mix(in srgb, var(--accent-primary) 10%, transparent);
}

.btn-outline:disabled {
  opacity: 0.4;
  cursor: not-allowed;
  transform: none;
}

.btn-outline:disabled:hover {
  background: transparent;
}

/* Dark button that carries the Border Beam — hero CTA */
.btn-beam {
  background: var(--bg-card);
  color: #ffffff;
  border: 1px solid var(--border-card);
  padding: 0.9rem 2rem;
  font-size: 1.05rem;
  border-radius: var(--radius-sm);
}

.btn-beam:hover {
  background: color-mix(in srgb, var(--bg-card) 85%, var(--accent-primary));
}

/* ---------- Navbar ---------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.9rem 1.25rem;
  border-bottom: 1px solid var(--border-card);
  background: color-mix(in srgb, var(--bg-primary) 82%, transparent);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}

.logo {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-weight: 700;
  font-size: 1.05rem;
  color: #ffffff;
  text-decoration: none;
}

.logo svg {
  width: 22px;
  height: 22px;
}

.nav-links {
  display: none; /* hidden on mobile; no hamburger yet */
  gap: 1.75rem;
}

.nav-links a,
.site-header nav a {
  color: var(--text-muted);
  text-decoration: none;
  font-size: 0.95rem;
  transition: color 0.15s ease;
}

.nav-links a:hover,
.site-header nav a:hover {
  color: #ffffff;
}

/* ---------- Floating pill nav (index.html ONLY) ----------
   Replaces the page's previous .site-header-based topbar entirely.
   .site-header/.logo above remain untouched -- still shared with
   dashboard.html/settings.html/login.html/signup.html. */

.top-nav {
  position: sticky;
  top: 1rem;
  z-index: 1000;
  isolation: isolate;
  width: min(760px, 92%);
  height: 92px;
  margin: 1rem auto 0;
  display: flex;
  justify-content: space-around;
  align-items: center;
  background: color-mix(in srgb, var(--bg-card) 75%, transparent);
  border: 1px solid color-mix(in srgb, white 10%, transparent);
  border-radius: 40px;
  backdrop-filter: blur(25px);
  -webkit-backdrop-filter: blur(25px);
  box-shadow:
    0 20px 50px color-mix(in srgb, black 35%, transparent),
    inset 0 1px 0 color-mix(in srgb, white 8%, transparent);
}

/* Soft ambient glow behind the pill, green instead of the reference's blue. */
.top-nav::before {
  content: "";
  position: absolute;
  width: 220px;
  height: 220px;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  background: color-mix(in srgb, var(--accent-primary) 25%, transparent);
  filter: blur(70px);
  z-index: -1;
  pointer-events: none;
}

/* Subscription renewal badge (index.html, wired up by marketing-nav.js) --
   same glassmorphism treatment as .card-glass (gradient glass panel,
   soft translucent border, backdrop blur) but a compact pill rather than
   a full card, sized for one line of text. Fixed to the viewport's
   top-right corner rather than living inside .top-nav's own pill: that
   pill is already at its designed 8-item capacity (see its own comment
   above), and this badge is scoped to sit NEXT TO it, not inside it. */
.renewal-badge {
  position: fixed;
  top: 1rem;
  right: 1.5rem;
  z-index: 999;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.55rem 1.1rem;
  border-radius: 999px;
  background: linear-gradient(135deg, var(--bg-card) 0%, var(--bg-primary) 100%);
  border: 1px solid color-mix(in srgb, white 10%, transparent);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  box-shadow:
    0 8px 24px color-mix(in srgb, black 30%, transparent),
    inset 0 1px 0 color-mix(in srgb, white 8%, transparent);
  font-size: 0.82rem;
  color: var(--text-muted);
  white-space: nowrap;
}

.renewal-badge-plan {
  color: var(--accent-primary);
  font-weight: 700;
}

.renewal-badge-sep {
  opacity: 0.5;
}

/* Narrower than this, .top-nav's own pill already claims 92% of the
   viewport width (see its own comment) -- no room left for a second,
   separate badge beside it without overlapping. */
@media (max-width: 900px) {
  .renewal-badge {
    display: none;
  }
}

.nav-item {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  color: var(--text-muted);
  text-decoration: none;
  font-size: 0.85rem;
  font-weight: 600;
  font-family: inherit;
  line-height: inherit; /* buttons default to line-height:normal (UA
    stylesheet) instead of inheriting like <a> does -- without this,
    #nav-settings-btn (a <button>) renders a hair shorter than its
    sibling <a> nav-items even with identical font-size/padding. */
  background: none;
  border: none;
  cursor: pointer;
  transition: color 0.35s ease;
}

.nav-item svg {
  width: 24px;
  height: 24px;
  stroke: currentColor;
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* The hover LIFT is applied to the children (icon + label), never to
   .nav-item itself -- .nav-item is what actually receives :hover, so if
   IT were the thing that moved, translateY would shift its own hit-box
   out from under a stationary cursor sitting right at the boundary,
   dropping :hover, snapping back, re-entering :hover, and repeating
   (visible jitter/flicker right at the edge). Transforming only the
   (visually) moving children instead leaves .nav-item's own hoverable
   geometry completely stationary -- transform never affects a parent's
   layout box, so the hover boundary itself never moves. */
.nav-item > * {
  transition: transform 0.35s ease;
}

.nav-item:hover {
  color: var(--accent-primary);
}

.nav-item:hover > * {
  transform: translateY(-3px);
}

/* More specific than ".nav-item:hover > *" (adds a type selector), so
   this wins for the icon specifically -- combines the shared lift with
   the icon's own extra scale in one transform, since a second transform
   declaration on the same element replaces rather than composes with
   the first. */
.nav-item:hover svg {
  transform: translateY(-3px) scale(1.12);
}

/* Set by js/marketing-nav.js on click -- Home/Features/Pricing/Help only
   (excludes #nav-settings-btn and the .nav-login/.nav-signup pills, see
   there). Settings is a plain .nav-item visually, same as its siblings --
   no special circular/elevated treatment. */
.nav-item.active {
  color: var(--accent-primary);
}

/* "Log in" / "Sign up" -- pill buttons, deliberately NOT styled like the
   plain stacked icon+label nav-items: row layout, padded background. */
.nav-login,
.nav-signup {
  flex-direction: row;
  gap: 0.4rem;
  padding: 0.6rem 1rem;
  border-radius: 999px;
  font-size: 0.8rem;
}

.nav-login svg,
.nav-signup svg {
  width: 16px;
  height: 16px;
}

.nav-login {
  background: color-mix(in srgb, white 6%, transparent);
  border: 1px solid color-mix(in srgb, white 12%, transparent);
  color: #ffffff;
}

.nav-login:hover {
  background: color-mix(in srgb, white 10%, transparent);
  color: #ffffff;
}

.nav-signup {
  background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
  color: var(--bg-primary);
  font-weight: 700;
}

.nav-signup:hover {
  color: var(--bg-primary);
  box-shadow: 0 10px 24px color-mix(in srgb, var(--accent-primary) 35%, transparent);
}

/* Logged-in user menu (js/marketing-nav.js populates it; js/navbar.js --
   already loaded on every page -- wires up the actual open/close/
   click-outside/Escape/arrow-key dropdown behavior via the shared
   .user-menu-wrap/.user-menu/.user-dropdown/[role="menuitem"] classes,
   reused verbatim from dashboard.html/settings.html rather than
   reimplemented. This block only restyles that shared dropdown to match
   the pill-nav's glassmorphism material instead of the dashboard's flat
   card look -- scoped under .nav-user-menu-wrap so dashboard/settings'
   own dropdown is untouched. */
.nav-user-menu-wrap {
  position: relative;
}

.nav-user-menu-wrap .user-menu {
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  gap: 0.4rem;
  padding: 0.6rem 1rem;
  border-radius: 999px;
  background: color-mix(in srgb, white 6%, transparent);
  border: 1px solid color-mix(in srgb, white 12%, transparent);
  color: #ffffff;
  font-size: 0.8rem;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  max-width: 180px;
  transition: background 0.25s ease;
}

.nav-user-menu-wrap .user-menu:hover,
.nav-user-menu-wrap .user-menu[aria-expanded="true"] {
  background: color-mix(in srgb, white 10%, transparent);
  color: #ffffff;
}

.nav-user-menu-wrap #nav-user-email {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nav-user-menu-wrap .chevron {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  transition: transform 0.2s ease;
}

.nav-user-menu-wrap .user-menu[aria-expanded="true"] .chevron {
  transform: rotate(180deg);
}

.nav-user-menu-wrap .user-dropdown {
  position: absolute;
  left: 0;
  top: calc(100% + 12px);
  z-index: 1000;
  min-width: 200px;
  padding: 0.5rem;
  /* Fully opaque -- was color-mix(... 75%, transparent), which let the
     hero heading behind it visibly bleed through when open. .card-glass
     itself (this project's own glassmorphism convention) is ALSO fully
     opaque -- its "glass" look comes from the border/shadow, not a
     translucent background -- so this now matches that exact gradient
     rather than introducing a one-off solid color. backdrop-filter is
     kept for visual consistency with the rest of this pill-nav's
     glassmorphism family (blurring its own edge), though with a fully
     opaque background behind it there's nothing left showing through
     for it to actually blur. */
  background: linear-gradient(135deg, var(--bg-card) 0%, var(--bg-primary) 100%);
  border: 1px solid color-mix(in srgb, white 10%, transparent);
  border-radius: 24px;
  backdrop-filter: blur(25px);
  -webkit-backdrop-filter: blur(25px);
  box-shadow:
    0 20px 50px color-mix(in srgb, black 35%, transparent),
    inset 0 1px 0 color-mix(in srgb, white 8%, transparent);
}

.nav-user-menu-wrap .user-dropdown [role="menuitem"] {
  display: block;
  width: 100%;
  padding: 0.6rem 0.9rem;
  border-radius: var(--radius-md);
  color: var(--text-muted);
  font: 500 0.9rem var(--font-sans);
  text-decoration: none;
  text-align: left;
  background: none;
  border: none;
  cursor: pointer;
}

.nav-user-menu-wrap .user-dropdown [role="menuitem"]:hover:not(:disabled) {
  color: #ffffff;
  background: color-mix(in srgb, white 8%, transparent);
}

.nav-user-menu-wrap .user-dropdown [role="menuitem"]:focus-visible {
  outline: 2px solid var(--accent-secondary);
  outline-offset: -2px;
}

/* #nav-manage-billing-btn only -- disabled for Free-plan users (no
   billing account to manage yet), same convention as settings.html's
   #nav-manage-billing/.tab-btn:disabled. */
.nav-user-menu-wrap .user-dropdown [role="menuitem"]:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.nav-user-menu-wrap .menu-divider {
  height: 1px;
  margin: 0.4rem 0.3rem;
  background: color-mix(in srgb, white 10%, transparent);
  border: none;
}

/* "Other Products" dropdown -- the trigger itself is a plain .nav-item
   (reused verbatim, not restyled), so it's visually identical to its
   Home/Features/Pricing/Help siblings; only the panel below it (opened
   on click) is new, and its glass-card treatment deliberately matches
   .user-dropdown above rather than inventing a second dropdown-panel
   style. */
.nav-products-wrap {
  position: relative;
}

.nav-products-menu {
  position: absolute;
  /* Right-aligned to the TRIGGER's own right edge (extends leftward),
     not centered -- this trigger sits near the right side of the pill
     (just before Sign up), so a centered panel could extend past the
     viewport's right edge on narrow screens even while staying under
     its own max-width (confirmed empirically: a 390px viewport pushed
     a centered panel ~18px past the edge). Mirrors .user-dropdown's own
     "extend away from the near edge" positioning (that one sits at the
     pill's LEFT end and extends rightward via left: 0; this one is at
     the right end, so it extends leftward via right: 0 instead). */
  right: 0;
  top: calc(100% + 12px);
  z-index: 1000;
  width: max-content;
  min-width: 220px;
  max-width: min(280px, calc(100vw - 2rem));
  padding: 0.5rem;
  background: linear-gradient(135deg, var(--bg-card) 0%, var(--bg-primary) 100%);
  border: 1px solid color-mix(in srgb, white 10%, transparent);
  border-radius: 24px;
  backdrop-filter: blur(25px);
  -webkit-backdrop-filter: blur(25px);
  box-shadow:
    0 20px 50px color-mix(in srgb, black 35%, transparent),
    inset 0 1px 0 color-mix(in srgb, white 8%, transparent);
}

.nav-products-item {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  width: 100%;
  padding: 0.6rem 0.9rem;
  border-radius: var(--radius-md);
  color: var(--text-muted);
  text-decoration: none;
  text-align: left;
  background: none;
  border: none;
  cursor: pointer;
}

.nav-products-item-name {
  color: #ffffff;
  font: 600 0.9rem var(--font-sans);
}

.nav-products-item-desc {
  color: inherit;
  font-size: 0.78rem;
}

.nav-products-item:hover {
  background: color-mix(in srgb, white 8%, transparent);
}

.nav-products-item:focus-visible {
  outline: 2px solid var(--accent-secondary);
  outline-offset: -2px;
}

.nav-user-avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--accent-primary);
  color: var(--bg-primary);
  font-size: 0.7rem;
  font-weight: 700;
  flex-shrink: 0;
}

/* Auth-state loading placeholder (js/marketing-nav.js) -- occupies the
   Log-in/Sign-up slots until the page-load auth check resolves, so
   neither ever flashes before the correct one is known. */
.nav-skeleton-item {
  cursor: default;
}

.nav-skeleton-item:hover {
  color: var(--text-muted);
}

.nav-skeleton-item:hover > * {
  transform: none;
}

.nav-skeleton-pill {
  display: inline-block;
  width: 72px;
  height: 32px;
  border-radius: 999px;
}

/* 8 items in a 92%-wide pill is tight -- icon-only below 480px so labels
   never wrap or force overflow. */
@media (max-width: 480px) {
  .top-nav {
    height: 76px;
    top: 0.6rem;
    margin-top: 0.6rem;
  }

  .nav-item {
    gap: 0;
  }

  .nav-item span {
    display: none;
  }

  .nav-item svg {
    width: 20px;
    height: 20px;
  }

  .nav-login,
  .nav-signup {
    padding: 0.5rem;
    border-radius: 50%;
  }

  /* .user-menu isn't a .nav-item, so ".nav-item span { display: none; }"
     above never touched it anyway -- collapse it to just the avatar
     circle explicitly, matching Log in/Sign up's own icon-only collapse
     at this width. */
  .nav-user-menu-wrap .user-menu {
    padding: 0.5rem;
    gap: 0;
  }

  .nav-user-menu-wrap #nav-user-email,
  .nav-user-menu-wrap .chevron {
    display: none;
  }

  .nav-skeleton-pill {
    width: 32px;
    height: 32px;
    border-radius: 50%;
  }
}

/* ---------- Hero ---------- */

.hero {
  padding: 3.5rem 0 4rem;
  background:
    radial-gradient(ellipse 70% 50% at 50% -10%,
      color-mix(in srgb, var(--accent-secondary) 9%, transparent),
      transparent);
}

.hero-inner {
  display: grid;
  grid-template-columns: 1fr;
  gap: 3rem;
  align-items: center;
}

.hero h1 {
  font-size: clamp(2rem, 6vw, 3.2rem);
  margin-bottom: 0.6rem;
}

.hero h1 .accent {
  color: var(--accent-primary);
}

.hero-sub {
  color: var(--text-muted);
  font-size: 1.1rem;
  max-width: 32rem;
  margin-bottom: 2rem;
}

.hero-cta-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
  margin-bottom: 3rem;
}

.hero-cta-note {
  color: var(--text-muted);
  font-size: 0.85rem;
}

/* Pipeline illustration: database → flowing light → locked cloud.
   Sits on its own, centered, directly above the "Works with" strip --
   NOT inside .hero (deliberately not using that section's own much
   larger `section { padding: 4rem 0; }`-derived spacing), so the gap
   above the strip stays small and consistent regardless of viewport
   width or how tall the hero column next to it happens to be. */
.pipeline-row {
  display: flex;
  justify-content: center;
  padding: 0 1.25rem;
  margin-bottom: 1.5rem; /* ~1cm gap above the compat strip below */
}

.pipeline {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  /* Explicit width: 100% is REQUIRED, not decorative: .pipeline is now
     a flex item of .pipeline-row (justify-content: center), so without
     an explicit width it sizes to fit its own content (fit-content)
     instead of stretching -- which collapsed .pipeline-line's own
     `flex: 1` (see animations.css) down to 0 width, since there was no
     leftover space left inside .pipeline for it to grow into. That
     silently broke the traveling-light animation on the line: the
     animation itself was never removed, its container just had
     nothing to travel across. max-width still caps it at the graphic's
     original intended size once .pipeline-row is wider than that. */
  width: 100%;
  max-width: 30rem;
  margin: 0 auto;
}

.pipeline-node {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 72px;
  height: 72px;
  border-radius: var(--radius-md);
  background: var(--bg-card);
  border: 1px solid var(--border-card);
}

.pipeline-node svg {
  width: 38px;
  height: 38px;
  stroke: var(--accent-primary);
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.pipeline-cloud svg {
  stroke: var(--accent-secondary);
}

.pipeline-line {
  flex: 1;
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(
    90deg,
    color-mix(in srgb, var(--accent-primary) 18%, transparent),
    color-mix(in srgb, var(--accent-secondary) 18%, transparent)
  );
}

/* .hero-inner's right column: the radial nav (js/radial-nav.js) stacked
   above the status cards, both centered -- see .hero-inner's own
   @media (min-width: 1024px) rule for why this is ONE wrapper (so the
   grid still only places two items side by side, not three). */
.hero-side {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2rem;
}

/* Status cards */

.hero-status {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.9rem;
  width: 100%;
}

.status-card {
  border-radius: var(--radius-md);
  padding: 1rem 1.1rem;
}

.status-card .label {
  display: block;
  color: var(--text-muted);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: 0.35rem;
}

.status-card .value {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 1.15rem;
  font-weight: 600;
}

.status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent-primary);
  flex-shrink: 0;
}

/* Hero stats' "Backup status" dot (js/marketing-nav.js) when the most
   recent backup attempt failed -- .conn-card's badge-failed uses the
   same --danger token for the same state elsewhere on the site. */
.status-dot.failed {
  background: var(--danger);
}

/* Hero stats' "Backup status" failure detail (js/marketing-nav.js) --
   info icon + popover showing the real error_message for that attempt.
   dashboard.js's own connection-card badge just uses a native `title`
   attribute for the same data, but that only reveals on hover, so it
   can't satisfy this card's "tap to reveal on mobile" requirement --
   this is a small, self-contained replacement for that one need. */
.status-info-wrap {
  position: relative;
  display: inline-flex;
  margin-left: 0.35rem;
}

.status-info-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  padding: 0;
  background: none;
  border: none;
  color: var(--text-muted);
  cursor: pointer;
}

.status-info-btn svg {
  width: 100%;
  height: 100%;
}

.status-info-btn:hover,
.status-info-btn:focus-visible {
  color: #ffffff;
}

.status-info-popover {
  display: none;
  position: absolute;
  /* Opens UPWARD, not down: .status-card uses isolation:isolate (see its
     comment -- confines its glow layer's negative z-index to itself),
     which also means this z-index can't escape THIS card's own stacking
     context to paint over a sibling grid card below it. There's nothing
     below to isolate-clip it if it opens upward into the hero copy
     instead. */
  bottom: calc(100% + 10px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 20;
  width: max-content;
  max-width: 220px;
  padding: 0.55rem 0.75rem;
  background: color-mix(in srgb, var(--bg-card) 92%, transparent);
  border: 1px solid color-mix(in srgb, white 12%, transparent);
  border-radius: var(--radius-sm);
  color: #ffffff;
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 1.4;
  text-align: left;
  white-space: normal;
  box-shadow: 0 10px 24px color-mix(in srgb, black 40%, transparent);
}

/* Desktop hover + keyboard focus reveal the popover with no JS needed;
   js/marketing-nav.js's click-toggle (.is-open) covers mobile tap,
   where :hover doesn't reliably apply. */
.status-info-wrap:hover .status-info-popover,
.status-info-wrap:focus-within .status-info-popover,
.status-info-popover.is-open {
  display: block;
}

/* ---------- Features ("Why DBBackup") ---------- */

.features-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
}

.feature-card {
  border-radius: var(--radius-md);
  padding: 1.5rem;
}

.feature-icon {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  margin-bottom: 1rem;
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--accent-primary) 8%, transparent);
}

.feature-icon svg {
  width: 24px;
  height: 24px;
  stroke: var(--accent-primary);
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.feature-card h3 {
  font-size: 1.05rem;
  margin-bottom: 0.4rem;
}

.feature-card p {
  color: var(--text-muted);
  font-size: 0.95rem;
  margin: 0;
}

/* ---------- Shared: dark-glassmorphism card material ----------
   Originally built for the public pricing cards; extracted here so any
   card-like container across the app can opt in via .card-glass. Owns
   ONLY the MATERIAL (gradient background, subtle border, hover lift +
   glow) -- never layout/sizing (padding, border-radius, display), which
   stays on each consuming component's own existing class, since a
   compact dashboard card and a large pricing card size themselves very
   differently while sharing the same visual material. Every consumer
   still needs its own border-radius (.card-glass-glow below inherits
   it) and padding. */

.card-glass {
  position: relative;
  isolation: isolate; /* keeps .card-glass-glow's negative z-index
                          confined to THIS card, painted above its own
                          background but below its in-flow content. */
  background: linear-gradient(135deg, var(--bg-card) 0%, var(--bg-primary) 100%);
  border: 1px solid color-mix(in srgb, white 10%, transparent);
  transition: transform 0.5s ease, border-color 0.5s ease, box-shadow 0.5s ease;
}

.card-glass:hover {
  transform: translateY(-8px);
  border-color: color-mix(in srgb, var(--accent-primary) 40%, transparent);
  box-shadow: 0 20px 60px -12px color-mix(in srgb, var(--accent-primary) 35%, transparent);
}

/* Decorative-only glow layer (frontend/js never reads/writes this div —
   aria-hidden, same convention as auth.html's .auth-bg/.auth-glow). A
   separate element rather than .card-glass's own ::before/::after so it
   never collides with something like .border-beam's use of those same
   pseudo-elements on a card that ALSO needs that effect (e.g. the
   featured/Pro pricing card). */
.card-glass-glow {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  overflow: hidden; /* clip the blob/radial glow to the card's rounded
                       shape WITHOUT clipping a sibling (e.g. a badge)
                       that deliberately straddles the card's own edge */
  border-radius: inherit;
}

/* Soft static glow blob, top-right corner — always visible. */
.card-glass-glow::before {
  content: "";
  position: absolute;
  top: -60px;
  right: -60px;
  width: 200px;
  height: 200px;
  border-radius: 50%;
  background: var(--accent-primary);
  filter: blur(70px);
  opacity: 0.18;
}

/* Animated radial light, top-right — fades in only on hover. */
.card-glass-glow::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(
    circle at top right,
    color-mix(in srgb, var(--accent-primary) 30%, transparent),
    transparent 60%
  );
  opacity: 0;
  transition: opacity 0.5s ease;
}

.card-glass:hover .card-glass-glow::after {
  opacity: 1;
}

/* ---------- Pricing ---------- */

.pricing-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem;
  align-items: stretch;
}

.price-card {
  display: flex;
  flex-direction: column;
  border-radius: var(--radius-xl);
  padding: 1.75rem;
}

/* Pro/"featured": same shared material as every other card (.card-glass),
   plus a standing green-tinted border and ambient glow even before hover
   (on top of .border-beam's own rotating ring, applied separately in
   animations.css) — a stronger version of the same hover glow, not a
   different effect. */
.price-card.featured {
  border-color: color-mix(in srgb, var(--accent-primary) 35%, transparent);
  box-shadow: 0 0 40px color-mix(in srgb, var(--accent-primary) 12%, transparent);
}

.price-card.featured:hover {
  box-shadow: 0 20px 70px -10px color-mix(in srgb, var(--accent-primary) 50%, transparent);
}

.price-card h3 {
  font-size: 1.1rem;
  margin-bottom: 0.25rem;
}

.price-amount {
  font-size: 2.2rem;
  font-weight: 700;
  letter-spacing: -0.03em;
}

.price-amount .per {
  font-size: 0.9rem;
  font-weight: 400;
  color: var(--text-muted);
}

.price-tagline {
  color: var(--text-muted);
  font-size: 0.9rem;
  margin-bottom: 1.25rem;
}

.price-features {
  list-style: none;
  margin: 0 0 1.75rem;
  padding: 0;
  flex: 1;
}

.price-features li {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  padding: 0.4rem 0;
  font-size: 0.95rem;
}

.price-features li::before {
  content: "✓";
  color: var(--accent-primary);
  font-weight: 700;
  flex-shrink: 0;
}

.price-badge {
  position: absolute;
  top: -0.8rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  padding: 0.25rem 0.9rem;
  border-radius: 999px;
  background: var(--accent-primary);
  color: var(--bg-primary);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  white-space: nowrap;
}

.price-card .btn {
  width: 100%;
}

/* ---------- Final CTA ---------- */

.final-cta {
  text-align: center;
  background:
    radial-gradient(ellipse 60% 60% at 50% 110%,
      color-mix(in srgb, var(--accent-primary) 8%, transparent),
      transparent);
}

.final-cta h2 {
  font-size: clamp(1.6rem, 4.5vw, 2.4rem);
  margin-bottom: 1.5rem;
}

/* ---------- Footer ---------- */

.site-footer {
  border-top: 1px solid var(--border-card);
  padding: 2rem 0;
  text-align: center;
}

.site-footer p {
  margin: 0;
  font-size: 0.9rem;
}

.site-footer p + p {
  margin-top: 0.6rem;
}

/* Terms/Privacy links -- the only links .site-footer has had since the
   old self-referencing "InfraCherry" brand link (https://infracherry.com)
   was removed when this became that domain's own homepage. */
.site-footer a {
  color: var(--text-muted);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.site-footer a:hover {
  color: #ffffff;
}

.footer-legal-links {
  font-size: 0.82rem;
}

.footer-legal-links span {
  margin: 0 0.5em;
  opacity: 0.5;
}

/* ---------- Legal pages (terms.html / privacy.html) ---------- */

.legal-main {
  padding: 3rem 0 4rem;
}

.legal-header {
  max-width: 760px;
  margin: 0 auto 2.5rem;
  text-align: center;
}

.legal-header h1 {
  font-size: clamp(1.8rem, 4vw, 2.4rem);
}

.legal-updated {
  color: var(--text-muted);
  font-size: 0.85rem;
}

/* Same glass-card material as .card-glass/.auth-card/.user-dropdown
   (gradient background + soft border + shadow), but deliberately WITHOUT
   .card-glass's hover-lift transform -- this is a large static reading
   surface, not a clickable card, so a page-wide lift/shadow animation on
   hover while someone's trying to read would just be distracting. */
.legal-card {
  max-width: 760px;
  margin: 0 auto;
  padding: 2.5rem clamp(1.5rem, 4vw, 3rem);
  background: linear-gradient(135deg, var(--bg-card) 0%, var(--bg-primary) 100%);
  border: 1px solid color-mix(in srgb, white 10%, transparent);
  border-radius: var(--radius-xl);
  box-shadow:
    0 20px 60px color-mix(in srgb, black 35%, transparent),
    inset 0 1px 0 color-mix(in srgb, white 8%, transparent);
}

.legal-card h2 {
  font-size: 1.3rem;
  margin-top: 2.25rem;
}

.legal-card h2:first-child {
  margin-top: 0;
}

.legal-card h3 {
  font-size: 1rem;
  margin-top: 1.5rem;
}

.legal-card p,
.legal-card li {
  color: var(--text-muted);
  font-size: 0.95rem;
}

.legal-card ul,
.legal-card ol {
  margin: 0 0 1em;
  padding-left: 1.4rem;
}

.legal-card li {
  margin-bottom: 0.4em;
}

.legal-card strong {
  color: #ffffff;
}

.legal-card a {
  color: var(--accent-primary);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.legal-card a:hover {
  color: var(--accent-secondary);
}

@media (max-width: 640px) {
  .legal-card {
    padding: 1.75rem 1.25rem;
    border-radius: var(--radius-lg);
  }
}

/* ---------- App pages (dashboard.html / settings.html) ---------- */

.card,
.card-grid > * {
  background: var(--bg-card);
  border: 1px solid var(--border-card);
  border-radius: var(--radius-md);
  padding: 1.5rem;
}

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 1rem;
}

.dashboard,
.settings {
  padding: 2rem 1.25rem;
  max-width: 960px;
  margin: 0 auto;
}

/* ==========================================================================
   Dashboard (dashboard.html)
   ========================================================================== */

:root {
  /* Semantic status colors for app pages. The brand palette has no
     danger/warning hue, so these are deliberate additions — used only
     for failed/destructive (--danger) or in-progress/pending
     (--warning) states, never decoratively. */
  --danger: #E5484D;
  --warning: #F5A623;

  /* "Restore to Original Source" (override mode) Danger Zone panel
     (docs/design/restore-override-phase3.md §11) -- five stage-indexed
     stops running from --warning (stage 0, the consequence-copy screen
     someone just reading what the button does shouldn't be met with
     full alarm-red) to --danger (stage 4, the live countdown right
     before the overwrite). Derived from the app's own existing
     --warning/--danger tokens via color-mix rather than new arbitrary
     hex values, so the gradient stays consistent with every other
     amber/red usage on the site. */
  --danger-stage-0: var(--warning);
  --danger-stage-1: color-mix(in srgb, var(--warning) 72%, var(--danger) 28%);
  --danger-stage-2: color-mix(in srgb, var(--warning) 46%, var(--danger) 54%);
  --danger-stage-3: color-mix(in srgb, var(--warning) 22%, var(--danger) 78%);
  --danger-stage-4: var(--danger);
}

.dash-main {
  padding-top: 1.5rem;
  padding-bottom: 3rem;
}

/* The landing page gives bare <section> large vertical padding; dashboard
   sections manage their own spacing. */
.dash-main section {
  padding: 0;
}

/* Navbar user menu */

.user-menu {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-muted);
  padding: 0.25rem;
}

.user-menu:hover {
  color: #ffffff;
}

.avatar {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--accent-primary) 18%, var(--bg-card));
  border: 1px solid var(--border-card);
  color: var(--accent-primary);
  font-weight: 700;
  font-size: 0.85rem;
}

.user-menu .chevron {
  width: 14px;
  height: 14px;
  transition: transform 0.15s ease;
}

.user-menu[aria-expanded="true"] .chevron {
  transform: rotate(180deg);
}

.user-menu-wrap {
  position: relative;
}

.user-dropdown {
  position: absolute;
  right: 0;
  top: calc(100% + 8px);
  z-index: 60;
  min-width: 190px;
  padding: 0.4rem;
  background: var(--bg-card);
  border: 1px solid var(--border-card);
  border-radius: var(--radius-md);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
}

.user-dropdown [role="menuitem"] {
  display: block;
  width: 100%;
  padding: 0.5rem 0.75rem;
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  font: 500 0.9rem var(--font-sans);
  text-decoration: none;
  text-align: left;
  background: none;
  border: none;
  cursor: pointer;
}

.user-dropdown [role="menuitem"]:hover {
  color: #ffffff;
  background: color-mix(in srgb, #ffffff 6%, transparent);
}

.user-dropdown [role="menuitem"]:focus-visible {
  outline: 2px solid var(--accent-secondary);
  outline-offset: -2px;
}

.user-dropdown .menu-divider {
  height: 1px;
  margin: 0.35rem 0.25rem;
  background: var(--border-card);
  border: none;
}

/* dashboard.html's top row: plan usage on the left, the radial nav
   (js/radial-nav.js) on the right -- stacked on narrower screens (see
   the @media (min-width: 1024px) rule below), matching index.html's own
   hero-side layout so the widget stays above the fold either way. */
.dash-top-row {
  display: grid;
  grid-template-columns: 1fr;
  align-items: start;
  gap: 2rem;
  margin-bottom: 2rem;
}

.dash-top-row .usage-bar {
  margin-bottom: 0;
}

/* Plan usage summary bar */

.usage-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1.25rem;
  margin-bottom: 2rem;
  border-radius: var(--radius-md);
}

/* Scoped under .dash-main for the same reason as .settings-section above
   -- .usage-bar is a <section>, so a plain single-class padding rule
   loses to .dash-main section { padding: 0 } regardless of source order. */
.dash-main .usage-bar {
  padding: 0.9rem 1.25rem;
}

.plan-chip {
  padding: 0.2rem 0.75rem;
  border-radius: 999px;
  background: color-mix(in srgb, var(--accent-primary) 12%, transparent);
  color: var(--accent-primary);
  font-size: 0.8rem;
  font-weight: 700;
  white-space: nowrap;
}

.usage-readout {
  flex: 1;
  min-width: 220px;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  font-size: 0.9rem;
  color: var(--text-muted);
}

.upgrade-hint {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--accent-secondary);
  text-decoration: none;
  white-space: nowrap;
}

.upgrade-hint:hover {
  text-decoration: underline;
}

/* Progress bars (usage + storage) */

.progress {
  height: 6px;
  border-radius: 3px;
  background: var(--border-card);
  overflow: hidden;
}

.progress > span {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--accent-primary), var(--accent-secondary));
  transition: width 0.6s ease;
}

/* Layout: connections main column + aside */

.dash-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2rem;
}

.section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 1.25rem;
}

.section-head h1 {
  font-size: 1.4rem;
  margin: 0;
}

/* Connection cards */

.conn-list {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.conn-card {
  border-radius: var(--radius-md);
  padding: 1.25rem 1.5rem;
}

.conn-head {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 1rem;
}

.conn-head h3 {
  margin: 0;
  font-size: 1.05rem;
}

.status-dot.muted {
  background: var(--text-muted);
  animation: none;
}

.provider-chip {
  padding: 0.1rem 0.6rem;
  border-radius: 999px;
  border: 1px solid var(--border-card);
  color: var(--text-muted);
  font-size: 0.75rem;
  white-space: nowrap;
}

.kebab {
  margin-left: auto;
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: 1.2rem;
  line-height: 1;
  padding: 0.25rem 0.5rem;
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.kebab:hover {
  color: #ffffff;
  background: color-mix(in srgb, #ffffff 6%, transparent);
}

.conn-meta {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 0.75rem;
  margin: 0 0 1.1rem;
}

.conn-meta dt {
  color: var(--text-muted);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: 0.15rem;
}

.conn-meta dd {
  margin: 0;
  font-size: 0.95rem;
}

.badge {
  display: inline-block;
  padding: 0.1rem 0.6rem;
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 600;
}

.badge-success {
  color: var(--accent-primary);
  background: color-mix(in srgb, var(--accent-primary) 12%, transparent);
}

.badge-failed {
  color: var(--danger);
  background: color-mix(in srgb, var(--danger) 12%, transparent);
}

/* "Backup now" -> 202 accepted, polling GET /connections until the
   status becomes terminal (see dashboard.js's pollBackupStatus()). The
   pulse animation itself lives in animations.css, next to .status-dot's
   own "alive" blink. */
.badge-pending {
  color: var(--warning);
  background: color-mix(in srgb, var(--warning) 12%, transparent);
}

/* Free-plan trial phase badges (dashboard.js's buildFreeTrialBadge(),
   billing/free_trial.py's own thresholds) -- days 31-60: a plain,
   non-interactive <span>, same amber treatment as .badge-pending. */
.badge-free-trial-warning {
  color: var(--warning);
  background: color-mix(in srgb, var(--warning) 12%, transparent);
}

/* Day 61+: a real <a href="index.html#pricing"> (not just a styled
   span), so it's independently clickable/tabbable, same red treatment
   as .badge-failed -- unlike every other badge in this file, this one
   is genuinely interactive. */
.badge-free-trial-ended {
  color: var(--danger);
  background: color-mix(in srgb, var(--danger) 12%, transparent);
  text-decoration: none;
  cursor: pointer;
}

.badge-free-trial-ended:hover {
  text-decoration: underline;
}

/* Shown below a connection card's meta list when its latest backup
   FAILED (dashboard.js's buildReportBox()) -- a neutral, informational
   nudge, not itself an error/warning restatement of the Failed badge
   above it, so it deliberately doesn't reuse --danger/--warning tints. */
.report-box {
  margin-top: 0.75rem;
  padding: 0.75rem 0.9rem;
  background: color-mix(in srgb, white 4%, transparent);
  border: 1px solid var(--border-card);
  border-radius: var(--radius-sm);
}

.report-box-text {
  margin: 0 0 0.6rem;
  font-size: 0.82rem;
  color: var(--text-muted);
}

.conn-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
}

/* "X of Y manual backups left today" / reset countdown under "Backup
   now" (dashboard.js's buildManualBackupQuota()) -- plain caption text,
   same treatment as .report-box-text just above, not its own box. */
.manual-backup-quota {
  margin: 0.6rem 0 0;
  font-size: 0.78rem;
  color: var(--text-muted);
}

.btn-sm {
  padding: 0.45rem 1rem;
  font-size: 0.85rem;
}

.btn-ghost {
  background: transparent;
  color: var(--text-muted);
  border: 1px solid var(--border-card);
}

.btn-ghost:hover {
  color: #ffffff;
  border-color: var(--text-muted);
}

/* "+ Add Database" card */

.add-card {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  padding: 1.25rem;
  border-radius: var(--radius-md);
  border: 1px dashed var(--border-card);
  background: transparent;
  color: var(--text-muted);
  font: 600 0.95rem var(--font-sans);
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease;
}

.add-card:hover {
  color: var(--accent-primary);
  border-color: var(--accent-primary);
}

.add-plus {
  font-size: 1.3rem;
  line-height: 1;
}

/* Shown instead of the clickable .add-card once
   state.connections.length reaches the plan's connection limit
   (dashboard.js's buildAddCard()) -- same dashed-box footprint, stacked
   text instead of the horizontal "+ Add Database" row, and not
   interactive (a plain <div>, not a <button>: there's nothing to click
   here besides the upgrade link). */
.add-card-disabled {
  flex-direction: column;
  gap: 0.35rem;
  cursor: default;
  color: var(--text-muted);
  opacity: 0.7;
}

.add-card-disabled:hover {
  color: var(--text-muted);
  border-color: var(--border-card);
}

/* Aside: storage + activity */

.dash-aside {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.aside-card {
  border-radius: var(--radius-md);
  padding: 1.25rem 1.5rem;
}

.aside-card h2 {
  font-size: 0.95rem;
  margin: 0 0 0.9rem;
}

.storage-readout {
  margin: 0 0 0.6rem;
  font-size: 1.05rem;
}

.activity-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.activity-item {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 0.5rem 0;
  font-size: 0.85rem;
  border-bottom: 1px solid color-mix(in srgb, var(--border-card) 60%, transparent);
}

.activity-item:last-child {
  border-bottom: none;
}

.activity-dot {
  flex-shrink: 0;
  width: 7px;
  height: 7px;
  margin-top: 0.45em;
  border-radius: 50%;
}

.activity-dot.success { background: var(--accent-primary); }
.activity-dot.error { background: var(--danger); }
.activity-dot.info { background: var(--accent-secondary); }

.activity-body {
  flex: 1;
  min-width: 0;
}

.activity-text {
  display: block;
}

/* Badge + timestamp on their own line below the message, rather than
   sharing the message's own line -- this sidebar card is narrow enough
   that a long connection name already wraps the message onto two
   lines, so the badge/timestamp would otherwise fight it for space. */
.activity-meta {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-top: 0.25rem;
}

.activity-when {
  font-size: 0.78rem;
}

/* Empty state */

.empty-state {
  max-width: 26rem;
  margin: 4rem auto;
  text-align: center;
}

.empty-illustration svg {
  width: 96px;
  height: 96px;
  margin: 0 auto 1.5rem;
}

.empty-state h1 {
  font-size: 1.4rem;
}

.empty-state p {
  margin-bottom: 1.75rem;
}

/* Toasts */

.toast-container {
  position: fixed;
  top: 4.5rem;
  right: 1.25rem;
  z-index: 100;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  max-width: min(320px, calc(100vw - 2.5rem));
}

.toast {
  padding: 0.75rem 1.1rem;
  border-radius: var(--radius-sm);
  background: var(--bg-card);
  border: 1px solid var(--border-card);
  border-left: 3px solid var(--accent-secondary);
  font-size: 0.9rem;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
}

.toast-success {
  border-left-color: var(--accent-primary);
}

/* Card kebab dropdown (same interaction pattern as the navbar user menu) */

.card-menu-wrap {
  position: relative;
  margin-left: auto;
}

.card-menu-wrap .kebab {
  margin-left: 0;
}

.card-menu {
  position: absolute;
  right: 0;
  top: calc(100% + 4px);
  z-index: 55;
  min-width: 170px;
  padding: 0.4rem;
  background: var(--bg-card);
  border: 1px solid var(--border-card);
  border-radius: var(--radius-md);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
}

.card-menu [role="menuitem"] {
  display: block;
  width: 100%;
  padding: 0.45rem 0.7rem;
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  font: 500 0.85rem var(--font-sans);
  text-align: left;
  background: none;
  border: none;
  cursor: pointer;
}

.card-menu [role="menuitem"]:hover:not([aria-disabled="true"]) {
  color: #ffffff;
  background: color-mix(in srgb, #ffffff 6%, transparent);
}

.card-menu [role="menuitem"]:focus-visible {
  outline: 2px solid var(--accent-secondary);
  outline-offset: -2px;
}

.card-menu [role="menuitem"].danger {
  color: var(--danger);
}

.card-menu [role="menuitem"][aria-disabled="true"] {
  opacity: 0.45;
  cursor: default;
}

/* Dashboard misc interactivity */

.badge-muted {
  color: var(--text-muted);
  background: color-mix(in srgb, var(--text-muted) 12%, transparent);
}

/* trigger_type badges (Backup History modal rows, dashboard.js's
   triggerTypeBadge()) -- "Manual" gets its own accent so a user-initiated
   backup stands out in the list; "Scheduled" is the routine/expected
   case, so it reuses .badge-muted's neutral treatment rather than
   competing for attention. */
.badge-manual {
  color: var(--accent-secondary);
  background: color-mix(in srgb, var(--accent-secondary) 12%, transparent);
}

.badge-scheduled {
  color: var(--text-muted);
  background: color-mix(in srgb, var(--text-muted) 12%, transparent);
}

.form-error {
  margin: 0 0 1rem;
  color: var(--danger);
  font-size: 0.85rem;
}

/* Neutral (non-error) inline message, e.g. login.html's post-redirect
   "Password changed, please log in again" notice. */
.form-info {
  margin: 0 0 1rem;
  padding: 0.6rem 0.9rem;
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--accent-primary) 12%, transparent);
  color: var(--accent-primary);
  font-size: 0.85rem;
}

.btn.is-loading {
  opacity: 0.65;
  pointer-events: none;
}

/* Same treatment for a non-.btn action button living in the settings
   sidebar (#nav-manage-billing) -- see settings.js. */
.tab-btn.is-loading {
  opacity: 0.65;
  pointer-events: none;
}

/* DEV ONLY control for QA-ing mock states; removed with the real API */
.dev-toggle {
  position: fixed;
  bottom: 1rem;
  left: 1rem;
  z-index: 80;
  padding: 0.4rem 0.7rem;
  font: 600 0.7rem var(--font-sans);
  letter-spacing: 0.05em;
  color: var(--text-muted);
  background: var(--bg-card);
  border: 1px dashed var(--border-card);
  border-radius: var(--radius-sm);
  cursor: pointer;
  opacity: 0.7;
}

.dev-toggle:hover {
  opacity: 1;
  color: #ffffff;
}

/* ── Hero Status: single-glance, zero-scroll summary (dashboard.js's
   renderHero()) ────────────────────────────────────────────────────── */

.dash-hero {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem;
  margin-bottom: 1.5rem;
}

.dash-hero-status,
.dash-hero-score {
  border-radius: var(--radius-md);
  padding: 1.25rem 1.5rem;
}

.dash-hero-headline {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  margin-bottom: 1.1rem;
}

.dash-hero-headline h1 {
  margin: 0;
  font-size: 1.25rem;
}

.dash-hero-status-icon {
  width: 26px;
  height: 26px;
  flex-shrink: 0;
}

.dash-hero-status-icon.good { color: var(--accent-primary); }
.dash-hero-status-icon.warn { color: var(--warning); }
.dash-hero-status-icon.bad { color: var(--danger); }

/* Reused by both the Hero row's stat chips AND the 4 quick-glance cards
   below -- each individual chip is a .status-card (the SAME class
   index.html's own marketing hero stats already use), so both places
   look identical by construction rather than a second, drifting copy. */
.dash-hero-stats,
.dash-quick-cards {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.9rem;
}

.dash-quick-cards {
  margin-bottom: 2rem;
}

.status-dot.warning {
  background: var(--warning);
}

/* Protection Score (Lite+) */

.dash-hero-score-body {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  flex-wrap: wrap;
}

.dash-hero-score h2 {
  font-size: 0.95rem;
  margin: 0 0 1rem;
}

.score-ring {
  --score-pct: 0;
  --score-color: var(--accent-primary);
  width: 92px;
  height: 92px;
  border-radius: 50%;
  flex-shrink: 0;
  display: grid;
  place-items: center;
  background: conic-gradient(
    var(--score-color) calc(var(--score-pct) * 1%),
    var(--border-card) 0
  );
}

.score-ring-inner {
  width: 74px;
  height: 74px;
  border-radius: 50%;
  background: var(--bg-card);
  display: grid;
  place-items: center;
  font-weight: 700;
  font-size: 1.35rem;
  color: #ffffff;
}

.score-ring-inner span {
  font-size: 0.65rem;
  font-weight: 500;
  color: var(--text-muted);
}

.score-breakdown {
  flex: 1;
  min-width: 220px;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.score-breakdown-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 0.85rem;
  color: var(--text-muted);
}

.score-breakdown-row .value {
  color: #ffffff;
  font-weight: 600;
}

/* Radial nav: shrunk to a small, secondary element now that the Hero
   Status row above is the page's primary at-a-glance content -- the
   widget itself (radial-nav.css) is untouched, this just caps how much
   room it's given on THIS page specifically (index.html's own hero-side
   instance is unaffected, it never gets this wrapper class).

   Labels are hidden at this size rather than left to shrink with the
   rest of the widget: radial-nav.css's own width clamp() has a
   DOCUMENTED 270px floor specifically because the item labels need that
   much room to stay legible/non-overlapping (see that file's own
   comment on it) -- forcing the widget smaller than that via max-width
   here (bypassing the clamp floor entirely, since max-width always wins
   over a conflicting width) reintroduces exactly the overlap that floor
   exists to prevent. Icon-only avoids it: the icons remain legible at a
   much smaller absolute size than the labels ever could, and each item
   still has a native title tooltip (radial-nav.js) for its label. */
.radial-nav-compact {
  max-width: 130px;
  justify-self: end;
}

.radial-nav-compact .radial-nav-item-label {
  display: none;
}

/* ── Generic new-panel wrapper (Backup Timeline, Database Health) --
   same border-radius/padding convention as .aside-card. ─────────────── */

.dash-panel {
  border-radius: var(--radius-md);
  padding: 1.5rem 1.75rem;
  margin-bottom: 2rem;
}

.dash-panel h2 {
  font-size: 1.05rem;
  margin: 0 0 1.1rem;
}

/* Backup Timeline */

.timeline-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}

.timeline-item {
  display: flex;
  align-items: flex-start;
  gap: 0.9rem;
  padding: 0.75rem 0;
  border-bottom: 1px solid color-mix(in srgb, white 6%, transparent);
}

.timeline-item:last-child {
  border-bottom: none;
}

.timeline-icon {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  flex-shrink: 0;
  display: grid;
  place-items: center;
  margin-top: 0.1rem;
}

.timeline-icon.success {
  background: color-mix(in srgb, var(--accent-primary) 18%, transparent);
  color: var(--accent-primary);
}

.timeline-icon.error {
  background: color-mix(in srgb, var(--danger) 18%, transparent);
  color: var(--danger);
}

.timeline-icon.pending {
  background: color-mix(in srgb, var(--warning) 18%, transparent);
  color: var(--warning);
}

.timeline-body {
  flex: 1;
  min-width: 0;
}

.timeline-title {
  font-size: 0.92rem;
  font-weight: 600;
}

.timeline-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.2rem;
  font-size: 0.78rem;
  color: var(--text-muted);
}

/* Database Health */

.health-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 1.1rem;
  margin: 0;
}

.health-grid dt {
  color: var(--text-muted);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: 0.3rem;
}

.health-grid dd {
  margin: 0;
  font-size: 0.98rem;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

/* ── Pro/Max insight cards: Backup Confidence, Recovery Readiness, Risk
   Analyzer, Backup Insights, Restore Simulation, Recovery Center -- all
   visually-complete, code-flagged placeholders (dashboard.js's own
   TODO(real-logic) comments), never labeled as mock in this UI. ─────── */

.dash-insights-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem;
  margin-bottom: 2rem;
}

.insight-card {
  border-radius: var(--radius-md);
  padding: 1.25rem 1.5rem;
}

.insight-card h3 {
  font-size: 0.8rem;
  margin: 0 0 0.9rem;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-weight: 700;
}

.insight-big-number {
  font-size: 2.1rem;
  font-weight: 700;
  color: var(--accent-primary);
  line-height: 1;
}

.insight-sub {
  font-size: 0.85rem;
  color: var(--text-muted);
  margin-top: 0.4rem;
}

.insight-list {
  list-style: none;
  margin: 0.85rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  font-size: 0.88rem;
}

.insight-list li {
  display: flex;
  justify-content: space-between;
  color: var(--text-muted);
}

.insight-list li span:last-child {
  color: #ffffff;
  font-weight: 600;
}

.recovery-center-callout {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 1.5rem;
  flex-wrap: wrap;
}

.recovery-center-time {
  font-size: 1.9rem;
  font-weight: 700;
  color: var(--accent-secondary);
  white-space: nowrap;
}

/* Locked (plan-gated) section state -- replaces a section's real content
   with a clearly-labeled upgrade prompt, never fabricated numbers. */

.dash-locked {
  text-align: center;
  padding: 2rem 1.5rem;
}

.dash-locked-icon {
  width: 30px;
  height: 30px;
  margin: 0 auto 0.75rem;
  color: var(--text-muted);
}

.dash-locked p {
  color: var(--text-muted);
  margin: 0.35rem 0 0.9rem;
  font-size: 0.9rem;
}

/* Dashboard responsive */

@media (min-width: 640px) {
  .dash-hero-stats {
    grid-template-columns: repeat(3, 1fr);
  }

  .dash-quick-cards {
    grid-template-columns: repeat(4, 1fr);
  }
}

@media (min-width: 768px) {
  .dash-insights-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 1024px) {
  .dash-grid {
    grid-template-columns: 2fr 1fr;
    align-items: start;
  }

  .dash-top-row {
    grid-template-columns: 1fr auto;
  }

  .dash-hero-stats {
    grid-template-columns: repeat(6, 1fr);
  }
}

@media (min-width: 1200px) {
  .dash-insights-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* ==========================================================================
   Settings (settings.html)
   ========================================================================== */

.settings-title {
  font-size: 1.4rem;
  margin-bottom: 1.5rem;
}

/* Layout: horizontal scrollable tabs (mobile) → sticky sidebar (desktop) */

.settings-layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.5rem;
  align-items: start;
}

/* Glassmorphism family shared with the top-nav's account dropdown
   (.nav-user-menu-wrap .user-dropdown in the marketing header) -- same
   blur/border/radius/shadow recipe, applied here to a sticky sidebar
   container instead of a popup. */
.settings-nav {
  display: flex;
  gap: 0.25rem;
  overflow-x: auto;
  padding: 0.5rem;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none; /* tabs swipe on touch; desktop gets the sidebar */
  background: color-mix(in srgb, var(--bg-card) 75%, transparent);
  border: 1px solid color-mix(in srgb, white 10%, transparent);
  border-radius: 24px;
  backdrop-filter: blur(25px);
  -webkit-backdrop-filter: blur(25px);
  box-shadow:
    0 20px 50px color-mix(in srgb, black 35%, transparent),
    inset 0 1px 0 color-mix(in srgb, white 8%, transparent);
}

.settings-nav::-webkit-scrollbar {
  display: none;
}

.tab-btn {
  white-space: nowrap;
  background: none;
  border: none;
  color: var(--text-muted);
  padding: 0.6rem 0.9rem;
  border-radius: var(--radius-md);
  font: 600 0.9rem var(--font-sans);
  cursor: pointer;
  text-align: left;
  transition: background 0.2s ease, color 0.2s ease;
}

/* Matches .nav-user-dropdown [role="menuitem"]'s own hover treatment. */
.tab-btn:hover:not(:disabled) {
  color: #ffffff;
  background: color-mix(in srgb, white 8%, transparent);
}

.tab-btn:focus-visible {
  outline: 2px solid var(--accent-secondary);
  outline-offset: -2px;
}

.tab-btn.active {
  color: var(--accent-primary);
  background: color-mix(in srgb, var(--accent-primary) 10%, transparent);
}

/* #nav-manage-billing and #bl-cancel-link (billing.html) -- disabled for
   Free-plan users (no billing account/subscription to manage yet),
   matching the app's existing disabled-button convention
   (.btn-danger:disabled). */
.tab-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

/* API Keys tab when the account's current plan can't use it --
   settings.js's applyApiKeysPlanGate(). Deliberately NOT the native
   `disabled` attribute (unlike #nav-manage-billing/#nav-manage-
   subscription above): this is a real role="tab" button that must stay
   in the roving-tabindex/arrow-key group and stay clickable -- clicking
   it still opens the tab, which then shows its own locked/upgrade block
   instead of the real key-management UI (same visual-only "not available
   yet" cue .app-sidebar-item.is-locked gives the matching sidebar item). */
.tab-btn.is-locked {
  opacity: 0.4;
  cursor: not-allowed;
}

/* Scoped under .dash-main to outweigh the `.dash-main section { padding: 0 }`
   reset above — these cards do want their own padding. */
.dash-main .settings-section {
  border-radius: var(--radius-md);
  padding: 1.75rem;
}

.settings-section h2 {
  font-size: 1.15rem;
  margin: 0 0 1.25rem;
}

.section-sub {
  margin: -0.75rem 0 1.5rem;
  font-size: 0.9rem;
}

.subsection-title {
  font-size: 0.95rem;
  margin: 2rem 0 1rem;
}

.subsection-title:first-of-type {
  margin-top: 0;
}

/* Forms */

.field {
  max-width: 24rem;
  margin-bottom: 1.1rem;
}

.field label {
  display: block;
  font-size: 0.8rem;
  color: var(--text-muted);
  margin-bottom: 0.35rem;
}

.field input,
.field select,
.field textarea,
.modal input {
  width: 100%;
  padding: 0.6rem 0.8rem;
  background: var(--bg-primary);
  border: 1px solid var(--border-card);
  border-radius: var(--radius-sm);
  color: #ffffff;
  font: 400 0.95rem var(--font-sans);
}

.field textarea {
  font-family: ui-monospace, "Cascadia Code", Consolas, monospace;
  font-size: 0.85rem;
  resize: vertical;
  min-height: 4.5rem;
}

.field input:focus,
.field select:focus,
.field textarea:focus,
.modal input:focus {
  outline: none;
  border-color: var(--accent-primary);
}

.readonly-value {
  padding: 0.6rem 0.8rem;
  background: color-mix(in srgb, var(--bg-primary) 60%, var(--bg-card));
  border: 1px solid var(--border-card);
  border-radius: var(--radius-sm);
  color: var(--text-muted);
}

.field-note {
  margin: 0.35rem 0 0;
  font-size: 0.78rem;
}

.field-note-alert {
  color: var(--app-warning);
  font-weight: 600;
}

.pitr-fresh-warning {
  margin: 1rem 0;
  padding: 0.85rem 1rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--app-warning);
  background: color-mix(in srgb, var(--app-warning) 12%, transparent);
}

.pitr-fresh-warning p {
  margin: 0;
  font-size: 0.85rem;
}

.pitr-fresh-warning p + p {
  margin-top: 0.4rem;
}

.pitr-summary-list {
  margin: 1rem 0;
  padding-left: 1.1rem;
  font-size: 0.85rem;
  line-height: 1.6;
}

.profile-avatar-row {
  margin-bottom: 1.5rem;
}

.avatar-lg {
  width: 64px;
  height: 64px;
  font-size: 1.5rem;
}

/* Plan summary (compact mirror of the pricing card) */

.plan-summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.5rem;
  padding: 1.25rem 1.5rem;
  margin-bottom: 1.25rem;
  border-radius: var(--radius-md);
}

.plan-summary-name h3 {
  margin: 0 0 0.1rem;
  font-size: 1rem;
  color: var(--accent-primary);
}

.plan-summary .price-amount {
  font-size: 1.5rem;
}

.plan-summary .usage-readout {
  flex: 1;
  min-width: 200px;
}

/* Upgrade cards (Lite/Pro/Max) — the SAME shared .card-glass material as
   the public pricing cards (previously a separate, bespoke translucent-
   blur treatment; unified for visual consistency across the app). */

.upgrade-cards {
  display: grid;
  /* auto-fit/minmax rather than a fixed-count breakpoint (e.g. the old
     "repeat(3, 1fr) above 640px"): this column now holds 4 cards
     (Easy/Lite/Pro/Max) instead of 3, and this section's actual
     available width isn't simply proportional to the viewport --
     .settings-nav's own sidebar changes width at its own breakpoints,
     so a fixed viewport-width media query got the wrong answer at
     several widths (confirmed empirically: overflowed at both 700px
     AND 1024px, fine in between). minmax's lower bound is the
     narrowest a card can get before its own feature text starts
     wrapping badly (checked against "Guided database restore", the
     longest recurring bullet) -- auto-fit just wraps to fewer columns
     whenever the ACTUAL container is too narrow for another one,
     regardless of why. */
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 1.25rem;
  margin-top: 1.25rem;
}

.upgrade-card {
  display: flex;
  flex-direction: column;
  padding: 1.75rem;
  border-radius: var(--radius-lg);
}

/* "Most popular" (Pro): same standing-glow treatment as .price-card.featured. */
.upgrade-card.popular {
  border-color: color-mix(in srgb, var(--accent-primary) 35%, transparent);
  box-shadow: 0 0 40px color-mix(in srgb, var(--accent-primary) 12%, transparent);
}

.upgrade-card.popular:hover {
  box-shadow: 0 20px 70px -10px color-mix(in srgb, var(--accent-primary) 50%, transparent);
}

.upgrade-card-badge {
  position: absolute;
  top: -0.8rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  padding: 0.25rem 0.9rem;
  border-radius: 999px;
  background: var(--accent-primary);
  color: var(--bg-primary);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  white-space: nowrap;
}

.upgrade-card-current-badge {
  align-self: flex-start;
  margin-bottom: 0.75rem;
  padding: 0.2rem 0.7rem;
  border-radius: 999px;
  background: color-mix(in srgb, var(--text-muted) 20%, transparent);
  color: var(--text-muted);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.04em;
}

.upgrade-card h3 {
  font-size: 1.05rem;
  margin-bottom: 0.25rem;
}

.upgrade-card-features {
  list-style: none;
  margin: 1rem 0 1.5rem;
  padding: 0;
  flex: 1;
}

.upgrade-card-features li {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  padding: 0.35rem 0;
  font-size: 0.88rem;
}

.upgrade-card-features li::before {
  content: "✓";
  color: var(--accent-primary);
  font-weight: 700;
  flex-shrink: 0;
}

.upgrade-card .btn {
  width: 100%;
}

/* Preference rows (2FA, notifications, danger zone) */

.pref-row {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.9rem 0;
  border-bottom: 1px solid color-mix(in srgb, var(--border-card) 60%, transparent);
}

.pref-row:last-child {
  border-bottom: none;
}

.pref-text {
  flex: 1;
}

/* 2FA setup: QR code + manual-entry secret */

.twofa-qr-wrap {
  display: inline-block;
  padding: 0.75rem;
  margin: 0.75rem 0;
  background: #fff; /* QR codes need real white/black contrast regardless of theme */
  border-radius: var(--radius-sm);
}

#twofa-secret-text {
  padding: 0.15rem 0.4rem;
  border-radius: 4px;
  background: var(--bg-primary);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.85rem;
  word-break: break-all;
}

.pref-text strong {
  font-size: 0.95rem;
}

.pref-text p {
  margin: 0.15rem 0 0;
  font-size: 0.85rem;
}

.saved-slot {
  min-width: 3rem;
  text-align: right;
  font-size: 0.8rem;
}

.saved-flash {
  color: var(--accent-primary);
  font-weight: 600;
}

/* Toggle switch */

.toggle {
  position: relative;
  display: inline-block;
  width: 40px;
  height: 22px;
  flex-shrink: 0;
  cursor: pointer;
}

.toggle input {
  position: absolute;
  opacity: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  cursor: pointer;
}

.toggle .track {
  position: absolute;
  inset: 0;
  border-radius: 999px;
  background: var(--border-card);
  transition: background 0.2s ease;
  pointer-events: none;
}

.toggle .track::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--text-muted);
  transition: transform 0.2s ease, background 0.2s ease;
}

.toggle input:checked ~ .track {
  background: color-mix(in srgb, var(--accent-primary) 35%, var(--border-card));
}

.toggle input:checked ~ .track::after {
  transform: translateX(18px);
  background: var(--accent-primary);
}

.toggle input:focus-visible ~ .track {
  outline: 2px solid var(--accent-secondary);
  outline-offset: 2px;
}

/* Plan-gated toggle (e.g. Notification Preferences' "Backup success
   emails" on Free/Easy/Lite -- settings.js's renderNotifications) --
   still reflects the real stored value, just not interactive. */
.toggle-disabled {
  cursor: not-allowed;
}

.toggle-disabled .track {
  opacity: 0.45;
}

.toggle-disabled input {
  cursor: not-allowed;
}

/* Sessions */

.session-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.session-row {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.75rem 0;
  border-bottom: 1px solid color-mix(in srgb, var(--border-card) 60%, transparent);
}

.session-row:last-child {
  border-bottom: none;
}

.session-current {
  margin-left: 0.5rem;
  padding: 0.05rem 0.5rem;
  border-radius: 999px;
  background: color-mix(in srgb, var(--accent-primary) 12%, transparent);
  color: var(--accent-primary);
  font-size: 0.7rem;
  font-weight: 700;
}

.link-btn {
  background: none;
  border: none;
  padding: 0.25rem;
  color: var(--accent-secondary);
  font: 600 0.85rem var(--font-sans);
  cursor: pointer;
}

.link-btn:hover {
  text-decoration: underline;
}

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

/* API keys */

.key-list {
  list-style: none;
  margin: 0 0 1.25rem;
  padding: 0;
}

.key-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1rem;
  padding: 0.75rem 0;
  border-bottom: 1px solid color-mix(in srgb, var(--border-card) 60%, transparent);
}

.key-row:last-child {
  border-bottom: none;
}

.key-row-info {
  flex: 1;
  min-width: 14rem;
}

.key-row-title {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}

.key-row-title strong {
  font-size: 0.95rem;
}

.key-masked {
  font-family: ui-monospace, "Cascadia Code", Consolas, monospace;
  font-size: 0.85rem;
  color: var(--text-muted);
}

.key-scopes {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin: 0.4rem 0 0;
}

.key-meta {
  margin: 0.35rem 0 0;
  font-size: 0.8rem;
}

.key-actions {
  display: flex;
  gap: 1rem;
  flex-shrink: 0;
}

.key-empty-state {
  padding: 1rem 0 1.5rem;
  max-width: 34rem;
}

.key-empty-state p {
  margin: 0 0 0.5rem;
  font-size: 0.9rem;
}

/* One-time key reveal (create/rotate response) -- shown in #key-reveal-modal,
   never closable except via its own explicit "I've copied my key" checkbox
   + Done button (settings.js deliberately excludes this modal from the
   generic overlay-click/Escape-to-close handling every other modal gets). */
.new-key-warning {
  margin: 0 0 0.6rem;
  font-size: 0.85rem;
  color: var(--accent-primary);
  font-weight: 600;
}

.key-reveal {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem 0.9rem;
  background: color-mix(in srgb, white 4%, transparent);
  border: 1px solid var(--border-card);
  border-radius: var(--radius-sm);
}

.key-reveal code {
  flex: 1;
  font-family: ui-monospace, "Cascadia Code", Consolas, monospace;
  font-size: 0.9rem;
  word-break: break-all;
}

.key-reveal-confirm {
  margin: 1rem 0 0;
}

/* Key activity audit trail (GET /settings/api-keys/audit) */

.audit-details summary {
  font-size: 0.95rem;
  font-weight: 600;
  cursor: pointer;
  padding: 0.5rem 0;
}

.audit-details[open] summary {
  margin-bottom: 0.5rem;
}

.audit-list {
  list-style: none;
  margin: 0 0 0.75rem;
  padding: 0;
}

.audit-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
  padding: 0.6rem 0;
  border-bottom: 1px solid color-mix(in srgb, var(--border-card) 60%, transparent);
}

.audit-row:last-child {
  border-bottom: none;
}

/* Help Center (help.html) */

.help-search {
  max-width: none;
  margin-bottom: 0.5rem;
}

.help-result-count {
  margin: 0 0 1.75rem;
  font-size: 0.85rem;
}

.help-group + .help-group {
  margin-top: 2.25rem;
}

.help-group-title {
  font-size: 1.3rem;
  margin: 0 0 0.5rem;
}

.help-entry {
  border-bottom: 1px solid color-mix(in srgb, var(--border-card) 60%, transparent);
}

.help-entry:last-child {
  border-bottom: none;
}

.help-entry summary {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  font-size: 0.95rem;
  font-weight: 600;
  cursor: pointer;
  padding: 0.8rem 0;
}

.help-entry[open] summary {
  padding-bottom: 0.3rem;
}

.help-entry-page {
  flex-shrink: 0;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--text-muted);
}

.help-entry-body {
  padding: 0 0 1.1rem;
}

.help-entry-body p,
.help-entry-body li {
  color: var(--text-muted);
  font-size: 0.92rem;
}

.help-entry-body ol {
  margin: 0.5rem 0 0.9rem;
  padding-left: 1.4rem;
}

.help-entry-body li {
  margin-bottom: 0.35em;
}

.help-entry-body .help-example {
  margin: 0.7rem 0 0;
  padding: 0.7rem 0.9rem;
  background: color-mix(in srgb, white 4%, transparent);
  border: 1px solid var(--border-card);
  border-radius: var(--radius-sm);
  font-size: 0.88rem;
}

.help-no-results {
  padding: 1.5rem 0;
  text-align: center;
}

/* Danger zone */

.danger-card {
  border-color: color-mix(in srgb, var(--danger) 40%, transparent);
}

.danger-card h2 {
  color: var(--danger);
}

/* Destructive section: keep every accent red-toned, never the shared
   .card-glass green -- a green glow on the Danger Zone would read as a
   "good" signal on exactly the wrong panel. */
.danger-card .card-glass-glow::before {
  background: var(--danger);
}

.danger-card .card-glass-glow::after {
  background: radial-gradient(
    circle at top right,
    color-mix(in srgb, var(--danger) 30%, transparent),
    transparent 60%
  );
}

.danger-card.card-glass:hover {
  border-color: color-mix(in srgb, var(--danger) 55%, transparent);
  box-shadow: 0 20px 60px -12px color-mix(in srgb, var(--danger) 30%, transparent);
}

.btn-danger {
  background: transparent;
  color: var(--danger);
  border: 1px solid var(--danger);
}

.btn-danger:hover:not(:disabled) {
  background: color-mix(in srgb, var(--danger) 12%, transparent);
}

.btn-danger:disabled {
  opacity: 0.4;
  cursor: not-allowed;
  transform: none;
}

/* Modal */

.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: grid;
  place-items: center;
  padding: 1rem;
  background: rgba(4, 6, 10, 0.72);
}

.modal {
  width: 100%;
  max-width: 26rem;
  /* .modal-overlay is a fixed, viewport-covering grid (place-items:
     center), so a modal taller than the viewport would otherwise have
     no way to reach content/buttons past its bottom edge -- max-height
     + its own scroll keeps the modal itself (not the page behind it)
     scrollable instead. A no-op for every existing, shorter modal. */
  max-height: min(85vh, 640px);
  overflow-y: auto;
  padding: 1.75rem;
  background: var(--bg-card);
  border: 1px solid var(--border-card);
  border-radius: var(--radius-lg);
}

.modal h3 {
  margin: 0 0 0.75rem;
  font-size: 1.1rem;
}

.modal input {
  margin: 1rem 0 1.25rem;
}

.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.6rem;
}

/* Backup History modal (dashboard.js's openHistoryModal()) */

.modal-wide {
  max-width: 34rem;
}

/* "Restore to Original Source" (override mode) Danger Zone panel --
   docs/design/restore-override-phase3.md §11, frontend/js/dashboard.js's
   own override-flow wiring. Deliberately its own bordered look, distinct
   from every other .modal on this page (deep navy/slate everywhere else
   on the dashboard signals trust; this panel is the one place that
   should NOT blend in) -- an amber-to-red gradient border that
   INTENSIFIES with the flow's own progress via the panel's own
   [data-stage] attribute, never solid alarm-red at rest. */
.override-panel {
  max-width: 30rem;
  border-width: 2px;
  border-color: var(--danger-stage-0);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--danger-stage-0) 22%, transparent);
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--danger-stage-0) 6%, transparent), transparent 40%),
    var(--bg-card);
  transition: border-color 400ms ease, box-shadow 400ms ease, background 400ms ease;
}

.override-panel[data-stage="1"] {
  border-color: var(--danger-stage-1);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--danger-stage-1) 26%, transparent);
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--danger-stage-1) 7%, transparent), transparent 40%),
    var(--bg-card);
}

.override-panel[data-stage="2"] {
  border-color: var(--danger-stage-2);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--danger-stage-2) 30%, transparent);
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--danger-stage-2) 8%, transparent), transparent 40%),
    var(--bg-card);
}

.override-panel[data-stage="3"] {
  border-color: var(--danger-stage-3);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--danger-stage-3) 34%, transparent);
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--danger-stage-3) 9%, transparent), transparent 40%),
    var(--bg-card);
}

.override-panel[data-stage="4"] {
  border-color: var(--danger-stage-4);
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--danger-stage-4) 40%, transparent),
    0 20px 60px -16px color-mix(in srgb, var(--danger-stage-4) 45%, transparent);
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--danger-stage-4) 10%, transparent), transparent 45%),
    var(--bg-card);
}

.override-panel-header {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 0.4rem;
}

.override-panel-icon {
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  color: var(--danger-stage-2);
}

.override-panel h3 {
  margin: 0;
}

.override-step {
  margin-top: 1rem;
}

.override-step[hidden] {
  display: none;
}

.override-step-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.6rem;
  margin-top: 1rem;
}

.override-consequence-list {
  margin: 0.75rem 0;
  padding-left: 1.1rem;
  font-size: 0.9rem;
  color: var(--text-muted);
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.override-active-conn-warning {
  padding: 0.75rem 0.9rem;
  margin: 0.75rem 0;
  border-radius: var(--radius-sm);
  border: 1px solid color-mix(in srgb, var(--danger-stage-2) 45%, transparent);
  background: color-mix(in srgb, var(--danger-stage-2) 12%, transparent);
  font-size: 0.88rem;
}

.override-countdown {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  margin: 1rem 0;
  text-align: center;
}

.override-countdown-number {
  font-size: 2.4rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--danger-stage-4);
}

.override-stepper {
  list-style: none;
  margin: 1rem 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  font-size: 0.88rem;
}

.override-stepper li {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  color: var(--text-muted);
}

.override-stepper li.is-active {
  color: var(--text-primary);
  font-weight: 600;
}

.override-stepper li.is-done {
  color: var(--danger-stage-2);
}

.override-stepper-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  border: 1.5px solid currentColor;
  flex-shrink: 0;
}

.override-stepper li.is-done .override-stepper-dot {
  background: currentColor;
}

.btn-danger-solid {
  background: var(--danger-stage-4);
  color: #fff;
  border: 1px solid var(--danger-stage-4);
}

.btn-danger-solid:hover:not(:disabled) {
  background: color-mix(in srgb, var(--danger-stage-4) 88%, black);
}

.btn-danger-solid:disabled {
  opacity: 0.4;
  cursor: not-allowed;
  transform: none;
}

.history-list {
  list-style: none;
  margin: 0 0 1rem;
  padding: 0;
  max-height: 22rem;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.history-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--border-card);
  border-radius: var(--radius-sm);
}

.history-row-loading {
  padding: 0.6rem 0.75rem;
  font-size: 0.85rem;
}

.history-row-info {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  min-width: 0;
}

.history-row-time {
  font-size: 0.85rem;
}

.history-row-meta {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.history-row-error {
  font-size: 0.78rem;
}

.history-row-trailing {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-shrink: 0;
}

.history-row-size {
  font-size: 0.78rem;
  color: var(--text-muted);
  white-space: nowrap;
}

.history-modal-actions {
  justify-content: space-between;
}

/* Error toast tone */

.toast-error {
  border-left-color: var(--danger);
}

/* Settings responsive */

@media (min-width: 1024px) {
  .settings-layout {
    grid-template-columns: 220px 1fr;
  }

  .settings-nav {
    position: sticky;
    top: 5rem;
    flex-direction: column;
    overflow-x: visible;
    padding-bottom: 0;
  }
}

/* ---------- Tablet ≥640px ---------- */

@media (min-width: 640px) {
  .nav-links {
    display: flex;
  }

  .hero-status {
    max-width: 30rem;
  }

  .pricing-grid {
    grid-template-columns: repeat(2, 1fr);
  }

  .features-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* ---------- Desktop ≥1024px ---------- */

@media (min-width: 1024px) {
  section {
    padding: 5.5rem 0;
  }

  .hero {
    padding: 5rem 0 6rem;
  }

  /* Copy + illustration left, status cards right */
  .hero-inner {
    grid-template-columns: 1.15fr 0.85fr;
    gap: 4rem;
  }

  .features-grid {
    grid-template-columns: repeat(4, 1fr);
  }

  .pricing-grid {
    /* 5 columns: matches the five-tier pricing structure (Free, Easy,
       Lite, Pro, Max) */
    grid-template-columns: repeat(5, 1fr);
    gap: 1.25rem;
  }

  /* Pro card lifts above its neighbors */
  .price-card.featured {
    transform: translateY(-0.75rem);
  }

  /* Hover adds the SAME -8px lift every other card gets, on top of (not
     instead of) the standing -0.75rem offset above -- more specific than
     the general .price-card:hover rule, so it wins regardless of source
     order. */
  .price-card.featured:hover {
    transform: translateY(calc(-0.75rem - 8px));
  }
}


/* ==========================================================================
   Auth pages (login.html / signup.html) — premium dark glassmorphism
   ========================================================================== */

/* Palette used only on these pages: cyan→violet over near-black navy.
   Deliberately outside the green/cyan brand tokens (same reasoning as the
   previous auth gradient), so the colors stay local to this section. */

.auth-body {
  background: #09090B;
}

/* Layered backdrop: radial washes + faint dot grid (pure CSS, CSP-safe) */

.auth-bg {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image:
    radial-gradient(ellipse 60% 50% at 50% -10%, rgba(36, 200, 255, 0.07), transparent 70%),
    radial-gradient(ellipse 50% 40% at 85% 110%, rgba(124, 77, 255, 0.07), transparent 70%),
    radial-gradient(circle, rgba(255, 255, 255, 0.035) 1px, transparent 1px);
  background-size: auto, auto, 24px 24px;
}

/* Blurred color glows floating behind the card */

.auth-glow {
  position: fixed;
  z-index: 0;
  width: 420px;
  height: 420px;
  border-radius: 50%;
  filter: blur(130px);
  pointer-events: none;
}

.auth-glow-blue {
  top: -140px;
  left: max(-120px, calc(50% - 620px));
  background: rgba(36, 200, 255, 0.14);
}

.auth-glow-purple {
  bottom: -160px;
  right: max(-120px, calc(50% - 620px));
  background: rgba(124, 77, 255, 0.13);
}

.auth-main {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  padding: 2.5rem 1.25rem;
}

/* Card */

.auth-card {
  width: 100%;
  max-width: 430px;
  padding: 2.5rem 2.25rem;
  background: rgba(20, 20, 28, 0.82);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 28px;
  box-shadow:
    0 24px 70px rgba(0, 0, 0, 0.5),
    0 2px 8px rgba(0, 0, 0, 0.35);
  animation: auth-card-in 0.6s cubic-bezier(0.22, 1, 0.36, 1) both;
}

@keyframes auth-card-in {
  from {
    opacity: 0;
    transform: translateY(18px) scale(0.985);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.auth-logo {
  display: flex;
  justify-content: center;
  margin-bottom: 1.75rem;
}

.auth-card h1 {
  font-size: 1.65rem;
  text-align: center;
  margin-bottom: 0.35rem;
}

.auth-sub {
  text-align: center;
  margin-bottom: 2rem;
  font-size: 0.92rem;
}

/* .field caps at 24rem for settings forms; auth inputs span the card */
.auth-card .field {
  max-width: none;
  margin-bottom: 1.15rem;
}

/* Inputs: 56px pills with a leading icon (and a toggle on passwords) */

.input-wrap {
  position: relative;
}

.auth-card .field input {
  height: 56px;
  padding: 16px;
  padding-left: 2.9rem;
  background: rgba(9, 9, 14, 0.65);
  border: 1px solid #2E2E38;
  border-radius: 16px;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.input-wrap-toggle input {
  padding-right: 3rem;
}

/* Focus: cyan border + soft glow (replaces the Border Beam on these pages) */
.auth-card .field input:focus {
  outline: none;
  border-color: #24C8FF;
  box-shadow:
    0 0 0 3px rgba(36, 200, 255, 0.14),
    0 0 24px rgba(36, 200, 255, 0.1);
}

/* Every auth icon is hard-pinned to its intended size — an unconstrained
   SVG falls back to its intrinsic dimensions and wrecks the layout. */
.input-wrap .input-icon {
  position: absolute;
  left: 1rem;
  top: 50%;
  transform: translateY(-50%);
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  color: var(--text-muted);
  pointer-events: none;
  transition: color 0.2s ease;
}

.input-wrap:focus-within .input-icon {
  color: #24C8FF;
}

.pw-toggle {
  position: absolute;
  right: 0.6rem;
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border: none;
  border-radius: 12px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  transition: color 0.15s ease;
}

.pw-toggle:hover {
  color: #ffffff;
}

.pw-toggle:focus-visible {
  outline: 2px solid #24C8FF;
  outline-offset: 1px;
}

.pw-toggle svg {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}

.field-error {
  margin: 0.35rem 0 0;
  color: var(--danger);
  font-size: 0.8rem;
}

/* Remember-me / forgot-password row */

.auth-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1.4rem;
  font-size: 0.85rem;
}

.remember {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--text-muted);
  cursor: pointer;
}

.remember input {
  width: 15px;
  height: 15px;
  margin: 0;
  accent-color: #24C8FF;
  cursor: pointer;
}

.remember input:focus-visible {
  outline: 2px solid #24C8FF;
  outline-offset: 2px;
}

.forgot-link {
  color: var(--text-muted);
  text-decoration: none;
}

.forgot-link:hover,
.forgot-link:focus-visible {
  color: var(--accent-primary);
  text-decoration: underline;
}

/* Primary auth CTA */

.btn-gradient {
  width: 100%;
  height: 56px;
  border-radius: 16px;
  background: linear-gradient(135deg, #24C8FF, #7C4DFF);
  color: #ffffff;
  font-size: 1.02rem;
  transition: transform 0.2s ease, box-shadow 0.2s ease, filter 0.2s ease;
}

.btn-gradient:hover:not(:disabled) {
  transform: translateY(-2px);
  box-shadow:
    0 8px 30px rgba(36, 200, 255, 0.25),
    0 4px 18px rgba(124, 77, 255, 0.25);
  filter: brightness(1.06);
}

.btn-gradient:focus-visible {
  outline: 2px solid #24C8FF;
  outline-offset: 2px;
}

.btn-gradient:disabled {
  cursor: not-allowed;
  transform: none;
}

.btn-spinner {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  border: 2px solid rgba(255, 255, 255, 0.35);
  border-top-color: #ffffff;
  border-radius: 50%;
  /* keyframes reused from animations.css */
  animation: icon-spin 0.7s linear infinite;
}

/* "OR" divider */

.auth-divider {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  margin: 1.6rem 0;
  color: var(--text-muted);
  font-size: 0.75rem;
  letter-spacing: 0.08em;
}

.auth-divider::before,
.auth-divider::after {
  content: "";
  height: 1px;
  flex: 1;
  background: rgba(255, 255, 255, 0.08);
}

/* Bottom link: gradient text matching the button */

.auth-alt {
  margin: 0;
  text-align: center;
  font-size: 0.9rem;
  color: var(--text-muted);
}

.auth-alt a {
  background: linear-gradient(135deg, #24C8FF, #7C4DFF);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  font-weight: 600;
  text-decoration: none;
}

/* Fine-print agreement line above signup.html's submit button. */
.auth-legal-note {
  margin: 0.75rem 0 0;
  text-align: center;
  font-size: 0.78rem;
  line-height: 1.5;
}

.auth-legal-note a {
  color: var(--text-muted);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.auth-legal-note a:hover {
  color: #ffffff;
}

.auth-alt a:hover,
.auth-alt a:focus-visible {
  /* text-decoration would be invisible on transparent text — glow instead */
  filter: brightness(1.25);
}

/* "Log in instead" link inside the signup form error */
.form-error a {
  color: inherit;
  text-decoration: underline;
}

/* Live password requirements checklist (signup.html) */

.pw-checklist {
  list-style: none;
  margin: 0.5rem 0 0;
  padding: 0;
  display: grid;
  gap: 0.3rem;
  font-size: 0.78rem;
  color: var(--text-muted);
}

.pw-checklist li {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  transition: color 0.15s ease;
}

.pw-checklist .check {
  width: 13px;
  height: 13px;
  flex-shrink: 0;
  color: color-mix(in srgb, var(--text-muted) 45%, transparent);
  transition: color 0.15s ease;
}

.pw-checklist li.met {
  color: #ffffff;
}

.pw-checklist li.met .check {
  color: #24C8FF;
}

/* Compact card on small screens */

@media (max-width: 480px) {
  .auth-card {
    padding: 2rem 1.4rem;
    border-radius: 22px;
  }
}

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

  .btn-gradient:hover:not(:disabled) {
    transform: none;
  }

  /* The "Signing in…" label alone carries the loading state */
  .btn-spinner {
    display: none;
  }
}

/* ==========================================================================
   Dashboard: real-API loading skeletons + error banner
   ========================================================================== */

.dash-error {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1rem 1.25rem;
  margin-bottom: 1.5rem;
  background: var(--bg-card);
  border: 1px solid color-mix(in srgb, var(--danger) 40%, var(--border-card));
  border-radius: var(--radius-md);
}

.dash-error p {
  margin: 0;
  color: var(--text-muted);
}

.skeleton {
  position: relative;
  overflow: hidden;
  background: color-mix(in srgb, #ffffff 4%, transparent);
  border-radius: var(--radius-sm);
}

.skeleton::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.05), transparent);
  animation: skeleton-shimmer 1.4s infinite;
}

@keyframes skeleton-shimmer {
  from { transform: translateX(-100%); }
  to { transform: translateX(100%); }
}

.skeleton-card {
  height: 150px;
  border: 1px solid var(--border-card);
  border-radius: var(--radius-md);
}

.skeleton-line {
  height: 14px;
  margin-bottom: 0.6rem;
}

.skeleton-chip {
  display: inline-block;
  width: 200px;
  height: 28px;
  border-radius: 999px;
}

.storage-note {
  margin: 0;
  font-size: 0.85rem;
}

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