html {
  font-size: 14px;
}

/* iOS Safari auto-zooms the whole page on focusing any input/select/textarea
   whose computed font-size resolves under 16px. Bootstrap's form controls are
   sized in rem, and with html{font-size:14px} above (chosen for a tighter,
   app-like scale) that puts every ordinary .form-control at 14px and every
   .form-control-sm at ~12px — both under the threshold. Pin them to a literal
   16px (not rem, so the html scale above can't shrink it again) so typing
   anywhere never zooms the viewport. site.css loads after bootstrap.min.css,
   so this wins over .form-control-sm's smaller size too despite equal
   selector specificity. */
.form-control,
.form-select,
textarea {
  font-size: 16px;
}

.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
  box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
}

html {
  position: relative;
  min-height: 100%;
}

/* ---------------------------------------------------------------------
   Instagram-style design tokens — dark theme. Blue accent stays the same,
   everything else flipped: near-white text, dark hairline borders, black
   page canvas with a slightly lighter dark-gray "surface" tone (--ig-bg)
   for hover states/inputs/popovers, and the same Instagram "story ring"
   gradient used on avatars that have unread stories/highlights.
   --------------------------------------------------------------------- */
:root {
    --ig-blue: #0095f6;
    --ig-blue-dark: #1877f2;
    --ig-text: #f5f5f5;
    --ig-text-secondary: #a8a8a8;
    --ig-border: #363636;
    --ig-border-light: #2a2a2a;
    --ig-bg: #1c1c1e;
    --ig-white: #000000;
    --ig-like: #ed4956;
    --ig-gradient: linear-gradient(45deg, #33daf0 0%, #3c82e6 25%, #2754dc 50%, #236ccc 75%, #1829bc 100%);
    --ig-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

/* Themed scrollbars everywhere (this app is always-dark, no light-mode toggle,
   so there's no need to branch this by color scheme like the rest of the
   dark-theme patch further down does). Firefox uses the standalone
   scrollbar-* properties; every Chromium/WebKit browser needs the
   ::-webkit-scrollbar pseudo-elements instead — browsers only ever render
   whichever one they support, so both are safe to declare everywhere. The
   universal selector is deliberate: it reaches every scrollable element (the
   page itself, dropdown menus, the DM thread, emoji/mention popovers) with
   one rule instead of hunting down each scroll container individually — the
   pseudo-elements simply don't exist on elements with nothing to scroll, so
   this doesn't add visual weight anywhere else. */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--ig-border) transparent;
}

*::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}

*::-webkit-scrollbar-track {
  background: transparent;
}

*::-webkit-scrollbar-thumb {
  background-color: var(--ig-border);
  border-radius: 999px;
  border: 2px solid transparent;
  background-clip: padding-box;
}

*::-webkit-scrollbar-thumb:hover {
  background-color: var(--ig-text-secondary);
}

body {
  background-color: var(--ig-bg);
  color: var(--ig-text);
  font-family: var(--ig-font);
}

a {
  color: var(--ig-blue-dark);
}

/* Rebrand Bootstrap's default primary button everywhere (including packaged
   ASP.NET Identity UI pages, which we don't own the markup for) so the whole
   app is on-brand without needing every page to opt into .btn-de-primary. */
.btn-primary {
  background-color: var(--ig-blue);
  border-color: var(--ig-blue);
  color: #fff;
  font-weight: 600;
}

.btn-primary:hover,
.btn-primary:focus,
.btn-primary:active {
  background-color: var(--ig-blue-dark) !important;
  border-color: var(--ig-blue-dark) !important;
  color: #fff;
}

.btn {
  border-radius: 8px;
  font-weight: 600;
}

.btn-outline-secondary {
  border-color: var(--ig-border);
  color: var(--ig-text);
}

.btn-outline-secondary:hover {
  background-color: var(--ig-bg);
  border-color: var(--ig-border);
  color: var(--ig-text);
}

/* Bottom icon nav bar, Instagram-style. This is the app's only nav — shown
   at every viewport width, not just on narrow screens, so web and mobile
   share one layout. Floats free of the phone-frame edges (inset + rounded,
   no shared border with .de-app-shell) as a small frosted-glass pill instead
   of a full-width bar flush against the screen edges. */
.de-bottom-nav {
  display: flex;
  align-items: center;
  justify-content: space-around;
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  bottom: 0.75rem;
  z-index: 1030;
  background: rgba(28, 28, 30, 0.55);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-radius: 18px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
  padding: 0.55rem 0.7rem;
}

/* Overrides .de-app-shell's width/max-width/border so the bar is inset from
   (rather than flush against) the phone-frame edges — needs the combined
   selector to win on specificity over the plain .de-app-shell rule. */
.de-bottom-nav.de-app-shell {
  width: calc(100% - 1.5rem);
  max-width: calc(var(--de-phone-width) - 8rem);
  border: none;
}

.de-bottom-nav a {
  color: var(--ig-text);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.35rem 0.7rem;
  position: relative;
}

.de-bottom-nav svg {
  width: 27px;
  height: 27px;
}

.de-bottom-nav a.active {
  color: var(--ig-text);
}

.de-bottom-nav a:not(.active) {
  color: #8e8e8e;
}

body {
    padding-bottom: 3.2rem;
}

/* Top bar, Instagram-style: create icon on the left, wordmark centered,
   activity icon on the right. Static (scrolls away with the page, unlike
   the fixed bottom nav) and hidden on identity (login/register) pages via
   _Layout.cshtml. Kept transparent/white-on-shadow so it still reads well
   sitting directly above a page's hero banner. position:relative + z-index
   is needed so it paints above the hero banner that pages with a banner
   (body.de-banner-page below) pull up underneath it. */
.de-top-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  position: relative;
  z-index: 1030;
  background: transparent;
  padding: 0.6rem 1rem;
}

/* Pages with a full-bleed hero banner pull their content wrapper up by the
   top bar's own rendered height (icon + vertical padding ≈ 2.7rem) so the
   banner slides in underneath the (still in-flow, non-fixed) top bar
   instead of sitting right below it. */
body.de-banner-page > .container-fluid {
  margin-top: -3.7rem;
}

.de-top-bar a {
  color: #fff;
  display: inline-flex;
  align-items: center;
  position: relative;
  filter: drop-shadow(0 1px 2px rgba(38, 38, 38, 0.85));
}

.de-top-bar-brand {
  font-weight: 700;
  font-size: 1.3rem;
  letter-spacing: -0.02em;
  text-decoration: none;
  color: #fff;
  filter: drop-shadow(0 1px 2px rgba(38, 38, 38, 0.85));
}

/* Phone-frame shell: caps the navbar, page content, and bottom nav to a
   single phone-like column at every viewport width (not just narrow ones),
   so the site never grows a wider "desktop" layout. Anything outside the
   column is just page background — the letterboxing that makes the phone
   frame visible on wide screens. */
:root {
  --de-phone-width: 430px;
}

body {
  background-color: #000000;
}

.de-app-shell {
  max-width: var(--de-phone-width);
  margin-left: auto;
  margin-right: auto;
}

div.de-app-shell {
  background-color: transparent;
}

/* Buttons */
.btn-de-primary {
  background-color: var(--ig-blue);
  border-color: var(--ig-blue);
  color: #fff;
}

.btn-de-primary:hover {
  background-color: var(--ig-blue-dark);
  border-color: var(--ig-blue-dark);
  color: #fff;
}

.de-btn-icon-circle {
  width: 36px;
  height: 36px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
}

/* Constrain page content to Instagram's centered feed-column width. Applied
   to the .container wrapper in _Layout.cshtml for normal (non full-bleed) pages. */
.de-feed-width {
  max-width: 630px;
}

/* Vertically centers a short list of options (e.g. the Create menu) in the
   space between the top bar and bottom nav, instead of pinning it to the
   top of an otherwise-empty page. */
.de-create-menu {
  min-height: calc(100vh - 7rem);
  display: flex;
  align-items: center;
}

