/* STANAGELOG phone fixes, loaded after the main stylesheet. One block per commit. */

/* ── No zoom (commit: lock zoom) ───────────────────────────────────────── */
html, body, a, button, input, select, textarea, label, summary, [role="button"] {
  touch-action: manipulation;
}
/* iOS zooms the page when a field under 16px takes focus. :where() keeps the
   specificity at zero, so rules that already set 16px or more still win. */
@media (max-width: 899px), (pointer: coarse) {
  :where(input, select, textarea):not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]):not([type="hidden"]) {
    font-size: 16px;
  }
  #q, .ios-search input { font-size: 16px !important; }
}

/* ── Fit the screen, no page scroll (commit: fit to screen) ────────────── */
:root { --safe-bottom: env(safe-area-inset-bottom, 0px); }
@media (max-width: 899px) {
  /* There is no bottom bar. The shell fills the screen and keeps the home-indicator gap. */
  .app-shell {
    height: var(--app-height, 100dvh) !important;
    max-height: var(--app-height, 100dvh) !important;
    padding-bottom: var(--safe-bottom);
  }
  /* Pro pages set padding on .app-content instead, so the title can stay pinned. */
  body.page-inventory .content-col { padding-bottom: calc(16px + var(--safe-bottom)) !important; }
  #view-root { padding-bottom: 24px; }
  .toast { bottom: calc(var(--safe-bottom) + 12px) !important; }
}
/* Billing and Recently deleted clipped their content on a phone with no way to scroll to the rest. */
@media (max-width: 899px) {
  body.page-billing .app-content, body.page-deleted .app-content {
    overflow-y: auto !important; overflow-x: hidden; min-height: 0;
    -webkit-overflow-scrolling: touch; overscroll-behavior-y: contain;
  }
}
/* No rubber-banding of the page, and no scroll chaining out of inner scrollers. */
@media (max-width: 899px) {
  html, body { overscroll-behavior: none; }
  .content-col, .app-content, #view-root, .panel-body, .dt-container, .settings-pop,
  .link-status-card, .ios-sheet, .dlg-card, .auth-main {
    overscroll-behavior: contain;
  }
}

/* Sign-in, welcome and club-code pages fit one screen and scroll inside the card area only when they must. */
@media (max-width: 640px) {
  html:has(body.page-auth), body.page-auth {
    height: 100dvh; overflow: hidden; overscroll-behavior: none;
  }
  body.page-auth .auth-wrap { height: 100dvh; min-height: 0; }
  body.page-auth .auth-main {
    min-height: 0; overflow-y: auto; overflow-x: hidden; align-items: flex-start;
    padding: 1rem 1rem calc(1rem + env(safe-area-inset-bottom, 0px));
    -webkit-overflow-scrolling: touch;
  }
  body.page-auth .auth-card { margin: auto 0; }
  /* The nav already shows the wordmark, so the card does not repeat it on a phone. */
  body.page-auth .auth-card > .site-wordmark { display: none; }
}

/* ── Phone header and form fixes (commit: inspect page) ────────────────── */
@media (max-width: 640px) {
  /* Pushed screens (detail, edit, inspect): back at the left, title centred, nothing overlapping.
     Users is in the menu (drawer), so it does not repeat in the header here. */
  body.ios-pushed .ios-nav-bar { justify-content: space-between; padding: 0 8px 0 max(4px, var(--safe-left)); }
  body.ios-pushed .ios-nav-actions { display: none; }
  body.ios-pushed .ios-back { max-width: 40%; flex: 0 1 auto; min-width: 44px; }
  body.ios-pushed .ios-back-label, body.ios-pushed #ios-back-label {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
  }
  body.ios-pushed .ios-nav-title {
    left: 40%; right: 40%; text-align: center; padding: 0 4px;
  }
  /* Edit and new-item screens used a class with no styles, so the heading sat at the screen edge. */
  .ios-hero {
    padding: 4px 16px 14px;
    padding-left: max(16px, var(--safe-left));
    padding-right: max(16px, var(--safe-right));
  }
}
/* Date fields: iOS draws them wider than the card and centres the text. */
input[type="date"], input[type="time"], input[type="datetime-local"] {
  display: block; width: 100%; max-width: 100%; min-width: 0; box-sizing: border-box;
  text-align: left; text-align-last: left;
}
input[type="date"]::-webkit-date-and-time-value,
input[type="time"]::-webkit-date-and-time-value,
input[type="datetime-local"]::-webkit-date-and-time-value { text-align: left; min-width: 0; margin: 0; }
@supports (-webkit-touch-callout: none) {
  input[type="date"], input[type="time"], input[type="datetime-local"] {
    -webkit-appearance: none; appearance: none; min-height: 44px; line-height: normal;
    padding-right: 2.4rem;
    background-repeat: no-repeat; background-position: right 12px center; background-size: 18px 18px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238a8a85' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='5' width='18' height='16' rx='2'/%3E%3Cpath d='M3 10h18M8 3v4M16 3v4'/%3E%3C/svg%3E");
  }
}
/* Tablet-width and landscape: the Users link in the header was the browser's default blue underline. */
.ios-nav-users { color: var(--accent); text-decoration: none; }

