/* =====================================================================
   TripMate - site chrome: header, navigation, footer, dashboard shell.
   ===================================================================== */

/* ---- Header ------------------------------------------------------ */
.site-header {
  position: sticky; top: 0; z-index: 100;
  /* Deliberately opaque rather than a frosted translucent bar: a sticky
     backdrop-filter re-blurs the full strip on every scroll frame, and the
     effect is invisible against these near-white surfaces anyway. */
  background: var(--surface);
  border-bottom: 1px solid var(--line-200);
  min-height: var(--header-h);
  transition: box-shadow var(--transition);
}
.site-header__inner {
  display: flex; align-items: center;
  gap: var(--sp-5); min-height: var(--header-h);
}

/* ---- Brand mark ---------------------------------------------------
   The logo is a single wide lockup (pin + wordmark + tagline) at roughly
   3:1, so it is sized by height and left to derive its own width.
   object-fit: contain guarantees it is never stretched, whatever box the
   surrounding layout gives it. */
.logo { display: inline-flex; align-items: center; flex-shrink: 0; min-width: 0; }
.logo__img {
  height: 46px; width: auto; max-width: 100%;
  object-fit: contain; object-position: left center;
  transition: transform var(--transition);
}
.logo:hover .logo__img { transform: scale(1.03); }
/* The footer sits on navy, where the lockup's own navy "Trip" would vanish.
   A white plate behind the mark keeps every part of it legible and, unlike
   a brightness/invert filter, preserves the pin illustration and the orange
   instead of flattening the whole lockup into a white silhouette. */
.logo--footer {
  background: var(--surface);
  border-radius: var(--r-md);
  padding: var(--sp-3) var(--sp-4);
}
.logo--footer .logo__img { height: 46px; }
.logo--footer:hover .logo__img { transform: none; }

@media (max-width: 980px) { .logo__img { height: 40px; } }
@media (max-width: 380px) { .logo__img { height: 34px; } }

/* ---- Primary nav -------------------------------------------------
   Centred between the wordmark and the account controls, with the active
   item marked by an underline rule rather than a filled pill: quieter, and
   it survives sitting on the translucent bar. */
.nav { display: flex; align-items: center; gap: var(--sp-1); margin-inline: auto; }
.nav__link {
  position: relative;
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: .6rem .85rem; border-radius: var(--r-sm);
  color: var(--ink-700); font-weight: 600; font-size: var(--fs-sm);
  white-space: nowrap; transition: color var(--transition);
}
.nav__link::after {
  content: ""; position: absolute; left: .85rem; right: .85rem; bottom: .15rem;
  height: 2px; border-radius: 2px; background: var(--coral-600);
  transform: scaleX(0); transform-origin: left; opacity: 0;
  transition: transform var(--transition), opacity var(--transition);
}
.nav__link:hover { color: var(--navy-900); }
.nav__link:hover::after { transform: scaleX(1); opacity: .35; }
.nav__link.is-active { color: var(--navy-900); }
.nav__link.is-active::after { transform: scaleX(1); opacity: 1; }

.header__actions { display: flex; align-items: center; gap: var(--sp-2); flex-shrink: 0; }
.header__actions .btn--outline { border-color: transparent; background: transparent; }
.header__actions .btn--outline:hover:not(:disabled) { background: var(--surface-3); border-color: transparent; color: var(--navy-900); }