/* Bootstrap's col-sm-N, col-md-N, col-lg-N, col-xl-N, and col-xxl-N widths
   key off the browser's actual viewport width, not the width of our
   phone-frame shell — so on a wide window they'd still lay out multi-column
   grids inside the narrow --de-phone-width column. Force every breakpoint
   tier back to full width so pages stack the same single-column way they
   already do on an actual narrow phone. */
[class*="col-sm-"],
[class*="col-md-"],
[class*="col-lg-"],
[class*="col-xl-"],
[class*="col-xxl-"] {
  flex: 0 0 100%;
  max-width: 100%;
}

/* Hero */
.de-hero-breakout {
  margin-left: -0.75rem;
  margin-right: -0.75rem;
}

/* Locks the whole page to the viewport (no page-level scrollbar) so the
   full-bleed map is the only thing on screen — used on the DiveSites index
   page only, via the de-no-scroll-page body class set in _Layout.cshtml.
   Overrides body's global reserved-space padding-bottom (kept for the fixed
   bottom nav on every other page) so the map's flex area extends all the
   way to the true bottom of the viewport, covering up to/underneath the
   floating (frosted-glass) bottom nav instead of stopping short of it. */
body.de-no-scroll-page {
  height: 100vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  padding-bottom: 0;
  position: relative;
}

/* position: fixed anchors to the live visual viewport, which iOS/Chrome
   mobile can visibly detach/jump during the elastic overscroll bounce
   triggered by dragging down on this page's full-bleed map (there's no
   scrollable content here to absorb the gesture). Since the body above is
   already locked to a fixed 100vh box, anchoring to that box instead via
   position: absolute keeps the nav put through the bounce, without
   touching the position: fixed every other (actually scrollable) page
   relies on to keep the nav visible while scrolling. */
body.de-no-scroll-page .de-bottom-nav {
  position: absolute;
}

/* .de-app-shell's margin-left/right: auto (for centering the phone-frame
   column on normal, non-flex pages) has a side effect here: body is now a
   flex container, and an auto margin on a flex item whose cross size is
   "auto" makes the item shrink-to-content instead of stretching — collapsing
   every de-app-shell child (top bar, container-fluid) to a sliver of its
   content width on narrow (real mobile) viewports. Giving it an explicit
   (non-auto) width via min() keeps the auto margins purely positional —
   fills the available width up to --de-phone-width, and centers within
   whatever's left over once the viewport is wider than that. */
body.de-no-scroll-page > .de-app-shell {
  width: min(100%, var(--de-phone-width));
}

/* Same "slide up underneath the transparent top bar" treatment as
   body.de-banner-page, so the full-bleed map covers up to the top bar too,
   just like the hero banners do on other pages. */
body.de-no-scroll-page > div.container-fluid {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  margin-top: -3.7rem;
}

body.de-no-scroll-page main {
  flex: 1 1 auto;
  min-height: 0;
  padding-bottom: 0 !important;
  display: flex;
  flex-direction: column;
}

/* Same "lock the page to the viewport" idea as de-no-scroll-page above, but
   for Messages/Conversation: a normal (non-transparent, non-hero) top bar,
   so no slide-under-the-top-bar treatment is needed here — only .de-dm-page
   below gets to flex-fill and only .de-dm-thread within it actually scrolls,
   so the header/composer stay static and the thread scrolls only once there
   are enough messages to need it. */
body.de-dm-conversation-page {
  height: 100vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  padding-bottom: 0;
}

body.de-dm-conversation-page > .de-app-shell {
  width: min(100%, var(--de-phone-width));
}

body.de-dm-conversation-page > div.container-fluid {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

body.de-dm-conversation-page main {
  flex: 1 1 auto;
  min-height: 0;
  padding-bottom: 0 !important;
  display: flex;
  flex-direction: column;
}

/* Full-bleed dive site browse map, filling whatever space de-no-scroll-page
   leaves above the bottom nav, with the search/filter controls floating
   over it instead of taking up page space above it. */
.de-map-fullpage {
  position: relative;
  margin-left: -0.75rem;
  margin-right: -0.75rem;
  flex: 1 1 auto;
  min-height: 400px;
}

.de-map-fullpage #browse-map {
  width: 100%;
  height: 100%;
}

/* Dims the map (tiles + pins) a touch so it reads as a backdrop rather than
   competing with the top bar and filter card floating above it. Sits above
   the whole Leaflet container but below those floating elements (z-index
   1000), and pointer-events: none so panning/zooming/clicking pins still
   works right through it. */
.de-map-fullpage::before {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.2);
  pointer-events: none;
  z-index: 900;
}

.de-map-filter-card {
    position: absolute;
    top: 1rem;
    left: 1rem;
    z-index: 1000;
    width: 187px;
    max-width: calc(100vw - 2rem);
    background: #0000009c;
    border-radius: 12px;
    border: 1px solid var(--ig-border);
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.12);
    padding: 1rem;
}

/* The map now extends up underneath the transparent top bar (see
   body.de-no-scroll-page > div.container-fluid above), so the floating
   filter card and Leaflet's own top-right zoom control need to drop below
   it instead of sitting at the map's very top edge. */
body.de-no-scroll-page .de-map-filter-card {
  top: 4.5rem;
}

body.de-no-scroll-page .leaflet-top {
  top: 3.7rem;
}

.de-hero {
  background: transparent;
  color: var(--ig-text);
  padding: 2.25rem 1rem;
}

.de-hero h1 {
  font-weight: 700;
  letter-spacing: -0.02em;
}

/* Stats */
.de-stat-card {
  background: transparent;
  border: 1px solid var(--ig-border);
  border-radius: 12px;
  box-shadow: none;
  padding: 0.85rem 0.5rem;
  text-align: center;
}

.de-stat-number {
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--ig-text);
}

/* Feature cards */
.de-feature-card {
  border: 1px solid var(--ig-border);
  border-radius: 12px;
  padding: 1.1rem;
  height: 100%;
  transition: box-shadow 0.15s ease;
}

.de-feature-card:hover {
  transform: none;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
}

.de-feature-icon {
  color: var(--ig-text);
  margin-bottom: 0.5rem;
}

/* Generic content cards (tribes, feed items) — no border or background of
   their own, so they blend into whatever page they sit on; just a subtle
   hover lift. */
.de-card {
  border: none;
  background: transparent;
  transition: box-shadow 0.15s ease;
}

.de-card:hover {
  transform: none;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.06);
}

/* Same look as .de-card but without the hover lift, for forms/static panels */
.de-panel {
  border-radius: 8px;
  border: none;
  background: transparent;
}

/* Dive conditions forecast card (Tribes/EventDetails). Unlike .de-panel this
   one is meant to stand out as its own "card" — subtle blue-tinted gradient
   plus a gradient top edge borrowed from --ig-gradient (the same one used
   for story rings) so it reads as a distinct, modern widget on the page. */
.de-weather-card {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--ig-border);
  border-radius: 16px;
  padding: 1rem 1.1rem;
  background: linear-gradient(160deg, rgba(0, 149, 246, 0.14) 0%, rgba(28, 28, 30, 0) 65%);
}

.de-weather-card::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: var(--ig-gradient);
}

/* QR code display (site QR on the landing page, buddy QR on Settings). The QR
   itself is a transparent-background SVG with its modules filled by the same
   blue gradient as --ig-gradient (see QrCodeImage.cs), so it needs a dark
   backdrop here — rather than the white card this used to be — for that
   gradient to read clearly. Ringed in the brand blue and topped with the same
   gradient used for story rings, so it still reads as a deliberate on-brand
   card rather than a plain image floating on the page. */
.de-qr-card {
  position: relative;
  display: inline-block;
  overflow: hidden;
  border-radius: 20px;
  padding: 1rem;
  background: transparent;
  box-shadow: 0 0 0 3px var(--ig-blue), 0 10px 28px rgba(0, 0, 0, 0.45);
}

.de-qr-card::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 5px;
  background: var(--ig-gradient);
}

.de-qr-card img {
  display: block;
  border-radius: 6px;
}

