/* ============================================================
   Vodegero — Mobile layer.

   Loaded LAST, after layout.css. This is the only file that may
   override the desktop cascade, and it exists because tokens/ and
   styles.css are copied verbatim from the design system and must
   never be hand-edited (see VODEGERO-UI.md). Anything a phone needs
   that contradicts a token lives here, not upstream.

   Two kinds of query, deliberately not interchangeable:

     @media (pointer: coarse)     capability — touch target floors and
                                  the 16px control font. A touchscreen
                                  laptop gets these and should.
     @media (max-width: 900px)    layout — the mobile chrome: tab bar,
                                  bottom sheets, card tables. 900px is
                                  where .vg-topnav__links already
                                  collapsed, so nav has exactly one
                                  switchover point.

   Everything is token-driven; no hard-coded colour.
   ============================================================ */

:root {
  /* Mobile chrome metrics. --vg-safe-b is the home-indicator inset;
     it resolves to 0px everywhere that has no notch, so it is always
     safe to add. */
  --vg-safe-b: env(safe-area-inset-bottom, 0px);
  --vg-safe-t: env(safe-area-inset-top, 0px);
  --vg-safe-l: env(safe-area-inset-left, 0px);
  --vg-safe-r: env(safe-area-inset-right, 0px);

  --vg-tabbar-h: 56px;
  /* Total space the tab bar steals from the bottom of the page. */
  --vg-tabbar-total: calc(var(--vg-tabbar-h) + var(--vg-safe-b));

  /* The WCAG 2.5.5 / iOS HIG floor. Android Material says 48; 44 is the
     binding minimum and what we hold every interactive control to. */
  --vg-touch: 44px;

  /* Stacking bands for mobile chrome. A page-level fixed bar (e.g. the detail
     page's inquire CTA) belongs BELOW --z-tabbar and should clear the tab bar
     geometrically with `bottom: var(--vg-tabbar-total)` — not by outranking
     it. A bar that covers the tab bar strands the user on that page. */
  --z-pagebar: 45;
  --z-tabbar: 55;
  --z-scrim: 59;
  --z-drawer: 60;
}

/* ------------------------------------------------------------
   Viewport height

   min-height:100vh is wrong on mobile: iOS resolves 100vh against the
   viewport with the URL bar RETRACTED, so a 100vh shell is always
   taller than what you can see and the page gains a phantom scroll.
   dvh tracks the bar as it collapses. Guarded by @supports so old
   browsers keep the vh value rather than falling back to auto.
   ------------------------------------------------------------ */
@supports (height: 100dvh) {
  .vg-body { min-height: 100dvh; }
  .vg-admin { min-height: 100dvh; }
  .vg-auth { min-height: 100dvh; }
  .vg-admin__side { height: 100dvh; }
}

/* ------------------------------------------------------------
   Touch input hygiene
   ------------------------------------------------------------ */