/* ---- Dropdown ---------------------------------------------------- */
.dropdown { position: relative; }
.dropdown__toggle {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  background: none; border: 1px solid var(--line-300); border-radius: var(--r-pill);
  padding: .3rem .7rem .3rem .3rem; cursor: pointer; font: inherit; color: var(--ink-700);
  min-height: 44px;
}
.dropdown__toggle:hover { border-color: var(--teal-600); }
.dropdown__menu {
  position: absolute; right: 0; top: calc(100% + 8px); min-width: 220px;
  max-width: min(320px, calc(100vw - var(--sp-5)));
  background: var(--surface); border: 1px solid var(--line-200);
  border-radius: var(--r-md); box-shadow: var(--shadow-lg);
  padding: var(--sp-2); z-index: 110;
  /* Animate both open and close: transform + opacity glide in, and a delayed
     visibility keeps the panel reachable until the close transition ends. */
  opacity: 0; visibility: hidden; pointer-events: none;
  transform: translateY(-6px) scale(.98); transform-origin: top right;
  transition: opacity 150ms ease, transform 200ms cubic-bezier(.2, .8, .25, 1), visibility 0s linear 200ms;
}
.dropdown__menu.is-open {
  opacity: 1; visibility: visible; pointer-events: auto; transform: none;
  transition: opacity 150ms ease, transform 220ms cubic-bezier(.2, .8, .25, 1);
}
.dropdown__item {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: .6rem .75rem; border-radius: var(--r-sm);
  color: var(--ink-700); font-size: var(--fs-sm); font-weight: 500;
  width: 100%; background: none; border: 0; cursor: pointer; text-align: left; font-family: inherit;
  transition: background var(--transition), color var(--transition);
}
.dropdown__item:hover { background: var(--surface-3); color: var(--navy-900); }
.dropdown__item--danger { color: var(--danger-600); }
.dropdown__item--danger:hover { background: var(--danger-100); color: var(--danger-600); }
.dropdown__divider { height: 1px; background: var(--line-200); margin: var(--sp-2) 0; }
.dropdown__header { padding: var(--sp-3) var(--sp-3) var(--sp-2); border-bottom: 1px solid var(--line-200); margin-bottom: var(--sp-2); }
.dropdown__header strong { display: block; color: var(--navy-900); font-size: var(--fs-sm); }
.dropdown__header small { color: var(--ink-500); }
@media (prefers-reduced-motion: reduce) {
  .dropdown__menu { transition: opacity 120ms ease, visibility 0s linear 120ms; transform: none; }
  .dropdown__menu.is-open { transition: opacity 120ms ease; transform: none; }
}

.avatar {
  width: 34px; height: 34px; border-radius: 50%; object-fit: cover;
  background: var(--sky-100); color: var(--teal-700);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: var(--fs-xs); font-weight: 700; flex-shrink: 0;
  overflow: hidden;
}
.avatar--lg { width: 72px; height: 72px; font-size: var(--fs-lg); }
.avatar--xl { width: 112px; height: 112px; font-size: var(--fs-2xl); }

/* When an upload 404s the browser paints the alt text inside the box, which
   overflows the circle and pushes everything under it out of alignment —
   one dead image visibly breaks a whole row of cards. Zeroing the font on
   the <img> hides that fallback text while leaving the alt attribute intact
   for assistive technology; the tinted box reads as a missing portrait.
   The rule is scoped to img so the initials <span> variant keeps its text. */
img.avatar, .agency-card__logo, .thumb { font-size: 0; text-indent: -9999px; }

/* ---- Notification bell ------------------------------------------- */
.bell { position: relative; background: none; border: 0; cursor: pointer; padding: var(--sp-2); border-radius: var(--r-md); color: var(--ink-700); min-width: 44px; min-height: 44px; }
.bell:hover { background: var(--surface-3); }
.bell__dot {
  position: absolute; top: 4px; right: 4px; min-width: 18px; height: 18px;
  padding: 0 4px; border-radius: var(--r-pill);
  background: var(--tm-accent); color: var(--tm-on-accent);
  font-size: 10px; font-weight: 700; line-height: 18px; text-align: center;
}
.notif-list { max-height: 380px; overflow-y: auto; }
.notif-item {
  display: block; padding: var(--sp-3); border-bottom: 1px solid var(--line-200);
  color: var(--ink-700); /* stop the <a> inheriting the blue link colour */
}
.notif-item:last-child { border-bottom: 0; }
.notif-item:hover { background: var(--surface-2); }
/* Unread: soft tint plus a left accent so it reads at a glance. */
.notif-item.is-unread { background: var(--sky-100); box-shadow: inset 3px 0 0 var(--teal-600); }
.notif-item strong {
  display: block; font-size: var(--fs-sm); font-weight: 600; color: var(--navy-900);
  line-height: 1.35; margin-bottom: 2px; overflow-wrap: anywhere;
}
/* Body + timestamp each on their own line (they were inline and collided). */
.notif-item span {
  display: block; font-size: var(--fs-xs); color: var(--ink-700);
  line-height: 1.45; margin-bottom: var(--sp-1); overflow-wrap: anywhere;
}
.notif-item small { display: block; font-size: var(--fs-xs); color: var(--ink-500); }

