/* ==========================================================================
   saygex-ai theme: design tokens + a few app components
   --------------------------------------------------------------------------
   Load AFTER bootstrap.min.css (Bootstrap 5.3.x):

     <html lang="en" data-bs-theme="dark">
     <link rel="stylesheet" href=".../bootstrap.min.css">
     <link rel="stylesheet" href="/assets/css/theme.css">

   - Dark is the default (decisions.md, Visual design 1). Put
     data-bs-theme="dark" on <html>; switch to "light" from Settings.
   - Bootstrap's own variables (--bs-*) are overridden per color mode.
     Our own tokens use the --sx-* prefix.
   - Bootstrap 5.3.3 hard-codes its blue (#0d6efd / #86b7fe) in some
     component rules (form focus, checks, range, dropdown/list active...).
     Section 4 re-points those at our primary so no blue leaks through.
   - Contrast ratios (WCAG 2.x) are noted next to each color. AA needs
     4.5:1 for body text, 3:1 for large text and UI parts (borders, dots).
   ========================================================================== */


/* --------------------------------------------------------------------------
   1. Font: Inter, self-hosted
   --------------------------------------------------------------------------
   TODO(Frontend): download Inter v4 (https://rsms.me/inter/, "Inter Variable"
   web fonts) and put these two files in web/assets/fonts/:
     - InterVariable.woff2
     - InterVariable-Italic.woff2
   Until then the system font stack below is used (nothing breaks).
   Licence: SIL Open Font License 1.1, so ship the OFL.txt next to the files.
   -------------------------------------------------------------------------- */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("../fonts/InterVariable.woff2") format("woff2");
}
@font-face {
  font-family: "Inter";
  font-style: italic;
  font-weight: 100 900;
  font-display: swap;
  src: url("../fonts/InterVariable-Italic.woff2") format("woff2");
}


/* --------------------------------------------------------------------------
   2. Tokens shared by both modes
   -------------------------------------------------------------------------- */
:root {
  --bs-font-sans-serif: "Inter", system-ui, -apple-system, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
  --bs-body-font-family: var(--bs-font-sans-serif);
  --bs-body-font-size: 0.9375rem;   /* 15px: dense, app-like */
  --bs-body-line-height: 1.45;

  --bs-border-radius: 0.5rem;
  --bs-border-radius-sm: 0.375rem;
  --bs-border-radius-lg: 0.75rem;
  --bs-border-radius-xl: 1rem;
  --bs-border-radius-pill: 50rem;

  /* Grid tiles (decisions.md, Visual design 4) */
  --sx-grid-gap: 3px;
  --sx-tile-radius: 0.5rem;
  --sx-tile-scrim: linear-gradient(to top, rgba(0, 0, 0, .82) 0%, rgba(0, 0, 0, .45) 45%, rgba(0, 0, 0, 0) 100%);

  /* Chat */
  --sx-bubble-radius: 1.125rem;
}


/* --------------------------------------------------------------------------
   3a. Dark mode (default)
   Contrast values are against --bs-body-bg #0f0f12 unless noted.
   -------------------------------------------------------------------------- */
