/* ============================================================
   responsive.css — Mobile/responsive overrides for Q2019.
   Loaded for ALL clients, AFTER the legacy stylesheets, so its
   rules win on equal specificity. Legacy CSS is untouched.

   Strategy: the legacy layout is a fixed-width, float-based two
   column design (left character panel 310px + offset content).
   On narrow screens we collapse it into a single full-width
   stacked column. !important is used only where we must defeat
   inline styles in _template.php (which otherwise win).

   Rounds:
     R1 (this file, initial) - viewport + single-column collapse.
     R2 - top toolbar + nav reflow.
     R3 - in-content tables / map / forms overflow.
     R4 - polish (tap targets, fonts, logo).
   ============================================================ */

/* ============================================================
   BASE (all widths) — keep the restructured nav markup looking
   IDENTICAL to the legacy single-<ul> toolbar on desktop.
   Round 2 split the toolbar into two <ul>s (.tlbactions +
   .tlbsite) and added per-link icons (.ti) + labels (.tl).
   Desktop must ignore the icons and flow both lists on one row.
   ============================================================ */

/* Hide the nav icons on desktop; show the text labels (legacy look). */
#toolbarcontent .ti { display: none; }

/* Both lists were one <ul> before; make them flow inline so the
   floated <li>s (tlbleft/tlbright) lay out exactly as they used to. */
#toolbarcontent ul.tlbactions,
#toolbarcontent ul.tlbsite {
  display: inline;
}

/* The hamburger nav item is mobile-only (on desktop the footer carries these
   links, so no hamburger is needed). The mobile media block re-shows it. */
#toolbarcontent ul.tlbactions li.m_nav_menu_item { display: none; }


/* Never let any element force a horizontal scrollbar wider than
   the viewport on small screens. */