/* ---- Mobile menu ------------------------------------------------- */
.nav-toggle {
  display: none; background: none; border: 1px solid var(--line-300);
  border-radius: var(--r-md); cursor: pointer; padding: .6rem;
  width: 44px; height: 44px; align-items: center; justify-content: center;
}
.nav-toggle span { display: block; width: 20px; height: 2px; background: var(--navy-900); position: relative; transition: background var(--transition); }
.nav-toggle span::before, .nav-toggle span::after {
  content: ""; position: absolute; left: 0; width: 20px; height: 2px; background: var(--navy-900);
  transition: transform var(--transition), top var(--transition);
}
.nav-toggle span::before { top: -6px; }
.nav-toggle span::after { top: 6px; }
.nav-toggle[aria-expanded="true"] span { background: transparent; }
.nav-toggle[aria-expanded="true"] span::before { top: 0; transform: rotate(45deg); }
.nav-toggle[aria-expanded="true"] span::after { top: 0; transform: rotate(-45deg); }

@media (max-width: 980px) {
  .nav-toggle { display: inline-flex; }
  /* .nav is taken out of flow below, so the remaining three controls need
     the old spread back to sit at the two ends of the bar. */
  .site-header__inner { justify-content: space-between; gap: var(--sp-3); }
  .nav {
    position: fixed; inset: var(--header-h) 0 auto 0;
    flex-direction: column; align-items: stretch; gap: 0;
    background: var(--surface); border-bottom: 1px solid var(--line-200);
    padding: var(--sp-3); box-shadow: var(--shadow-lg);
    max-height: calc(100vh - var(--header-h)); overflow-y: auto;
    transform: translateY(-12px); opacity: 0; pointer-events: none;
    transition: transform var(--transition), opacity var(--transition);
  }
  .nav.is-open { transform: none; opacity: 1; pointer-events: auto; }
  .nav__link { padding: var(--sp-3); border-radius: var(--r-sm); font-size: var(--fs-base); }
  /* Only one auth button fits beside the hamburger at this width. Show Log in
     rather than Sign up: it is the returning visitor's action, and Sign up is
     still one tap away through the "Create an account" line on the login page.
     The button also needs a visible frame here, because its desktop header
     style is a borderless ghost that would read as plain text when it is the
     only control on the bar. */
  .header__actions .btn--primary { display: none; }
  .header__actions .btn--outline,
  .header__actions .btn--outline:hover:not(:disabled) {
    display: inline-flex;
    background: var(--tm-surface);
    border-color: var(--tm-border-strong);
    color: var(--tm-primary);
  }
}

/* At the narrowest supported width the brand mark and the account controls
   cannot both keep their natural size. The lockup is allowed to shrink to a
   share of the bar rather than being hidden, so the brand stays visible.
   (This replaced a rule that hid the old separate .logo__text wordmark; the
   wordmark now lives inside the logo image itself.) */
@media (max-width: 360px) {
  .site-header__inner { gap: var(--sp-2); }
  .logo { max-width: 46vw; }
  .logo__img { height: 32px; }
}