.de-weather-header {
  display: flex;
  align-items: center;
  gap: 0.7rem;
}

.de-weather-header-icon {
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 149, 246, 0.16);
  color: var(--ig-blue);
}

.de-weather-title {
  font-weight: 700;
  font-size: 0.95rem;
  color: var(--ig-text);
}

.de-weather-subtitle {
  font-size: 0.82rem;
  color: var(--ig-text-secondary);
}

.de-weather-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(84px, 1fr));
  gap: 0.6rem;
  margin-top: 1rem;
}

.de-weather-stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 0.3rem;
  padding: 0.65rem 0.3rem;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.04);
}

.de-weather-stat-icon {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 149, 246, 0.14);
  color: var(--ig-blue);
}

.de-weather-stat-value {
  font-weight: 700;
  font-size: 0.85rem;
  color: var(--ig-text);
}

.de-weather-stat-label {
  font-size: 0.65rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ig-text-secondary);
}

.de-weather-sources {
  margin-top: 0.85rem;
  padding-top: 0.6rem;
  border-top: 1px solid var(--ig-border-light);
  font-size: 0.72rem;
  color: var(--ig-text-secondary);
}

/* Reusable swipe-to-reveal-remove list row, wired up by swipe-to-remove.js.
   .de-swipe-row lays .de-swipe-content and .de-swipe-actions out side by
   side as flex siblings (not stacked/overlapping layers) so they always
   share the exact same height with no independent-box rounding to go out
   of sync — .de-swipe-actions simply sits just past the item's clipped
   right edge until the row is dragged left to reveal it. */
.de-swipe-item {
  position: relative;
  overflow: hidden;
  border-radius: 12px;
}

.de-swipe-row {
  display: flex;
  align-items: stretch;
  transform: translateX(0);
  transition: transform 0.2s ease;
  will-change: transform;
}

.de-swipe-row.de-swipe-dragging {
  transition: none;
}

.de-swipe-content {
  flex: 1 0 100%;
  min-width: 100%;
  touch-action: pan-y;
}

.de-swipe-actions {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 1rem;
  background: var(--ig-like);
}

.de-swipe-remove-btn {
  width: 44px;
  height: 44px;
  border: none;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.15);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

/* Small unread-count badge overlaid on the top bar's notification bell. */
.de-notification-badge {
  position: absolute;
  top: -4px;
  right: -6px;
  min-width: 16px;
  height: 16px;
  padding: 0 3px;
  border-radius: 999px;
  background: var(--ig-like);
  color: #fff;
  font-size: 0.6rem;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
}

/* End-to-end encrypted buddy messaging (Messages/Conversation). Paired with
   body.de-dm-conversation-page: the page itself is locked to the viewport,
   .de-dm-page fills the space that leaves, and .de-dm-thread is the one
   piece that actually scrolls — so the header/composer stay put and the
   thread only grows a scrollbar once there are enough messages to need it,
   instead of the whole page scrolling. */
.de-dm-page {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.de-dm-thread {
  /* Driven by dm-conversation.js's setupSwipeTimeline while the user is
     dragging the thread left (0 at rest, up to 1 mid-drag) — read by
     .de-dm-bubble (shifts left, uncovering .de-dm-time-gutter beneath it)
     and .de-dm-time-gutter (fades in) below. */
  --dm-swipe-progress: 0;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 1rem 0;
  overflow-y: auto;
  overflow-x: hidden;
  touch-action: pan-y;
}

.de-dm-date-separator {
  align-self: center;
  margin: 0.4rem 0;
  padding: 0.15rem 0.7rem;
  border-radius: 10px;
  background: var(--ig-bg);
  color: var(--ig-text-secondary);
  font-size: 0.68rem;
  font-weight: 600;
}

.de-dm-row {
  position: relative;
  display: flex;
  max-width: 100%;
  box-sizing: border-box;
}

.de-dm-row-mine {
  justify-content: flex-end;
}

.de-dm-row-theirs {
  justify-content: flex-start;
}

.de-dm-bubble {
  position: relative;
  max-width: 75%;
  padding: 0.5rem 0.85rem;
  border-radius: 16px;
  font-size: 0.9rem;
  word-wrap: break-word;
  cursor: pointer;
  /* At rest this is 0 — bubbles sit flush against the row's edge, nothing
     reserved. Dragging the thread shifts every bubble left together,
     uncovering .de-dm-time-gutter (same width as the max shift here) sitting
     underneath at the row's trailing edge. */
  transform: translateX(calc(var(--dm-swipe-progress, 0) * -3rem));
  transition: transform 0.15s ease;
}

.de-dm-bubble-mine {
  background: var(--ig-blue);
  color: #fff;
}

.de-dm-bubble-theirs {
  background: var(--ig-border-light);
  color: var(--ig-text);
}

/* Sits underneath the bubble at the row's trailing edge — invisible at rest
   (opacity 0), only revealed once the bubble above it has shifted left
   during a drag (see .de-dm-bubble and .de-dm-thread's --dm-swipe-progress).
   Never wider than the row, so this can't cause horizontal overflow. */
.de-dm-time-gutter {
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 3rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: 0.6rem;
  color: var(--ig-text-secondary);
  opacity: var(--dm-swipe-progress, 0);
  transition: opacity 0.15s ease;
  pointer-events: none;
}

.de-dm-bubble-meta:empty {
  display: none;
}

.de-dm-edited-label {
  display: block;
  margin-top: 0.2rem;
  font-size: 0.65rem;
  opacity: 0.7;
  font-style: italic;
}

.de-dm-bubble-text {
  white-space: pre-wrap;
}

.de-dm-decrypt-failed {
  opacity: 0.75;
  font-style: italic;
  white-space: normal;
}

.de-dm-key-reset-notice {
  margin: 0 1rem 0.75rem;
}

.de-dm-reply-quote {
  border-left: 2px solid currentColor;
  opacity: 0.75;
  padding-left: 0.5rem;
  margin-bottom: 0.35rem;
  font-size: 0.8rem;
  cursor: pointer;
}

.de-dm-media-expired {
  font-size: 0.78rem;
  opacity: 0.75;
  font-style: italic;
}

.de-dm-bubble-attachment {
  display: block;
  max-width: 100%;
  max-height: 260px;
  border-radius: 10px;
  margin-bottom: 0.35rem;
}

/* A single reaction (no count) overlapping the bubble's bottom-right corner,
   Facebook-Messenger-tapback style, instead of a row of emoji+count badges
   below the content. */
.de-dm-reactions:empty {
  display: none;
}

.de-dm-reaction-badge {
  position: absolute;
  right: -0.3rem;
  bottom: -0.3rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.3rem;
  height: 1.3rem;
  border-radius: 50%;
  font-size: 0.75rem;
  line-height: 1;
  background: var(--ig-bg);
  border: 1.5px solid #000;
}

/* Long-press-on-own-bubble / tap-on-their-bubble action menu — inserted
   directly after the target row in normal document flow (so it appears
   "underneath" that message, pushing later ones down) rather than as a
   floating overlay, avoiding any scroll-position recalculation. .de-dm-thread
   is a flex column, so a bare block here would stretch to its full width by
   default — align-self + width:fit-content keeps it small and pinned to
   whichever side the target message is on (own messages: right; the other
   person's: left). */
.de-dm-action-popup {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.2rem;
  width: fit-content;
  max-width: 85%;
  padding: 0.25rem;
  margin: 0.1rem 0;
  border: 1px solid var(--ig-border);
  border-radius: 10px;
  background: var(--ig-bg);
  align-self: flex-start;
}

.de-dm-action-popup-mine {
  align-self: flex-end;
}

.de-dm-action-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  white-space: nowrap;
  border: none;
  background: transparent;
  color: var(--ig-text);
  font-size: 0.75rem;
  padding: 0.3rem 0.5rem;
  border-radius: 7px;
}

.de-dm-action-btn:hover {
  background: var(--ig-border-light);
}

.de-dm-action-danger {
  color: var(--ig-like);
}