@media (max-width: 768px) {

  html, body {
    max-width: 100%;
    overflow-x: hidden;
  }

  /* The outer wrapper is 95% wide on desktop; on mobile take the
     full width and drop the side borders so content isn't inset. */
  #wrapper {
    width: 100%;
    border-left: 0;
    border-right: 0;
  }

  /* ---- Top toolbar (char select / Hide / premium / logout) ----
     Inline styles in _template.php hard-code min-width:812px;
     width:820px and display:table, which overflow a 390px screen.
     Force it fluid; full reflow of its contents is Round 2. */
  #top_toolbar_box {
    min-width: 0 !important;
    width: 100% !important;
    display: block !important;
    box-sizing: border-box;
    overflow: hidden;
  }

  /* ---- Column collapse: stack left panel above main content ----
     #left is float:left; width:310px and #middle has
     margin-left:315px. Unset both so each becomes a full-width
     block that stacks vertically. */
  #left {
    float: none !important;
    width: auto !important;
    margin: 0 0 10px 0 !important;
  }

  #middle,
  #widemiddle {
    margin: 0 !important;
  }

  /* #main1 has a right margin that, combined with full width,
     can cause minor overflow; normalize it. */
  #main1 {
    margin: 10px 0 0 0;
  }

  /* Keep any boxed content inside the column width, and give it a small
     gutter so content isn't pressed flush against the screen edges. The
     full-bleed chrome (top bar, nav action bar, bottom Context Bar) lives
     outside these columns and is intentionally not inset. */
  .column-in {
    box-sizing: border-box;
    padding-left: 8px;
    padding-right: 8px;
  }

  /* ---- R2: Hide the cityscape logo banner ----
     #header/#logo is the 90px QUARANTINE 2019 banner that sits
     between the character bar and the navbar. Reclaim that space
     on mobile. */
  #header { display: none !important; }

  /* ---- R2: Top bar — lift external link icons in, right-aligned ----
     The char-select sits left; the Game-Guide / Discord / Reddit
     icons sit right. The legacy #tb_content_right (premium / patch /
     rules / settings / logout text) doesn't fit on a phone, so it's
     hidden here (those remain reachable: Settings/Logout via the
     toolbar/menus, patch notes via the top bar on desktop). */
  #top_toolbar_box {
    display: flex !important;
    align-items: center;
    gap: 6px;
    padding: 2px 6px;
    height: auto !important;
  }

  #tb_content_right { display: none !important; }

  /* The [Hide] toolbar toggle is a desktop affordance for collapsing the
     820px bar; the mobile bar is already compact, so hide it on phones. */
  #tb_hide { display: none !important; }

  /* The decorative end-cap images assume the fixed 820px bar; as flex
     children their negative margins push content past the viewport. */
  #top_toolbar_box .tb_endcap { display: none !important; }

  /* ---- R2: Navbar -> single in-game action bar of icons ----
     The toolbar's site links move to the top bar above, so hide the
     in-toolbar copy. The action items become an evenly spaced icon
     row that fits one line at 390px. */
  #toolbar {
    height: auto;
  }
  #toolbarcontent,
  #toolbarcontent2 {
    height: auto;
    background-image: none;   /* the divider end-caps assume fixed height */
    margin: 0;
  }

  #toolbarcontent ul.tlbsite { display: none !important; }

  #toolbarcontent ul.tlbactions {
    display: flex;
    width: 100%;
    margin: 0;
    padding: 0;
  }

  #toolbarcontent ul.tlbactions li.tlbleft {
    float: none;
    flex: 1 1 0;              /* equal width across */
    background-image: none;   /* drop the legacy divider bg image */
    text-align: center;
  }

  /* Awards + Achievements are too crowded in the mobile nav bar; they move
     into the hamburger drawer (mobile_ui.js MISC_LINKS). Hide them here. */
  #toolbarcontent ul.tlbactions li.m_nav_drawered { display: none !important; }

  /* The hamburger is the last nav item on mobile (replacing the old fixed
     top-left button); re-show the item the BASE rule hides on desktop. */
  #toolbarcontent ul.tlbactions li.m_nav_menu_item { display: block; }

  #toolbarcontent ul.tlbactions li.tlbleft a {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: auto;
    line-height: 1.1;
    padding: 8px 2px;         /* generous vertical tap target */
  }

  /* Show the icon, hide the text by default (icon-only). */
  #toolbarcontent ul.tlbactions .ti {
    display: block;
    width: 24px;
    height: 24px;
  }
  #toolbarcontent ul.tlbactions .tl {
    display: none;
    font-size: 10px;
    margin-top: 3px;
  }

  /* Fallback / opt-in: body.nav-labels shows captions under icons. */
  body.nav-labels #toolbarcontent ul.tlbactions .tl {
    display: block;
  }

  /* ====================================================================
     R3: Context Bar + ContentView (new mobile system, mobile_ui.js)
     The legacy in-page game tab bar and its content wrapper are hidden;
     the new ContentView shows one fetched panel at a time, driven by a
     bottom-pinned Context Bar. The Character box stays separate.
     ==================================================================== */

  /* Hide the legacy game tab bar + its content wrapper on mobile. They are
     NOT removed (desktop and legacy-mode keep using them) -- just hidden.
     #maintabs_tab is hidden here in CSS (not just via the JS-added
     .m_legacy_hidden) so the legacy building content does NOT paint before
     mobile_ui.js boots -- otherwise it flashes in and is yanked away the
     instant the engine selects the restored tab (e.g. Local Map). */
  #maintabs { display: none !important; }
  #maintabs_tab { display: none !important; }
  .m_legacy_hidden { display: none !important; }

  /* The sidebar Local Map moves into the Context Bar's Map view on mobile, so
     hide the sidebar copy. The Character box (player_info_sidebar) stays. */
  .m_sidebar_map { display: none !important; }

  /* Leave room at the bottom so the fixed Context Bar never covers content.
     The single-view game screen has no ContextBar, so it reclaims that space
     (see body.m_page_game below). */
  body { padding-bottom: 60px; }

  /* ====================================================================
     Character HUD bar (mobile, game page) — mobile_ui.js buildCharBar.
     A compact 2-row status bar inserted ABOVE the green navbar (#toolbar),
     replacing the tall desktop character sidebar (#left). It is full-bleed
     chrome (inserted outside .column-in) so it spans edge-to-edge. Design
     tokens are the handoff "Refined HUD"; class colours are applied inline
     by the JS (zombie #6fc04a / human #4f9fd4).
     ==================================================================== */

  /* Hide the stacked legacy character box on the game page; the HUD bar above
     the navbar replaces it. (Mirrors body.m_page_groups #left.) */
  body.m_page_game #left { display: none !important; }

  @keyframes q19pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(255,210,74,0); }
    50%      { box-shadow: 0 0 0 4px rgba(255,210,74,.18); }
  }

  #m_charbar {
    display: flex;
    flex-direction: column;
    gap: 9px;
    padding: 9px 9px 11px;
    background: linear-gradient(#323232, #272727);
    border-bottom: 1px solid #4a4a3a;
    box-sizing: border-box;
    font-family: Tahoma, Verdana, "Segoe UI", sans-serif;
  }

  #m_charbar .m_cb_row1 { display: flex; align-items: center; gap: 9px; }
  #m_charbar .m_cb_row2 { display: flex; align-items: center; gap: 7px; margin-top: 5px; }

  /* ---- Avatar (XP ring + level pill) ---- */
  #m_charbar .m_cb_avatar { position: relative; width: 50px; height: 50px; flex-shrink: 0; }
  #m_charbar .m_cb_xpring { width: 50px; height: 50px; border-radius: 50%; }
  #m_charbar .m_cb_portrait {
    position: absolute; inset: 4px; border-radius: 50%;
    background: #141414; border: 1px solid #2a2a2a;
    display: flex; align-items: center; justify-content: center;
  }
  #m_charbar .m_cb_level {
    position: absolute; left: 50%; bottom: -5px; transform: translateX(-50%);
    background: #161616; border: 1px solid #6a5a28; color: #e7b34a;
    font-size: 9px; font-weight: 800; padding: 0 5px; border-radius: 7px;
    line-height: 14px; white-space: nowrap;
  }

  /* ---- Identity ----
     Name + group stay on ONE line each and are never abbreviated. The base
     sizes here are the MAX (name 14px prominent, group 11px); mobile_ui.js
     fitCharNames() shrinks the font-size down to a floor until each fits its
     column, so a long name/group scales down rather than wrapping or
     ellipsising. overflow:hidden is a safety net only -- the JS keeps the text
     within the box. */
  #m_charbar .m_cb_identity { min-width: 0; flex: 1; }
  #m_charbar .m_cb_name {
    font-size: 14px; font-weight: 700;
    white-space: nowrap; overflow: hidden; line-height: 1.25;
  }
  #m_charbar .m_cb_group {
    font-size: 11px; color: #5a9bd4;
    white-space: nowrap; overflow: hidden; line-height: 1.25;
  }
  #m_charbar .m_cb_dead { color: #d24a3d; font-weight: 800; }

  /* ---- Gauges (shared column: 40x40 + 8px caption, centres aligned) ----
     The column is a centred flex column: the dial/square (40px) and the caption
     are both centred on the column's vertical axis via align-items:center, so a
     caption wider than 40px (e.g. "50/50") stays centred on the gauge instead of
     pushing it off to one side. */
  #m_charbar .m_cb_gauge {
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
  }
  #m_charbar .m_cb_inv,
  #m_charbar .m_cb_skill { cursor: pointer; }
  #m_charbar .m_cb_skill { margin-right: 5px; }   /* room for the overflowing badge */
  #m_charbar .m_cb_cap { font-size: 11px; margin-top: 3px; line-height: 1; white-space: nowrap; text-align: center; }
  #m_charbar .m_cb_cap_ep  { color: #9ec0e0; }
  #m_charbar .m_cb_cap_inv { color: #e0b080; }
  #m_charbar .m_cb_cap_sp  { color: #e0c060; }

  #m_charbar .m_cb_inv:active,
  #m_charbar .m_cb_skill:active { transform: scale(.9); }
  #m_charbar .m_cb_inv:hover .m_cb_square,
  #m_charbar .m_cb_skill:hover .m_cb_dial { filter: brightness(1.12); }

  /* Circular dials (EP, Skill) */
  #m_charbar .m_cb_dial { position: relative; width: 40px; height: 40px; margin: 0 auto; border-radius: 50%; }
  #m_charbar .m_cb_ring { width: 40px; height: 40px; border-radius: 50%; }
  #m_charbar .m_cb_dialinner {
    position: absolute; inset: 4px; border-radius: 50%; background: #222;
    display: flex; align-items: center; justify-content: center;
  }

  /* Square inventory fill-meter */
  #m_charbar .m_cb_square {
    position: relative; width: 40px; height: 40px; margin: 0 auto;
    border-radius: 7px; overflow: hidden; background: #1a1a12;
    border: 1.5px solid #4cc24c;
  }
  #m_charbar .m_cb_squarefill { position: absolute; left: 0; right: 0; bottom: 0; }
  #m_charbar .m_cb_squareicon {
    position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  }

  /* Skill gauge states */
  #m_charbar .m_cb_skill_on .m_cb_dial { animation: q19pulse 2.4s ease-in-out infinite; }
  #m_charbar .m_cb_skill_off .m_cb_dial { opacity: .5; }
  #m_charbar .m_cb_skill_off .m_cb_dialinner { background: #1c1c1c; }
  #m_charbar .m_cb_skillbadge {
    position: absolute; right: -5px; top: -5px;
    font-size: 8px; font-weight: 800; color: #3a2700;
    background: linear-gradient(#ffe082, #ffc107);
    border: 1.5px solid #161616; border-radius: 7px; padding: 0 3px; line-height: 13px;
  }

  /* ---- HP row ---- */
  #m_charbar .m_cb_heart { flex-shrink: 0; }
  #m_charbar .m_cb_hpboxes { flex: 1; display: flex; gap: 3px; }
  #m_charbar .m_cb_hpbox { flex: 1; height: 13px; border-radius: 2px; background: #19190f; box-shadow: inset 0 0 0 1px #333; }
  #m_charbar .m_cb_hpfull {
    background: linear-gradient(#4cc24c, #2f7d2f);
    box-shadow: inset 0 1px 0 rgba(255,255,255,.25);
  }
  #m_charbar .m_cb_hplabel { font-size: 10px; font-weight: 700; color: #cfcf9a; flex-shrink: 0; text-align: right; min-width: 48px; }
  #m_charbar .m_cb_hplabel span { color: #888; }

  /* Dead state: dim the avatar portrait. */
  #m_charbar.m_char_dead .m_cb_portrait { border-color: #3a2020; }

  /* ====================================================================
     Bottom slideout sheet (generic, mobile_ui.js buildSheet/openSheet).
     Hosts the Inventory (and any future game-screen detail). Slides up
     over the page, HALF the screen by default, with Expand (fullscreen)
     / Collapse / Close + a drag-down-to-dismiss handle -- the same
     interaction language as the mobile Metamap tile-detail sheet.
     ==================================================================== */
  #m_sheet_overlay {
    position: fixed;
    left: 0; top: 0; right: 0; bottom: 0;
    z-index: 9700;                 /* above the Context Bar / badges */
    background: rgba(0, 0, 0, 0.5); /* dim the page behind */
  }

  #m_sheet {
    position: absolute;
    left: 0; right: 0; bottom: 0;
    height: 50%;                   /* half the screen by default */
    display: flex;
    flex-direction: column;
    background: #1a1a1a;
    color: #e8e8e8;
    border-top: 1px solid #556b1f;
    box-shadow: 0 -4px 14px rgba(0, 0, 0, 0.6);
    transform: translateY(100%);   /* hidden below the screen by default */
    transition: transform 0.22s ease, height 0.22s ease;
    box-sizing: border-box;
  }
  #m_sheet.m_sheet_open { transform: translateY(0); }
  /* While dragging the handle, kill the transition for 1:1 finger tracking. */
  #m_sheet.m_sheet_dragging { transition: none; }
  /* Expanded: fill (almost) the whole screen. */
  #m_sheet.m_sheet_expanded { height: 100%; }

  /* Header: centered drag handle + expand/collapse/close pinned top-right,
     with an optional title on the left. */
  #m_sheet_bar {
    flex: 0 0 auto;
    position: relative;
    display: flex;
    align-items: center;
    min-height: 30px;
    border-bottom: 1px solid #2a2a2a;
  }
  #m_sheet_handle {
    position: absolute;
    left: 0; right: 0; top: 0;
    height: 30px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: grab;
    touch-action: none;
  }
  #m_sheet_handle::before {
    content: "";
    width: 40px;
    height: 4px;
    border-radius: 2px;
    background: #888;
  }
  #m_sheet_title {
    position: relative;
    z-index: 1;                    /* above the full-width handle */
    padding-left: 12px;
    font-size: 13px;
    font-weight: bold;
    color: #cde08a;
    pointer-events: none;          /* don't block the handle drag */
  }
  #m_sheet_btns {
    position: absolute;
    top: 0; right: 6px;
    z-index: 1;
    display: flex;
    align-items: center;
    gap: 4px;
    height: 100%;
  }
  .m_sheet_btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 32px;
    height: 30px;
    color: #d8d8d8;
    font-size: 18px;
    line-height: 1;
    border-radius: 4px;
    cursor: pointer;
    -webkit-user-select: none;
    user-select: none;
  }
  .m_sheet_btn:active { background: rgba(255, 255, 255, 0.15); }
  #m_sheet_close { font-size: 20px; color: #fff; }

  /* Scrollable content area (inner scroll, not layout). */
  #m_sheet_content {
    flex: 1 1 auto;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: 8px 12px 16px 12px;
  }
  /* Tame legacy fragment markup so it fits the narrow sheet. */
  #m_sheet_content table { max-width: 100%; }
  #m_sheet_content h3,
  #m_sheet_content h5 { margin: 8px 0 4px; }

  /* ---- ContentView ---- */
  #m_contentview {
    width: 100%;
    box-sizing: border-box;
  }
  #m_contentview .m_panel {
    width: 100%;
    box-sizing: border-box;
  }

  /* ---- Single stacked view (game screen) ----
     ONE screen, three stacked snap areas in a single scroll container:
       1. Map      (#m_panel_map)      -- 3x3 local map, natural height, at top
       2. Location (#m_panel_building) -- long building/location info; capped so
          it inner-scrolls its own content
       3. Recent   (#m_area_events)    -- events block lifted out of the building
          fragment (mobile_ui.js liftEventsArea)
     Map + Location stay on the SAME screen (the disliked old design split them
     onto separate tabs, so you couldn't move on the map and act on the building
     without tab-hopping). A fast flick snaps between area tops (mobile_ui.js
     bindScrollSnap); the container's height is measured in JS (sizeSnapContainer)
     so it fills from its top down to the screen bottom. */
  body.m_page_game { padding-bottom: 0; }

  /* The snap scroll container. height is set inline by sizeSnapContainer(); this
     just establishes it as the scroller and the offsetParent for area tops. */
  #m_contentview.m_single {
    position: relative;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }
  #m_contentview.m_single .m_panel,
  #m_contentview.m_single .m_snap_area { display: block; }

  #m_contentview.m_single #m_panel_map {
    /* The local 3x3 map sits at the top; center the fixed-width grid. */
    text-align: center;
    padding: 6px 0 4px;
    background: #141414;
    border-bottom: 1px solid #2a2a2a;
  }
  #m_contentview.m_single #m_panel_map table { margin: 0 auto; }

  /* Location area: cap its height so long building content scrolls INSIDE the
     area (the snap gesture only crosses to a neighbor once this inner scroll is
     at its edge). 56vh keeps the Map visible above it on the same screen. */
  #m_contentview.m_single #m_panel_building {
    padding-top: 4px;
    max-height: 56vh;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }

  /* Recent events area, once lifted out of the building fragment. */
  #m_contentview.m_single #m_area_events {
    padding: 4px 8px 16px;
    border-top: 1px solid #2a2a2a;
  }

  .m_loader {
    padding: 30px 10px;
    text-align: center;
    color: #cdcdcd;
  }

  /* ---- Context Bar (bottom-pinned tab set) ---- */
  #m_contextbar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 9000;
    display: flex;
    height: 56px;
    background: #171717;
    border-top: 1px solid #869927;
  }
  #m_contextbar .m_ctx_btn {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-decoration: none;
    color: #9aa0a6;
    border: 0;
    background: transparent;
    line-height: 1;
  }
  #m_contextbar .m_ctx_icon {
    width: 24px;
    height: 24px;
    /* default (inactive) icons are dimmed; active gets full white + glow */
    opacity: 0.55;
  }
  #m_contextbar .m_ctx_label {
    font-size: 10px;
    margin-top: 4px;
  }

  /* Active selection: brighten + green "glow". */
  #m_contextbar .m_ctx_btn.m_active {
    color: #cde08a;
  }
  #m_contextbar .m_ctx_btn.m_active .m_ctx_icon {
    opacity: 1;
    filter: drop-shadow(0 0 5px #aadb3f) drop-shadow(0 0 2px #aadb3f);
  }

  /* ---- Messages badge (top-right) ---- */
  #m_msgbadge {
    position: fixed;
    top: 4px;
    right: 8px;
    z-index: 9500;
    display: inline-block;
    line-height: 0;
  }
  #m_msgbadge img {
    width: 24px;
    height: 24px;
    display: block;
  }
  #m_msgbadge .m_badge_count {
    position: absolute;
    top: -6px;
    right: -8px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    box-sizing: border-box;
    border-radius: 8px;
    background: #c0392b;
    color: #fff;
    font-size: 10px;
    line-height: 16px;
    text-align: center;
    font-weight: bold;
  }

  /* ---- Messages overlay ---- */
  #m_msg_overlay {
    position: fixed;
    left: 0; top: 0; right: 0; bottom: 0;
    z-index: 9600;
    background: rgba(0,0,0,0.6);
  }
  #m_msg_panel {
    position: absolute;
    left: 0; right: 0; top: 0; bottom: 56px; /* clear the Context Bar */
    background: #1a1a1a;
    display: flex;
    flex-direction: column;
  }
  #m_msg_head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 8px 12px;
    background: #869927;
    color: #fff;
    font-weight: bold;
  }
  #m_msg_head a { color: #fff; text-decoration: none; font-size: 16px; }
  #m_msg_body {
    flex: 1 1 auto;
    overflow: auto;
    padding: 8px;
  }

  /* The game screen has no ContextBar, so its Messages overlay fills to the
     bottom edge rather than reserving the 56px bar gap. */
  body.m_page_game #m_msg_panel { bottom: 0; }

  /* ---- Mobile inbox/outbox list ---- */
  #m_mail_toolbar {
    display: flex;
    gap: 8px;
    padding: 4px 2px 10px;
  }
  .m_mail_toolbtn {
    flex: 1 1 auto;
    min-height: 40px;
    background: #2f3a12;
    color: #cde08a;
    border: 1px solid #4a5a1d;
    border-radius: 5px;
    font-size: 14px;
  }
  .m_mail_toolbtn:active { background: #3d4a18; }
  /* Mail rows reuse the .m_list standard (tall, whole-row tap). The subject
     cell stacks the subject text over a smaller timestamp. */
  tr.m_mail_row td { padding: 12px 10px; }
  .m_mail_from {
    width: 34%;
    color: #cfcfcf;
    font-size: 13px;
    word-break: break-word;
  }
  .m_mail_subjtext { display: block; font-size: 14px; color: #e8e8e8; }
  .m_mail_meta { display: block; margin-top: 3px; font-size: 11px; color: #888; }
  /* Unread: brighter + a left accent so it stands out at a glance. */
  tr.m_mail_unread .m_mail_from,
  tr.m_mail_unread .m_mail_subjtext { font-weight: bold; color: #fff; }
  tr.m_mail_unread td:first-child { box-shadow: inset 3px 0 0 #869927; }
  .m_mail_empty { color: #999; padding: 16px 4px; }

  /* Pager */
  #m_mail_pager {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    padding: 12px 4px 4px;
  }
  .m_mail_pgbtn {
    min-height: 38px;
    padding: 0 16px;
    background: #2a2a2a;
    color: #e0e0e0;
    border: 1px solid #000;
    border-radius: 5px;
    font-size: 14px;
  }
  .m_mail_pgbtn[disabled] { opacity: 0.4; }
  .m_mail_pglabel { color: #aaa; font-size: 13px; }

  /* ---- Message slideout (bottom sheet inside the Messages overlay) ---- */
  #m_msg_sheet {
    position: absolute;
    left: 0; right: 0; bottom: 0;
    height: 50%;                   /* half the screen to start */
    display: flex;
    flex-direction: column;
    background: #161616;
    border-top: 2px solid #869927;
    box-shadow: 0 -4px 14px rgba(0,0,0,0.6);
    transform: translateY(100%);   /* hidden below until opened */
    transition: transform 0.24s ease;
    z-index: 2;
  }
  #m_msg_sheet.m_open { transform: translateY(0); }
  /* Compose needs the room -> fill the whole overlay panel. */
  #m_msg_sheet.m_sheet_full { height: 100%; top: 0; }
  #m_msg_sheet_head {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 8px 12px;
    background: #2a2a2a;
    border-bottom: 1px solid #000;
  }
  #m_msg_sheet_title { color: #cde08a; font-weight: bold; font-size: 15px; }
  #m_msg_sheet_head a { color: #fff; text-decoration: none; font-size: 18px; padding: 4px 8px; }
  #m_msg_sheet_body {
    flex: 1 1 auto;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: 12px;
  }

  /* Message view */
  .m_mailview_subject { margin: 0 0 4px; color: #cde08a; font-size: 17px; }
  .m_mailview_meta { margin: 0 0 10px; color: #999; font-size: 12px; }
  .m_mailview_body {
    color: #e6e6e6;
    font-size: 14px;
    line-height: 1.5;
    white-space: pre-wrap;
    word-wrap: break-word;
    border-top: 1px solid #2a2a2a;
    padding-top: 10px;
  }
  .m_mailview_actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 16px;
  }
  .m_mailview_btn {
    flex: 1 1 auto;
    min-height: 42px;
    background: #2f3a12;
    color: #cde08a;
    border: 1px solid #4a5a1d;
    border-radius: 5px;
    font-size: 14px;
  }
  .m_mailview_btn:active { background: #3d4a18; }
  .m_mailview_del { background: #3a1f1f; color: #e6b3b3; border-color: #5a2a2a; }

  /* Compose */
  .m_mailcompose_errors { color: #e6a0a0; font-size: 13px; margin-bottom: 8px; }
  .m_mailcompose_label { display: block; color: #aab86a; font-size: 12px; text-transform: uppercase; margin: 8px 0 3px; }
  .m_mailcompose_input,
  .m_mailcompose_textarea {
    width: 100%;
    box-sizing: border-box;
    background: #111;
    border: 1px solid #000;
    border-radius: 4px;
    color: #e0e0e0;
    font-size: 15px;
    padding: 9px 8px;
  }
  .m_mailcompose_textarea { resize: vertical; min-height: 120px; }
  .m_mailcompose_actions { display: flex; gap: 8px; margin-top: 14px; }
  .m_mailnotice h3 { color: #cde08a; }

  /* ---- Recent events: top-bar trigger + stack-nav popup ----
     Recent events is a full-screen view pushed over the game screen (push on
     open, pop on close, no reload), not a ContextBar tab. The trigger sits in
     the top-right icon strip, just left of the Messages badge. */
  #m_events_btn {
    position: fixed;
    top: 4px;
    right: 44px;            /* sits left of the 24px Messages badge at right:8px */
    z-index: 9500;
    display: inline-block;
    line-height: 0;
  }
  #m_events_btn img {
    width: 24px;
    height: 24px;
    display: block;
    opacity: 0.85;
  }

  #m_events_overlay {
    position: fixed;
    left: 0; top: 0; right: 0; bottom: 0;
    z-index: 9600;
    background: #1a1a1a;
  }
  #m_events_panel {
    position: absolute;
    left: 0; right: 0; top: 0; bottom: 0;   /* full screen -- no bar to clear */
    background: #1a1a1a;
    display: flex;
    flex-direction: column;
  }
  #m_events_head {
    display: flex;
    align-items: center;
    padding: 8px 12px;
    background: #869927;
    color: #fff;
    font-weight: bold;
  }
  /* Back chevron is a generous tap target with breathing room from the title. */
  #m_events_head a#m_events_close {
    color: #fff;
    text-decoration: none;
    font-size: 26px;
    line-height: 1;
    margin: -4px 12px -4px -4px;
    padding: 4px 8px;
  }
  #m_events_body {
    flex: 1 1 auto;
    overflow: auto;
    padding: 8px;
  }

  /* ====================================================================
     MiscDrawer (mobile_ui.js) — app-global slide-out side menu.
     Hosts the low-frequency chrome the legacy #footer carried (Change
     Password / Settings / Game Rules + copyright), which is hidden on
     mobile to reclaim the footer's vertical space. Built once per boot,
     independent of any page config (present on every mobile page).
     ==================================================================== */

  /* Hide the legacy footer on mobile; its contents live in the drawer.
     Not removed -- desktop / legacy mode keep using it. */
  #footer { display: none !important; }

  /* Trigger: the hamburger now lives as the last item in the in-game nav bar
     (#m_nav_menu, styled by the .tlbactions rules above). No fixed button. */

  /* ---- Scrim + sliding panel ---- */
  #m_drawer_overlay {
    position: fixed;
    left: 0; top: 0; right: 0; bottom: 0;
    z-index: 9600;
    background: rgba(0,0,0,0.6);
  }
  #m_drawer {
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 78%;
    max-width: 300px;
    background: #1a1a1a;
    border-right: 1px solid #869927;
    display: flex;
    flex-direction: column;
    /* Slide in from the left: start off-screen, animate to 0. */
    transform: translateX(-100%);
    transition: transform 0.2s ease-out;
  }
  #m_drawer.m_open { transform: translateX(0); }

  #m_drawer_head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 8px 12px;
    background: #869927;
    color: #fff;
    font-weight: bold;
  }
  #m_drawer_head a { color: #fff; text-decoration: none; font-size: 16px; }

  #m_drawer_links {
    flex: 1 1 auto;
    overflow: auto;
    list-style: none;
    margin: 0;
    padding: 0;
  }
  #m_drawer_links li {
    list-style: none;
    margin: 0;
    text-indent: 0 !important;   /* override any inherited list indent */
  }
  #m_drawer_links .m_drawer_link {
    display: block;
    padding: 14px 16px;          /* generous tap target */
    color: #cdcdcd;
    text-decoration: none;
    border-bottom: 1px solid #2a2a2a;
    font-weight: bold;
  }
  #m_drawer_links .m_drawer_link:active { background: #222; }

  /* "Social" section: external community links (Discord, Reddit) lifted off the
     mobile top-bar icon strip. The link list above flexes to fill, so this
     section + copyright are pinned to the bottom of the drawer. A top border
     acts as the divider separating it from the scrolling link list. */
  #m_drawer_social {
    border-top: 1px solid #2a2a2a;
  }
  .m_drawer_social_head {
    padding: 10px 16px 4px;
    color: #869927;
    font-size: 11px;
    font-weight: bold;
    text-transform: uppercase;
    letter-spacing: 0.05em;
  }
  .m_drawer_social_link {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 16px;
    color: #cdcdcd;
    text-decoration: none;
    font-weight: bold;
  }
  .m_drawer_social_link:active { background: #222; }
  .m_drawer_social_link img {
    width: 22px;
    height: 22px;
    display: block;
  }

  #m_drawer_foot {
    padding: 12px 16px;
    color: #777;
    font-size: 9px;            /* small enough to keep the copyright on one line */
    line-height: 1.4;
    white-space: nowrap;
  }
  #m_drawer_foot a { color: #869927; text-decoration: none; }

  /* ====================================================================
     R3.x: Stats nav -> horizontal scrolling pill bar.
     The desktop stats sidebar is a tall vertical list of category page
     links that, when stacked on mobile, pushes the actual stats content
     ~260px down. Restyle it into a single compact, sideways-scrolling
     row of pills. Pure CSS -- each pill is still a normal page link.
     ==================================================================== */

  /* Collapse the table chrome so the menu isn't a boxed widget. */
  #stats_nav_box,
  #stats_nav_box tbody,
  #stats_nav_box tr,
  #stats_nav_box td {
    display: block;
    width: auto !important;
    border: 0;
    padding: 0;
    margin: 0;
  }
  /* Drop the "Stats" header row and the <br> spacers on mobile. */
  #stats_nav_box .boxheader { display: none; }
  #stats_nav .m_hide { display: none; }

  /* The list becomes a horizontal, swipeable strip. */
  #stats_nav {
    display: flex;
    gap: 6px;
    margin: 0 0 8px 0;
    padding: 6px 8px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    white-space: nowrap;
    background: #1a1a1a;
    border-bottom: 1px solid #869927;
  }
  #stats_nav li {
    display: inline-block;
    list-style: none;
    margin: 0;
    text-indent: 0 !important;   /* override the inline text-indent */
    flex: 0 0 auto;
  }

  /* Pills. */
  #stats_nav .stats_nav_link {
    display: block;
    padding: 7px 14px;
    border: 1px solid #869927;
    border-radius: 14px;
    color: #cdcdcd;
    text-decoration: none;
    font-weight: bold;
    background: #222;
  }
  /* Current page: filled green pill. */
  #stats_nav .stats_nav_link.m_active {
    background: #869927;
    color: #fff;
    border-color: #aadb3f;
  }

  /* ---- Stats charts: scale to fit the screen ----
     The stat charts are fixed-size pre-rendered PNGs (trend graphs are
     800px wide, pie charts 600px) so they overflow a phone. Scale them
     down proportionally to the available width. Targets the stats image
     path so no per-view markup change is needed. */
  img[src*="/images/stats/"] {
    max-width: 100%;
    height: auto;
  }

  /* ====================================================================
     Groups nav -> top-right action buttons.
     The groups / group-management sidebars are tall lists of links plus
     non-link content (search forms, the manage-page info block). On mobile
     the links become a compact, right-aligned, wrapping cluster of action
     buttons; the search forms and info block stay inline in normal flow.
     Pure CSS -- each button is still a normal page link.
     ==================================================================== */

  /* Strip the table chrome so sections lay out as blocks. */
  #groups_nav_box, #groups_nav_box tbody, #groups_nav_box tr, #groups_nav_box td,
  #groups_manage_nav_box, #groups_manage_nav_box tbody, #groups_manage_nav_box tr, #groups_manage_nav_box td {
    display: block;
    width: auto !important;
    border: 0;
    padding: 0;
    margin: 0;
  }

  /* Section headers become small right-aligned labels above their buttons. */
  #groups_nav_box .m_navhead .boxheader,
  #groups_manage_nav_box .m_navhead .boxheader {
    background: none;
    border: 0;
    padding: 6px 0 2px 0;
    text-align: right;
    color: #aab86a;
    font-size: 11px;
    text-transform: uppercase;
  }

  /* The link list becomes a right-aligned wrapping button cluster. */
  .m_navlinks {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;   /* top-right alignment */
    gap: 6px;
    margin: 0 0 6px 0;
    padding: 0;
  }
  .m_navlinks li {
    display: inline-block;
    list-style: none;
    margin: 0;
    text-indent: 0 !important;   /* kill the &nbsp;/indent used on desktop */
    flex: 0 0 auto;
  }
  /* Drop the leading &nbsp; spacing nodes that indented sub-links on desktop. */
  .m_navlinks li { white-space: nowrap; }

  .m_navlinks .grp_nav_link {
    display: inline-block;
    padding: 6px 12px;
    border: 1px solid #869927;
    border-radius: 14px;
    background: #222;
    color: #cdcdcd;
    text-decoration: none;
    font-weight: bold;
    font-size: 12px;
  }
  .m_navlinks .grp_nav_link.m_active {
    background: #869927;
    color: #fff;
    border-color: #aadb3f;
  }
  /* Member-count text that follows some links (e.g. "(3 members)") -- keep it
     readable but small, on its own next to the button. */
  #groups_manage_nav_box .m_navlinks li { font-size: 11px; color: #9aa0a6; }

  /* The manage-page info block + search forms stay as normal stacked content. */
  #groups_nav_box .m_navform,
  #groups_manage_nav_box .m_navinfo,
  #groups_manage_nav_box .m_navform {
    display: block;
    text-align: left;
    margin-top: 6px;
  }

  /* ---- Groups Context Bar: hide the original page content ----
     When mobile_ui.js boots the groups config it adds body.m_page_groups.
     The Context Bar's panels (#m_contentview) become the only content; the
     original sidebar (#left) and the in-page group list rendered straight
     into #pagecontent are hidden so nothing renders twice. The injected
     #m_contentview is explicitly kept. */
  body.m_page_groups #left { display: none !important; }
  body.m_page_groups #pagecontent > *:not(#m_contentview) { display: none !important; }

  /* ====================================================================
     Interaction & layout standards (apply to every converted page).
     See _specs/mobile/mobile-conversion-framework.md.

       1. Lists -> Table -> whole-row activation (.m_list / .m_list_row)
       2. Tap-target spacing + edge deadzone (.m_tap)

     The Groups list is the reference implementation of #1.
     ==================================================================== */

  /* ---- Lists: spaced table, the whole row is the tap target ----
     The desktop list packs rows tight (e.g. groups was table.tabular whose
     only hit target was the inner group-name link). On mobile the rows get
     room to breathe and the ENTIRE row activates (mobile_ui.js navigates the
     row's data-href). The inner <a> stays for desktop/legacy + keyboard. */
  table.m_list {
    width: 100%;
    border-collapse: collapse;
    table-layout: fixed;
  }
  table.m_list th {
    text-align: left;
    padding: 8px 10px;
    border-bottom: 1px solid #869927;
    color: #aab86a;
    font-size: 11px;
    text-transform: uppercase;
  }
  table.m_list td {
    padding: 14px 10px;            /* generous row height -> easy to read + aim */
    border-bottom: 1px solid #2a2a2a;
    vertical-align: middle;
  }
  /* The row is tappable: pointer cursor + a clear pressed state so the whole
     row reads as one target, and the inner link looks like plain text. */
  tr.m_list_row { cursor: pointer; }
  tr.m_list_row:active td { background: #222; }
  tr.m_list_row a {
    text-decoration: none;
    /* The link no longer needs to be the visible affordance -- the row is.
       It stays in the DOM for desktop/legacy and keyboard users. */
  }

  /* ---- Tap-target spacing + edge deadzone ----
     Touch is imprecise. Any actionable control opts into .m_tap to get an
     enlarged hit area (inner padding) PLUS a non-activating gap from its
     neighbours (outer margin = the deadzone), so a slightly-off tap lands in
     dead space instead of firing the control next to it. Existing clusters
     (.m_navlinks gap, the ContextBar's flexed segments) are the baseline; use
     .m_tap for standalone buttons/links that don't already sit in one. */
  .m_tap {
    display: inline-block;
    padding: 10px 14px;            /* enlarge the target itself */
    margin: 4px;                   /* deadzone: non-activating gap to neighbours */
    min-height: 24px;
    min-width: 24px;
    box-sizing: border-box;
  }

  /* ---- TitleHeader (.m_titlebar) ----
     Built by Layout::MobileTitleHeader(). Screen title (ALL CAPS) on the left,
     vertically centered with a small left margin; major actions as right-aligned
     icon buttons. Markup is always emitted; only shown on mobile. */
  .m_titlebar {
    display: flex;
    align-items: center;           /* vertically center title + actions */
    justify-content: space-between;
    min-height: 44px;
    padding: 4px 6px 4px 0;
    background: #171717;
    border-bottom: 1px solid #869927;
  }
  .m_titlebar_title {
    flex: 1 1 auto;
    margin-left: 10px;             /* small left margin */
    text-transform: uppercase;     /* uppercase via CSS, not in PHP */
    letter-spacing: 0.5px;
    font-weight: bold;
    color: #cde08a;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;       /* long titles truncate, never wrap/overflow */
  }
  .m_titlebar_actions {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
  }
  /* Icon buttons: enlarged hit area (padding) + a deadzone gap (margin) between
     adjacent actions so they can't be mis-tapped -- the tap-target standard. */
  .m_titlebar_action {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 8px;                  /* enlarge target */
    margin: 0 2px;                 /* deadzone between adjacent action icons */
    min-width: 24px;
    min-height: 24px;
    box-sizing: border-box;
    line-height: 0;
  }
  .m_titlebar_action img {
    width: 24px;
    height: 24px;
    display: block;
  }
  .m_titlebar_action:active { opacity: 0.6; }
}

