/*
  modern-overrides.css (v2.12.4)
  ================================================
  
  ROOT CAUSE OF BLANK PAGE (v2.2.0):
  
  Setting height:100% on html + body + .responsive-wrapper combined
  with overflow-x:hidden on html/body caused a well-known browser quirk:
  
    When you set overflow-x:hidden on <body>, many browsers silently
    set overflow-y to "auto" as a side effect. Combined with height:100%,
    the body becomes a scroll-container exactly viewport-height tall.
    Content APPEARS to vanish because it's trapped inside an invisible
    overflow:auto box.
  
  FIX: Remove ALL height:100% from html/body/wrapper. Only set height
  where absolutely needed (the #jsmap div directly). Never set
  overflow-x:hidden on html or body.
*/

/* ============================================================
   1. CSS VARIABLES & BASE RESET
   ============================================================ */
:root {
  --bg: #f6f7fb;
  --surface: #ffffff;
  --text: #1f2937;
  --muted: #6b7280;
  --border: #e5e7eb;
  --shadow: 0 6px 22px rgba(0,0,0,0.08);
  --radius: 12px;
  --primary: #00bcd4;
  --primary-2: #0097a7;
}

/* Safe reset - NO height on html/body, NO overflow on html/body */
*, *::before, *::after {
  box-sizing: border-box;
}

html {
  overflow-x: hidden;
  min-height: 100%;
}

body.modern-shell {
  margin: 0;
  padding: 0;
  color: var(--text);
  background: #ffffff;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: 14px;
  line-height: 1.45;
  /* NO height: 100% - causes blank page */
  /* NO overflow-x: hidden - causes blank page when set on body */
  /* v2.12.4: white background - body is taller than content on short pages,
     grey --bg bleeds through transparent wrapper ancestors */
}

/* ============================================================
   2. RESPONSIVE WRAPPER
   ============================================================ */
.responsive-wrapper {
  width: 100%;
  max-width: 100%;
  margin: 0;
  padding: 0;
  overflow-x: hidden;
  background-color: #ffffff !important; /* v2.12.4: wrapper must be white - grey :not(:has(#jsmap)) rule removed from wrapper selector */
}

/*
  MOBILE PAGE WIDTH FIX:
  HTML align="center" on parent TDs acts like margin:auto, centering
  the inner table and leaving gray gaps on mobile.
  Fix: set margin:0 on all layout tables, make TDs left-aligned.
*/
table.contentMapTable,
table.contentMapTableFull,
table.contentTable {
  width: 100% !important;
  max-width: 100% !important;
  min-width: 0 !important;
  margin-left: 0 !important;
  margin-right: 0 !important;
}

td.contentTrackMapCellFull,
td.contentTrackMapCell,
td.contentCell {
  width: 100% !important;
  max-width: 100% !important;
  box-sizing: border-box !important;
}

/* Anonymous table direct child of contentTrackMapCellFull */
td.contentTrackMapCellFull > table,
td.contentTrackMapCell > table {
  width: 100% !important;
  max-width: 100% !important;
}

/* Override align="center" centering on outer layout TDs */
td[align="center"] > table.contentMapTableFull,
td[align="center"] > table.contentMapTable,
td[align="center"] > table.contentTable {
  margin: 0 !important;
}

td[valign="top"][align="center"] {
  text-align: left !important;
  width: 100% !important;
}

/* Login tables */
table.accountLoginTable,
table.accountLoginTable_nobord {
  width: 100% !important;
}

/* ── Login page full-viewport fix ─────────────────────────────
   PROBLEM: body background is --bg (#f6f7fb grey) but the login
   card only fills ~460px on a 667px device, leaving a grey strip
   below the card.

   FIX 1: White background on login page body (via :has() targeting
     the login table — avoids affecting map/report pages).
   FIX 2: Login outer table fills full viewport height so the white
     card stretches to the bottom on all screen sizes.
   FIX 3: accountLoginCell_nobord also white and fills available space
     so no grey gaps appear inside the card either.

   :has() is supported in all modern browsers (Chrome 105+, Safari 15.4+,
   Firefox 121+). For older browsers the grey body background is the
   graceful fallback — no functional breakage.
*/
body.modern-shell:has(table.accountLoginTable_nobord) {
  background: #ffffff !important;
}

body.modern-shell:has(table.accountLoginTable) {
  background: #ffffff !important;
}

/* Outer wrapper and layout tables on login page */
body.modern-shell:has(table.accountLoginTable_nobord) .responsive-wrapper,
body.modern-shell:has(table.accountLoginTable)        .responsive-wrapper {
  min-height: 100vh;
  background: #ffffff;
}

/* Login container: stretch to fill viewport.
   DO NOT set background here — AccountLogin.css sets its background
   image/color on this table. Only set min-height. */
table.accountLoginTable_nobord,
table.accountLoginTable {
  min-height: calc(100vh - 50px); /* 50px for nav bar */
}

/* Login cell: DO NOT set background here — AccountLogin.css sets the
   background image on the inner content cell. Overriding with white
   removes the illustration. Only ensure vertical centering. */
td.accountLoginCell_nobord,
td.accountLoginCell {
  vertical-align: middle;
}

/* Location detail table: scrollable on mobile */
#trackMapDataTable {
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

#trackMapDataTable table {
  min-width: 700px;
}

/* ============================================================
   1. CSS VARIABLES & BASE RESET
   ============================================================ */
:root {
  --bg: #f6f7fb;
  --surface: #ffffff;
  --text: #1f2937;
  --muted: #6b7280;
  --border: #e5e7eb;
  --shadow: 0 6px 22px rgba(0,0,0,0.08);
  --radius: 12px;
  --primary: #00bcd4;
  --primary-2: #0097a7;
}

/* Safe reset - NO height on html/body, NO overflow on html/body */
*, *::before, *::after {
  box-sizing: border-box;
}

/* ============================================================
   2. RESPONSIVE WRAPPER
   ============================================================ */
.responsive-wrapper {
  width: 100%;
  max-width: 100%;
  margin: 0;
  padding: 0;
  overflow-x: hidden;
}
}

/*
  MOBILE PAGE WIDTH FIX:
  Layout tables use HTML align="center" on parent TDs.
  Without explicit width:100%, they shrink to content width
  and float centered — leaving gray gaps on both sides.
*/
table.contentMapTable,
table.contentMapTableFull,
table.contentTable {
  width: 100% !important;
  max-width: 100% !important;
  min-width: 0 !important;
}

td.contentTrackMapCellFull,
td.contentTrackMapCell,
td.contentCell {
  width: 100% !important;
  max-width: 100% !important;
  box-sizing: border-box !important;
}

/* Outer centering TDs — make them full width too */
td[valign][align="center"],
td[valign="top"][align="center"] {
  text-align: left !important;
  width: 100% !important;
}

/* ============================================================
   3. TYPOGRAPHY
   ============================================================ */
body, td, input, select, textarea {
  font-size: 14px !important;
}

h1 { font-size: clamp(18px, 4vw, 24px) !important; }
h2 { font-size: clamp(16px, 3.5vw, 20px) !important; }
h3 { font-size: clamp(14px, 3vw, 18px) !important; }
h4 { font-size: clamp(13px, 2.5vw, 16px) !important; }

a { color: var(--primary); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ============================================================
   4. TABLES - SELECTIVE (JS-SAFE) APPROACH
   ============================================================ */

/* Safe: widen tables but don't change display */
table[width] {
  width: 100% !important;
  max-width: 100% !important;
}

td[width], th[width] {
  width: auto !important;
}

/* Only convert DATA/REPORT tables to scrollable blocks */
/*
  COLUMN ALIGNMENT FIX:
  Do NOT set display:block on tables with thead/tbody.
  When thead and tbody are both display:table inside a display:block
  parent, they become independent tables with no shared column widths
  → header columns don't align with data columns.
  
  Instead: keep table as display:table, set overflow:auto on the
  parent container (#trackMapDataTable for location details).
*/
table.adminSelectTable,
table.adminSelectTable_sortable,
table.mapDetailsTable,
table.mapDetailsTable_sortable {
  display: table !important;   /* MUST stay as table for column alignment */
  width: 100% !important;
  table-layout: auto;
}

/* The container divs get the scroll, not the table itself */
#trackMapDataTable,
div.adminSelectTableContainer {
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* thead/tbody/tfoot stay as their natural display */
table.adminSelectTable thead,
table.adminSelectTable tbody,
table.adminSelectTable tfoot,
table.adminSelectTable_sortable thead,
table.adminSelectTable_sortable tbody,
table.adminSelectTable_sortable tfoot,
table.mapDetailsTable thead,
table.mapDetailsTable tbody,
table.mapDetailsTable tfoot,
table.mapDetailsTable_sortable thead,
table.mapDetailsTable_sortable tbody,
table.mapDetailsTable_sortable tfoot {
  display: table-header-group;  /* thead natural value */
}
table.adminSelectTable tbody,
table.adminSelectTable_sortable tbody,
table.mapDetailsTable tbody,
table.mapDetailsTable_sortable tbody {
  display: table-row-group;
}

table.adminSelectTable tr,
table.adminSelectTable_sortable tr,
table.mapDetailsTable tr,
table.mapDetailsTable_sortable tr {
  display: table-row;
}

table.adminSelectTable td,
table.adminSelectTable th,
table.adminSelectTable_sortable td,
table.adminSelectTable_sortable th,
table.mapDetailsTable td,
table.mapDetailsTable th,
table.mapDetailsTable_sortable td,
table.mapDetailsTable_sortable th {
  display: table-cell;
  white-space: nowrap;
}

/* CRITICAL: Layout tables must ALWAYS be display:table */
table.contentMapTable,
table.contentMapTableFull,
table.contentTable,
table.bannerTable,
table.menuSubFrame {
  display: table !important;
  /* NO height:100% here - it caused the blank page */
}

/*
  v2.12.4 — TOP AND BOTTOM BLANK SPACE FIX
  Confirmed working via console diagnostics on iPad Pro + Surface Pro 7.

  ROOT CAUSE:
  The parent TD of table.contentTable has height="100%" as an HTML
  attribute, stretching it to the full viewport (e.g. 1607px on iPad Pro).
  Controls.css sets .contentTable { height:100% } so the table inherits
  that full height. The TBODY distributes the excess across all TRs:
    - TR[0] contentMessage (empty) absorbs ~874px → TOP BLANK SPACE
      (fixed in modern-patches.js v3.43.1 via height:auto + display:none)
    - After JS fix: contentTable shrinks to 733px but .responsive-wrapper
      stays 1607px with transparent background → body grey (#f6f7fb)
      shows through for remaining 874px → BOTTOM GREY SPACE

  FIX 1 — table.contentTable height:auto (reinforced by JS in v3.43.1)
  FIX 2 — table.contentTable > tbody white background (inner safety net)
  FIX 3 — .responsive-wrapper white background (outer confirmed fix)
    elementsFromPoint at y=800 shows: TD → TABLE → .responsive-wrapper
    → BODY (grey). Wrapper is transparent, body grey bleeds through.
    Setting white on wrapper covers the gap. Confirmed in console.
*/
table.contentTable {
  height: auto !important;
}

table.contentTable > tbody {
  background-color: #ffffff;
}

/* Soften table borders */
table td, table th {
  border-color: var(--border) !important;
}

/* ============================================================
   5. MAP - SAFE HEIGHT APPROACH
   ============================================================ */

/*
  MAP HEIGHT FIX (v2.5.0):

  Uses CSS custom property --map-h set dynamically by JS after measuring
  getBoundingClientRect().top of mapProviderCell at scroll=0.
  This works on every device, browser, zoom level — no hardcoded offsets.

  JS sets:  document.documentElement.style.setProperty('--map-h', Xpx)
  Fallback: calc(100vh - 115px) covers the instant before JS runs.
*/

/* mapProviderCell: display:block so height constraint works */
/* Scope display:block only where mapProviderCell is direct TR child
   (tracker map, group map). On zone.info it is nested inside a 2-column
   layout table (TR>TD>TABLE>TR>TD.mapProviderCell) and display:block
   there collapses the right-side form column. */
/* mapProviderCell as direct TR child (tracker/group map).
   Height not overridden here — let inline styles and setMapHeight JS control it. */
td.mapProviderCell {
  overflow: hidden !important;
  padding: 0 !important;
  vertical-align: top !important;
}
.modern-shell td.mapProviderCell {
  height: var(--map-h) !important;
}

/* zone.info nested mapProviderCell: keep table-cell, just constrain height */
/* nested zone.info mapProviderCell - no height override, no display override */
td > table td.mapProviderCell {
  overflow: hidden !important;
  padding: 0 !important;
  vertical-align: top !important;
}

/* #jsmap: min-height:0 removes the 400px CSS floor */
/* #jsmap height NOT overridden here — zone.info sets height:310px inline
   and !important was overriding it. setMapHeight JS sets --map-h for
   tracker/group map pages via the .modern-shell rule below. */
#jsmap {
  width: 100% !important;
  height: 100%;
  min-height: 0 !important;
  position: relative !important;
  overflow: hidden !important;
}
/* Only apply var height where our JS explicitly set it */
.modern-shell #jsmap {
  height: var(--map-h) !important;
}