@media (pointer: coarse) {
  /* Grey flash on tap. We supply our own :active feedback. */
  a, button, [role="button"], .vg-btn, .vg-icon-btn, .vg-tag, .vg-check, .vg-switch {
    -webkit-tap-highlight-color: transparent;
  }

  /* ---- iOS focus zoom ----------------------------------------
     Safari force-zooms the viewport when a focused control's font is
     under 16px, and never zooms back out. --text-base is 14px, so
     EVERY field on the site did this. 16px is the threshold, not a
     preference — do not lower it.

     The correct fix is the font size. Do NOT reach for
     `maximum-scale=1` / `user-scalable=no` on the viewport meta: that
     stops the zoom by banning pinch-zoom outright, which fails
     WCAG 1.4.4.
     ------------------------------------------------------------ */
  .vg-input,
  .vg-input--bare,
  .vg-select,
  .vg-topnav__search input,
  textarea,
  input[type="text"],
  input[type="search"],
  input[type="email"],
  input[type="password"],
  input[type="number"],
  input[type="tel"],
  input[type="url"],
  input[type="date"] {
    font-size: 16px;
  }

  /* ---- Touch target floors -----------------------------------
     Padding, not height: a min-height alone leaves the hit area
     centred on a short glyph in some engines. These are the controls
     that sat under 44px.
     ------------------------------------------------------------ */
  .vg-btn { min-height: var(--vg-touch); }
  .vg-btn--sm { min-height: var(--vg-touch); padding-block: 10px; }

  .vg-icon-btn { width: var(--vg-touch); height: var(--vg-touch); }
  .vg-icon-btn--sm { width: var(--vg-touch); height: var(--vg-touch); }
  .vg-icon-btn--lg { width: 48px; height: 48px; }

  .vg-pagination__link { min-width: var(--vg-touch); height: var(--vg-touch); }
  .vg-tabs__tab { min-height: var(--vg-touch); }
  .vg-tag { min-height: 36px; }
  a.vg-tag, button.vg-tag, .vg-tag--interactive { min-height: var(--vg-touch); }

  /* The checkbox/switch glyphs stay their designed size; the LABEL is
     the hit area, so grow that instead and keep the visual identical. */
  .vg-check, .vg-switch { min-height: var(--vg-touch); }

  .vg-input-wrap__toggle { width: var(--vg-touch); height: var(--vg-touch); margin-right: -8px; }
  .vg-toast__close { width: 40px; height: 40px; margin: -8px -8px 0 0; }
  .vg-alert__close { width: 40px; height: 40px; margin: -8px -8px 0 0; }
  .vg-tag__remove { width: 32px; height: 32px; margin-right: -6px; }
  .vg-footer__link { min-height: 36px; display: flex; align-items: center; }
}

/* ------------------------------------------------------------
   Hover is a lie on touch

   A tap satisfies :hover on touch browsers and the state STICKS until
   you tap elsewhere — so every lift/shadow/tint fires on press and
   stays. Neutralise them where there is no real pointer rather than
   rewriting components.css, which keeps the desktop cascade honest.
   ------------------------------------------------------------ */
@media (hover: none) {
  .vg-btn--primary:hover:not(:disabled),
  .vg-btn--accent:hover:not(:disabled),
  .vg-btn--danger:hover:not(:disabled) { transform: none; }

  .vg-btn--secondary:hover:not(:disabled) { background: var(--surface-card); }
  .vg-btn--ghost:hover:not(:disabled) { background: transparent; }

  .vg-card--interactive:hover { box-shadow: var(--shadow-xs); transform: none; }
  .vg-listing-card:hover { box-shadow: var(--shadow-xs); transform: none; }

  .vg-icon-btn--ghost:hover:not(:disabled),
  .vg-icon-btn--secondary:hover:not(:disabled) { background: transparent; }
  .vg-icon-btn--secondary:hover:not(:disabled) { background: var(--surface-card); }

  .vg-topnav__link:hover { background: transparent; color: var(--text-secondary); }
  .vg-topnav__link.is-active:hover { background: var(--sand-100); color: var(--text-heading); }
  .vg-table tbody tr:hover { background: transparent; }
  a.vg-tag:hover, button.vg-tag:hover, .vg-tag--interactive:hover { background: var(--surface-warm); }
  .vg-pagination__link:hover { background: transparent; color: var(--text-secondary); }
  .vg-footer__link:hover { color: var(--text-secondary); }

  /* Tooltips are hover-only, so on touch they are either invisible or —
     worse — stuck open after a tap. Every .vg-tip in the app carries an
     aria-label, so dropping the bubble loses nothing. */
  .vg-tip::after { display: none; }

  /* Press feedback has to carry the whole affordance now. */
  .vg-btn:active:not(:disabled) { transform: var(--press-scale); }
  .vg-icon-btn:active:not(:disabled) { transform: var(--press-scale); }
  .vg-listing-card:active { transform: var(--press-scale); }
}