.de-dm-quick-emojis {
  display: flex;
  gap: 0.1rem;
}

.de-dm-quick-emoji {
  border: none;
  background: transparent;
  font-size: 0.95rem;
  line-height: 1;
  padding: 0.2rem;
  border-radius: 7px;
}

.de-dm-quick-emoji:hover {
  background: var(--ig-border-light);
}

.de-dm-reply-preview {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.6rem;
  background: var(--ig-bg);
  border-radius: 8px;
  margin-bottom: 0.3rem;
}

.de-dm-reply-preview-bar {
  width: 3px;
  align-self: stretch;
  background: var(--ig-blue);
  border-radius: 2px;
}

.de-dm-reply-preview-text {
  flex: 1;
  font-size: 0.8rem;
  color: var(--ig-text-secondary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.de-dm-composer-editing .de-comment-editor {
  border-color: var(--ig-blue);
}

/* Shared-post card (post-share-dm.js payload rendered by dm-conversation.js)
   — the thumbnail bleeds to the bubble's edges, so the bubble itself drops
   its usual text padding and the padding moves onto the label/time instead. */
.de-dm-bubble-media {
  padding: 0;
  max-width: 220px;
  overflow: hidden;
}

.de-dm-shared-post {
  display: block;
  color: inherit;
  text-decoration: none;
}

.de-dm-shared-post-img {
  display: block;
  width: 100%;
  max-height: 220px;
  object-fit: cover;
}

.de-dm-shared-post-label {
  display: block;
  padding: 0.5rem 0.85rem 0;
  font-size: 0.85rem;
  font-weight: 600;
}

.de-dm-bubble-media .de-dm-bubble-meta:not(:empty) {
  padding: 0 0.85rem 0.5rem;
}

/* Fallback shared-post card for posts with no image (video-only or
   text-only) — sits inside a normally-padded bubble instead of the
   edge-to-edge .de-dm-bubble-media treatment above. */
.de-dm-shared-post-fallback {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.de-dm-shared-post-fallback .de-dm-shared-post-label {
  padding: 0;
  font-size: 0.75rem;
  font-weight: 400;
  opacity: 0.8;
}

.de-dm-shared-post-author {
  display: block;
  font-weight: 600;
}

.de-dm-composer {
  /* Just a normal (non-scrolling) flex item now — .de-dm-page's own
     padding-bottom already clears .de-bottom-nav, the floating pill nav
     fixed at the very bottom of every page, so this doesn't need to be
     sticky/offset itself. */
  position: relative;
  flex-shrink: 0;
  display: flex;
  align-items: flex-end;
  gap: 0.5rem;
  padding: 0.5rem 0;
  background: #000;
}

/* The message box takes the full composer width — the send button is pulled
   out of flex flow (see the button rule below) and overlaid inside the box
   instead of sitting beside it as a separate flex item. */
.de-dm-composer .flex-grow-1 {
  width: 100%;
}

.de-dm-composer > button[type="submit"] {
  position: absolute;
  top: 2.35rem;
  right: 0.7rem;
  z-index: 2;
}

/* Room for the overlaid send button so typed text never runs under it. */
.de-dm-composer .de-comment-editor-input {
  padding-right: 3.5rem;
}

/* The composer sits near the bottom of the viewport on this page (see
   .de-dm-composer above) — the emoji/link toolbar panels normally drop down
   from their trigger button (.de-emoji-panel/.de-link-panel default to
   top:100%), which would push them off-screen or under the bottom nav here.
   Flip them to open upward instead, scoped to this page only so every other
   composer (tribe posts, event chat, condition reports) keeps the normal
   drop-down behavior. */
.de-dm-composer .de-emoji-panel,
.de-dm-composer .de-link-panel {
  top: auto;
  bottom: 100%;
  margin-top: 0;
  margin-bottom: 0.25rem;
}

.de-dm-composer textarea {
  flex: 1;
  resize: none;
  max-height: 6rem;
}

/* Fieldset/legend used in place of a plain section heading (Dashboard's
   "My Tribes", "My Buddies", "My Events") — borderless, just gives the
   legend label its small-caps section-heading treatment. */
.de-legend-box {
    border: none;
    border-radius: 8px;
    padding: 1rem;
    margin: 0;
}

.de-legend-box legend {
  width: auto;
  float: none;
  padding: 0 0.5rem;
  margin-left: 0.5rem;
  margin-bottom: 0;
  font-size: 0.8rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--ig-text-secondary);
}

/* Instagram-style post card: white box, 1px border, rounded corners, each
   post visually separate (not a flat flowing list). */
.de-feed-item {
  padding: 0;
  margin-bottom: 0.5rem;
  background: transparent;
  border-radius: 8px;
  overflow: hidden;
}


/* Momentary highlight for a post deep-linked to via #post-{id} (e.g. from
   the dashboard's "My Posts" list), so it's easy to spot in a long feed. */
.de-feed-item.de-post-highlight,
.de-comment-row.de-post-highlight {
  box-shadow: 0 0 0 2px var(--ig-blue);
  transition: box-shadow 2s ease;
  border-radius: 8px;
}

.de-feed-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem;
  padding: 0.7rem 0.9rem;
}

.de-feed-name {
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--ig-text);
}

.de-feed-meta {
  font-size: 0.75rem;
  color: var(--ig-text-secondary);
  white-space: nowrap;
}

.de-feed-text {
  font-size: 0.9rem;
  line-height: 1.4;
  margin: 0;
  padding: 0 0.9rem;
}

/* Instagram Explore-style photo grid on the Search page (Tribes/Index),
   shown while the search box is empty — one square tile per recent tribe
   post that has a photo. */
.de-explore-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2px;
}

.de-explore-tile {
  display: block;
  position: relative;
  aspect-ratio: 1 / 1;
  background-color: var(--ig-border-light);
  background-size: cover;
  background-position: center;
}

/* Video posts in the Explore grid: the video itself stands in for a
   thumbnail (no server-side frame extraction) — the #t=0.1 fragment on its
   src plus preload="metadata" makes browsers seek to and paint that frame
   without downloading/playing the file. A small "reels" badge in the corner
   is the only way to tell it apart from a photo tile at a glance. */
.de-explore-tile-video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.de-explore-tile-video-badge {
  position: absolute;
  top: 0.4rem;
  right: 0.4rem;
  color: #fff;
  filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.7));
  line-height: 0;
}

/* Dive site / tribe descriptions: rendered through ChatFormatting.RenderRichText
   (same linkify/mention pipeline as posts), but shown as a standalone block of
   prose rather than a feed row, so line breaks the author typed need to survive
   without a <pre> tag. */
.de-richtext {
  white-space: pre-wrap;
  line-height: 1.5;
}

.de-feed-text .de-feed-name {
  margin-right: 0.4rem;
}

/* Dive site Resources tab: flat rows matching the feed's borderless card
   look, separated by a hairline instead of Bootstrap's boxed list-group. */
.de-resource-item {
  padding: 0.75rem 0.25rem;
  border-bottom: 1px solid var(--ig-border-light);
}

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

.de-feed-title {
  font-size: 0.95rem;
  font-weight: 600;
  margin: 0.1rem 0 0.25rem;
}

.de-feed-body {
  padding: 0.6rem 0 0.2rem;
}

/* Chat mentions and replies */
.de-mention {
  color: var(--ig-blue-dark);
  font-weight: 600;
}

.de-reply-list {
  margin-left: 2.5rem;
  border-left: 2px solid var(--ig-border-light);
  padding-left: 0.75rem;
}

/* Comment row inside a post card — no border/box of its own (the post card
   already provides that), just compact vertical rhythm between comments. */
.de-comment-row {
  padding: 0.4rem 0;
}

.de-comment-row .de-feed-text {
  padding: 0;
}

.de-comment-row .de-feed-header {
  padding: 0;
}

/* Post action icons (like / comment / share / bookmark) and the "..." options menu */
.de-icon-btn {
  border: none;
  background: none;
  color: var(--ig-text);
  padding: 0.3rem;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.8rem;
}