/* Desktop: pin calendar panel to fixed width */
@media (min-width: 1201px) {
  #mapControlCell {
    width:     170px !important;
    min-width: 170px !important;
    max-width: 170px !important;
    vertical-align: top !important;
    overflow: visible !important;
  }
  td#mapControlBar,
  td.mapControlCollapseBar_R,
  td.mapControlCollapseBar_L {
    width: 8px !important;
    min-width: 8px !important;
    max-width: 8px !important;
  }
}

/* OpenLayers viewport fills #jsmap via absolute inset */
/* olMapViewport: do not override position - OL manages this itself.
   Only ensure it fills jsmap dimensions. */
#jsmap > .olMapViewport {
  width: 100% !important;
  height: 100% !important;
}

/* ============================================================
   MOBILE MAP LAYOUT
   ============================================================
   Who owns what, below 1200px:

   CSS owns the BOX. Breaking the legacy map table out of table layout
   is declarative work: the table, its tbody, the map row and the map
   cell are all display:block (see "MOBILE: FORCE MAP AND CONTROL TO
   STACK VERTICALLY" further down), which is what lets #jsmap's
   width:100% resolve against a real containing block.

   JS owns only what CSS cannot express: the map HEIGHT (a fraction of
   the live viewport, which vh units get wrong while a phone's address
   bar animates), stacking the OUTER row that holds the map column and
   the control panel, and calling OpenLayers' updateSize() afterwards —
   OL does not observe its own container.

   JS must not write widths here. It used to: the map cell was left as
   a table-cell, so the browser wrapped it in a shrink-to-fit anonymous
   table and every width had to be measured and pinned in pixels. Those
   measurements are gone, and with them the class of bug where one pass
   overwrote another's pixel width and the map collapsed to zero.

   The two blocks that used to describe this area contradicted each
   other; this file also carried the whole section twice, verbatim.
*/

@media (max-width: 1200px) {
  /* Collapse bar always hidden */
  td#mapControlBar,
  td.mapControlCollapseBar_L,
  td.mapControlCollapseBar_R {
    display: none !important;
  }

  /* Location details table — horizontal scroll */
  #trackMapDataTable {
    width:      100% !important;
    overflow-x: auto !important;
    -webkit-overflow-scrolling: touch !important;
    display:    block !important;
  }
}


/* ============================================================
   6. MENU BAR
   ============================================================ */
.menuBarUns,
.menuBarUns20,
.menuBarUnsW,
.menuBarSel,
.menuBarSel20,
.menuBarSelW {
  width: auto !important;
  min-width: 80px !important;
  max-width: 150px !important;
  padding: 8px 12px !important;
  font-size: 13px !important;
  white-space: nowrap;
  border-radius: 10px;
  margin: 2px;
  display: inline-block;
}

.menuBarUnsW,
.menuBarSelW {
  background-image: none !important;
  background-color: #fff !important;
  border: 1px solid var(--border) !important;
}

.menuBarUnsW:hover {
  background-color: #f3f4f6 !important;
}

.menuBarSelW {
  background-color: var(--primary) !important;
  color: #fff !important;
  font-weight: 600 !important;
}

td.menuBar,
.menuBar {
  background: transparent !important;
  display: block !important;
  width: 100% !important;
  padding: 8px 0 !important;
}

/* Submenu - no overflow restrictions */
table.menuSubFrame {
  display: table !important;
  min-width: 180px;
  background-color: #F7FBFF !important;
  border: 2px solid var(--border) !important;
  border-radius: 8px;
  box-shadow: var(--shadow);
  overflow: visible !important;
  max-height: none !important;
}

td.menuSubItemCol {
  font-size: 13px !important;
  padding: 8px !important;
  cursor: pointer;
  border-top: 1px solid #BBBBBB;
  text-align: left;
  overflow: visible !important;
  white-space: nowrap;
}

td.menuSubItemCol:hover,
td.menuSubItemCol:active {
  background-color: #E5E8ED !important;
}

/* The submenu container div (created by mnubarCreateMenuFrame, appended to body) */
/* Must be above the map (OpenLayers uses z-index ~100-1000) */
div[style*="position:absolute"] > table.menuSubFrame,
div[style*="position: absolute"] > table.menuSubFrame {
  display: table !important;
}

@media (max-width: 768px) {
  .menuBarUns, .menuBarUnsW, .menuBarSel, .menuBarSelW {
    min-width: 60px !important;
    font-size: 12px !important;
    padding: 8px 10px !important;    /* Larger touch target */
    min-height: 36px !important;
  }

  /* Submenu items: larger touch targets on mobile */
  td.menuSubItemCol {
    padding: 12px 16px !important;   /* ~44px minimum touch target */
    font-size: 14px !important;
  }

  table.menuSubFrame {
    min-width: 160px !important;
  }
}

/* ============================================================
   7. FORMS & INPUTS
   ============================================================ */
button,
input[type="button"],
input[type="submit"],
input[type="reset"],
.formButton {
  -webkit-appearance: none;
  appearance: none;
  background: var(--primary) !important;
  color: #fff !important;
  border: 1px solid var(--border);
  padding: 6px 12px;
  border-radius: 6px;
  font-weight: 600;
  font-size: 13px !important;
  cursor: pointer;
  transition: all 0.2s;
  min-height: 30px !important;
}

button:hover,
input[type="button"]:hover,
input[type="submit"]:hover,
.formButton:hover {
  background: var(--primary-2) !important;
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3);
}

input[type="text"],
input[type="password"],
input[type="email"],
input[type="number"],
select,
textarea,
.textInput,
.textReadOnly,
.deviceChooserInput {
  border: 1px solid var(--border) !important;
  border-radius: 8px !important;
  padding: 5px 8px !important;
  background: #fff !important;
  color: var(--text) !important;
  font-size: 13px !important;
  width: auto !important;
  max-width: 500px !important;
  transition: border-color 0.2s;
  min-height: 28px !important;
  box-sizing: border-box !important;
}

/*
  TRACKER NAME INPUT (#deviceDescription)
  This is a small read-only display input showing the selected tracker name.
  HTML: <input id="deviceDescription" style="height:17px" size="20" readonly>
  Our general input CSS (min-height:40px, width:100%) breaks its layout.
  Restore original compact styling:
*/
#deviceDescription {
  height: 17px !important;
  min-height: 0 !important;
  width: auto !important;
  max-width: none !important;
  padding: 0px 3px !important;
  margin: 0px 3px !important;
  border-radius: 3px !important;
  font-size: 13px !important;
  display: inline-block !important;
  vertical-align: middle !important;
  cursor: pointer !important;
}

input:focus,
select:focus,
textarea:focus {
  border-color: var(--primary) !important;
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1) !important;
  outline: none;
}

/* Mobile: prevent zoom-on-focus */
@media (max-width: 768px) {
  input[type="text"],
  input[type="password"],
  select,
  textarea {
    font-size: 16px !important;
  }
}

/* Mobile: full-width buttons */
@media (max-width: 520px) {
  button,
  input[type="button"],
  input[type="submit"],
  .formButton {
    width: auto !important;
    min-width: 72px !important;
    margin: 4px 6px 4px 0 !important;
    display: inline-block !important;
  }
}

/* ============================================================
   8. DEVICE/TRACKER SELECTION
   ============================================================ */

/*
  DO NOT override display on #devChooserView or .devSelectorDiv_hidden.
  OpenGTS JS controls show/hide via class swaps.
  Forcing display:block made it always visible below the map.
*/

