/* ==========================================================================
   URL Shortener — design system
   A distinct, premium look for the public/customer-facing pages (Home,
   Pricing, About Us, Contact Us, Login, Register, and the signed-in
   customer workspace), layered on top of Bootstrap 5. Internal admin CRUD
   tables inherit the same buttons/cards/forms automatically, so quality
   stays consistent everywhere without a second design language to maintain.
   ========================================================================== */

:root {
  --brand-50:  #eef2ff;
  --brand-100: #e0e7ff;
  --brand-500: #6366f1;
  --brand-600: #4f46e5;
  --brand-700: #4338ca;
  --brand-900: #312e81;

  --accent-500: #06b6d4;
  --accent-600: #0891b2;

  --danger-500: #ef4444;
  --success-500: #059669;
  --success-600: #047857;

  --ink-900: #0f172a;
  --ink-700: #334155;
  --ink-500: #64748b;
  --ink-300: #cbd5e1;
  --ink-100: #f1f5f9;
  --ink-50:  #f8fafc;

  --gradient-brand: linear-gradient(135deg, var(--brand-600) 0%, var(--brand-500) 45%, var(--accent-500) 100%);
  --gradient-soft:  linear-gradient(180deg, var(--brand-50) 0%, #ffffff 55%);

  --shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.06), 0 1px 1px rgba(15, 23, 42, 0.04);
  --shadow-md: 0 8px 24px rgba(15, 23, 42, 0.08), 0 2px 6px rgba(15, 23, 42, 0.05);
  --shadow-lg: 0 24px 48px -12px rgba(49, 46, 129, 0.25);

  --radius-md: 0.75rem;
  --radius-lg: 1.25rem;
  --radius-pill: 999px;
}

html { font-size: 15px; }
@media (min-width: 768px) { html { font-size: 16px; } }

html, body { height: 100%; }
html {
  /* Defensive backstop: no single element (a wide table, a long unbroken code string, a
     mispositioned fixed element) should ever be able to force the whole page to scroll
     sideways — everything that legitimately needs its own horizontal scroll (tables, the
     analytics heatmap/trend charts, code blocks) already scrolls inside its own container. */
  overflow-x: hidden;
}
body {
  font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  color: var(--ink-900);
  background: var(--ink-50);
  -webkit-font-smoothing: antialiased;
  max-width: 100vw;
  overflow-x: hidden;
}
img, svg, table { max-width: 100%; }
pre, code { overflow-x: auto; }

h1, h2, h3, h4, h5, h6 { font-weight: 700; letter-spacing: -0.01em; }

a { color: var(--brand-600); text-decoration: none; }
a:hover { color: var(--brand-700); }

.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
  box-shadow: 0 0 0 0.15rem #fff, 0 0 0 0.3rem var(--brand-500);
}

/* ---- Buttons ---------------------------------------------------------- */
.btn { font-weight: 600; border-radius: var(--radius-pill); padding: 0.55rem 1.35rem; transition: transform .15s ease, box-shadow .15s ease, filter .15s ease; }
.btn-sm { border-radius: var(--radius-pill); }
.btn-primary {
  background: var(--gradient-brand);
  border: none;
  box-shadow: var(--shadow-sm);
}
.btn-primary:hover { filter: brightness(1.08); transform: translateY(-1px); box-shadow: var(--shadow-md); }
.btn-outline-primary { border-color: var(--brand-500); color: var(--brand-600); }
.btn-outline-primary:hover { background: var(--brand-500); border-color: var(--brand-500); transform: translateY(-1px); }
.btn-outline-secondary:hover { transform: translateY(-1px); }
.btn-lg { padding: 0.85rem 1.9rem; font-size: 1.05rem; }

/* ---- Cards ------------------------------------------------------------- */
.card {
  border: 1px solid rgba(15, 23, 42, 0.06);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  transition: box-shadow .2s ease, transform .2s ease;
}
.card.card-hover:hover, .pricing-card:hover { box-shadow: var(--shadow-md); transform: translateY(-3px); }
.card-header { background: transparent; border-bottom: 1px solid rgba(15, 23, 42, 0.06); font-weight: 600; }

/* ---- Public navbar ------------------------------------------------------ */
.navbar-public {
  background: rgba(255, 255, 255, 0.85);
  backdrop-filter: saturate(180%) blur(12px);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid rgba(15, 23, 42, 0.06);
  box-shadow: 0 1px 0 rgba(15, 23, 42, 0.03);
  padding-top: 0.6rem;
  padding-bottom: 0.6rem;
}
.navbar-public .navbar-brand {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-weight: 800;
  font-size: 1.25rem;
  background: var(--gradient-brand);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  white-space: nowrap;
}
.navbar-public .nav-link {
  color: var(--ink-700) !important;
  font-weight: 600;
  position: relative;
  margin: 0 0.15rem;
  white-space: nowrap;
}
.navbar-public .nav-link::after {
  content: "";
  position: absolute;
  left: 0.75rem; right: 0.75rem; bottom: 0.2rem;
  height: 2px;
  background: var(--gradient-brand);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .2s ease;
}
.navbar-public .nav-link:hover::after,
.navbar-public .nav-link.active::after { transform: scaleX(1); }
.navbar-public .dropdown-menu {
  border: none;
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  padding: 0.5rem;
}
.navbar-public .dropdown-item { border-radius: 0.5rem; font-weight: 500; padding: 0.5rem 0.75rem; }
.navbar-public .dropdown-item:hover { background: var(--brand-50); color: var(--brand-700); }
.navbar-public .navbar-text, .navbar-public .btn-outline-light {
  color: var(--ink-700) !important;
  border-color: var(--ink-300) !important;
}
.navbar-public .btn-outline-light:hover { background: var(--ink-100); }

/* Round initial-letter avatar for the signed-in account menu — reads better than a bare
   dropdown arrow next to an email address, and stays a fixed compact size regardless of how
   long the account's name/email is (the name itself only shows on extra-wide screens). */