[data-bs-theme="dark"] {
  color-scheme: dark;

  /* Surfaces: near-black, slightly cool */
  --bs-body-bg: #0f0f12;            --bs-body-bg-rgb: 15, 15, 18;
  --bs-secondary-bg: #17171c;       --bs-secondary-bg-rgb: 23, 23, 28;   /* raised: sheets, modals, menus */
  --bs-tertiary-bg: #1f1f26;        --bs-tertiary-bg-rgb: 31, 31, 38;    /* inputs-on-sheet, incoming bubbles, page behind phone frame */

  /* Text */
  --bs-body-color: #ececf1;         --bs-body-color-rgb: 236, 236, 241;  /* 16.3:1 (13.9:1 on tertiary) */
  --bs-emphasis-color: #ffffff;     --bs-emphasis-color-rgb: 255, 255, 255;
  --bs-heading-color: inherit;
  --bs-secondary-color: #a1a1ad;    --bs-secondary-color-rgb: 161, 161, 173; /* 7.5:1 (6.4:1 on tertiary) */
  --bs-tertiary-color: #8a8a96;     --bs-tertiary-color-rgb: 138, 138, 150;  /* 5.6:1 (4.8:1 on tertiary) */

  /* Lines */
  --bs-border-color: #2c2c35;
  --bs-border-color-translucent: rgba(255, 255, 255, .1);
  --sx-border-strong: #6b6b78;      /* input + outline-button edges: 3.6:1 (UI, needs 3:1) */

  /* Accent: soft violet = Bootstrap primary */
  --bs-primary: #a78bfa;            --bs-primary-rgb: 167, 139, 250;     /* 7.0:1 as text/links (6.0:1 on tertiary) */
  --sx-on-primary: #0f0f12;                                             /* text on primary fill: 7.0:1 */
  --sx-primary-hover: #b9a3fb;
  --sx-primary-active: #c4b5fd;
  --bs-primary-text-emphasis: #c4b5fd;
  --bs-primary-bg-subtle: #221a3a;
  --bs-primary-border-subtle: #4c3a87;
  --bs-link-color: #a78bfa;         --bs-link-color-rgb: 167, 139, 250;
  --bs-link-hover-color: #c4b5fd;   --bs-link-hover-color-rgb: 196, 181, 253;
  --bs-focus-ring-color: rgba(167, 139, 250, .45);
  --sx-focus-border: #a78bfa;

  /* Status */
  --sx-online: #22c55e;                                                 /* dot: 8.4:1 (UI, needs 3:1) */
  --bs-success: #22c55e;            --bs-success-rgb: 34, 197, 94;
  --bs-danger: #f87171;             --bs-danger-rgb: 248, 113, 113;      /* text-danger: 6.9:1. Bootstrap's #dc3545 is only 4.2:1 here. */
  /* .btn-danger keeps Bootstrap's #dc3545 fill with white text: 4.5:1 */

  /* Silhouette tile (profiles without photos) */
  --sx-silhouette-bg: #1f1f26;
  --sx-silhouette-fg: #3b3b47;

  /* Pride gradient: softened stops, all >= 6:1 on the dark surface */
  --sx-pride-stops: #ff6b6b, #ffa94d, #ffd43b, #69db7c, #4dabf7, #b197fc;
}


/* --------------------------------------------------------------------------
   3b. Light mode (option in Settings)
   Contrast values are against --bs-body-bg #ffffff unless noted.
   -------------------------------------------------------------------------- */
[data-bs-theme="light"] {
  color-scheme: light;

  --bs-body-bg: #ffffff;            --bs-body-bg-rgb: 255, 255, 255;
  --bs-secondary-bg: #f4f4f6;       --bs-secondary-bg-rgb: 244, 244, 246;
  --bs-tertiary-bg: #ebebef;        --bs-tertiary-bg-rgb: 235, 235, 239;

  --bs-body-color: #18181b;         --bs-body-color-rgb: 24, 24, 27;     /* 17.7:1 (14.9:1 on tertiary) */
  --bs-emphasis-color: #000000;     --bs-emphasis-color-rgb: 0, 0, 0;
  --bs-heading-color: inherit;
  --bs-secondary-color: #5c5c66;    --bs-secondary-color-rgb: 92, 92, 102;   /* 6.6:1 (5.6:1 on tertiary) */
  --bs-tertiary-color: #6e6e78;     --bs-tertiary-color-rgb: 110, 110, 120;  /* 5.0:1 on white only (4.2:1 on tertiary: don't use there for text) */

  --bs-border-color: #dcdce2;
  --bs-border-color-translucent: rgba(0, 0, 0, .1);
  --sx-border-strong: #8c8c96;      /* input + outline-button edges: 3.3:1 (UI, needs 3:1) */

  --bs-primary: #7c3aed;            --bs-primary-rgb: 124, 58, 237;      /* 5.7:1 as text (4.8:1 on tertiary) */
  --sx-on-primary: #ffffff;                                             /* white on primary fill: 5.7:1 */
  --sx-primary-hover: #6d28d9;                                          /* white on hover: 7.1:1 */
  --sx-primary-active: #5b21b6;
  --bs-primary-text-emphasis: #5b21b6;
  --bs-primary-bg-subtle: #ede9fe;
  --bs-primary-border-subtle: #c4b5fd;
  --bs-link-color: #7c3aed;         --bs-link-color-rgb: 124, 58, 237;
  --bs-link-hover-color: #5b21b6;   --bs-link-hover-color-rgb: 91, 33, 182;
  --bs-focus-ring-color: rgba(124, 58, 237, .3);
  --sx-focus-border: #a78bfa;

  --sx-online: #16a34a;                                                 /* dot: 3.3:1 (UI, needs 3:1) */
  --bs-success: #16a34a;            --bs-success-rgb: 22, 163, 74;
  /* danger: Bootstrap default #dc3545, 4.5:1 as text on white */

  --sx-silhouette-bg: #e4e4ea;
  --sx-silhouette-fg: #c6c6d0;

  /* Deeper stops so the gradient still reads on white (logotype: exempt from
     WCAG contrast, but keep it legible anyway) */
  --sx-pride-stops: #e03131, #f76707, #f59f00, #2f9e44, #1971c2, #7048e8;
}