/* Just ensure the scrollable list has a max-height when shown */
#DeviceTableList,
.devSelectorTableList {
  max-height: 250px;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

/* Style the device search input without breaking the show/hide */
.deviceChooserInput {
  font-size: 13px !important;
  padding: 4px 6px !important;
  border: 1px solid var(--border) !important;
  border-radius: 4px !important;
  min-height: 0 !important;
  width: auto !important;
  height: auto !important;
}

/* ============================================================
   9. TABLE HEADERS & CELLS
   ============================================================ */
th.adminTableHeaderCol_sort,
th.adminTableHeaderCol_nosort,
th.mapDetailsHeaderColumn_sort,
th.mapDetailsHeaderColumn_nosort {
  font-size: 13px !important;
  padding: 10px 8px !important;
  white-space: nowrap;
  position: sticky;
  top: 0;
  background: #f9fafb !important;
  z-index: 10;
}

td.adminTableBodyCol,
td.mapDetailsDataColumn {
  font-size: 13px !important;
  padding: 8px !important;
  word-break: break-word;
}

tr.adminTableBodyRowOdd,
tr.mapDetailsDataRowOdd {
  background-color: #ffffff !important;
}

tr.adminTableBodyRowEven,
tr.mapDetailsDataRowEven {
  background-color: #f9fafb !important;
}

div.trackMapDetailLocation {
  max-height: 400px !important;
  overflow-y: auto !important;
  -webkit-overflow-scrolling: touch;
}

/* ============================================================
   10. CONTENT CELLS
   ============================================================ */
.contentCell,
.contentTopMenuCell {
  padding: 12px !important;
  border: 1px solid var(--border) !important;
  background-color: var(--surface) !important;
  border-radius: var(--radius);
}

/*
  contentMessage: OpenGTS uses this for status/error messages.
  The element is always present in HTML but usually empty (whitespace only).
  Our CSS was always showing a pink bar even when empty.
  
  Fix: Remove permanent background. JS will add class "has-message"
  when actual content is set, which triggers the visual styling.
*/
.contentMessage {
  font-size: 14px !important;
  font-weight: 600;
  text-align: center;
  /* No background/border by default - see .contentMessage.has-message below */
}

.contentMessage.has-message {
  margin: 6px 0;
  padding: 8px 12px;
  color: #dc2626;
  background: #fef2f2;
  border: 1px solid #fecaca;
  border-radius: 8px;
}

/* ============================================================
   11. SCROLLBARS
   ============================================================ */
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: #f1f1f1; border-radius: 4px; }
::-webkit-scrollbar-thumb { background: #c1c1c1; border-radius: 4px; }
::-webkit-scrollbar-thumb:hover { background: #a1a1a1; }

/* ============================================================
   12. MISC
   ============================================================ */

/*
  Only apply max-width to content images, excluding small UI icons
  like Pulldown.png. Using :not([src*="Pulldown"]) to protect them.
*/
.contentCell img:not([src*="Pulldown"]):not([src*="pulldown"]),
.contentTopMenuCell img,
td.adminTableBodyCol img,
td.mapDetailsDataColumn img {
  max-width: 100%;
  height: auto;
}

/* Pulldown arrow images: preserve original size */
img[src*="Pulldown"],
img[src*="pulldown"] {
  width: auto !important;
  height: auto !important;
  max-width: none !important;
  display: inline !important;
  vertical-align: middle !important;
}

span.spanLink {
  color: var(--primary) !important;
  cursor: pointer;
  text-decoration: underline;
}

/* Loading Map Points overlay - center within #jsmap on mobile */
#jsmap > div[style*="position:absolute"],
#jsmap > div[style*="position: absolute"] {
  left: 50% !important;
  transform: translateX(-50%) !important;
}

/* ============================================================
   END OF MODERN-OVERRIDES.CSS (v3.1.0)
   ============================================================ */

/* ============================================================
   DESKTOP LAYOUT (>1200px) - Group Map Fix
   ============================================================
   Ensure control panel stays side-by-side with map on desktop.
   Handles BOTH page structures:
   - Device map: TR > TD.mapProviderCell (direct child)
   - Group map: TR > TD > TABLE > TD.mapProviderCell (nested)
*/

@media (min-width: 1201px) {
  /* Control cell should be table-cell (side-by-side) on desktop */
  /* This works for device map (direct child structure) */
  tr:has(> td.mapProviderCell) > td#mapControlCell,
  tr:has(> td.mapProviderCell) > td.mapControlCell,
  /* This works for group map (nested structure) */
  tr:has(> td > table td.mapProviderCell) > td#mapControlCell,
  tr:has(> td > table td.mapProviderCell) > td.mapControlCell {
    display: table-cell !important;
    width: auto !important;
    max-height: none !important;
    overflow-y: visible !important;
    padding-left: 5px !important;
    vertical-align: top !important;
  }
  
  /* Collapse bar visible on desktop */
  td#mapControlBar,
  td.mapControlCollapseBar_L,
  td.mapControlCollapseBar_R {
    display: table-cell !important;
  }
}

/* ============================================================
   RESPONSIVE FORM INPUTS
   ============================================================ */

/* Address input field - make it responsive */
#gotoAddressFld,
input.textInput[name="gotoAddressFld"] {
  width: 100% !important;
  max-width: 400px !important;
  box-sizing: border-box !important;
}

/* On mobile, allow full width */
@media (max-width: 768px) {
  #gotoAddressFld,
  input.textInput[name="gotoAddressFld"] {
    max-width: 100% !important;
  }
}

/* ============================================================
   MOBILE FIXES - Date Chooser & Find Location
   ============================================================ */

@media (max-width: 1200px) {
  /* Fix: Control cell needs more height for calendar */
  td#mapControlCell,
  td.mapControlCell {
    max-height: 60vh !important; /* Increased from 50vh */
    min-height: 400px !important; /* Increased from 300px */
    overflow-y: auto !important; /* CRITICAL: Enable vertical scrolling */
    -webkit-overflow-scrolling: touch !important; /* Smooth iOS scrolling */
    padding-top: 12px !important; /* Space for top content */
    /* overflow-x removed - let content scroll naturally if needed */
  }
  
  /* Fix: "Find Location" button - correct selector for INPUT button */
  input[type="button"][value*="Find Location"],
  input[type="button"][value*="Location"] {
    width: auto !important;
    max-width: 150px !important;
    padding: 8px 16px !important;
    margin-left: 8px !important;
    display: inline-block !important;
  }
  
  /* Fix: Address input field on mobile - flex:1 fills remaining space next to button */
  #gotoAddressFld {
    flex: 1 1 80px !important;
    width: auto !important;
    max-width: 100% !important;
    min-width: 80px !important;
    display: inline-block !important;
    vertical-align: middle !important;
    box-sizing: border-box !important;
  }
  
  /* CRITICAL FIX: Form must be constrained to viewport width */
  form#GotoAddress,
  form:has(#gotoAddressFld) {
    display: flex !important;
    flex-wrap: wrap !important;
    width: 100% !important;
    max-width: 100% !important; /* Use 100% not 375px — must work on all screen sizes */
    overflow: hidden !important; /* Prevent horizontal scroll */
    gap: 8px !important; /* Space between elements */
    padding: 8px !important; /* Inner spacing */
    box-sizing: border-box !important;
    align-items: center !important;
  }
  
  /* Button should shrink if needed */
  input[type="button"][value*="Find Location"],
  input[type="button"][value*="Location"] {
    flex-shrink: 0 !important;
    margin-left: 0 !important; /* Remove margin, use gap instead */
  }
  
  /* Input should shrink if needed */
  #gotoAddressFld {
    flex-shrink: 1 !important;
    min-width: 150px !important;
  }
}

/* Extra small mobile devices - stack vertically */
@media (max-width: 320px) {
  /* Only on VERY small devices (320px and below), stack vertically */
  #gotoAddressFld {
    width: 100% !important;
    max-width: 100% !important;
    margin-bottom: 8px !important;
  }
  
  input[type="button"][value*="Find Location"],
  input[type="button"][value*="Location"] {
    width: 100% !important;
    max-width: 100% !important;
    margin-left: 0 !important;
  }
}

/* ============================================================
   DESKTOP EXPLICIT RULES (>1200px)
   ============================================================
   Undo mobile styles and ensure proper desktop layout
*/

@media (min-width: 1201px) {
  /* Control cell: Remove mobile constraints */
  td#mapControlCell,
  td.mapControlCell {
    max-height: none !important;
    min-height: auto !important;
    overflow-y: visible !important;
  }
  
  /* Find Location elements: Reset to auto/default */
  input[type="button"][value*="Find Location"],
  input[type="button"][value*="Location"] {
    width: auto !important;
    max-width: none !important;
    padding: initial !important;
    margin-left: initial !important;
    display: inline !important;
  }
  
  #gotoAddressFld {
    width: auto !important;
    max-width: none !important;
    display: inline !important;
  }
  
  form:has(#gotoAddressFld) {
    display: inline !important;
  }
}

/* ============================================================
   FIX: Find Location Form Container (TD) Too Wide
   ============================================================ */

@media (max-width: 1200px) {
  /* The TD containing the form must also be constrained */
  td:has(> form#GotoAddress) {
    max-width: 100% !important; /* Use 100% not 375px — must work on all screen sizes */
    width: auto !important;
    display: table-cell !important; /* Keep table-cell to avoid breaking layout */
    box-sizing: border-box !important;
    overflow: hidden !important; /* Prevent content overflow */
  }
}

/* ============================================================
   MOBILE: PREVENT ALL HORIZONTAL SCROLL - REMOVED
   ============================================================
   These rules were too aggressive and broke horizontal scroll
   on pages that need it. Rely on proper positioning instead.
*/

/* Removed:
@media (max-width: 1200px) {
  body { overflow-x: hidden !important; }
  .responsive-wrapper { overflow-x: hidden !important; }
  table { max-width: 100vw !important; }
  td { max-width: 100vw !important; }
}
*/

/* ============================================================
   MOBILE: STACK FORM ROW VERTICALLY
   ============================================================
   The TR containing SelectDeviceForm and GotoAddress needs
   to stack vertically on mobile so forms don't push off-screen
*/

@media (max-width: 1200px) {
  /* Find the TR that contains both SelectDeviceForm and GotoAddress */
  tr:has(form#SelectDeviceForm):has(form#GotoAddress) {
    display: flex !important;
    flex-direction: column !important;
    width: 100% !important;
  }
  
  /* All TDs in that TR should be full width and stack */
  tr:has(form#SelectDeviceForm):has(form#GotoAddress) > td {
    display: block !important;
    width: 100% !important;
    max-width: 100% !important;
    margin-bottom: 8px !important;
  }
}

/* ============================================================
   MOBILE: REMOVE PADDING THAT CAUSES OVERFLOW
   ============================================================ */

@media (max-width: 1200px) {
  /* Remove padding only from TDs that contain forms to prevent overflow */
  td:has(> form) {
    padding-left: 0px !important;
    padding-right: 0px !important;
  }
  
  /* Specifically target the content TD */
  td.contentTrackMapCellFull {
    padding-left: 0px !important;
    padding-right: 0px !important;
  }
}

/* ============================================================
   MOBILE: FORCE MAP AND CONTROL TO STACK VERTICALLY
   ============================================================
   Override JS table layout to ensure proper vertical stacking
*/

@media (max-width: 1200px) {
  /* TR containing map must be block (not table-row) for stacking */
  tr:has(> td.mapProviderCell),
  tr:has(> td > table td.mapProviderCell) {
    display: block !important;
    width: 100% !important;
  }
  
  /* Map cell must be block (not table-cell).

     display:block is load-bearing, not cosmetic. Left as a table-cell
     inside a display:block TR the browser wraps it in an ANONYMOUS TABLE
     box, which is shrink-to-fit: the cell then sizes to its content, so
     #jsmap's width:100% is circular and resolves to 0. The map goes white
     (markers still paint, tiles do not) and OpenLayers recalculates its
     zoom against a 0-wide viewport.

     This is the same declaration enforceDesktopMapTable() writes inline on
     desktop (modern-patches.js, 'mapCell display block/width 100%'), which
     is why desktop never had the bug. Mobile used to compensate by
     measuring a pixel width in JS instead; that measurement is gone. */
  tr:has(> td.mapProviderCell) > td.mapProviderCell,
  td.mapProviderCell {
    display: block !important;
    width: 100% !important;
  }
  
  /* Group map wrapper TD also block */
  tr:has(> td > table td.mapProviderCell) > td:first-child {
    display: block !important;
    width: 100% !important;
  }
}

/* ============================================================
   MOBILE: FORCE MAP TABLE TO BE BLOCK
   ============================================================
   The table containing the map must also be block to stack
*/

@media (max-width: 1200px) {
  /* Table containing map cell must be block */
  table:has(td.mapProviderCell) {
    display: block !important;
    width: 100% !important;
  }
}

/* ============================================================
   MOBILE: FORCE ALL TABLE ELEMENTS TO BLOCK
   ============================================================
   TBODYs must also be block to break table layout completely
   Only target TBODYs that contain map or control cells
*/

@media (max-width: 1200px) {
  /* Force TBODYs containing map/control to block */
  tbody:has(td.mapProviderCell),
  tbody:has(td#mapControlCell),
  tbody:has(td.mapControlCell) {
    display: block !important;
    width: 100% !important;
  }
}

/* ============================================================
   MOBILE: SELECTOR ROW RESPONSIVE (SIMPLIFIED)
   ============================================================
   Don't restructure TR - just make elements responsive
*/

@media (max-width: 768px) {
  /* Make dropdown input smaller */
  #deviceDescription {
    max-width: 120px !important;
    width: 120px !important;
    font-size: 12px !important;
  }
  
  /* Make all buttons smaller to fit.

     input#, not #: taskmanager_trigger0 is not a unique id on this site.
     The map's control row carries it on an <input type="button">, but
     the server also numbers the per-row "manage task" LINKS of the Group
     Message grid and of the map's own location details table
     taskmanager_trigger0, 1, 2... so this button rule was landing on the
     first row's link and on no other, painting it 11px in a 24px box
     while every row under it stayed 13px (user, 2026-08-16). Naming the
     element type keeps the rule on the button it was written for: an
     anchor cannot match it. */
  #next_tracker,
  input#taskmanager_trigger0,
  #loadLeftOverAddressBtn {
    font-size: 11px !important;
    padding: 6px 8px !important;
    white-space: nowrap !important;
  }
  
  /* Group Map: Find Location elements */
  #gotoAddressButton {
    font-size: 11px !important;
    padding: 6px 8px !important;
  }
  
  #gotoAddressFld {
    flex: 1 1 80px !important;
    width: auto !important;
    max-width: 100% !important;
    font-size: 12px !important;
  }
  
  /* NOTE: #lastEventDate / #lastEventTime / #lastEventTmz are NOT hidden.
     flex-wrap wraps them to their own line — hiding them makes the
     "Last Event:" field appear blank (v3.15.2 regression fix). */
}

/* ============================================================
   v3.15.2 ADDITIONS
   ============================================================
   
   Two targeted fixes. All previous rules above are unchanged.
   These additions are at the end so they win the cascade.
*/