/* ------------------------------------------------------------
   Bottom tab bar — the primary mobile nav.

   Replaces the hamburger below 900px: thumb-reachable, always
   visible, no hidden menu.
   ------------------------------------------------------------ */
.vg-tabbar { display: none; }

@media (max-width: 900px) {
  .vg-tabbar {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: var(--z-tabbar);
    display: flex;
    align-items: stretch;
    height: var(--vg-tabbar-total);
    /* The bar's own background must run UNDER the home indicator, so
       pad rather than shrink. */
    padding-bottom: var(--vg-safe-b);
    background: rgba(251, 248, 242, 0.92);
    backdrop-filter: blur(12px);
    border-top: 1px solid var(--border-warm);
  }

  .vg-tabbar__item {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    min-width: 0;
    padding: 6px 4px;
    border: none;
    background: transparent;
    color: var(--text-muted);
    font-family: var(--font-body);
    font-size: var(--text-3xs);
    font-weight: var(--fw-semibold);
    text-decoration: none;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: var(--transition-color);
  }
  .vg-tabbar__item:hover { text-decoration: none; }
  .vg-tabbar__item .vg-icon { color: currentColor; }
  .vg-tabbar__label {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    letter-spacing: 0.01em;
  }

  .vg-tabbar__item.is-active { color: var(--brand-primary); }
  .vg-tabbar__item:active { background: var(--sand-100); }

  /* The conversion CTA. It reads as a tab, not a button, but the gold
     mark makes it the one thing on the bar with weight — it was
     `vg-hide-sm` (invisible on phones) before this. */
  .vg-tabbar__item--cta .vg-tabbar__icon-wrap {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 26px;
    border-radius: var(--radius-pill);
    background: var(--brand-accent);
    color: var(--brand-accent-ink);
    box-shadow: var(--shadow-gold);
  }
  .vg-tabbar__item--cta { color: var(--text-heading); }

  /* Give the page back the space the fixed bar covers, or the footer
     and the last card sit under it forever. */
  .vg-body { padding-bottom: var(--vg-tabbar-total); }

  /* Toasts must clear the bar. */
  .vg-toast-region {
    bottom: calc(var(--vg-tabbar-total) + var(--space-3));
    left: var(--space-3);
    right: var(--space-3);
  }
  .vg-toast { width: auto; max-width: none; }
}

/* Admin and auth are task shells, not browse surfaces: their layouts render
   no tab bar and their <body> carries no .vg-body, so neither the bar nor its
   body padding reaches them. Nothing to opt out of here. */

/* ------------------------------------------------------------
   Top nav on mobile

   The hamburger and its dropdown are gone below 900px; the tab bar
   owns navigation. What is left is brand + search, which is what a
   marketplace top bar should be.
   ------------------------------------------------------------ */
@media (max-width: 900px) {
  .vg-topnav__inner {
    height: 58px;
    gap: var(--space-3);
    padding-left: calc(var(--gutter) + var(--vg-safe-l));
    padding-right: calc(var(--gutter) + var(--vg-safe-r));
  }
  .vg-topnav__toggle { display: none; }
  .vg-topnav__links { display: none; }
  .vg-topnav__links.is-open { display: none; }
  .vg-topnav__wordmark { display: none; }
  .vg-topnav__brand img { height: 30px; }
  .vg-topnav__search { padding: 7px 14px; }

  /* Sign-in/bell/avatar live in the Account tab now. */
  .vg-topnav__actions { display: none; }
}

@media (max-width: 900px) {
  /* Sticky offsets keyed to the shorter bar. */
  .vg-topnav { top: 0; }
}

/* ------------------------------------------------------------
   Bottom sheets

   .vg-dialog stays a native <dialog> — only the presentation changes.
   Anchoring to the bottom puts the controls under the thumb instead of
   at the top of a phone held one-handed.
   ------------------------------------------------------------ */