.de-icon-btn:hover {
  color: var(--ig-text-secondary);
}

.de-icon-btn.active {
  color: var(--ig-like);
}

.de-icon-btn svg {
  flex-shrink: 0;
}

/* Row of action icons under a post's media, Instagram-style (heart, comment,
   share on the left; bookmark on the right). */
.de-feed-actions {
  display: flex;
  align-items: center;
  padding: 0.3rem 0.6rem;
}

.de-feed-actions .de-icon-btn {
  padding: 0.4rem 0.5rem;
}

.de-feed-actions-spacer {
  flex: 1 1 auto;
}

.de-feed-like-count {
  font-size: 0.85rem;
  font-weight: 600;
  padding: 0 0.9rem;
  margin-bottom: 0.3rem;
}

/* Icon button variant with a visible text label — for actions that need to
   be immediately noticeable (not just discoverable via hover/aria-label),
   e.g. navigating to an event's details. Bordered like a real button so it
   reads clearly alongside adjacent btn-outline-* actions, with a larger
   touch target than the bare icon-only .de-icon-btn. */
.de-icon-btn-labeled {
    border: 1px solid var(--ig-border);
    border-radius: 8px;
    padding: 0.3rem 0.65rem;
    text-decoration: none;
    color: var(--ig-text);
}

.de-icon-btn-labeled:hover {
  border-color: #b2b2b2;
  background: var(--ig-bg);
  color: var(--ig-text);
}

.de-post-menu-toggle {
  border: none;
  background: none;
  color: var(--ig-text);
  padding: 0.1rem 0.35rem;
  border-radius: 8px;
  line-height: 1;
}

.de-post-menu-toggle:hover {
  background: var(--ig-bg);
}

/* Single-button view switch (e.g. events grid vs. calendar) — swaps its
   icon+label between two states on click instead of showing two separate buttons. */
.de-view-switch {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.35rem 0.75rem;
  border: 1px solid var(--ig-border);
  border-radius: 8px;
  background: transparent;
  color: var(--ig-text);
  font-size: 0.85rem;
  font-weight: 600;
}

.de-view-switch:hover {
  border-color: #b2b2b2;
  background: var(--ig-bg);
}

/* Wraps a toolbar icon button that opens a floating panel (emoji, link),
   so the panel's absolute position is anchored to the button itself
   rather than snapping to the corner of its flex-container ancestor. */
.de-icon-popover-anchor {
  position: relative;
  display: inline-flex;
}

/* Emoji picker */
.de-emoji-panel {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 1000;
  margin-top: 0.25rem;
  padding: 0.5rem;
  background: var(--ig-bg);
  border: 1px solid var(--ig-border);
  border-radius: 8px;
  box-shadow: 0 2px 16px rgba(0, 0, 0, 0.15);
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 0.15rem;
  width: 260px;
}

.de-emoji-option {
  border: none;
  background: none;
  font-size: 1.1rem;
  line-height: 1.6;
  border-radius: 6px;
  padding: 0.1rem;
}

.de-emoji-option:hover {
  background: var(--ig-bg);
}

/* Link-insert popover */
.de-link-panel {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 1000;
  margin-top: 0.25rem;
  padding: 0.5rem;
  background: var(--ig-bg);
  border: 1px solid var(--ig-border);
  border-radius: 8px;
  box-shadow: 0 2px 16px rgba(0, 0, 0, 0.15);
  display: flex;
  gap: 0.4rem;
  width: 260px;
}

.de-link-panel input {
  flex: 1;
  min-width: 0;
}

/* Comment composer styled as a single bordered editor box, with the
   textarea and its icon toolbar (emoji/photo/location) inside one frame
   instead of separate floating controls. */
.de-comment-editor {
  border: 1px solid var(--ig-border);
  border-radius: 20px;
  padding: 0.4rem 0.6rem 0.35rem;
  background: transparent;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.de-comment-editor:focus-within {
  border-color: #b2b2b2;
  box-shadow: none;
}

/* EventDetails reply composer sits inside an already-bordered .de-panel, so
   its own .de-comment-editor border is redundant — drop it there only. */
.de-reply-composer .de-comment-editor,
.de-reply-composer .de-comment-editor:focus-within {
  border-color: transparent;
}

.de-comment-editor-input {
  padding: 0.15rem 0.1rem;
  resize: none;
  overflow-y: hidden;
  /* iOS Safari auto-zooms the page on focusing any input/textarea whose
     font-size resolves below 16px — .form-control-sm sets 0.875rem (14px),
     so pin this back to 16px to stop that zoom. */
  font-size: 16px;
}

.de-comment-editor-toolbar {
  border-top: 1px solid var(--ig-border-light);
  margin-top: 0.35rem;
  padding-top: 0.3rem;
}

/* Icon overlaid inside a text input (e.g. map pin for location fields) */
.de-input-icon {
  position: absolute;
  left: 0.6rem;
  top: 50%;
  transform: translateY(-50%);
  color: var(--ig-text-secondary);
  pointer-events: none;
  display: flex;
  align-items: center;
  z-index: 5;
}

/* Pill-shaped, borderless search bar (Instagram-style) with a leading
   icon and a clear button that only appears once there's text. */
.de-search-bar {
  position: relative;
  display: flex;
  align-items: center;
}

.de-search-input {
  border: none;
  border-radius: 999px;
  background-color: var(--ig-border-light);
  padding-left: 2.25rem;
  padding-right: 2.25rem;
}

.de-search-input:focus {
  background-color: var(--ig-border-light);
  box-shadow: none;
}

.de-search-clear {
  position: absolute;
  right: 0.5rem;
  top: 50%;
  transform: translateY(-50%);
  background: none;
  border: none;
  padding: 0.3rem;
  line-height: 0;
  color: var(--ig-text-secondary);
  display: flex;
  align-items: center;
  z-index: 5;
  cursor: pointer;
}

.de-search-clear:hover {
  color: var(--ig-text);
}

.de-feed-media {
  border-radius: 0;
  overflow: hidden;
  background: #000;
}

.de-feed-media img,
.de-feed-media video {
  aspect-ratio: 1 / 1;
  object-fit: cover;
  width: 100%;
}

.de-feed-actions .btn {
  padding: 0.15rem 0.6rem;
  font-size: 0.78rem;
}

/* Page banner (tribe header, etc.) */
.de-page-banner {
  position: relative;
  background: transparent;
  color: var(--ig-text);
  border: 1px solid var(--ig-border);
  border-radius: 8px;
  padding: 2rem;
}

.de-page-banner .text-muted {
  color: var(--ig-text-secondary) !important;
}

.de-page-banner.de-has-banner-image {
  background-size: cover;
  background-position: center;
  color: #fff;
}

.de-page-banner.de-has-banner-image::before {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.35);
  border-radius: 8px;
}

.de-page-banner.de-has-banner-image > * {
  position: relative;
}

.de-page-banner.de-has-banner-image .text-muted {
  color: rgba(255, 255, 255, 0.85) !important;
}

/* Full-bleed variant: sits inside .de-hero-breakout, so it spans edge to
   edge of the app shell instead of sitting inset inside .container. Its
   parent (body.de-banner-page > .container-fluid) is pulled up underneath
   the top bar, so the extra top padding here keeps the title text clear of
   the bar's icons instead of sitting under them. */
.de-page-banner-full {
  border-left: none;
  border-right: none;
  border-radius: 0;
  padding-top: 4.5rem;
}

/* Floating edit icon pinned to a banner's top-right corner. On a full-bleed
   banner (pulled up underneath the top bar) it needs to drop below the bar
   too, or it would sit underneath/overlap the bar's icons (previously
   top: 0.25rem landed right on top of the notifications bell). Match the
   banner's own padding-top so the icon clears the bar the same way the
   title does. */