/* ── FIX 1: mapControlCell stacking context (Group Map) ────
   
   ROOT CAUSE: OpenLayers uses position:relative on its viewport
   div and creates absolutely-positioned children at z-index 749
   (map layers) and z-index 1001 (PanZoomBar). When mapControlCell
   has no stacking context (position:static), those OL elements
   can visually overlap it even after JS stacks the layout vertically.
   
   FIX: position:relative on mapControlCell creates its own stacking
   context. Combined with z-index:20 it renders above OL's layers.
   background-color:white ensures no visual bleed-through.
   
   NOTE: JS (fixMobileMapLayout) also sets these via setProperty.
   The CSS here is a reinforcing fallback / handles cases where JS
   hasn't fired yet on page load.
   
   IMPORTANT: NOT setting display here — JS owns that. Only stacking.
*/
@media (max-width: 1200px) {
  td#mapControlCell,
  td.mapControlCell {
    position: relative !important;       /* own stacking context */
    z-index: 20 !important;             /* above OL z-index layers */
    background-color: #ffffff !important; /* no bleed-through */
  }
}

/* ── FIX 2: Tracker Map top row flex-wrap (Tracker Map only) ─
   
   ROOT CAUSE: tracker_map top row <tr> has 5+ "nowrap" <td> cells
   (device selector, Next Tracker, Manage Task, Load Missing Addr,
   Last Event) totalling wider than 375px → overflows right.
   
   DISTINCTION from group_map: The existing rule at ~line 1299 targets
   tr:has(form#SelectDeviceForm):has(form#GotoAddress) which only
   matches group_map (that row has both forms). Tracker_map's row
   uniquely contains #next_tracker — used as the selector anchor.
   
   JS (fixTrackerTopRow) is the primary fix; this CSS rule is the
   reinforcing fallback for browsers/conditions where JS hasn't fired.
*/
@media (max-width: 1200px) {
  /*
    TRACKER MAP TOP ROW — CSS-ONLY STACK (JS fixTrackerTopRow confirmed
    not running; row inline style=null in diagnostic).

    Confirmed cell structure (from diagnostic):
      Cell 0: TD "Tracker Map:" label+dropdown  height:19px inline
      Cell 1: INPUT hidden (loadLeftOverAddressInput) — already display:none
      Cell 2: INPUT hidden (currentUserId) — already display:none
      Cell 3: TD Next Tracker button
      Cell 4: TD spacer padding-left:12px, no children, &nbsp; only ← GAP CAUSE
      Cell 5: TD Manage Task button
      Cell 6: TD Load Missing Addresses button
      Cell 7: TD Last Event span

    FIX:
    1. flex-direction:column (not wrap) — every cell is a full-width row
    2. Hide Cell 4 (spacer) by attribute selector [style*="padding-left:12px"]
       — it's the only TD in this row with that exact inline padding
    3. Override height:19px on Cell 0 so dropdown has natural height
    4. Make all button cells + their inputs full width
    5. Uniform gap:6px between all rows
  */
  tr:has(#next_tracker) {
    display: flex !important;
    flex-direction: column !important;
    flex-wrap: nowrap !important;
    align-items: stretch !important;
    gap: 6px !important;
    width: 100% !important;
    box-sizing: border-box !important;
  }

  /* All TDs: full width, no side padding */
  tr:has(#next_tracker) > td {
    display: block !important;
    width: 100% !important;
    max-width: 100% !important;
    box-sizing: border-box !important;
    white-space: normal !important;
    padding: 0 !important;
  }

  /* Cell 0: selector label+dropdown — restore natural height, add bottom spacing */
  tr:has(#next_tracker) > td:first-child {
    height: auto !important;
    padding-bottom: 2px !important;
  }

  /* Cell 4: spacer TD — uniquely identified by its inline padding-left:12px
     It contains only &nbsp; with no child elements — hide it completely */
  tr:has(#next_tracker) > td[style*="padding-left:12px"] {
    display: none !important;
    height: 0 !important;
    padding: 0 !important;
    margin: 0 !important;
  }

  /* All buttons inside the row: fill full cell width */
  tr:has(#next_tracker) input[type="button"] {
    width: 100% !important;
    box-sizing: border-box !important;
    margin: 0 !important;
  }

  /* Forms wrapping buttons: also full width */
  tr:has(#next_tracker) form {
    width: 100% !important;
    margin: 0 !important;
    padding: 0 !important;
  }

  /* Last Event cell: small vertical padding for readability */
  tr:has(#next_tracker) > td:last-child {
    padding: 2px 0 !important;
    font-size: 8pt !important;
  }
}

/* ── DESKTOP: restore full table-row layout ───────────────── */
@media (min-width: 1201px) {
  tr:has(#next_tracker) {
    display: table-row !important;
    flex-direction: unset !important;
  }
  tr:has(#next_tracker) > td {
    display: table-cell !important;
    width: auto !important;
    padding: revert !important;
  }
  tr:has(#next_tracker) > td[style*="padding-left:12px"] {
    display: table-cell !important;
  }
  tr:has(#next_tracker) input[type="button"] {
    width: auto !important;
  }
}

/* ── v3.15.5 FIX: Clip OL tile images to map bounds ────────
   
   ROOT CAUSE (confirmed by diagnostic):
   OL tile images are position:absolute inside #jsmap and physically
   extend 193px BELOW jsmap's boundary (olTileImage bottom=701 vs
   jsmapBottom=508) when overflow is visible. They cover the top of
   mapControlCell (where "Find Location" sits) regardless of z-index
   because overflow:visible lets them escape the containing box.
   
   overflow:hidden on #jsmap clips all OL children to the map bounds.
   Also applied to .olMapViewport and td.mapProviderCell for belt+braces.
   
   JS (fixMobileMapLayout) also sets this via setProperty — CSS here
   is the declarative reinforcement that loads before JS fires.
*/
@media (max-width: 1200px) {
  #jsmap {
    overflow: hidden !important;
  }

  /* OL viewport div (first child of #jsmap) */
  #jsmap > div,
  #jsmap > .olMapViewport {
    overflow: hidden !important;
  }

  /* mapProviderCell: immediate parent of #jsmap in group_map's
     nested table structure. Clips at the cell boundary too. */
  td.mapProviderCell {
    overflow: hidden !important;
  }
}
/* ── END v3.15.5 ─────────────────────────────────────────── */


/* ── v3.15.6 FIX: Group Map selector row outer TD height ───
   
   ROOT CAUSE (confirmed from view source, line 716):
   The outer TD wrapping the group_map selector row has a hardcoded
   inline style "height:16px". Our CSS flex-column rule correctly
   stacks SelectDeviceForm and GotoAddress vertically, but the outer TD's
   table-layout height:16px forces the row height to stay at 16px.
   The stacked GotoAddress form overflows and paints OVER the map,
   where OpenLayers tiles (z-index:749) cover it.

   This CSS targets the outer TD using a :has() chain.
   The JS function fixGroupMapSelectorRow() is the primary fix;
   this CSS is the declarative reinforcement.
*/
@media (max-width: 1200px) {
  /* Outer TD containing the inner selector table */
  td:has(> table > tbody > tr > td > form#SelectDeviceForm) {
    height: auto !important;
    overflow: visible !important;
    padding-bottom: 4px !important;
  }

  /* Inner table must be full width */
  td:has(> table > tbody > tr > td > form#SelectDeviceForm) > table {
    width: 100% !important;
  }

  /* Inner TR: flex-column to stack the two form TDs vertically */
  tr:has(> td > form#SelectDeviceForm) {
    display: flex !important;
    flex-direction: column !important;
    width: 100% !important;
  }

  tr:has(> td > form#SelectDeviceForm) > td {
    display: block !important;
    width: 100% !important;
    white-space: normal !important;
  }

  /* GotoAddress form: flex row so button + input sit side by side */
  form#GotoAddress {
    display: flex !important;
    flex-wrap: wrap !important;
    align-items: center !important;
    gap: 4px !important;
    width: 100% !important;
    box-sizing: border-box !important;
  }

  /* Constrain the address input to leave room for the button */
  #gotoAddressFld {
    flex: 1 1 80px !important;
    width: auto !important;
    max-width: 220px !important;
    min-width: 80px !important;
    box-sizing: border-box !important;
  }
}
/* ── END v3.15.6 ─────────────────────────────────────────── */


/* ── Dashboard buttons: constrain width on desktop ────────────
   
   ROOT CAUSE: Bootstrap btn-block sets width:100%, and container-fluid
   + col-sm-12 let it span the full viewport on desktop.
   On mobile (<768px) full-width buttons are correct and stay unchanged.

   FIX (desktop only):
   - Centre the container and cap it at 480px
   - Override btn-block to auto width with a max-width
   - Add vertical spacing between buttons
*/
@media (min-width: 769px) {
  /* Constrain the dashboard button containers */
  #dashboardrow,
  #dashboardrow1,
  #dashboardrow2 {
    display: flex !important;
    justify-content: center !important;
    margin-bottom: 10px !important;
  }

  #dashboardrow  .col-sm-12,
  #dashboardrow1 .col-sm-12,
  #dashboardrow2 .col-sm-12 {
    flex: 0 0 auto !important;
    width: auto !important;
    max-width: 480px !important;
    min-width: 240px !important;
  }

  /* Override btn-block full-width on desktop */
  #dashboardbutton,
  #dashboardbutton1,
  #dashboardbutton2 {
    width: auto !important;
    min-width: 240px !important;
    max-width: 480px !important;
    display: inline-block !important;
  }
}

/* Mobile: keep full-width buttons as-is */
@media (max-width: 768px) {
  #dashboardrow,
  #dashboardrow1,
  #dashboardrow2 {
    margin-bottom: 8px !important;
  }
}
/* ── END Dashboard button fix ───────────────────────────────── */

/* ============================================================
   END v3.15.2 ADDITIONS
   ============================================================ */

/* Hide Locate Tracker button (id=pingDeviceButton, type=submit) */
#pingDeviceButton {
  display: none !important;
}

/* ══════════════════════════════════════════════════════════════
   REPORTS PAGE — MOBILE RESPONSIVE LAYOUT
   ══════════════════════════════════════════════════════════════

   Structure (from view source):
   <table height="90%">          ← two-column outer table
     <tr>
       <td style="border-right:3px double black">   ← LEFT: tracker selector + calendars
         <div id="calDiv">
           <div id="rptCal_fr" style="width:150px">
           <div id="rptCal_to" style="padding-top:8px; width:150px">
       <td nowrap width="100%">  ← RIGHT: all report radio buttons

   Problems:
   1. Two columns side-by-side on 375px — each only ~180px wide
   2. Calendar divs fixed at width:150px — clips on narrow screens
   3. Right TD has nowrap — content bleeds off screen
   4. adminComboBox selects are too wide for mobile
   5. Vertical border-right divider is meaningless when stacked
*/

