/* ===== LapakAnabul brand layer (sits on top of Bootstrap 5) =====
   Ported from D:\SourceCode\dogadoption\Theme\html\css\styles.css (the "Pawsome" demo
   theme). Colors are placeholders until real LapakAnabul brand colors are supplied —
   everything below consumes the --pri/--ink/--cream/--muted variables so a rebrand is a
   one-file change (see plan Phase 7). */
:root {
  --pri: #FF7A2F;
  --ink: #2C231D;
  --cream: #FFF9F4;
  --muted: #8A7B70;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: 'Nunito', sans-serif;
  color: var(--ink);
  background: var(--cream);
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}
main { flex: 1; }

.brand-font { font-family: 'Baloo 2', system-ui, sans-serif; }

/* --- Validation error spans (asp-validation-for) always sit on their own line/block.
   <span> is inline by default, and so is <label> (Bootstrap's .form-label only adds
   margin, it doesn't change display) — without this, an error message with actual text
   visually runs straight into whatever follows it (typically the next field's label) on
   the same line instead of breaking, e.g. "Pilih kota. Nama Kontak/Shelter". Targets
   data-valmsg-for specifically (what asp-validation-for renders to) so every such span
   site-wide gets this, not just one form. --- */
[data-valmsg-for] { display: block; }