/* ── Dark mode and contrast (commit: contrast) ─────────────────────────── */
/* Sign-in code, welcome and sign-in pages in dark mode: the main button was white with white text and
   the code box white with white text. */
html[data-theme="dark"] .hero-btn-primary { background: #ffffff; color: #0a0a0a; }
html[data-theme="dark"] .hero-btn-primary:hover { background: #e8e6e1; color: #000; }
html[data-theme="dark"] .auth-input { background: var(--surface); color: var(--ink); }
html[data-theme="dark"] .auth-foot a { color: #5fa77a; }
html[data-theme="dark"] .welcome-skip { color: var(--muted); }
@media (prefers-color-scheme: dark) {
  html:not([data-theme="light"]) .hero-btn-primary { background: #ffffff; color: #0a0a0a; }
  html:not([data-theme="light"]) .auth-input { background: var(--surface); color: var(--ink); }
  html:not([data-theme="light"]) .auth-foot a { color: #5fa77a; }
}
/* Light mode: the amber, red and faint grey text was under 4.5:1 on white. */
:root:not([data-theme="dark"]) { --warn: #9a5700; --danger: #c42b2b; --fg-faint: #6b6b66; }
:root:not([data-theme="dark"]) .st.st-due,
:root:not([data-theme="dark"]) .st.st-never { color: #8a5300; }
:root:not([data-theme="dark"]) .st.st-overdue,
:root:not([data-theme="dark"]) .st.st-expired { color: #b91c1c; }
/* Dark mode: green links, Edit/Cancel/Back and the OK chip were dark green on near-black. */
[data-theme="dark"] .ios-back,
[data-theme="dark"] .ios-nav-users,
[data-theme="dark"] .ios-btn-plain:not(.ios-btn-danger),
[data-theme="dark"] #btn-edit,
[data-theme="dark"] .st.st-ok,
[data-theme="dark"] .segment button[data-result="pass"].on { color: #5fa77a; }
[data-theme="dark"] .st.st-overdue,
[data-theme="dark"] .st.st-expired { color: #f87171; }
/* 10px labels are bumped to 11px. */
@media (max-width: 899px) {
  .st, .cap, .panel-label.cap, .sec, .filter-label, .kit-row-type, .ios-large-sub, .menu-sec, th { font-size: 11px; }
}

/* ── Tap targets (commit: tap targets) ─────────────────────────────────── */
/* Small buttons keep their look and get an invisible 44px touch area, so nothing moves.
   Short text links grow their padding and give it back with a negative margin, so lines keep their height. */
@media (max-width: 899px) {
  .link-status, #settings-btn, #ios-add-btn, .brand-link, .kit-nav-logo { position: relative; }
  /* The menu button is already absolutely placed by ios-app.css, and that also anchors its touch area. */
  .link-status::after { content: ""; position: absolute; inset: -10px -9px; }
  #settings-btn::after, #ios-add-btn::after, #ham-btn::after { content: ""; position: absolute; inset: -6px -8px; }
  .brand-link::after, .kit-nav-logo::after { content: ""; position: absolute; inset: -11px -6px; }
  body.page-pro .app-content :is(td, dd, li, p, .note) > a:not(.btn):not(.tr-prow),
  a.tr-item, .auth-foot a, a[href="/deleted"] {
    display: inline-block; padding: 13px 6px; margin: -13px -6px;
  }
  label.check, label.pro-check, label:has(> input[type="checkbox"]), label:has(> input[type="radio"]) {
    display: flex; align-items: center; gap: 0.5rem; min-height: 44px;
  }
  input[type="checkbox"], input[type="radio"] { flex: 0 0 auto; width: 20px; height: 20px; accent-color: var(--accent, #1f4d32); }
  .ios-search, .ios-search input, #q { min-height: 44px; }
  .welcome-skip { min-height: 44px; }
}

/* ── Drawer stats contrast (commit: drawer stats) ───────────────────────── */
/* "Total / Attention" labels and counts: hard-coded greys were unreadable on the dark drawer
   (2.5:1) and the red was 3.8:1 on white. */
[data-theme="dark"] .sidebar-stat .sstat-label { color: #b5b5ae; }
[data-theme="dark"] .sidebar-stat .sstat-value { color: #f2f1ee; }
[data-theme="dark"] .sidebar-stat.attn .sstat-label,
[data-theme="dark"] .sidebar-stat.attn .sstat-value { color: #f87171; }
[data-theme="dark"] .nav-item .n, [data-theme="dark"] #nav-inv-count { color: #b5b5ae !important; }
:root:not([data-theme="dark"]) .sidebar-stat.attn .sstat-label,
:root:not([data-theme="dark"]) .sidebar-stat.attn .sstat-value { color: #c42b2b; }
@media (prefers-color-scheme: dark) {
  html:not([data-theme="light"]) .sidebar-stat .sstat-label, html:not([data-theme="light"]) .nav-item .n { color: #b5b5ae; }
  html:not([data-theme="light"]) .sidebar-stat .sstat-value { color: #f2f1ee; }
  html:not([data-theme="light"]) .sidebar-stat.attn .sstat-label,
  html:not([data-theme="light"]) .sidebar-stat.attn .sstat-value { color: #f87171; }
}

/* ── Record inspection fits the screen (commit: inspection fit) ─────────────
   The screen is a column: item line, a body, and Save / Cancel pinned in one row.
   Nothing scrolls on a normal record. Only .insp-body may scroll (keyboard open, a long note). */
body.page-inventory .content-col:has(.insp-fit) {
  display: flex !important; flex-direction: column; overflow: hidden !important; padding: 0 !important;
}
body.page-inventory .content-col:has(.insp-fit) .app-content,
body.page-inventory .content-col:has(.insp-fit) #view-root {
  display: flex !important; flex-direction: column; flex: 1 1 auto !important;
  min-height: 0 !important; overflow: hidden !important; padding: 0 !important;
}
.insp-fit { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.insp-top { flex: 0 0 auto; padding: 0 max(16px, var(--safe-left, 0px)) 6px; }
.insp-item {
  font-size: 14px; line-height: 20px; color: var(--fg-subtle);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.insp-body {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden;
  -webkit-overflow-scrolling: touch; overscroll-behavior: contain;
  padding: 0 max(16px, var(--safe-left, 0px)) 8px;
}
.insp-card {
  display: grid; gap: 8px; padding: 10px 12px;
  background: var(--ios-card, var(--bg-panel, #fff));
  border: 1px solid var(--ios-hairline, var(--border, #e5e2dc)); border-radius: 8px;
}
.insp-row2 { display: grid; grid-template-columns: minmax(0, 1fr) 9.25rem; gap: 8px; }
.insp-fit .row-hidden { display: none !important; }
.insp-f { min-width: 0; }
.insp-f .flabel, .insp-extra .flabel {
  display: block; padding: 0 0 3px; font-size: 12px; line-height: 16px; color: var(--fg-subtle);
}
.insp-f .finput { width: 100%; min-width: 0; height: 44px; min-height: 44px; font-size: 16px; padding: 0 8px; }
.insp-f input[type="date"] { display: flex; align-items: center; }
.insp-f input[type="date"]::-webkit-date-and-time-value { text-align: left; min-height: 1.2em; }
.insp-res .segment { display: flex; width: 100%; }
.insp-res .segment button { flex: 1 1 0; min-height: 44px; padding: 0 4px; }
/* One reserved line for Next check (pass) or Recheck in (monitor); Fail leaves it empty. It never changes height on a pass or fail. */
.insp-extra { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 8px; min-height: 44px; }
.insp-extra .flabel { padding: 0; font-size: 13px; }
.insp-extra .ffield { min-width: 0; flex: 0 1 auto; }
.insp-extra .due-calc { margin-left: 0; font-size: 13px; }
.insp-extra .recheck-row { flex-wrap: nowrap; gap: 6px; }
.insp-extra .recheck-row .psel { width: auto; min-width: 0; max-width: 9.5rem; height: 44px; }
.insp-extra .recheck-row .fnum { width: 4.5rem; height: 44px; }
.insp-notes .ftext {
  display: block; width: 100%; box-sizing: border-box; height: 64px; min-height: 44px; max-height: 40dvh;
  resize: none; overflow-y: auto; font-size: 16px; line-height: 1.35; padding-top: 10px; padding-bottom: 10px;
}
/* The note grows only while you are typing in it. */
.insp-notes .ftext:focus { height: min(140px, 32dvh); }
.insp-actions {
  flex: 0 0 auto; flex-direction: row; gap: 10px; align-items: stretch;
  padding: 10px max(16px, var(--safe-left, 0px)) max(10px, var(--safe-bottom, 0px));
  border-top: 0.5px solid var(--ios-hairline, var(--border, #e5e2dc));
  background: var(--ios-grouped, var(--bg, #faf9f7));
}
.insp-actions .btn { min-height: 48px; margin: 0; justify-content: center; }
.insp-actions #btn-save { flex: 2 1 0; min-width: 0; }
.insp-actions #btn-cancel { flex: 1 1 0; min-width: 0; font-weight: 500; }
@media (max-width: 374px) {
  .insp-row2 { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 340px) {
  .insp-actions #btn-save svg { display: none; }
}
/* Landscape phone: two columns, form on the left, note on the right. */
@media (max-height: 500px) and (min-width: 560px) {
  .insp-card { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: 14px; row-gap: 6px; }
  .insp-row2, .insp-res, .insp-extra { grid-column: 1; }
  .insp-notes { grid-column: 2; grid-row: 1 / span 3; display: flex; flex-direction: column; min-height: 0; }
  .insp-notes .ftext { flex: 1 1 auto; height: auto; max-height: none; }
  .insp-notes .ftext:focus { height: auto; }
  .insp-top { padding-bottom: 2px; }
  .insp-actions { padding-top: 6px; }
}

/* Narrow phones: give the centred header title enough room ("Inspect" was cut to "Inspe…"). */
@media (max-width: 360px) {
  body.ios-pushed .ios-back { max-width: 32%; }
  body.ios-pushed .ios-nav-title { left: 32%; right: 32%; }
}

/* ── Pro pages and the kit list fit the screen (commit: fit pro and list) ──
   The shell stays put. A long pro form scrolls in .app-content; the kit list
   scrolls in #view-root. The title stays pinned. A primary save row sticks
   to the bottom of that scroll area. Desktop (900px and up) is unchanged. */
@media (max-width: 899px) {
  /* LOG PRO: one column, title pinned, the form is the only scroller.
     Selectors are one class deeper than pro.css. That file is linked again
     from the page head, after this sheet, and its overflow/flex use !important. */
  body.page-pro .app-body > .content-col {
    display: flex !important;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden !important;
    padding: 0 !important;
  }
  body.page-pro .app-body > .content-col > .page-head,
  body.page-pro .app-body > .content-col > .page-head h1 {
    flex: 0 0 auto;
  }
  body.page-pro .app-body > .content-col > .page-head {
    display: block;
    margin: 0;
    padding: 2px max(16px, var(--safe-right)) 6px max(16px, var(--safe-left));
  }
  body.page-pro .page-head h1.ios-large-title {
    margin: 0;
    padding: 0;
    font-size: 24px;
    line-height: 28px;
    letter-spacing: -0.4px;
  }
  body.page-pro .page-head .ios-large-sub {
    margin: 0;
    padding: 2px 0 0;
  }
  body.page-pro .content-col > .app-content {
    flex: 1 1 auto !important;
    min-height: 0 !important;
    display: block !important;
    overflow-y: auto !important;
    overflow-x: hidden !important;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    scroll-padding-bottom: 72px;
    padding: 0 max(16px, var(--safe-right)) calc(16px + var(--safe-bottom)) max(16px, var(--safe-left)) !important;
  }
  /* .panel is overflow:hidden, which would trap a sticky save row inside the card.
     Visible lets the row stick to .app-content. Wide tables still scroll in their own box. */
  body.page-pro .app-content .panel { overflow: visible; }
  body.page-pro .content-col #team .panel-body.flush,
  body.page-pro .content-col .dt-wrap {
    overflow-x: auto !important;
    max-width: 100%;
    overscroll-behavior-x: contain;
  }
  /* Last primary action of a pro form, including Save draft and Save daily inspection.
     z-index stays under the confirm-save sheet (200) and the ios-sheet (1000). */
  body.page-pro form[data-confirm-save] > p:last-child:has(> button.btn.primary[type="submit"]),
  body.page-pro form > p:last-child:has(> button.btn.primary[type="submit"]) {
    position: sticky;
    /* The scroller's bottom padding would leave a gap under a bottom:0 bar. */
    bottom: calc(-16px - var(--safe-bottom));
    z-index: 5;
    margin: 12px -0.75rem 0;
    padding: 10px 0.75rem calc(10px + 16px + var(--safe-bottom));
    background: var(--ios-grouped, var(--bg, #faf9f7));
    border-top: 0.5px solid var(--ios-hairline, var(--border, #e5e2dc));
  }

  /* Kit list: the shell and the title, search, and filter stay put.
     #view-root is the only scroller, so the large title can still collapse.
     Pushed detail, edit, and record-inspection screens are left alone. */
  body.page-inventory:not(.ios-pushed) .content-col:not(:has(.insp-fit)) {
    display: flex !important;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden !important;
    padding: 0 !important;
  }
  body.page-inventory:not(.ios-pushed) .content-col:not(:has(.insp-fit)) .page-head,
  body.page-inventory:not(.ios-pushed) .content-col:not(:has(.insp-fit)) .page-head h1 {
    flex: 0 0 auto;
  }
  body.page-inventory:not(.ios-pushed) .content-col:not(:has(.insp-fit)) .app-content {
    display: flex !important;
    flex-direction: column;
    flex: 1 1 auto !important;
    min-height: 0 !important;
    overflow: hidden !important;
    padding: 0 !important;
  }
  body.page-inventory:not(.ios-pushed) .content-col:not(:has(.insp-fit)) #view-root:not(:has(.ios-screen)):not(:has(.insp-fit)) {
    display: block !important;
    flex: 1 1 auto !important;
    min-height: 0 !important;
    overflow-y: auto !important;
    overflow-x: hidden !important;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    padding-bottom: calc(16px + var(--safe-bottom)) !important;
  }
  body.page-inventory:not(.ios-pushed) #view-root > .filterrow.kit-bar,
  body.page-inventory:not(.ios-pushed) #view-root > .filter-applied,
  body.page-inventory:not(.ios-pushed) #view-root > .check-interval {
    flex: 0 0 auto;
  }
  body.page-inventory:not(.ios-pushed) #view-root > .filterrow.kit-bar {
    position: sticky;
    top: 0;
    z-index: 4;
    margin-bottom: 0;
    padding-bottom: 10px;
    background: var(--ios-grouped, var(--bg, #faf9f7));
  }
  body.page-inventory:not(.ios-pushed) #view-root > .filter-applied:not(:empty) {
    position: sticky;
    top: 54px;
    z-index: 4;
    margin-top: 0;
    background: var(--ios-grouped, var(--bg, #faf9f7));
  }
}

/* ── Overdue pulse (commit: overdue pulse) ───────────────────────────────
   Soft pulse on overdue labels, on desktop and phone. Opacity eases between
   1 and 0.7. The pill glow is a pseudo-element, so the text colour and
   background stay as they are. Print and reduced motion keep the labels still. */
.st.st-overdue { position: relative; }
.st.st-overdue::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  box-shadow: 0 0 8px 1px rgba(239, 68, 68, .55);
  opacity: 0;
}

@media (prefers-reduced-motion: no-preference) {
  .st.st-overdue {
    animation: overdue-pulse-fade 1.8s ease-in-out infinite;
  }
  .st.st-overdue::after {
    animation: overdue-pulse-glow 1.8s ease-in-out infinite;
  }
  .dt-row:has(.st-overdue) .row-dot {
    animation: overdue-pulse-dot 1.8s ease-in-out infinite;
  }
  .kit-filter-n-hot {
    animation: overdue-pulse-fade 1.8s ease-in-out infinite;
  }
  .pro-overdue-hot {
    animation: overdue-pulse-fade 1.8s ease-in-out infinite;
  }

  @keyframes overdue-pulse-fade {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.7; }
  }
  @keyframes overdue-pulse-glow {
    0%, 100% { opacity: 0; }
    50% { opacity: 1; }
  }
  @keyframes overdue-pulse-dot {
    0%, 100% { opacity: 1; box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); }
    50% { opacity: 0.7; box-shadow: 0 0 8px 1px rgba(239, 68, 68, .55); }
  }
}

@media (prefers-reduced-motion: reduce) {
  .st.st-overdue,
  .st.st-overdue::after,
  .dt-row:has(.st-overdue) .row-dot,
  .kit-filter-n-hot,
  .pro-overdue-hot {
    animation: none !important;
  }
  .st.st-overdue::after { opacity: 0; }
}

@media print {
  .st.st-overdue,
  .st.st-overdue::after,
  .dt-row:has(.st-overdue) .row-dot,
  .kit-filter-n-hot,
  .pro-overdue-hot {
    animation: none !important;
  }
  .st.st-overdue::after { opacity: 0; }
}

/* ── Sticky search and filter (commit: sticky search) ──
   Desktop and wide landscape only. Phones (max-width 899px) already
   pin the kit search inside #view-root and are left alone. PRO register
   filters stay unpinned on a phone: four stacked fields would eat the screen.
   .content-col keeps scrolling the kit list. #app scrolls the register. */
@media (min-width: 900px) {
  /* Measured: sticky top:0 on the kit bar stops 28px down, under
     .content-col's padding-top, and rows paint in that strip.
     A negative margin on the bar covers "Check every N days" at rest.
     Moving the 28px onto .page-head leaves the title, the bar, and the
     rows where they are, and top:0 then sits on the pane edge.
     --bg is the page colour in light, in [data-theme=dark], and when
     the system theme is dark. z-index 4 is under .filter-pop (6),
     the topbar (30), and the sheets. The bar is 44px (Filter is 44px);
     applied chips sit on that line. Check-every scrolls away. */
  body.page-inventory .content-col { padding-top: 0; }
  body.page-inventory .page-head { padding-top: 28px; }
  body.page-inventory #view-root > .filterrow.kit-bar {
    position: sticky;
    top: 0;
    z-index: 4;
    background: var(--bg);
  }
  body.page-inventory #view-root:has(> .filter-applied:not(:empty)) > .filterrow.kit-bar {
    margin-bottom: 0;
  }
  body.page-inventory #view-root > .filter-applied:not(:empty) {
    position: sticky;
    top: 44px;
    z-index: 3;
    margin-top: 0;
    padding-top: 12px;
    background: var(--bg);
  }

  /* Register only. .panel is overflow:hidden, which traps sticky.
     clip keeps the card's corners and lets the form stick to #app.
     top:-0.75rem cancels #app's padding-top (0.75rem); top:0 left a
     strip of table rows above the fields. padding-bottom keeps the
     same gap the form's margin used to leave, and fills it. */
  body.page-pro .app-content .panel:has(> .panel-body > form.pro-filters[action="/pro/register"]) {
    overflow: hidden;
    overflow: clip;
  }
  body.page-pro form.pro-filters[action="/pro/register"] {
    position: sticky;
    top: -0.75rem;
    z-index: 4;
    margin-bottom: 0;
    padding-bottom: 0.8rem;
    background: var(--bg-panel);
  }
}