@media (max-width: 1200px) {

  /* ── Outer two-column report table: stack vertically ── */
  table[height="90%"] {
    display: block !important;
    width: 100% !important;
  }
  table[height="90%"] > tbody {
    display: block !important;
    width: 100% !important;
  }
  table[height="90%"] > tbody > tr {
    display: flex !important;
    flex-direction: column !important;
    width: 100% !important;
  }

  /* ── Left column (tracker selector + calendars) ── */
  table[height="90%"] > tbody > tr > td:first-child {
    display: block !important;
    width: 100% !important;
    border-right: none !important;        /* remove vertical divider */
    border-bottom: 2px solid #ccc !important; /* horizontal divider instead */
    padding-right: 0 !important;
    padding-bottom: 12px !important;
    margin-bottom: 12px !important;
    box-sizing: border-box !important;
  }

  /* ── Right column (report list) ── */
  table[height="90%"] > tbody > tr > td:last-child {
    display: block !important;
    width: 100% !important;
    white-space: normal !important;       /* override nowrap */
    margin-left: 0 !important;
    padding-left: 0 !important;
    box-sizing: border-box !important;
  }

  /* ── Calendar divs: full width instead of 150px ── */
  #rptCal_fr,
  #rptCal_to {
    width: 100% !important;
    max-width: 100% !important;
  }

  /* Calendar tables inside divs: full width */
  #rptCal_fr > table,
  #rptCal_to > table,
  #rptCal_fr.table,
  #rptCal_to.table,
  table.calTable {
    width: 100% !important;
  }

  /* Calendar month days table: fill available space */
  table.calMonthDaysTable {
    width: 100% !important;
  }

  /* calDiv container: full width */
  #calDiv,
  div.calDiv {
    width: 100% !important;
    padding: 4px 0 0 0 !important;
  }

  /* ── Tracker selector input ── */
  #deviceDescDisp {
    width: auto !important;
    box-sizing: border-box !important;
  }

  /* ── Report option dropdowns: full width, wrap on small screens ── */
  select.adminComboBox {
    max-width: 100% !important;
    width: 100% !important;
    display: block !important;
    margin: 4px 0 !important;
    box-sizing: border-box !important;
  }

  /* ── Report radio buttons: block so they stack cleanly ── */
  span.reportRadioButton {
    display: block !important;
    margin: 4px 0 !important;
    white-space: normal !important;
  }

  /* ── Report inner table (wraps radio buttons + submit): full width ── */
  table[height="90%"] table[width="100%"] {
    width: 100% !important;
  }

  /* ── Format selector row and Get Report button ── */
  form#GetReport {
    display: flex !important;
    flex-wrap: wrap !important;
    align-items: center !important;
    gap: 8px !important;
    padding: 8px 0 !important;
  }

  form#GetReport input[type="submit"] {
    width: 100% !important;
    margin: 0 !important;
    box-sizing: border-box !important;
  }

  /* ── Text input for task search (OTDR): full width ── */
  #r_txt_OTDR {
    width: 100% !important;
    max-width: 100% !important;
    box-sizing: border-box !important;
    display: block !important;
    margin-top: 4px !important;
  }
}

/* ── DESKTOP: restore side-by-side table layout ── */
@media (min-width: 1201px) {
  table[height="90%"] {
    display: table !important;
  }
  table[height="90%"] > tbody {
    display: table-row-group !important;
  }
  table[height="90%"] > tbody > tr {
    display: table-row !important;
    flex-direction: unset !important;
  }
  table[height="90%"] > tbody > tr > td {
    display: table-cell !important;
    width: auto !important;
    white-space: nowrap !important;
    border-bottom: none !important;
    border-right: revert !important;
    padding-bottom: revert !important;
    margin-bottom: 0 !important;
  }
  /* Restore left column border */
  table[height="90%"] > tbody > tr > td:first-child {
    border-right: 3px double black !important;
    border-bottom: none !important;
  }
  #rptCal_fr, #rptCal_to {
    width: 150px !important;
    max-width: 150px !important;
  }
  #calDiv, div.calDiv {
    width: auto !important;
    padding: revert !important;
  }
  select.adminComboBox {
    width: auto !important;
    max-width: none !important;
    display: inline-block !important;
    margin: revert !important;
  }
  span.reportRadioButton {
    display: inline !important;
    white-space: nowrap !important;
  }
  /* Restore task search input to original inline */
  #r_txt_OTDR {
    width: auto !important;
    max-width: none !important;
    display: inline !important;
    margin-top: 0 !important;
  }
  /* Restore Get Report form */
  form#GetReport {
    display: block !important;
  }
  form#GetReport input[type="submit"] {
    width: auto !important;
  }
  /* Restore tracker selector */
  #deviceDescDisp {
    width: auto !important;
  }
}
/* ── END Reports page responsive fix ── */

/* ══════════════════════════════════════════════════════════════
   REPORT OUTPUT TABLE — STYLING + MOBILE RESPONSIVE
   ══════════════════════════════════════════════════════════════

   The generated report page (report.show) has no CSS in its <head>.
   These rules restore the proper OpenGTS report table appearance
   (alternating rows, header background, borders) AND make the
   wide data table horizontally scrollable on mobile.

   Classes used by OpenGTS report output:
     table.rptTbl_sortable   — the main data table
     tr.rptHdrRow            — header row
     th.rptHdrCol_sort       — header cells
     tr.rptBodyRowOdd/Even   — alternating data rows
     td.rptBodyCol           — data cells
     h1.rptTitle             — report title
     h2.rptSubtitle          — report subtitle
     td.reportDisplayCell    — outer cell wrapping everything
*/

/* ── Report page outer wrapper ── */
table.reportDisplayTable {
  width: 100% !important;
}

td.reportDisplayCell {
  padding: 8px !important;
  box-sizing: border-box !important;
}

/* ── Report title and subtitle ── */
h1.rptTitle {
  font-size: 1.4em !important;
  font-weight: bold !important;
  margin: 8px 0 4px !important;
  color: #1f2937 !important;
}

h2.rptSubtitle {
  font-size: 0.95em !important;
  font-weight: normal !important;
  color: #374151 !important;
  margin: 4px 0 8px !important;
}

/* ── Mobile: horizontal-scroll report table ── */
@media (max-width: 1200px) {

  /* Step 1: reportDisplayCell is the outermost wrapper — make it a
     proper block that fills the viewport width */
  td.reportDisplayCell {
    display: block !important;
    width: 100% !important;
    padding: 4px !important;
    box-sizing: border-box !important;
    overflow: hidden !important;
  }

  /* Step 2: <center> becomes a full-width block scroll container.
     This is where we enable horizontal scroll — everything inside
     can be wider than the screen and the user swipes to see it. */
  td.reportDisplayCell > center {
    display: block !important;
    width: 100% !important;
    text-align: left !important;
    overflow-x: auto !important;
    -webkit-overflow-scrolling: touch !important;
    /* Subtle scroll hint shadow on right edge */
    background:
      linear-gradient(to right, white 30%, rgba(255,255,255,0)),
      linear-gradient(to right, rgba(0,0,0,0.08), rgba(0,0,0,0)) 100% 0;
    background-repeat: no-repeat;
    background-size: 40px 100%, 8px 100%;
    background-attachment: local, scroll;
  }

  /* Step 3: Outer meta table (title row + refresh/map row + data row)
     must NOT be constrained to 100% — let it be as wide as content */
  td.reportDisplayCell > center > table {
    width: auto !important;
    min-width: 100% !important;
    box-sizing: border-box !important;
  }

  /* Step 4: The colspan=3 TD holding the data table — full natural width */
  td.reportDisplayCell > center > table > tbody > tr > td[colspan="3"] {
    display: table-cell !important;
    width: auto !important;
    min-width: 100% !important;
    box-sizing: border-box !important;
  }

  /* Step 5: The actual report data table renders at natural column widths
     — do NOT force width:100% which causes the squish-to-fit effect */
  table.rptTbl_sortable {
    width: auto !important;
    min-width: 600px !important;   /* ensures readability before scrolling */
    font-size: 12px !important;    /* slightly smaller on mobile */
  }

  /* Step 6: Smaller header cells on mobile */
  th.rptHdrCol_sort,
  th.rptHdrCol {
    padding: 6px 8px !important;
    font-size: 11px !important;
  }

  /* Step 7: Data cells — reduce padding, keep nowrap for readability */
  td.rptBodyCol {
    padding: 5px 8px !important;
    font-size: 12px !important;
    white-space: nowrap !important;
  }

  /* Step 8: Title + subtitle — smaller on mobile */
  h1.rptTitle {
    font-size: 1em !important;
    margin: 4px 0 !important;
  }

  h2.rptSubtitle {
    font-size: 0.8em !important;
    margin: 2px 0 6px !important;
  }

  /* Step 9: Refresh/Map links row — flex so they sit at opposite ends */
  td.reportDisplayCell > center > table > tbody > tr:nth-child(2) {
    display: flex !important;
    justify-content: space-between !important;
    align-items: center !important;
    width: 100% !important;
    padding: 4px 0 !important;
  }

  /* Step 10: Sticky header — stays visible as user scrolls down rows */
  table.rptTbl_sortable thead tr.rptHdrRow th {
    position: sticky !important;
    top: 0 !important;
    z-index: 10 !important;
    background-color: #2c3e50 !important;
  }
}

/* ── Report data table styling (all screen sizes) ── */
table.rptTbl_sortable {
  border-collapse: collapse !important;
  width: 100% !important;     /* desktop: fill container */
  font-size: 13px !important;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif !important;
}

/* Header row */
tr.rptHdrRow {
  background-color: #2c3e50 !important;
  color: #ffffff !important;
}

th.rptHdrCol_sort,
th.rptHdrCol {
  padding: 8px 10px !important;
  text-align: left !important;
  font-weight: 600 !important;
  font-size: 12px !important;
  white-space: nowrap !important;
  border: 1px solid #1a252f !important;
  color: #ffffff !important;
  cursor: pointer !important;
}

/* Odd rows */
tr.rptBodyRowOdd {
  background-color: #ffffff !important;
}

/* Even rows — alternating colour */
tr.rptBodyRowEven {
  background-color: #f0f4f8 !important;
}

/* Hover on data rows */
tr.rptBodyRowOdd:hover,
tr.rptBodyRowEven:hover {
  background-color: #dbeafe !important;
}

/* Data cells */
td.rptBodyCol {
  padding: 7px 10px !important;
  border: 1px solid #d1d5db !important;
  vertical-align: top !important;
  font-size: 13px !important;
  color: #1f2937 !important;
  white-space: nowrap !important;
}

/* Geozone/address cell: allow wrapping for long text */
td.rptBodyCol > div[style*="word-wrap"] {
  white-space: normal !important;
  min-width: 120px !important;
}

/* Footer row */
tr.rptFooterRow td {
  background-color: #f8fafc !important;
  border-top: 2px solid #2c3e50 !important;
  font-weight: bold !important;
  padding: 7px 10px !important;
}

/* ── Links in report table ── */
td.rptBodyCol a,
td.rptBodyCol .spanLink {
  color: #00bcd4 !important;
  text-decoration: none !important;
  cursor: pointer !important;
}

td.rptBodyCol a:hover,
td.rptBodyCol .spanLink:hover {
  text-decoration: underline !important;
}

/* ── Refresh / Map links above table ── */
td.reportDisplayCell > center > table > tbody > tr:first-child td a,
td.reportDisplayCell > center > table > tbody > tr:nth-child(2) td a,
td.reportDisplayCell > center > table > tbody > tr:nth-child(2) td .spanLink {
  color: #00bcd4 !important;
  font-size: 13px !important;
}
/* ── END Report output styling ── */

/* ============================================================
   SCROLLBAR HIDE — map pages have ~19px phantom scroll from
   table layout. Hide scrollbar visually; data table scroll
   still works when expanded (body overflow-y: auto default).
   ============================================================ */
body.modern-shell {
  scrollbar-width: none;
  -ms-overflow-style: none;
}
body.modern-shell::-webkit-scrollbar {
  display: none;
}

/* ============================================================
   MAP CONTROL PANEL — COMPACT UI (v2.5.0)
   Update + Auto buttons side by side, smaller fonts/padding
   ============================================================ */

/* mapControlCell: compact padding */
td#mapControlCell,
td.mapControlCell {
  font-size: 12px !important;
}

/* UpdateMap form: flex row so Update+Auto sit side by side */
form#UpdateMap {
  display: flex !important;
  flex-direction: row !important;
  gap: 4px !important;
  padding: 4px 0 !important;
  flex-wrap: nowrap !important;
}

/* Update and Auto buttons: compact, equal width, never stack */
form#UpdateMap .formButton,
form#UpdateMap input[type="button"] {
  flex: 1 1 auto !important;
  width: auto !important;
  min-width: 0 !important;
  padding: 5px 8px !important;
  min-height: 28px !important;
  font-size: 12px !important;
  border-radius: 6px !important;
  white-space: nowrap !important;
}