/* Buttons */
.btn-brand {
  background: var(--pri);
  border: none;
  color: #fff;
  border-radius: 999px;
  font-weight: 800;
  padding: .62rem 1.5rem;
}
.btn-brand:hover,
.btn-brand:focus { background: color-mix(in srgb, var(--pri) 86%, #000); color: #fff; }

.btn-soft {
  background: color-mix(in srgb, var(--pri) 13%, #fff);
  color: var(--pri);
  border: none;
  border-radius: 999px;
  font-weight: 800;
  padding: .62rem 1.5rem;
}
.btn-soft:hover { background: color-mix(in srgb, var(--pri) 20%, #fff); color: var(--pri); }

/* Forms */
.form-control,
.form-select {
  border-radius: 14px;
  /* Matches Tom Select's own .ts-control padding (.375rem .75rem) so plain text
     inputs/selects render at the same height as the Jenis/Ras/Kota dropdowns —
     Tom Select's wrapper adopts this class for its border/radius, but its inner
     .ts-control has its own fixed padding this rule can't reach. */
  padding: .375rem .75rem;
  border: 1.5px solid #EADFD6;
  font-weight: 600;
}
.form-control::placeholder {
  color: var(--muted);
  font-weight: 400;
  opacity: 1;
}
.form-control:focus,
.form-select:focus {
  border-color: var(--pri);
  box-shadow: 0 0 0 .25rem color-mix(in srgb, var(--pri) 20%, transparent);
}
/* Bootstrap reserves space for the input via .form-check/.form-switch's padding-left,
   then pulls it fully into that space with a matching negative margin-left — both
   calibrated to the *default* 1em/2em input width. Enlarging the input alone (without
   adjusting these to match) leaves it shifted/overflowing relative to its label. */
.form-check-input {
  width: 1.5em;
  height: 1.5em;
}
.form-check {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding-left: 2em;
}
.form-check + .form-check {
  margin-top: .5rem;
}
.form-check .form-check-input {
  margin-left: -2em;
  margin-top: 0;
}
.form-switch {
  padding-left: 3.5em;
}
.form-switch .form-check-input {
  width: 3em;
  height: 1.5em;
  margin-left: -3.5em;
}
/* Scoped smaller variant for secondary/auxiliary checkboxes (e.g. "Gunakan nomor dari
   profile" next to a field label) — reverts to Bootstrap's original 1em sizing rather
   than the site-wide enlarged default. */
.form-check-sm {
  padding-left: 1.5em;
  gap: .35rem;
}
.form-check-sm .form-check-input {
  width: 1em;
  height: 1em;
  margin-left: -1.5em;
}
.form-check-sm .form-check-label {
  font-size: .8rem;
}
.form-check-input:checked {
  background-color: var(--pri);
  border-color: var(--pri);
}
.form-check-input:focus {
  border-color: var(--pri);
  box-shadow: 0 0 0 .25rem color-mix(in srgb, var(--pri) 20%, transparent);
}

/* Cards */
.pet-card {
  display: flex;
  flex-direction: column;
  height: 100%;
  background: #fff;
  border-radius: 22px;
  overflow: hidden;
  box-shadow: 0 8px 24px rgba(0, 0, 0, .05);
  color: inherit;
  text-decoration: none;
  transition: transform .22s ease, box-shadow .22s ease;
}
.pet-card:hover {
  transform: translateY(-6px);
  box-shadow: 0 20px 44px rgba(214, 120, 40, .18);
  color: inherit;
}

/* Nav pills */
.nav-pill {
  cursor: pointer;
  color: var(--ink);
  font-weight: 700;
  border-radius: 999px;
  padding: .42rem .95rem;
  transition: .15s;
  text-decoration: none;
}
.nav-pill:hover { background: color-mix(in srgb, var(--pri) 10%, #fff); color: var(--pri); }
.nav-pill.active { background: color-mix(in srgb, var(--pri) 14%, #fff); color: var(--pri); }

.thumb { cursor: pointer; transition: .15s; }
.thumb:hover { transform: translateY(-2px); }

a { color: var(--pri); text-decoration: none; }
a:hover { color: color-mix(in srgb, var(--pri) 80%, #000); }

.floaty { animation: floaty 6s ease-in-out infinite; }
@keyframes floaty { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-12px); } }

.chip {
  background: #F6EEE7;
  color: #7A6A5E;
  font-weight: 700;
  font-size: 12px;
  padding: .28rem .6rem;
  border-radius: 999px;
}
/* PostAnimal/Form.cshtml's section-title chips specifically (mb-3 modifier) — not the
   Animal Detail info chips or Profile hub group labels, which reuse the plain .chip look. */
.chip.mb-3 {
  color: var(--pri);
}
.stat-box {
  background: var(--cream);
  border-radius: 16px;
  padding: 14px;
  text-align: center;
}
/* --- Form-level error summary (PostAnimal/Form.cshtml): wrapped in a plain .stat-box for
   its outer width/shape (guaranteed match with every other card in the form, rather than a
   rule trying to replicate .stat-box's box model directly on the alert element — that kept
   leaving a visible width gap despite matching padding/margin/border values). This is just
   the inner red/error palette + its own smaller radius so it nests cleanly inside stat-box's
   16px-rounded frame instead of showing sharp corners against it. --- */
.form-alert-danger {
  background: #f8d7da;
  border: 1px solid #f5c2c7;
  border-radius: 10px;
  padding: 10px 12px;
  color: #842029;
}
.form-alert-danger + .form-alert-danger { margin-top: 10px; }
.form-alert-danger a { color: #6a1a21; }
/* Matches .stat-box's 14px inset — the page <h1> otherwise sits flush against the container
   edge while every card below it is padded 14px, making the title look shifted left relative
   to its own form (see PostAnimal/Form.cshtml). */
.form-page-title { padding-left: 14px; padding-right: 14px; }

/* Browse view modes (Home/Index) — #post-list gets one of these classes; the card
   markup itself (Home/_PostCards.cshtml) never changes, only the layout around it. */
#post-list.view-grid,
#post-list.view-tile {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
}
#post-list.view-grid { gap: 20px; }
#post-list.view-tile { gap: 12px; }

@media (min-width: 768px) {
  #post-list.view-grid,
  #post-list.view-tile {
    grid-template-columns: repeat(4, 1fr);
  }
}
@media (min-width: 992px) {
  /* Fixed column counts (not auto-fill) so both modes stay a predictable,
     consistent shape at any viewport width instead of fluctuating with it. */
  #post-list.view-grid { grid-template-columns: repeat(6, 1fr); }
  #post-list.view-tile { grid-template-columns: repeat(4, 1fr); }
}

/* --- Infinite-scroll skeleton placeholders (Home/Index) — appended into #post-list
   as real grid items while the next page loads, then swapped out for real cards. --- */
.skeleton-shimmer {
  background: linear-gradient(90deg, #eef0f3 25%, #f5f6f8 37%, #eef0f3 63%);
  background-size: 400% 100%;
  animation: skeleton-shimmer 1.4s ease infinite;
}
@keyframes skeleton-shimmer {
  0% { background-position: 100% 50%; }
  100% { background-position: 0 50%; }
}
.skeleton-media { aspect-ratio: 4/3; }
.skeleton-line { height: 10px; border-radius: 6px; margin: 12px 12px 0; }
.skeleton-line-sm { width: 45%; margin-top: 8px; }

#post-list.view-tile .pet-card .p-3 { padding: .6rem !important; }
#post-list.view-tile .pet-card .fw-bold { font-size: 12px !important; }
.view-mode-btn {
  padding: .4rem .9rem;
}
.view-mode-btn.active {
  background: var(--pri);
  color: #fff;
}

/* --- Navbar: notification bell + avatar dropdown menu --- */
.notif-badge-pos { position: absolute; top: -4px; right: -4px; }
.notif-badge-pos .badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  font-size: 10px;
  line-height: 1;
}
.avatar-menu-toggle::after,
.notif-menu-toggle::after,
.apps-menu-toggle::after { display: none; }

/* --- 3x3 "apps" waffle-menu icon (navbar) --- */
.waffle-icon {
  display: grid;
  grid-template-columns: repeat(3, 4px);
  grid-template-rows: repeat(3, 4px);
  gap: 3px;
}
.waffle-icon span {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--pri);
}
.site-navbar .dropdown-menu {
  border: none;
  box-shadow: 0 12px 32px rgba(0, 0, 0, .16);
}
.notif-dropdown-menu { width: 340px; }
.notif-dropdown-list { max-height: 360px; overflow-y: auto; }

/* Below the navbar-expand-lg breakpoint, .navbar-collapse's own menu items (apps/notif/avatar
   dropdowns) stack in a flex-column — but Bootstrap/Popper still positions each .dropdown-menu
   as an absolutely-floated card anchored to its (small, icon-only) toggle. On a narrow screen
   that reads as messy/disconnected: the card floats off wherever that toggle happens to land
   in the stack, detached from the collapsed panel's own flow, sometimes overlapping page
   content below the navbar entirely. Forcing it static instead makes it expand in place, right
   under its toggle, pushing the rest of the stacked menu down — a normal accordion-style mobile
   menu instead of a floating popover. Only below lg; at lg+ (a real horizontal navbar) the
   floating popover behavior is what you want, so it's left alone there. */
@media (max-width: 991.98px) {
  .site-navbar .dropdown-menu {
    /* !important is required here: Bootstrap's dropdown uses Popper.js, which sets
       position/inset/transform as *inline* styles on the element every time it opens —
       inline styles beat any external stylesheet rule unless it's !important, so a plain
       "position: static" here would be silently overridden the moment the dropdown shows. */
    position: static !important;
    inset: auto !important;
    transform: none !important;
    float: none;
    width: 100%;
    margin-top: .5rem;
  }
}

/* =====================================================================
   Utility & component classes — every inline style="" across the app's
   views is replaced by one of these, so the CSS lives in one file.
   ===================================================================== */

/* --- Generic text/weight/size utilities --- */
.text-muted-brand { color: var(--muted); }
.fw-700 { font-weight: 700; }
.fw-800 { font-weight: 800; }
.fs-30 { font-size: 30px; }
.fs-28 { font-size: 28px; }
.fs-26 { font-size: 26px; }
.fs-24 { font-size: 24px; }
.fs-20 { font-size: 20px; }
.fs-18 { font-size: 18px; }
.fs-17 { font-size: 17px; }
.fs-14 { font-size: 14px; }
.fs-12 { font-size: 12px; }
.fs-meta { font-size: .6em; }
.fs-post-date { font-size: .775em; }
.meta-pill {
  display: inline-flex;
  align-items: center;
  background: rgba(0, 0, 0, 0.6);
  color: #fff;
  border-radius: 999px;
  padding: .15rem .35rem;
  max-width: 100%;
}
.meta-pill-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.media-tag { position: absolute; bottom: 6px; max-width: calc(100% - 12px); }
.media-tag-left { left: 6px; }
.media-tag-right { right: 6px; }
.text-prewrap { white-space: pre-wrap; }
.spinner-brand { color: var(--pri); }
.spinner-lg { width: 3rem; height: 3rem; }
.badge-brand { background: var(--pri); }

/* --- Full-page block overlay: sits above everything (including the sticky navbar)
   and intercepts every click, so the user can't fire off other navigation/requests
   while an AJAX call is in flight. --- */
.page-block-overlay {
  position: fixed;
  inset: 0;
  background: rgba(255, 255, 255, .7);
  z-index: 2000;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* --- Floating "Buat Lapak" action button (Home, logged-in only) --- */
.fab-create {
  position: fixed;
  bottom: 24px;
  right: 24px;
  z-index: 1030;
  box-shadow: 0 8px 24px rgba(0, 0, 0, .25);
}

/* --- Narrow container widths (page-level wrappers) --- */
.container-narrow-280 { max-width: 280px; }
.container-narrow-560 { max-width: 560px; }
.container-narrow-640 { max-width: 640px; }
.container-narrow-700 { max-width: 700px; }

/* --- Rounded/overflow-hidden panel (list-groups, modal content) --- */
.rounded-panel { border-radius: 16px; overflow: hidden; }

/* --- Image helpers --- */
.img-cover { width: 100%; height: 100%; object-fit: cover; display: block; }
.img-placeholder { width: 100%; height: 100%; background: var(--cream); }
.thumb-sm { width: 72px; height: 72px; object-fit: cover; border-radius: 12px; }

/* --- Avatar circles --- */
.avatar-circle { border-radius: 50%; background: color-mix(in srgb, var(--pri) 14%, var(--cream)); overflow: hidden; }
.avatar-sm { width: 64px; height: 64px; flex-shrink: 0; }
.avatar-nav { width: 34px; height: 34px; flex-shrink: 0; }
.avatar-md { width: 88px; height: 88px; margin: 0 auto; }

/* --- Brand badge (circular "L" logo), size variants --- */
.brand-badge { color: #fff; font-weight: 800; }
.brand-badge-nav { width: 38px; height: 38px; border-radius: 13px; background: var(--pri); font-size: 22px; }
.brand-badge-footer { width: 36px; height: 36px; border-radius: 12px; background: var(--pri); font-size: 20px; }
.brand-badge-lg { width: 54px; height: 54px; border-radius: 18px; background: var(--pri); font-size: 28px; }
.brand-title-nav { font-size: 24px; font-weight: 800; color: var(--ink); }
.brand-title-footer { font-size: 22px; font-weight: 800; color: var(--ink); }
.brand-logo-nav { height: 40px; width: auto; }
.brand-logo-footer { height: 34px; width: auto; }

/* --- Success checkmark badge (Payment/Success) --- */
.success-badge { width: 64px; height: 64px; border-radius: 50%; background: #e8f8ee; color: #2e9d5c; font-size: 32px; }

/* --- Site chrome: navbar / footer --- */
.site-navbar { background: rgba(255, 255, 255, .92); backdrop-filter: blur(10px); box-shadow: 0 2px 20px rgba(0, 0, 0, .05); }
/* --- Breadcrumb (_Breadcrumb.cshtml), rendered once in _Layout.cshtml right below the
   navbar for pages that opt in via ViewData["Breadcrumbs"]. --- */
.breadcrumb-nav { background: var(--cream); border-bottom: 1px solid #F2E9E1; }
.breadcrumb-nav .breadcrumb { padding: .6rem 0; font-size: 13px; font-weight: 700; }
.breadcrumb-nav .breadcrumb-item a { color: var(--pri); }
.breadcrumb-nav .breadcrumb-item.active { color: var(--ink); }
.breadcrumb-nav .breadcrumb-item + .breadcrumb-item::before { color: var(--muted); }
.site-footer { background: #fff; border-top: 1px solid #F2E9E1; }
.footer-tagline { color: var(--muted); max-width: 22rem; margin-top: 10px; }
.footer-heading { font-weight: 800; margin-bottom: 10px; }
.footer-link { color: var(--muted); font-weight: 600; }
.footer-bottom { border-top: 1px solid #F2E9E1; margin-top: 24px; padding-top: 18px; color: var(--muted); font-size: 14px; font-weight: 600; }

/* --- Auth/narrow-card pages (Login, Register, ForgotPassword, ResetPassword,
   VerifyEmail, VerifyResetCode, ChangePassword, Report, Checkout, Qris,
   Success, Profile/Edit — every centered white-card form page) --- */
.auth-container { max-width: 26rem; }
.auth-card { background: #fff; border-radius: 26px; padding: 36px 30px; box-shadow: 0 12px 40px rgba(0, 0, 0, .06); }
/* Payment/Checkout.cshtml wants a stronger, more diffuse shadow than the shared .auth-card
   default — scoped to its own class rather than changing .auth-card itself, which every
   other auth-style page above also relies on. */
.auth-card.checkout-card { box-shadow: 0px 0px 5px 5px rgb(0 0 0 / 10%); }
.auth-title { font-weight: 800; font-size: 30px; margin: 14px 0 2px; }
.auth-title-sm { font-weight: 800; font-size: 26px; }
.otp-input { font-size: 24px; letter-spacing: 8px; }
/* display:block matters for a non-<button> element using this class (e.g. an <a> "Batal"
   link) — <a> defaults to display:inline, where the width rule below is simply ignored by
   CSS (width only applies to block/inline-block elements), so pairing it with a <button>
   that had width:100% via inline-block's own default made the two look mismatched even
   though both nominally had "100%" width set. */
.btn-block-lg { display: block; width: 100%; font-size: 17px; text-align: center; }

/* --- Home/browse post cards --- */
.post-card-media { position: relative; aspect-ratio: 4/3; overflow: hidden; }
.grid-span-all { grid-column: 1 / -1; }
.empty-state-title { color: var(--muted); font-weight: 700; font-size: 18px; }
.empty-state-text { color: var(--muted); font-weight: 700; }
.line-clamp-2 {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  line-height: 1.3;
  min-height: 2.6em;
}

/* --- My Listings --- */
.pet-card-row { flex-direction: row; }
.pet-thumb-list { width: 120px; aspect-ratio: 1; flex-shrink: 0; overflow: hidden; }
/* Icon-only CTA buttons on a listing card (_MyAnimalItems.cshtml) — round, pastel-tinted per
   action, matching the mobile app's own icon row. title="" attributes on each carry the label
   for hover/screen-reader discoverability now that there's no visible text. */
.btn-icon-circle {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  padding: 0;
  font-size: 16px;
  flex-shrink: 0;
}
.btn-icon-view    { background: color-mix(in srgb, #6c757d 15%, #fff); color: #6c757d; }
.btn-icon-history { background: color-mix(in srgb, #fd7e14 15%, #fff); color: #fd7e14; }
.btn-icon-edit    { background: color-mix(in srgb, #0dcaf0 18%, #fff); color: #0dcaf0; }
.btn-icon-bump    { background: color-mix(in srgb, #fd7e14 18%, #fff); color: #fd7e14; }
.btn-icon-extend  { background: color-mix(in srgb, #198754 15%, #fff); color: #198754; }
.btn-icon-sold    { background: color-mix(in srgb, #d63384 15%, #fff); color: #d63384; }
.btn-icon-pay     { background: var(--pri); color: #fff; }
.btn-icon-delete  { background: color-mix(in srgb, #dc3545 15%, #fff); color: #dc3545; }
/* Legend above the listing cards (MyAnimals/Index.cshtml) — same per-action colors as the
   btn-icon-* circles above (minus the circle/background), so each legend entry visually
   matches the CTA icon it explains. */
.legend-icon-view    { color: #6c757d; }
.legend-icon-history { color: #fd7e14; }
.legend-icon-edit    { color: #0dcaf0; }
.legend-icon-bump    { color: #fd7e14; }
.legend-icon-extend  { color: #198754; }
.legend-icon-sold    { color: #d63384; }
.legend-icon-pay     { color: var(--pri); }
.legend-icon-delete  { color: #dc3545; }
/* --- "Riwayat" workflow timeline (MyAnimals/_WorkflowHistory.cshtml) — a connected dot+line
   per entry. The rail's line uses flex stretch (the row's default align-items) to always
   match its content's height, so it connects cleanly into the next dot regardless of whether
   that entry has a Reason line making it taller. */
.workflow-timeline-row { display: flex; gap: 12px; }
.workflow-timeline-rail { display: flex; flex-direction: column; align-items: center; width: 12px; flex-shrink: 0; }
.workflow-timeline-dot { width: 12px; height: 12px; border-radius: 50%; flex-shrink: 0; margin-top: 4px; }
.workflow-timeline-line { flex: 1; width: 2px; background: #EADFD6; margin: 2px 0; }
.workflow-timeline-content { flex: 1; padding-bottom: 18px; }
/* Ajax status message (MyAnimals/Index.cshtml) — fixed to the viewport (below the sticky
   navbar, z-index 1020) rather than the page flow, so it stays visible even if the user has
   scrolled down a long listings page — collapses to nothing when empty since fixed elements
   don't reserve layout space. */
.ajax-status-fixed {
  position: fixed;
  top: 76px;
  left: 16px;
  right: 16px;
  z-index: 1040;
  max-width: 560px;
  margin: 0 auto;
}
/* Bootstrap's own .alert-dismissible default already places .btn-close top-right, but pinned
   explicitly here so it's guaranteed regardless of Bootstrap version/defaults. */
.ajax-status-fixed .alert-dismissible {
  padding-right: 3rem;
}
.ajax-status-fixed .alert-dismissible .btn-close {
  position: absolute;
  top: .75rem;
  right: .75rem;
  /* Bootstrap's own alert-dismissible padding (1.25rem 1rem) makes the button tall enough
     that the X glyph renders centered within it rather than hugging the top — overriding it
     smaller here keeps the glyph itself visually pinned to the corner. */
  padding: .5rem;
}

/* --- Notifications --- */
.notification-item { border-radius: 16px; text-decoration: none; color: inherit; background: #fff; }
.notification-item.notification-unread { background: var(--cream); }
.notification-dot { width: 10px; height: 10px; border-radius: 50%; margin-top: 6px; flex-shrink: 0; background: transparent; }
.notification-dot.notification-dot-unread { background: var(--pri); }

/* --- Payment / QRIS --- */
.qr-image { width: 240px; height: 240px; margin: 0 auto; display: block; border-radius: 16px; }
.text-brand { color: var(--pri); }
/* White card just around the QR + save-QR button (Payment/Qris.cshtml) — distinct from the
   page's own cream background, unlike .auth-card this isn't meant to wrap the whole page. */
.qr-card { background: #fff; border-radius: 24px; padding: 24px; box-shadow: 0 8px 24px rgba(0, 0, 0, .05); }
.countdown-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--pri);
  color: #fff;
  font-weight: 800;
  border-radius: 999px;
  padding: .5rem 1.25rem;
}
.countdown-pill-expired { background: var(--muted); }

/* --- Post a listing form — photo tiles sit in a Bootstrap .row/.col grid (see
   PostAnimal/Form.cshtml) rather than fixed pixel sizes, so they scale up on wider
   screens and stay reasonably sized (not tiny) on small devices. --- */
.photo-keep-img { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; border-radius: 12px; display: block; margin-bottom: 4px; }
/* Small white circle + shadow behind Bootstrap's plain X icon — the shared "close" look used
   for the photo-upload grid's remove buttons, the Animal Detail lightbox's close button, and
   the Home click-to-preview popup's close button (site-wide "X to close" visual language). */
.btn-close-circle { background-color: #fff; background-size: 10px; border-radius: 50%; padding: 4px; box-shadow: 0 2px 6px rgba(0, 0, 0, .25); }
/* Pins .btn-close-circle to the corner of whatever it overlays (photo tile / lightbox image).
   z-index matters specifically for the Animal Detail lightbox reuse (_DetailContent.cshtml)
   — there the button sits *before* the carousel in the DOM, so without an explicit z-index the
   carousel/image (default stacking order) paints over it despite being position: absolute. Not
   used by the Home popup's close button, which sits inline in a flex topbar instead. */
.photo-remove-btn { position: absolute; top: -6px; right: -6px; z-index: 5; }
/* --- Shared pill badge for a photo tile's bottom-edge label — "Utama" on the first new
   photo (reinforcing the helper text below the grid, "Foto pertama adalah foto utama") and
   the species-check rejection tag below both sit in the same spot and only differ by color,
   so the color is the one thing each modifier sets. --- */
.photo-badge-label {
  position: absolute;
  bottom: 4px;
  left: 2px;
  right: 2px;
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  text-align: center;
  padding: 1px 2px;
  border-radius: 4px;
  line-height: 1.3;
}
.photo-primary-label { background: var(--pri); }
/* --- Photo that failed the species check — shown right in the grid (not just named in a
   text warning) so the user recognizes their own photo instead of reading a filename. --- */
.photo-rejected .photo-keep-img { border: 2px solid #dc3545; opacity: .6; }
.photo-rejected-label { background: rgba(220, 53, 69, .9); }
.photo-add-tile {
  /* No explicit width here — it's a Bootstrap column itself (col-6/col-md-4/col-lg-3),
     so its width must come from Bootstrap's grid CSS, not this rule (a same-specificity
     width here, loaded after Bootstrap's stylesheet, would win the cascade and stretch
     this tile to 100% of the row instead of matching its column). aspect-ratio alone
     keeps it square at whatever width the grid resolves to. */
  aspect-ratio: 1 / 1;
  border: 2px dashed #EADFD6;
  border-radius: 12px;
  background: var(--cream);
  color: var(--muted);
  font-size: 28px;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.photo-add-tile:hover { border-color: var(--pri); color: var(--pri); }
.photo-add-tile:disabled { opacity: .5; cursor: not-allowed; }
.photo-add-tile:disabled:hover { border-color: #EADFD6; color: var(--muted); }

/* --- Terms & Conditions modal (PostAnimal/Form.cshtml) — embeds the API's
   layout-free /api/terms page, since it's a standalone chrome-free document. --- */
.terms-modal-iframe { width: 100%; height: 70vh; border: 0; display: block; }

/* --- Profile hub --- */
.chip-label { width: fit-content; }

/* --- Announcement modal --- */
.announcement-modal-content { border-radius: 22px; overflow: hidden; border: none; }
.announcement-close-btn { top: 14px; right: 14px; z-index: 10; background: #fff; border-radius: 50%; padding: 8px; }
.announcement-slide-img { width: 100%; display: block; }

/* --- Animal Detail (Animal/Detail.cshtml) — single-column, mobile-app-style layout: a
   full-bleed image gallery up top (a Bootstrap carousel with indicators for multi-photo
   posts, counter overlaid on top) followed by info sections, ending with the "Hubungi
   Pemilik" CTA in normal flow at the bottom of the post. Capped at 560px and centered so
   it still reads the same way on wide desktop viewports. */
.detail-shell { max-width: 560px; margin: 0 auto; padding-bottom: 32px; }
/* Home's click-to-preview popup (#postDetailModal) reuses the exact same Detail content, but
   narrower than the standalone page (.detail-shell above) — a preview popup reads better compact
   than at full-page width. */
.detail-popup-dialog { max-width: 420px; }
/* .detail-popup-frame hugs the visible card tightly (unlike .modal-dialog itself, which
   .modal-dialog-centered stretches to the full modal viewport height) — position: relative
   here is what lets the close button anchor to the card's own corner instead of the top of
   that invisible tall box. Height-capping + internal scroll is reimplemented here with vh
   units instead of Bootstrap's own .modal-dialog-scrollable (which needs .modal-content to
   be a percentage-height child of .modal-dialog — a chain this wrapper would otherwise break).
   isolation: isolate forces a real stacking-context boundary here — without it, the close
   button's z-index: 20 is only *supposed* to beat .modal-content's entire subtree regardless of
   nesting depth (a plain sibling z-index comparison, per spec), but in practice the fetched
   gallery's carousel image was still winning clicks in the corner where the two overlap.
   Bootstrap's own .carousel-item carries backface-visibility: hidden by default — the same
   property that already caused unexpected compositing/stacking behavior elsewhere in this
   codebase — so rather than chase why that's promoting the image above a plain z-index:auto
   ancestor, isolate makes the comparison unambiguous: nothing inside .modal-content can outrank
   a sibling at this level no matter what's happening in its own compositing. */
.detail-popup-frame { position: relative; isolation: isolate; }
.detail-popup-dialog .modal-content { max-height: 78vh; overflow: hidden; }
.detail-popup-dialog .modal-body { overflow-y: auto; }
/* Pokes slightly past the popup's top-right corner — same "half on/half off the edge" badge
   treatment as .photo-remove-btn (lightbox close button, photo-upload tiles). Not clipped
   here because it's a sibling of .modal-content, outside its own overflow: hidden. Back to
   .btn-close's own default sizing — the enlarged hit-box tried earlier is no longer needed now
   that the click-to-close is verified against this button's actual bounding rect directly (see
   the capture-phase listener in Home/Index.cshtml), regardless of its size. */
.detail-popup-close-btn { position: absolute; top: -6px; right: -6px; z-index: 20; }
.detail-gallery { position: relative; aspect-ratio: 4/3; background: #fff; overflow: hidden; }
/* Bootstrap's carousel/carousel-inner/carousel-item size to their image's natural height by
   default — stretch them to fill .detail-gallery's fixed aspect-ratio box instead, same as
   the plain single-image case (.img-cover already fills 100%/100% with object-fit: cover). */
.detail-gallery.carousel,
.detail-gallery .carousel-inner,
.detail-gallery .carousel-item { height: 100%; }
/* Home's click-to-preview popup toggles this on "Perbesar" instead of opening a nested
   lightbox (see initAnimalDetailGallery's toggleRatioInPlace option) — the box itself keeps
   its fixed 4:3 size (so the popup never resizes/jumps on toggle), only how the photo fits
   inside it changes: cropped to fill (default) vs. shown in full, letterboxed against a black
   backdrop instead of cropped. */
.detail-gallery-original { background: #000; }
.detail-gallery-original img { object-fit: contain; }
.gallery-counter {
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 3;
  background: rgba(0, 0, 0, .55);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  padding: .2rem .6rem;
  border-radius: 999px;
}
.gallery-expand-btn {
  position: absolute;
  bottom: 12px;
  right: 12px;
  z-index: 3;
  width: 34px;
  height: 34px;
  border-radius: 8px;
  border: none;
  background: rgba(0, 0, 0, .45);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 15px;
}
/* Bootstrap's carousel controls span the full height of the carousel by default (top: 0;
   bottom: 0;), which overlaps the corner buttons layered on top of it — Perbesar at the
   bottom-right always, and, when this gallery loads inside Home's click-to-preview popup,
   that popup's own close button poking in from the top-right too. A click landing in that
   overlap zone reached the carousel control underneath instead of the button on top of it
   regardless of z-index (z-index only wins ties within the same stacking context, and getting
   every ancestor's stacking context right is fragile) — shortening the controls so they never
   reach those corners at all sidesteps the problem instead of fighting to win it. */
.detail-gallery .carousel-control-prev,
.detail-gallery .carousel-control-next { top: 46px; bottom: 46px; }
/* "Perbesar" lightbox (Animal/Detail.cshtml) — a dark full-size viewer for the same photo
   set. Its own carousel (#lightboxCarousel) keeps the indicators visible there too, so
   switching photos still works the same way as the small gallery above. Uses object-fit:
   contain (unlike the small gallery's cropped object-fit: cover) so the full photo is
   always visible rather than cropped to fill a fixed aspect ratio. */
.lightbox-modal-content { background: #000; border: none; position: relative; }
/* Same reasoning as .detail-gallery above — clears the close button's corner at the top. */
.lightbox-modal-content .carousel-control-prev,
.lightbox-modal-content .carousel-control-next { top: 46px; }
.lightbox-img { width: 100%; max-height: 80vh; object-fit: contain; display: block; }
.detail-title { font-size: 26px; }
.detail-status-badge { font-size: 13px; padding: .4rem .9rem; flex-shrink: 0; }
.detail-date-pill {
  display: inline-flex;
  align-items: center;
  width: fit-content;
  background: color-mix(in srgb, var(--pri) 14%, #fff);
  color: var(--pri);
  font-weight: 700;
  font-size: 13px;
  padding: .4rem .9rem;
  border-radius: 999px;
}
.detail-contact-box { background: var(--cream); border-radius: 16px; }
.detail-contact-icon {
  width: 64px;
  height: 64px;
  border-radius: 12px;
  flex-shrink: 0;
  background: color-mix(in srgb, var(--pri) 16%, #fff);
  color: var(--pri);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
}
.detail-section-title { font-size: 18px; font-weight: 800; }
#detail-description-text { font-size: 14px; }
/* Plain inline text link, not a real button — sits right after the truncated Description. */
.detail-read-more-btn { background: none; border: none; padding: 0; font: inherit; font-size: 14px; font-weight: 700; color: var(--pri); cursor: pointer; }
.detail-read-more-btn:hover { text-decoration: underline; }
.detail-contact-btn { width: 100%; display: flex; align-items: center; justify-content: center; }
/* Plain centered text link (no pill background) beneath the Hubungi Pemilik button. Also
   applied to a <button> (opens the "Laporkan" modal for a signed-in user, vs. a plain <a> to
   Login for an anonymous one — see _DetailContent.cshtml) — strip the browser's default button
   chrome so both render identically. */
.detail-report-link { color: #dc3545; font-weight: 700; }
.detail-report-link:hover { color: color-mix(in srgb, #dc3545 80%, #000); }
button.detail-report-link { background: none; border: none; padding: 0; font: inherit; cursor: pointer; }

/* --- "Laporkan" overlay (#reportModal, _DetailContent.cshtml) — a plain custom overlay, not a
   real Bootstrap-*driven* .modal (see the markup comment for why: it needs to stay open
   *alongside* #postDetailModal on Home's popup, which Bootstrap's Modal component doesn't
   reliably support for two simultaneous instances). It still carries the `modal` class purely
   for Bootstrap's CSS custom properties (--bs-modal-header-padding etc., only ever defined on
   .modal — see the markup comment), which is exactly why this override needs to be scoped to
   #reportModal specifically rather than a bare `.report-overlay` class selector: `.modal`'s own
   `display: none` is the same specificity as a plain class, and this needs to win unconditionally
   rather than depend on site.css happening to load after bootstrap.css. .report-overlay-open is
   toggled by site.js instead of Bootstrap's .show. Positioned/backdropped the same way
   Bootstrap's own .modal/.modal-backdrop would be, at a higher z-index so it always sits on top
   of Home's #postDetailModal (1055) and its own backdrop (1050). Always `display: flex` (never
   toggled to `none`) so the flip transition below can actually play in both directions.
   visibility: hidden (delayed until the opacity transition finishes, so it doesn't cut the close
   animation short) is a second, independent guarantee against accidentally-interactive content
   while closed, on top of opacity + pointer-events — this covers this element sitting centered
   over the *entire* viewport at all times (open or not), directly on top of whatever else is
   there (Home's #postDetailModal close button, most visibly), where even one descendant
   somewhere still resolving to an effective pointer-events: auto would be enough to silently
   swallow clicks meant for what's underneath. */
#reportModal.report-overlay {
  position: fixed;
  inset: 0;
  z-index: 1060;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity .35s ease, visibility 0s linear .35s;
}
#reportModal.report-overlay.report-overlay-open {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity .35s ease, visibility 0s linear;
}
.report-overlay-backdrop { position: absolute; inset: 0; background: rgba(0, 0, 0, .5); }
/* The dialog's own flip, independent of the backdrop fade above. `perspective()` is folded into
   the same transform rather than set as a separate property on an ancestor, since this only ever
   needs to apply to this one dialog. transform: none (not rotateY(0deg)) at rest below is
   mathematically identical but slightly more correct — no lingering non-default transform value
   once settled. */
#reportModal .modal-dialog {
  position: relative;
  z-index: 1;
  transition: transform 1.1s cubic-bezier(.22, .68, .18, 1.1), opacity .35s ease .15s;
  transform: perspective(1600px) rotateY(100deg);
  opacity: 0;
}
/* .report-overlay is always display:flex/centered even while "closed" (opacity 0 + rotated —
   see above), which keeps .modal-content sitting in the middle of the viewport at all times, not
   just while open. Bootstrap's own .modal-content { pointer-events: auto; } re-enables clicks on
   it regardless of that — meaning this invisible, closed dialog was still intercepting clicks
   meant for whatever's underneath (Home's #postDetailModal close button, most visibly, since
   both sit roughly centered near the top of the viewport). Only interactive while actually open. */
#reportModal .modal-content { pointer-events: none; }
#reportModal.report-overlay-open .modal-content { pointer-events: auto; }
#reportModal.report-overlay-open .modal-dialog {
  transform: none;
  opacity: 1;
}
/* Applied (by initAnimalDetailReport, site.js) to whichever card is currently "behind" the
   flipping report modal — Home's preview popup dialog, or the standalone Detail page's own
   content wrapper — for as long as #reportModal is open, then removed again once it's fully
   hidden (Batal, the header's × close, backdrop click, Esc — any dismissal, since removing the
   class is what actually reverses the transform below back to its normal resting state, no
   separate "reverse" logic needed). Hinged on its own right edge (transform-origin) and
   translated left as it rotates, so the exit unambiguously reads as swinging away right-to-left
   — rotateY's sign alone reads ambiguously depending on viewing angle/mental model, the
   translateX is what actually pins the direction down. Same duration as #reportModal above.
   !important on transition/transform/opacity is load-bearing, not defensive: on Home's popup
   this class lands on #postDetailModal's own .modal-dialog, which already matches Bootstrap's
   `.modal.fade .modal-dialog` / `.modal.show .modal-dialog { transform: none; }` — both 2-3
   classes deep, comfortably beating this single-class selector on specificity alone, so without
   !important Bootstrap's own rules silently win and this transform never visibly applies. */
.detail-flip-recede {
  transition: transform 1.1s cubic-bezier(.22, .68, .18, 1.1), opacity .35s ease !important;
  transform-origin: right center;
  transform: perspective(1600px) translateX(-60px) rotateY(-80deg) !important;
  opacity: 0 !important;
}