.de-page-banner-full .de-banner-edit-btn {
  top: 4.5rem;
}
.de-banner-edit-btn {
    position: absolute;
    top: 1rem;
    right: 1rem;
    width: 2.25rem;
    height: 2.25rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: transparent;
    border: 1px solid white;
    color: white;
    transition: background 0.15s ease;
    z-index: 2;
}

    .de-banner-edit-btn:hover {
        background: #666161;
        color: var(--ig-text);
    }


/* Fullscreen image viewer overlay, opened by image-lightbox.js when a
   content image (img.img-fluid) is clicked. */
.de-lightbox-overlay {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.9);
  cursor: zoom-out;
}

.de-lightbox-overlay img {
  max-width: 92vw;
  max-height: 92vh;
  object-fit: contain;
  cursor: default;
}

.de-lightbox-close {
  position: absolute;
  top: 1rem;
  right: 1rem;
  width: 2.5rem;
  height: 2.5rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: transparent;
  border: 1px solid white;
  color: white;
  transition: background 0.15s ease;
}

.de-lightbox-close:hover {
  background: rgba(255, 255, 255, 0.15);
}

/* Avatars */
.de-avatar-sm {
  width: 32px;
  height: 32px;
  object-fit: cover;
  border-radius: 50%;
  flex-shrink: 0;
  border: 1px solid var(--ig-border-light);
}

.de-avatar-lg {
  width: 48px;
  height: 48px;
  object-fit: cover;
  border-radius: 50%;
  flex-shrink: 0;
  border: 1px solid var(--ig-border-light);
}

/* Instagram "story ring" — a gradient ring wrapped around an avatar, used on
   the tribe-details story bar to highlight members with a recent post/event. */
.de-story-ring {
  display: inline-flex;
  padding: 2.5px;
  border-radius: 50%;
  background: var(--ig-gradient);
  flex-shrink: 0;
}

.de-story-ring-inner {
  display: flex;
  padding: 2px;
  border-radius: 50%;
  background: var(--ig-white);
}

.de-story-ring img {
  display: block;
  border: none;
}

.de-story-ring.de-story-ring-muted {
  background: var(--ig-border);
}

.de-story-bar {
  display: flex;
  gap: 1rem;
  overflow-x: auto;
  background: transparent;
  border-radius: 8px;
  /* Still horizontally scrollable (touch/trackpad/drag), just without the
     visible scrollbar track — this row (Dashboard's My Tribes/My Buddies)
     reads better as a plain content strip than as a scroll widget. */
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.de-story-bar::-webkit-scrollbar {
  display: none;
}

.de-story-bar-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.3rem;
  width: 4.5rem;
  flex-shrink: 0;
  text-align: center;
  color: var(--ig-text);
  text-decoration: none;
}

.de-story-bar-item span {
  font-size: 0.7rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

/* "See all" tile capping a story bar (e.g. Dashboard's My Tribes) at a
   handful of items, in place of an avatar image. */
.de-story-see-all {
  width: 56px;
  height: 56px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  font-weight: 600;
  font-size: 0.85rem;
  color: var(--ig-text-secondary);
}

/* Small role-management menu overlaid on a member's avatar ring (Members
   tab) — only rendered for rows the current owner/moderator can act on. */
.de-member-menu {
  position: absolute;
  bottom: -2px;
  right: -2px;
}

.de-member-menu-toggle {
  width: 20px;
  height: 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--ig-bg);
  border: 1px solid var(--ig-border);
  color: var(--ig-text);
  padding: 0;
  line-height: 1;
}

.de-member-menu-toggle:hover {
  background: var(--ig-border-light);
}

/* Tribe branding */
.de-tribe-logo {
  width: 48px;
  height: 48px;
  object-fit: cover;
  border-radius: 50%;
  border: 2px solid #fff;
  box-shadow: 0 0 0 1px var(--ig-border);
  flex-shrink: 0;
}

/* Badges */
.de-badge-cyan {
  background-color: var(--ig-blue);
  color: #fff;
}

/* Star ratings */
.de-stars {
  color: #f5a623;
  letter-spacing: 1px;
}

/* Interactive star-rating input: five radio buttons rendered as stars.
   Source order is reversed (5,4,3,2,1) and flex-direction: row-reverse puts
   them back in visual left-to-right order, so ":checked ~ label" and
   ":hover ~ label" (which only match LATER siblings) light up the hovered
   star and everything to its left. CSS-only, keyboard accessible. */
.de-star-rating {
  display: inline-flex;
  flex-direction: row-reverse;
  gap: 0.1rem;
}

.de-star-rating input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.de-star-rating label {
  font-size: 1.6rem;
  line-height: 1;
  color: var(--ig-border);
  cursor: pointer;
  transition: color 0.1s ease;
}

.de-star-rating label:hover,
.de-star-rating label:hover ~ label,
.de-star-rating input:checked ~ label {
  color: #f5a623;
}

.de-star-rating input:focus-visible + label {
  outline: 2px solid var(--ig-blue);
  outline-offset: 2px;
  border-radius: 2px;
}

/* Entry-type cycle button: a single button showing an icon + label for the
   current state, advancing to the next state on click (see entry-type-switch.js). */
.de-entry-type-switch {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  border: 1px solid var(--ig-border);
  border-radius: 8px;
  background: transparent;
  color: var(--ig-text);
  padding: 0.25rem 0.65rem;
  font-size: 0.85rem;
  line-height: 1.5;
}

.de-entry-type-switch:hover {
  border-color: #b2b2b2;
  color: var(--ig-text);
}

.de-entry-type-switch svg {
  flex-shrink: 0;
}

/* Optional range-slider input (visibility, water temp): a checkbox toggle
   enables/disables the slider, so an unset value is genuinely omitted from
   the form post instead of defaulting to whatever position the slider
   happens to be at. */
.de-slider-widget {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.de-slider-toggle {
  accent-color: var(--ig-blue);
  cursor: pointer;
  flex-shrink: 0;
}

.de-slider-widget input[type="range"] {
  flex: 1;
  -webkit-appearance: none;
  appearance: none;
  height: 6px;
  border-radius: 3px;
  background: var(--ig-border);
  outline: none;
}

.de-slider-widget input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--ig-blue);
  border: 2px solid #fff;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
  cursor: pointer;
}

.de-slider-widget input[type="range"]::-moz-range-thumb {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--ig-blue);
  border: 2px solid #fff;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
  cursor: pointer;
}

.de-slider-widget input[type="range"]:disabled {
  opacity: 0.4;
}

.de-slider-widget input[type="range"]:disabled::-webkit-slider-thumb {
  cursor: not-allowed;
}