/* Calendar title row: smaller */
td.calTitleFieldExpanded,
td.calTitleFieldCollapsed,
td.calTitleDateCell {
  font-size: 11px !important;
  padding: 2px 4px !important;
}

/* Calendar day cells: tighter */
td.calMonthDayCell,
td.calMonthDayHeader {
  font-size: 11px !important;
  padding: 1px 2px !important;
}

/* Timezone select: compact */
td#mapControlCell select,
td.mapControlCell select {
  font-size: 11px !important;
  padding: 3px 4px !important;
  min-height: 24px !important;
  height: auto !important;
}

/* Cursor Location / Distance labels: smaller */
td#mapControlCell td,
td.mapControlCell td {
  font-size: 11px !important;
}

/* Replay / InfoBox row */
td#mapControlCell input[type="checkbox"],
td.mapControlCell input[type="checkbox"] {
  margin: 0 2px !important;
}

/* Battery level text */
td#mapControlCell .noborderTable,
td.mapControlCell .noborderTable {
  font-size: 11px !important;
}

/* calTable: full width inside 170px panel */
table.calTable {
  width: 100% !important;
}

div#mapCal_fr,
div#mapCal_to {
  width: 100% !important;
}

/* ============================================================
   MAP CONTROL CELL HEIGHT FIX
   The calendar panel (right column) is taller than the map,
   expanding the shared TR and leaving white space left of it.
   Cap mapControlCell at mapH so it doesn't inflate the TR.
   ============================================================ */
@media (min-width: 1201px) {
  td#mapControlCell,
  td.mapControlCell {
    height: var(--map-h, calc(100vh - 115px)) !important;
    max-height: var(--map-h, calc(100vh - 115px)) !important;
    overflow-y: auto !important;
    overflow-x: hidden !important;
    vertical-align: top !important;
  }
}

/* ============================================================
   TOP NAV + SELECTOR ROW — COMPACT
   Menu tabs, tracker selector, Next/Manage/Load buttons
   ============================================================ */

/* Menu bar tabs: smaller, tighter */
.menuBarUns, .menuBarUnsW, .menuBarSel, .menuBarSelW,
.menuBarUns20, .menuBarSel20 {
  padding: 5px 10px !important;
  font-size: 12px !important;
  min-height: 28px !important;
  min-width: 60px !important;
  border-radius: 6px !important;
}

/* Top selector row buttons (Next Tracker, Manage Task, Load Missing Addresses) */
td.selectorCell input[type="button"],
td.selectorCell .formButton,
#mapSelectForm input[type="button"],
#mapSelectForm .formButton,
td.contentTrackMapCellFull > table > tbody > tr:first-child input[type="button"],
td.contentTrackMapCellFull > table > tbody > tr:first-child .formButton {
  padding: 4px 10px !important;
  font-size: 12px !important;
  min-height: 26px !important;
  border-radius: 6px !important;
}

/* Last Event text: smaller */
td.contentTrackMapCellFull > table > tbody > tr:first-child td {
  font-size: 12px !important;
  padding: 2px 4px !important;
}

/* ============================================================
   DATA TABLE — COMPACT + STYLED
   ============================================================ */

/* Hide/Show Location Details link */
a[onclick*="trackMapShowHideDetails"],
#trackMapDataTable > div > a,
td[onclick*="Details"] {
  font-size: 12px !important;
  padding: 3px 0 !important;
  display: block !important;
  text-align: center !important;
}

/* Data table header row */
table.mapDetailsTable th,
table.mapDetailsTable_sortable th,
table.adminSelectTable th {
  font-size: 11px !important;
  padding: 4px 6px !important;
  background: #2c3e50 !important;
  color: #fff !important;
  white-space: nowrap !important;
}

/* Data table cells */
table.mapDetailsTable td,
table.mapDetailsTable_sortable td,
table.adminSelectTable td {
  font-size: 11px !important;
  padding: 3px 6px !important;
  white-space: nowrap !important;
}

/* Alternating rows */
table.mapDetailsTable tr:nth-child(even) td,
table.mapDetailsTable_sortable tr:nth-child(even) td {
  background: #f8fafc !important;
}

table.mapDetailsTable tr:hover td,
table.mapDetailsTable_sortable tr:hover td {
  background: #dbeafe !important;
}

/* "View On Map" links in data table */
table.mapDetailsTable td a,
table.mapDetailsTable_sortable td a {
  color: var(--primary) !important;
  font-size: 11px !important;
}

/* trackMapDataTable scroll container */
#trackMapDataTable {
  max-height: 220px !important;
  overflow-y: auto !important;
  overflow-x: auto !important;
  border-top: 2px solid var(--border) !important;
}

/* ============================================================
   MAP CONTROL PANEL — TIGHT SPACING (v2.6.0)
   Reduces all margins/padding/hr gaps between sections
   Based on exact HTML structure from tracker_map.html
   ============================================================ */

/* Overall inner table of mapControlCell: no padding */
td#mapControlCell > table,
td.mapControlCell > table {
  width: 100% !important;
  border-spacing: 0 !important;
  border-collapse: collapse !important;
}

/* All TRs in the control panel: zero margin */
td#mapControlCell > table > tbody > tr > td,
td.mapControlCell > table > tbody > tr > td {
  padding-top: 0 !important;
  padding-bottom: 0 !important;
}

/* "Select Date Range:" header */
td#mapControlCell > table > tbody > tr:first-child > td {
  font-size: 10px !important;
  padding: 2px 0 1px 0 !important;
  border-top: 1px solid #ccc !important;
}

/* calDiv container: reduce height, remove margin */
div#calDiv {
  height: auto !important;
  margin-top: 1px !important;
}

/* mapCal_to: reduce top margin */
div#mapCal_to {
  margin-top: 1px !important;
}

/* Calendar expand/collapse arrow bar */
td.calExpandBar,
td.calCollapseBar {
  padding: 0 !important;
  line-height: 1 !important;
}

/* Calendar day cells: tighter */
td.calMonthDOW,
td.calThisMonthDaysEnabled,
td.calThisMonthDaysDisabled,
td.calSelectedDay,
td.calNextMonthDays,
td.calPrevMonthDays {
  font-size: 10px !important;
  padding: 1px 2px !important;
  text-align: center !important;
}

/* Calendar month header (◄ Feb '26 ►) */
td.calMonthAdvance,
td.calMonthName {
  font-size: 10px !important;
  padding: 1px 0 !important;
}

/* HR separators: minimal */
td#mapControlCell hr,
td.mapControlCell hr {
  margin: 2px 0 !important;
  border: none !important;
  border-top: 1px solid #e5e7eb !important;
}

/* TimeZone section: tight */
form#TimeZoneSelect {
  margin: 0 !important;
  padding: 0 !important;
}

form#TimeZoneSelect span {
  font-size: 10px !important;
  line-height: 1.2 !important;
}

form#TimeZoneSelect select {
  font-size: 10px !important;
  padding: 1px 2px !important;
  min-height: 18px !important;
  height: 18px !important;
  width: 100% !important;
  margin: 0 !important;
  border-radius: 4px !important;
}

/* UpdateMap form: already flex, just tighten margin */
form#UpdateMap {
  margin: 2px 0 !important;
  padding: 0 !important;
}

/* Replay form: tighter */
form#ReplayMap {
  margin: 1px 0 0 0 !important;
}

form#ReplayMap table {
  margin: 0 !important;
}

form#ReplayMap b,
form#ReplayMap label {
  font-size: 11px !important;
}

/* Cursor Location section */
#trackMapLatLonDisplay,
#trackMapDistanceDisplay {
  font-size: 10px !important;
  margin: 0 0 0 4px !important;
  line-height: 1.3 !important;
}

td#mapControlCell b,
td.mapControlCell b {
  font-size: 10px !important;
}

/* Pushpin legend */
span.mapProviderLegend {
  font-size: 10px !important;
  font-weight: bold !important;
}

table.mapProviderLegend td {
  padding: 1px 3px 1px 0 !important;
  font-size: 10px !important;
  line-height: 1.2 !important;
}

table.mapProviderLegend img {
  width: 10px !important;
  height: 16px !important;
}

/* Battery level */
td#lastBatteryLevel img {
  height: 14px !important;
}

td#lastBatteryLevel b,
td#lastBatteryLevel + td b {
  font-size: 10px !important;
}

table#mapControlCell > table > tbody > tr:last-child > td,
td#mapControlCell > table > tbody > tr:last-child > td {
  padding-bottom: 2px !important;
}

/* ============================================================
   MERGE NOPRINT (Main Menu|Logout) + MENU BAR INTO ONE ROW
   noprint sits above menuBar in the DOM — use negative margin
   to pull the menuBar up, and position noprint links to the right.
   ============================================================ */

/* noprint: shrink to zero height, float links to the right */
div.noprint {
  height: 0 !important;
  overflow: visible !important;
  position: relative !important;
  z-index: 10 !important;
  margin: 0 !important;
  padding: 0 !important;
}

div.noprint table {
  position: absolute !important;
  right: 0 !important;
  top: 0 !important;
  width: auto !important;
  margin: 0 !important;
  padding: 0 !important;
}

div.noprint td.navBarClear {
  font-size: 11px !important;
  padding: 4px 4px !important;
  white-space: nowrap !important;
}

div.noprint a {
  font-size: 11px !important;
  color: var(--primary) !important;
}

/* menuBar TD: add right padding so tabs don't overlap the links */
td.menuBar {
  padding-right: 120px !important;
}

/* ============================================================
   DATE CHOOSER — FILL FULL WIDTH OF PANEL (v2.7.0)
   mapCal_fr/mapCal_to have inline width:150px
   mapControlCell is 170px with 5px padding-left = 165px usable
   Override inline widths to fill available space.
   ============================================================ */
div#mapCal_fr,
div#mapCal_to {
  width: 100% !important;
  box-sizing: border-box !important;
}

div#calDiv {
  width: 100% !important;
  height: auto !important;
  box-sizing: border-box !important;
}

table#mapCal_fr\.table,
table#mapCal_to\.table {
  width: 100% !important;
}

table.calTable {
  width: 100% !important;
}

table.calMonthDaysTable,
table.calMonthHeaderTable,
table.calTitleTable {
  width: 100% !important;
}

/* ============================================================
   MOBILE FIXES (v2.8.0)
   ============================================================ */

/* 1. MENU TABS: stretch to fill full width, no wrapping */
@media (max-width: 1200px) {
  td.menuBar > table {
    width: 100% !important;
    table-layout: fixed !important;
  }
  td.menuBar > table > tbody > tr > td {
    width: auto !important;
    text-align: center !important;
    white-space: nowrap !important;
    overflow: hidden !important;
    text-overflow: ellipsis !important;
  }
  /* Tighter padding so all 4 tabs fit on 375px */
  .menuBarUnsW, .menuBarSelW,
  .menuBarUns, .menuBarSel {
    padding: 6px 4px !important;
    font-size: 11px !important;
    min-width: 0 !important;
    min-height: 28px !important;
  }
}

/* 2. DATA TABLE WRAPPER: allow horizontal scroll */
#trackMapDataTable {
  overflow-x: auto !important;
  overflow-y: auto !important;
  -webkit-overflow-scrolling: touch !important;
  max-width: 100% !important;
  display: block !important;
}

/* Ensure the wrapper doesn't get clipped by ancestors */
td.contentTrackMapCellFull,
td.mapProviderCell {
  overflow-x: visible !important;
}

/* ============================================================
   FIX CONTENT TABLE OVERFLOW ON NARROW MOBILE (v2.9.0)
   
   On 360px screens, contentTable computes to 430px because
   its ancestor TR/TD are 430px (table natural content width).
   CSS width:100% on the table alone doesn't fix it — the
   parent TR drives the width. Fix the entire ancestor chain.
   ============================================================ */