@media (max-width: 900px) {
  .vg-dialog {
    align-items: flex-end;
    padding: 0;
  }

  .vg-dialog__panel,
  .vg-dialog__panel--sm,
  .vg-dialog__panel--lg {
    max-width: none;
    width: 100%;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    /* Not 100dvh: leaving a strip of scrim visible signals "this
       dismisses" and keeps the sheet from reading as a new page. */
    max-height: 92dvh;
    animation: vg-sheet-up var(--dur-slow) var(--ease-out);
  }

  /* Drag handle. Decorative — the sheet is dismissible by scrim tap,
     Escape, the close button, and swipe. */
  .vg-dialog__panel::before {
    content: "";
    display: block;
    width: 36px;
    height: 4px;
    flex: none;
    margin: 10px auto 0;
    border-radius: var(--radius-pill);
    background: var(--ink-200);
  }

  .vg-dialog__head { padding: 14px var(--space-5) 0; }
  .vg-dialog__body { padding: var(--space-4) var(--space-5); }

  /* A sheet with no foot ends on its body, so the body owes the home
     indicator its clearance. */
  .vg-dialog__panel:not(:has(.vg-dialog__foot)) .vg-dialog__body {
    padding-bottom: calc(var(--space-4) + var(--vg-safe-b));
  }

  .vg-dialog__foot {
    padding: var(--space-4) var(--space-5);
    /* Clear the home indicator; the foot is the lowest thing on screen. */
    padding-bottom: calc(var(--space-4) + var(--vg-safe-b));
    /* Actions stack full-width — side-by-side buttons on a 360px screen
       are both too narrow to read and too small to hit. */
    flex-direction: column-reverse;
    gap: var(--space-2);
  }
  .vg-dialog__foot .vg-btn { width: 100%; }

  /* Sheet being dragged down by touch. Transform is set inline by JS. */
  .vg-dialog__panel.is-dragging { animation: none; transition: none; }
  .vg-dialog__panel.is-settling { animation: none; transition: transform var(--dur-base) var(--ease-out); }
}

@keyframes vg-sheet-up {
  from { transform: translateY(100%); }
  to { transform: none; }
}

/* ------------------------------------------------------------
   Drawers — scroll lock

   Set by JS on <body> while a drawer or sheet is open. position:fixed
   is the only approach iOS Safari actually honours; overflow:hidden
   alone does not stop the scroll chain there. JS stores and restores
   the scroll offset around it.
   ------------------------------------------------------------ */
body.vg-scroll-locked {
  position: fixed;
  width: 100%;
  overflow: hidden;
  /* top is set inline by JS to -{scrollY}px so the page does not jump. */
}

/* Stop a scrolled-to-end drawer from chaining its scroll to the page. */
.vg-admin__side,
.vg-browse__filters,
.vg-dialog__body {
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}

/* ------------------------------------------------------------
   Admin shell on mobile
   ------------------------------------------------------------ */
@media (max-width: 900px) {
  .vg-admin__topbar {
    padding-left: calc(var(--space-4) + var(--vg-safe-l));
    padding-right: calc(var(--space-4) + var(--vg-safe-r));
    gap: var(--space-2);
  }
  .vg-admin__main {
    padding-left: calc(var(--space-4) + var(--vg-safe-l));
    padding-right: calc(var(--space-4) + var(--vg-safe-r));
    padding-bottom: calc(var(--space-9) + var(--vg-safe-b));
  }
  .vg-admin__side {
    padding-bottom: var(--vg-safe-b);
    width: min(300px, 86vw);
  }

  /* Breadcrumbs are a desktop wayfinding device; on a phone they eat the
     bar and wrap. The page title in .vg-page-head already says where
     you are. */
  .vg-admin__topbar .vg-breadcrumb a,
  .vg-admin__topbar .vg-breadcrumb .vg-breadcrumb__sep { display: none; }

  .vg-page-head { gap: var(--space-3); margin-bottom: var(--space-5); }
  .vg-page-head__title { font-size: var(--text-2xl); }
  /* A page action next to a wrapped title looks accidental. Full-width
     reads as intentional and is easier to hit. */
  .vg-page-head > .vg-row { width: 100%; }
  .vg-page-head > .vg-row > .vg-btn { flex: 1; }
}

