/* ==========================================================================
   Reepy — mobile and app shell
   --------------------------------------------------------------------------
   Loaded after style.css. Kept in its own file rather than appended to the main
   sheet so the app layer can be reasoned about, cached and versioned on its own,
   and so the webview shell added later has one place to look.

   Everything here uses the existing theme tokens (--surface, --border, --text,
   --primary and so on). Nothing hard-codes a colour, because the site ships six
   themes and a fixed hex would be unreadable in half of them.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Safe areas
   Notched phones report insets through env(). Reading them costs nothing on a
   device without a notch, where every inset resolves to 0.
   -------------------------------------------------------------------------- */
:root {
  --app-safe-top:    env(safe-area-inset-top, 0px);
  --app-safe-bottom: env(safe-area-inset-bottom, 0px);
  --app-safe-left:   env(safe-area-inset-left, 0px);
  --app-safe-right:  env(safe-area-inset-right, 0px);
  --app-tabbar-h:    58px;
}

/* --------------------------------------------------------------------------
   Bottom tab bar
   -------------------------------------------------------------------------- */
.app-tabbar {
  display: none;
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 1040;
  background: var(--surface);
  border-top: 1px solid var(--border);
  padding-bottom: var(--app-safe-bottom);
  /* Opaque rather than translucent: a blurred bar over a scrolling table reads
     as a rendering glitch on low-end devices. */
}

.app-tab {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-height: var(--app-tabbar-h);
  padding: 6px 2px;
  color: var(--text-muted);
  text-decoration: none;
  font-size: .68rem;
  line-height: 1.1;
  text-align: center;
  /* Kills the grey flash Android paints on tap, which looks broken next to a
     custom active state. */
  -webkit-tap-highlight-color: transparent;
}

.app-tab i { font-size: 1.15rem; }
.app-tab span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.app-tab:hover { color: var(--text); }
.app-tab.is-active { color: var(--primary); }
.app-tab.is-active i { transform: translateY(-1px); }

@media (max-width: 991.98px) {
  .app-tabbar { display: flex; }

  /* Give the page back the height the bar covers, or the last row of every
     list ends up permanently unreachable. */
  body { padding-bottom: calc(var(--app-tabbar-h) + var(--app-safe-bottom)); }

  /* The existing sidebar toggle sits exactly where the bar now is. */
  .sidebar-toggle { bottom: calc(var(--app-tabbar-h) + var(--app-safe-bottom) + 12px) !important; }
}

/* --------------------------------------------------------------------------
   App mode
   The webview supplies its own title bar and back gesture, so the marketing
   navbar and footer are dead weight inside it.
   -------------------------------------------------------------------------- */
body.app-mode .navbar,
body.app-mode .reepy-footer { display: none !important; }

body.app-mode .reepy-main { padding-top: var(--app-safe-top); }

/* Pages that print should never carry app chrome. */
@media print {
  .app-tabbar { display: none !important; }
  body { padding-bottom: 0 !important; }
}

/* --------------------------------------------------------------------------
   Touch ergonomics
   Small controls are fine with a mouse and miserable with a thumb.
   -------------------------------------------------------------------------- */
@media (max-width: 767.98px) {
  .btn-sm, .btn-xs { min-height: 38px; padding-inline: .7rem; }
  .form-control, .form-select { min-height: 44px; font-size: 16px; }
  /* 16px is not a style choice: iOS Safari zooms the whole page when a focused
     input is smaller, and the zoom does not reverse cleanly. */

  .form-control-sm, .form-select-sm { min-height: 38px; font-size: 16px; }

  .app-tab, .sidebar-link, .nav-link { touch-action: manipulation; }

  /* Wide tables are the main source of horizontal page scroll on phones.
     Contain the scroll to the table itself. */
  .table-responsive { -webkit-overflow-scrolling: touch; }

  .content-header h1 { font-size: 1.35rem; }
  .card-body { padding: 1rem; }

  /* Action rows that read as a line on desktop and a jumble on a phone. */
  .card-footer.d-flex { row-gap: .5rem; }
}

/* --------------------------------------------------------------------------
   Offline banner, raised by the service worker
   -------------------------------------------------------------------------- */
.app-offline {
  display: none;
  position: fixed;
  left: 0; right: 0;
  top: var(--app-safe-top);
  z-index: 1050;
  padding: .5rem .75rem;
  text-align: center;
  font-size: .8rem;
  background: var(--warning);
  color: #111;
}
body.is-offline .app-offline { display: block; }

/* --------------------------------------------------------------------------
   Install prompt, browser only
   -------------------------------------------------------------------------- */
.app-install-bar {
  display: none;
  align-items: center;
  gap: .75rem;
  padding: .6rem .9rem;
  margin: 0 0 1rem;
  background: var(--surface-2, var(--surface));
  border: 1px solid var(--border);
  border-radius: 10px;
}
.app-install-bar.is-visible { display: flex; }