@media (max-width: 480px) {
  /* Constrain the outermost wrapper table and all its rows */
  body > table,
  body > div > table {
    width: 100% !important;
    max-width: 100vw !important;
    min-width: 0 !important;
    table-layout: fixed !important;
  }

  body > table > tbody > tr,
  body > table > tbody > tr > td,
  body > div > table > tbody > tr,
  body > div > table > tbody > tr > td {
    width: 100% !important;
    max-width: 100vw !important;
    min-width: 0 !important;
    box-sizing: border-box !important;
  }

  /* contentTable and its TR row */
  table.contentTable {
    table-layout: fixed !important;
    width: 100% !important;
    max-width: 100vw !important;
  }

  table.contentTable > tbody > tr,
  table.contentTable > tbody > tr > td {
    max-width: 100vw !important;
    min-width: 0 !important;
    box-sizing: border-box !important;
    overflow: hidden !important;
  }

  /* Charts and images: never wider than viewport */
  canvas, svg, img {
    max-width: 100% !important;
    height: auto !important;
  }
}

/* ============================================================
   REPORTS PAGE — DESKTOP VISUAL POLISH (v2.10.0)
   Target look: gray background, compact left panel with
   border-right divider, no white card on right, no scroll.
   ============================================================ */

/* Gray background matching image1 reference */
body.modern-shell:has(table[height="90%"]) {
  background-color: #e8eaed !important;
}
body.modern-shell:has(table[height="90%"]) .responsive-wrapper,
body.modern-shell:has(table[height="90%"]) td.contentCell,
body.modern-shell:has(table[height="90%"]) td.contentTrackMapCell,
body.modern-shell:has(table[height="90%"]) td.contentTrackMapCellFull,
body.modern-shell:has(table[height="90%"]) table.contentTable {
  background-color: #e8eaed !important;
}

/* Kill the height="90%" attribute — it inflates table to 615px+
   causing empty space below content */
table[height="90%"] {
  height: auto !important;
  min-height: 0 !important;
  background-color: #e8eaed !important;
}
table[height="90%"] > tbody > tr > td {
  height: auto !important;
}
table.contentTable {
  height: auto !important;
}

@media (min-width: 1201px) {
  /* Left panel: same gray, compact fixed width */
  table[height="90%"] > tbody > tr > td:first-child {
    background-color: #e8eaed !important;
    padding: 8px 10px !important;
    vertical-align: top !important;
    width: 175px !important;
    min-width: 175px !important;
    border-right: 3px double #aaa !important;
  }

  /* Right panel: same gray, no white card */
  table[height="90%"] > tbody > tr > td:last-child {
    background-color: #e8eaed !important;
    padding: 8px 16px !important;
    vertical-align: top !important;
  }

  /* Calendar width chain: leftTd(183) → anonDiv(161) → calDiv → rptCal
     The anonymous DIV at 161px is the bottleneck — stretch it to 100% */
  table[height="90%"] > tbody > tr > td:first-child > div,
  table[height="90%"] > tbody > tr > td:first-child > div > div {
    width: 100% !important;
    max-width: 100% !important;
    box-sizing: border-box !important;
  }
  #calDiv, div.calDiv {
    width: 100% !important;
    max-width: 100% !important;
  }
  #rptCal_fr, #rptCal_to {
    width: 100% !important;
    max-width: 100% !important;
  }
  #rptCal_fr > table,
  #rptCal_to > table,
  #rptCal_fr table,
  #rptCal_to table {
    width: 100% !important;
  }

  /* Reduce title/instructions spacing to close the empty gap below Get Report */
  td.contentCell > span.menuTitle {
    display: block !important;
    margin: 4px 0 2px 0 !important;
    font-size: 14px !important;
  }
  td.contentCell > span.menuInstructions {
    display: block !important;
    margin: 0 0 4px 0 !important;
    font-size: 12px !important;
  }
  td.contentCell > br {
    display: none !important;
  }
  td.contentCell > hr {
    margin: 4px 0 6px 0 !important;
  }

  /* rptCal width: controlled via chain width:100% below */

  /* Report radio rows: tight spacing */
  table[height="90%"] td > table tr td {
    padding: 2px 4px !important;
    vertical-align: middle !important;
    white-space: nowrap !important;
  }

  /* Dropdowns: auto width, max 320px */
  table[height="90%"] select.adminComboBox {
    width: auto !important;
    max-width: 320px !important;
  }

  /* Task search input: reasonable fixed width */
  #r_txt_OTDR {
    width: 260px !important;
    max-width: 260px !important;
    display: inline !important;
    margin-top: 0 !important;
  }

  /* Format row: inline compact */
  form#GetReport {
    display: flex !important;
    align-items: center !important;
    gap: 8px !important;
    margin-top: 12px !important;
  }
  form#GetReport select {
    width: auto !important;
    max-width: 100px !important;
  }
  form#GetReport input[type="submit"] {
    width: auto !important;
  }
}
/* ── END Reports page visual polish ── */

/* ============================================================
   REPORTS PAGE — REDUCE CONTENTCELL PADDING (v2.10.1)
   contentCell h:679 vs table90 h:603 = 76px gap from padding
   and title/instructions spacing. Tighten to remove scroll feel.
   ============================================================ */
@media (min-width: 1201px) {
  body.modern-shell:has(table[height="90%"]) td.contentCell {
    padding: 4px 8px !important;
    vertical-align: top !important;
  }
}

/* ============================================================
   REPORTS PAGE — SUPPRESS PHANTOM SCROLLBAR (v2.10.2)
   html and .responsive-wrapper have overflow-y:auto which shows
   a phantom scrollbar even when scrollHeight === clientHeight.
   Switch to overflow-y:hidden on reports page only.
   ============================================================ */
body.modern-shell:has(table[height="90%"]) {
  overflow-y: hidden !important;
}
body.modern-shell:has(table[height="90%"]) .responsive-wrapper {
  overflow-y: hidden !important;
}

/* ============================================================
   REPORTS PAGE — REMOVE TOP WHITESPACE (v2.10.3)
   The space above the menu bar comes from the contentTable
   outer wrapper having default cellspacing/padding.
   ============================================================ */
body.modern-shell:has(table[height="90%"]) table.contentTable {
  border-spacing: 0 !important;
  border-collapse: collapse !important;
  padding: 0 !important;
  margin: 0 !important;
}

body.modern-shell:has(table[height="90%"]) table.contentTable > tbody > tr:first-child > td {
  padding: 0 !important;
  margin: 0 !important;
}

/* menuGroup row: compact it */
body.modern-shell:has(table[height="90%"]) td.menuGroup,
body.modern-shell:has(table[height="90%"]) tr.menuGroup > td {
  padding: 0 !important;
  margin: 0 !important;
  height: auto !important;
  line-height: 1 !important;
}

/* ============================================================
   REPORTS PAGE — SCROLLBAR GUTTER FIX (v2.10.4)
   Windows browsers reserve scrollbar gutter space even when
   content fits. Use scrollbar-gutter:stable to prevent reflow
   without showing a phantom scrollbar track.
   ============================================================ */
body.modern-shell:has(table[height="90%"]) {
  overflow-y: hidden !important;
  scrollbar-gutter: stable !important;
}

/* ============================================================
   REPORT OUTPUT — DESKTOP + MOBILE FIT (v2.10.5)

   Strategy: content is never truncated or wrapped mid-value.
   Instead the table renders at natural width and the wrapper
   scrolls horizontally when needed — on ALL screen sizes.
   A thin scrollbar-free scroll container hides the OS bar.

   This is generic — works for any report with any columns.
   ============================================================ */

/* Table: natural width, never squished */
table.rptTbl_sortable {
  width: auto !important;
  table-layout: auto !important;
  font-size: 11px !important;
  border-collapse: collapse !important;
}

/* All headers: compact padding, never wrap */
th.rptHdrCol_sort,
th.rptHdrCol {
  padding: 5px 6px !important;
  font-size: 11px !important;
  white-space: nowrap !important;
}

/* All data cells: compact, never wrap — preserves all values intact */
td.rptBodyCol {
  padding: 4px 6px !important;
  font-size: 11px !important;
  white-space: nowrap !important;
  vertical-align: top !important;
}

/* Outer report layout table: must not exceed viewport width.
   This is the TABLE at ancestor level 5 wrapping CENTER > rptTbl_sortable.
   Without this constraint it inflates to table natural width (1905px)
   and the inner scroll div inherits that width — defeating overflow:auto. */
td.reportDisplayCell {
  max-width: 100vw !important;
  width: 100% !important;
  box-sizing: border-box !important;
  padding: 4px !important;
  overflow: hidden !important;
}

/* The outer table wrapping CENTER must be capped too */
table.reportDisplayTable,
td.reportDisplayCell > center,
td.reportDisplayCell > * {
  max-width: 100% !important;
  width: 100% !important;
  box-sizing: border-box !important;
}