/* ---- Footer ------------------------------------------------------ */
.site-footer {
  background: var(--navy-900); color: #A8B8D0;
  padding-top: var(--sp-8); margin-top: var(--sp-8);
  position: relative;
}
/* Hairline of brand colour where the page meets the footer. */
.site-footer::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 3px;
  background: linear-gradient(90deg, var(--teal-600), var(--sky-400) 45%, var(--coral-500));
  opacity: .8;
}
.site-footer h4 {
  color: #fff; font-size: var(--fs-xs); margin-bottom: var(--sp-4);
  text-transform: uppercase; letter-spacing: .12em; font-weight: 700;
}
.site-footer a { color: #A8B8D0; font-size: var(--fs-sm); }
.site-footer a:hover { color: #fff; }
.site-footer .logo, .site-footer .logo:hover { color: #fff; }
.footer__grid {
  display: grid; grid-template-columns: 1.7fr repeat(3, 1fr);
  gap: var(--sp-6) var(--sp-5); padding-bottom: var(--sp-7);
}
.footer__links { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: var(--sp-1); }
/* Links get a real touch target and a small travel-in on hover. */
.footer__links a {
  display: inline-block; padding: .3rem 0;
  transition: color var(--transition), transform var(--transition);
}
.footer__links a:hover { transform: translateX(3px); }
.footer__about { font-size: var(--fs-sm); max-width: 36ch; color: #8EA0BC; line-height: 1.65; }
.footer__bottom {
  border-top: 1px solid rgba(255,255,255,.1); padding: var(--sp-5) 0;
  display: flex; justify-content: space-between; align-items: center; gap: var(--sp-3);
  flex-wrap: wrap; font-size: var(--fs-sm); color: #8095B4;
}
@media (max-width: 860px) {
  .footer__grid { grid-template-columns: repeat(2, 1fr); gap: var(--sp-6) var(--sp-5); }
  /* The brand blurb reads as an intro, so it spans both columns above them. */
  .footer__grid > :first-child { grid-column: 1 / -1; }
  .footer__about { max-width: 52ch; }
}
@media (max-width: 480px) {
  .footer__grid { grid-template-columns: 1fr; gap: var(--sp-5); }
  .footer__bottom { flex-direction: column; text-align: center; }
}

/* ---- Newsletter --------------------------------------------------
   Deliberately quiet: a bordered ivory panel rather than another
   full-bleed gradient competing with the hero and the footer. */
.newsletter {
  /* Warm cream here and on the assistant promo, to break the run of cool
     white panels without tinting whole sections. */
  background: var(--tm-surface-warm);
  border: 1px solid #F5E2D0;
  border-radius: var(--r-xl);
  padding: var(--sp-7) var(--sp-6);
  text-align: center;
  position: relative; overflow: hidden;
}
.newsletter::before {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(ellipse 70% 120% at 50% 0%, rgba(255, 201, 120, .28), transparent 70%);
  pointer-events: none;
}
.newsletter .input { background: var(--surface); border-color: #EED9C4; }
.newsletter > * { position: relative; }
.newsletter h2 { color: var(--navy-900); font-size: var(--fs-2xl); }
.newsletter p { color: var(--ink-500); max-width: 52ch; margin-inline: auto; }
.newsletter__form { display: flex; gap: var(--sp-2); max-width: 460px; margin: var(--sp-5) auto 0; flex-wrap: wrap; }
.newsletter__form .input { flex: 1; min-width: 220px; }
@media (max-width: 520px) {
  .newsletter { padding: var(--sp-6) var(--sp-4); }
  .newsletter__form .btn { width: 100%; }
}

/* ---- Dashboard shell --------------------------------------------- */
.dash { display: grid; grid-template-columns: 250px 1fr; min-height: calc(100vh - var(--header-h)); align-items: start; }
.dash__sidebar {
  background: var(--surface); border-right: 1px solid var(--line-200);
  padding: var(--sp-5) var(--sp-3);
  position: sticky; top: var(--header-h); max-height: calc(100vh - var(--header-h)); overflow-y: auto;
}
.dash__main { padding: var(--sp-6) var(--sp-5); min-width: 0; }
/* The authenticated side of the product is more application than editorial:
   page titles stay in the UI sans and work harder at small sizes. Scoped to
   the shell rather than to .dash__head, because five dashboard pages put
   their <h1> directly in .dash__main and would otherwise keep the serif. */
.dash__head { margin-bottom: var(--sp-6); }
.dash h1 {
  font-family: var(--font-sans);
  font-weight: 700; font-size: var(--fs-2xl); letter-spacing: -0.02em;
}
.dash__head h1 { margin-bottom: var(--sp-1); }
.dash__head p { color: var(--ink-500); margin: 0; }

.side-nav { list-style: none; padding: 0; margin: 0 0 var(--sp-5); display: flex; flex-direction: column; gap: 2px; }
.side-nav__label {
  font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .11em;
  color: var(--ink-400); font-weight: 700; padding: var(--sp-4) var(--sp-3) var(--sp-2);
}
.side-nav__link {
  display: flex; align-items: center; gap: var(--sp-3);
  position: relative;
  padding: .65rem .8rem; border-radius: var(--r-md);
  color: var(--ink-700); font-weight: 600; font-size: var(--fs-sm);
  transition: background var(--transition), color var(--transition);
}
.side-nav__link:hover { background: var(--surface-3); color: var(--navy-900); }
/* A tinted row with a brand rail, rather than a heavy filled slab: it keeps
   the sidebar calm when a dashboard has twelve of these. */
.side-nav__link.is-active { background: var(--sky-100); color: var(--teal-700); }
.side-nav__link.is-active::before {
  content: ""; position: absolute; left: 0; top: 20%; bottom: 20%;
  width: 3px; border-radius: 0 3px 3px 0; background: var(--teal-600);
}
.side-nav__link .count {
  margin-left: auto; background: var(--tm-accent); color: var(--tm-on-accent);
  border-radius: var(--r-pill); font-size: 11px; padding: 1px 7px; font-weight: 700;
}
.side-nav__link.is-active .count { background: var(--tm-accent); color: var(--tm-on-accent); }

.dash-toggle { display: none; }

/* The backdrop is a sibling of .dash__sidebar inside the .dash grid. It must
   be taken out of flow at every width, or it claims the first grid column and
   pushes the sidebar and main content into the wrong tracks. */
.dash__backdrop {
  position: fixed; inset: 0; background: rgba(16, 35, 63, .45);
  z-index: 114; display: none;
}

@media (max-width: 900px) {
  .dash { grid-template-columns: 1fr; }
  .dash__sidebar {
    position: fixed; inset: var(--header-h) auto 0 0; width: 270px; z-index: 115;
    transform: translateX(-100%); transition: transform var(--transition);
    box-shadow: var(--shadow-lg); max-height: none; height: calc(100vh - var(--header-h));
  }
  .dash__sidebar.is-open { transform: none; }
  .dash-toggle { display: inline-flex; margin-bottom: var(--sp-4); }
  .dash__main { padding: var(--sp-4) var(--sp-3); }
  .dash__backdrop.is-open { display: block; }
}

/* ---- Stat cards -------------------------------------------------- */
.stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: var(--sp-4); margin-bottom: var(--sp-5); }
.stat {
  background: var(--surface); border: 1px solid var(--line-200);
  border-radius: var(--r-lg); padding: var(--sp-5); box-shadow: var(--shadow-sm);
  position: relative; overflow: hidden;
}
.stat__label { font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .1em; color: var(--ink-500); font-weight: 700; margin-bottom: var(--sp-3); }
.stat__value {
  font-size: clamp(1.6rem, 1.4rem + .7vw, 2rem); font-weight: 700;
  color: var(--navy-900); line-height: 1.1; letter-spacing: -0.025em;
}
.stat__meta { font-size: var(--fs-sm); color: var(--ink-500); margin-top: var(--sp-2); }
/* The accent is a top rail rather than a thick left border, so a row of
   stat cards keeps a common left edge with everything below it. */
.stat--accent, .stat--teal, .stat--success, .stat--warning { border-left: 0; }
.stat--accent::before, .stat--teal::before, .stat--success::before, .stat--warning::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 3px;
}
.stat--accent::before  { background: var(--coral-600); }
.stat--teal::before    { background: var(--teal-600); }
.stat--success::before { background: var(--success-600); }
.stat--warning::before { background: var(--warning-600); }

/* ---- Panels ------------------------------------------------------ */
.panel { background: var(--surface); border: 1px solid var(--line-200); border-radius: var(--r-lg); box-shadow: var(--shadow-sm); margin-bottom: var(--sp-5); overflow: hidden; }
.panel__head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); padding: var(--sp-4) var(--sp-5); border-bottom: 1px solid var(--line-200); flex-wrap: wrap; background: var(--surface-2); }
.panel__head h2, .panel__head h3 {
  margin: 0; font-size: var(--fs-base); font-family: var(--font-sans);
  font-weight: 700; letter-spacing: -0.008em;
}
.panel__body { padding: var(--sp-5); }
.panel__body--flush { padding: 0; }

/* ---- Filter bar -------------------------------------------------- */
.filters { background: var(--surface); border: 1px solid var(--line-200); border-radius: var(--r-lg); padding: var(--sp-5); margin-bottom: var(--sp-5); box-shadow: var(--shadow-sm); }
.filters__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--sp-4); }
.filters__actions { display: flex; gap: var(--sp-3); margin-top: var(--sp-4); flex-wrap: wrap; align-items: center; }
.filters .field { margin-bottom: 0; }
.filters .label { font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .08em; color: var(--ink-500); }
.filters__toggle { display: none; }
@media (max-width: 700px) {
  /* On mobile the filter set is a disclosure: one full-width control that
     opens the grid, so the results stay the first thing on screen. */
  .filters { padding: var(--sp-4); }
  /* The toggle holds only its label, so it stays centred: space-between
     would strand the text on the left of a full-width button. */
  .filters__toggle { display: inline-flex; width: 100%; justify-content: center; }
  /* Collapse the fields only in a filter bar that actually ships a toggle to
     reopen them. admin/users.php has a .filters block with no toggle, and the
     unconditional rule left its Search / Role / Status fields hidden on
     mobile with Apply and Reset still live above them — filtering by
     controls you cannot see. Browsers without :has() simply keep the fields
     visible, which is the safe direction to fail in. */
  .filters:has(.filters__toggle) .filters__grid { display: none; }
  /* Must carry the same :has() prefix as the rule above, or the collapse
     rule outranks it on specificity and the toggle stops opening. */
  .filters:has(.filters__toggle) .filters__grid.is-open,
  .filters__grid.is-open { display: grid; margin-top: var(--sp-4); gap: var(--sp-3); }
  .filters__actions .btn { flex: 1; }
}