/* ------------------------------------------------------------
   Tables → card list

   Below 900px the admin tables (10 columns) stop being tables. This is
   pure CSS keyed off data-label on each <td>, which matters: the
   client-side search/filter/pagination scripts toggle rows with
   `row.style.display = '' | 'none'`, and clearing the inline value
   hands control back to whichever display THIS layer specifies. The JS
   is untouched and works in both modes.
   ------------------------------------------------------------ */
@media (max-width: 900px) {
  .vg-table-wrap--cards {
    overflow-x: visible;
    border: none;
    background: transparent;
  }
  .vg-table-wrap--cards .vg-table { display: block; }
  .vg-table-wrap--cards .vg-table thead { display: none; }
  .vg-table-wrap--cards .vg-table tbody { display: flex; flex-direction: column; gap: var(--space-3); padding: var(--space-3); }

  .vg-table-wrap--cards .vg-table tbody tr {
    display: block;
    background: var(--surface-card);
    border: 1px solid var(--border-cool);
    border-radius: var(--radius-card);
    padding: var(--space-4);
    box-shadow: var(--shadow-xs);
  }

  /* The `hidden` attribute is only a UA-sheet `display: none`, so the author
     `display: block` above beats it and the row stays visible. The pagination
     scripts hide the "no matches" row with `.hidden = true`, so without this
     it renders permanently on mobile. */
  .vg-table-wrap--cards .vg-table tbody tr[hidden] { display: none; }

  /* Row state that the card background would otherwise erase. This file loads
     last, so `tr { background: var(--surface-card) }` wins over the equal-
     specificity `.is-unread` rule in the page — restate it here. */
  .vg-table-wrap--cards .vg-table tbody tr.is-unread {
    background: var(--blue-50);
    border-color: var(--blue-200);
  }
  /* The unread marker is an inset bar on the first cell — fine as a row edge
     in table mode, but mid-card once cells stack. Move it to the card. */
  .vg-table-wrap--cards .vg-table tbody tr.is-unread td:first-child { box-shadow: none; }
  .vg-table-wrap--cards .vg-table tbody tr.is-unread { box-shadow: inset 3px 0 0 var(--brand-primary), var(--shadow-xs); }

  .vg-table-wrap--cards .vg-table tbody td {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    padding: 6px 0;
    border-bottom: none;
    text-align: left;
  }

  /* The label the <thead> used to carry, restored per cell. */
  .vg-table-wrap--cards .vg-table tbody td::before {
    content: attr(data-label);
    flex: none;
    font-family: var(--eyebrow-font);
    font-size: var(--text-3xs);
    letter-spacing: var(--eyebrow-track);
    text-transform: uppercase;
    color: var(--text-muted);
    font-weight: var(--fw-medium);
  }
  .vg-table-wrap--cards .vg-table__num { text-align: right; }

  /* Multi-line values (a breakdown, a wrapped snippet). The td is a
     space-between flex row, so loose sibling nodes would be strewn across it —
     wrap them in one .vg-cell-lines and the row stays label | value. */
  .vg-table-wrap--cards .vg-cell-lines {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 2px;
    min-width: 0;
    text-align: right;
  }

  /* The name is the card heading: full width, no label, top of card. */
  .vg-table-wrap--cards .vg-table tbody td.vg-cell-title {
    display: block;
    padding-top: 0;
    padding-bottom: var(--space-3);
    margin-bottom: var(--space-2);
    border-bottom: 1px solid var(--border-cool);
  }
  .vg-table-wrap--cards .vg-table tbody td.vg-cell-title::before { content: none; }
  .vg-table-wrap--cards .vg-cell-strong { font-size: var(--text-lg); }

  /* Actions become a real row of buttons at the card foot. */
  .vg-table-wrap--cards .vg-table tbody td.vg-cell-actions {
    display: block;
    padding-top: var(--space-3);
    margin-top: var(--space-2);
    border-top: 1px solid var(--border-cool);
    width: auto !important;
  }
  .vg-table-wrap--cards .vg-table tbody td.vg-cell-actions::before { content: none; }
  .vg-table-wrap--cards .vg-table__actions { justify-content: flex-start; gap: var(--space-2); }

  /* The empty/no-match rows are full-bleed messages, not cards. */
  .vg-table-wrap--cards .vg-table tbody tr.vg-row-message {
    background: transparent;
    border: none;
    box-shadow: none;
    padding: 0;
  }
  .vg-table-wrap--cards .vg-table tbody tr.vg-row-message td { display: block; padding: 0; }
  .vg-table-wrap--cards .vg-table tbody tr.vg-row-message td::before { content: none; }

  /* Toolbar filters stack; each control gets the full width. */
  .vg-toolbar { flex-direction: column; align-items: stretch; padding-inline: var(--space-4); }
  .vg-toolbar__search { min-width: 0; }
  .vg-table-foot { padding-inline: var(--space-4); justify-content: center; }
  .vg-table-foot .vg-pagination { flex-wrap: wrap; justify-content: center; }
}