/* --------------------------------------------------------------------------
   Sidebar clearance
   The drawer is position:fixed with bottom:0, so the tab bar lands directly on
   top of its last rows - which is where Log out lives. Ending the drawer above
   the bar is the fix; body padding does nothing for a fixed element.
   -------------------------------------------------------------------------- */
@media (max-width: 991.98px) {
  .reepy-sidebar {
    bottom: calc(var(--app-tabbar-h) + var(--app-safe-bottom));
    padding-bottom: .5rem;
  }
}

/* --------------------------------------------------------------------------
   Expanding last tab
   -------------------------------------------------------------------------- */
.app-tab.is-open { color: var(--primary); }
.app-tab.is-open i::after {
  content: '';
  position: absolute; bottom: 2px; left: 50%;
  width: 14px; height: 2px; margin-left: -7px;
  background: currentColor; border-radius: 2px;
}
.app-tab { position: relative; background: none; border: 0; }

.app-panel-backdrop {
  position: fixed; inset: 0;
  z-index: 1035;
  background: rgba(0, 0, 0, .5);
}

.app-panel {
  position: fixed;
  left: 0; right: 0;
  bottom: calc(var(--app-tabbar-h) + var(--app-safe-bottom));
  z-index: 1041;
  background: var(--surface);
  border-top: 1px solid var(--border);
  border-radius: 14px 14px 0 0;
  box-shadow: 0 -8px 32px rgba(0, 0, 0, .35);
  /* Capped so the page stays visible behind it: a panel that fills the screen
     is a page, and the person loses their place. */
  max-height: 72vh;
  display: flex;
  flex-direction: column;
  animation: appPanelIn .18s ease-out;
}