/* Derived gradients (re-evaluated per mode because the stops change) */
[data-bs-theme] {
  --sx-pride: linear-gradient(90deg, var(--sx-pride-stops));
  --sx-pride-conic: conic-gradient(from 0deg, var(--sx-pride-stops), #ff6b6b);
}
[data-bs-theme="light"] {
  --sx-pride-conic: conic-gradient(from 0deg, var(--sx-pride-stops), #e03131);
}


/* --------------------------------------------------------------------------
   4. Bootstrap component overrides (point hard-coded blue at our primary)
   -------------------------------------------------------------------------- */
body {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-feature-settings: "cv11", "ss01";   /* Inter: single-storey a, open digits */
}

/* Carousels sit on photos: keep indicators/arrows white in dark mode too
   (Bootstrap 5.3 turns them black there) */
[data-bs-theme="dark"] .carousel .carousel-indicators [data-bs-target] { background-color: #fff; }
[data-bs-theme="dark"] .carousel .carousel-control-prev-icon,
[data-bs-theme="dark"] .carousel .carousel-control-next-icon { filter: none; }

/* Raised surfaces are a step lighter in dark mode */
[data-bs-theme="dark"] .modal     { --bs-modal-bg: var(--bs-secondary-bg); }
[data-bs-theme="dark"] .offcanvas { --bs-offcanvas-bg: var(--bs-secondary-bg); }
[data-bs-theme="dark"] .dropdown-menu { --bs-dropdown-bg: var(--bs-secondary-bg); }

.btn-primary {
  --bs-btn-color: var(--sx-on-primary);
  --bs-btn-bg: var(--bs-primary);
  --bs-btn-border-color: var(--bs-primary);
  --bs-btn-hover-color: var(--sx-on-primary);
  --bs-btn-hover-bg: var(--sx-primary-hover);
  --bs-btn-hover-border-color: var(--sx-primary-hover);
  --bs-btn-active-color: var(--sx-on-primary);
  --bs-btn-active-bg: var(--sx-primary-active);
  --bs-btn-active-border-color: var(--sx-primary-active);
  --bs-btn-disabled-color: var(--sx-on-primary);
  --bs-btn-disabled-bg: var(--bs-primary);
  --bs-btn-disabled-border-color: var(--bs-primary);
  --bs-btn-focus-shadow-rgb: var(--bs-primary-rgb);
}
.btn-outline-primary {
  --bs-btn-color: var(--bs-primary);
  --bs-btn-border-color: var(--bs-primary);
  --bs-btn-hover-color: var(--sx-on-primary);
  --bs-btn-hover-bg: var(--bs-primary);
  --bs-btn-hover-border-color: var(--bs-primary);
  --bs-btn-active-color: var(--sx-on-primary);
  --bs-btn-active-bg: var(--bs-primary);
  --bs-btn-active-border-color: var(--bs-primary);
  --bs-btn-disabled-color: var(--bs-primary);
  --bs-btn-disabled-border-color: var(--bs-primary);
  --bs-btn-focus-shadow-rgb: var(--bs-primary-rgb);
}
/* Neutral outline button (Filter, Reset, Cancel...). Bootstrap's #6c757d text
   is only 4.1:1 on the dark surface, so use body text + a stronger border. */
.btn-outline-secondary {
  --bs-btn-color: var(--bs-body-color);
  --bs-btn-border-color: var(--sx-border-strong);
  --bs-btn-hover-color: var(--bs-body-color);
  --bs-btn-hover-bg: var(--bs-tertiary-bg);
  --bs-btn-hover-border-color: var(--sx-border-strong);
  --bs-btn-active-color: var(--bs-body-color);
  --bs-btn-active-bg: var(--bs-tertiary-bg);
  --bs-btn-active-border-color: var(--bs-secondary-color);
  --bs-btn-disabled-color: var(--bs-secondary-color);
  --bs-btn-disabled-border-color: var(--bs-border-color);
}
/* Outline danger (Stop sharing...): use the mode's readable red for text/border */
.btn-outline-danger {
  --bs-btn-color: var(--bs-danger);
  --bs-btn-border-color: var(--bs-danger);
}
/* Muted links: Bootstrap's grey (#6c757d) is 4.1:1 on dark; use secondary text */
.link-secondary {
  color: RGBA(var(--bs-secondary-color-rgb), var(--bs-link-opacity, 1)) !important;
  text-decoration-color: RGBA(var(--bs-secondary-color-rgb), var(--bs-link-underline-opacity, 1)) !important;
}
.link-secondary:hover, .link-secondary:focus {
  color: var(--bs-body-color) !important;
  text-decoration-color: var(--bs-body-color) !important;
}
.text-bg-primary { color: var(--sx-on-primary) !important; }
.badge.text-bg-primary { --bs-badge-color: var(--sx-on-primary); }

.dropdown-menu { --bs-dropdown-link-active-bg: var(--bs-primary); --bs-dropdown-link-active-color: var(--sx-on-primary); }
.list-group    { --bs-list-group-active-bg: var(--bs-primary); --bs-list-group-active-border-color: var(--bs-primary); --bs-list-group-active-color: var(--sx-on-primary); }
.nav-pills     { --bs-nav-pills-link-active-bg: var(--bs-primary); --bs-nav-pills-link-active-color: var(--sx-on-primary); }
.pagination    { --bs-pagination-active-bg: var(--bs-primary); --bs-pagination-active-border-color: var(--bs-primary); --bs-pagination-active-color: var(--sx-on-primary); --bs-pagination-focus-box-shadow: 0 0 0 .25rem var(--bs-focus-ring-color); }
.progress, .progress-stacked { --bs-progress-bar-bg: var(--bs-primary); }
.btn-close     { --bs-btn-close-focus-shadow: 0 0 0 .25rem var(--bs-focus-ring-color); }

/* Forms: visible field edges (Bootstrap's border color is too faint for 3:1) */
.form-control,
.form-select,
.form-check-input { border-color: var(--sx-border-strong); }
.input-group-text { border-color: var(--sx-border-strong); }

/* Forms: focus */
.form-control:focus,
.form-select:focus,
.form-check-input:focus {
  border-color: var(--sx-focus-border);
  box-shadow: 0 0 0 .25rem var(--bs-focus-ring-color);
}

/* Forms: checks, radios, switches */
.form-check-input:checked,
.form-check-input[type="checkbox"]:indeterminate {
  background-color: var(--bs-primary);
  border-color: var(--bs-primary);
}
.form-switch .form-check-input:focus:not(:checked) {
  --bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23a78bfa'/%3e%3c/svg%3e");
}
/* Dark mode: draw the check/dot/knob in near-black so it contrasts with the light violet */
[data-bs-theme="dark"] .form-check-input:checked[type="checkbox"] {
  --bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%230f0f12' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e");
}
[data-bs-theme="dark"] .form-check-input:checked[type="radio"] {
  --bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%230f0f12'/%3e%3c/svg%3e");
}
[data-bs-theme="dark"] .form-switch .form-check-input:checked {
  --bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%230f0f12'/%3e%3c/svg%3e");
}

/* Forms: range */
.form-range::-webkit-slider-thumb { background-color: var(--bs-primary); }
.form-range::-moz-range-thumb     { background-color: var(--bs-primary); }
.form-range::-webkit-slider-thumb:active { background-color: var(--sx-primary-active); }
.form-range::-moz-range-thumb:active     { background-color: var(--sx-primary-active); }
.form-range:focus::-webkit-slider-thumb  { box-shadow: 0 0 0 1px var(--bs-body-bg), 0 0 0 .25rem var(--bs-focus-ring-color); }
.form-range:focus::-moz-range-thumb      { box-shadow: 0 0 0 1px var(--bs-body-bg), 0 0 0 .25rem var(--bs-focus-ring-color); }


/* --------------------------------------------------------------------------
   5. Pride gradient utilities
   Use sparingly: logo/wordmark, empty states, loading spinner only
   (decisions.md, Visual design 2). Never on buttons, badges or body text.
   -------------------------------------------------------------------------- */
.text-pride {
  color: var(--bs-primary);                 /* fallback */
  background-image: var(--sx-pride);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
.bg-pride { background-image: var(--sx-pride) !important; }

/* Wordmark (placeholder lettering until a logo exists) */
.sx-wordmark {
  display: inline-block;        /* gradient spans the text, not the whole row */
  font-weight: 800;
  letter-spacing: -0.035em;
  line-height: 1;
}

/* Loading spinner: a pride-coloured ring.
   Usage: <span class="sx-spinner" role="status"><span class="visually-hidden">Loading</span></span> */
.sx-spinner {
  display: inline-block;
  flex-shrink: 0;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  background: var(--sx-pride-conic);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 3px));
          mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 3px));
  animation: sx-spin .9s linear infinite;
  vertical-align: middle;
}
.sx-spinner-sm { width: 1rem; height: 1rem; }
@keyframes sx-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .sx-spinner { animation-duration: 2.4s; } }