/* CENTER becomes the scroll container */
td.reportDisplayCell > center {
  display: block !important;
  overflow-x: auto !important;
  -webkit-overflow-scrolling: touch !important;
  scrollbar-width: thin !important;
  scrollbar-color: #ccc transparent !important;
}
td.reportDisplayCell > center::-webkit-scrollbar { height: 4px !important; }
td.reportDisplayCell > center::-webkit-scrollbar-thumb { background: #ccc !important; border-radius: 2px !important; }

/* ============================================================
   ADMIN/FORM PAGES — LAYOUT FIX (v2.11.0)
   ============================================================ */


/* Desktop zoom: handled via JS (zoom CSS not cross-browser) */


/* Admin table: never full viewport width */
table.adminTable,
table.adminSurroundTable {
  width: auto !important;
  max-width: 900px !important;
}

/* Admin body cols: restore natural inline layout, no word-break */
td.adminTableBodyCol {
  width: auto !important;
  max-width: 500px !important;
  word-break: normal !important;
  white-space: normal !important;
}

/* Inputs: size to content, capped at 400px — matches original look */
td.adminTableBodyCol input[type="text"],
td.adminTableBodyCol input:not([type]),
td.adminTableBodyCol input[type="password"],
td.adminTableBodyCol input[type="email"],
td.adminTableBodyCol textarea {
  width: auto !important;
  max-width: 400px !important;
  min-width: 120px !important;
  box-sizing: border-box !important;
}

/* Row backgrounds: subtle gray like original */
tr.adminTableBodyRowOdd {
  background-color: #f8f9fa !important;
}
tr.adminTableBodyRowEven {
  background-color: #ffffff !important;
}

/* Content background on admin pages - apply only to contentCell, not wrapper
   (applying to wrapper caused grey strip below short-content pages v2.12.4) */
body.modern-shell:not(:has(#jsmap)):not(:has(table[height="90%"])) td.contentCell {
  background-color: #e8eaed !important;
}

/* ============================================================
   ADMIN PAGES — BUTTON LAYOUT + POLISH (v2.11.1)
   ============================================================ */

/* Change/Cancel/Submit buttons: always inline, never stacked */
@media (min-width: 1201px) {
  td.adminTableFooterRow input[type="submit"],
  td.adminTableFooterRow input[type="button"],
  td.adminTableFooterRow input.formButton,
  td.adminTableFooterRow button,
  /* Also catch buttons directly in TR without specific TD class */
  tr:has(input[type="submit"]) input[type="submit"],
  tr:has(input[type="submit"]) input[type="button"],
  tr:has(input[type="submit"]) input.formButton {
    display: inline-block !important;
    width: auto !important;
    margin-right: 8px !important;
  }

  /* The TD containing the buttons: don't stack them */
  td.adminTableFooterRow,
  tr:has(input[type="submit"]) > td {
    white-space: nowrap !important;
  }
}

/* Mobile: buttons full width but still spaced */
@media (max-width: 1200px) {
  td.adminTableFooterRow input[type="submit"],
  td.adminTableFooterRow input.formButton,
  tr:has(input[type="submit"]) input[type="submit"],
  tr:has(input[type="submit"]) input.formButton {
    display: inline-block !important;
    width: auto !important;
    margin: 4px 8px 4px 0 !important;
  }
}

/* ============================================================
   ADMIN PAGES — HR BETWEEN BUTTONS FIX (v2.11.2)
   A literal <HR> tag sits between Change and Cancel buttons
   in the form, pushing Cancel below Change.
   Hide HR elements that are direct children of forms.
   ============================================================ */
form > hr,
form > HR {
  display: none !important;
}


/* ============================================================
   ADMIN VIEW/EDIT TABLE - MOBILE FIX (v2.12.1)
   Real classes: adminViewTable, adminViewTableHeader, adminViewTableData
   Data TD has hardcoded width=500 in HTML, overflows 430px mobile.
   Cannot use display:block on TDs inside tables reliably.
   Instead: cap the outer table and use overflow+scroll approach,
   then use a JS transform via patches for true stacking.
   ============================================================ */

/* Desktop: cap data column */
td.adminViewTableData {
  max-width: 520px !important;
  box-sizing: border-box !important;
  overflow: hidden !important;
}

td.adminViewTableData input,
td.adminViewTableData select,
td.adminViewTableData textarea {
  max-width: 100% !important;
  width: auto !important;
  box-sizing: border-box !important;
}

/* Cap the outer table itself */
table.adminViewTable {
  max-width: 100% !important;
  width: auto !important;
}

/* Mobile: make contentCell scrollable instead of clipping */
@media (max-width: 600px) {
  td.contentCell {
    overflow-x: auto !important;
    padding: 4px !important;
  }

  table.adminViewTable {
    width: 100% !important;
    table-layout: fixed !important;
  }

  td.adminViewTableHeader {
    width: 38% !important;
    max-width: 38% !important;
    word-break: break-word !important;
    white-space: normal !important;
    font-size: 11px !important;
    padding: 4px 4px !important;
    vertical-align: middle !important;
  }

  td.adminViewTableData {
    width: 62% !important;
    max-width: 62% !important;
    overflow: hidden !important;
    padding: 4px 4px !important;
  }

  td.adminViewTableData input,
  td.adminViewTableData select {
    width: 100% !important;
    max-width: 100% !important;
    min-width: 0 !important;
    box-sizing: border-box !important;
    font-size: 12px !important;
  }
}


/* ============================================================
   GEOZONE MAP TABLE HEIGHT FIX (v2.12.2)
   zone.info structure: outer-TD(h:630px) > TABLE(width:100%, no height)
   > TBODY > TR > TD.mapProviderCell > #jsmap(h:630px inline)
   
   The inner TABLE has no height, so it collapses to h:0 despite
   its parent TD being 630px tall. #jsmap inline height:630px is
   then ignored because the table-cell (mapProviderCell) has h:0.
   
   Fix: make the inner table and its rows fill their parent TD.
   Target: table containing mapProviderCell that is itself inside a TD.
   ============================================================ */
td > table:has(td.mapProviderCell) {
  height: 100% !important;
}

td > table:has(td.mapProviderCell) > tbody,
td > table:has(td.mapProviderCell) > tbody > tr {
  height: 100% !important;
}


/* ============================================================
   GEOZONE MOBILE OVERFLOW FIXES
   zone.info: zoneDescription span and form elements overflow vw
   ============================================================ */
@media (max-width: 1200px) {
  span.zoneDescription,
  div.zoneDescription {
    max-width: 100% !important;
    width: auto !important;
    box-sizing: border-box !important;
    overflow: hidden !important;
    text-overflow: ellipsis !important;
    white-space: nowrap !important;
  }

  div.zoneCheckSelect {
    max-width: 100% !important;
    box-sizing: border-box !important;
  }

  /* Geozone form TD: constrain all content to viewport width */
  td > table td.mapProviderCell ~ td,
  tr > td:last-child:has(~ td.mapProviderCell) {
    max-width: 100vw !important;
    box-sizing: border-box !important;
    overflow-x: hidden !important;
  }
}

@media (max-width: 1200px) {
  /* Geozone page: clip all tables to viewport width */
  body.modern-shell:has(td.mapProviderCell) table {
    max-width: 100vw !important;
    overflow-x: hidden !important;
  }
  body.modern-shell:has(td.mapProviderCell) td {
    max-width: 100vw !important;
    box-sizing: border-box !important;
  }
}

/* ============================================================
   v2.12.4 — HOME PAGE MENU COLOUR UNIFICATION
   Confirmed visually in console. Aligns expandable menu items
   with the site's --primary teal (#00bcd4) so buttons and menu
   use one consistent colour family instead of teal + light blue.
   ============================================================ */

/* Dashboard buttons — ensure consistent teal (overrides Bootstrap btn-link) */
td.contentTopMenuCell .btn.btn-link {
  background-color: var(--primary) !important;
  color: #ffffff !important;
  border-radius: 6px !important;
  text-decoration: none !important;
}
td.contentTopMenuCell .btn.btn-link:hover,
td.contentTopMenuCell .btn.btn-link:focus {
  background-color: var(--primary-2) !important;
  color: #ffffff !important;
}

/* Expandable menu group headers — dark teal matching buttons */
#topMenuExpand li.menuGroup {
  background-color: var(--primary) !important;
  color: #ffffff !important;
  border-radius: 6px !important;
  margin-bottom: 4px !important;
}
#topMenuExpand li.menuGroup:hover {
  background-color: var(--primary-2) !important;
}

/* Expanded sub-items — light teal so hierarchy is clear */
#topMenuExpand li.itemLeaf {
  background-color: #e0f7fa !important;
  color: #006064 !important;
  border-radius: 4px !important;
  margin-bottom: 2px !important;
}
#topMenuExpand li.itemLeaf:hover {
  background-color: #b2ebf2 !important;
}
#topMenuExpand li.itemLeaf a,
#topMenuExpand li.itemLeaf .itemLeafDesc {
  color: #006064 !important;
  text-decoration: none !important;
}
#topMenuExpand li.itemLeaf a:hover {
  color: #004d40 !important;
  text-decoration: underline !important;
}

/* ============================================================
   THE BULK-GRID HOLD (v3.114.0)
   ============================================================
   The four bulk-grid pages (zone/dev/user/group.info) are re-skinned
   by modern-patches, and the browser paints the page progressively as
   it parses - so the legacy grid used to flash before the script could
   dress it (user, 2026-08-19). The class is armed BEFORE any paint:
   modern-patches' own bootstrap does it where the server loads the
   script in <head>, decorators/main.jsp does it on the decorated
   path. modern-patches releases it with body.mpb-ready the moment the
   grid is dressed - and the animation releases it even if no script
   ever gets that far, so nothing can leave the page blank.
   The rule lives HERE because this sheet is linked in <head> on both
   paths, ahead of the first paint.

   The delay is 8s (v3.118.0, was 1.6s): it is a dead-man's switch for
   a script that armed the hold and then died, nothing more. At 1.6s it
   doubled as a wall clock racing real devices - a 4x-throttled phone
   parses these pages for ~8s, so the switch tripped mid-parse and
   handed the user the legacy grid it exists to hide (user, 2026-08-20).
   The delay counts from when the parser creates td.contentCell, so on
   slow devices it starts late too - the healthy release always comes
   first, from modern-patches at DOMContentLoaded. */
html.modern-ui.mp-bulkhold body:not(.mpb-ready) td.contentCell {
    /* v3.127.0: allow progressive rendering on large server-rendered grids.
       The old visibility:hidden hold made modern mode look frozen until the
       final row had parsed, unlike legacy mode. Modern CSS is already present
       in <head>; reveal rows as they arrive and keep only a loading cue. */
    visibility: visible;
    animation: none;
}
/* mp-holdlive = modern-patches itself armed the hold, so its JS
   releases (DCL + 1.2s, load) are bound and guaranteed — the switch
   stands down entirely and no wall clock races the parser at all.
   The decorator path arms the hold without this class and keeps the
   8s fuse, because there the script may never arrive. */
html.modern-ui.mp-bulkhold.mp-holdlive body:not(.mpb-ready) td.contentCell {
    visibility: visible;
    animation: none;
}
@keyframes mpBulkHold {
    to { visibility: visible; }
}
/* While the hold is on, the empty content area says so (user,
   2026-08-20): the same card-and-ring the report pages show while
   streaming. Pseudos of the held cell itself, so everything shares
   one clock: visibility:visible overrides the cell's hidden (pseudos
   may do that; display could not), and the 8s dead-man fuse hides the
   cue on exactly the animation-delay anchor that reveals the cell —
   both count from the cell's creation. Under mp-holdlive the fuse is
   disarmed on both, and the cue simply leaves with body.mpb-ready.
   The card sits fixed under the app bar and veils nothing: the header
   and menus stay usable the whole time. */
/* v3.130.0: keep the progressive-load cue visually centred in the
   viewport.  It remains non-blocking (pointer-events:none), so the app bar
   and already-streamed rows stay usable while the remainder of the server
   response is arriving. */
html.modern-ui.mp-bulkhold body:not(.mpb-ready) td.contentCell::after {
    content: 'Loading…';
    visibility: visible;
    position: fixed;
    top: 50%;
    left: 50%;
    right: auto;
    transform: translate(-50%, -50%);
    z-index: 4000;
    pointer-events: none;
    min-width: 132px;
    box-sizing: border-box;
    padding: 58px 24px 18px;
    text-align: center;
    background: var(--cmw-surface);
    border: 1px solid var(--cmw-border);
    border-radius: var(--cmw-radius-lg);
    box-shadow: var(--cmw-shadow);
    font: 600 15px var(--cmw-font);
    color: var(--cmw-ink);
    animation: mpBulkCueHide 0s linear 8s forwards;
}
html.modern-ui.mp-bulkhold body:not(.mpb-ready) td.contentCell::before {
    content: '';
    visibility: visible;
    position: fixed;
    top: calc(50% - 30px);
    left: calc(50% - 11px);
    right: auto;
    width: 22px;
    height: 22px;
    border: 2.5px solid var(--cmw-border);
    border-top-color: var(--cmw-primary-dark);
    border-radius: 50%;
    z-index: 4001;
    pointer-events: none;
    animation: mpBulkSpin 0.7s linear infinite,
               mpBulkCueHide 0s linear 8s forwards;
}
html.modern-ui.mp-bulkhold.mp-holdlive body:not(.mpb-ready) td.contentCell::after {
    animation: none;
}
html.modern-ui.mp-bulkhold.mp-holdlive body:not(.mpb-ready) td.contentCell::before {
    animation: mpBulkSpin 0.7s linear infinite;
}
@keyframes mpBulkSpin {
    to { transform: rotate(360deg); }
}
@keyframes mpBulkCueHide {
    to { visibility: hidden; }
}

/* ============================================================
   ZEBRA ROWS, EVERYWHERE (v3.115.0)
   ============================================================
   Alternating rows are the agreed design for every admin table, and
   they had died site-wide in a cascade fight: cells forced
   transparent, then the row colour re-whitened by a later rule in
   THIS file, leaving at best a 2% tint no ordinary panel can show
   (user: "I need it everywhere", 2026-08-19). The bulk grids carry
   their own copy of this at higher weight; this one covers every
   other table the server marks with Odd/Even row classes, including
   the map details table.

   Striped by POSITION among the marked rows, not by the classes
   themselves: the sorters move rows around and the classes travel
   with them, and a sorted table would otherwise show two tinted rows
   touching. Declared last in this file on purpose - it must outrank
   the earlier per-class rules at equal importance. */
html.modern-ui table tr:nth-child(even of .adminTableBodyRowOdd, .adminTableBodyRowEven),
html.modern-ui table tr:nth-child(even of .mapDetailsDataRowOdd, .mapDetailsDataRowEven) {
    background-color: var(--cmw-stripe) !important;
}
/* the sortable lists have always tinted the row under the pointer;
   the stripe must not outrank that */
html.modern-ui table.adminSelectTable_sortable tbody
    tr:nth-child(even of .adminTableBodyRowOdd, .adminTableBodyRowEven):hover {
    background-color: var(--cmw-surface-alt) !important;
}