/* ---- Mobile card-style tables ------------------------------------ */
@media (max-width: 720px) {
  .table--cards thead { display: none; }
  .table--cards tbody tr {
    display: block; border: 1px solid var(--line-200); border-radius: var(--r-md);
    margin-bottom: var(--sp-3); padding: var(--sp-2); background: var(--surface);
  }
  .table--cards td { display: flex; justify-content: space-between; gap: var(--sp-3); border: 0; padding: var(--sp-2); text-align: right; }
  .table--cards td::before {
    content: attr(data-label); font-weight: 700; color: var(--ink-500);
    text-align: left; flex-shrink: 0; font-size: var(--fs-xs);
    text-transform: uppercase; letter-spacing: .05em;
  }
  .table--cards td.numeric { text-align: right; }
}

/* ---- Assistant floating button (rendered site-wide by footer.php) -- */
.assistant-fab {
  position: fixed; right: var(--sp-4); bottom: var(--sp-4); z-index: 90;
  display: inline-flex; align-items: center; gap: var(--sp-2);
  background: var(--tm-accent); color: var(--tm-on-accent);
  padding: .8rem 1.2rem; border: 0; border-radius: var(--r-pill);
  box-shadow: var(--shadow-lg); font-family: inherit; font-weight: 600; font-size: var(--fs-sm);
  cursor: pointer;
  transition: background var(--transition), transform var(--transition);
}
.assistant-fab:hover { background: var(--tm-accent-hover); color: var(--tm-on-accent); transform: translateY(-2px); }
@media (max-width: 560px) {
  .assistant-fab span { display: none; }
  .assistant-fab { padding: .9rem; border-radius: 50%; }
}

/* The button is fixed over the bottom-right corner, so without this the
   last card in a dashboard or sidebar is permanently half-covered. Reserve
   its height at the end of the scrollable content instead. */
.dash__main, .planner-layout, .page-main { padding-bottom: calc(var(--sp-8) + 3rem); }