/* Empty state: pride ring around a glyph, title, copy, optional action */
.sx-empty {
  text-align: center;
  padding: 3rem 1.5rem;
  color: var(--bs-secondary-color);
}
.sx-empty-icon {
  position: relative;
  display: inline-grid;
  place-items: center;
  width: 4.5rem;
  height: 4.5rem;
  margin-bottom: 1rem;
  border-radius: 50%;
  background: var(--sx-pride-conic);
  font-size: 1.75rem;
  color: var(--bs-body-color);
}
.sx-empty-icon::before {                 /* punches the middle out to make a ring */
  content: "";
  position: absolute;
  inset: 3px;
  border-radius: 50%;
  background: var(--bs-body-bg);
}
.sx-empty-icon > * { position: relative; }
.sx-empty-title { color: var(--bs-body-color); font-weight: 600; font-size: 1.0625rem; margin-bottom: .25rem; }


/* --------------------------------------------------------------------------
   6. App components
   -------------------------------------------------------------------------- */

/* Online dot. Add .sx-online-dot-ring when it sits on a photo. */
.sx-online-dot {
  display: inline-block;
  flex-shrink: 0;
  width: .5rem;
  height: .5rem;
  border-radius: 50%;
  background: var(--sx-online);
  box-shadow: 0 0 0 2px var(--bs-body-bg);
  vertical-align: middle;
}
.sx-online-dot-ring { box-shadow: 0 0 0 2px rgba(0, 0, 0, .45); }