/* ============================================================
   R4 — Mobile Metamap.
   The Metamap is a modal popup pushed over the page (a stack-
   navigator view), NOT a ContextBar page conversion. On mobile
   the desktop $.window is replaced by a full-screen popup that
   mmObj builds at runtime: a fixed top bar, a pan/zoom map
   viewport (the existing tile grid wrapped in a transform
   layer), and a slide-up bottom detail sheet.

   Spec: _specs/mobile/mobile-metamap.md
   ============================================================ */
@media (max-width: 768px) {

  /* Full-screen popup pushed over the page. Hidden until open. */
  #mm_mobile {
    position: fixed;
    top: 0; left: 0; right: 0; bottom: 0;
    z-index: 100000;               /* above the legacy $.window stack */
    background: #1d1d1d;
    display: none;                 /* mmObj toggles to flex on open */
    flex-direction: column;
    overflow: hidden;
    -webkit-user-select: none;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
  }
  #mm_mobile.mm_open { display: flex; }

  /* --- Top bar: title + Players/Flags + close ------------------------ */
  #mm_mobile_topbar {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 4px;
    height: 46px;
    padding: 0 6px;
    background: #2a2a2a;
    border-bottom: 1px solid #000;
    box-sizing: border-box;
  }
  #mm_mobile_title {
    flex: 1 1 auto;
    color: #cde08a;
    font-weight: bold;
    font-size: 15px;
    padding-left: 4px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .mm_mobile_btn {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 34px;
    padding: 6px 9px;              /* enlarge tap target */
    margin: 0 1px;                 /* deadzone between adjacent controls */
    background: #3a3a3a;
    border: 1px solid #000;
    border-radius: 4px;
    color: #e0e0e0;
    font-size: 13px;
    line-height: 1;
    box-sizing: border-box;
    cursor: pointer;
  }
  .mm_mobile_btn:active { background: #4a4a4a; }
  .mm_mobile_btn.mm_active { background: #556b1f; color: #fff; }
  #mm_mobile_close {
    font-size: 20px;
    padding: 4px 10px;
    color: #fff;
  }

  /* --- Dedicated search bar: input + Find, below the top bar --------- */
  #mm_mobile_searchbar {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px;
    background: #242424;
    border-bottom: 1px solid #000;
    box-sizing: border-box;
  }
  #mm_mobile_search_input {
    flex: 1 1 auto;
    min-width: 0;                  /* allow the input to shrink in flex row */
    height: 34px;
    padding: 0 8px;
    background: #111;
    border: 1px solid #000;
    border-radius: 4px;
    color: #e0e0e0;
    font-size: 14px;
    box-sizing: border-box;
  }
  #mm_mobile_search_btn {
    flex: 0 0 auto;
  }

  /* --- Map viewport: clips the larger grid; all movement via transform */
  #mm_mobile_viewport {
    flex: 1 1 auto;
    position: relative;
    overflow: hidden;
    background: #000;
    touch-action: none;            /* we own pan/zoom; suppress browser gestures */
  }
  /* The pan/zoom layer. Origin top-left so translate/scale math is simple.
     mmObj sets transform inline. Children = the untouched #mm_map_box grid. */
  #mm_mobile_pan {
    position: absolute;
    top: 0; left: 0;
    transform-origin: 0 0;
    will-change: transform;
  }
  /* Smooth glide for programmatic recenters (e.g. tapping a search result).
     Toggled on only for that move so live pan/pinch stays 1:1. */
  #mm_mobile_pan.mm_pan_animating {
    transition: transform 0.3s ease;
  }
  /* The legacy grid keeps its own fixed pixel size (set inline by the view);
     we just re-host it inside the pan layer. Float clearing is preserved
     because #mm_map_box already sizes itself. */
  #mm_mobile_pan #mm_map_box {
    float: none;
    margin: 0;
  }
  /* Tiles are small raster PNG/JPGs; the pan layer scales them above 1x, which
     the browser blurs by default. Crisp-edge upscaling keeps the icons sharp
     when zoomed in. Mobile-only, so the desktop popup is unaffected. */
  #mm_mobile_pan .mm_sq,
  #mm_mobile_pan .mm_sq_filler {
    image-rendering: -webkit-optimize-contrast; /* older WebKit/Blink */
    image-rendering: pixelated;                 /* modern */
  }

  /* --- Top search-results drawer: slides DOWN from the top ----------- */
  /* Separate surface from the bottom detail sheet. Height = 2/3 of the sheet's
     max-height (sheet 33% -> drawer 22%). Dismiss only (no expand/collapse). */
  #mm_mobile_results {
    position: absolute;
    top: 0; left: 0; right: 0;
    max-height: 22%;
    display: flex;
    flex-direction: column;
    background: rgba(0, 0, 0, 0.9);
    color: #e8e8e8;
    border-bottom: 1px solid #556b1f;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.6);
    transform: translateY(-100%);  /* hidden above the viewport by default */
    transition: transform 0.22s ease;
    z-index: 6;                    /* above the bottom sheet (z:5) */
    box-sizing: border-box;
  }
  #mm_mobile_results.mm_results_open { transform: translateY(0); }
  #mm_mobile_results_bar {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    min-height: 30px;
    padding: 2px 6px 2px 12px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.12);
  }
  #mm_mobile_results_title {
    flex: 1 1 auto;
    color: #cde08a;
    font-weight: bold;
    font-size: 14px;
  }
  #mm_mobile_results_content {
    flex: 1 1 auto;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: 4px 12px 12px 12px;
  }
  #mm_mobile_results_content h4 { margin: 6px 0 6px; color: #cde08a; }
  .mm_mobile_results_table {
    width: 100%;
    border-collapse: collapse;
  }
  .mm_mobile_results_table th,
  .mm_mobile_results_table td {
    text-align: left;
    padding: 7px 6px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.12);
    font-size: 14px;
  }
  .mm_mobile_results_table th {
    color: #9fae6f;
    font-size: 12px;
    text-transform: uppercase;
  }
  .mm_mobile_results_table a {
    color: #cde08a;
    cursor: pointer;
  }

  /* --- Zoom in/out combo: fixed bottom-right of the map -------------- */
  #mm_mobile_zoom {
    position: absolute;
    right: 10px;
    bottom: 12px;
    display: flex;
    flex-direction: column;
    gap: 1px;
    z-index: 4;                    /* above the map, below the sheet (z:5) */
    border-radius: 6px;
    overflow: hidden;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.5);
    transition: bottom 0.22s ease; /* slides up in step with the sheet */
  }
  /* Lift above the collapsed sheet (~1/3 height) while it's open
     (mmObj toggles mm_zoom_raised in step with the sheet). */
  #mm_mobile_zoom.mm_zoom_raised {
    bottom: calc(33% + 12px);
  }
  .mm_zoom_btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 42px;
    height: 42px;
    background: rgba(42, 42, 42, 0.92);
    color: #fff;
    font-size: 24px;
    line-height: 1;
    cursor: pointer;
    -webkit-user-select: none;
    user-select: none;
  }
  .mm_zoom_btn:active { background: rgba(85, 107, 31, 0.95); }
  #mm_mobile_zoom_in { border-bottom: 1px solid #000; }

  /* --- Bottom detail sheet -------------------------------------------- */
  #mm_mobile_sheet {
    position: absolute;
    left: 0; right: 0; bottom: 0;
    max-height: 33%;               /* never more than ~1/3 of the screen */
    display: flex;
    flex-direction: column;
    background: rgba(0, 0, 0, 0.9); /* mostly solid, slight map show-through */
    color: #e8e8e8;
    border-top: 1px solid #556b1f;
    box-shadow: 0 -4px 14px rgba(0, 0, 0, 0.6);
    transform: translateY(100%);   /* hidden below the viewport by default */
    transition: transform 0.22s ease;
    z-index: 5;
    box-sizing: border-box;
  }
  #mm_mobile_sheet.mm_sheet_open { transform: translateY(0); }
  /* While dragging the handle we kill the transition for 1:1 finger tracking;
     mmObj toggles this class. */
  #mm_mobile_sheet.mm_sheet_dragging { transition: none; }
  /* Expanded: fill the area below the search bar. The sheet is absolutely
     positioned inside #mm_mobile_viewport, which already starts below the top
     + search bars, so top:0 / max-height:none covers the map but not the bars. */
  #mm_mobile_sheet.mm_sheet_expanded {
    top: 0;
    max-height: none;
  }

  /* Header row: centered drag handle with the expand/collapse/close controls
     pinned to the top-right. */
  #mm_mobile_sheet_bar {
    flex: 0 0 auto;
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 26px;
  }
  /* Grab handle — drag down to dismiss. */
  #mm_mobile_handle {
    flex: 0 0 auto;
    height: 26px;
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: grab;
    touch-action: none;
  }
  #mm_mobile_handle::before {
    content: "";
    width: 40px;
    height: 4px;
    border-radius: 2px;
    background: #888;
  }
  /* Expand / Collapse / Close, top-right of the sheet. */
  #mm_mobile_sheet_btns {
    position: absolute;
    top: 0;
    right: 6px;
    display: flex;
    align-items: center;
    gap: 4px;
    height: 100%;
  }
  .mm_sheet_btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 30px;
    height: 26px;
    color: #d8d8d8;
    font-size: 17px;
    line-height: 1;
    border-radius: 4px;
    cursor: pointer;
  }
  .mm_sheet_btn:active { background: rgba(255, 255, 255, 0.15); }
  #mm_mobile_sheet_close { font-size: 20px; color: #fff; }
  /* Scrollable content area inside the sheet (inner scroll, not layout). */
  #mm_mobile_sheet_content {
    flex: 1 1 auto;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: 4px 12px 14px 12px;
  }
  /* Tame the legacy fragment markup (fixed-width tables, headings) so it
     fits the narrow sheet without horizontal overflow. */
  #mm_mobile_sheet_content table { width: 100% !important; }
  #mm_mobile_sheet_content h3,
  #mm_mobile_sheet_content h4 { margin: 6px 0 4px; }
  #mm_mobile_sheet_content input[type="button"] {
    min-height: 34px;
    padding: 6px 12px;
  }

  /* Hide the desktop side panel inside the popup -- on mobile the map is the
     whole view and Players/Flags/Search live in the top bar + sheet. */
  #mm_mobile #mm_menu_box { display: none; }
  /* The desktop layout wrapper has a hard-coded 920px width inline; neutralize
     it so the re-hosted grid isn't forced to a desktop width. */
  #mm_mobile_pan > div[style] { width: auto !important; display: block !important; }
}