/* Water-temp slider gets a cold-to-warm gradient track instead of the flat one. */
.de-slider-widget input[type="range"].de-slider-temp {
  background: linear-gradient(to right, #4dabf7, #ffd43b, #ff6b6b);
}

.de-slider-widget input[type="range"].de-slider-temp::-moz-range-track {
  background: linear-gradient(to right, #4dabf7, #ffd43b, #ff6b6b);
  height: 6px;
  border-radius: 3px;
}

.de-slider-value {
  min-width: 3.2rem;
  font-weight: 600;
  color: var(--ig-text);
  text-align: right;
  flex-shrink: 0;
}

/* Segmented single-choice control (e.g. current strength) — radio buttons
   styled as a connected row of toggle buttons, only the checked one filled. */
.de-segmented {
  display: inline-flex;
  border: 1px solid var(--ig-border);
  border-radius: 8px;
  overflow: hidden;
}

.de-segmented input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.de-segmented label {
  padding: 0.35rem 0.75rem;
  font-size: 0.85rem;
  cursor: pointer;
  color: var(--ig-text-secondary);
  border-right: 1px solid var(--ig-border);
  transition: background 0.1s ease, color 0.1s ease;
}

.de-segmented label:last-of-type {
  border-right: none;
}

.de-segmented label:hover {
  background: var(--ig-bg);
}

.de-segmented input:checked + label {
  background: var(--ig-blue);
  color: #fff;
}

.de-segmented input:focus-visible + label {
  outline: 2px solid var(--ig-blue-dark);
  outline-offset: -2px;
}

/* Full-width variant (condition report form): stretches to fill its row
   instead of sizing to content, with each option sharing the space evenly. */
.de-segmented.w-100 label {
  flex: 1;
  text-align: center;
}

/* Identity UI (Login/Register/Manage) pages — packaged Razor Pages we don't
   own the markup for, scoped via a body class set in _Layout.cshtml. The
   whole packaged page (h1 + form/row content) lives inside <main>, so that's
   styled as one compact "card" rather than trying to reach markup we can't
   edit directly. Kept deliberately small/understated. */
.de-auth-page {
  background: var(--ig-bg);
}

.de-auth-page .container {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
  padding-top: 2rem;
  padding-bottom: 2rem;
}

.de-auth-page main {
  width: 100%;
  max-width: 400px;
  background: transparent;
  border: 1px solid var(--ig-border);
  border-radius: 8px;
  padding: 1.5rem;
  box-shadow: none;
}

.de-auth-page h1 {
  color: var(--ig-text);
  font-weight: 700;
  font-size: 1.25rem;
  text-align: center;
  margin-bottom: 1rem;
  font-family: var(--ig-font);
}

.de-auth-page main header {
  text-align: center;
  padding: 0.25rem 0;
}

/* Top-level subtitle directly under h1 (e.g. ForgotPassword's "Enter your
   email."), as opposed to the eyebrow labels inside the split panels below. */
.de-auth-page main > h2 {
  text-align: center;
  color: var(--ig-text-secondary);
  font-weight: 500;
  font-size: 0.95rem;
  margin-bottom: 1rem;
}

.de-auth-page hr {
  display: none;
}

/* Single stacked panel — local login/register form, then external logins
   below it, all in one column (no side-by-side split). */
.de-auth-page .row {
  display: block;
  margin: 0;
}

.de-auth-page .row > [class*="col-"] {
  width: 100%;
  max-width: 100%;
  flex: none;
  padding: 0;
}

.de-auth-page .col-md-4 > section,
.de-auth-page .col-md-4 > form {
  padding: 0;
}

.de-auth-page .col-md-6.col-md-offset-2 {
  margin-top: 1.25rem;
  padding-top: 1.25rem;
  padding-left: 0;
  border-left: none;
  border-top: 1px solid var(--ig-border);
}

/* Eyebrow-style labels for the panel headings ("Use a local account to
   log in." / "Use another service to log in."). */
.de-auth-page .row h2,
.de-auth-page .row h3 {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--ig-text-secondary);
  font-weight: 700;
  margin-bottom: 0.5rem;
}

/* Undo Bootstrap's floating-label behavior — plain label above a normal
   input instead of an overlapping/animated placeholder-style label. The
   <label> comes AFTER the <input> in the markup (that's how the floating
   animation works), so a flex column with the label reordered first is used
   to visually put it on top without fighting the DOM order. */
.de-auth-page main .form-floating {
  position: static;
  display: flex;
  flex-direction: column;
}

.de-auth-page main .form-floating > .form-control {
  height: auto;
  padding: 0.65rem 0.75rem;
  order: 1;
  background: var(--ig-bg);
}

.de-auth-page main .form-floating > .form-control::placeholder {
  color: var(--ig-text-secondary);
  opacity: 1;
}

.de-auth-page main .form-floating > label {
  position: static;
  transform: none !important;
  order: 0;
  display: block;
  padding: 0;
  margin-bottom: 0.3rem;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--ig-text);
  opacity: 1 !important;
  height: auto;
}

.de-auth-page main .form-control {
  border: 1px solid var(--ig-border);
  border-radius: 6px;
  font-size: 0.9rem;
}

.de-auth-page main .form-control:focus {
  border-color: #b2b2b2;
  box-shadow: none;
  background: #262626;
}

.de-auth-page main .form-check-input {
  accent-color: var(--ig-blue);
}

.de-auth-page main a {
  color: var(--ig-blue-dark);
  font-weight: 600;
  text-decoration: none;
  font-size: 0.85rem;
}

.de-auth-page main a:hover {
  text-decoration: underline;
}

.de-auth-page main .col-md-4 p {
  display: inline;
  margin: 0;
  font-size: 0.85rem;
}

.de-auth-page main .col-md-4 p + p::before {
  content: "\00b7";
  display: inline-block;
  margin: 0 0.6rem;
  color: var(--ig-border);
  font-weight: 700;
}

.de-auth-page main .col-md-4 form > div:last-child {
  text-align: center;
  margin-top: 0.75rem;
}

.de-auth-page main .btn-primary:not([name="provider"]) {
  background-color: var(--ig-blue);
  border-color: var(--ig-blue);
  border-radius: 8px;
  padding: 0.45rem 0.75rem;
  font-size: 0.9rem;
  font-weight: 600;
}

.de-auth-page main #external-account p {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.de-auth-page #external-account button[name="provider"] {
  width: 100%;
  border-radius: 8px;
  font-weight: 600;
  font-size: 0.9rem;
  padding: 0.4rem 0.75rem 0.4rem 2.75rem;
  background-repeat: no-repeat;
  background-position: 0.85rem center;
  background-size: 18px 18px;
}

.de-auth-page button[value="Google"] {
  background-color: #fff;
  background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxOCAxOCIgd2lkdGg9IjE4IiBoZWlnaHQ9IjE4Ij48cGF0aCBmaWxsPSIjNDI4NUY0IiBkPSJNMTcuNjQgOS4yMDQ1YzAtLjYzODEtLjA1NzMtMS4yNTE4LS4xNjM2LTEuODQwOUg5djMuNDgxOGg0Ljg0MzZjLS4yMDg2IDEuMTI1LS44NDI3IDIuMDc4Mi0xLjc5NTkgMi43MTY0djIuMjU4MWgyLjkwODdjMS43MDE4LTEuNTY2OCAyLjY4MzYtMy44NzQxIDIuNjgzNi02LjYxNTR6Ii8+PHBhdGggZmlsbD0iIzM0QTg1MyIgZD0iTTkgMThjMi40MyAwIDQuNDY3My0uODA2NCA1Ljk1NjQtMi4xODE4bC0yLjkwODctMi4yNTgxYy0uODA2NC41NC0xLjgzNjguODU5MS0zLjA0NzcuODU5MS0yLjM0NCAwLTQuMzI4Mi0xLjU4MzEtNS4wMzYtMy43MTA0SC45NTczdjIuMzMxOEMyLjQzODIgMTUuOTgzMiA1LjQ4MTggMTggOSAxOHoiLz48cGF0aCBmaWxsPSIjRkJCQzA1IiBkPSJNMy45NjQgMTAuNzFjLS4xOC0uNTQtLjI4MjItMS4xMTY4LS4yODIyLTEuNzFzLjEwMjMtMS4xNy4yODIyLTEuNzFWNC45NTgySC45NTczQy4zNDc3IDYuMTczMiAwIDcuNTQ3NyAwIDlzLjM0NzcgMi44MjY4Ljk1NzMgNC4wNDE4TDMuOTY0IDEwLjcxeiIvPjxwYXRoIGZpbGw9IiNFQTQzMzUiIGQ9Ik05IDMuNTc5NWMxLjMyMTQgMCAyLjUwNzcuNDU0MSAzLjQ0MDQgMS4zNDZsMi41ODE0LTIuNTgxM0MxMy40NjMyLjg5MTggMTEuNDI1OSAwIDkgMCA1LjQ4MTggMCAyLjQzODIgMi4wMTY4Ljk1NzMgNC45NTgyTDMuOTY0IDcuMjlDNC42NzE4IDUuMTYyNyA2LjY1NiAzLjU3OTUgOSAzLjU3OTV6Ii8+PC9zdmc+");
  color: #3c4043;
  border-color: #dadce0;
}

.de-auth-page button[value="Google"]:hover {
  background-color: #f7f8f8;
}