/* Nearby grid: 3 columns, small gaps, rounded tiles (3 columns at every width
   for now; wider layouts are not designed yet) */
.sx-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sx-grid-gap);
  padding: var(--sx-grid-gap);
}
.sx-tile {
  position: relative;
  display: block;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  border-radius: var(--sx-tile-radius);
  background-color: var(--bs-tertiary-bg);
  color: #fff;                            /* always on a photo + scrim, in both modes */
  text-decoration: none;
  isolation: isolate;
}
.sx-tile:hover { color: #fff; }
.sx-tile:focus-visible { outline: 2px solid var(--bs-primary); outline-offset: 2px; }
.sx-tile > img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sx-tile::after {                         /* bottom scrim for name + distance */
  content: "";
  position: absolute;
  inset: 45% 0 0 0;
  background: var(--sx-tile-scrim);
  z-index: 1;
  pointer-events: none;
}
.sx-tile-meta {
  position: absolute;
  inset: auto 0 0 0;
  z-index: 2;
  padding: 0 .375rem .3rem;
  line-height: 1.2;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .5);
}
.sx-tile-name {
  display: flex;
  align-items: center;
  gap: .3rem;
  min-width: 0;
  font-size: .8125rem;
  font-weight: 600;
}
.sx-tile-name > .sx-tile-name-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sx-tile-dist { display: block; font-size: .75rem; color: rgba(255, 255, 255, .85); }
.sx-tile-fav {
  position: absolute;
  top: .25rem;
  right: .375rem;
  z-index: 2;
  font-size: .875rem;
  color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .6);
}