/* ------------------------------------------------------------
   Auth shell on mobile
   ------------------------------------------------------------ */
@media (max-width: 900px) {
  .vg-auth__form-pane {
    padding: calc(var(--space-6) + var(--vg-safe-t))
             calc(var(--space-5) + var(--vg-safe-r))
             calc(var(--space-6) + var(--vg-safe-b))
             calc(var(--space-5) + var(--vg-safe-l));
  }
  .vg-auth__title { font-size: var(--text-3xl); }
  .vg-auth__body { justify-content: flex-start; padding-top: var(--space-7); }
  /* Sign in is the one thing on this screen; it should not be a 42px
     target floating next to the fold. */
  .vg-auth__body .vg-btn--primary { width: 100%; min-height: 48px; }
}

/* ------------------------------------------------------------
   Public page chrome
   ------------------------------------------------------------ */
@media (max-width: 900px) {
  .vg-container {
    padding-left: calc(var(--gutter) + var(--vg-safe-l));
    padding-right: calc(var(--gutter) + var(--vg-safe-r));
  }
  .vg-page { padding-block: var(--space-6) var(--space-8); }
  .vg-page--tight { padding-block: var(--space-5) var(--space-7); }

  .vg-footer__inner { padding-block: var(--space-7) var(--space-5); }
  .vg-footer__bar { padding-bottom: calc(var(--space-5) + var(--vg-safe-b)); }
}

@media (max-width: 640px) {
  /* Display type set for a 1240px canvas overflows a 360px one. */
  .vg-h1 { font-size: var(--text-3xl); }
  .vg-h2 { font-size: var(--text-2xl); }
  .vg-h3 { font-size: var(--text-xl); }
  .vg-lede { font-size: var(--text-md); }
  .vg-stat__value { font-size: var(--text-2xl); }

  .vg-container { --gutter: var(--space-4); }

  /* Cards get an edge-to-edge feel without losing the gutter. */
  .vg-card { padding: var(--space-5); }
  .vg-card--pad-lg { padding: var(--space-5); }

  /* Card foot actions stack rather than crowd. */
  .vg-card__foot { flex-direction: column-reverse; align-items: stretch; }
  .vg-card__foot .vg-btn { width: 100%; }

  /* .vg-btn is `white-space: nowrap` with no shrink escape, so a long label
     pushes the page sideways at 360px. A full-width button has somewhere to
     wrap to, so let it. */
  .vg-btn--block { white-space: normal; }

  .vg-empty { padding: var(--space-8) var(--space-4); }
}

/* ------------------------------------------------------------
   Motion
   ------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  .vg-dialog__panel { animation: none; }
  .vg-dialog__panel.is-settling { transition: none; }
}