.navbar-avatar {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.9rem; height: 1.9rem; flex: none;
  border-radius: 50%;
  background: var(--gradient-brand);
  color: #fff; font-weight: 700; font-size: 0.85rem;
}

/* Notification Center bell dropdown — capped width/height with its own scrollbar so a handful of
   long messages can never blow the dropdown (or the page) out past the viewport. */
.notif-dropdown-menu {
  width: 320px;
  max-width: 90vw;
  max-height: 380px;
  overflow-y: auto;
}
.notif-dropdown-menu .dropdown-item { white-space: normal; }

/* The toggler + language switcher shown next to the brand on small screens, so language never
   requires opening the hamburger first — the desktop-only language item further down hides
   itself via d-none/d-lg-block instead. */
.navbar-compact-controls .nav-link { color: var(--ink-700) !important; font-size: 1.1rem; }
.navbar-toggler { border: none; padding: 0.3rem 0.5rem; }
.navbar-toggler:focus { box-shadow: 0 0 0 0.15rem var(--brand-100); }

/* Every nav-item wraps onto its own line instead of forcing the page wider than the viewport —
   the previous single-row layout with justify-content-between had no such safety valve, which
   is what let the bar overflow horizontally once enough links/dropdowns were added. */
.navbar-public .navbar-nav { flex-wrap: wrap; }

@media (max-width: 991.98px) {
  .navbar-public .navbar-collapse {
    margin-top: 0.75rem;
    padding: 0.75rem;
    background: #fff;
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    border: 1px solid rgba(15, 23, 42, 0.06);
  }
  .navbar-public .navbar-nav { gap: 0.15rem; }
  .navbar-public .dropdown-menu { box-shadow: none; padding-inline-start: 0.75rem; }
}

/* ---- Hero / marketing sections ----------------------------------------- */
.hero-section {
  background: var(--gradient-soft);
  border-radius: var(--radius-lg);
  padding: 4rem 1.5rem;
  position: relative;
  overflow: hidden;
}
.hero-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  background: var(--brand-100);
  color: var(--brand-700);
  font-weight: 700;
  font-size: 0.85rem;
  padding: 0.35rem 0.9rem;
  border-radius: var(--radius-pill);
}
.hero-title {
  font-size: clamp(2.2rem, 5vw, 3.5rem);
  font-weight: 800;
  line-height: 1.1;
  background: var(--gradient-brand);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.feature-card {
  border-radius: var(--radius-lg);
  padding: 1.75rem;
  height: 100%;
  background: #fff;
  border: 1px solid rgba(15, 23, 42, 0.06);
  box-shadow: var(--shadow-sm);
  transition: transform .2s ease, box-shadow .2s ease;
}
.feature-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); }
.feature-icon {
  width: 3rem; height: 3rem;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--radius-md);
  background: var(--gradient-brand);
  font-size: 1.4rem;
  margin-bottom: 1rem;
}

/* ---- Homepage "try it now" demo box + real-usage stats strip (August 2026
   competitive-parity round) — this is now the ONLY styling for these classes: guests and
   signed-in users see the exact same light card (the guest-only dark override that used to
   live further below has been removed — see the "Public marketing site — light theme" note
   near the end of this file). */
.try-it-card {
  border-radius: var(--radius-lg);
  padding: 2rem;
  background: #fff;
  border: 1px solid rgba(15, 23, 42, 0.06);
  box-shadow: var(--shadow-sm);
}
.try-it-result { border-top: 1px dashed rgba(15, 23, 42, 0.12); padding-top: 1rem; }
.stats-strip {
  border-radius: var(--radius-lg);
  padding: 2rem 1rem;
  background: var(--gradient-soft);
}
.stats-value { font-size: clamp(1.8rem, 4vw, 2.4rem); font-weight: 800; color: var(--brand-700); }
.stats-label { font-size: 0.85rem; color: var(--ink-500); font-weight: 600; }

/* ---- Home page: hero mock dashboard card (August 2026 light-theme pass) ----
   These classes previously existed ONLY inside the old body.site-public dark
   override further below (now removed) — meaning on the rare path where this
   same Home page renders inside the signed-in app shell, they were silently
   unstyled. Promoting them to real base rules here fixes that gap and gives
   the guest-facing light theme its styling in one place, shared by both. */
.hero-mock-card {
  background: #fff;
  border: 1px solid rgba(15, 23, 42, 0.08);
  border-radius: var(--radius-lg);
  padding: 1.35rem;
  box-shadow: var(--shadow-lg);
}
.hero-mock-url-bar {
  display: flex; align-items: center; gap: 0.6rem;
  background: var(--ink-50); border: 1px solid rgba(15, 23, 42, 0.06);
  border-radius: var(--radius-md); padding: 0.65rem 0.9rem;
  font-size: 0.85rem; color: var(--ink-500); margin-bottom: 1rem;
}
.hero-mock-url-result { margin-inline-start: auto; color: var(--brand-600); font-weight: 700; }
.hero-mock-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.6rem; margin-bottom: 1rem; }
.hero-mock-stat { background: var(--ink-50); border: 1px solid rgba(15, 23, 42, 0.06); border-radius: var(--radius-md); padding: 0.75rem 0.9rem; }
.hero-mock-stat-label { font-size: 0.68rem; color: var(--ink-500); font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; }
.hero-mock-stat-value { font-size: 1.3rem; font-weight: 800; color: var(--ink-900); margin-top: 0.2rem; }
.hero-mock-stat-value.is-success { color: var(--success-500); }
.hero-mock-caption { font-size: 0.72rem; color: var(--ink-500); text-align: end; margin-top: 0.25rem; }

/* ---- Home page: "how it works" step numbers ---- */
.how-step-number { font-size: 0.85rem; font-weight: 800; color: var(--brand-500); }
.how-step-number + h3 { color: var(--ink-900); }