/* Profile without photos: generic silhouette (mask, so it follows the theme) */
.sx-tile-silhouette { background-color: var(--sx-silhouette-bg); }
.sx-silhouette,
.sx-tile-silhouette::before {
  background-color: var(--sx-silhouette-fg);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ccircle cx='50' cy='38' r='18'/%3E%3Cpath d='M14 100c0-22 16-36 36-36s36 14 36 36z'/%3E%3C/svg%3E") center bottom / 78% no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ccircle cx='50' cy='38' r='18'/%3E%3Cpath d='M14 100c0-22 16-36 36-36s36 14 36 36z'/%3E%3C/svg%3E") center bottom / 78% no-repeat;
}
.sx-tile-silhouette::before { content: ""; position: absolute; inset: 0; }

/* Bottom tab bar (decisions.md, Visual design 7): three icon-only tabs,
   Favorites / Grid / Chats, using Bootstrap Icons. No visible labels:
   every tab needs title="..." (hover tooltip) and aria-label="...".
   Active tab: class .active + aria-current="page" + the "-fill" icon variant.

   <nav class="sx-tabbar" aria-label="Main">
     <a href="..." title="Favorites" aria-label="Favorites"><span class="sx-tab-icon"><i class="bi bi-star" aria-hidden="true"></i></span></a>
     <a href="..." class="active" aria-current="page" title="Grid" aria-label="Grid"><span class="sx-tab-icon"><i class="bi bi-grid-3x3-gap-fill" aria-hidden="true"></i></span></a>
     <a href="..." title="Chats" aria-label="Chats, 3 unread"><span class="sx-tab-icon"><i class="bi bi-chat-dots" aria-hidden="true"></i><span class="badge rounded-pill text-bg-primary">3</span></span></a>
   </nav> */
.sx-tabbar {
  display: flex;
  flex-shrink: 0;
  border-top: 1px solid var(--bs-border-color);
  background: var(--bs-body-bg);
  padding-bottom: env(safe-area-inset-bottom);
}
.sx-tabbar a {
  flex: 1 1 0;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 3.25rem;                   /* >= 44px touch target */
  color: var(--bs-secondary-color);      /* inactive icon: 7.5:1 dark / 6.6:1 light */
  text-decoration: none;
}
.sx-tabbar a:hover { color: var(--bs-body-color); }
.sx-tabbar a.active { color: var(--bs-primary); }
.sx-tabbar a:focus-visible { outline: 2px solid var(--bs-primary); outline-offset: -4px; border-radius: .5rem; }
.sx-tab-icon { position: relative; font-size: 1.5rem; line-height: 1; }
.sx-tab-icon .badge {
  position: absolute;
  top: -.35rem;
  left: 100%;
  margin-left: -.55rem;
  font-size: .625rem;
  padding: .25em .45em;
  box-shadow: 0 0 0 2px var(--bs-body-bg);
}

/* "Me" avatar, top right of every signed-in screen: the user's main photo,
   or the Bootstrap Icons person-circle when there is no photo.
   Opens the Me area (profile edit + settings). Add .active inside that area.

   <a class="sx-me" href="..." title="Me" aria-label="Me: profile and settings"><img src="..." alt=""></a>
   <a class="sx-me" href="..." title="Me" aria-label="Me: profile and settings"><i class="bi bi-person-circle" aria-hidden="true"></i></a> */
.sx-me {
  display: inline-grid;
  place-items: center;
  flex-shrink: 0;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  overflow: hidden;
  background: var(--bs-tertiary-bg);
  color: var(--bs-secondary-color);
  text-decoration: none;
}
.sx-me > img { width: 100%; height: 100%; object-fit: cover; }
.sx-me > .bi { font-size: 2rem; line-height: 1; }
.sx-me:hover { color: var(--bs-body-color); }
.sx-me.active { box-shadow: 0 0 0 2px var(--bs-body-bg), 0 0 0 4px var(--bs-primary); overflow: visible; }
.sx-me.active > img { border-radius: 50%; }
.sx-me:focus-visible { outline: 2px solid var(--bs-primary); outline-offset: 2px; }

/* Chat bubbles */
.sx-bubble {
  max-width: 78%;
  padding: .5rem .8rem;
  border-radius: var(--sx-bubble-radius);
  overflow-wrap: anywhere;
}
.sx-bubble-in  { align-self: flex-start; background: var(--bs-tertiary-bg); color: var(--bs-body-color); border-bottom-left-radius: .375rem; }
.sx-bubble-out { align-self: flex-end;   background: var(--bs-primary);     color: var(--sx-on-primary); border-bottom-right-radius: .375rem; }
.sx-bubble-media { padding: .25rem; }