@keyframes appPanelIn {
  from { transform: translateY(12px); opacity: 0; }
  to   { transform: translateY(0);    opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .app-panel { animation: none; }
}

.app-panel-grip {
  width: 36px; height: 4px; border-radius: 2px;
  background: var(--border);
  margin: .6rem auto .2rem;
  flex-shrink: 0;
}

.app-panel-scroll {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: .25rem .75rem 1rem;
  overscroll-behavior: contain;
}

.app-panel-group { padding: .35rem 0; }
.app-panel-group + .app-panel-group { border-top: 1px solid var(--border); }

.app-panel-title {
  font-size: .68rem; font-weight: 600; text-transform: uppercase;
  letter-spacing: .05em; color: var(--text-muted);
  padding: .6rem .5rem .3rem;
}

.app-panel-link {
  display: flex; align-items: center; gap: .75rem;
  padding: .7rem .5rem;
  color: var(--text); text-decoration: none;
  font-size: .92rem;
  border-radius: 8px;
  min-height: 44px;
  -webkit-tap-highlight-color: transparent;
}
.app-panel-link:hover,
.app-panel-link:active { background: var(--surface-2); color: var(--text); text-decoration: none; }
.app-panel-link i { width: 20px; font-size: 1.05rem; color: var(--text-muted); }
.app-panel-signout { color: var(--danger); }
.app-panel-signout i { color: var(--danger); }

.app-panel-chips { display: flex; flex-wrap: wrap; gap: .4rem; padding: .25rem .5rem; }
.app-chip {
  padding: .45rem .7rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: transparent;
  color: var(--text);
  font-size: .78rem;
  text-decoration: none;
  min-height: 36px;
}
.app-chip:hover, .app-chip.is-active { border-color: var(--primary); color: var(--primary); text-decoration: none; }

/* Freeze the page behind the open panel. */
body.app-panel-open { overflow: hidden; }

/* --------------------------------------------------------------------------
   Footer
   Two different problems, so two different answers.

   On a dashboard or in app mode the marketing footer is pure noise - the panel
   above already carries everything it linked to, and a column of site links
   under a data table is the single clearest tell that this is a web page.

   On public pages in a mobile browser it stays, collapsed. Removing it there
   would cost the internal links that Google's mobile-first crawler follows;
   collapsing keeps every link in the DOM and takes the wall off the screen.
   -------------------------------------------------------------------------- */
@media (max-width: 991.98px) {
  .dashboard-body .reepy-footer,
  body.app-mode .reepy-footer { display: none !important; }

  .footer-group > summary {
    display: flex; align-items: center; justify-content: space-between;
    list-style: none;
    padding: .85rem .25rem;
    min-height: 44px;
    cursor: pointer;
    border-bottom: 1px solid var(--border);
    -webkit-tap-highlight-color: transparent;
  }
  .footer-group > summary::-webkit-details-marker { display: none; }
  .footer-group > summary h6 { margin: 0; }
  .footer-group > summary::after {
    content: '\f282'; /* bootstrap-icons chevron-down */
    font-family: 'bootstrap-icons';
    font-size: .8rem;
    color: var(--text-muted);
    transition: transform .15s ease;
  }
  .footer-group[open] > summary::after { transform: rotate(180deg); }
  .footer-group > .footer-group-body { padding: .35rem .25rem .75rem; }
  .footer-group ul { margin-bottom: 0; }
  .footer-group li a { display: block; padding: .4rem 0; }
}

/* Desktop keeps the classic footer: no accordion, everything expanded. */
@media (min-width: 992px) {
  .footer-group > summary { list-style: none; pointer-events: none; }
  .footer-group > summary::-webkit-details-marker { display: none; }
}

/* --------------------------------------------------------------------------
   Native form controls on dark themes

   A <select>'s open option list is painted by the operating system, not by the
   page, and it does not inherit the site's colours. On the dark themes that
   produced pale text on a pale panel — visible in the picker, invisible in a
   screenshot of the closed control, and easy to miss for anyone developing on
   the light theme.

   color-scheme is the real fix: it tells the browser this document is dark and
   every native widget - dropdowns, date pickers, scrollbars, autofill - follows.
   The explicit option rules below cover the browsers that honour the property
   only partially.
   -------------------------------------------------------------------------- */
html[data-theme^="dark"]  { color-scheme: dark; }
html[data-theme^="light"] { color-scheme: light; }

html[data-theme^="dark"] select option,
html[data-theme^="dark"] select optgroup,
html[data-theme^="dark"] datalist option {
  background-color: var(--surface);
  color: var(--text);
}

/* Chrome paints autofilled inputs a fixed pale yellow and ignores background-color.
   An inset shadow the size of the field is the one thing it does respect. */
html[data-theme^="dark"] input:-webkit-autofill,
html[data-theme^="dark"] input:-webkit-autofill:hover,
html[data-theme^="dark"] input:-webkit-autofill:focus,
html[data-theme^="dark"] textarea:-webkit-autofill,
html[data-theme^="dark"] select:-webkit-autofill {
  -webkit-text-fill-color: var(--text);
  -webkit-box-shadow: 0 0 0 1000px var(--surface) inset;
  caret-color: var(--text);
  transition: background-color 5000s ease-in-out 0s;
}

/* Placeholder text sits at the same lightness as the field on some themes. */
.form-control::placeholder,
.form-select::placeholder { color: var(--text-muted); opacity: 1; }

/* --------------------------------------------------------------------------
   Collapsible sidebar groups

   The admin area has more than sixty pages. Flat, that is not a menu any more —
   it is a scroll, and an operator ends up typing URLs because reading the list
   is slower. Grouping by the job being done, with everything but the first
   group closed, turns it back into something scannable.

   The group holding the current page opens itself server-side, so the sidebar
   is short by default and still never hides where you are.
   -------------------------------------------------------------------------- */
.sidebar-group { margin: .15rem 0; }

.sidebar-group > summary {
  display: flex;
  align-items: center;
  gap: .65rem;
  padding: .42rem .6rem;
  border-radius: var(--radius-sm, 6px);
  color: var(--text-muted);
  font-size: .8rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  cursor: pointer;
  list-style: none;
  -webkit-tap-highlight-color: transparent;
}
.sidebar-group > summary::-webkit-details-marker { display: none; }
.sidebar-group > summary:hover { background: var(--surface-2); color: var(--text); }
.sidebar-group > summary > i:first-child { width: 18px; font-size: .95rem; }

.sidebar-group-caret {
  margin-left: auto;
  font-size: .7rem;
  transition: transform .15s ease;
}
.sidebar-group[open] > summary { color: var(--text); }
.sidebar-group[open] .sidebar-group-caret { transform: rotate(180deg); }

/* Indent the children so an open group reads as one block rather than as more
   top-level items. The rule marks where the group starts and ends. */
.sidebar-group > .sidebar-link {
  margin-left: .75rem;
  padding-left: .75rem;
  border-left: 1px solid var(--border);
  border-radius: 0 var(--radius-sm, 6px) var(--radius-sm, 6px) 0;
  font-size: .88rem;
}
.sidebar-group > .sidebar-link.active { border-left-color: var(--primary); }

/* A closed group still shows it contains the current page. */
.sidebar-group:not([open]) > summary { position: relative; }

@media (max-width: 991.98px) {
  .sidebar-group > summary { min-height: 44px; }
  .sidebar-group > .sidebar-link { min-height: 40px; }
}


/* ---------- RTL (Phase 72.E): sidebar groups indent from the right ---------- */
[dir="rtl"] .sidebar-group-caret { margin-left: 0; margin-right: auto; }
[dir="rtl"] .sidebar-group > .sidebar-link {
  margin-left: 0; margin-right: .75rem;
  padding-left: .6rem; padding-right: .75rem;
  border-left: 0; border-right: 1px solid var(--border);
  border-radius: var(--radius-sm, 6px) 0 0 var(--radius-sm, 6px);
}
[dir="rtl"] .sidebar-group > .sidebar-link.active { border-right-color: var(--primary); }