/* ---- Home page: closing CTA band — deliberately stays a bold, fully-colored
   band even on the light theme (the way Stripe/Linear keep one saturated CTA
   near the bottom of an otherwise light page) so it still reads as the page's
   strongest visual pull. Everything above it on the page is light/white. ---- */
.cta-band {
  background: var(--gradient-brand);
  border-radius: 1.25rem;
  padding: 3.5rem 2rem;
  text-align: center;
  position: relative;
  overflow: hidden;
  color: #fff;
}
.cta-band::before {
  content: ""; position: absolute; top: -8rem; left: 50%; transform: translateX(-50%);
  width: 34rem; height: 20rem;
  background: radial-gradient(closest-side, rgba(255, 255, 255, 0.25), transparent 70%);
  filter: blur(10px); pointer-events: none;
}
.cta-band h2 { color: #fff; position: relative; }
.cta-band p, .cta-band .text-muted { color: rgba(255, 255, 255, 0.88) !important; position: relative; }
.cta-band .btn-primary { background: #fff; color: var(--brand-700); box-shadow: var(--shadow-md); }
.cta-band .btn-primary:hover { background: var(--ink-50); color: var(--brand-700); }

/* ---- Home page: analytics/conversion-tracking highlight section ---- */
.conv-highlight-card {
  background: var(--gradient-soft);
  border: 1px solid var(--brand-100);
  border-radius: 1.25rem;
  padding: 3rem;
  position: relative;
  overflow: hidden;
}
.conv-highlight-card::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 2px;
  background: var(--gradient-brand);
}
.conv-highlight-eyebrow { background: #fff; border: 1px solid var(--accent-500); color: var(--accent-600); }
.conv-code-snippet {
  background: var(--ink-900); border-radius: 0.75rem;
  padding: 1rem 1.1rem; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.82rem; color: #a5f3fc; overflow-x: auto;
}
.conv-funnel-card { background: #fff; border: 1px solid rgba(15, 23, 42, 0.08); border-radius: 1.25rem; padding: 1.75rem; box-shadow: var(--shadow-md); }
.conv-funnel-row { margin-bottom: 0.9rem; }
.conv-funnel-row:last-child { margin-bottom: 0; }
.conv-funnel-label { display: flex; justify-content: space-between; font-size: 0.85rem; margin-bottom: 0.35rem; color: var(--ink-900); font-weight: 600; }
.conv-funnel-track { height: 12px; border-radius: 999px; background: var(--ink-100); overflow: hidden; }
.conv-funnel-fill { height: 100%; background: var(--gradient-brand); }
.conv-funnel-fill.is-success { background: var(--success-500); }

/* ---- Features page (Home/Features.cshtml): alternating feature rows ---- */
.feat-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2rem;
  align-items: center;
  padding: 3rem 0;
  border-bottom: 1px solid rgba(15, 23, 42, 0.08);
}
.feat-row:last-of-type { border-bottom: none; }
@media (min-width: 992px) {
  .feat-row { grid-template-columns: 1fr 1fr; gap: 3.5rem; }
  .feat-row.feat-row-reverse > *:first-child { order: 2; }
  .feat-row.feat-row-reverse > *:last-child { order: 1; }
}
.feat-icon-badge {
  width: 2.9rem; height: 2.9rem;
  display: flex; align-items: center; justify-content: center;
  border-radius: 0.75rem;
  background: var(--brand-50);
  font-size: 1.3rem;
  margin-bottom: 1rem;
}
.feat-row h2 { color: var(--ink-900); }
.feat-check-row { display: flex; align-items: flex-start; gap: 0.6rem; margin-top: 0.6rem; color: var(--ink-700); }
.feat-check-row .pricing-check { margin-top: 0.15rem; }
.feat-visual-card {
  background: #fff;
  border: 1px solid rgba(15, 23, 42, 0.08);
  border-radius: 1.25rem;
  padding: 1.75rem;
  color: var(--ink-700);
  box-shadow: var(--shadow-md);
}

/* ---- Pricing FAQ ---- */
.faq-item { padding: 1.35rem 0; border-bottom: 1px solid rgba(15, 23, 42, 0.08); }
.faq-item:last-child { border-bottom: none; }
.faq-item > div:first-child { color: var(--ink-900); }

/* ---- Pricing ------------------------------------------------------------ */
.pricing-card {
  border-radius: var(--radius-lg);
  position: relative;
  overflow: visible;
}
.pricing-card.pricing-featured {
  border: 2px solid var(--brand-500);
  box-shadow: var(--shadow-lg);
}
.pricing-badge {
  position: absolute;
  top: -0.85rem; left: 50%;
  transform: translateX(-50%);
  background: var(--gradient-brand);
  color: #fff;
  font-size: 0.75rem;
  font-weight: 700;
  padding: 0.35rem 1rem;
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-sm);
  white-space: nowrap;
}
.pricing-price { font-size: 2.5rem; font-weight: 800; }
.pricing-check { color: var(--accent-600); font-weight: 700; margin-right: 0.4rem; }
.pricing-x { color: var(--danger-500); font-weight: 700; margin-right: 0.4rem; opacity: 0.85; }
.pricing-feature-excluded { opacity: 0.7; }

/* ---- Flash discounts (Pricing + Subscribe) ------------------------------- */
.pricing-card.pricing-discounted {
  border: 2px solid var(--danger-500);
  animation: discount-card-glow 2.4s ease-in-out infinite;
}
@keyframes discount-card-glow {
  0%, 100% { box-shadow: 0 0 0 4px rgba(239, 68, 68, 0.10), var(--shadow-lg); }
  50%      { box-shadow: 0 0 0 9px rgba(239, 68, 68, 0.22), var(--shadow-lg); }
}
.discount-ribbon {
  position: absolute;
  top: -0.85rem; left: 50%;
  transform: translateX(-50%);
  background: linear-gradient(135deg, #ef4444, #f97316);
  color: #fff;
  font-size: 0.75rem;
  font-weight: 800;
  padding: 0.4rem 1.1rem;
  border-radius: var(--radius-pill);
  box-shadow: 0 4px 14px rgba(239, 68, 68, 0.45);
  white-space: nowrap;
  animation: discount-pulse 1.6s ease-in-out infinite;
  z-index: 2;
}
@keyframes discount-pulse {
  0%, 100% { transform: translateX(-50%) scale(1); }
  50%      { transform: translateX(-50%) scale(1.08); }
}
.pricing-price-was { font-size: 1.15rem; color: var(--ink-500); text-decoration: line-through; font-weight: 600; }
.pricing-price-discounted { color: var(--danger-500); }
.discount-countdown {
  display: inline-flex; align-items: center; gap: 0.4rem;
  background: rgba(239, 68, 68, 0.08);
  border: 1px solid rgba(239, 68, 68, 0.25);
  color: #b91c1c;
  font-weight: 700;
  font-size: 0.85rem;
  padding: 0.3rem 0.7rem;
  border-radius: var(--radius-pill);
}
.discount-countdown-label { font-weight: 500; opacity: 0.85; }
.discount-countdown-value { font-variant-numeric: tabular-nums; }
.discount-countdown-ended { opacity: 0.6; }
/* Three staggered floating money emoji, purely decorative — the "eye-catching" flourish on a
   discounted card. Absolutely positioned within .pricing-card (position: relative already), each
   with its own start position + animation-delay so they don't all rise in lockstep. */
.discount-money-fly {
  position: absolute;
  font-size: 1.3rem;
  opacity: 0;
  pointer-events: none;
  animation: discount-money-float 3.2s ease-in infinite;
  z-index: 1;
}
.discount-money-fly-1 { left: 12%; bottom: 8%;  animation-delay: 0s; }
.discount-money-fly-2 { left: 50%; bottom: 4%;  animation-delay: 1.1s; }
.discount-money-fly-3 { left: 82%; bottom: 12%; animation-delay: 2.1s; }
@keyframes discount-money-float {
  0%   { opacity: 0; transform: translateY(0) rotate(0deg); }
  15%  { opacity: 1; }
  85%  { opacity: 1; }
  100% { opacity: 0; transform: translateY(-140px) rotate(20deg); }
}
@media (prefers-reduced-motion: reduce) {
  .pricing-card.pricing-discounted, .discount-ribbon, .discount-money-fly { animation: none; }
}

/* ---- Auth cards (Login/Register) ---------------------------------------- */
.auth-shell {
  min-height: 100vh;
  display: flex; align-items: center; justify-content: center;
  background: var(--gradient-soft);
  padding: 1.5rem;
}
.auth-card {
  width: 100%; max-width: 420px;
  background: #fff;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: 2.25rem;
  border-top: 4px solid transparent;
  border-image: var(--gradient-brand) 1;
}
.auth-brand {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-weight: 800;
  font-size: 1.4rem;
  background: var(--gradient-brand);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* ---- Contact / About icon rows ------------------------------------------ */
.contact-row {
  display: flex; align-items: center; gap: 1rem;
  padding: 1rem 1.25rem;
  border-radius: var(--radius-md);
  background: #fff;
  border: 1px solid rgba(15, 23, 42, 0.06);
  box-shadow: var(--shadow-sm);
  margin-bottom: 0.85rem;
}
.contact-icon {
  width: 2.75rem; height: 2.75rem; flex: none;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: var(--brand-50);
  font-size: 1.2rem;
}

/* ---- Subscription status / usage ---------------------------------------- */
.status-card {
  border-top: 4px solid transparent;
  border-image: var(--gradient-brand) 1;
}
.usage-tile {
  background: var(--ink-50);
  border-radius: var(--radius-md);
  padding: 1.25rem;
  height: 100%;
}
.usage-tile-label {
  color: var(--ink-500);
  font-weight: 700;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  margin-bottom: 0.4rem;
}
.usage-tile-value { font-size: 1.9rem; font-weight: 800; color: var(--ink-900); margin-bottom: 0.6rem; }
.usage-tile-value .usage-tile-limit { font-size: 1rem; font-weight: 600; color: var(--ink-500); }
.progress { border-radius: var(--radius-pill); background: var(--ink-100); }

/* ---- Analytics: ranked bar-lists (Country/City/Device/OS/Browser/Referrer) ---------------- */
/* Single sequential hue (brand) — these are magnitude rankings of one metric (click count),
   never multiple comparable series, so the categorical palette doesn't apply here. */
.bar-list { display: flex; flex-direction: column; gap: 0.6rem; }
.bar-list-row { display: grid; grid-template-columns: 7rem 1fr 2.25rem; align-items: center; gap: 0.6rem; }
.bar-list-label {
  font-size: 0.85rem; font-weight: 600; color: var(--ink-700);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.bar-list-track { height: 10px; border-radius: var(--radius-pill); background: var(--ink-100); overflow: hidden; }
.bar-list-fill { height: 100%; border-radius: var(--radius-pill); background: var(--gradient-brand); }
.bar-list-count { font-size: 0.85rem; font-weight: 700; color: var(--ink-900); text-align: right; }

/* ---- Analytics: clicks-over-time trend chart ------------------------------------------------ */
.trend-chart-scroll { overflow-x: auto; padding-bottom: 0.25rem; }
.trend-chart-bars {
  display: flex; align-items: flex-end; gap: 3px;
  height: 160px;
  min-width: max-content;
  border-bottom: 1px solid var(--ink-300);
}
.trend-bar-col { display: flex; flex-direction: column; align-items: center; justify-content: flex-end; height: 100%; width: 14px; flex: none; }
.trend-bar {
  width: 100%; max-width: 20px;
  background: var(--brand-500);
  border-radius: 4px 4px 0 0;
  min-height: 2px; /* a real zero still shows as a hairline sliver at the baseline, not a gap */
}
.trend-chart-labels { display: flex; gap: 3px; min-width: max-content; margin-top: 0.4rem; }
.trend-chart-label {
  width: 14px; flex: none; text-align: center;
  font-size: 0.62rem; color: var(--ink-500);
  writing-mode: vertical-rl; text-orientation: mixed; height: 3.2rem;
}

/* ---- Analytics: stat tiles with a delta (Today vs yesterday, etc.) ------------------------- */
.stat-tile { background: var(--ink-50); border-radius: var(--radius-md); padding: 1.1rem 1.25rem; height: 100%; }
.stat-tile-label { color: var(--ink-500); font-weight: 700; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.03em; margin-bottom: 0.35rem; }
.stat-tile-value { font-size: 1.9rem; font-weight: 800; color: var(--ink-900); }
.stat-tile-delta { font-size: 0.85rem; font-weight: 700; margin-top: 0.25rem; }
.stat-tile-delta.up { color: #16a34a; }
.stat-tile-delta.down { color: #dc2626; }
.stat-tile-delta.flat { color: var(--ink-500); }

/* ---- Analytics: engagement split (first-time vs returning) ------------------------------- */
.engagement-bar { display: flex; height: 14px; border-radius: var(--radius-pill); overflow: hidden; background: var(--ink-100); }
.engagement-bar-segment.first-time { background: var(--brand-500); }
.engagement-bar-segment.returning { background: var(--accent-500); }
.engagement-legend { display: flex; gap: 1.25rem; margin-top: 0.6rem; font-size: 0.85rem; }
.engagement-legend-swatch { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 0.4rem; }

/* ---- Analytics: peak-time heatmap (hour x day-of-week) ------------------------------------ */
/* Sequential single hue (brand) per the dataviz skill — a heatmap IS the recommended form for
   "compare magnitude across a grid", and a single metric (click count) needs only one hue. */
.heatmap-scroll { overflow-x: auto; }
.heatmap-grid { display: grid; grid-template-columns: 2.75rem repeat(24, 1fr); gap: 2px; min-width: 640px; }
.heatmap-hour-label { font-size: 0.65rem; color: var(--ink-500); text-align: center; }
.heatmap-day-label { font-size: 0.72rem; color: var(--ink-700); font-weight: 600; display: flex; align-items: center; }
.heatmap-cell { aspect-ratio: 1 / 1; border-radius: 3px; min-width: 14px; }
.heatmap-scale { display: flex; align-items: center; gap: 0.4rem; margin-top: 0.75rem; font-size: 0.75rem; color: var(--ink-500); }
.heatmap-scale-swatch { width: 14px; height: 14px; border-radius: 3px; }

/* ---- Footer -------------------------------------------------------------- */
.site-footer {
  border-top: 1px solid rgba(15, 23, 42, 0.06);
  color: var(--ink-500);
  padding: 1.5rem 0;
  margin-top: 3rem;
  font-size: 0.9rem;
  text-align: center;
}

/* ---- Richer public footer (Product/Company/Account/Connect columns), August 2026
   competitive-parity round — only used on the guest-facing footer, not the signed-in shell's
   plain copyright line. */
.site-footer-rich { text-align: start; padding-top: 2.5rem; }
.footer-heading { font-weight: 700; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 0.85rem; color: var(--ink-700); }
.footer-link-list { list-style: none; padding: 0; margin: 0; }
.footer-link-list li { margin-bottom: 0.55rem; }
.footer-link-list a { color: inherit; text-decoration: none; }
.footer-link-list a:hover { text-decoration: underline; }
.footer-social-row { display: flex; gap: 0.6rem; }
.footer-social-link {
  width: 2.2rem; height: 2.2rem;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: var(--ink-100);
  color: var(--ink-700);
  font-weight: 700;
  text-decoration: none;
  transition: background .15s ease, color .15s ease;
}
.footer-social-link:hover { background: var(--brand-500); color: #fff; }
.footer-divider { border: none; border-top: 1px solid rgba(15, 23, 42, 0.08); margin: 0 0 1rem; }

/* ---- Misc ---------------------------------------------------------------- */
.badge { font-weight: 600; border-radius: var(--radius-pill); padding: 0.4em 0.75em; }
.form-control, .form-select { border-radius: 0.6rem; border-color: var(--ink-300); padding: 0.55rem 0.85rem; }
.form-control:focus, .form-select:focus { border-color: var(--brand-500); }

/* ---- Directional "back" links ---------------------------------------------
   The arrow glyph lives in CSS (not in the localized string) so a single
   Localizer key works for both languages and the arrow itself flips with the
   reading direction — see references/marks-and-anatomy style reasoning: text
   content should never bake in a directional glyph if layout can flip. ---- */
.back-link::before { content: "\2190\00A0"; } /* ← + nbsp */
[dir="rtl"] .back-link::before { content: none; }
[dir="rtl"] .back-link::after { content: "\00A0\2192"; } /* nbsp + → */

/* ==========================================================================
   Bilingual (Arabic/English) support
   - Arabic text uses "Cairo" (loaded only when needed — see _Layout.cshtml /
     the standalone auth pages), a typeface designed for Arabic script instead
     of Inter's Latin-only design falling back to the OS default.
   - [dir="rtl"] is set on <html> by the same pages, so this block covers the
     WHOLE mirrored layout, not just flipped text — nav, hero, cards, forms,
     tables, buttons, bar-lists, and the analytics widgets added this batch.
   - Logical properties (margin-inline-*, text-align: start/end, etc.) are
     used wherever Bootstrap's own physical utilities (ms-*, me-*, text-start)
     aren't already in play, so most of the design mirrors "for free" and this
     block only needs to correct the handful of hard-coded physical spots.
   ========================================================================== */
body.lang-ar,
body.lang-ar .hero-title,
body.lang-ar h1, body.lang-ar h2, body.lang-ar h3, body.lang-ar h4, body.lang-ar h5, body.lang-ar h6 {
  font-family: "Cairo", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Tahoma, Arial, sans-serif;
}

[dir="rtl"] { text-align: right; }

/* Bootstrap's grid/flex utilities (d-flex, gap-*, justify-content-*) are already
   direction-agnostic; what needs correcting is content that assumed LTR order
   or used a physical (not logical) offset. */
[dir="rtl"] .navbar-nav { padding-right: 0; }
[dir="rtl"] .dropdown-menu-end { --bs-position: start; right: auto; left: 0; }
[dir="rtl"] .form-check { padding-right: 1.5em; padding-left: 0; }
[dir="rtl"] .form-check .form-check-input { float: right; margin-right: -1.5em; margin-left: 0; }
[dir="rtl"] .form-text, [dir="rtl"] .text-danger.small { text-align: right; }

/* Analytics bar-lists / trend chart / heatmap: the bars themselves are
   magnitude, not text, so their fill direction stays LTR (a bar always grows
   left→right regardless of page language — flipping it would make the "more"
   direction ambiguous); only the surrounding labels mirror. */
[dir="rtl"] .bar-list-row { flex-direction: row-reverse; }
[dir="rtl"] .trend-chart-scroll, [dir="rtl"] .heatmap-scroll { direction: ltr; }
[dir="rtl"] .trend-chart-scroll > *, [dir="rtl"] .heatmap-grid { direction: rtl; }
[dir="rtl"] .engagement-legend-swatch { margin-right: 0; margin-left: 0.4rem; }

[dir="rtl"] table { text-align: right; }
[dir="rtl"] .card-header, [dir="rtl"] .feature-card, [dir="rtl"] .contact-row { text-align: right; }
[dir="rtl"] .contact-row { flex-direction: row-reverse; justify-content: flex-end; }

/* ==========================================================================
   Live chat — floating customer/guest widget + admin shared inbox
   ========================================================================== */
.chat-widget-bubble {
  position: fixed; inset-inline-end: 1.5rem; bottom: 1.5rem; z-index: 1070;
  width: 56px; height: 56px; border-radius: 50%;
  background: var(--gradient-brand); border: none; color: #fff; font-size: 1.5rem;
  box-shadow: var(--shadow-lg); cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.chat-widget-dot { position: absolute; top: 4px; inset-inline-end: 4px; width: 12px; height: 12px; border-radius: 50%; background: #dc2626; border: 2px solid #fff; }
.chat-widget-panel {
  position: fixed; inset-inline-end: 1.5rem; bottom: 5.5rem; z-index: 1070;
  width: 320px; max-width: calc(100vw - 2rem); height: 440px; max-height: calc(100vh - 8rem);
  background: #fff; border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
  display: flex; flex-direction: column; overflow: hidden;
}
.chat-widget-header {
  background: var(--gradient-brand); color: #fff; padding: 0.75rem 1rem;
  display: flex; align-items: center; justify-content: space-between; font-weight: 700;
}
.chat-widget-form { padding: 1rem; overflow-y: auto; }
.chat-widget-messages { flex: 1; overflow-y: auto; padding: 0.75rem; background: var(--ink-50); }
.chat-widget-send { display: flex; gap: 0.5rem; padding: 0.6rem; border-top: 1px solid var(--ink-100); }
.chat-widget-send .form-control { flex: 1; }

/* Message bubbles — shared between the widget and the admin inbox thread. Customer messages
   align to the reading-start side, admin/support replies to the reading-end side (mirrors
   naturally under [dir="rtl"] since these use logical inset-inline-*, not left/right). */
.chat-bubble { max-width: 80%; margin-bottom: 0.5rem; padding: 0.5rem 0.75rem; border-radius: var(--radius-md); font-size: 0.88rem; }
.chat-bubble-customer { background: #fff; border: 1px solid var(--ink-100); margin-inline-end: auto; }
.chat-bubble-admin { background: var(--brand-500); color: #fff; margin-inline-start: auto; }
.chat-bubble-time { font-size: 0.68rem; opacity: 0.65; margin-top: 0.2rem; }

/* Admin shared inbox — two-pane layout */
.chat-inbox { display: flex; height: 70vh; min-height: 420px; overflow: hidden; }
.chat-inbox-list { width: 300px; flex: none; border-inline-end: 1px solid var(--ink-100); overflow-y: auto; }
.chat-conv-row { display: block; padding: 0.7rem 1rem; border-bottom: 1px solid var(--ink-100); color: inherit; }
.chat-conv-row:hover { background: var(--ink-50); }
.chat-conv-row.active { background: var(--brand-50); border-inline-start: 3px solid var(--brand-500); }
.chat-conv-preview { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chat-conv-time { font-size: 0.68rem; }
.chat-inbox-thread { flex: 1; display: flex; flex-direction: column; }
.chat-thread-header { padding: 0.75rem 1rem; border-bottom: 1px solid var(--ink-100); }
.chat-thread-messages { flex: 1; overflow-y: auto; padding: 1rem; background: var(--ink-50); }
.chat-reply-form { display: flex; gap: 0.5rem; padding: 0.75rem; border-top: 1px solid var(--ink-100); }
.chat-reply-form textarea { flex: 1; resize: none; }

@media (max-width: 640px) {
  .chat-inbox { flex-direction: column; height: auto; }
  .chat-inbox-list { width: 100%; max-height: 240px; border-inline-end: none; border-bottom: 1px solid var(--ink-100); }
}

/* Live short-URL Details page (url-details-live.js) — connection status badge, the pulsing
   dot that says "this page updates itself", the live-activity feed, and the brief highlight
   flash on a number that just changed. */
.live-badge { display: inline-flex; align-items: center; gap: 0.35rem; }
.live-badge-dot {
  width: 0.5rem; height: 0.5rem; border-radius: 50%;
  background: currentColor; display: inline-block;
  animation: live-pulse 1.6s ease-in-out infinite;
}
.live-badge-dot-header { background: #16a34a; }

@keyframes live-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.4; transform: scale(0.8); }
}

.live-activity-feed { max-height: 220px; overflow-y: auto; }
.live-activity-item { padding: 0.35rem 0; border-bottom: 1px solid var(--ink-100); }
.live-activity-item:last-child { border-bottom: none; }
.live-activity-item-new { animation: live-item-in 0.4s ease-out; background: var(--brand-50); }

@keyframes live-item-in {
  from { background: var(--brand-100); }
  to { background: var(--brand-50); }
}

.live-flash { animation: live-flash-anim 0.9s ease-out; border-radius: 0.25rem; }

@keyframes live-flash-anim {
  0% { background: var(--brand-100); }
  100% { background: transparent; }
}

@media (prefers-reduced-motion: reduce) {
  .live-badge-dot, .live-activity-item-new, .live-flash { animation: none; }
}

/* ==========================================================================
   Signed-in app shell — persistent sidebar navigation
   Replaces the public site's top dropdown menu once someone is signed in (see
   _Layout.cshtml's __isAuthenticated branch) with a real portal-style shell: a
   dark rail of every workspace/admin destination down the reading-start side,
   plus a slim top bar for language/notifications/account. Deliberately uses
   inset-inline-start (not left/right) for the rail's resting position, so it
   sits on the left for English and the right for Arabic with no [dir="rtl"]
   override needed at all — only the OFF-CANVAS TRANSFORM below (a physical
   translateX, since CSS transforms aren't direction-aware) needs one.
   ========================================================================== */
:root {
  --sidebar-width: 268px;
  --sidebar-collapsed-width: 74px;
}

.app-shell { display: flex; min-height: 100vh; }

.app-sidebar {
  width: var(--sidebar-width);
  flex: none;
  background: linear-gradient(190deg, var(--brand-900) 0%, var(--brand-700) 60%, var(--brand-600) 100%);
  position: fixed;
  inset-inline-start: 0;
  top: 0;
  height: 100vh;
  display: flex;
  flex-direction: column;
  z-index: 1030;
  box-shadow: var(--shadow-lg);
  transition: transform 0.25s ease, width 0.2s ease;
  overflow-x: hidden;
}

.app-sidebar-brand-row {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding-inline-end: 0.6rem;
}

.app-sidebar-brand {
  display: flex; align-items: center; gap: 0.6rem;
  padding: 1.35rem 1.35rem 1.1rem;
  font-weight: 800; font-size: 1.15rem;
  color: #fff !important;
  flex: 1 1 auto;
  min-width: 0;
}

/* Desktop-only persistent collapse toggle (the « / » icon button next to the brand). Distinct
   from .app-sidebar-toggle below, which is the MOBILE hamburger that opens/closes the whole
   panel as an off-canvas overlay — this one just narrows the always-visible desktop rail down
   to an icon-only strip so a wide form/table on the page can reclaim that horizontal space. */
.app-sidebar-collapse-toggle {
  flex: none;
  width: 2rem; height: 2rem;
  display: flex; align-items: center; justify-content: center;
  border: none;
  border-radius: var(--radius-md);
  background: rgba(255, 255, 255, 0.08);
  color: rgba(255, 255, 255, 0.85);
  font-size: 0.95rem;
  line-height: 1;
  cursor: pointer;
  transition: background 0.15s ease;
}
.app-sidebar-collapse-toggle:hover { background: rgba(255, 255, 255, 0.18); color: #fff; }

.app-sidebar-nav {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 0.25rem 0.85rem 1rem;
}

.app-sidebar-section-label {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.5);
  padding: 1.1rem 0.6rem 0.4rem;
}

.app-sidebar-link {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.55rem 0.6rem;
  margin-bottom: 0.1rem;
  border-radius: var(--radius-md);
  color: rgba(255, 255, 255, 0.82) !important;
  font-weight: 600;
  font-size: 0.92rem;
  white-space: nowrap;
  position: relative;
  border: none;
  background: transparent;
  width: 100%;
  text-align: start;
  transition: background 0.15s ease, color 0.15s ease;
}
.app-sidebar-link .icon { flex: none; width: 1.35rem; text-align: center; font-size: 1.02rem; }
.app-sidebar-link .badge { margin-inline-start: auto; }
.app-sidebar-link:hover { background: rgba(255, 255, 255, 0.09); color: #fff !important; }
.app-sidebar-link.active { background: rgba(255, 255, 255, 0.16); color: #fff !important; }
.app-sidebar-link.active::before {
  content: "";
  position: absolute;
  inset-inline-start: 0; top: 0.35rem; bottom: 0.35rem;
  width: 3px; border-radius: var(--radius-pill);
  background: var(--accent-500);
}
.app-sidebar-link-btn { cursor: pointer; }

.app-sidebar-footer {
  padding: 0.75rem 0.85rem 1.1rem;
  border-top: 1px solid rgba(255, 255, 255, 0.14);
}

.app-main {
  flex: 1 1 auto;
  min-width: 0;
  margin-inline-start: var(--sidebar-width);
  display: flex;
  flex-direction: column;
  transition: margin-inline-start 0.2s ease;
}

/* Collapsed desktop state — toggled on .app-shell by app-shell.js (persisted via
   localStorage so it survives full page navigations, since this is a plain CSS class on a
   server-rendered element, not JS-managed component state). Shrinks the rail to an icon-only
   strip and gives that reclaimed width back to .app-main. Link/section text stays in the markup
   (each already wrapped in <span class="label">…</span> — see _Layout.cshtml) so nothing is
   re-rendered on toggle; it's simply hidden, and every link keeps its title="" tooltip for
   discoverability while collapsed. */
.app-shell.sidebar-collapsed .app-sidebar { width: var(--sidebar-collapsed-width); }
.app-shell.sidebar-collapsed .app-main { margin-inline-start: var(--sidebar-collapsed-width); }
.app-shell.sidebar-collapsed .app-sidebar-brand .label,
.app-shell.sidebar-collapsed .app-sidebar-section-label,
.app-shell.sidebar-collapsed .app-sidebar-link .label,
.app-shell.sidebar-collapsed .app-sidebar-footer .label {
  display: none;
}
.app-shell.sidebar-collapsed .app-sidebar-brand { justify-content: center; padding-inline: 0.75rem; }
.app-shell.sidebar-collapsed .app-sidebar-link { justify-content: center; padding-inline: 0; }
.app-shell.sidebar-collapsed .app-sidebar-link .icon { width: auto; }
.app-shell.sidebar-collapsed .app-sidebar-link.active::before { inset-inline-start: 0; }
/* The icon glyph itself (« vs ») is swapped by app-shell.js on toggle, not by CSS, since the
   "correct" direction depends on both the collapsed state AND the page's dir — simpler and more
   reliable to just set the right character in script than to juggle transform/rtl overrides. */

/* Suppresses the width/margin transition for exactly one layout pass — used only when applying
   the persisted collapsed state on script load, so returning to an already-collapsed page
   doesn't visibly animate open-then-shut on every navigation. */
.app-shell.no-sidebar-transition,
.app-shell.no-sidebar-transition .app-sidebar,
.app-shell.no-sidebar-transition .app-main {
  transition: none !important;
}

.app-topbar {
  position: sticky;
  top: 0;
  z-index: 1020;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.6rem 1.25rem;
  background: rgba(255, 255, 255, 0.88);
  backdrop-filter: saturate(180%) blur(12px);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid rgba(15, 23, 42, 0.06);
}
.app-topbar .nav-link { color: var(--ink-700) !important; font-weight: 600; }
/* Bootstrap's own dropdown-menu z-index (1000) is lower than the sidebar's (1030) — on a desktop
   width narrow enough that an end-aligned menu (e.g. the 320px-wide notification list) would
   otherwise stretch back over the sidebar's column, it must still win that overlap. */
.app-topbar .dropdown-menu { z-index: 1040; }

.app-sidebar-toggle {
  display: none;
  border: none;
  background: transparent;
  font-size: 1.4rem;
  line-height: 1;
  color: var(--ink-700);
  padding: 0.25rem 0.5rem;
  border-radius: var(--radius-md);
}
.app-sidebar-toggle:hover { background: var(--ink-100); }

.app-content { flex: 1 1 auto; padding: 1.25rem; }

.app-sidebar-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 42, 0.45);
  z-index: 1025;
}

@media (max-width: 991.98px) {
  .app-sidebar { transform: translateX(-100%); }
  .app-sidebar.is-open { transform: translateX(0); }
  [dir="rtl"] .app-sidebar { transform: translateX(100%); }
  [dir="rtl"] .app-sidebar.is-open { transform: translateX(0); }

  .app-main, .app-shell.sidebar-collapsed .app-main { margin-inline-start: 0; }
  .app-sidebar-toggle { display: inline-flex; align-items: center; justify-content: center; }
  .app-sidebar-overlay.is-open { display: block; }

  /* Mobile already has its own open/close control (the hamburger above, off-canvas panel) —
     the desktop-only collapse-to-icon-rail toggle would be redundant (and the icon-only rail
     makes little sense at a width where the panel is already a full off-canvas overlay), so
     hide it here and ignore any persisted collapsed state entirely at this breakpoint. */
  .app-sidebar-collapse-toggle { display: none; }
  .app-shell.sidebar-collapsed .app-sidebar { width: var(--sidebar-width); }
  .app-shell.sidebar-collapsed .app-sidebar-brand .label,
  .app-shell.sidebar-collapsed .app-sidebar-section-label,
  .app-shell.sidebar-collapsed .app-sidebar-link .label,
  .app-shell.sidebar-collapsed .app-sidebar-footer .label {
    display: initial;
  }
  .app-shell.sidebar-collapsed .app-sidebar-brand {
    justify-content: flex-start;
    padding: 1.35rem 1.35rem 1.1rem;
  }
  .app-shell.sidebar-collapsed .app-sidebar-link {
    justify-content: flex-start;
    padding: 0.55rem 0.6rem;
  }
  .app-shell.sidebar-collapsed .app-sidebar-link .icon { width: 1.35rem; }
}

/* ==========================================================================
   QR create form — frame-style gallery + live preview panel
   (Pages/QrCodes/Index.cshtml, wwwroot/js/qr-create.js)
   ========================================================================== */
.qr-frame-gallery .qr-frame-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 0.5rem 0.75rem;
  line-height: 1.1;
}

.qr-live-preview-frame {
  border: 1px solid var(--ink-100, #e5e7eb);
  border-radius: var(--radius-md, 0.5rem);
  background: #fafafa;
  padding: 1rem;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 180px;
}

.qr-live-preview {
  width: 100%;
  max-width: 220px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.qr-live-preview svg {
  width: 100%;
  height: auto;
  display: block;
}

@media (min-width: 992px) {
  /* Keeps the preview panel visible alongside the form fields as the page scrolls, the same way
     the screenshot's own reference design (a fixed "Preview" panel beside a longer settings
     form) behaves — desktop-width only, since there's no meaningful "alongside" on narrow
     screens where the two columns stack. */
  .qr-live-preview-frame { position: sticky; top: 1rem; }
}


/* ==========================================================================
   Public marketing site — light theme (August 2026)
   Guests used to get a completely separate hardcoded dark palette here
   (body.site-public), while the exact same classes rendered in a light
   theme for signed-in users inside the app shell. By explicit request
   ("محتاج تصميم فاتح مش دارك للويب سايت") that dark override block has been
   removed entirely: guest pages now render with the SAME light design
   system already used everywhere else in the app (see the base rules above
   — hero-section, hero-eyebrow, hero-title, feature-card, pricing-card,
   auth-card, contact-row, site-footer, and the newly-promoted
   hero-mock-card/conv-highlight-card/cta-band/feat-row/faq-item rules).
   One design language, one place to maintain it, and it now matches what a
   visitor sees the moment they create an account instead of switching them
   from dark to light. The body.site-public class itself is left on <body>
   in _Layout.cshtml (harmless, and available if a guest-only tweak is ever
   needed again) — it just carries no rules of its own any more.
   ========================================================================== */