.de-auth-page button[value="Facebook"] {
  background-color: #1877f2;
  background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjE4IiBoZWlnaHQ9IjE4Ij48cGF0aCBmaWxsPSIjZmZmZmZmIiBkPSJNMjIgMTJjMC01LjUyMy00LjQ3Ny0xMC0xMC0xMFMyIDYuNDc3IDIgMTJjMCA0Ljk5MSAzLjY1NyA5LjEyOCA4LjQzOCA5Ljg3OHYtNi45ODdoLTIuNTRWMTJoMi41NFY5Ljc5N2MwLTIuNTA2IDEuNDkyLTMuODkgMy43NzctMy44OSAxLjA5NCAwIDIuMjM4LjE5NSAyLjIzOC4xOTV2Mi40NmgtMS4yNmMtMS4yNDMgMC0xLjYzLjc3MS0xLjYzIDEuNTYyVjEyaDIuNzczbC0uNDQzIDIuODloLTIuMzN2Ni45ODhDMTguMzQzIDIxLjEyOCAyMiAxNi45OTEgMjIgMTJ6Ii8+PC9zdmc+");
  border-color: #1877f2;
}

.de-auth-page button[value="Facebook"]:hover {
  background-color: #1466d8;
}

.de-auth-page button[value="Apple"] {
  background-color: #000;
  background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjE4IiBoZWlnaHQ9IjE4Ij48cGF0aCBmaWxsPSIjZmZmZmZmIiBkPSJNMTguNzEgMTkuNWMtLjgzIDEuMjQtMS43MSAyLjQ1LTMuMDUgMi40Ny0xLjM0LjAzLTEuNzctLjc5LTMuMjktLjc5LTEuNTMgMC0yIC43Ny0zLjI3LjgyLTEuMzEuMDUtMi4zLTEuMzItMy4xNC0yLjUzQzQuMjUgMTcgMi45NCAxMi40NSA0LjcgOS4zOWMuODctMS41MiAyLjQzLTIuNDggNC4xMi0yLjUxIDEuMjgtLjAyIDIuNS44NyAzLjI5Ljg3Ljc4IDAgMi4yNi0xLjA3IDMuODEtLjkxLjY1LjAzIDIuNDcuMjYgMy42NCAxLjk4LS4wOS4wNi0yLjE3IDEuMjgtMi4xNSAzLjgxLjAzIDMuMDIgMi42NSA0LjAzIDIuNjggNC4wNC0uMDMuMDctLjQyIDEuNDQtMS4zOCAyLjgzTTEzIDMuNWMuNzMtLjgzIDEuOTQtMS40NiAyLjk0LTEuNS4xMyAxLjE3LS4zNCAyLjM1LTEuMDQgMy4xOS0uNjkuODUtMS44MyAxLjUxLTIuOTUgMS40Mi0uMTUtMS4xNS40MS0yLjM1IDEuMDUtMy4xMXoiLz48L3N2Zz4=");
  border-color: #000;
}

.de-auth-page button[value="Apple"]:hover {
  background-color: #222;
}

/* Settings sub-nav */
.nav-pills .nav-link.active {
  background-color: var(--ig-blue);
}

.nav-pills .nav-link:not(.active) {
  color: var(--ig-text);
}

/* Tribe details tabs */
.nav-tabs {
  border-bottom-color: var(--ig-border);
}

.nav-tabs .nav-link.active {
  color: var(--ig-text);
  font-weight: 600;
  border: none;
  border-bottom: 2px solid var(--ig-text);
  background: transparent;
}

.nav-tabs .nav-link:not(.active) {
  color: var(--ig-text-secondary);
  border: none;
}

/* Event calendar */
.de-calendar-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 0.75rem;
}

.de-calendar-header h5 {
  margin: 0;
  color: var(--ig-text);
}

.de-calendar-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 3px;
}

.de-calendar-day-label {
  text-align: center;
  font-size: 0.65rem;
  font-weight: 600;
  color: var(--ig-text);
  padding-bottom: 0.25rem;
}

.de-calendar-day {
  aspect-ratio: 1;
  border-radius: 6px;
  border: 1px solid transparent;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: 0.7rem;
}

.de-calendar-day.de-outside-month {
  opacity: 0.35;
}

.de-calendar-day.de-today {
  border-color: var(--ig-text);
}

.de-calendar-day.de-has-events {
  background: rgba(0, 149, 246, 0.1);
  font-weight: 600;
  cursor: pointer;
}

.de-calendar-day.de-has-events:hover {
  background: rgba(0, 149, 246, 0.2);
}

.de-calendar-count {
  min-width: 13px;
  height: 13px;
  padding: 0 3px;
  border-radius: 7px;
  background: var(--ig-blue);
  color: #fff;
  font-size: 0.55rem;
  font-weight: 700;
  line-height: 13px;
  margin-top: 2px;
}

/* Brief highlight flash when jumping to a feed item from the calendar */
@keyframes de-highlight-flash {
  0% { box-shadow: 0 0 0 3px var(--ig-blue); }
  100% { box-shadow: 0 0 0 0 rgba(0, 149, 246, 0); }
}

.de-highlight {
  animation: de-highlight-flash 1.6s ease-out;
}
.abs-0{
    top:0;
    right:0;
}

/* Dark theme: Bootstrap's own component defaults (form controls, dropdowns,
   hr, text-muted, alerts) are hardcoded for a light background and don't
   pick up our --ig-* tokens on their own — patched here so raw Bootstrap
   markup used throughout the app (forms, RSVP/options dropdowns, dividers,
   error banners) matches the rest of the dark UI instead of staying white. */
.form-control,
.form-select {
    background-color: #000000;
    border-color: var(--ig-border);
    color: var(--ig-text);
    /* Without this, browsers draw native control chrome (the datetime
       picker's calendar icon, spinner arrows) in a light-theme palette by
       default — a black icon on our black background is invisible. */
    color-scheme: dark;
}

    .form-control:focus,
    .form-select:focus {
        background-color: #000000;
        border-color: #b2b2b2;
        color: var(--ig-text);
        box-shadow: none;
    }

.form-control::placeholder {
  color: var(--ig-text-secondary);
  opacity: 1;
}

.form-select option {
  background-color: var(--ig-bg);
  color: var(--ig-text);
}

.dropdown-menu {
  background-color: var(--ig-bg);
  border-color: var(--ig-border);
}

.dropdown-item {
  color: var(--ig-text);
}

.dropdown-item:hover,
.dropdown-item:focus {
  background-color: var(--ig-border);
  color: var(--ig-text);
}

.dropdown-item.active,
.dropdown-item:active {
  background-color: var(--ig-blue);
  color: #fff;
}

hr {
  border-color: var(--ig-border);
  opacity: 1;
}

.text-muted {
  color: var(--ig-text-secondary) !important;
}

.alert-danger {
  background-color: rgba(237, 73, 86, 0.15);
  border-color: rgba(237, 73, 86, 0.4);
  color: #ff8a93;
}

/* Bootstrap's .text-body utility hardcodes a dark gray with !important —
   used on a few de-card-style links (Dashboard, Create) to keep link text
   from turning Bootstrap-link-blue. Harmless in light mode (its hardcoded
   color happened to match our old dark --ig-text almost exactly), but reads
   as near-invisible dark-on-black now — override back to our token. */
.text-body {
  color: var(--ig-text) !important;
}

/* Bootstrap's offcanvas (the tribe calendar's "events for this day" panel)
   hardcodes a white background with no matching text color override, so it
   inherited the page's near-white text — unreadable white-on-white. Patched
   like the other raw-Bootstrap components above; the close icon is a dark
   glyph baked into an SVG background-image, so it needs the same invert
   filter Bootstrap ships for its own .btn-close-white variant. */
.offcanvas {
  background-color: var(--ig-bg);
  color: var(--ig-text);
  border-color: var(--ig-border);
}

.offcanvas-header {
  border-bottom: 1px solid var(--ig-border);
}

.offcanvas-title {
  color: var(--ig-text);
}

.offcanvas .btn-close {
  filter: invert(1) grayscale(100%) brightness(200%);
}
.no-borders{
    border:0
}