/* ==========================================================================
   mobile-app.css — mobile presentation layer for the app shell
   --------------------------------------------------------------------------
   PHASE 1 scope: app shell (header + side drawer) and generic mobile
   primitives used by the Dashboard.

   HARD RULE: every declaration in this file lives inside
              @media (max-width: 991.98px)
   so the desktop layout (>= 992px) is byte-for-byte unaffected.

   991.98px is the same breakpoint style.css already uses for its
   "@media screen and (max-width: 991px)" shell rules, so the mobile and
   desktop worlds switch over at exactly one point.

   This file is loaded LAST in angular.json so it wins over styleMobile.css
   without needing !important everywhere.
   ========================================================================== */

@media (max-width: 991.98px) {

  /* ---------------------------------------------------------------- tokens */
  :root {
    --m-brand: #2a58ad;
    --m-brand-dark: #1d4896;
    --m-brand-deep: #103880;
    --m-accent: #4285f4;
    --m-ink: #1f2937;
    --m-ink-soft: #6b7280;
    --m-line: #e5e7eb;
    --m-surface: #ffffff;
    --m-canvas: #f4f6fa;

    --m-tap: 44px;                 /* minimum touch target            */
    --m-gutter: 12px;
    --m-radius: 12px;

    --m-bar-h: 56px;               /* header row 1                    */
    --m-actions-h: 52px;           /* header row 2 (quick actions)    */
    --m-safe-top: env(safe-area-inset-top, 0px);
    --m-safe-bottom: env(safe-area-inset-bottom, 0px);

    --m-ease: cubic-bezier(0.32, 0.72, 0, 1);
  }

  /* Fallback only, used for the first paint before header.component.ts
     measures the real header and writes --app-header-h onto <html>. It is one
     bar tall now that the quick-action rail is hidden; leaving the old
     `+ --m-actions-h` here would open a 52px gap under the header until the
     measurement lands. */
  :root {
    --app-header-h: var(--m-bar-h);
  }

  html {
    -webkit-text-size-adjust: 100%;
  }

  /* Safety net against a stray wide child scrolling the page sideways.
     Deliberately on <body> ONLY: `overflow-x: hidden` on <html> makes iOS
     Safari treat <html> as the scroll container, which breaks momentum
     scrolling and position:sticky further down the tree. `overscroll-behavior`
     is likewise left off the document element for the same reason. */
  body {
    max-width: 100%;
    overflow-x: hidden;
  }

  /* ==========================================================================
     1. HEADER — one sticky bar + one scrollable quick-action rail
     --------------------------------------------------------------------------
     The existing <ul class="nav-left"> / <ul class="nav-right"> are collapsed
     with `display: contents`, which promotes their <li> children to flex items
     of .header-container. Placement is then pure `order`, so NO existing
     element is moved, removed or duplicated in the DOM.
     ========================================================================== */

  app-header .header {
    width: 100% !important;
    top: 0;
    left: 0;
    right: 0;
    margin: 0;
    border-bottom: 1px solid var(--m-line);
    box-shadow: 0 1px 2px rgba(16, 24, 40, 0.06);
    padding-top: var(--m-safe-top);
    background: var(--m-surface);
  }

  app-header .header .header-container {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    padding: 0;              /* row 2 is full-bleed; row 1 pads its own items */
    min-height: var(--m-bar-h);
  }

  /* The float clearfix is meaningless in flex layout. */
  app-header .header .header-container:after {
    content: none;
    display: none;
  }

  app-header .header .header-container .nav-left,
  app-header .header .header-container .nav-right {
    display: contents;
  }

  app-header .header .header-container .nav-left > li,
  app-header .header .header-container .nav-right > li {
    float: none;
    display: flex;
    align-items: center;
  }

  /* ---- row 1 order ---- */
  app-header .header .header-container .nav-left > li.nav-hamburger { order: 1; }
  app-header .header .header-container .nav-left > li.org-brand     { order: 2; }
  app-header .header .header-container .mobile-org-name             { order: 3; }
  app-header .header .header-container .nav-left > li.notifications { order: 4; }
  app-header .header .header-container .nav-right > li.dropdown     { order: 5; }

  /* Forced flex line break (empty <span>, display:none on desktop). */
  app-header .header .header-container .mobile-header-break {
    order: 6;
    display: block;
    flex: 0 0 100%;
    width: 100%;
    height: 0;
    margin: 0;
    padding: 0;
  }

  /* ---- row 2: quick actions from BOTH uls land here, in DOM order ---- */
  app-header .header .header-container .nav-left > li.header-navigation,
  app-header .header .header-container .nav-right > li.header-navigation {
    order: 7;
  }

  /* The user / renewal / financial-year <li> holds only .small_view blocks,
     which style.css already hides below 992px. Drop the now-empty box. */
  app-header .header .header-container .nav-right > li:not(.dropdown):not(.header-navigation) {
    display: none;
  }

  /* ---- row 1 chrome ---- */
  app-header .header .header-container .nav-left > li:not(.header-navigation),
  app-header .header .header-container .nav-right > li.dropdown {
    min-height: var(--m-bar-h);
  }

  app-header .header .header-container .nav-left > li.nav-hamburger {
    padding-left: 4px;
  }

  app-header .header .header-container .nav-right > li.dropdown {
    padding-right: 8px;
  }

  app-header .header .header-container .nav-left > li > a,
  app-header .header .header-container .nav-right > li > a {
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: var(--m-tap);
    min-height: var(--m-tap);
    line-height: 1;
    padding: 0 6px;
    color: var(--m-ink);
  }

  app-header .header .header-container .nav-left > li.nav-hamburger > a {
    font-size: 1.1rem;
    color: var(--m-brand);
  }

  app-header .header .header-container .nav-left > li.org-brand {
    padding-right: 8px;
    border-right: 0;
  }

  app-header .header .header-container .nav-left > li.org-brand > a {
    padding: 0 4px;
    min-width: 0;
  }

  /* Deliberately more specific than header.component.css's `.org-brand img`
     (which pins the desktop logo to 160x50) so it wins without !important
     games — component styles are injected after this file. */
  app-header .header .header-container .nav-left > li.org-brand img {
    max-height: 30px !important;
    width: auto !important;
    max-width: 104px !important;
    object-fit: contain;
  }

  /* Company name — additive element, sits between logo and the icon cluster
     and absorbs the free space so the icons pin to the right edge. */
  app-header .header .header-container .mobile-org-name {
    display: block;
    /* basis 0, NOT auto: with `auto` the flex base size is the full text
       width, which overflows the line and wraps the icon cluster onto a
       third row. Basis 0 + min-width 0 lets it shrink and ellipsise. */
    flex: 1 1 0;
    min-width: 0;
    padding: 0 6px;
    color: var(--m-ink);
    overflow: hidden;
  }

  app-header .header .header-container .mobile-org-name__title {
    display: block;
    font-size: 0.8rem;
    font-weight: 700;
    line-height: 1.2;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  app-header .header .header-container .mobile-org-name small {
    display: block;
    font-size: 0.62rem;
    font-weight: 500;
    color: var(--m-ink-soft);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  app-header .header .header-container .nav-left .notifications .counter,
  app-header .header .header-container .nav-right .notifications .counter {
    top: 4px;
    right: 0;
    font-size: 9px;
    line-height: 15px;
    min-width: 15px;
    height: 15px;
    padding: 0 3px;
  }

  app-header .header .header-container .userHeaderImage .peer.mR-10 {
    margin-right: 0 !important;
  }

  app-header .header .header-container .userHeaderImage img {
    width: 30px !important;
    height: 30px !important;
  }

  /* Opt-out marker for chrome that is desktop-only. Used on the support-ticket
     and market-place icons: both are `li.notifications`, the same class as the
     notification bell, which stays — so the element is marked in the template
     rather than matched by a structural selector. `!important` because the
     row-1 layout rules above set `display: flex` on every header <li>. */
  .m-hide-mobile {
    display: none !important;
  }

  /* ---- row 2: the quick-action rail — HIDDEN ON MOBILE --------------------
     Requested off: it cost a whole band of vertical space above every screen
     for shortcuts the drawer already carries. Nothing becomes unreachable —
     header.component.ts builds `reportsMenu` / `settingsMenu` by FILTERING the
     same `sideMenu` array the drawer renders, and Sale / Purchase / Receipt /
     Payment / Party Statement are all side-menu entries too.

     The header height is measured live (`syncMobileHeaderOffset`), so the page
     offset follows the shorter header on its own.

     The rail's styling rules are kept below rather than deleted — they are
     inert while this is `display: none`, and turning the rail back on is then
     a matter of removing this one rule. */
  app-header .header .header-container .nav-left > li.header-navigation,
  app-header .header .header-container .nav-right > li.header-navigation,
  app-header .header .header-container .mobile-header-break {
    display: none !important;
  }

  app-header .header .header-container .nav-left > li.header-navigation,
  app-header .header .header-container .nav-right > li.header-navigation {
    flex: 1 1 0;
    min-width: 44px;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    min-height: var(--m-actions-h);
    padding: 5px 2px !important;
    margin: 0 !important;
    border-left: 0;
    border-right: 1px solid rgba(255, 255, 255, 0.18);
    overflow: hidden;
  }

  app-header .header .header-container .nav-right > li.header-navigation:last-of-type {
    border-right: 0;
  }

  app-header .header .header-container li.header-navigation button.btn.btn-link {
    min-height: 0;
    padding: 0 !important;
    margin: 0 !important;
    line-height: 1 !important;
  }

  app-header .header .header-container li.header-navigation button.btn.btn-link i,
  app-header .header .header-container li.header-navigation .dropdown-toggle i {
    font-size: 15px !important;
  }

  app-header .header .header-container li.header-navigation div.divtext {
    font-size: 9px !important;
    line-height: 1.1;
    margin-top: 4px;
    max-width: 100%;
    color: #fff;
    text-align: center;
    white-space: normal;      /* "C. Receipt" / "Party Stmt" wrap, never clip */
    word-break: break-word;
  }

  app-header .header .header-container li.header-navigation div.divtext small {
    font-size: inherit;
  }

  @media (min-width: 400px) {
    app-header .header .header-container li.header-navigation div.divtext {
      font-size: 10px !important;
    }
  }

  app-header .header .header-container li.header-navigation .dropdown {
    display: flex;
    flex-direction: column;
    align-items: center;
  }

  /* Header dropdowns (notifications / reports / settings / profile).
     They stay ANCHORED to their trigger — the app lets more than one be open
     at a time, and turning them into fixed bottom sheets made them pile up on
     the same spot. Here they are only constrained to the viewport: the
     notification menu's hard-coded min-width:400px is the actual overflow
     culprit on a 360px screen. */
  app-header .header .header-container .dropdown-menu {
    min-width: 0 !important;
    width: auto !important;
    max-width: calc(100vw - 16px) !important;
    max-height: 70vh !important;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    border-radius: 12px;
    box-shadow: 0 8px 28px rgba(16, 24, 40, 0.22);
    z-index: 1050;
  }

  /* Horizontal placement is deliberately left to Popper (Bootstrap 4 drives
     these with translate3d + preventOverflow). Forcing left/right here would
     compound with that transform and push the menu off-screen. */

  app-header .header .header-container .dropdown-menu > li > a,
  app-header .header .header-container .nav-right .dropdown-menu > li > a,
  app-header .header .header-container .dropdown-menu .dropdown-item {
    min-height: var(--m-tap);
    display: flex;
    align-items: center;
    padding: 10px 16px !important;
    font-size: 0.85rem;
  }

  /* Desktop opens report/setting sub-lists to the side; on mobile stack them. */
  app-header .header .header-container .dropdown-menu .submenu {
    position: static !important;
    right: auto !important;
    top: auto !important;
    width: 100% !important;
    max-height: none !important;
    overflow: visible !important;
    box-shadow: none !important;
    border-radius: 0 !important;
    padding-bottom: 0 !important;
    background: rgba(0, 0, 0, 0.12);
  }

  app-header .header .header-container .notifications .dropdown-menu p .btn {
    min-height: var(--m-tap);
    margin: 4px 4px 0 0;
  }

  /* Marquee sits under the two header rows. */
  app-header .header #marquee,
  app-header .header .marquee {
    height: 22px;
    font-size: 12px;
  }

  /* ==========================================================================
     2. SIDE DRAWER
     --------------------------------------------------------------------------
     styleMobile.css leaves the sidebar at `left: 0` below 960px, i.e. open on
     top of the page from first paint. Here it is parked off-canvas and only
     the explicit `mobile-drawer-open` state (set by header.siderbarMenu())
     slides it in.
     ========================================================================== */

  /* The panel is parked off-canvas with `left: 0` + translateX so the slide is
     a compositor-only transform. The scrim is a sibling (see
     side-menu.component.html), so this transform cannot capture it. */
  .sidebar {
    left: 0 !important;
    width: 292px;
    max-width: 88vw;
    top: 0;
    height: 100% !important;
    background: var(--m-brand);
    box-shadow: none;
    transform: translateX(-102%);
    transition: transform 0.28s var(--m-ease), box-shadow 0.28s var(--m-ease);
    padding-top: var(--m-safe-top);
  }

  .app.mobile-drawer-open .sidebar {
    transform: translateX(0);
    box-shadow: 8px 0 32px rgba(16, 24, 40, 0.28);
  }

  .app.mobile-drawer-open .over-bar {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
  }

  /* Lock the page behind the open drawer. */
  body.mobile-drawer-lock {
    overflow: hidden;
    touch-action: none;
  }

  .sidebar .sidebar-inner {
    height: 100%;
  }

  .sidebar .sidebar-content {
    max-height: 100%;
    height: 100%;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }

  .sidebar .sidebar-menu {
    height: auto;
    min-height: 100%;
    border-right: 0;
    padding-bottom: calc(24px + var(--m-safe-bottom));
  }

  /* Drawer profile block */
  .sidebar .profile.clearfix {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 16px 16px 14px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.14);
  }

  .sidebar .profile_pic,
  .sidebar:hover .profile_pic,
  .sidebar.full-sidepanel .profile_pic {
    margin: 0 !important;
    float: none !important;
  }

  /* Close control in the drawer header. The scrim already dismisses the menu,
     but at `max-width: 88vw` it is only a ~45px strip on a 375px screen. */
  .sidebar .profile.clearfix .m-drawer-x {
    flex: 0 0 auto;
    align-self: flex-start;
    margin-left: auto;
    width: 36px;
    height: 36px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.16);
    color: #fff;
    font-size: 1.35rem;
    line-height: 1;
  }

  .sidebar .profile.clearfix .m-drawer-x:active {
    background: rgba(255, 255, 255, 0.28);
  }

  .sidebar .img-circle.profile_img,
  .sidebar:hover .img-circle.profile_img,
  .sidebar.full-sidepanel .img-circle.profile_img {
    width: 44px !important;
    height: 44px !important;
    border-radius: 50%;
  }

  .sidebar .profile_info,
  .sidebar:hover .profile_info,
  .sidebar.full-sidepanel .profile_info {
    display: block !important;
    margin: 0 !important;
    padding: 0 !important;
    min-width: 0;
    overflow: hidden;
  }

  .sidebar .profile_info span {
    font-size: 0.7rem;
    color: rgba(255, 255, 255, 0.72);
  }

  .sidebar .profile_info h2.userName {
    font-size: 0.95rem;
    font-weight: 600;
    margin: 2px 0 0;
    color: #fff;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  /* Menu rows — comfortable, thumb-sized, no truncation. */
  .sidebar-wrapper .sidebar-menu ul li a,
  .sidebar-wrapper.sidebar .sidebar-menu ul li a,
  .sidebar-wrapper.sidebar.full-sidepanel .sidebar-menu ul li a {
    display: flex !important;
    align-items: center;
    width: 100%;
    min-height: var(--m-tap);
    margin-left: 0 !important;
    padding: 10px 14px !important;
    font-size: 0.86rem;
    color: rgba(255, 255, 255, 0.92);
  }

  .sidebar .sidebar-menu > li > a .title,
  .sidebar:hover .sidebar-inner .sidebar-menu > li > a .title,
  .sidebar.full-sidepanel .sidebar-inner .sidebar-menu > li > a .title {
    display: inline-block !important;
    flex: 1 1 auto;
    min-width: 0;
    white-space: normal;
    line-height: 1.25;
  }

  .sidebar-wrapper .sidebar-menu ul li a i {
    flex: 0 0 auto;
    width: 26px;
    height: 26px;
    line-height: 26px;
    margin-right: 10px;
    font-size: 14px;
    text-align: center;
  }

  .sidebar-wrapper .sidebar-menu ul li a .arrow {
    flex: 0 0 auto;
    float: none !important;
    margin: 0 0 0 auto !important;
  }

  .sidebar .sidebar-menu > li > a:active {
    background: rgba(255, 255, 255, 0.1);
  }

  /* Sub-menu open/close is animated by jQuery slideUp/slideDown (custom.js),
     which writes inline `display`. Never set `display` here — only skin it. */
  .sidebar-wrapper .sidebar-menu .sidebar-submenu {
    background: var(--m-brand-deep);
    margin-left: 0 !important;
    box-shadow: none;
    border-radius: 0;
  }

  .sidebar-wrapper .sidebar-menu .sidebar-submenu li a {
    padding-left: 30px !important;
    font-size: 0.82rem;
  }

  .sidebar-menu > li.active,
  .sidebar-menu .submenu-list.active > a {
    background: var(--m-brand-dark);
  }

  .sidebar .appversion {
    position: static !important;
    padding: 14px 16px calc(20px + var(--m-safe-bottom));
    margin: 8px 0 0 !important;
    left: auto !important;
    right: auto !important;
  }

  .sidebar .appversion a {
    position: static !important;
    left: auto !important;
    top: auto !important;
    display: inline-block;
    margin-left: 8px;
  }

  /* ==========================================================================
     3. PAGE CANVAS
     ========================================================================== */

  .page-container {
    padding-left: 0 !important;
    min-height: 100vh;
    background: var(--m-canvas);
  }

  /* Scoped to `.app` — the shell wrapper in start.component.html. The login,
     organization, module, branch and financial-year screens are top-level
     routes that live OUTSIDE `.app`, have no <app-header>, and therefore
     never receive a measured --app-header-h. They are handled in section 3d. */
  .app .main-content,
  .app .main-content2 {
    /* --app-header-h is measured live by header.component.ts */
    padding: calc(var(--app-header-h) + 10px) var(--m-gutter)
             calc(24px + var(--m-safe-bottom)) !important;
    min-height: auto;
  }

  /* `main-content21` is used by exactly one screen - POS Sale New 2 - and that
     screen renders in the HEADERLESS shell: `start.component.ts` sets
     `showFullScreen` when the url contains `pos-sale-new2`, and that branch of
     start.component.html has no <app-header> at all. Giving it the header
     offset above (it used to be in that selector list) reserved a header's
     worth of blank space at the top of a page with no header - and because
     `--app-header-h` keeps whatever the last real header measured, the gap was
     far bigger than the 56px default. It needs the gutters, not the offset. */
  .app .main-content21 {
    padding: 8px var(--m-gutter) calc(24px + var(--m-safe-bottom)) !important;
    min-height: auto;
  }

  .app .main-content.showMarquee,
  .app .main-content2.showMarquee {
    padding-top: calc(var(--app-header-h) + 10px) !important;
  }

  /* Overlays that are anchored to the viewport must clear the fixed header. */
  .ngx-spinner-overlay,
  .popupapiloadingdiv {
    z-index: 1300;
  }

  /* SweetAlert2 (subscription / confirm dialogs) */
  .swal2-popup {
    width: calc(100vw - 32px) !important;
    max-width: calc(100vw - 32px) !important;
    padding: 18px 16px !important;
    font-size: 0.9rem;
    border-radius: 14px;
  }

  .swal2-popup .swal2-actions {
    flex-wrap: wrap;
    gap: 8px;
  }

  .swal2-popup .swal2-actions .swal2-styled {
    min-height: var(--m-tap);
    margin: 0;
  }

  .swal2-popup.swal-wide {
    width: calc(100vw - 32px) !important;
  }

  /* ==========================================================================
     3d. AUTH & CONTEXT-SELECTION SCREENS
     --------------------------------------------------------------------------
     /login, /organizations, /modules, /org-branches, /org-financial-years are
     top-level routes rendered OUTSIDE the `.app` shell. They ship their own
     simple `.header navbar` (a div-based one, not the <app-header> component)
     and their own `<main class="main-content2">`, so none of the shell rules
     in sections 1-3 reach them.
     ========================================================================== */

  /* ---- login ---- */

  .loginpage {
    position: relative;
    min-height: 100vh;
    height: auto;
    padding: 24px 16px calc(24px + var(--m-safe-bottom));
  }

  .loginpage > .card {
    flex: 1 1 auto;
    width: 100%;
    max-width: 420px;
    margin: 0 auto;
    border: 0;
    border-radius: 16px;
    box-shadow: 0 10px 40px rgba(16, 24, 40, 0.18);
  }

  .loginpage .logincontent-area {
    padding: 0;
  }

  .loginpage .loginlogo img {
    max-width: 168px !important;
    height: auto;
  }

  .loginpage .card-body {
    padding: 0 18px 18px !important;
  }

  .loginpage .form-control {
    min-height: 46px;
    font-size: 16px;
    border-radius: 10px;
  }

  .loginpage .btn {
    min-height: 48px;
    font-size: 0.95rem !important;
    border-radius: 10px !important;
  }

  .loginpage .eye-pos {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: var(--m-tap);
    min-height: var(--m-tap);
  }

  .loginpage a {
    display: inline-flex;
    align-items: center;
    min-height: 40px;
  }

  /* ---- standalone header on the selection screens ---- */

  /* CRITICAL: style.css declares `.header { position: fixed; z-index: 800 }`
     globally, and these pages reuse that class. On a phone this header is
     ~190px tall (title + full-width search + user block), so as a fixed
     overlay it hid the first list item, swallowed single search results
     entirely, and ate every touch-drag in the top third of the screen.
     There is no reason to pin it here — the app shell's own fixed header is a
     different element (<app-header>). Put it back in normal flow so the page
     scrolls as one surface and the content simply starts below it. */
  app-user-organizations .header.navbar,
  app-user-modules .header.navbar,
  app-user-branches .header.navbar,
  app-no-organization .header.navbar,
  app-settings-main .header.navbar,
  app-user-financial-years .header.navbar {
    position: static;
    width: 100% !important;
    z-index: auto;
    border-bottom: 1px solid var(--m-line);
    box-shadow: 0 1px 2px rgba(16, 24, 40, 0.05);
    padding-top: var(--m-safe-top);
  }

  /* Two rows instead of three: [ title .......... user avatar ]
                                 [ search ................... ]
     `display: contents` on the wrapper <div class="nav-right"> promotes the
     search box and the user <ul> to flex items so `order` can split them. */
  app-user-organizations .header.navbar .header-container,
  app-user-modules .header.navbar .header-container,
  app-user-branches .header.navbar .header-container,
  app-no-organization .header.navbar .header-container,
  app-settings-main .header.navbar .header-container,
  app-user-financial-years .header.navbar .header-container {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    row-gap: 8px;
    padding: 8px 12px;
  }

  app-user-organizations .header.navbar .header-container > .nav-left,
  app-user-modules .header.navbar .header-container > .nav-left,
  app-user-branches .header.navbar .header-container > .nav-left,
  app-no-organization .header.navbar .header-container > .nav-left,
  app-settings-main .header.navbar .header-container > .nav-left,
  app-user-financial-years .header.navbar .header-container > .nav-left {
    order: 1;
    flex: 1 1 auto;
    min-width: 0;
    float: none;
    margin: 0;
    display: flex;
    align-items: center;
  }

  app-user-organizations .header.navbar .header-container > div.nav-right,
  app-user-modules .header.navbar .header-container > div.nav-right,
  app-user-branches .header.navbar .header-container > div.nav-right,
  app-no-organization .header.navbar .header-container > div.nav-right,
  app-settings-main .header.navbar .header-container > div.nav-right,
  app-user-financial-years .header.navbar .header-container > div.nav-right {
    display: contents;
  }

  app-user-organizations .header.navbar .header-container ul.nav-right,
  app-user-modules .header.navbar .header-container ul.nav-right,
  app-user-branches .header.navbar .header-container ul.nav-right,
  app-no-organization .header.navbar .header-container ul.nav-right,
  app-settings-main .header.navbar .header-container ul.nav-right,
  app-user-financial-years .header.navbar .header-container ul.nav-right {
    order: 2;
    flex: 0 0 auto;
    width: auto;
    float: none;
    display: flex;
    align-items: center;
    gap: 6px;
    list-style: none;
    padding: 0;
    margin: 0;
  }

  app-user-organizations .header.navbar .header-container #custom-search-input,
  app-user-modules .header.navbar .header-container #custom-search-input,
  app-user-branches .header.navbar .header-container #custom-search-input,
  app-no-organization .header.navbar .header-container #custom-search-input,
  app-settings-main .header.navbar .header-container #custom-search-input,
  app-user-financial-years .header.navbar .header-container #custom-search-input {
    order: 3;
    flex: 1 1 100%;
    width: 100%;
    top: 0;
    margin: 0;
  }

  app-user-organizations .header.navbar .header-container .left_side_head,
  app-user-modules .header.navbar .header-container .left_side_head,
  app-user-branches .header.navbar .header-container .left_side_head,
  app-no-organization .header.navbar .header-container .left_side_head,
  app-settings-main .header.navbar .header-container .left_side_head,
  app-user-financial-years .header.navbar .header-container .left_side_head {
    margin-left: 0 !important;
  }

  app-user-organizations .header.navbar .header-container p.heading_lead,
  app-user-modules .header.navbar .header-container p.heading_lead,
  app-user-branches .header.navbar .header-container p.heading_lead,
  app-no-organization .header.navbar .header-container p.heading_lead,
  app-settings-main .header.navbar .header-container p.heading_lead,
  app-user-financial-years .header.navbar .header-container p.heading_lead {
    margin: 0 !important;
    top: 0 !important;
    font-size: 1.05rem;
  }

  app-user-organizations .header.navbar .header-container ul.nav-right > li,
  app-user-modules .header.navbar .header-container ul.nav-right > li,
  app-user-branches .header.navbar .header-container ul.nav-right > li,
  app-no-organization .header.navbar .header-container ul.nav-right > li,
  app-settings-main .header.navbar .header-container ul.nav-right > li,
  app-user-financial-years .header.navbar .header-container ul.nav-right > li {
    float: none;
    padding-top: 0 !important;
    display: flex;
    align-items: center;
  }

  app-user-organizations .header.navbar .header-container ul.nav-right > li > a,
  app-user-modules .header.navbar .header-container ul.nav-right > li > a,
  app-user-branches .header.navbar .header-container ul.nav-right > li > a,
  app-no-organization .header.navbar .header-container ul.nav-right > li > a,
  app-settings-main .header.navbar .header-container ul.nav-right > li > a,
  app-user-financial-years .header.navbar .header-container ul.nav-right > li > a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: var(--m-tap);
    min-height: var(--m-tap);
  }

  app-user-organizations .header.navbar .header-container ul.nav-right .dropdown-menu,
  app-user-modules .header.navbar .header-container ul.nav-right .dropdown-menu,
  app-user-branches .header.navbar .header-container ul.nav-right .dropdown-menu,
  app-no-organization .header.navbar .header-container ul.nav-right .dropdown-menu,
  app-settings-main .header.navbar .header-container ul.nav-right .dropdown-menu,
  app-user-financial-years .header.navbar .header-container ul.nav-right .dropdown-menu {
    left: auto;
    right: 0;
    max-height: 70vh;
    overflow-y: auto;
  }

  /* ---- selection screens body ---- */

  /* Their header is in normal flow, not fixed, so no header offset is needed. */
  app-user-organizations .main-content2,
  app-user-modules .main-content2,
  app-user-branches .main-content2,
  app-no-organization .main-content2,
  app-user-financial-years .main-content2 {
    padding: 12px var(--m-gutter) calc(24px + var(--m-safe-bottom)) !important;
    min-height: auto;
  }

  app-user-modules .container,
  app-user-organizations .container-fluid {
    padding-left: 0;
    padding-right: 0;
  }

  app-user-modules .main-content2 .row,
  app-user-organizations .main-content2 .row {
    margin-left: 0;
    margin-right: 0;
  }

  app-user-modules .main-content2 [class*="col-md-"],
  app-user-organizations .main-content2 [class*="col-md-"] {
    padding-left: 0;
    padding-right: 0;
  }

  /* Organization / module / branch / financial-year cards */
  .highlight_box2 {
    padding: 10px !important;
    margin-bottom: 10px;
    border-radius: 12px;
  }

  .highlight_box2 .form-row,
  .highlight_box2 .row {
    margin-left: 0;
    margin-right: 0;
    align-items: center;
  }

  .highlight_box2 .grid_left,
  .highlight_box2 .grid_right {
    flex: 0 0 auto;
    max-width: none;
    width: auto;
    padding: 0 8px 0 0;
    border-right: 0 !important;
  }

  .highlight_box2 .grid_right {
    margin-left: auto;
    padding: 0 0 0 8px;
  }

  .highlight_box2 .grid_left img {
    height: 30px;
  }

  .highlight_box2 > a,
  .highlight_box2 .form-row > a {
    flex: 1 1 auto;
    min-width: 0;
    max-width: none;
    padding: 6px 0;
    border-right: 0 !important;
  }

  .highlight_box2 h3 {
    font-size: 0.95rem;
    font-weight: 600;
    margin: 0;
    line-height: 1.3;
    word-break: break-word;
  }

  .highlight_box2 h4 {
    font-size: 0.78rem;
    color: var(--m-ink-soft);
    margin: 2px 0 0;
  }

  /* The empty desktop spacer column collapses the card on a phone. */
  .highlight_box2 .form-row > .col-md-4:empty {
    display: none;
  }

  /* Right-hand action panel on the organization screen stacks below the list. */
  .right_card {
    margin-top: 12px;
  }

  .right_card .create_org_btn {
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: var(--m-tap);
    padding: 12px 8px !important;
  }

  .right_card .create_org_btn .fa-5x {
    font-size: 2em;
  }

  .right_card .create_org_btn h3 {
    font-size: 0.95rem;
    margin: 0;
  }

  /* Module screen hero */
  .heading_welcome {
    padding: 12px 0 !important;
    font-size: 1.15rem;
  }

  .font_size_sub {
    font-size: 0.85rem;
  }

  .expired {
    position: static !important;
    display: inline-block;
    margin-left: 8px;
  }

  /* ==========================================================================
     3b. PAGE ARCHETYPES  (applies app-wide, mobile only)
     --------------------------------------------------------------------------
     Nearly every screen in this app is built from the same five blocks:

       <main class="main-content">
         .page-header  ->  .left_side_head p.heading_lead   (title)
                           .right_saerch_side               (search + actions)
                             #custom-search-input
                             .btn_header
         #*_search_form.card.collapse -> form > .form-row > .col-md-* (filters)
         .table-responsive.table_height > table.cat-table   (list)
         <app-pagination>                                   (footer)

     Styling those blocks once here covers ~250 list/report screens with no
     per-component edits and no duplicated logic. Bootstrap already stacks
     `col-md-*` below 768px, so the grid is deliberately NOT overridden — only
     the floats, fixed heights and touch targets that actually break.
     ========================================================================== */

  /* ---- page title ---- */

  /* style.css hides the page title outright below 992px
     (`p.heading_lead { display: none !important }`), which leaves mobile users
     with no idea what screen they are on. Bring it back as a proper title. */
  p.heading_lead {
    display: block !important;
    margin: 0 0 2px !important;
    font-size: 1rem;
    font-weight: 700;
    line-height: 1.25;
    color: var(--m-ink);
    white-space: normal;
    overflow-wrap: break-word;
  }

  p.heading_lead i {
    margin-right: 6px;
    color: var(--m-brand);
  }

  /* Some titles carry a run of context after the screen name (Item Ledger
     appends the item, its MRP, unit, description and godown). Inside a bold
     1rem heading that reads as one long blob and pushes the data off the
     first screen. Dropped to its own normal-weight line instead. */
  p.heading_lead .m-title-meta {
    display: inline;
    font-size: 0.72rem !important;
    font-weight: 400;
    color: var(--m-ink-soft);
  }

  p.heading_lead .m-title-meta:first-of-type {
    display: block;
    margin-top: 2px;
  }

  .page-header {
    margin: 0 0 10px;
  }

  .page-header .container-fluid,
  .page-header .row {
    margin-left: 0;
    margin-right: 0;
    padding-left: 0;
    padding-right: 0;
  }

  .page-header .row > [class*="col-md-"] {
    flex: 1 1 100%;
    max-width: 100%;
    padding-left: 0;
    padding-right: 0;
  }

  /* ---- search + action bar ---- */

  .right_saerch_side {
    display: flex !important;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    justify-content: flex-start;
    width: 100%;
    margin-top: 8px;
  }

  .right_saerch_side > * {
    margin-right: 0 !important;
  }

  .right_saerch_side .mr-21 {
    flex: 1 1 100%;
    margin-right: 0 !important;
  }

  #custom-search-input {
    top: 0;
    width: 100%;
    margin-right: 0;
    border-bottom: 0;
  }

  #custom-search-input .input-group {
    width: 100%;
    max-width: 100%;
    flex-wrap: nowrap;
  }

  #custom-search-input .form-control {
    min-height: 42px;
    font-size: 16px;          /* >=16px stops iOS Safari zoom-on-focus */
    border: 1px solid var(--m-line);
    border-right: 0;
    border-radius: 10px 0 0 10px;
  }

  #custom-search-input .btn,
  #custom-search-input .input-group-btn11 {
    min-width: 46px;
    min-height: 42px;
    border-radius: 0 10px 10px 0 !important;
  }

  /* Some forms ship BOTH a `.btn_header.desktop_links` and a
     `.btn_header.mobile_links` variant, switched by styleMobile.css at 960px.
     `display: flex` below would outrank `.desktop_links { display: none }`
     (equal specificity, this file loads later) and resurrect the desktop set
     on top of the mobile one — so the switch is restated here, at this
     layer's own 991.98px breakpoint. That also closes the 961-991px gap where
     styleMobile had not yet switched over. */
  .desktop_links {
    display: none !important;
  }

  .mobile_links {
    display: flex !important;
  }

  /* The action cluster floats up by -15px on desktop, which overlaps the
     title once the columns stack. Make it an ordinary wrapping flex row. */
  .btn_header,
  .btn_header1 {
    position: static;
    top: 0;
    float: none !important;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    width: 100%;
    justify-content: flex-start;
  }

  .btn_header > .btn,
  .btn_header > a.btn,
  .btn_header > button {
    flex: 0 1 auto;
    min-height: var(--m-tap);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    margin: 0 !important;
    padding: 0 14px;
    font-size: 0.8rem !important;
    border-radius: 10px !important;
  }

  /* Icon actions in the rail are written three different ways across the app:
     `<a><img></a>` (print / pdf / excel on most screens), `<a class="btn">`
     and `<button class="btn btn-link"><img></button>` (Item Master's
     export-for-import). They must all end up the same size and on the same
     row, or two neighbouring exports look like two unrelated controls. */
  .btn_header > a:not(.btn) {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: var(--m-tap);
    min-height: var(--m-tap);
    margin: 0 !important;
    border-radius: 10px;
  }

  /* an icon-only action should not carry a text button's side padding */
  .btn_header > button.btn-link,
  .btn_header > a.btn-link {
    min-width: var(--m-tap);
    padding: 0 !important;
  }

  .btn_header img {
    width: 26px;
  }

  /* ---- filter / search cards ---- */

  .card.collapse.show,
  .card.collapsing,
  [id$="_search_form"] {
    border-radius: 12px;
  }

  [id$="_search_form"] .form-row,
  [id$="_search_form"] .form.row {
    margin-left: 0;
    margin-right: 0;
  }

  /* `.col` / `.col-sm-*` stay side-by-side at phone widths (only `col-md-*`
     stacks natively), which squeezes filter fields to a few characters. */
  /* Bootstrap's plain `.col` is `flex: 1 0 0%` - it never stacks, at any
     width. So a filter row whose fields are `col-md-*` (which DO stack) and
     whose Search/Reset buttons sit in a bare `.col` ends up with the buttons
     squeezed into whatever sliver is left beside a full-width field. On All
     ITC that is exactly why Search was not visible.

     This was keyed on `[id$="_search_form"]`, and 13 filter panels do not use
     that id - `gstr_anx_one_form`, `daily_activity_search`, `userSearchForm`,
     `demo` and others. Keying on `.card` instead covers every filter panel,
     which is the shape they all share, without needing to know its id. */
  [id$="_search_form"] .form-row > .col,
  [id$="_search_form"] .form.row > .col,
  .card > div > form .form-row > .col,
  .card > div > form .form.row > .col,
  .card > form .form-row > .col,
  .card > form .form.row > .col,
  .modal .form-row > .col,
  .modal .form.row > .col {
    flex: 1 1 100% !important;
    max-width: 100% !important;
  }

  /* the buttons in that column read as actions, not as a squeezed field */
  .card > div > form .form-row > .col > .btn,
  .card > div > form .form.row > .col > .btn,
  .card > form .form-row > .col > .btn,
  .card > form .form.row > .col > .btn,
  [id$="_search_form"] .form-row > .col > .btn,
  [id$="_search_form"] .form.row > .col > .btn {
    min-height: var(--m-tap);
    padding: 0 18px;
    border-radius: 10px;
  }

  [id$="_search_form"] .form-row > [class*="col-"],
  [id$="_search_form"] .form.row > [class*="col-"] {
    padding-left: 0;
    padding-right: 0;
  }

  [id$="_search_form"] .form-group {
    margin-bottom: 10px;
  }

  /* Trailing button column of a filter form. */
  [id$="_search_form"] .col.pt-3,
  [id$="_search_form"] .col-md-3.pt-3 {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    padding-top: 4px !important;
  }

  [id$="_search_form"] .btn {
    flex: 1 1 0;
    min-width: 96px;
    min-height: var(--m-tap);
    margin: 0 !important;
    border-radius: 10px !important;
  }

  /* ---- form controls (global touch + no-zoom baseline) ---- */

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

  textarea.form-control {
    min-height: 76px;
  }

  /* Field labels only. Radio/checkbox labels are the control's visible text,
     so they keep full contrast and their own sizing. */
  label:not(.custom-control-label):not(.form-check-label):not(.btn) {
    font-size: 0.78rem;
    font-weight: 600;
    margin-bottom: 3px;
    color: var(--m-ink-soft);
  }

  .custom-control-label,
  .form-check-label {
    min-height: 24px;
    display: inline-flex;
    align-items: center;
    font-size: 0.85rem;
  }

  .ng-select .ng-select-container,
  .ng-select.ng-select-single .ng-select-container {
    min-height: 42px !important;
    font-size: 16px;
  }

  /* ng-select renders its dropdown in place; keep it inside the screen. */
  .ng-dropdown-panel {
    max-width: calc(100vw - 24px);
  }

  .ng-dropdown-panel .ng-option {
    min-height: var(--m-tap);
    display: flex;
    align-items: center;
    font-size: 0.88rem;
  }

  /* select2 renders TWO elements with class `.select2-container`:
       1. the inline trigger, next to the original <select>
       2. the open dropdown, appended to <body> with computed inline
          left/top/width taken from the trigger's bounding box
     A blanket `width: 100% !important` also hits (2), overriding the computed
     width so the list renders off-position and cannot be tapped. Scope the
     stretch to trigger containers only — none of these selectors can match a
     direct child of <body>. */
  .form-group .select2-container,
  .input-group .select2-container,
  .adw_select .select2-container,
  .form-row .select2-container,
  td .select2-container {
    width: 100% !important;
    max-width: 100% !important;
  }

  /* The body-appended dropdown.

     select2 writes inline `top`/`left`/`width` from the field's own position
     and size. Vertically that is right, but horizontally it means a dropdown
     opened from a field that starts two-thirds across - the Eligibility
     Status picker on All ITC, say - opens at that x and runs off the right
     edge, so its search box and options are cut in half. Capping the width
     alone did not help: the LEFT edge was the problem.

     On a phone the sensible shape is a full-width sheet under the field, so
     the horizontal placement is pinned to the viewport and only select2's
     vertical placement is left alone. */
  body > .select2-container {
    left: 6px !important;
    right: 6px !important;
    width: calc(100vw - 12px) !important;
    max-width: calc(100vw - 12px) !important;
    z-index: 1200;
  }

  body > .select2-container .select2-dropdown {
    width: 100% !important;
    max-width: 100%;
  }

  .select2-container .select2-selection--single {
    height: 42px !important;
  }

  .select2-container .select2-selection--single .select2-selection__rendered {
    line-height: 40px !important;
    font-size: 16px;
  }

  .select2-container .select2-selection--single .select2-selection__arrow {
    height: 40px !important;
  }

  .select2-dropdown {
    width: auto !important;
    max-width: calc(100vw - 24px) !important;
  }

  .select2-results__option {
    min-height: var(--m-tap);
    display: flex;
    align-items: center;
    font-size: 0.88rem;
  }

  .select2-search__field {
    min-height: 40px;
    font-size: 16px !important;
  }

  datepicker-popup .input-group,
  .timepicker-input .input-group {
    width: 100%;
  }

  datepicker-popup .form-control {
    min-height: 42px;
    font-size: 16px;
  }

  /* The owl date-time picker overlay must clear the fixed app header. */
  .cdk-overlay-container .owl-dt-popup,
  .cdk-overlay-container .owl-dt-container {
    max-width: calc(100vw - 16px);
  }

  /* ---- list tables ---- */

  /* Every `.table_height*` variant is a desktop-tuned `calc(100vh - Npx)`.
     Recompute from the live header height instead, with a floor so the list
     never collapses to a sliver on a short screen. */
  .table_height,
  .table_height1,
  .table_height2,
  .table_height3,
  .table_height4,
  .table_height5,
  .table_height6,
  .table_height_custom_rate {
    max-height: calc(100vh - var(--app-header-h) - 170px) !important;
    min-height: 240px;
  }

  .table-responsive,
  [class*="table_height"] {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
  }

  /* style.css already makes `main table.cat-table th` sticky, but leaves it
     transparent, so rows scroll visibly through the header. */
  main table.cat-table th,
  .table-responsive table thead th {
    position: sticky;
    top: 0;
    z-index: 2;
    background: #eef1f5 !important;
    font-size: 0.72rem;
    white-space: nowrap;
  }

  table.cat-table td {
    font-size: 0.8rem;
    padding: 10px 8px !important;
    vertical-align: middle;
  }

  /* Row actions are the most-tapped thing on every list screen. */
  table.cat-table td .actionBtn,
  table.cat-table td .dropdown-toggle,
  table.cat-table td a > i {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 38px;
    min-height: 38px;
  }

  /* Action dropdowns must not be clipped by the scroll container. */
  table.cat-table td .dropdown-menu {
    position: fixed;
    max-height: 60vh;
    overflow-y: auto;
  }

  /* ---- pagination ---- */

  app-pagination .flex_page {
    flex-wrap: wrap;
    gap: 6px;
    justify-content: center;
    padding: 8px 6px calc(8px + var(--m-safe-bottom));
  }

  app-pagination .flex_page select {
    min-height: 40px;
    font-size: 15px;
    border-radius: 8px;
  }

  .ngx-pagination {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 4px;
    margin: 0 !important;
    padding: 0 !important;
  }

  .ngx-pagination li {
    margin: 0 !important;
  }

  .ngx-pagination li a,
  .ngx-pagination li.current,
  .ngx-pagination li span {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    min-width: 38px;
    min-height: 38px;
    padding: 0 8px !important;
    border-radius: 8px;
  }

  /* ---- tabs ---- */

  .nav-tabs,
  .classic-tabs .nav {
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }

  .nav-tabs::-webkit-scrollbar,
  .classic-tabs .nav::-webkit-scrollbar {
    display: none;
  }

  .nav-tabs .nav-item,
  .nav-tabs .nav-link {
    flex: 0 0 auto;
    white-space: nowrap;
    min-height: var(--m-tap);
    display: flex;
    align-items: center;
  }

  /* ---- misc chrome ---- */

  /* style.css pins every .btn to 0.75rem; that is below the comfortable
     reading floor on a phone. */
  .btn {
    font-size: 0.8rem !important;
  }

  .btn-sm,
  .btn.btn-sm {
    padding: 0.4rem 0.9rem;
  }

  /* Full-bleed helpers used by a few report screens. */
  .w-1000 {
    width: auto;
    min-width: 100%;
  }

  .apiloader {
    width: 100% !important;
  }

  /* ==========================================================================
     3c. TRANSACTION ENTRY FORMS
     --------------------------------------------------------------------------
     Sale / Purchase / Credit Note / Debit Note / Returns / Challans / Quotation
     / PO all share the same skeleton and the same class vocabulary, so styling
     it once covers the whole family:

       .modal-dialog.large_form.modal-full-height.modal-top   (107 templates)
         .modal-header.primary-bg  > .container-fluid > .row  (120)
           .btn_header.desktop_links | .btn_header.mobile_links
         .modal-body > form
           .card > .form-row            party / invoice fields
           .m-item-grid       > table.editable_tbl.item-table   (37/70)
           .additional-item-table-responsive > table.charge-table         (76)
           .payment-table-responsive         > table.trans-table          (54)
         .modal-footer.footer-fixed.footer_modal_form          (66)
     ========================================================================== */

  /* ---- entry-form header: replaced, not patched ----
     The desktop header is a `container-fluid > row > col-md-7|col-md-5` grid
     holding two alternate `.btn_header` variants plus a close button nested
     inside the button row. Every attempt to coerce that into a phone layout
     with overrides produced overlap: buttons cannot shrink (Bootstrap sets
     `.btn { white-space: nowrap }`), the title carries `top: -10px`, and the
     close is the last item of a `flex-end` row so it is the first thing
     pushed off screen.

     So on mobile that header is not restyled — it is replaced. The templates
     render a purpose-built `.m-dialog-bar` immediately BEFORE the header, and
     the sibling combinator below hides the original. Exactly one of the two
     is ever in the layout, so they cannot overlap each other or the form, and
     the bar is a plain two-row flex column whose height is its content. */

  .m-dialog-bar ~ .modal-header {
    display: none !important;
  }

  .m-dialog-bar {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: calc(8px + var(--m-safe-top)) 10px 10px;
    background: var(--m-brand);
    color: #fff;
  }

  .m-dialog-bar__row {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
  }

  .m-dialog-bar__title {
    flex: 1 1 auto;
    min-width: 0;
  }

  .m-dialog-bar__heading {
    display: block;
    font-size: 1rem;
    font-weight: 700;
    line-height: 1.2;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .m-dialog-bar__title small {
    display: block;
    font-size: 0.68rem;
    line-height: 1.3;
    opacity: 0.85;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  /* Always visible, always 40px, always the top-right corner — it is a direct
     flex child of the title row, so nothing can displace it. */
  .m-dialog-bar__close {
    flex: 0 0 auto;
    width: 40px;
    height: 40px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.18);
    color: #fff;
    font-size: 1.6rem;
    line-height: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  .m-dialog-bar__close:active {
    background: rgba(255, 255, 255, 0.32);
  }

  /* Two primary actions share the row; "More" hugs its label. */
  .m-dialog-bar__actions > .btn {
    flex: 1 1 0;
    min-width: 0;
    min-height: 42px;
    margin: 0 !important;
    padding: 0 10px !important;
    font-size: 0.8rem !important;
    font-weight: 600 !important;
    line-height: 1.15;
    white-space: nowrap;
    border-radius: 8px !important;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  .m-dialog-bar__more {
    flex: 0 0 auto;
    position: relative;
  }

  .m-dialog-bar__more > .btn {
    flex: 0 0 auto;
    min-height: 42px;
    padding: 0 12px !important;
    font-size: 0.8rem !important;
    border-radius: 8px !important;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  .m-dialog-bar__more .dropdown-menu {
    z-index: 1080;
    min-width: 210px;
    max-height: 60vh;
    overflow-y: auto;
  }

  .m-dialog-bar__more .dropdown-item {
    display: flex;
    align-items: center;
    min-height: var(--m-tap);
    font-size: 0.86rem;
  }

  /* ---- step tabs: Details -> Items -> Payment ----------------------------
     An entry form is one very long scroll on a phone. The form is already
     divided into sibling sections in the template; each one is tagged
     `.m-sec-details` / `.m-sec-items` / `.m-sec-payment` (a class on an
     EXISTING element - no new nesting), and `data-mstep` on .modal-content
     says which is showing. Desktop never sets a matching rule, so the
     attribute is inert there and every section stays visible. */

  .m-dialog-bar__steps {
    gap: 0;
    padding: 0;
    margin-top: 2px;
    border-top: 1px solid rgba(255, 255, 255, 0.18);
  }

  .m-dialog-bar__steps .m-step {
    flex: 1 1 0;
    min-width: 0;
    min-height: 40px;
    padding: 0 4px;
    border: 0;
    border-bottom: 2px solid transparent;
    background: transparent;
    color: rgba(255, 255, 255, 0.7);
    font-size: 0.78rem;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .m-dialog-bar__steps .m-step.is-active {
    color: #fff;
    border-bottom-color: #fff;
  }

  /* count badge on the Items step so the tab itself reports progress */
  .m-dialog-bar__steps .m-step__count {
    display: inline-block;
    min-width: 17px;
    margin-left: 5px;
    padding: 0 4px;
    border-radius: 9px;
    background: rgba(255, 255, 255, 0.26);
    font-size: 0.68rem;
    line-height: 17px;
  }

  /* the switch itself - only the active step's sections are in the flow.
     `extra` is a fourth slot: Vendor has Detail / Bank / Address / Statutory. */
  [data-mstep="details"] .m-sec-items,
  [data-mstep="details"] .m-sec-payment,
  [data-mstep="details"] .m-sec-extra,
  [data-mstep="items"] .m-sec-details,
  [data-mstep="items"] .m-sec-payment,
  [data-mstep="items"] .m-sec-extra,
  [data-mstep="payment"] .m-sec-details,
  [data-mstep="payment"] .m-sec-items,
  [data-mstep="payment"] .m-sec-extra,
  [data-mstep="extra"] .m-sec-details,
  [data-mstep="extra"] .m-sec-items,
  [data-mstep="extra"] .m-sec-payment {
    display: none !important;
  }

  /* four chips need to stay legible */
  .m-dialog-bar__steps .m-step {
    padding: 0 2px;
    font-size: 0.74rem;
  }

  /* ---- Additional Charges + Payment Details ------------------------------
     `table.m-stack-charge` and `table.m-stack-pay`. ---------------------------
     Same two-row shape as the item grid - a <tbody> row per committed charge
     (charge.isEditable === true renders plain text) plus a <tfoot> entry row -
     but only 6-8 short columns and rarely more than two or three rows, so it
     does not need a bottom sheet. Committed charges collapse to a one-line
     card; the row being edited becomes a stacked labelled form inline.
     Keyed on the table classes themselves, so every form that uses either
     grid picks this up - 8 forms for charges, 17 for payments. */

  /* `!important` on the shell: these tables carry component-scoped rules
     (`#item-attribute-table ...`) that are injected AFTER the global sheets,
     so an un-flagged `display: block` is not safe here. The doubled class
     also lifts specificity above any single-class or element chain. */
  .m-stack-charge.m-stack-charge,
  .m-stack-pay.m-stack-pay,
  .m-stack-charge.m-stack-charge > tbody,
  .m-stack-pay.m-stack-pay > tbody,
  .m-stack-charge.m-stack-charge > tfoot,
  .m-stack-pay.m-stack-pay > tfoot {
    display: block !important;
    width: 100% !important;
    min-width: 0 !important;
    max-width: 100% !important;
  }

  .m-stack-charge.m-stack-charge > thead,
  .m-stack-pay.m-stack-pay > thead {
    display: none !important;
  }

  /* rows must leave table layout too, or the cells stay in columns */
  .m-stack-charge.m-stack-charge > tbody > tr,
  .m-stack-pay.m-stack-pay > tbody > tr,
  .m-stack-charge.m-stack-charge > tfoot > tr,
  .m-stack-pay.m-stack-pay > tfoot > tr {
    display: block !important;
    width: 100% !important;
  }

  /* A stacked grid must never be forced to its content width - that rule is
     for the tables still scrolling sideways, and it fights the cards. */
  .modal .m-stack-grid,
  .modal table.m-stack-grid {
    min-width: 0 !important;
    max-width: 100% !important;
    table-layout: auto !important;
  }

  /* Last resort for grids whose component stylesheet targets them BY ID.
     Angular injects component styles after every global sheet, and an ID
     beats any class chain, so `#item-attribute-table td { ... }` could keep
     winning. Matching the same id settles it. */
  #item-attribute-table.m-stack-grid,
  #item-attribute-table.m-stack-grid > tbody,
  #item-attribute-table.m-stack-grid > tfoot {
    display: block !important;
    width: 100% !important;
    min-width: 0 !important;
  }

  #item-attribute-table.m-stack-grid > thead {
    display: none !important;
  }

  #item-attribute-table.m-stack-grid > tbody > tr,
  #item-attribute-table.m-stack-grid > tfoot > tr {
    display: block !important;
    width: 100% !important;
    padding: 8px 10px !important;
    border: 1px solid var(--m-line) !important;
    border-radius: 10px;
    margin-bottom: 8px;
    background: #fff;
  }

  #item-attribute-table.m-stack-grid > tbody > tr > td,
  #item-attribute-table.m-stack-grid > tfoot > tr > td {
    display: block !important;
    width: 100% !important;
    max-width: 100% !important;
    padding: 6px 0 !important;
    border: 0 !important;
    border-bottom: 1px solid #f1f3f6 !important;
  }

  #item-attribute-table.m-stack-grid > tbody > tr > td:last-child,
  #item-attribute-table.m-stack-grid > tfoot > tr > td:last-child {
    border-bottom: 0 !important;
  }

  /* the five column groups become named blocks. `flex: 0 0 42%` from
     m-stack-all would turn this into a side label, so it is reset here. */
  #item-attribute-table.m-stack-grid > tbody > tr > td[data-label]::before,
  #item-attribute-table.m-stack-grid > tfoot > tr > td[data-label]::before {
    content: attr(data-label) !important;
    display: block !important;
    flex: none !important;
    width: 100% !important;
    margin: 0 0 6px !important;
    padding-bottom: 4px;
    border-bottom: 1px solid #eef1f6;
    font-size: 0.68rem !important;
    font-weight: 700 !important;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    text-align: left !important;
    color: var(--m-brand) !important;
  }

  /* the S.No cell is just a row number and its delete action */
  #item-attribute-table.m-stack-grid td[data-label="SNo"] {
    display: flex !important;
    align-items: center;
    justify-content: space-between;
    background: #f6f8fb;
    border-radius: 8px;
    padding: 6px 10px !important;
  }

  #item-attribute-table.m-stack-grid td[data-label="SNo"]::before {
    content: "Variant" !important;
    width: auto !important;
    margin: 0 !important;
    border: 0 !important;
    padding: 0 !important;
  }

  /* `m-stack-all` right-aligns its cells (correct for a figure against a
     label). Here each cell is a GROUP of label/field pairs, so the cell must
     go back to normal reading order and let the pairs align themselves. */
  #item-attribute-table.m-stack-grid > tbody > tr > td,
  #item-attribute-table.m-stack-grid > tfoot > tr > td {
    text-align: left !important;
  }

  /* each label/field pair is one row: label left, control right */
  #item-attribute-table.m-stack-grid .form-group {
    display: flex !important;
    align-items: center;
    gap: 10px;
    margin-bottom: 8px !important;
  }

  #item-attribute-table.m-stack-grid .form-group label {
    flex: 0 0 40%;
    width: auto !important;
    margin: 0 !important;
    text-align: left !important;
    font-size: 0.78rem;
    color: var(--m-ink-soft);
  }

  #item-attribute-table.m-stack-grid .form-group input,
  #item-attribute-table.m-stack-grid .form-group select,
  #item-attribute-table.m-stack-grid .form-group ng-select,
  #item-attribute-table.m-stack-grid .form-group .adw_select,
  #item-attribute-table.m-stack-grid .form-group .ng-select {
    flex: 1 1 auto;
    width: auto !important;
    min-width: 0;
    text-align: left !important;
  }

  #item-attribute-table.m-stack-grid td {
    padding-top: 6px !important;
    border-bottom-width: 1px !important;
    vertical-align: top;
  }

  /* a read-only edit view renders values as bare text, not inputs - keep them
     on the same line as their label rather than trailing off to the right */
  #item-attribute-table.m-stack-grid .form-group > span,
  #item-attribute-table.m-stack-grid .form-group > div:not([class*="select"]) {
    flex: 1 1 auto;
    min-width: 0;
    text-align: left !important;
    font-weight: 600;
    color: var(--m-ink);
    word-break: break-word;
  }

  /* only a wrapper holding a stacked grid stops scrolling sideways */
  .m-stack-wrap {
    max-height: none !important;
    min-height: 0 !important;
    overflow: visible !important;
  }

  /* ---- a committed charge: one line, name left, total right ---- */
  .m-stack-charge > tbody > tr.m-committed,
  .m-stack-pay > tbody > tr.m-committed {
    position: relative;
    display: flex !important;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 2px 8px;
    padding: 9px 46px 9px 10px;
    border: 1px solid var(--m-line);
    border-radius: 10px;
    margin-bottom: 6px;
    background: #fff;
  }

  .m-stack-charge > tbody > tr.m-committed > td,
  .m-stack-pay > tbody > tr.m-committed > td {
    display: block;
    width: auto !important;
    padding: 0 !important;
    border: 0 !important;
    font-size: 0.84rem;
  }

  .m-stack-charge > tbody > tr.m-committed > td::before,
  .m-stack-pay > tbody > tr.m-committed > td::before {
    content: none !important;
  }

  /* only Charge and Total stay on the collapsed face */
  .m-stack-charge > tbody > tr.m-committed > td.m-quiet,
  .m-stack-pay > tbody > tr.m-committed > td.m-quiet,
  .m-stack-charge > tbody > tr.m-committed > td:not([data-label]):not(.m-cell-actions):not(.m-detail-toggle),
  .m-stack-pay > tbody > tr.m-committed > td:not([data-label]):not(.m-cell-actions):not(.m-detail-toggle) {
    display: none !important;
  }

  .m-stack-charge > tbody > tr.m-committed > td[data-label="Charge"],
  .m-stack-pay > tbody > tr.m-committed > td[data-label="Charge"] {
    flex: 1 1 100%;
    font-weight: 600;
    color: var(--m-ink);
  }

  .m-stack-charge > tbody > tr.m-committed > td[data-label="Amount"] {
    color: var(--m-ink-soft);
  }

  /* a committed payment reads: mode / ledger .......... amount */
  .m-stack-pay > tbody > tr.m-committed > td[data-label="Mode"] {
    flex: 1 1 100%;
    font-weight: 600;
    color: var(--m-ink);
  }

  .m-stack-pay > tbody > tr.m-committed > td[data-label="Ledger"] {
    color: var(--m-ink-soft);
  }

  .m-stack-pay > tbody > tr.m-committed > td[data-label="Amount"] {
    margin-left: auto;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
  }

  .m-stack-charge > tbody > tr.m-committed > td[data-label="Total"],
  .m-stack-pay > tbody > tr.m-committed > td[data-label="Total"] {
    margin-left: auto;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
  }

  .m-stack-charge > tbody > tr.m-committed > td.m-cell-actions,
  .m-stack-pay > tbody > tr.m-committed > td.m-cell-actions {
    position: absolute;
    top: 50%;
    right: 6px;
    transform: translateY(-50%);
    display: flex;
  }

  /* ---- the row being edited / added: stacked labelled fields ---- */
  .m-stack-charge > tbody > tr.default_row:not(.m-committed),
  .m-stack-pay > tbody > tr.default_row:not(.m-committed),
  .m-stack-charge > tfoot > tr.selected_row,
  .m-stack-pay > tfoot > tr.selected_row {
    display: flex !important;
    flex-wrap: wrap;
    gap: 8px;
    padding: 10px;
    border: 1px solid var(--m-brand);
    border-radius: 10px;
    margin-bottom: 6px;
    background: #f8fafd;
  }

  .m-stack-charge > tbody > tr.default_row:not(.m-committed) > td,
  .m-stack-pay > tbody > tr.default_row:not(.m-committed) > td,
  .m-stack-charge > tfoot > tr.selected_row > td,
  .m-stack-pay > tfoot > tr.selected_row > td {
    display: flex;
    flex-direction: column;
    flex: 1 1 100%;
    width: auto !important;
    min-width: 0;
    padding: 0 !important;
    border: 0 !important;
  }

  .m-stack-charge > tbody > tr.default_row:not(.m-committed) > td[data-label]::before,
  .m-stack-pay > tbody > tr.default_row:not(.m-committed) > td[data-label]::before,
  .m-stack-charge > tfoot > tr.selected_row > td[data-label]::before,
  .m-stack-pay > tfoot > tr.selected_row > td[data-label]::before {
    content: attr(data-label);
    margin-bottom: 3px;
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: var(--m-ink-soft);
  }

  /* the money columns sit two-up; the rest take the full width */
  .m-stack-charge > tbody > tr.default_row:not(.m-committed) > td[data-label="Amount"],
  .m-stack-pay > tbody > tr.default_row:not(.m-committed) > td[data-label="Amount"],
  .m-stack-charge > tbody > tr.default_row:not(.m-committed) > td[data-label="Tax Amount"],
  .m-stack-pay > tbody > tr.default_row:not(.m-committed) > td[data-label="Tax Amount"],
  .m-stack-charge > tbody > tr.default_row:not(.m-committed) > td[data-label="Total"],
  .m-stack-pay > tbody > tr.default_row:not(.m-committed) > td[data-label="Total"],
  .m-stack-charge > tbody > tr.default_row:not(.m-committed) > td[data-label="Add/Less"],
  .m-stack-pay > tbody > tr.default_row:not(.m-committed) > td[data-label="Add/Less"],
  .m-stack-charge > tfoot > tr.selected_row > td[data-label="Amount"],
  .m-stack-pay > tfoot > tr.selected_row > td[data-label="Amount"],
  .m-stack-charge > tfoot > tr.selected_row > td[data-label="Tax Amount"],
  .m-stack-pay > tfoot > tr.selected_row > td[data-label="Tax Amount"],
  .m-stack-charge > tfoot > tr.selected_row > td[data-label="Total"],
  .m-stack-pay > tfoot > tr.selected_row > td[data-label="Total"],
  .m-stack-charge > tfoot > tr.selected_row > td[data-label="Add/Less"],
  .m-stack-pay > tfoot > tr.selected_row > td[data-label="Add/Less"] {
    flex: 1 1 calc(50% - 4px);
  }

  /* the commit button spans the row and gets a real target */
  .m-stack-charge > tbody > tr.default_row:not(.m-committed) > td.m-cell-actions,
  .m-stack-pay > tbody > tr.default_row:not(.m-committed) > td.m-cell-actions,
  .m-stack-charge > tfoot > tr.selected_row > td.m-cell-actions,
  .m-stack-pay > tfoot > tr.selected_row > td.m-cell-actions {
    order: 90;
    flex: 1 1 100%;
  }

  .m-stack-charge > tbody > tr.default_row:not(.m-committed) > td.m-cell-actions .btn,
  .m-stack-pay > tbody > tr.default_row:not(.m-committed) > td.m-cell-actions .btn,
  .m-stack-charge > tfoot > tr.selected_row > td.m-cell-actions .btn,
  .m-stack-pay > tfoot > tr.selected_row > td.m-cell-actions .btn,
  .m-stack-charge > tbody > tr.default_row:not(.m-committed) > td.m-cell-actions .action_btn,
  .m-stack-pay > tbody > tr.default_row:not(.m-committed) > td.m-cell-actions .action_btn,
  .m-stack-charge > tfoot > tr.selected_row > td.m-cell-actions .action_btn,
  .m-stack-pay > tfoot > tr.selected_row > td.m-cell-actions .action_btn {
    width: 100%;
    min-height: var(--m-tap);
  }

  .m-stack-charge > tbody > tr.default_row:not(.m-committed) > td.m-cell-actions .edit1,
  .m-stack-pay > tbody > tr.default_row:not(.m-committed) > td.m-cell-actions .edit1,
  .m-stack-charge > tfoot > tr.selected_row > td.m-cell-actions .edit1,
  .m-stack-pay > tfoot > tr.selected_row > td.m-cell-actions .edit1 {
    display: flex;
    justify-content: flex-end;
    gap: 6px;
  }

  /* `.btn_add_more` is a 20px circle on desktop (`border-radius: 50%
     !important`), so stretching it to the row width turned it into a giant
     ellipse. Square it off, give it a real height, and swap the bare "+"
     glyph for a label - the item sheet already does the same thing. */
  .m-stack-charge td.m-cell-actions .btn_add_more,
  .m-stack-pay td.m-cell-actions .btn_add_more {
    width: 100%;
    height: auto;
    min-height: var(--m-tap);
    padding: 0 12px !important;
    border-radius: 10px !important;
    line-height: 1 !important;
    font-size: 0 !important;
  }

  .m-stack-charge td.m-cell-actions .btn_add_more::after,
  .m-stack-pay td.m-cell-actions .btn_add_more::after {
    font-size: 0.9rem;
    font-weight: 600;
    letter-spacing: 0.01em;
  }

  .m-stack-charge td.m-cell-actions .btn_add_more::after {
    content: "Add charge";
  }

  .m-stack-pay td.m-cell-actions .btn_add_more::after {
    content: "Add payment";
  }

  /* Stock Journal's two grids hold ITEMS - they only wear `charge-table`
     because the class is shared. `m-stack-item` keeps the charge card layout
     but names the button for what it actually adds. Placed after the
     `.m-stack-charge` rule so it wins on order at equal specificity. */
  .m-stack-item td.m-cell-actions .btn_add_more::after {
    content: "Add item";
  }

  /* empty chrome cells in either row must not leave gaps */
  .m-stack-charge > tbody > tr > td:empty,
  .m-stack-pay > tbody > tr > td:empty,
  .m-stack-charge > tfoot > tr > td:empty,
  .m-stack-pay > tfoot > tr > td:empty {
    display: none !important;
  }

  /* The desktop "Press F9" filler row is meaningless on a phone. It must NOT
     catch the entry row's commit button, which is also an unlabelled cell and
     is often given a colspan - that is what hid "Add item" on the Production
     Process Master. */
  .m-stack-charge > tfoot > tr > td.m-kbd-hint,
  .m-stack-pay > tfoot > tr > td.m-kbd-hint,
  .m-stack-charge > tfoot > tr > td[colspan]:not([data-label]):not(.m-cell-actions):not(.m-addbtn):not(.m-note),
  .m-stack-pay > tfoot > tr > td[colspan]:not([data-label]):not(.m-cell-actions):not(.m-addbtn):not(.m-note) {
    display: none !important;
  }

  /* an all-fields card should not print a label with nothing after it */
  .m-stack-all.m-stack-all > tbody > tr.m-committed > td[data-label]:empty,
  .m-stack-all.m-stack-all > tfoot > tr > td[data-label]:empty {
    display: none !important;
  }

  /* Purchase carries a full-width notice row inside the charge tbody ("the
     additional charges that are..."). It is not an editor - the card styling
     above is scoped to tr.default_row so it stays plain; just let it wrap. */
  /* `.m-detail-cell` is excluded because it is a Bootstrap collapse: an
     unconditional `display: block !important` here would outrank
     `.collapse:not(.show)` and pin every detail panel open (Ledger Account
     hangs its voucher/item tables off exactly such a cell). */
  .m-stack-charge > tbody > tr > td[colspan]:not(.m-detail-cell),
  .m-stack-pay > tbody > tr > td[colspan]:not(.m-detail-cell) {
    display: block !important;
    width: 100% !important;
    padding: 8px !important;
    white-space: normal !important;
    font-size: 0.76rem;
  }

  /* A stacked report can hang a detail panel off a `<td colspan class="collapse">`
     that sits directly inside <tbody> with no <tr> (Dynamic Delivery does this,
     as Party Proforma Summary does). Scoped to `.show` for the same reason as
     the compact version: an unconditional `display` would outrank Bootstrap's
     `.collapse:not(.show)` and pin the panel open. */
  .m-stack-grid > tbody > td.m-detail-cell.show {
    display: block !important;
    width: 100% !important;
    padding: 0 0 10px !important;
    text-align: left;
    white-space: normal;
    overflow: visible;
  }

  .m-stack-grid > tbody > td.m-detail-cell .table-responsive,
  .m-stack-grid > tbody > td.m-detail-cell [class*="table_height"] {
    max-height: none !important;
    min-height: 0 !important;
    overflow: visible !important;
  }

  /* an expandable card has to look expandable */
  .m-stack-grid > tbody > tr.accordion-toggle {
    cursor: pointer;
    position: relative;
  }

  .m-stack-grid > tbody > tr.accordion-toggle::after {
    content: "\f107";                       /* chevron-down */
    font-family: "Font Awesome 5 Free";
    font-weight: 900;
    position: absolute;
    top: 8px;
    right: 10px;
    font-size: 0.8rem;
    color: var(--m-brand);
    opacity: 0.75;
  }

  .m-stack-grid > tbody > tr.accordion-toggle:not(.collapsed)::after {
    content: "\f106";                       /* chevron-up */
  }

  /* ---- wide reports as cards (`m-rep-card`) -------------------------------
     Sale Report is 35 columns. Stacked in full that is 35 labelled lines per
     sale; collapsed to a face it would hide most of the report. So each sale
     is a CARD with a four-line face and its own tap-to-expand:

         ┌────────────────────────────────────────────┐
         │ INV-0012                      12-07-2026   │
         │ ABC Traders Pvt Ltd                        │
         │ Blue Shirt (L)                             │
         │ 2 BAG × 4,000.00            8,000.00    ⌄  │
         └────────────────────────────────────────────┘

     The face carries no labels - the format says what each value is. Tapping
     the card reveals the other 27 fields, each as `LABEL ....... value`, for
     that card only. Nothing is permanently hidden and the desktop table is
     untouched: every rule here is inside the mobile media query. */
  .m-rep-card > tbody > tr.m-committed {
    position: relative;
    display: flex !important;
    flex-wrap: wrap;
    align-items: baseline;
    column-gap: 6px;
    row-gap: 2px;
    padding: 10px 26px 10px 12px;   /* right gutter for the chevron */
    margin-bottom: 8px;
    border: 1px solid var(--m-line);
    border-radius: 10px;
    background: #fff;
    cursor: pointer;
  }

  .m-rep-card > tbody > tr.m-committed > td {
    display: block;
    width: auto !important;
    min-width: 0 !important;
    padding: 0 !important;
    border: 0 !important;
    font-size: 0.82rem;
    font-variant-numeric: tabular-nums;
  }

  /* ---- the face: four lines, no labels ---- */
  .m-rep-card > tbody > tr.m-committed > td[data-label="Bill No"] {
    order: 1;
    font-weight: 700;
    color: var(--m-accent);
  }

  .m-rep-card > tbody > tr.m-committed > td[data-label="Date"] {
    order: 2;
    margin-left: auto;
    font-size: 0.72rem;
    color: var(--m-ink-soft);
  }

  .m-rep-card > tbody > tr.m-committed > td[data-label="Party"] {
    order: 3;
    flex: 1 1 100%;
    font-weight: 600;
    color: var(--m-ink);
    word-break: break-word;
  }

  .m-rep-card > tbody > tr.m-committed > td[data-label="Item"] {
    order: 4;
    flex: 1 1 100%;
    font-size: 0.78rem;
    color: var(--m-ink-soft);
    word-break: break-word;
  }

  .m-rep-card > tbody > tr.m-committed > td[data-label="Qty"]  { order: 5; color: var(--m-ink-soft); }
  .m-rep-card > tbody > tr.m-committed > td[data-label="Unit"] { order: 6; color: var(--m-ink-soft); }
  .m-rep-card > tbody > tr.m-committed > td[data-label="Rate"] { order: 7; color: var(--m-ink-soft); }

  .m-rep-card > tbody > tr.m-committed > td[data-label="Qty"]::after {
    content: " ×";
    color: #9aa3af;
  }

  .m-rep-card > tbody > tr.m-committed > td[data-label="Bill Amount"] {
    order: 8;
    margin-left: auto;
    font-size: 0.9rem;
    font-weight: 700;
    color: var(--m-ink);
  }

  /* ---- the other 27: hidden until this card is tapped ---- */
  .m-rep-card > tbody > tr.m-committed:not(.m-adv-open) > td.m-adv {
    display: none !important;
  }

  .m-rep-card > tbody > tr.m-committed.m-adv-open > td.m-adv {
    order: 20;
    display: flex !important;
    flex: 1 1 100%;
    justify-content: space-between;
    gap: 12px;
    padding: 4px 0 !important;
    border-top: 1px solid #f3f4f6 !important;
    text-align: right;
    font-size: 0.78rem;
    word-break: break-word;
  }

  /* the charge card suppresses labels on committed rows; the detail needs them */
  .m-rep-card > tbody > tr.m-committed.m-adv-open > td.m-adv::before {
    content: attr(data-label) !important;
    flex: 0 0 44%;
    text-align: left;
    font-size: 0.68rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    color: var(--m-ink-soft);
  }

  /* an empty secondary field says nothing - drop it rather than print a label */
  .m-rep-card > tbody > tr.m-committed > td.m-adv:empty {
    display: none !important;
  }

  /* the card announces that it opens */
  .m-rep-card > tbody > tr.m-committed::after {
    content: "107";                       /* chevron-down */
    font-family: "Font Awesome 5 Free";
    font-weight: 900;
    position: absolute;
    right: 9px;
    bottom: 9px;
    font-size: 0.75rem;
    color: var(--m-brand);
    opacity: 0.65;
  }

  .m-rep-card > tbody > tr.m-committed.m-adv-open::after {
    content: "106";                       /* chevron-up */
  }

  /* no record / spacer rows keep their own shape. `.m-detail-cell` is left
     out for the same reason as above - it is a collapse and must stay shut
     until its toggle is tapped. */
  .m-rep-card > tbody > tr > td[colspan]:not(.m-detail-cell) {
    display: block !important;
    width: 100% !important;
    text-align: center;
    padding: 16px 8px !important;
  }

  /* ---- statement cards (`m-stmt-card`) ------------------------------------
     Party Statement is a running ledger, so its card is shaped like a
     statement line rather than a list row:

         INV-0012                          12-07-2026
         Sale - ABC Traders Pvt Ltd
         AMT. OUT 12,500.00           BAL 4,500.00

     Amt. Out and Amt. In are mutually exclusive per row; the template binds
     each cell's LABEL to the same condition as its value, so the one that
     does not apply resolves to '' and is dropped here - no blank "AMT. IN"
     line is ever printed. The two amounts keep their labels because a bare
     figure in a ledger is ambiguous. */
  .m-rep-card.m-stmt-card > tbody > tr.m-committed > td[data-label="Voucher No"] {
    order: 1;
    font-weight: 700;
    color: var(--m-accent);
  }

  .m-rep-card.m-stmt-card > tbody > tr.m-committed > td[data-label="Particulars"] {
    order: 3;
    flex: 1 1 100%;
    font-weight: 600;
    color: var(--m-ink);
    word-break: break-word;
  }

  /* Every statement report names its two amount columns differently - "Amt.
     Out/In" on Party Statement, "Dr/Cr" on the ledgers, "Cash In/Out",
     "Amount In/Out", "Debit/Credit" on the books. Rather than grow this list
     once per report, the newer ones carry `.m-dr` / `.m-cr` and keep whatever
     wording the report itself uses as the label. */
  .m-rep-card.m-stmt-card > tbody > tr.m-committed > td[data-label="Amt. Out"],
  .m-rep-card.m-stmt-card > tbody > tr.m-committed > td[data-label="Amt. In"],
  .m-rep-card.m-stmt-card > tbody > tr.m-committed > td[data-label="Dr"],
  .m-rep-card.m-stmt-card > tbody > tr.m-committed > td[data-label="Cr"],
  .m-rep-card.m-stmt-card > tbody > tr.m-committed > td.m-dr,
  .m-rep-card.m-stmt-card > tbody > tr.m-committed > td.m-cr {
    order: 5;
    display: flex !important;
    gap: 5px;
    font-weight: 600;
  }

  /* an amount cell whose value is blank for this row prints nothing at all */
  .m-rep-card.m-stmt-card > tbody > tr.m-committed > td.m-dr:empty,
  .m-rep-card.m-stmt-card > tbody > tr.m-committed > td.m-cr:empty {
    display: none !important;
  }

  .m-rep-card.m-stmt-card > tbody > tr.m-committed > td[data-label="Running Balance"] {
    order: 8;
    margin-left: auto;
    display: flex !important;
    gap: 5px;
    font-weight: 700;
  }

  /* the two amounts and the balance keep a short label; the rest of the face
     does not (the charge card suppresses labels with !important) */
  .m-rep-card.m-stmt-card > tbody > tr.m-committed > td[data-label="Amt. Out"]::before,
  .m-rep-card.m-stmt-card > tbody > tr.m-committed > td[data-label="Amt. In"]::before,
  .m-rep-card.m-stmt-card > tbody > tr.m-committed > td[data-label="Dr"]::before,
  .m-rep-card.m-stmt-card > tbody > tr.m-committed > td[data-label="Cr"]::before,
  .m-rep-card.m-stmt-card > tbody > tr.m-committed > td.m-dr::before,
  .m-rep-card.m-stmt-card > tbody > tr.m-committed > td.m-cr::before,
  .m-rep-card.m-stmt-card > tbody > tr.m-committed > td[data-label="Running Balance"]::before {
    content: attr(data-label) !important;
    flex: 0 0 auto;
    font-size: 0.64rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    color: var(--m-ink-soft);
  }

  /* "Running Balance" is long for a face chip */
  .m-rep-card.m-stmt-card > tbody > tr.m-committed > td[data-label="Running Balance"]::before {
    content: "BAL" !important;
  }

  /* a cell whose conditional label resolved to '' carries no value either */
  .m-rep-card > tbody > tr.m-committed > td[data-label=""] {
    display: none !important;
  }

  /* ---- TDS/TCS cards (`m-tds-card`) ---------------------------------------
     Ten columns, of which five are reference data (serial, type, section,
     PAN, rate). The face keeps what identifies the entry and what it costs:

         SB-0042                           12-07-2026
         ABC Traders Pvt Ltd
         AMOUNT 50,000.00              TAX 500.00

     Date and Party ride the shared `m-rep-card` rules; only the three labels
     this report adds are declared here. */
  .m-rep-card.m-tds-card > tbody > tr.m-committed > td[data-label="Voucher"] {
    order: 1;
    font-weight: 700;
    color: var(--m-accent);
  }

  .m-rep-card.m-tds-card > tbody > tr.m-committed > td[data-label="Amount"] {
    order: 5;
    display: flex !important;
    gap: 5px;
    font-weight: 600;
  }

  .m-rep-card.m-tds-card > tbody > tr.m-committed > td[data-label="Tax"] {
    order: 8;
    margin-left: auto;
    display: flex !important;
    gap: 5px;
    font-weight: 700;
  }

  .m-rep-card.m-tds-card > tbody > tr.m-committed > td[data-label="Amount"]::before,
  .m-rep-card.m-tds-card > tbody > tr.m-committed > td[data-label="Tax"]::before {
    content: attr(data-label) !important;
    flex: 0 0 auto;
    font-size: 0.64rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    color: var(--m-ink-soft);
  }

  /* ---- item ledger: shell ---------------------------------------------------
     This table carries `fixTable5`, i.e. `min-width: 1600px !important` from
     style.css. The shared `.m-stack-charge.m-stack-charge` shell already wins
     that contest on specificity, but a 1600px canvas is the exact failure that
     made All ITC look "converted but still scrolling sideways" - the cards get
     laid out at 1600px inside a 400px screen, so the page scrolls and every
     card's content sits off to the right. Restating the shell here, keyed to
     this table's own class and doubled with `[class][class]`, puts it beyond
     anything in the app that could reach it. Costs nothing when the generic
     shell is already winning. */
  table.m-iled-card[class][class],
  table.m-iled-card[class][class] > tbody,
  table.m-iled-card[class][class] > tfoot,
  table.m-frz-off[class][class],
  table.m-frz-off[class][class] > tbody,
  table.m-frz-off[class][class] > tfoot {
    display: block !important;
    width: 100% !important;
    min-width: 0 !important;
    max-width: 100% !important;
    table-layout: auto !important;
  }

  table.m-iled-card[class][class] > thead,
  table.m-frz-off[class][class] > thead {
    display: none !important;
  }

  table.m-iled-card[class][class] > tbody > tr,
  table.m-iled-card[class][class] > tfoot > tr,
  table.m-frz-off[class][class] > tbody > tr,
  table.m-frz-off[class][class] > tfoot > tr {
    width: 100% !important;
    min-width: 0 !important;
    max-width: 100% !important;
  }

  table.m-iled-card[class][class] > tbody > tr > td,
  table.m-iled-card[class][class] > tfoot > tr > th,
  table.m-frz-off[class][class] > tbody > tr > td,
  table.m-frz-off[class][class] > tfoot > tr > th {
    width: auto !important;
    min-width: 0 !important;
    max-width: 100% !important;
    white-space: normal !important;
    position: static !important;
    overflow-wrap: break-word;
  }

  /* ---- item ledger cards (`m-iled-card`) ----------------------------------
     Item Ledger is a movement ledger: three groups of Qty / Rate / Amount
     (Inward, Outward, Closing) per voucher. Wrapped as free-flowing flex text
     that is nine unlabelled figures in a row, so this card switches to a grid
     and gives each group its own line, with the columns still aligned down
     the card:

         #12  SB-0042                        12-07-2026
         Sale Invoice                        Main Godown
         IN  2       @ 400.00                   800.00
         OUT 1       @ 500.00                   500.00
         BAL 5       @ 420.00                 2,100.00

     Grid, not flex, because the alignment IS the report - a rate under a rate
     and an amount under an amount is what makes three movement lines readable
     at a glance. */
  .m-rep-card.m-iled-card > tbody > tr.m-committed {
    display: grid !important;
    grid-template-columns: minmax(0, auto) minmax(0, 1fr) minmax(0, auto);
    column-gap: 8px;
    row-gap: 3px;
    align-items: baseline;
    padding-right: 12px;
    cursor: default;
  }

  /* nothing is hidden behind a tap here, so no chevron is offered */
  .m-rep-card.m-iled-card > tbody > tr.m-committed::after {
    content: none !important;
  }

  .m-rep-card.m-iled-card > tbody > tr.m-committed > td[data-label="S. No."] {
    grid-column: 1;
    grid-row: 1;
    font-size: 0.68rem;
    color: var(--m-ink-soft);
  }

  .m-rep-card.m-iled-card > tbody > tr.m-committed > td[data-label="S. No."]::before {
    content: "#" !important;
    color: var(--m-ink-soft);
  }

  .m-rep-card.m-iled-card > tbody > tr.m-committed > td[data-label="Voucher No"] {
    grid-column: 2;
    grid-row: 1;
    font-weight: 700;
    color: var(--m-accent);
  }

  .m-rep-card.m-iled-card > tbody > tr.m-committed > td[data-label="Bill Date"] {
    grid-column: 3;
    grid-row: 1;
    justify-self: end;
    font-size: 0.72rem;
    color: var(--m-ink-soft);
  }

  .m-rep-card.m-iled-card > tbody > tr.m-committed > td[data-label="Voucher Type"] {
    grid-column: 1 / span 2;
    grid-row: 2;
    font-weight: 600;
    word-break: break-word;
  }

  /* Godown is a conditional column; sharing row 2 rather than taking a row of
     its own means the card does not leave a gap when it is switched off. */
  .m-rep-card.m-iled-card > tbody > tr.m-committed > td[data-label="Godown"] {
    grid-column: 3;
    grid-row: 2;
    justify-self: end;
    font-size: 0.72rem;
    color: var(--m-ink-soft);
  }

  .m-rep-card.m-iled-card > tbody > tr.m-committed > td[data-label="In Qty"]      { grid-column: 1; grid-row: 3; }
  .m-rep-card.m-iled-card > tbody > tr.m-committed > td[data-label="In Rate"]     { grid-column: 2; grid-row: 3; }
  .m-rep-card.m-iled-card > tbody > tr.m-committed > td[data-label="In Amount"]   { grid-column: 3; grid-row: 3; }
  .m-rep-card.m-iled-card > tbody > tr.m-committed > td[data-label="Out Qty"]     { grid-column: 1; grid-row: 4; }
  .m-rep-card.m-iled-card > tbody > tr.m-committed > td[data-label="Out Rate"]    { grid-column: 2; grid-row: 4; }
  .m-rep-card.m-iled-card > tbody > tr.m-committed > td[data-label="Out Amount"]  { grid-column: 3; grid-row: 4; }
  .m-rep-card.m-iled-card > tbody > tr.m-committed > td[data-label="Closing Qty"]    { grid-column: 1; grid-row: 5; }
  .m-rep-card.m-iled-card > tbody > tr.m-committed > td[data-label="Closing Rate"]   { grid-column: 2; grid-row: 5; }
  .m-rep-card.m-iled-card > tbody > tr.m-committed > td[data-label="Closing Amount"] { grid-column: 3; grid-row: 5; }

  /* the quantity cell carries its group's tag */
  .m-rep-card.m-iled-card > tbody > tr.m-committed > td[data-label$=" Qty"] {
    display: flex !important;
    gap: 6px;
    align-items: baseline;
    font-weight: 600;
  }

  .m-rep-card.m-iled-card > tbody > tr.m-committed > td[data-label$=" Qty"]::before {
    flex: 0 0 auto;
    min-width: 26px;
    font-size: 0.6rem;
    font-weight: 700;
    letter-spacing: 0.03em;
  }

  .m-rep-card.m-iled-card > tbody > tr.m-committed > td[data-label="In Qty"]::before {
    content: "IN" !important;
    color: #0f7b4f;
  }

  .m-rep-card.m-iled-card > tbody > tr.m-committed > td[data-label="Out Qty"]::before {
    content: "OUT" !important;
    color: #b42318;
  }

  .m-rep-card.m-iled-card > tbody > tr.m-committed > td[data-label="Closing Qty"]::before {
    content: "BAL" !important;
    color: var(--m-brand);
  }

  /* a bare rate in the middle column would read as another amount */
  .m-rep-card.m-iled-card > tbody > tr.m-committed > td[data-label$=" Rate"] {
    justify-self: start;
    font-size: 0.76rem;
    color: var(--m-ink-soft);
  }

  .m-rep-card.m-iled-card > tbody > tr.m-committed > td[data-label$=" Rate"]::before {
    content: "@ " !important;
    color: var(--m-ink-soft);
  }

  .m-rep-card.m-iled-card > tbody > tr.m-committed > td[data-label$=" Amount"] {
    justify-self: end;
    font-weight: 600;
  }

  /* ---- register summaries (`m-reg-card`) -----------------------------------
     Sale and Purchase Register are month-by-month summaries - six columns,
     nothing hidden - so the whole row fits on two lines and there is no tap to
     expand and no chevron:

         #7  July 2026                      NET 12,45,000.00
         TOTAL SALES 12,49,500      SALES RETURN 4,500

     The two transaction figures each drill through to their invoice list, so
     they keep an accent colour and a real tap target of their own. The row is
     NOT a toggle - that would swallow those two taps. */
  .m-rep-card.m-reg-card > tbody > tr.m-committed {
    row-gap: 0;
    column-gap: 8px;
    padding: 7px 10px;
    margin-bottom: 4px;
    border-radius: 8px;
    cursor: default;
  }

  .m-rep-card.m-reg-card > tbody > tr.m-committed::after {
    content: none !important;         /* nothing to expand */
  }

  /* forces the two figures onto their own line */
  .m-rep-card.m-reg-card > tbody > tr.m-committed::before {
    content: "";
    order: 4;
    flex: 0 0 100%;
    height: 0;
  }

  .m-rep-card.m-reg-card > tbody > tr.m-committed > td[data-label="S.No."] {
    order: 1;
    font-size: 0.64rem;
    color: var(--m-ink-soft);
  }

  .m-rep-card.m-reg-card > tbody > tr.m-committed > td[data-label="S.No."]::before {
    content: "#" !important;
  }

  .m-rep-card.m-reg-card > tbody > tr.m-committed > td[data-label="Months"] {
    order: 2;
    flex: 1 1 auto;
    font-weight: 700;
    font-size: 0.82rem;
    color: var(--m-ink);
  }

  .m-rep-card.m-reg-card > tbody > tr.m-committed > td.m-net {
    order: 3;
    display: flex !important;
    gap: 4px;
    align-items: baseline;
    font-size: 0.84rem;
    font-weight: 700;
    color: var(--m-brand);
  }

  .m-rep-card.m-reg-card > tbody > tr.m-committed > td.m-net::before {
    content: "NET" !important;
    font-size: 0.56rem;
    font-weight: 600;
    color: var(--m-ink-soft);
  }

  /* each figure drills through to its invoice list - give it a real target */
  .m-rep-card.m-reg-card > tbody > tr.m-committed > td.m-txn {
    order: 5;
    flex: 1 1 auto;
    display: flex !important;
    gap: 5px;
    align-items: baseline;
    min-height: 32px;
    margin-top: 3px;
    padding: 4px 0 !important;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--m-accent);
  }

  .m-rep-card.m-reg-card > tbody > tr.m-committed > td.m-txn::before {
    content: attr(data-label) !important;
    font-size: 0.56rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    color: var(--m-ink-soft);
  }

  /* ---- frozen-column reports (`m-frz-off`) ---------------------------------
     Item Stock Report and Item Inventory Report freeze their first columns for
     the desktop grid. That is a real, working desktop feature and none of it
     is touched: the freeze lives in each component's own stylesheet, keyed to
     `:nth-child(2)`-`:nth-child(5)`, and is left exactly as written. Two
     consequences drive everything below.

     First, NO cell may be added to or removed from these rows - a single extra
     `<td>` would renumber every `:nth-child()` and slide the frozen columns
     onto the wrong data. So the mobile conversion is `data-label` attributes
     and classes only, never new markup inside a row.

     Second, a pinned cell inside a stacked card is nonsense (they would all
     pile up at `left: -1px`), so the pinning is switched off for the phone.
     Beating it takes real specificity: Angular compiles
     `.item-table tr td:nth-child(3)` to
     `.item-table[_ngcontent-c] tr[_ngcontent-c] td:nth-child(3)[_ngcontent-c]`
     - five in the class column - and flags it `!important`. `[class]` repeated
     four times matches that five and wins on the element column, without
     touching anything above 991.98px. */
  table.m-frz-off[class][class][class][class] > thead > tr > th,
  table.m-frz-off[class][class][class][class] > tbody > tr > td,
  table.m-frz-off[class][class][class][class] > tfoot > tr > th {
    position: static !important;
    left: auto !important;
    right: auto !important;
    top: auto !important;
    bottom: auto !important;
    z-index: auto !important;
    width: auto !important;
    min-width: 0 !important;
    max-width: 100% !important;
    background: transparent !important;
  }

  /* Large datasets: a stock report routinely renders hundreds of cards. This
     lets the browser skip layout and paint for the ones scrolled out of view,
     with a size hint so the scrollbar stays honest. Ignored by engines that
     do not support it, so it is a pure win where it lands. */
  .m-rep-card.m-stk-card > tbody > tr.m-committed,
  .m-rep-card.m-mov-card > tbody > tr.m-committed {
    content-visibility: auto;
    contain-intrinsic-size: auto 52px;
  }

  /* ---- item stock rows (`m-stk-card`) --------------------------------------
     These reports run to thousands of items, so this is a LIST, not a gallery
     of cards: two lines, roughly 52px, eight or nine visible at once. What a
     stock lookup actually needs is on those two lines - name, code, unit, MRP
     and the closing figure - and the other twenty-odd columns stay one tap
     away instead of making every row tall.

         #12  Blue Shirt (L)                CLOSING 128
         ITM-0012   PCS   MRP 450.00                  v

     Flex with a forced break rather than grid: the face wants two fixed lines,
     but the expanded half wants a wrapping strip of chips, and one `::before`
     on the row buys both. */
  .m-rep-card.m-stk-card > tbody > tr.m-committed {
    row-gap: 0;
    column-gap: 6px;
    padding: 6px 22px 6px 9px;
    margin-bottom: 4px;
    border-radius: 8px;
  }

  .m-rep-card.m-stk-card > tbody > tr.m-committed > td {
    font-size: 0.72rem;
    line-height: 1.28;
  }

  /* the break between the two face lines - a zero-height full-width flex item */
  .m-rep-card.m-stk-card > tbody > tr.m-committed::before {
    content: "";
    order: 4;
    flex: 0 0 100%;
    height: 0;
  }

  /* a two-line row wants the chevron centred, not sitting at the bottom */
  .m-rep-card.m-stk-card > tbody > tr.m-committed::after {
    top: 50%;
    bottom: auto;
    transform: translateY(-50%);
  }

  .m-rep-card.m-stk-card > tbody > tr.m-committed > td[data-label="S. No."] {
    order: 1;
    font-size: 0.62rem;
    color: var(--m-ink-soft);
  }

  .m-rep-card.m-stk-card > tbody > tr.m-committed > td[data-label="S. No."]::before {
    content: "#" !important;
    color: var(--m-ink-soft);
  }

  .m-rep-card.m-stk-card > tbody > tr.m-committed > td[data-label="Item"] {
    order: 2;
    flex: 1 1 auto;
    font-weight: 700;
    font-size: 0.8rem;
    color: var(--m-ink);
    word-break: break-word;
  }

  /* the "Blocked" flag rides inside the item cell */
  .m-rep-card.m-stk-card > tbody > tr.m-committed > td[data-label="Item"] .status_ovedue {
    display: inline-block;
    margin-left: 5px;
    padding: 0 5px;
    border-radius: 5px;
    font-size: 0.56rem;
    font-weight: 700;
    vertical-align: middle;
  }

  .m-rep-card.m-stk-card > tbody > tr.m-committed > td.m-close {
    order: 3;
    display: flex !important;
    gap: 4px;
    align-items: baseline;
    font-size: 0.84rem;
    font-weight: 700;
    color: var(--m-brand);
  }

  /* "CLOSING STOCK" spelled out is too wide for a face chip */
  .m-rep-card.m-stk-card > tbody > tr.m-committed > td.m-close::before {
    content: "CLOSING" !important;
    font-size: 0.56rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--m-ink-soft);
  }

  /* ---- face line 2: code, unit, MRP ---- */
  .m-rep-card.m-stk-card > tbody > tr.m-committed > td[data-label="ItemCode"] {
    order: 5;
    font-size: 0.66rem;
    color: var(--m-ink-soft);
  }

  .m-rep-card.m-stk-card > tbody > tr.m-committed > td[data-label="Unit"] {
    order: 6;
    font-size: 0.66rem;
    color: var(--m-ink-soft);
  }

  .m-rep-card.m-stk-card > tbody > tr.m-committed > td[data-label="MRP"] {
    order: 7;
    display: flex !important;
    gap: 3px;
    font-size: 0.66rem;
    color: var(--m-ink-soft);
  }

  .m-rep-card.m-stk-card > tbody > tr.m-committed > td[data-label="MRP"]::before {
    content: "MRP" !important;
    font-size: 0.56rem;
    font-weight: 600;
  }

  /* ---- behind the tap ----
     The movement figures are chips, but only once the row is opened - on the
     face they would cost a third line on every one of a thousand rows. */
  .m-rep-card.m-stk-card > tbody > tr.m-committed:not(.m-adv-open) > td.m-stat {
    display: none !important;
  }

  .m-rep-card.m-stk-card > tbody > tr.m-committed.m-adv-open > td.m-stat {
    order: 15;
    flex: 0 0 auto;
    display: flex !important;
    flex-direction: column;
    align-items: flex-end;
    gap: 0;
    min-width: 58px;
    margin-top: 4px;
    padding: 3px 5px !important;
    border: 1px solid var(--m-line) !important;
    border-radius: 6px;
    background: #f8fafc;
    font-size: 0.72rem;
    font-weight: 600;
  }

  .m-rep-card.m-stk-card > tbody > tr.m-committed.m-adv-open > td.m-stat::before {
    content: attr(data-label) !important;
    font-size: 0.54rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    color: var(--m-ink-soft);
    white-space: nowrap;
  }

  /* the labelled detail lines are tighter here than on the generic card */
  .m-rep-card.m-stk-card > tbody > tr.m-committed.m-adv-open > td.m-adv {
    padding: 2px 0 !important;
    font-size: 0.72rem;
  }

  /* ---- item inventory rows (`m-mov-card`) ----------------------------------
     Same problem as the stock report, same answer: a two-line face with the
     movement block behind the tap. Grid here, because the movement rows only
     make sense when a rate sits under a rate and an amount under an amount -
     and the same three columns frame the face cleanly too.

         #12  Blue Shirt (L)                      BAL 128
         PCS        MRP 450.00                  51,840.00

     Opened, rows 3-6 appear underneath with the Opening / Inward / Outward
     groups and the profit line. Closing stays on the face either way, so
     nothing jumps position when the row expands. */
  .m-rep-card.m-mov-card > tbody > tr.m-committed {
    display: grid !important;
    grid-template-columns: minmax(0, auto) minmax(0, 1fr) minmax(0, auto);
    column-gap: 8px;
    row-gap: 1px;
    align-items: baseline;
    padding: 6px 22px 6px 9px;
    margin-bottom: 4px;
    border-radius: 8px;
  }

  .m-rep-card.m-mov-card > tbody > tr.m-committed > td {
    font-size: 0.72rem;
    line-height: 1.28;
  }

  .m-rep-card.m-mov-card > tbody > tr.m-committed::after {
    top: 50%;
    bottom: auto;
    transform: translateY(-50%);
  }

  .m-rep-card.m-mov-card > tbody > tr.m-committed > td[data-label="S. No."] {
    grid-column: 1;
    grid-row: 1;
    font-size: 0.62rem;
    color: var(--m-ink-soft);
  }

  .m-rep-card.m-mov-card > tbody > tr.m-committed > td[data-label="S. No."]::before {
    content: "#" !important;
    color: var(--m-ink-soft);
  }

  .m-rep-card.m-mov-card > tbody > tr.m-committed > td[data-label="Item"] {
    grid-column: 2;
    grid-row: 1;
    font-weight: 700;
    font-size: 0.8rem;
    color: var(--m-ink);
    word-break: break-word;
  }

  .m-rep-card.m-mov-card > tbody > tr.m-committed > td[data-label="Closing Qty"] {
    grid-column: 3;
    grid-row: 1;
    justify-self: end;
    font-size: 0.82rem;
    font-weight: 700;
    color: var(--m-brand);
  }

  .m-rep-card.m-mov-card > tbody > tr.m-committed > td[data-label="Unit"] {
    grid-column: 1;
    grid-row: 2;
    font-size: 0.66rem;
    color: var(--m-ink-soft);
  }

  .m-rep-card.m-mov-card > tbody > tr.m-committed > td[data-label="MRP"] {
    grid-column: 2;
    grid-row: 2;
    display: flex !important;
    gap: 3px;
    font-size: 0.66rem;
    color: var(--m-ink-soft);
  }

  .m-rep-card.m-mov-card > tbody > tr.m-committed > td[data-label="MRP"]::before {
    content: "MRP" !important;
    font-size: 0.56rem;
    font-weight: 600;
  }

  /* the stock value sits under the quantity it belongs to */
  .m-rep-card.m-mov-card > tbody > tr.m-committed > td[data-label="Closing Amount"] {
    grid-column: 3;
    grid-row: 2;
    justify-self: end;
    font-weight: 600;
  }

  /* ---- the movement block, behind the tap ----
     Scoped to `.m-mov` rather than `.m-adv` so the generic "labelled full-width
     line" treatment does not fight the three-column placement below. */
  .m-rep-card.m-mov-card > tbody > tr.m-committed:not(.m-adv-open) > td.m-mov {
    display: none !important;
  }

  .m-rep-card.m-mov-card > tbody > tr.m-committed > td.m-mov[data-mtag]              { grid-column: 1; }
  .m-rep-card.m-mov-card > tbody > tr.m-committed > td.m-mov[data-label$=" Rate"]    { grid-column: 2; justify-self: start; }
  .m-rep-card.m-mov-card > tbody > tr.m-committed > td.m-mov[data-label$=" Amount"]  { grid-column: 3; justify-self: end; font-weight: 600; }

  .m-rep-card.m-mov-card > tbody > tr.m-committed > td.m-mov[data-label^="Opening"] { grid-row: 3; }
  .m-rep-card.m-mov-card > tbody > tr.m-committed > td.m-mov[data-label^="Inward"]  { grid-row: 4; }
  .m-rep-card.m-mov-card > tbody > tr.m-committed > td.m-mov[data-label^="Outward"] { grid-row: 5; }

  /* the quantity cell of each group carries that group's tag */
  .m-rep-card.m-mov-card > tbody > tr.m-committed > td.m-mov[data-mtag] {
    display: flex !important;
    gap: 6px;
    align-items: baseline;
    font-weight: 600;
  }

  .m-rep-card.m-mov-card > tbody > tr.m-committed > td.m-mov[data-mtag]::before {
    content: attr(data-mtag) !important;
    flex: 0 0 auto;
    min-width: 24px;
    font-size: 0.56rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    color: var(--m-ink-soft);
  }

  .m-rep-card.m-mov-card > tbody > tr.m-committed > td.m-mov[data-mtag="IN"]::before  { color: #0f7b4f; }
  .m-rep-card.m-mov-card > tbody > tr.m-committed > td.m-mov[data-mtag="OUT"]::before { color: #b42318; }

  .m-rep-card.m-mov-card > tbody > tr.m-committed > td.m-mov[data-label$=" Rate"] {
    font-size: 0.68rem;
    color: var(--m-ink-soft);
  }

  .m-rep-card.m-mov-card > tbody > tr.m-committed > td.m-mov[data-label$=" Rate"]::before {
    content: "@ " !important;
    color: var(--m-ink-soft);
  }

  /* the profit line closes the movement block */
  .m-rep-card.m-mov-card > tbody > tr.m-committed > td.m-mov[data-label="Gross Profit"] {
    grid-column: 1 / span 2;
    grid-row: 6;
    display: flex !important;
    gap: 6px;
    font-weight: 600;
  }

  .m-rep-card.m-mov-card > tbody > tr.m-committed > td.m-mov[data-label="Gross Profit"]::before {
    content: "GROSS PROFIT" !important;
    font-size: 0.56rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    color: var(--m-ink-soft);
  }

  .m-rep-card.m-mov-card > tbody > tr.m-committed > td.m-mov[data-label="GP %"] {
    grid-column: 3;
    grid-row: 6;
    justify-self: end;
    font-weight: 600;
  }

  .m-rep-card.m-mov-card > tbody > tr.m-committed > td.m-mov[data-label="GP %"]::after {
    content: " %";
    font-size: 0.58rem;
    color: var(--m-ink-soft);
  }

  /* the remaining fields (closing rate, description, batch, dates) are plain
     labelled lines under the movement block */
  .m-rep-card.m-mov-card > tbody > tr.m-committed.m-adv-open > td.m-adv {
    grid-column: 1 / -1;
    padding: 2px 0 !important;
    font-size: 0.7rem;
  }

  /* ---- ageing cards (`m-age-card`) ----------------------------------------
     Outstanding Ageing has a fixed head (serial, party, balance) and then one
     column PER AGE BUCKET, generated from `ageHeading` - so the number of
     columns is data, not markup. The buckets become a wrapping strip of
     labelled chips under the party line, which reads the same whether the
     org has three buckets or eight:

         #4  ABC Traders Pvt Ltd            BALANCE 84,500.00
         ┌────────┐┌────────┐┌────────┐┌────────┐
         │0-30 DAY││31-60   ││61-90   ││90+     │
         │12,000  ││ 4,500  ││     0  ││68,000  │
         └────────┘└────────┘└────────┘└────────┘   */
  .m-rep-card.m-age-card > tbody > tr.m-committed > td[data-label="S.No"] {
    order: 1;
    font-size: 0.68rem;
    color: var(--m-ink-soft);
  }

  .m-rep-card.m-age-card > tbody > tr.m-committed > td[data-label="S.No"]::before {
    content: "#" !important;
    color: var(--m-ink-soft);
  }

  .m-rep-card.m-age-card > tbody > tr.m-committed > td[data-label="Party Name"] {
    order: 2;
    flex: 1 1 auto;
    font-weight: 700;
    color: var(--m-ink);
    word-break: break-word;
  }

  .m-rep-card.m-age-card > tbody > tr.m-committed > td[data-label="Balance"] {
    order: 3;
    flex: 0 0 auto;
    margin-left: auto;
    display: flex !important;
    gap: 5px;
    font-weight: 700;
  }

  .m-rep-card.m-age-card > tbody > tr.m-committed > td[data-label="Balance"]::before {
    content: "BALANCE" !important;
    flex: 0 0 auto;
    font-size: 0.64rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--m-ink-soft);
  }

  /* one chip per bucket; `data-label` is bound to the bucket's own name so
     the strip follows whatever `ageHeading` returns */
  .m-rep-card.m-age-card > tbody > tr.m-committed > td.m-bucket {
    order: 20;
    flex: 0 0 auto;
    display: flex !important;
    flex-direction: column;
    align-items: flex-end;
    gap: 1px;
    min-width: 62px;
    margin-top: 6px;
    padding: 4px 6px !important;
    border: 1px solid var(--m-line) !important;
    border-radius: 8px;
    background: #f8fafc;
    font-size: 0.76rem;
    font-weight: 600;
  }

  /* An ageing card has nothing hidden behind a tap - every bucket is already
     on it - so it must not advertise a chevron it would not honour, and it
     does not need the gutter the chevron sits in. */
  .m-rep-card.m-age-card > tbody > tr.m-committed {
    padding-right: 12px;
    cursor: default;
  }

  .m-rep-card.m-age-card > tbody > tr.m-committed::after {
    content: none !important;
  }

  .m-rep-card.m-age-card > tbody > tr.m-committed > td.m-bucket::before {
    content: attr(data-label) !important;
    font-size: 0.56rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    color: var(--m-ink-soft);
    white-space: nowrap;
  }

  /* ---- statement cards with a drill-down (Ledger Account) -----------------
     Ledger Account is the statement card plus a second, independent
     disclosure: the `+` opens the voucher/item breakdown for that entry
     (`loadSubData`, a real request), while tapping the card body reveals the
     `.m-adv` fields. Both stay reachable - the `+` keeps its own 44px target
     at the end of the amounts line, clear of the card's own chevron gutter. */
  .m-rep-card > tbody > tr.m-committed > td.m-detail-toggle {
    order: 9;
    flex: 0 0 auto;
    display: flex !important;
    align-items: center;
    justify-content: center;
    min-width: 34px;
    min-height: 34px;
    margin-right: 6px;                    /* clear of the chevron gutter */
  }

  .m-rep-card > tbody > tr.m-committed > td.m-detail-toggle::before {
    content: none !important;
  }

  .m-rep-card > tbody > tr.m-committed > td.m-detail-toggle .accordion-toggle {
    display: flex !important;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border: 1px solid var(--m-line);
    border-radius: 8px;
    background: var(--m-canvas);
  }

  /* The panel itself. Only `.show` is styled, so Bootstrap still owns whether
     it is open; these rules just undo the desktop table_height clamp and the
     centring the colspan rules apply to "No Record Found" strips. */
  .m-rep-card > tbody > tr > td.m-detail-cell.show {
    display: block !important;
    width: 100% !important;
    padding: 0 0 8px !important;
    text-align: left !important;
    white-space: normal !important;
    overflow: visible !important;
    border: 0 !important;
  }

  .m-rep-card > tbody > tr > td.m-detail-cell .table-responsive,
  .m-rep-card > tbody > tr > td.m-detail-cell [class*="table_height"] {
    max-height: none !important;
    min-height: 0 !important;
    overflow: visible !important;
  }

  .m-rep-card > tbody > tr > td.m-detail-cell .bgc-white {
    padding-bottom: 0 !important;
    margin-bottom: 8px !important;
  }

  /* ---- grouped reports (Daily Activity) ----------------------------------
     Rows arrive in groups: a title row, the activity rows, then a totals row,
     all as `colspan` cells. Stacked, they would read as three identical grey
     strips, so each is given its own voice. */
  .m-stack-grid > tbody > tr > td.m-group-head {
    position: sticky;
    top: 0;
    z-index: 2;
    margin: 10px 0 0;
    padding: 8px 10px !important;
    border-radius: 8px 8px 0 0;
    background: var(--m-brand) !important;
    color: #fff !important;
    font-size: 0.78rem;
    font-weight: 700;
    text-align: left;
    letter-spacing: 0.02em;
  }

  .m-stack-grid > tbody > tr > td.m-group-total {
    margin: 0 0 6px;
    padding: 8px 10px !important;
    border-radius: 0 0 8px 8px;
    background: #eef2f9 !important;
    font-size: 0.75rem;
    font-weight: 600;
    text-align: left;
    color: var(--m-ink);
  }

  /* the aliceblue backgrounds are inline on the <tr>; the cell above supplies
     the real colour, so the row itself must not paint over the card gap */
  .m-stack-grid > tbody > tr[style*="aliceblue"] {
    background: none !important;
  }

  /* ---- Voucher Entry settlement grid (`.m-settle-grid`) ------------------
     Neither an item grid nor a charge grid: a list of open bills you tick and
     part-pay. Each bill becomes a three-line card -

         ┌──────────────────────────────────────────┐
         │ INV-0012                    12,500.00  ☑ │
         │ 12-07-2026            Due   4,500.00     │
         │ [ Pay now .............................] │
         └──────────────────────────────────────────┘

     so the amount you owe and the amount you are paying sit together. */

  .m-settle-grid,
  .m-settle-grid > tbody,
  .m-settle-grid > tfoot {
    display: block;
    width: 100% !important;
    min-width: 0 !important;
  }

  .m-settle-grid > thead {
    display: none;
  }

  .m-settle-grid > tbody > tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto 34px;
    align-items: center;
    gap: 2px 8px;
    padding: 9px 10px;
    margin-bottom: 6px;
    border: 1px solid var(--m-line);
    border-radius: 10px;
    background: #fff;
  }

  .m-settle-grid > tbody > tr > td {
    display: block;
    width: auto !important;
    padding: 0 !important;
    border: 0 !important;
    font-size: 0.82rem;
    font-variant-numeric: tabular-nums;
  }

  .m-settle-grid > tbody > tr > td::before { content: none !important; }

  .m-settle-grid td.m-quiet { display: none !important; }

  .m-settle-grid td[data-label="Bill No."] {
    grid-column: 1;
    grid-row: 1;
    font-weight: 700;
    color: var(--m-accent);
  }

  .m-settle-grid td[data-label="Bill Amount"] {
    grid-column: 2;
    grid-row: 1;
    text-align: right;
    font-weight: 700;
  }

  .m-settle-grid td.m-settle-check {
    grid-column: 3;
    grid-row: 1;
    display: flex !important;
    align-items: center;
    justify-content: center;
  }

  .m-settle-grid td[data-label="Date"] {
    grid-column: 1;
    grid-row: 2;
    font-size: 0.72rem;
    color: var(--m-ink-soft);
  }

  .m-settle-grid td[data-label="Due"] {
    grid-column: 2 / span 2;
    grid-row: 2;
    text-align: right;
    font-size: 0.78rem;
    color: var(--m-ink-soft);
  }

  /* label the due figure so the two amounts can't be confused */
  .m-settle-grid td[data-label="Due"]::after {
    content: " due";
    font-size: 0.68rem;
  }

  /* the pay-now field spans the card and is the only tap target on line 3 */
  .m-settle-grid td.m-settle-pay {
    grid-column: 1 / -1;
    grid-row: 3;
    margin-top: 6px;
  }

  .m-settle-grid td.m-settle-pay input {
    width: 100%;
    min-height: var(--m-tap);
    font-size: 16px;
  }

  /* totals row: only the money survives */
  .m-settle-grid > tfoot > tr {
    display: flex;
    justify-content: flex-end;
    gap: 12px;
    padding: 8px 10px;
    border-top: 2px solid var(--m-line);
    font-size: 0.82rem;
    font-weight: 700;
  }

  .m-settle-grid > tfoot > tr > th {
    border: 0 !important;
    padding: 0 !important;
  }

  .m-settle-grid > tfoot > tr > th.m-quiet { display: none !important; }

  .m-settle-grid > tfoot > tr > th[data-label]::before {
    content: attr(data-label) " ";
    font-weight: 500;
    color: var(--m-ink-soft);
  }

  /* the wrapper must not clip the cards */
  .m-settle-grid,
  .m-settle-grid > tbody > tr > td {
    white-space: normal !important;
  }

  /* ---- step navigation (Voucher Settlement) ------------------------------
     The step chips in the dialog bar let you jump anywhere, but settlement is
     a linear task, so each step also ends with the move to the next one. */
  .m-step-nav {
    display: flex;
    gap: 8px;
    margin: 4px 0 20px;
  }

  .m-step-nav .btn {
    flex: 1 1 0;
    min-height: var(--m-tap);
    border-radius: 10px;
    font-weight: 600;
  }

  .m-step-nav .btn-light {
    flex: 0 0 90px;
    background: #eef1f6;
    color: var(--m-ink);
  }

  /* the running figures read as a summary strip, not a form row */
  .m-sec-payment > .form-group[style] {
    float: none !important;
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 10px 12px;
    border: 1px solid var(--m-line);
    border-radius: 10px;
    background: #f8fafd;
    font-size: 0.85rem !important;
  }

  .m-sec-payment > .form-group[style] > span {
    margin-right: 0 !important;
    display: flex;
    justify-content: space-between;
    font-variant-numeric: tabular-nums;
  }

  /* Bulk Voucher Settlement settles everything and skips steps 2-3, so it
     belongs on step 1 beside Search - not buried next to a step it bypasses.
     Give it a real row of its own rather than a floated corner checkbox. */
  .check_box_top .custom-control.float-right {
    float: none !important;
    display: flex;
    align-items: center;
    min-height: var(--m-tap);
    padding: 8px 12px 8px 34px;
    border: 1px dashed var(--m-line);
    border-radius: 10px;
    background: #fffdf5;
  }

  .check_box_top .custom-control.float-right .custom-control-label {
    font-weight: 600;
    font-size: 0.86rem;
  }

  /* ---- `.m-stack-all`: show every field, not a collapsed face -------------
     The compact card (item / qty x rate / amount) suits an invoice line, where
     the rest is detail you only need while editing. A Production Voucher is
     the opposite: MRP, stock qty, variant, manual rate and the dimensions are
     all part of reading the document, so nothing may be tucked away. Committed
     rows here list every labelled cell as `LABEL ......... value`. */
  .m-stack-all.m-stack-all > tbody > tr.m-committed {
    display: block !important;
    padding: 8px 12px;
  }

  .m-stack-all.m-stack-all > tbody > tr.m-committed > td,
  .m-stack-all.m-stack-all > tbody > tr.m-committed > td.m-quiet,
  .m-stack-all.m-stack-all > tbody > tr.m-committed > td[data-label] {
    display: flex !important;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    width: 100% !important;
    margin: 0 !important;
    padding: 5px 0 !important;
    border-bottom: 1px solid #f3f4f6 !important;
    text-align: right;
    font-size: 0.82rem;
    font-weight: 400;
    color: var(--m-ink);
    word-break: break-word;
  }

  /* `!important` is load-bearing. The charge card suppresses labels with
     `.m-stack-charge > tbody > tr.m-committed > td::before { content: none
     !important }` (its collapsed face needs no labels), and every grid using
     this pattern carries BOTH classes - `m-stack-charge` for the shell,
     `m-stack-all` to show every field. An important declaration beats a
     normal one whatever the specificity, so without this the label half of
     `m-stack-all` never rendered at all: 12 grids were drawing bare columns
     of values with nothing to say which field each one was. */
  .m-stack-all.m-stack-all > tbody > tr.m-committed > td[data-label]::before {
    content: attr(data-label) !important;
    flex: 0 0 42%;
    text-align: left;
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    color: var(--m-ink-soft);
  }

  /* the amount still reads as the row's headline */
  .m-stack-all.m-stack-all > tbody > tr.m-committed > td[data-label="Total"] {
    font-weight: 700;
  }

  .m-stack-all.m-stack-all > tbody > tr.m-committed > td:last-child {
    border-bottom: 0 !important;
  }

  /* actions go back into the flow as a full-width row rather than floating */
  .m-stack-all.m-stack-all > tbody > tr.m-committed > td.m-cell-actions {
    position: static !important;
    transform: none !important;
    justify-content: flex-end;
    padding-top: 8px !important;
  }

  .m-stack-all.m-stack-all > tbody > tr.m-committed > td.m-cell-actions::before {
    content: none;
  }

  /* ---- Production Voucher fixes ------------------------------------------
     The Additional Charges card is inline-styled `padding-left: 60%` so it
     sits under the totals on a wide screen. On a phone that leaves the fields
     in a 40%-wide gutter. */
  .modal .card[style*="padding-left: 60%"],
  .modal .card[style*="padding-left:60%"] {
    padding-left: 8px !important;
  }

  /* Its nested "Process Detail" popup is a second .modal-content with its own
     header and no dialog bar. The close button is a bare `.close` that the
     header's flex row squeezed to nothing - give it a real target and keep it
     on screen while the sheet scrolls. */
  .modal .modal-content .modal-content > .modal-header {
    position: sticky;
    top: 0;
    z-index: 4;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 10px 12px !important;
  }

  .modal .modal-content .modal-content > .modal-header > .close,
  .modal .modal-content .modal-content > .modal-header > button.close {
    position: static !important;
    flex: 0 0 auto;
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    margin: 0 !important;
    padding: 0 !important;
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.18);
    color: #fff !important;
    opacity: 1 !important;
    font-size: 1.4rem;
    line-height: 1;
  }

  /* the heading next to it must not push the button off the row */
  .modal .modal-content .modal-content > .modal-header > h4,
  .modal .modal-content .modal-content > .modal-header > h5,
  .modal .modal-content .modal-content > .modal-header > p {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  /* ==========================================================================
     Item / Service Master - visual polish
     --------------------------------------------------------------------------
     Everything below is scoped to `#item_form2` so it cannot reach any other
     screen. The structural rules above make the form usable; this makes it
     read like an app rather than a squeezed desktop dialog: one idea per card,
     a calm neutral canvas, brand colour reserved for headings and focus.
     ========================================================================== */

  #item_form2 .modal-body {
    background: var(--m-canvas);
    padding: 12px 10px calc(96px + env(safe-area-inset-bottom, 0px)) !important;
  }

  /* --- every block of fields becomes a card on the canvas --- */
  #item_form2 .m-sec > .col-md-12,
  #item_form2 .m-sec .bgc-white,
  #item_form2 .m-sec .AddVariationDiv {
    background: var(--m-surface);
    border: 1px solid var(--m-line);
    border-radius: 14px;
    box-shadow: 0 1px 2px rgba(16, 24, 40, 0.04);
    padding: 12px !important;
    margin: 0 0 12px !important;
  }

  /* --- field rows: label above, control full width, generous target --- */
  #item_form2 .form-group {
    margin-bottom: 12px !important;
  }

  #item_form2 .form-group > label {
    display: block;
    margin-bottom: 5px;
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: var(--m-ink-soft);
  }

  /* the required marker should read as a marker, not as part of the label */
  #item_form2 .form-group > label .text-danger,
  #item_form2 .form-group > label span[style*="red"] {
    color: #dc2626 !important;
    font-weight: 700;
  }

  #item_form2 .form-control,
  #item_form2 .ng-select .ng-select-container,
  #item_form2 .select2-container .select2-selection--single {
    min-height: var(--m-tap);
    border-radius: 10px !important;
    border: 1px solid var(--m-line) !important;
    background: #fbfcfe;
    font-size: 16px;            /* keeps iOS from zooming on focus */
    color: var(--m-ink);
  }

  #item_form2 .form-control:focus,
  #item_form2 .ng-select.ng-select-focused .ng-select-container {
    border-color: var(--m-accent) !important;
    background: #fff;
    box-shadow: 0 0 0 3px rgba(66, 133, 244, 0.14) !important;
  }

  #item_form2 .form-control[readonly],
  #item_form2 .form-control:disabled {
    background: #f1f3f7;
    color: var(--m-ink-soft);
  }

  /* --- variant cards --- */
  #item-attribute-table.m-stack-grid > tbody > tr,
  #item-attribute-table.m-stack-grid > tfoot > tr {
    border: 1px solid var(--m-line) !important;
    border-radius: 14px;
    box-shadow: 0 1px 3px rgba(16, 24, 40, 0.06);
    padding: 0 !important;
    margin-bottom: 12px;
    overflow: hidden;
  }

  #item-attribute-table.m-stack-grid > tbody > tr > td,
  #item-attribute-table.m-stack-grid > tfoot > tr > td {
    padding: 12px 12px 6px !important;
  }

  /* the variant number strip tops the card */
  #item-attribute-table.m-stack-grid td[data-label="SNo"] {
    background: linear-gradient(180deg, #f7f9fc 0%, #f2f5fa 100%) !important;
    border-radius: 0 !important;
    border-bottom: 1px solid var(--m-line) !important;
    padding: 8px 12px !important;
    font-weight: 700;
    color: var(--m-brand);
  }

  /* delete sits in the strip as a proper icon button */
  #item-attribute-table.m-stack-grid td[data-label="SNo"] .roundbtn,
  #item-attribute-table.m-stack-grid td[data-label="SNo"] a,
  #item-attribute-table.m-stack-grid td[data-label="SNo"] button {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    width: 34px !important;
    height: 34px !important;
    padding: 0 !important;
    border-radius: 9px !important;
    background: #fdeaea !important;
    color: #dc2626 !important;
    border: 0 !important;
  }

  /* group heading: a small brand rule above each set of fields */
  #item-attribute-table.m-stack-grid > tbody > tr > td[data-label]:not([data-label="SNo"])::before,
  #item-attribute-table.m-stack-grid > tfoot > tr > td[data-label]:not([data-label="SNo"])::before {
    padding: 0 0 6px !important;
    border-bottom: 2px solid rgba(42, 88, 173, 0.15) !important;
  }

  /* label/value pairs inside a group */
  #item-attribute-table.m-stack-grid .form-group {
    margin-bottom: 10px !important;
  }

  /* inside a variant group the label sits BESIDE its field, so it must not
     inherit the block/uppercase treatment the top-level field labels get */
  #item-attribute-table.m-stack-grid .form-group label {
    display: block;
    margin-bottom: 0 !important;
    font-size: 0.74rem;
    font-weight: 600;
    text-transform: none !important;
    letter-spacing: 0 !important;
    color: var(--m-ink-soft);
  }

  /* --- step tabs read as a segmented control --- */
  #item_form2 .m-dialog-bar__steps .m-step.is-active {
    background: rgba(255, 255, 255, 0.14);
    border-radius: 8px 8px 0 0;
  }

  /* --- the toggles on the Options step --- */
  #item_form2 .m-sec-payment .custom-control {
    display: flex;
    align-items: center;
    min-height: var(--m-tap);
    margin: 0 0 6px;
    padding: 6px 10px 6px 34px;
    border: 1px solid var(--m-line);
    border-radius: 10px;
    background: #fff;
  }

  #item_form2 .m-sec-payment .custom-control-label {
    font-size: 0.86rem;
    font-weight: 500;
    color: var(--m-ink);
  }

  /* ==========================================================================
     GST Rate Applicability
     --------------------------------------------------------------------------
     A parent item card with its rate-history rows nested underneath. The
     history rows share `attr-cont` with the parent, so without this they read
     as more parent cards. Scoped with `.m-gst-grid`, a marker added to this
     table - `id="item"` is shared with item-bulk-update, ledger-adjustment,
     amc and backup-data, and `fixTable7` with amc-details.
     ========================================================================== */

  /* the parent item card */
  .m-gst-grid > tbody > tr.m-committed:not(.ChildRows) {
    border: 1px solid var(--m-line) !important;
    border-radius: 12px;
    box-shadow: 0 1px 2px rgba(16, 24, 40, 0.05);
    margin-bottom: 8px;
  }

  /* the selection checkbox belongs at the top of the card, not floating */
  .m-gst-grid > tbody > tr.m-committed > td.m-cell-actions {
    justify-content: flex-start !important;
    padding: 0 0 6px !important;
    border-bottom: 1px solid #eef1f6 !important;
  }

  .m-gst-grid > tbody > tr.m-committed > td.m-cell-actions::before {
    content: "Select" !important;
    flex: 0 0 42%;
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    color: var(--m-ink-soft);
  }

  /* history rows: indented, tinted, visually owned by the card above */
  .m-gst-grid > tbody > tr.ChildRows {
    margin: -4px 0 10px 14px !important;
    border: 1px solid #e3e8f0 !important;
    border-left: 3px solid var(--m-accent) !important;
    border-radius: 0 10px 10px 0 !important;
    background: #f7f9fc !important;
    box-shadow: none !important;
  }

  .m-gst-grid > tbody > tr.ChildRows > td {
    background: transparent !important;
    border-bottom-color: #e7ecf3 !important;
    font-size: 0.78rem;
  }

  .m-gst-grid > tbody > tr.ChildRows > td::before {
    color: var(--m-accent) !important;
  }

  /* "Child Row Not Found!" is a note, not a record */
  .m-gst-grid > tbody > tr.ChildRows > td[colspan] {
    display: block !important;
    padding: 8px !important;
    border: 0 !important;
    text-align: center !important;
    font-size: 0.76rem;
    font-style: italic;
    color: var(--m-ink-soft);
  }

  .m-gst-grid > tbody > tr.ChildRows > td[colspan]::before {
    content: none !important;
  }

  /* delete on a history row reads as a destructive action */
  .m-gst-grid > tbody > tr.ChildRows > td[data-label="Action"] a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: 9px;
    background: #fdeaea;
  }

  /* ==========================================================================
     Item Bulk Update - field picker
     --------------------------------------------------------------------------
     The point of this screen is changing ONE field across many items. Listing
     all 21 fields per item turns a 30-second job into a scroll marathon, so
     the chip row picks a field and every card collapses to `name + that one
     input`. "All fields" restores the full card for the occasional deep edit.
     ========================================================================== */

  .m-field-picker {
    display: flex;
    align-items: center;
    gap: 6px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding: 8px 10px;
    margin: 0 0 8px;
    background: var(--m-surface);
    border: 1px solid var(--m-line);
    border-radius: 12px;
  }

  .m-field-picker::-webkit-scrollbar { display: none; }

  .m-field-picker__hint {
    flex: 0 0 auto;
    margin-right: 2px;
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--m-ink-soft);
  }

  .m-field-picker .m-fchip {
    flex: 0 0 auto;
    min-height: 34px;
    padding: 0 12px;
    border: 1px solid var(--m-line);
    border-radius: 17px;
    background: #f6f8fb;
    color: var(--m-ink);
    font-size: 0.78rem;
    font-weight: 600;
    white-space: nowrap;
  }

  .m-field-picker .m-fchip.is-active {
    background: var(--m-brand);
    border-color: var(--m-brand);
    color: #fff;
  }

  /* one rule per field - CSS cannot compare an attribute to another attribute */
  [data-mfield="BarCode"] > tbody > tr > td[data-label]:not([data-label="BarCode"]):not([data-label="Name"]) {
    display: none !important;
  }

  [data-mfield="ItemCode"] > tbody > tr > td[data-label]:not([data-label="ItemCode"]):not([data-label="Name"]) {
    display: none !important;
  }

  [data-mfield="Op. Stock Qty"] > tbody > tr > td[data-label]:not([data-label="Op. Stock Qty"]):not([data-label="Name"]) {
    display: none !important;
  }

  [data-mfield="Op. Stock Value"] > tbody > tr > td[data-label]:not([data-label="Op. Stock Value"]):not([data-label="Name"]) {
    display: none !important;
  }

  [data-mfield="Avg/Purchase Rate"] > tbody > tr > td[data-label]:not([data-label="Avg/Purchase Rate"]):not([data-label="Name"]) {
    display: none !important;
  }

  [data-mfield="Sale Rate"] > tbody > tr > td[data-label]:not([data-label="Sale Rate"]):not([data-label="Name"]) {
    display: none !important;
  }

  [data-mfield="Our Price"] > tbody > tr > td[data-label]:not([data-label="Our Price"]):not([data-label="Name"]) {
    display: none !important;
  }

  [data-mfield="Secondary Unit"] > tbody > tr > td[data-label]:not([data-label="Secondary Unit"]):not([data-label="Name"]) {
    display: none !important;
  }

  [data-mfield="Secondary Qty"] > tbody > tr > td[data-label]:not([data-label="Secondary Qty"]):not([data-label="Name"]) {
    display: none !important;
  }

  [data-mfield="Secondary Rate"] > tbody > tr > td[data-label]:not([data-label="Secondary Rate"]):not([data-label="Name"]) {
    display: none !important;
  }

  [data-mfield="Min. Order"] > tbody > tr > td[data-label]:not([data-label="Min. Order"]):not([data-label="Name"]) {
    display: none !important;
  }

  [data-mfield="Max. Order"] > tbody > tr > td[data-label]:not([data-label="Max. Order"]):not([data-label="Name"]) {
    display: none !important;
  }

  [data-mfield="ReOrder"] > tbody > tr > td[data-label]:not([data-label="ReOrder"]):not([data-label="Name"]) {
    display: none !important;
  }

  /* with a single field showing, the card becomes one compact line */
  [data-mfield]:not([data-mfield="all"]) > tbody > tr.m-committed {
    display: flex !important;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 10px;
    padding: 8px 10px !important;
  }

  [data-mfield]:not([data-mfield="all"]) > tbody > tr.m-committed > td[data-label="Name"] {
    flex: 1 1 100%;
    border-bottom: 0 !important;
    padding-bottom: 2px !important;
    font-weight: 600;
  }

  [data-mfield]:not([data-mfield="all"]) > tbody > tr.m-committed > td[data-label="Name"]::before {
    content: none !important;
  }

  [data-mfield]:not([data-mfield="all"]) > tbody > tr.m-committed > td[data-label]:not([data-label="Name"]) {
    flex: 1 1 100%;
    border-bottom: 0 !important;
    padding-top: 0 !important;
  }

  /* ==========================================================================
     GST Rate Applicability - card shaped to the actual task
     --------------------------------------------------------------------------
     The workflow is: filter -> tick items -> Set HSN / Taxability / Rate ->
     Apply -> Save. So a row is mostly something you IDENTIFY and TICK, with
     four fields you may override per item. Rendering all 19 columns as equal
     labelled lines buried the four that matter under the read-only tax split.
     Now: a heading line, the four editable fields, and the split on one line.
     ========================================================================== */

  /* item name is the card's heading, not a labelled field */
  .m-gst-grid > tbody > tr.m-committed:not(.ChildRows) > td[data-label="Item"] {
    display: block !important;
    padding: 2px 0 0 !important;
    border-bottom: 0 !important;
    text-align: left !important;
    font-size: 0.95rem;
    font-weight: 700;
    color: var(--m-ink);
  }

  .m-gst-grid > tbody > tr.m-committed:not(.ChildRows) > td[data-label="Item"]::before {
    content: none !important;
  }

  /* category sits under it as a caption */
  .m-gst-grid > tbody > tr.m-committed:not(.ChildRows) > td[data-label="Category"] {
    display: block !important;
    padding: 0 0 8px !important;
    border-bottom: 1px solid #eef1f6 !important;
    text-align: left !important;
    font-size: 0.72rem;
    color: var(--m-ink-soft);
  }

  .m-gst-grid > tbody > tr.m-committed:not(.ChildRows) > td[data-label="Category"]::before {
    content: none !important;
  }

  /* the four fields you can actually change, called out */
  .m-gst-grid > tbody > tr.m-committed > td[data-label="Applicable From"],
  .m-gst-grid > tbody > tr.m-committed > td[data-label="HSN No"],
  .m-gst-grid > tbody > tr.m-committed > td[data-label="Taxablity"],
  .m-gst-grid > tbody > tr.m-committed > td[data-label="Tax Rate"] {
    align-items: center;
    padding: 6px 0 !important;
  }

  .m-gst-grid > tbody > tr.m-committed > td[data-label="Applicable From"]::before,
  .m-gst-grid > tbody > tr.m-committed > td[data-label="HSN No"]::before,
  .m-gst-grid > tbody > tr.m-committed > td[data-label="Taxablity"]::before,
  .m-gst-grid > tbody > tr.m-committed > td[data-label="Tax Rate"]::before {
    color: var(--m-ink) !important;
  }

  /* IGST / CGST / SGST / CESS are read-only splits of one number - one line */
  .m-gst-grid > tbody > tr.m-committed > td[data-label="IGST"],
  .m-gst-grid > tbody > tr.m-committed > td[data-label="CGST"],
  .m-gst-grid > tbody > tr.m-committed > td[data-label="SGST"],
  .m-gst-grid > tbody > tr.m-committed > td[data-label="CESS"] {
    display: inline-flex !important;
    width: auto !important;
    gap: 4px;
    padding: 4px 8px 4px 0 !important;
    border-bottom: 0 !important;
    font-size: 0.74rem;
    color: var(--m-ink-soft);
  }

  .m-gst-grid > tbody > tr.m-committed > td[data-label="IGST"]::before,
  .m-gst-grid > tbody > tr.m-committed > td[data-label="CGST"]::before,
  .m-gst-grid > tbody > tr.m-committed > td[data-label="SGST"]::before,
  .m-gst-grid > tbody > tr.m-committed > td[data-label="CESS"]::before {
    flex: 0 0 auto !important;
    font-size: 0.64rem !important;
  }

  /* the row that holds them gets a tinted strip so the split reads as a group */
  .m-gst-grid > tbody > tr.m-committed:not(.ChildRows) {
    padding-bottom: 4px !important;
  }

  /* History toggle is an action, not a value */
  .m-gst-grid > tbody > tr.m-committed > td[data-label="History"] {
    justify-content: flex-start !important;
    padding-top: 8px !important;
    border-top: 1px solid #eef1f6;
    border-bottom: 0 !important;
  }

  .m-gst-grid > tbody > tr.m-committed > td[data-label="History"]::before {
    content: none !important;
  }

  /* a history row is one line, not seven */
  .m-gst-grid > tbody > tr.ChildRows > td[data-label] {
    display: inline-flex !important;
    width: auto !important;
    gap: 4px;
    padding: 3px 10px 3px 0 !important;
    border-bottom: 0 !important;
    font-size: 0.72rem;
  }

  .m-gst-grid > tbody > tr.ChildRows > td[data-label="Item"],
  .m-gst-grid > tbody > tr.ChildRows > td[data-label="Category"] {
    display: none !important;
  }

  .m-gst-grid > tbody > tr.ChildRows > td[data-label]::before {
    flex: 0 0 auto !important;
    font-size: 0.62rem !important;
  }

  /* ---- Item Bulk Update: fill-down strip + sticky action bar ---- */
  .m-fill-strip {
    display: flex;
    gap: 6px;
    align-items: center;
    padding: 8px 10px;
    margin: 0 0 8px;
    border: 1px solid rgba(42, 88, 173, 0.25);
    border-radius: 12px;
    background: #f2f6fd;
  }

  .m-fill-strip .form-control {
    flex: 1 1 auto;
    min-width: 0;
    min-height: 40px;
    border-radius: 9px;
    font-size: 16px;
  }

  .m-fill-strip .btn {
    flex: 0 0 auto;
    min-height: 40px;
    padding: 0 10px;
    border-radius: 9px;
    font-size: 0.76rem;
    font-weight: 700;
    white-space: nowrap;
  }

  .m-fill-strip .m-fill-sel {
    background: #fff;
    border: 1px solid var(--m-brand);
    color: var(--m-brand);
  }

  .m-fill-strip .m-fill-all {
    background: var(--m-brand);
    color: #fff;
  }

  .m-fill-strip .btn:disabled {
    opacity: 0.45;
  }

  /* sticky bar: count on the left, Save on the right */
  .m-bulk-bar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1100;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 8px 12px calc(8px + env(safe-area-inset-bottom, 0px));
    background: var(--m-surface);
    border-top: 1px solid var(--m-line);
    box-shadow: 0 -2px 10px rgba(16, 24, 40, 0.08);
  }

  .m-bulk-bar__count {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 0.8rem;
    color: var(--m-ink-soft);
  }

  .m-bulk-bar__count strong {
    font-size: 1rem;
    color: var(--m-brand);
  }

  .m-bulk-bar__clear {
    margin-left: 8px;
    padding: 0;
    border: 0;
    background: none;
    color: var(--m-accent);
    font-size: 0.76rem;
    font-weight: 600;
    text-decoration: underline;
  }

  .m-bulk-bar .btn-success {
    flex: 0 0 auto;
    min-width: 108px;
    min-height: var(--m-tap);
    border-radius: 10px;
    font-weight: 700;
  }

  /* the bar must not sit on top of the last card */
  .m-bulk-bar ~ * { margin-bottom: 0; }

  .itembulkupdatelist { margin-bottom: 84px !important; }

  /* the picker and the strip travel with you while you work down the list */
  .m-field-picker {
    position: sticky;
    top: 0;
    z-index: 6;
  }

  /* ---- Production Process Master ---- */

  /* the section heading sits in a col-3, which stays 25% wide on a phone and
     prints one word per line */
  #processmodel_master .col-3,
  #processmodel_master .col-2,
  #processmodel_master .col-4 {
    flex: 0 0 100% !important;
    max-width: 100% !important;
  }

  #processmodel_master .summery_text {
    margin: 4px 0 8px;
    padding-bottom: 6px;
    border-bottom: 2px solid rgba(42, 88, 173, 0.15);
    font-size: 0.82rem;
    font-weight: 700;
    color: var(--m-brand);
  }

  /* the commit button belongs after the fields it commits, not above them.
     `order` needs a flex container, and an all-fields row is display:block. */
  .m-stack-all.m-stack-all > tfoot > tr {
    display: flex !important;
    flex-direction: column;
  }

  /* An HTML `width="5%"` on a <td> is a presentational hint that no rule here
     was answering: the row above is a flex COLUMN, and an explicit width beats
     `stretch`. So the entry row kept its desktop proportions - the add button
     sat in a 5% cell (a clipped circle), the type select in a 20% one - and
     sizing the CONTROLS to 100% only made them fill a cell that was already
     tiny. Cells in a stacked card span the card; the widths are the table
     layout the card replaced. `tr:not(.selected_row)` leaves the charge/payment
     editor rows to the `flex: 1 1 100%` rule that already handles them. */
  .m-stack-all.m-stack-all > tfoot > tr > td,
  .m-stack-all.m-stack-all > tbody > tr > td[width],
  .m-stack-charge > tfoot > tr:not(.selected_row) > td[width],
  .m-stack-pay > tfoot > tr:not(.selected_row) > td[width] {
    width: 100% !important;
    max-width: 100% !important;
    min-width: 0 !important;
  }

  /* A colspan cell with no label is usually desktop filler, so it is hidden.
     Some carry real guidance ("First Contact-No. must be the WhatsApp
     number") - `m-note` opts those back in as a full-width callout. */
  .m-stack-grid > tfoot > tr > td.m-note,
  .m-stack-grid > tbody > tr > td.m-note {
    display: block !important;
    order: 95;
    width: 100% !important;
    padding: 8px 0 0 !important;
    border: 0 !important;
    text-align: left !important;
    font-size: 0.75rem;
    line-height: 1.35;
  }

  /* "Add item" is the right word on a Stock Journal grid and the wrong one on
     a contact list. A grid can name its own button. */
  .m-stack-grid td.m-cell-actions .btn_add_more[data-maddlabel]::after,
  .m-stack-grid td.m-addbtn .btn_add_more[data-maddlabel]::after {
    content: attr(data-maddlabel);
  }

  .m-stack-all.m-stack-all > tfoot > tr > td.m-cell-actions,
  .m-stack-all.m-stack-all > tfoot > tr > td.m-addbtn {
    order: 90;
    margin-top: 8px;
    padding-top: 10px !important;
    border-top: 1px solid var(--m-line) !important;
    border-bottom: 0 !important;
  }

  .m-stack-all.m-stack-all > tfoot > tr > td.m-cell-actions .btn_add_more,
  .m-stack-all.m-stack-all > tfoot > tr > td.m-addbtn .btn_add_more {
    width: 100%;
    min-height: var(--m-tap);
    border-radius: 10px !important;
  }

  /* ---- list rows whose Action cell holds more than one control ----
     The compact grid reserves a single 44px column for the action. Master
     lists put Edit AND Delete there as two separate <a>s, which overflowed it
     and drifted apart. Let the column take the width it needs and keep the
     icons together as one group. */
  .m-list-compact td[data-label="Action"] {
    gap: 2px;
  }

  /* a wrapper that only holds the cog menu carries no chrome of its own -
     the `.dropdown-toggle` inside is the button */
  .m-list-compact td[data-label="Action"] > a.m-action-wrap {
    display: contents;
  }

  .m-list-compact td[data-label="Action"] > a:not(.m-action-wrap),
  .m-list-compact td[data-label="Action"] .actionBtn {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    margin: 0 !important;
    border-radius: 8px;
    background: #f4f6fa;
  }

  .m-list-compact td[data-label="Action"] > a + a,
  .m-list-compact td[data-label="Action"] .actionBtn + .actionBtn {
    margin-left: 4px !important;
  }

  .m-list-compact td[data-label="Action"] i {
    font-size: 14px !important;
    margin: 0 !important;
    /* `table.cat-table td a > i` gives every list icon a 38px floor so it is
       tappable in the desktop-style table. Here the 36px <a> around it IS the
       tap target, so the floor only makes the icon overflow its own button. */
    min-width: 0 !important;
    min-height: 0 !important;
  }

  /* ---- the shared "Add New Address" dialog (#addressPopup) ----------------
     Opened from the Shipping / Billing Address dropdown's "Add New" in every
     transaction form (commonService.openAddress -> address-add).

     This one was my doing. Its mobile bar carries only a title and a close -
     no actions row - while the generic rule `.m-dialog-bar ~ .modal-footer`
     hides the real footer, and that footer is where Close AND Save live. So
     on a phone the dialog had no way to save at all.

     The footer is put back and pinned to the bottom of the dialog, which is
     also what the desktop shows; the bar keeps the title. Scoped to this id,
     so no other dialog's footer is un-hidden. */
  #addressPopup .m-dialog-bar ~ .modal-footer {
    display: flex !important;
  }

  #addressPopup .modal-footer {
    position: sticky;
    bottom: 0;
    z-index: 3;
    flex: 0 0 auto !important;
    flex-wrap: nowrap;
    gap: 8px;
    justify-content: stretch;
    margin: 0 !important;
    padding: 10px 12px calc(10px + env(safe-area-inset-bottom, 0px)) !important;
    background: var(--m-surface);
    border-top: 1px solid var(--m-line);
    box-shadow: 0 -4px 12px rgba(16, 24, 40, 0.08);
  }

  #addressPopup .modal-footer .btn {
    flex: 1 1 0;
    min-height: var(--m-tap);
    margin: 0 !important;
    border-radius: 10px;
    font-weight: 600;
  }

  /* the body is the only scroller, so the footer cannot be pushed off */
  #addressPopup .modal-content {
    display: flex !important;
    flex-direction: column !important;
    height: 100% !important;
    max-height: 100% !important;
    overflow: hidden !important;
  }

  #addressPopup .modal-body {
    flex: 1 1 auto !important;
    min-height: 0 !important;
    max-height: none !important;
    overflow-y: auto !important;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
  }

  /* ---- Billing / Shipping "Add New" address popups ------------------------
     `[id$="cust_detail_m"]` catches all nine: cust_detail_m plus the
     purchase_, credit_, debit_, profromainvoice_ and quotation_ variants.
     Every transaction form carries its own copy of this dialog.

     Its Save / Reset footer was ending up below the fold, so the popup looked
     like it stopped after the Address field. The generic dialog rules should
     already pin it, but this one is opened on top of an ALREADY-OPEN
     transaction dialog, and a second modal is exactly where an inherited
     height or overflow from the stack can leave `.modal-content` unbounded -
     at which point a flex footer simply sits past the bottom of the screen.

     Rather than depend on that chain holding, the popup is made explicitly
     self-contained: bounded content box, the body as the only scroller, and
     the footer stuck to the bottom of it. Scoped by id, so no other dialog
     can be affected, and inside the mobile query, so desktop is untouched. */
  .modal[id$="cust_detail_m"] .modal-content {
    display: flex !important;
    flex-direction: column !important;
    height: 100% !important;
    max-height: 100% !important;
    overflow: hidden !important;
  }

  .modal[id$="cust_detail_m"] .modal-body {
    flex: 1 1 auto !important;
    min-height: 0 !important;
    max-height: none !important;
    overflow-y: auto !important;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    /* clearance so the last field clears the sticky footer */
    padding-bottom: 12px !important;
  }

  .modal[id$="cust_detail_m"] .modal-footer {
    position: sticky;
    bottom: 0;
    z-index: 3;
    flex: 0 0 auto !important;
    display: flex !important;
    flex-wrap: nowrap;
    gap: 8px;
    justify-content: stretch;
    margin: 0 !important;
    padding: 10px 12px calc(10px + env(safe-area-inset-bottom, 0px)) !important;
    background: var(--m-surface);
    border-top: 1px solid var(--m-line);
    box-shadow: 0 -4px 12px rgba(16, 24, 40, 0.08);
  }

  .modal[id$="cust_detail_m"] .modal-footer .btn {
    flex: 1 1 0;
    min-height: var(--m-tap);
    margin: 0 !important;
    border-radius: 10px;
    font-weight: 600;
  }

  /* ---- Customer / Vendor registration ---- */

  /* the GST lookup row is `label + 300px inline input + button`, which on a
     phone crashes into the section heading underneath */
  #customer_form .modal-body > .form-row > .col-md-12,
  #vendor_form .modal-body > .form-row > .col-md-12,
  #add_crm_customer .modal-body > .form-row > .col-md-12 {
    padding-left: 12px !important;
    padding-right: 12px !important;
  }

  /* All three templates that carry a GST lookup - Customer, Vendor and CRM
     Add Customer - inline-style the field `width: 300px; display: inline`. */
  #customer_form .modal-body input[name="gstinMain"],
  #vendor_form .modal-body input[name="gstinMain"],
  #add_crm_customer .modal-body input[name="gstinMain"] {
    display: block !important;
    width: 100% !important;
    margin: 4px 0 8px;
  }

  #customer_form .modal-body > .form-row > .col-md-12 > .btn,
  #vendor_form .modal-body > .form-row > .col-md-12 > .btn,
  #add_crm_customer .modal-body > .form-row > .col-md-12 > .btn {
    display: block;
    width: 100%;
    min-height: var(--m-tap);
    border-radius: 10px;
  }

  /* `.nav-link` here is a section heading dressed as a tab - the step chips
     already say where you are, so render it as a plain heading */
  .classic-tabs .nav.tabs-cyan {
    display: block;
    margin: 0 0 8px;
    padding: 0;
    background: none !important;
    box-shadow: none !important;
  }

  .classic-tabs .nav.tabs-cyan .nav-item {
    display: block;
    list-style: none;
  }

  .classic-tabs .nav.tabs-cyan .nav-link {
    display: block;
    padding: 0 0 6px !important;
    border: 0 !important;
    border-bottom: 2px solid rgba(42, 88, 173, 0.15) !important;
    border-radius: 0 !important;
    background: none !important;
    color: var(--m-brand) !important;
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
  }

  /* ---- Customer / Vendor: saved Address and Bank cards -------------------
     These are the `.profile-pic > .card` blocks under the entry fields.

     The actions live in `.edit`, which the desktop sheet declares as
     `position: absolute; display: none`, revealed by `.profile-pic:hover`.
     A touch screen has no hover. The Address card gets away with it because
     its markup carries an inline `display: block` - the Bank card does not,
     so Edit and Delete were UNREACHABLE on a phone. And `.edit a` is
     `color: #fff`, which only reads while hovered, so even on the Address
     card the pencil was white on white.

     Actions therefore become a normal row beneath the text: always present,
     in real colours, at tap size. */
  #customer_form .profile-pic,
  #vendor_form .profile-pic {
    display: block !important;
    width: 100% !important;
  }

  #customer_form .profile-pic .edit,
  #vendor_form .profile-pic .edit {
    display: flex !important;
    position: static !important;
    justify-content: flex-end;
    align-items: center;
    gap: 4px;
    margin-top: 8px;
    padding: 6px 0 0 !important;
    border-top: 1px solid var(--m-line);
  }

  #customer_form .profile-pic .edit a,
  #vendor_form .profile-pic .edit a,
  #customer_form .profile-pic .edit .btn-link,
  #vendor_form .profile-pic .edit .btn-link {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    width: 40px;
    min-height: var(--m-tap);
    padding: 0 !important;
    color: var(--m-brand) !important;
    font-size: 1rem;
  }

  #customer_form .profile-pic .edit .fa-times,
  #vendor_form .profile-pic .edit .fa-times {
    color: #d9534f !important;
  }

  #customer_form .profile-pic .card,
  #vendor_form .profile-pic .card {
    margin-bottom: 10px;
    padding: 12px !important;
    border: 1px solid var(--m-line);
    border-radius: 10px;
  }

  #customer_form .profile-pic .card h5,
  #vendor_form .profile-pic .card h5 {
    margin-bottom: 4px;
    font-size: 0.86rem;
    font-weight: 700;
    color: var(--m-brand);
  }

  #customer_form .profile-pic .card p,
  #vendor_form .profile-pic .card span {
    font-size: 0.82rem;
    line-height: 1.4;
  }

  /* The add control is an unlabelled 30px `+` glyph sitting in a `col-md-4`
     that is padded to line up with the fields on a wide screen. On a phone
     it reads as decoration, so it becomes a labelled full-width button -
     `data-maddlabel` names it, since the same class adds an address on one
     card and a bank account on the other. */
  #customer_form .address_btn_more,
  #vendor_form .address_btn_more {
    padding-top: 4px !important;
  }

  #customer_form .addAddress_btn,
  #vendor_form .addAddress_btn {
    display: flex !important;
    align-items: center;
    justify-content: center;
    gap: 8px;
    width: 100%;
    min-height: var(--m-tap);
    padding: 0 12px;
    border: 1px dashed rgba(42, 88, 173, 0.45) !important;
    border-radius: 10px;
    background: #f4f7fd !important;
    color: var(--m-brand);
    font-size: 0.85rem;
    font-weight: 600;
  }

  #customer_form .addAddress_btn > div,
  #vendor_form .addAddress_btn > div,
  #customer_form .addAddress_btn .add_btn,
  #vendor_form .addAddress_btn .add_btn {
    display: inline-flex;
    align-items: center;
    padding: 0 !important;
    margin: 0 !important;
  }

  #customer_form .addAddress_btn .add_btn i,
  #vendor_form .addAddress_btn .add_btn i {
    font-size: 1.05rem !important;
    color: var(--m-brand) !important;
  }

  #customer_form .addAddress_btn[data-maddlabel]::after,
  #vendor_form .addAddress_btn[data-maddlabel]::after {
    content: attr(data-maddlabel);
  }

  /* the address textarea is a single short line by default */
  #customer_form .modal-body textarea.form-control,
  #vendor_form .modal-body textarea.form-control {
    min-height: 72px;
  }

  /* ---- status legend / quick filters (`.filter-cat`) ----------------------
     A `display: flex` list with no wrap, `width: 100%; float: left` and a
     fixed `margin-right` per chip. On a phone it runs straight off the right
     edge - on Follow Up only Overdue / Todays / Assigned / UnAssigned were
     reachable, while Converted, Tentative and Reset sat past the edge with no
     way to get to them: the row has no scroller of its own, and the card
     around it clips.

     Wrapping beats a horizontal scroller here. These are filters, and a
     filter you cannot see is a filter you cannot use. Shared by Follow Up,
     Lead, Daily Activity and Tentative Report. */
  .filter-cat {
    flex-wrap: wrap;
    gap: 6px;
    width: 100% !important;
    float: none !important;
    margin: 0 !important;
    padding: 4px 0 !important;
  }

  .filter-cat li {
    float: none !important;
    align-items: center;
    margin: 0 !important;
    padding: 6px 10px !important;
    border-radius: 8px;
    font-size: 0.78rem;
    line-height: 1.2;
  }

  /* the vertical rules between groups say nothing once the list wraps */
  .filter-cat li.seperator {
    display: none !important;
  }

  /* the swatch and its label read as one chip */
  .filter-cat li > div[class^="div"] {
    float: none !important;
    flex: 0 0 auto;
    margin: 0 6px 0 0 !important;
  }

  .filter-cat li > a {
    display: inline-flex;
    align-items: center;
  }

  /* Assign / Transfer share the same list but are buttons, not filters */
  .filter-cat li[style*="border:none"] {
    padding: 0 !important;
    border: 0 !important;
  }

  .filter-cat .btn {
    min-height: var(--m-tap);
    display: inline-flex;
    align-items: center;
    border-radius: 10px;
  }

  /* ---- entry FORMS that are pages, not dialogs ---------------------------
     CRM Order Add is a full page: no `.modal-content` flex column, so no
     sticky footer and no dialog bar. Its Save lives in the page header and
     scrolls out of reach on a form this long. `m-entry-page` marks such a
     page; the commit is repeated in a bar pinned to the bottom and the header
     copy is hidden so there is exactly one Save on screen. */
  .m-entry-page .page-header .btn_header {
    display: none !important;
  }

  /* Step chips for a page-based entry form. The dialog version rides in the
     brand bar; here there is no bar, so the strip sticks under the app header
     and carries its own brand background. */
  .m-entry-page .m-page-steps {
    position: sticky;
    top: 0;
    z-index: 20;
    display: flex;
    gap: 0;
    margin: 0 calc(-1 * var(--m-gutter)) 10px;
    padding: 0 4px;
    background: var(--m-brand);
    box-shadow: 0 1px 4px rgba(16, 24, 40, 0.12);
  }

  .m-entry-page .m-page-steps .m-step {
    flex: 1 1 0;
    min-width: 0;
    min-height: 42px;
    padding: 0 2px;
    border: 0;
    border-bottom: 2px solid transparent;
    background: transparent;
    color: rgba(255, 255, 255, 0.72);
    font-size: 0.76rem;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .m-entry-page .m-page-steps .m-step.is-active {
    color: #fff;
    border-bottom-color: #fff;
  }

  .m-entry-page .m-page-steps .m-step__count {
    display: inline-block;
    min-width: 17px;
    margin-left: 5px;
    padding: 0 4px;
    border-radius: 9px;
    background: rgba(255, 255, 255, 0.26);
    font-size: 0.68rem;
    line-height: 17px;
  }

  .m-entry-page .m-page-actions {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1030;
    display: flex;
    gap: 8px;
    padding: 8px var(--m-gutter) calc(8px + var(--m-safe-bottom));
    background: var(--m-surface);
    border-top: 1px solid var(--m-line);
    box-shadow: 0 -2px 10px rgba(16, 24, 40, 0.08);
  }

  .m-entry-page .m-page-actions .btn {
    flex: 1 1 auto;
    min-height: var(--m-tap);
    border-radius: 10px;
    font-weight: 600;
  }

  /* clearance so the last field can be scrolled clear of the pinned bar */
  .m-entry-page #mainContent {
    padding-bottom: calc(72px + var(--m-safe-bottom));
  }

  /* the two-column split (party | summary) is a desktop device; stacked, the
     divider reads as a stray line */
  .m-entry-page .form-row > .col-md-6.border-right {
    border-right: 0 !important;
  }

  /* ---- Customer Type Rate ------------------------------------------------
     Two systems on one screen (Discount / Custom Rate) chosen by a radio pair,
     then a filter panel, then the grids. */

  /* the mode switch is the first decision on the screen - make it read like
     one, instead of two inline radios lost above the filters */
  #mainContent fieldset#group {
    display: flex;
    gap: 8px;
    margin-bottom: 10px;
    padding: 4px;
    border-radius: 10px;
    background: #eef1f6;
  }

  #mainContent fieldset#group .custom-control.custom-control-inline {
    flex: 1 1 0;
    min-width: 0;
    margin: 0 !important;
    padding: 8px 6px 8px 28px;
    border-radius: 8px;
    background: #fff;
    font-size: 0.78rem;
  }

  /* `.form-col` is not a Bootstrap column, so the filter panel keeps its
     desktop shadow box on a phone - give it the card treatment instead */
  #mainContent .form-col.shadow {
    margin-top: 4px;
    padding: 10px;
    border-radius: 10px;
    background: #fff;
  }

  /* Add to Queue / Save sit in `col-md-1`..`col-md-3` boxes padded to line up
     with the fields beside them on a wide screen. Stacked, that padding is
     just a gap above a shrink-wrapped button.

     A full-width header button is right for a lone text action (Save, Filter,
     Search) and wrong for an ICON action. Item Master's export-for-import is
     `<button class="btn btn-link"><img></button>`, so it matched, was blown up
     to `width: 100%` and pushed onto a row of its own - landing in the middle
     of the screen while the plain `<a><img></a>` export beside it stayed a bare
     icon in the corner. That is the "two export buttons" report: one control,
     two wildly different renderings.

     `:not(.btn-link)` is the narrow fix. App-wide there are exactly two
     icon-only `.btn-link`s directly in a `.btn_header` - this one and one on
     Ledger Creation - and both want to stay inline icons. Every text button
     keeps the full-width treatment it already had. */
  #mainContent .form-group[class*="col-md-"] > .btn,
  #mainContent .right_saerch_side .btn_header > .btn:not(.btn-link) {
    display: block;
    width: 100%;
    min-height: var(--m-tap);
    border-radius: 10px;
  }

  #mainContent .form-group.pt-3[class*="col-md-"] {
    padding-top: 4px !important;
    margin-left: 0 !important;
    margin-right: 0 !important;
  }

  /* The Custom Rate grid is inline-styled `width: max-content` because its
     rate columns are generated one per customer type. The stack shell already
     forces `width: 100%`; this keeps the generated rate inputs usable once
     each becomes its own labelled line. */
  .m-stack-all td[data-label] > input.form-control,
  .m-stack-all td[data-label] > select.custom-select {
    width: 100% !important;
    max-width: 180px;
    min-height: 38px;
    margin-left: auto;
    text-align: right;
  }

  /* ---- controls inside a stacked sub-grid ----
     Contact / Email / discount rows carry desktop column widths on the <th>
     and inline widths on their selects, so the fields stayed thumbnail-sized
     once the cell went full width. */
  .m-stack-grid td .adw_select,
  .m-stack-grid td .input-group,
  .m-stack-grid td .ng-select,
  .m-stack-grid td select2,
  .m-stack-grid td .select2-container,
  .m-stack-grid td .discount {
    width: 100% !important;
    min-width: 0 !important;
    max-width: 100% !important;
  }

  /* A Bootstrap column inside a stacked cell keeps its 15px gutters, which
     eat into an already narrow value side (Discount Master wraps its rate
     control in a `col-md-12`). The card supplies the padding. */
  .m-stack-grid td > [class*="col-md-"],
  .m-stack-grid td > .form-group > [class*="col-md-"] {
    padding-left: 0 !important;
    padding-right: 0 !important;
    margin-bottom: 0 !important;
  }

  /* the currency selector next to a rate is inline-styled `width: 70px
     !important`, so it cannot be resized from here - let the amount take
     whatever is left rather than letting the pair overflow */
  .m-stack-grid td .discount > .form-control:not(.discount_type) {
    flex: 1 1 auto;
    min-width: 0;
  }

  .m-stack-grid td input.form-control,
  .m-stack-grid td select.form-control {
    width: 100% !important;
    min-width: 0 !important;
  }

  /* the round "+" add button is 30px on desktop and clipped its own label */
  .m-stack-grid td .roundbtn {
    display: flex !important;
    align-items: center;
    justify-content: center;
    width: 100% !important;
    height: auto !important;
    min-height: var(--m-tap);
    padding: 0 12px !important;
    border-radius: 10px !important;
    font-size: 0.86rem;
    font-weight: 700;
  }

  /* trash + pencil in a stacked row read as one action group */
  .m-stack-grid td.m-cell-actions .edit1 {
    display: flex !important;
    gap: 6px;
    justify-content: flex-end;
  }

  .m-stack-grid td.m-cell-actions .edit1 > a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: 8px;
    background: #f4f6fa;
  }

  /* ---- entry-form body ---- */

  /* Entry forms are dense; the generic dialog padding wastes width here. */
  .modal .large_form .modal-body {
    padding: 8px 8px calc(96px + env(safe-area-inset-bottom, 0px)) !important;
  }

  .modal .modal-body > form > .form-row {
    margin-left: 0;
    margin-right: 0;
  }

  /* Same problem one class over: a plain Bootstrap `.row` pulls -15px, and
     several dialogs open their body with `<div class="form row">` (Bank
     Master, for one) rather than `.form-row`. Against a 12px body gutter that
     puts the row 3px past each edge of the panel, which is enough to make the
     body scroll sideways - and once it is nudged, the field text sits under
     the edge. */
  .modal .modal-body > .row,
  .modal .modal-body > .form.row,
  .modal .modal-body > form > .row {
    margin-left: 0;
    margin-right: 0;
  }

  /* ---- `.discount`: an amount next to its unit selector -------------------
     `.discount` is `display: flex`, and the amount beside the selector is a
     `.form-control`, which Bootstrap gives `width: 100%`. As a flex item it
     therefore claims the whole line and the selector next to it is squeezed
     down to its minimum, cutting the text off on the right - "Select CR DR"
     on Bank Master, the currency symbol elsewhere. The amount flexes instead
     and the selector keeps a floor wide enough to read. 21 dialogs share this
     markup.

     `.discount_type` is excluded deliberately: it carries an inline
     `width: 70px !important` that no stylesheet can override, so allowing it
     to grow would only fight an unwinnable rule. */
  .modal .discount {
    gap: 6px;
  }

  .modal .discount > .form-control:not(.discount_type) {
    flex: 1 1 auto;
    min-width: 0;
  }

  .modal .discount > div {
    flex: 0 0 auto;
    min-width: 92px;
  }

  .modal .discount > div select2,
  .modal .discount > div .select2-container {
    width: 100% !important;
  }

  /* POS sale pins this column to min-width:800px via [ngStyle], which forces
     the whole dialog to scroll sideways on a phone. */
  .modal .form-row > .col-md-6.border-right {
    min-width: 0 !important;
    border-right: 0 !important;
    border-bottom: 1px solid var(--m-line);
    padding-bottom: 6px;
  }

  /* ---- BOTTOM-SHEET ITEM ENTRY (mobile) ----
     The grid has ~18 columns; panning it on a phone is unusable. On mobile it
     becomes: a plain list of committed lines, plus a bottom sheet that holds
     whichever entry row is active.

     The grid ships TWO mutually-exclusive control sets:
       <tfoot> row   - the NEW-item entry row (showHideAddItemRow)
       <tbody> row   - the EDIT row for one existing line (isDisabled=false,
                       which also sets showHideAddItemRow=false)
     Both are turned into the same sheet, so "add" and "edit" look identical.
     Committed <tbody> rows (.m-committed) become the list.

     Nothing is duplicated: same <select2>s, same inputs, same handlers, same
     #ViewChild refs, same addItems()/editItem()/deleteItem() calls. Only the
     presentation changes, so every calculation path is untouched. */

  .m-item-grid {
    max-height: none !important;
    min-height: 0;
    overflow: visible !important;
    padding-bottom: 4px;
  }

  .m-item-grid > table.item-table,
  .m-item-grid > table.item-table > tbody,
  .m-item-grid > table.item-table > tfoot {
    display: block;
    width: 100%;
    min-width: 0;
  }

  .m-item-grid > table.item-table > thead {
    display: none;
  }

  /* ---- neutralise the desktop column freeze -------------------------------
     Every entry form ships a component stylesheet that pins its first columns:

         .item-table tr td:first-child, .item-table tr th:first-child {
           position: sticky !important; left: 0px !important; width: 70px !important; }
         .item-table tr td:nth-child(2) { left: 70px  !important; width: 70px  !important; }
         .item-table tr td:nth-child(3) { left: 140px !important; width: 160px !important; }

     Those rules carry NO media query, so the desktop column-freezing follows
     the grid onto the phone: the action cell is dragged to a fixed left offset
     with a fixed width, which is why the trash/pencil sat in a tall box at the
     card's left edge instead of the right gutter. Their `!important` also beat
     the card's own `position: absolute`.

     There are no columns to freeze inside a card or a sheet, so the pinning is
     dropped here - before the rules below, which then re-assert the layout.

     Specificity matters here as much as `!important` does. Angular compiles
     those component selectors with its encapsulation attribute -
     `.item-table[_ngcontent-c] tr[_ngcontent-c] td[_ngcontent-c]:nth-child(3)`
     - which is FIVE in the class column. A plainly written rule here reaches
     two, and the class column is compared before the element column, so the
     component rule won and the pinning survived: that is the CATEGORY and ITEM
     rows sitting indented by `left: 140px` and overflowing at `width: 160px`.

     Repeating `[class]` raises the class column to six without changing what
     the selector matches. The sheet chrome is excluded because it sets its own
     `width: 100% !important` and must keep it. */
  .m-item-grid[class][class] table.item-table[class][class] > thead > tr > th,
  .m-item-grid[class][class] table.item-table[class][class] > tbody > tr
    > td:not(.m-sheet-head):not(.m-sheet-actions):not(.m-more-cell),
  .m-item-grid[class][class] table.item-table[class][class] > tfoot > tr
    > td:not(.m-sheet-head):not(.m-sheet-actions):not(.m-more-cell) {
    position: static !important;
    left: auto !important;
    right: auto !important;
    top: auto !important;
    width: auto !important;
    min-width: 0 !important;
    z-index: auto !important;
  }

  /* ============ 1. committed lines = the list ============
     Flex, not grid. The previous version placed Quantity and Rate in the SAME
     grid cell (row 2 / column 1) so they painted on top of each other, and the
     data-label ::before pseudo-elements were still rendering underneath. Both
     are fixed here: labels are suppressed on the list (the format speaks for
     itself) and every value gets its own flex slot. */

  .m-item-grid > table.item-table > tbody > tr.m-committed {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    column-gap: 6px;
    row-gap: 2px;
    width: 100%;
    margin: 0 0 8px;
    padding: 12px 14px;             /* the action cell is in the flow now */
    background: #fff;
    border: 1px solid var(--m-line);
    border-radius: 12px;
    box-shadow: 0 1px 2px rgba(16, 24, 40, 0.05);
  }

  .m-item-grid > table.item-table > tbody > tr.m-committed > td {
    display: block;
    width: auto !important;
    min-width: 0 !important;
    max-width: none !important;
    border: 0 !important;
    padding: 0 !important;
    font-size: 0.85rem;
    text-align: left;
    font-variant-numeric: tabular-nums;
  }

  /* no uppercase field labels on the summary line */
  .m-item-grid > table.item-table > tbody > tr.m-committed > td::before {
    content: none !important;
  }

  .m-item-grid > table.item-table > tbody > tr.m-committed > td:not(.m-sum) {
    display: none !important;
  }

  /* line 1 - item name, full width */
  .m-item-grid > table.item-table > tbody > tr.m-committed > td[data-label="Item"] {
    order: 1;
    flex: 1 1 100%;
    margin-bottom: 2px;
    font-size: 0.92rem;
    font-weight: 600;
    line-height: 1.3;
    color: var(--m-ink);
    word-break: break-word;
  }

  /* line 2 - qty x rate ............ amount */
  .m-item-grid > table.item-table > tbody > tr.m-committed > td[data-label="Quantity"] {
    order: 2;
    color: var(--m-ink-soft);
  }

  .m-item-grid > table.item-table > tbody > tr.m-committed > td[data-label="Quantity"]::after {
    content: " ×";
    margin-left: 4px;
    color: #9aa3af;
  }

  .m-item-grid > table.item-table > tbody > tr.m-committed > td[data-label="Rate"] {
    order: 3;
    color: var(--m-ink-soft);
  }

  .m-item-grid > table.item-table > tbody > tr.m-committed > td[data-label="Total Amount"] {
    order: 4;
    margin-left: auto;
    font-size: 0.95rem;
    font-weight: 700;
    color: var(--m-ink);
  }

  /* actions pinned to the card's right edge, clear of the text */
  .m-item-grid > table.item-table > tbody > tr.m-committed > td.m-cell-actions {
    /* Placed by FLOW, not by `position: absolute`.

       Absolute positioning here depended on `tr.m-committed` being the
       containing block, and on out-ranking a `position: sticky !important`
       that the component stylesheets apply to whichever cell happens to be
       nth-child(1..3). Both held only some of the time, and when either
       failed the cell fell back to its static position - the START of the
       flex row - which is why the icons sat in a column at the card's left
       edge instead of the right gutter.

       As an ordinary flex item with `order: 90` and `margin-left: auto` it
       lands at the end of the last line regardless of any of that. */
    position: static !important;
    order: 90;
    flex: 0 0 auto;
    margin-left: auto !important;
    align-self: center;
    width: auto !important;
    display: flex;
  }

  .m-item-grid table.item-table td.m-cell-actions .edit1 {
    /* the template writes `style="display: block"` on this div, and an inline
       declaration beats any normal one - hence the icons stacking vertically */
    display: flex !important;
    align-items: center;
    gap: 2px;
  }

  .m-item-grid table.item-table td.m-cell-actions a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 38px;
    min-height: 38px;
    border-radius: 8px;
  }

  /* Newly committed line animates in so the add lands visibly.
     `backwards` for the same reason as the two sheet animations: `both` would
     leave `transform: translateY(0)` on every card, making each one a
     stacking context and a containing block for positioned descendants. */
  .m-item-grid > table.item-table > tbody > tr.m-committed {
    animation: mLineIn 0.24s var(--m-ease) backwards;
  }

  @keyframes mLineIn {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: translateY(0); }
  }

  /* desktop-only keyboard hints ("Press F9 to add") */
  .m-kbd-hint {
    display: none !important;
  }

  /* in-grid totals row: bare unlabelled inputs read as noise on a phone, and
     the same figures are shown in the invoice summary below the grid */
  .m-item-grid > table.item-table > tfoot > tr:not(.selected_row) {
    display: none !important;
  }

  /* A row mid-edit, while the sheet is closed, reads as a normal list line. */
  .m-item-grid:not(.m-sheet-open) > table.item-table > tbody > tr:not(.m-committed) {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    column-gap: 6px;
    width: 100%;
    margin: 0 0 8px;
    padding: 12px 92px 12px 14px;
    background: #fffdf3;
    border: 1px solid #f0d98c;
    border-radius: 12px;
  }

  .m-item-grid:not(.m-sheet-open) > table.item-table > tbody > tr:not(.m-committed) > td {
    display: none !important;
  }

  .m-item-grid:not(.m-sheet-open) > table.item-table > tbody > tr:not(.m-committed) > td.m-cell-actions {
    display: flex !important;
    position: absolute !important;
    top: 50% !important;
    right: 8px !important;
    left: auto !important;
    transform: translateY(-50%);
    width: auto !important;
    padding: 0 !important;
    border: 0 !important;
  }

  .m-item-grid:not(.m-sheet-open) > table.item-table > tbody > tr:not(.m-committed)::after {
    content: "Editing - tap to continue";
    font-size: 0.82rem;
    font-weight: 600;
    color: #8a6d1f;
  }

  /* ============ 2. the active entry row = bottom sheet ============ */

  /* The entry rows are ALWAYS in the DOM, so the sheet must be gated on
     explicit state - otherwise it is permanently open and the invoice appears
     on the item form instead of the header. Closed is the default: the user
     picks a customer first, then taps "Add item" (or the edit pencil, which
     also sets mSheetOpen). */
  /* Only the NEW-item entry row is hidden when the sheet is closed. A tbody
     row that is mid-edit (isDisabled=false) must stay visible - hiding it made
     a cancelled edit look like the line had been deleted, when in fact it was
     still in Items[] the whole time. It renders with the committed styling
     below and is marked as being edited. */
  .m-item-grid:not(.m-sheet-open) > table.item-table > tfoot > tr.selected_row {
    display: none !important;
  }

  .m-item-grid.m-sheet-open > table.item-table > tbody > tr:not(.m-committed),
  .m-item-grid.m-sheet-open > table.item-table > tfoot > tr.selected_row {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1090;
    display: flex;
    flex-direction: column;
    width: 100%;
    /* 86vh resolves against iOS Safari's LARGE viewport (URL bar hidden),
       so the sheet's bottom edge - and the action bar with it - lands below
       the visible area whenever the URL bar is showing. dvh (below) tracks
       the live viewport; vh stays as the fallback for older engines. */
    max-height: 86vh;
    /* the action bar now sits at the TOP of the sheet, so only a normal
       resting gap plus the home indicator is needed here */
    padding-bottom: calc(18px + env(safe-area-inset-bottom, 0px)) !important;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    margin: 0;
    padding: 0;
    background: #fff;
    border: 0;
    border-radius: 18px 18px 0 0;
    box-shadow: 0 -10px 40px rgba(16, 24, 40, 0.3);
    /* `backwards`, not `both` - see the dialog animation lower down. `both`
       keeps the last keyframe applied forever, leaving `transform:
       translateY(0)` on this row. A transform makes the element the
       containing block for `position: fixed` descendants and a new stacking
       context, which is what made the sticky action bar float mid-screen and
       left select2's dropdown resolving against the wrong box. */
    animation: mSheetIn 0.28s var(--m-ease) backwards;
  }

  /* grab handle */
  /* ---- backdrop ----
     The sheet is `position: fixed` over the bottom of the screen with nothing
     behind it, so the form underneath stayed visible through it - "With
     Inventory", "Other Income/Discounts & Debits(F8)" and the rest printed
     straight across the sheet's fields - and remained tappable, so a stray
     touch could change the form under the open sheet.

     The layer hangs off the GRID, not the sheet row: the row is `z-index:
     1090` and forms a stacking context, so a child of it can never paint
     behind it. As a sibling in the same context, 1089 sits under the sheet and
     over the page. */
  .m-item-grid.m-sheet-open::before {
    content: "";
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 1089;
    background: rgba(16, 24, 40, 0.45);
  }

  /* and the sheet itself must be opaque, whatever the row classes carry */
  .m-item-grid.m-sheet-open > table.item-table > tbody > tr:not(.m-committed),
  .m-item-grid.m-sheet-open > table.item-table > tfoot > tr.selected_row {
    background: #fff !important;
  }

  .m-item-grid.m-sheet-open > table.item-table > tbody > tr:not(.m-committed)::before,
  .m-item-grid.m-sheet-open > table.item-table > tfoot > tr.selected_row::before {
    content: "";
    position: absolute;
    top: 7px;
    left: 50%;
    transform: translateX(-50%);
    width: 38px;
    height: 4px;
    border-radius: 2px;
    background: #d1d5db;
  }

  /* field rows inside the sheet */
  .m-item-grid.m-sheet-open > table.item-table > tbody > tr:not(.m-committed) > td,
  .m-item-grid.m-sheet-open > table.item-table > tfoot > tr.selected_row > td {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    width: 100% !important;
    min-width: 0 !important;
    max-width: none !important;
    padding: 5px 14px !important;
    border: 0 !important;
    font-size: 0.85rem;
    text-align: left;
  }

  .m-item-grid table.item-table td[data-label]::before {
    content: attr(data-label);
    flex: 0 0 34%;
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: var(--m-ink-soft);
  }

  /* empty spacer cells must not create blank sheet rows */
  .m-item-grid.m-sheet-open > table.item-table > tfoot > tr.selected_row > td:empty,
  .m-item-grid.m-sheet-open > table.item-table > tbody > tr:not(.m-committed) > td:empty {
    display: none !important;
  }

  .m-item-grid table.item-table td > .input-group,
  .m-item-grid table.item-table td > input,
  .m-item-grid table.item-table td > select,
  .m-item-grid table.item-table td > textarea,
  .m-item-grid table.item-table td > .select2-container,
  .m-item-grid table.item-table td > .ng-select {
    flex: 1 1 auto;
    min-width: 0 !important;
    width: auto !important;
    max-width: none !important;
  }

  .m-item-grid table.item-table td .min_width_350 {
    min-width: 0 !important;
  }

  .m-item-grid table.item-table td input,
  .m-item-grid table.item-table td select {
    min-height: 42px;
    font-size: 16px;
    text-align: right;
  }

  .m-item-grid table.item-table td .select2-container .select2-selection--single,
  .m-item-grid table.item-table td .ng-select .ng-select-container {
    min-height: 42px !important;
    height: 42px !important;
  }

  /* field order: Item first, money last, everything rare behind "More" */
  .m-item-grid table.item-table td[data-label="Category"]     { order: 2; }
  .m-item-grid table.item-table td[data-label="Item"]         { order: 3; }
  .m-item-grid table.item-table td[data-label="Ledger"]       { order: 3; }
  .m-item-grid table.item-table td[data-label="Variant"]      { order: 4; }
  .m-item-grid table.item-table td[data-label="Attribute"]    { order: 5; }
  .m-item-grid table.item-table td[data-label="Unit"]         { order: 6; }
  .m-item-grid table.item-table td[data-label="MRP"]          { order: 7; }
  .m-item-grid table.item-table td[data-label="Quantity"]     { order: 8; }
  .m-item-grid table.item-table td[data-label="Rate"]         { order: 9; }
  .m-item-grid table.item-table td[data-label="Discount"]     { order: 10; }
  .m-item-grid table.item-table td[data-label="Tax Slab"]     { order: 11; }
  .m-item-grid table.item-table td.m-adv                      { order: 20; }
  .m-item-grid table.item-table td[data-label="Total"]        { order: 30; }
  .m-item-grid table.item-table td[data-label="Taxable Amt"]  { order: 31; }
  .m-item-grid table.item-table td[data-label="Total Amount"] { order: 32; }
  .m-item-grid table.item-table td.m-addbtn                   { order: 40; }

  .m-item-grid table.item-table td[data-label="Total Amount"] {
    margin-top: 6px;
    padding-top: 8px !important;
    border-top: 1px solid #eef0f3 !important;
    font-weight: 700;
    font-size: 0.95rem;
  }

  /* advanced fields collapsed until "More details" */
  .m-item-grid table.item-table td.m-adv {
    display: none !important;
  }

  .m-item-grid.m-adv-open table.item-table td.m-adv {
    display: flex !important;
  }

  /* the "+" commit button becomes the sheet's primary action */
  .m-item-grid table.item-table td.m-addbtn {
    position: sticky;
    bottom: 0;
    margin-top: 10px;
    padding-top: 10px !important;
    background: #fff;
    border-top: 1px solid var(--m-line) !important;
  }

  .m-item-grid table.item-table td.m-addbtn::before {
    content: none;
  }

  .m-item-grid table.item-table td.m-addbtn .action_btn,
  .m-item-grid table.item-table td.m-addbtn .btn_add_more {
    width: 100%;
  }

  .m-item-grid table.item-table td.m-addbtn .btn_add_more {
    min-height: 46px;
    font-size: 0.95rem !important;
    font-weight: 600 !important;
    border-radius: 10px !important;
  }

  /* the in-sheet add anchor of the EDIT row */
  .m-item-grid.m-sheet-open > table.item-table > tbody > tr:not(.m-committed) > td.m-cell-actions {
    order: 40;
    position: sticky;
    bottom: 0;
    justify-content: stretch;
    margin-top: 10px;
    padding-top: 10px !important;
    background: #fff;
    border-top: 1px solid var(--m-line) !important;
  }

  .m-item-grid.m-sheet-open > table.item-table > tbody > tr:not(.m-committed) > td.m-cell-actions .edit1 {
    width: 100%;
    justify-content: flex-end;
    gap: 8px;
  }

  .m-item-grid.m-sheet-open > table.item-table > tbody > tr:not(.m-committed) > td.m-cell-actions a {
    min-width: 46px;
    min-height: 46px;
    background: #eef4ff;
  }

  /* Explicit entry point for the item sheet. Sits where the grid used to be,
     so the items section reads as: [Add item] + the list of committed lines. */
  .m-add-item-bar {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
    margin: 4px 0 10px;
  }

  .m-add-item-bar .btn {
    width: 100%;
    min-height: 46px;
    font-size: 0.9rem !important;
    font-weight: 600 !important;
    border-radius: 10px !important;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  .m-add-item-bar .btn:disabled {
    opacity: 0.5;
  }

  .m-add-item-bar small {
    text-align: center;
    font-size: 0.72rem;
    color: var(--m-ink-soft);
  }

  /* ---- sheet chrome: header, More toggle, sticky action bar ----
     These are mobile-only <td>s inside the row that becomes the sheet, so the
     sheet is one self-contained box - no floating siblings to collide with.
     The d-lg-none class removes them entirely from 992px up, and a
     display:none <td> takes part in no table layout, so the desktop
     grid is untouched. */

  .m-item-grid table.item-table td.m-sheet-head {
    order: 0;
    position: sticky;
    top: 0;
    z-index: 7;
    justify-content: space-between;
    width: 100%;
    /* explicit height so .m-sheet-actions can stick directly beneath it */
    height: 52px;
    min-height: 52px;
    margin: 0;
    padding: 0 14px !important;
    background: #fff;
    border-bottom: 0 !important;
    font-size: 1rem;
    font-weight: 700;
    color: var(--m-ink);
  }

  .m-item-grid table.item-table td.m-sheet-head::before { content: none; }

  .m-sheet-x {
    width: 36px;
    height: 36px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: #f1f3f6;
    color: var(--m-ink);
    font-size: 1.4rem;
    line-height: 1;
  }

  .m-item-grid table.item-table td.m-more-cell {
    order: 19;
    justify-content: flex-start;
    padding: 2px 0 !important;
  }

  .m-item-grid table.item-table td.m-more-cell::before { content: none; }

  .m-item-grid table.item-table td.m-more-cell .btn {
    padding: 0 !important;
    min-height: 36px;
    font-size: 0.78rem !important;
    font-weight: 600 !important;
    color: var(--m-accent) !important;
    text-decoration: none;
  }

  .m-item-grid table.item-table td.m-more-cell .btn i { margin-right: 6px; font-size: 0.7rem; }

  .m-item-grid table.item-table td.m-sheet-actions {
    /* Directly beneath the title, stuck to the top of the sheet's scroll
       area. This avoids every bottom-anchoring hazard at once: no vh vs
       dvh mismatch, no home-indicator overlap, and - critically - no
       dependence on `position: fixed`, which cannot reach the viewport
       from inside this sheet anyway (the entry animation leaves a
       transform on it, making it the containing block for fixed
       descendants - that is why the bar floated mid-screen). */
    order: 1;
    position: sticky;
    top: 52px;
    z-index: 6;
    gap: 10px;
    width: 100%;
    margin: 0 0 8px;
    padding: 8px 14px 10px !important;
    background: #fff;
    box-shadow: 0 6px 10px -6px rgba(16, 24, 40, 0.18);
    border-top: 0 !important;
    border-bottom: 1px solid var(--m-line) !important;
  }

  .m-item-grid table.item-table td.m-sheet-actions::before { content: none; }

  .m-item-grid table.item-table td.m-sheet-actions .btn {
    flex: 1 1 0;
    min-height: 48px;
    font-size: 0.9rem !important;
    font-weight: 600 !important;
    border-radius: 10px !important;
  }

  .m-item-grid table.item-table td.m-sheet-actions .btn-cancel {
    flex: 0 0 34%;
    background: #f1f3f6;
    color: var(--m-ink) !important;
  }

  /* the raw desktop "+" cell is replaced by the sticky Add item button */
  .m-item-grid table.item-table td.m-addbtn { display: none !important; }

  /* computed, read-only figures read as values, not as empty inputs */
  .m-item-grid table.item-table td[data-label="Total"] input,
  .m-item-grid table.item-table td[data-label="Taxable Amt"] input,
  .m-item-grid table.item-table td[data-label="Total Amount"] input {
    background: transparent;
    border: 0;
    padding-right: 0;
    font-weight: 600;
    color: var(--m-ink);
  }

  .m-item-grid table.item-table td[data-label="Total Amount"] input {
    font-size: 1.05rem;
    font-weight: 700;
  }

  @supports (max-height: 86dvh) {
    .m-item-grid.m-sheet-open > table.item-table > tbody > tr:not(.m-committed),
    .m-item-grid.m-sheet-open > table.item-table > tfoot > tr.selected_row {
      max-height: 86dvh;
    }
  }

  /* ---- sheet chrome: unconditional guarantees ----
     The open/closed rules above use child combinators
     (`> table.item-table > tbody > tr > td`), which depend on the exact
     nesting each form happens to use. Proforma proved that fragile: its
     chrome leaked into the page while the sheet was closed, and the header
     cell stayed a narrow table column instead of spanning the sheet. These
     two blocks use descendant selectors + !important so the outcome does not
     depend on any form's nesting. */

  /* 1. chrome always spans the sheet, never a narrow column */
  .m-item-grid table.item-table td.m-sheet-head,
  .m-item-grid table.item-table td.m-more-cell,
  .m-item-grid table.item-table td.m-sheet-actions {
    flex: 0 0 auto !important;
    width: 100% !important;
    min-width: 100% !important;
    max-width: 100% !important;
    box-sizing: border-box;
  }

  .m-item-grid table.item-table td.m-sheet-head > span {
    flex: 1 1 auto;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  /* 2. chrome exists only while the sheet is open */
  .m-item-grid:not(.m-sheet-open) table.item-table td.m-sheet-head,
  .m-item-grid:not(.m-sheet-open) table.item-table td.m-more-cell,
  .m-item-grid:not(.m-sheet-open) table.item-table td.m-sheet-actions {
    display: none !important;
  }

  /* 3. and the whole entry row collapses when closed, whatever its nesting */
  .m-item-grid:not(.m-sheet-open) table.item-table tfoot tr.selected_row {
    display: none !important;
  }

  .m-item-grid:not(.m-sheet-open) table.item-table tbody tr:not(.m-committed) > td:not(.m-cell-actions) {
    display: none !important;
  }

  /* ---- sheet chrome: final layout contract ----
     Two coupled problems came from pinning the header to a fixed 52px and
     sticking the action bar at `top: 52px`:
       * the header could not size to its content, so the title collapsed to a
         few characters and collided with the close button;
       * any drift in that 52px let scrolling fields slide under the buttons.
     The magic number is gone. The title scrolls away (it is only a label);
     the ACTION BAR is the one sticky element, pinned at top: 0 with an opaque
     background and a stacking level above every field. Nothing can overlap
     it and no offset has to be guessed. */

  .m-item-grid table.item-table td.m-sheet-head {
    position: static !important;
    order: 0 !important;
    height: auto !important;
    min-height: 48px !important;
    display: flex !important;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 12px 14px 10px !important;
  }

  .m-item-grid table.item-table td.m-sheet-head > span {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 1rem;
    font-weight: 700;
  }

  .m-item-grid table.item-table td.m-sheet-head .m-sheet-x {
    flex: 0 0 40px;
    width: 40px;
    height: 40px;
  }

  .m-item-grid table.item-table td.m-sheet-actions {
    position: sticky !important;
    top: 0 !important;
    bottom: auto !important;
    order: 1 !important;
    z-index: 30 !important;
    display: flex !important;
    background: #fff !important;
    box-shadow: 0 6px 10px -6px rgba(16, 24, 40, 0.25);
  }

  /* Every field sits below the sticky bar in the stacking order.

     `!important` is required, not decorative. The column-freeze neutraliser
     earlier in this file sets `position: static !important; z-index: auto
     !important` on every cell in the grid, and an important declaration beats
     a normal one whatever the specificity - so without it these two lose.

     What that costs is not subtle: `position: relative` here is what makes
     each field cell a STACKING CONTEXT, which traps the `z-index: 1210` given
     to select2 / ng-select just below. Lose the context and those controls
     escape to 1210 and paint straight over the sticky Cancel / Save item bar
     (z-index 30) - the item and variant pickers printing across the buttons. */
  .m-item-grid.m-sheet-open table.item-table tbody tr:not(.m-committed) > td:not(.m-sheet-actions):not(.m-sheet-head),
  .m-item-grid.m-sheet-open table.item-table tfoot tr.selected_row > td:not(.m-sheet-actions):not(.m-sheet-head) {
    position: relative !important;
    z-index: 0 !important;
  }

  /* select2 / ng-select popups must still clear the sticky bar */
  .m-item-grid table.item-table td .select2-container,
  .m-item-grid table.item-table td .ng-dropdown-panel {
    z-index: 1210;
  }

  /* ---- ng-autocomplete (the MRP field) ------------------------------------
     The library gives its panel `position: absolute` with NO `top`, so it
     lands at its static position - directly after `.input-container` in the
     flow. style.css then pins the container to a fixed
     `height: calc(2rem + 2px) !important` (~34px) for the desktop grid, while
     the sheet gives the input a 38-44px touch target. The input overflows its
     own container, the panel's static position is measured past it, and the
     list opens with a gap below the field.

     Anchoring the panel to the bottom of the container removes the guesswork,
     and the container is allowed to size to the input it holds. */
  .m-item-grid table.item-table td .autocomplete-container {
    position: relative !important;
    height: auto !important;
    min-height: 0 !important;
    box-shadow: none !important;
  }

  .m-item-grid table.item-table td .autocomplete-container .input-container input {
    height: auto !important;
    min-height: 38px;
    line-height: normal !important;
  }

  .m-item-grid table.item-table td .autocomplete-container .suggestions-container {
    top: 100% !important;
    left: 0;
    width: 100% !important;
    max-height: 44vh;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    z-index: 1215;
    border: 1px solid var(--m-line);
    border-radius: 0 0 8px 8px;
  }

  .m-item-grid table.item-table td .autocomplete-container .suggestions-container ul li a {
    padding: 11px 14px !important;
    font-size: 0.85rem;
  }

  /* Lift the cell that OWNS the panel above the fields that follow it.

     Unit and Attribute are select2, which appends its dropdown to <body> -
     it leaves the cell entirely, so nothing in the sheet can cover it. That
     is why those two behave and MRP does not: ng-autocomplete renders its
     `.suggestions-container` INSIDE the cell.

     Every field cell is a stacking context (`position: relative; z-index: 0`,
     which select2 needs so it cannot escape over the sticky bar), so the
     panel's own `z-index: 1215` is trapped inside the MRP cell's context.
     Quantity, Rate and Discount come later in DOM order at the same level and
     paint over it - the list showing through the gaps between them.

     5 clears the sibling fields; the sticky Cancel / Add item bar sits at 30,
     so the list still cannot cover the commit buttons. The panel scrolls with
     the field because it stays inside the cell - no repositioning on scroll
     is needed. */
  .m-item-grid.m-sheet-open table.item-table tbody tr:not(.m-committed)
    > td[data-label="MRP"]:not(.m-sheet-actions):not(.m-sheet-head),
  .m-item-grid.m-sheet-open table.item-table tfoot tr.selected_row
    > td[data-label="MRP"]:not(.m-sheet-actions):not(.m-sheet-head) {
    z-index: 5 !important;
  }

  /* ============ 3. totals row in <tfoot> ============ */

  .m-item-grid > table.item-table > tfoot > tr:not(.selected_row) {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 12px;
    width: 100%;
    margin: 4px 0 0;
    padding: 10px 12px;
    background: #f8fafc;
    border: 1px solid var(--m-line);
    border-radius: 12px;
  }

  .m-item-grid > table.item-table > tfoot > tr:not(.selected_row) > td {
    display: flex;
    align-items: center;
    gap: 6px;
    width: auto !important;
    min-width: 0 !important;
    padding: 0 !important;
    border: 0 !important;
    font-size: 0.8rem;
  }

  .m-item-grid > table.item-table > tfoot > tr:not(.selected_row) > td:empty {
    display: none !important;
  }

  /* `.item-table-responsive` is reused on containers that are NOT the item
     grid - the TDS/TCS table and the item rate-history table. They must keep
     horizontal scrolling; the sheet rules above are now scoped to
     `.m-item-grid` so they no longer strip it. */
  .item-table-responsive:not(.m-item-grid) {
    max-height: 52vh !important;
    overflow: auto !important;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
  }

  .item-table-responsive:not(.m-item-grid) > table {
    min-width: max-content;
  }

  .item-table-responsive:not(.m-item-grid) > table thead th {
    position: sticky;
    top: 0;
    z-index: 3;
    background: #e2e9eb !important;
    font-size: 0.72rem;
    white-space: nowrap;
  }

  .item-table-responsive:not(.m-item-grid) > table td {
    padding: 6px 8px !important;
    font-size: 0.8rem;
  }

  .item-table-responsive:not(.m-item-grid) > table td input,
  .item-table-responsive:not(.m-item-grid) > table td select {
    min-height: 38px;
    font-size: 16px;
  }

  /* TDS / TCS radio pair and its rate + remark fields */
  .modal .modal-body .custom-control.custom-radio {
    min-height: 38px;
    display: inline-flex;
    align-items: center;
    margin-right: 14px;
  }

  .modal .modal-body .labal_text {
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--m-ink-soft);
  }

  .modal .modal-body .value_text {
    font-variant-numeric: tabular-nums;
  }

  /* Grids that did NOT opt into stacking keep the horizontal scroller they
     have always had - stock transfer, process invoice, eway bill and friends
     share the `charge-table` class without sharing its column set. */
  .additional-item-table-responsive:not(.m-stack-wrap),
  .payment-table-responsive:not(.m-stack-wrap) {
    max-height: calc(100vh - var(--app-header-h) - 230px) !important;
    min-height: 160px;
    overflow: auto !important;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
  }

  table.charge-table:not(.m-stack-grid),
  table.trans-table:not(.m-stack-grid) {
    min-width: max-content;
  }

  table.charge-table:not(.m-stack-grid) thead th,
  table.trans-table:not(.m-stack-grid) thead th {
    position: sticky;
    top: 0;
    z-index: 3;
    background: #e2e9eb !important;
    font-size: 0.72rem;
    white-space: nowrap;
  }

  .additional-item-table-responsive:not(.m-stack-wrap)::-webkit-scrollbar:horizontal,
  .payment-table-responsive:not(.m-stack-wrap)::-webkit-scrollbar:horizontal {
    height: 14px;
  }

  /* input sizing applies to both stacked and scrolling grids */
  table.charge-table td input,
  table.trans-table td input,
  table.charge-table td select,
  table.trans-table td select {
    min-height: 38px;
    font-size: 16px;
  }

  /* ---- editable grids in EVERY other transaction form ----
     E-way Bill, E-Invoice, Receipt, Credit Note, Sale Return, Debit Note,
     Purchase Return, Challans ... all use `table.editable_tbl` (70 templates).
     Only the Sale item grid is converted to a bottom sheet; the rest stay real
     grids that pan horizontally, so they need the touch treatment here.
     The sheet's own rules are more specific, so they still win inside
     `.m-item-grid`. */
  .modal .table-responsive:not(.m-item-grid) {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
  }

  table.editable_tbl:not(.m-stack-grid):not(.m-settle-grid):not(.m-card-table):not(.m-list-compact) {
    min-width: max-content;
  }

  table.editable_tbl thead th {
    position: sticky;
    top: 0;
    z-index: 3;
    /* style.css sets `table.table1 th { background: none !important }`, which
       would let rows scroll through a transparent sticky header */
    background: #e2e9eb !important;
    font-size: 0.72rem;
    white-space: nowrap;
  }

  table.editable_tbl td {
    padding: 4px 6px !important;
    vertical-align: middle;
  }

  table.editable_tbl td input,
  table.editable_tbl td select,
  table.editable_tbl td textarea {
    min-height: 38px;
    font-size: 16px;          /* >=16px stops iOS zoom-on-focus */
  }

  table.editable_tbl td .ng-select .ng-select-container,
  table.editable_tbl td .select2-container .select2-selection--single {
    min-height: 38px !important;
    height: 38px !important;
  }

  /* keep the row's action column in view while panning right */
  table.editable_tbl tbody td.profile-pic1 {
    position: sticky;
    left: 0;
    z-index: 2;
    background: #fff;
    box-shadow: 1px 0 0 #dcdcdc;
  }

  table.editable_tbl tbody td.profile-pic1 a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 34px;
    min-height: 34px;
  }

  /* the same dormant-z-index trap as .enquiry-tag */
  table.editable_tbl .enquiry-tag {
    z-index: auto !important;
  }

  /* fatter scrollbar so it is clear these grids pan */
  .modal .table-responsive:not(.m-item-grid)::-webkit-scrollbar:horizontal {
    height: 14px;
  }

  .modal .table-responsive:not(.m-item-grid)::-webkit-scrollbar-thumb {
    background: #b6bfc9;
    border-radius: 7px;
  }

  /* ---- entry-form footer ---- */

  .modal .modal-footer.footer-fixed {
    position: relative;
    width: auto;
  }

  .modal .modal-footer.footer_modal_form {
    background: #e2e9eb;
  }

  /* ---- stray desktop affordances ----
     `.moveRight` is a chevron that nudges a horizontally-scrolling grid to the
     right; styleMobile.css force-shows it below 960px. The item grid is now a
     sheet and the charge/payment grids pan by touch, so it is dead weight that
     renders as a lone ">" floating in the form. */
  .moveRight {
    display: none !important;
  }

  /* The entry dialogs repeat Save/Close in a bottom .modal-footer. On mobile
     the m-dialog-bar already carries SAVE / SAVE + ADD / MORE at the top, so
     the footer is a duplicate that eats a row of screen. Scoped by sibling so
     only dialogs that actually have the mobile bar lose their footer. */
  .m-dialog-bar ~ .modal-footer {
    display: none !important;
  }

  /* ---- remaining entry-form panels ----
     Attachments, Additional Charges, Other Income/Discounts, Payment Details,
     Bank Details and the collapsible panels all sit in the same .form-row /
     .card / .btn vocabulary, so they are handled together here rather than one
     screenshot at a time. */

  /* Wide action buttons (e.g. "Add Or View Attachements") were clipping: they
     are laid out inline with a fa-2x icon and a long label that cannot wrap. */
  .modal .modal-body > form > .form-row > .btn,
  .modal .modal-body .form-row > .btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    min-height: 46px;
    margin: 4px 0;
    padding: 8px 12px !important;
    font-size: 0.85rem !important;
    line-height: 1.2;
    white-space: normal;
    overflow-wrap: break-word;
    border-radius: 10px !important;
  }

  .modal .modal-body .form-row > .btn .fa-2x {
    font-size: 1.1em;
    margin-right: 8px !important;
  }

  .modal .modal-body .form-row > .btn .align-text-bottom {
    vertical-align: middle;
  }

  /* Collapsible section headers (Other Income/Discounts & Debits, etc.) */
  .modal .modal-body [data-toggle="collapse"],
  .modal .modal-body .card-header[data-toggle="collapse"] {
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: var(--m-tap);
    font-size: 0.88rem;
  }

  /* Panels: full width, no desktop side gutters, comfortable spacing */
  .modal .modal-body > form > .form-row > [class*="col-"],
  .modal .modal-body .card > .form-row > [class*="col-"],
  .modal .modal-body .card-body > .form-row > [class*="col-"] {
    padding-left: 0;
    padding-right: 0;
  }

  .modal .modal-body .card {
    border-radius: 10px;
    margin-bottom: 10px;
  }

  .modal .modal-body .card-body {
    padding: 10px;
  }

  /* Any leftover fixed pixel widths inside the dialog body would force the
     whole sheet to scroll sideways. */
  .modal .modal-body [style*="width: 800px"],
  .modal .modal-body [style*="min-width: 800px"],
  .modal .modal-body .min_width_350,
  .modal .modal-body .w-1000 {
    min-width: 0 !important;
    width: auto !important;
  }

  /* Totals / summary blocks read as label-value rows rather than a grid. */
  .modal .modal-body .highlight_box2 {
    padding: 10px !important;
  }

  /* Inline pixel widths scattered through the entry-form body (550px, 400px,
     250px !important, 200px !important, 180px, 100px ...) each force the sheet
     or the dialog to scroll sideways. Neutralised wholesale on mobile; the two
     that carry !important need !important back to beat them. Desktop keeps
     every one of them because this block is inside the mobile media query. */
  .modal .modal-body [style*="width:"],
  .modal .modal-body [style*="width :"],
  .modal .modal-body [style*="min-width:"] {
    max-width: 100% !important;
  }

  .modal .modal-body [style*="width: 550px"],
  .modal .modal-body [style*="width: 400px"],
  .modal .modal-body [style*="width: 250px"],
  .modal .modal-body [style*="width: 200px"],
  .modal .modal-body [style*="min-width:180px"],
  .modal .modal-body [style*="min-width: 180px"] {
    width: auto !important;
    min-width: 0 !important;
  }

  /* Negative top offsets used to tuck controls under desktop labels leave
     things overlapping once fields stack. */
  .modal .modal-body [style*="margin-top: -1"],
  .modal .modal-body [style*="margin-top:-1"] {
    margin-top: 0 !important;
  }

  /* Absolutely-positioned helper controls re-join the flow. */
  .modal .modal-body [style*="position:absolute"][style*="width"],
  .modal .modal-body [style*="position: absolute"][style*="width"] {
    position: static !important;
  }

  /* ---- collapsible sub-sections inside the entry forms ----
     Transport Details / Referral Details / Commercial Terms use
     `<h5>Title <i class="fa-angle-up" data-toggle="collapse"></i></h5>`.
     The chevron is a plain inline <i> straight after the text, so it drifts
     with the heading as the text reflows - which is the "toggle jumps from
     left to right" behaviour. Make the heading a real header row: title left,
     chevron pinned right, whole strip a 44px target. */
  .modal .modal-body h5[class$="DetailHeading"],
  .modal .modal-body h5[class$="Heading"],
  .modal .modal-body .TransportDetailHeading,
  .modal .modal-body .ReferralDetailHeading {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    width: 100%;
    min-height: var(--m-tap);
    margin: 10px 0 6px;
    padding: 6px 10px;
    background: #f4f6fa;
    border: 1px solid var(--m-line);
    border-radius: 10px;
    font-size: 0.88rem;
    font-weight: 700;
    color: var(--m-ink);
  }

  .modal .modal-body h5[class$="Heading"] > i,
  .modal .modal-body .TransportDetailHeading > i,
  .modal .modal-body .ReferralDetailHeading > i {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    margin: 0;
    border-radius: 8px;
    background: #fff;
    color: var(--m-accent);
    font-size: 0.85rem;
  }

  /* An element that is both a flex container (.form-row) and a collapse target
     must stay a flex container once Bootstrap reveals it, or its fields lose
     their wrapping and misalign. */
  .modal .modal-body .form-row.collapse.show,
  .modal .modal-body .form-row.collapsing {
    display: flex !important;
    flex-wrap: wrap;
    width: 100%;
    margin-left: 0;
    margin-right: 0;
  }

  .modal .modal-body .form-row.collapse > [class*="col-"],
  .modal .modal-body .form-row.collapsing > [class*="col-"] {
    flex: 1 1 100%;
    max-width: 100%;
    padding-left: 0;
    padding-right: 0;
  }

  /* ---- dynamic / custom property fields ----
     Generated at runtime, so they carry no layout classes of their own and
     inherit whatever desktop grid the host used. */
  .modal .modal-body app-dynamic-attributes .form-row > [class*="col-"],
  .modal .modal-body [class*="dynamic"] .form-row > [class*="col-"],
  .modal .modal-body [class*="custom-field"] .form-row > [class*="col-"],
  .modal .modal-body [class*="DynamicProperties"] [class*="col-"] {
    flex: 1 1 100% !important;
    max-width: 100% !important;
    padding-left: 0;
    padding-right: 0;
  }

  .modal .modal-body app-dynamic-attributes .form-control,
  .modal .modal-body [class*="dynamic"] .form-control {
    min-height: 42px;
    font-size: 16px;
  }

  /* ==========================================================================
     4. DIALOGS  (applies app-wide, mobile only)
     --------------------------------------------------------------------------
     The app ships ~246 Bootstrap/MDB dialogs in a handful of desktop variants:
       .modal-dialog                              (plain / .modal-md / .modal-lg)
       .modal-dialog.large_form.modal-full-height.modal-top
       .modal-dialog.modal-full-height.modal-right[.half-right-N]
     On a phone every one of them should be the same thing: a full-screen sheet
     with a sticky header, a scrolling body and a sticky footer. Rather than
     tag 246 templates, all variants are normalised here. Desktop is untouched
     because this whole file is inside the mobile media query.

     `.m-sheet` opts a dialog out of full-screen and into a bottom sheet
     (used for the promo carousel, which is media-only).
     ========================================================================== */

  .modal:not(.m-sheet) .modal-dialog {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100% !important;
    min-width: 0 !important;
    max-width: 100% !important;
    height: 100% !important;
    max-height: 100% !important;
    margin: 0 !important;
    padding: 0 !important;
  }

  /* `height: 100%` resolves against the LAYOUT viewport, which on mobile is
     taller than the visible area while the URL bar is showing - so the foot of
     the dialog (and the last thing in the scrolling body, e.g. the Attachments
     button) sits below the fold and cannot be reached. dvh tracks the visible
     viewport. */
  @supports (height: 100dvh) {
    .modal:not(.m-sheet) .modal-dialog,
    .modal:not(.m-sheet) .modal-content {
      height: 100dvh !important;
      max-height: 100dvh !important;
    }
  }

  /* The three width classes extracted from unoverridable inline !important
     styles (see the tail of style.css). Higher specificity than those rules
     so the outcome does not depend on stylesheet order. */
  .modal:not(.m-sheet) .modal-dialog.dlg-w30,
  .modal:not(.m-sheet) .modal-dialog.dlg-w50,
  .modal:not(.m-sheet) .modal-dialog.dlg-mw400 {
    width: 100% !important;
    max-width: 100% !important;
  }

  .modal:not(.m-sheet) .modal-content {
    display: flex;
    flex-direction: column;
    height: 100% !important;
    max-height: 100% !important;
    width: 100% !important;
    margin: 0 !important;
    border: 0;
    border-radius: 0 !important;
    overflow: hidden;
  }

  /* Most dialogs put .modal-header / .modal-body / .modal-footer straight
     inside .modal-content, so the body is a flex ITEM and its
     `flex: 1 1 auto; min-height: 0; overflow-y: auto` has something to scroll
     inside. 58 dialogs wrap those three in a <form> instead (either the whole
     set, or just body+footer with the header outside).

     A block-level <form> is `height: auto`, which breaks the chain: the body
     is no longer a flex item, so its flex sizing is ignored, it grows to its
     full content height, and .modal-content's `overflow: hidden` CLIPS
     everything past the fold - the dialog will not scroll at all and the
     fields below the first screen are unreachable.

     Letting the form join the column restores it. Any nested <form> deeper in
     the tree is untouched - this is a direct-child selector. */
  .modal:not(.m-sheet) .modal-content > form {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    max-height: 100%;
  }

  /* --- bottom-sheet variant --- */
  .modal.m-sheet .modal-dialog {
    position: fixed;
    top: auto;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100% !important;
    max-width: 100% !important;
    max-height: 92vh;
    margin: 0 !important;
    padding: 0 !important;
  }

  .modal.m-sheet .modal-content {
    display: flex;
    flex-direction: column;
    max-height: 92vh;
    border: 0;
    border-radius: 18px 18px 0 0;
    overflow: hidden;
    box-shadow: 0 -10px 40px rgba(16, 24, 40, 0.28);
  }

  /* Grab handle */
  .modal.m-sheet .modal-content::before {
    content: "";
    position: absolute;
    top: 8px;
    left: 50%;
    transform: translateX(-50%);
    width: 38px;
    height: 4px;
    border-radius: 2px;
    background: #d1d5db;
    z-index: 2;
  }

  /* Media-only sheets (no header/footer chrome) skip the grab handle. */
  .modal.m-sheet.m-sheet--bare .modal-content::before {
    content: none;
  }

  .modal.m-sheet .modal-header {
    padding-top: 20px;
  }

  /* --- shared dialog chrome --- */
  .modal .modal-header {
    flex: 0 0 auto;
    /* `relative` anchors the pinned close button below. */
    position: relative;
    z-index: 3;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    min-height: 54px;
    /* right gutter reserves the close button's corner */
    padding: 8px 52px 8px 14px !important;
    background: var(--m-surface);
    border-bottom: 1px solid var(--m-line);
  }

  .modal .modal-header .modal-title,
  .modal .modal-header h4,
  .modal .modal-header h5 {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
    font-size: 1rem !important;
    line-height: 1.3;
    text-align: left;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  /* CLOSE BUTTON — pinned to the header's top-right corner.
     In the transaction forms the close sits at the END of `.btn_header`,
     which is a `justify-content: flex-end` flex row. As soon as the action
     buttons stop fitting, the close is the first thing pushed off the right
     edge — leaving no way to dismiss a full-screen dialog. Taking it out of
     flow guarantees it is always visible and always tappable.
     Competing rules neutralised here: `.close_popup .close` (top:-8px,
     2.3rem) and `.large_form .modal-header .close` (font-size:53px). */
  .modal .modal-header .close,
  .modal .modal-header .btn_header > button.close {
    position: absolute !important;
    top: 6px !important;
    right: 6px !important;
    left: auto !important;
    bottom: auto !important;
    z-index: 6;
    flex: 0 0 auto;
    width: 42px !important;
    height: 42px !important;
    min-width: 42px !important;
    min-height: 42px !important;
    max-width: 42px !important;
    margin: 0 !important;
    padding: 0 !important;
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    font-size: 1.7rem !important;
    line-height: 1 !important;
    border-radius: 50%;
    opacity: 1;
  }

  .modal .modal-header .close > span {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    line-height: 1;
  }

  /* On the blue transaction-form headers give it a subtle scrim so the glyph
     never disappears against the background. */
  .modal .modal-header.primary-bg .close {
    color: #fff !important;
    background: rgba(255, 255, 255, 0.18);
  }

  .modal .modal-header.close_popup h4 {
    top: 0;
    background: none;
  }

  /* `.large_form` blows the close glyph up to 40-53px on desktop. */
  .modal .large_form .modal-header .close {
    font-size: 1.8rem !important;
    position: static;
  }

  .modal .modal-body {
    flex: 1 1 auto;
    min-height: 0 !important;
    /* style.css pins this to calc(100vh - 100px) globally, which fights the
       flex column and double-scrolls. */
    max-height: none !important;
    overflow-y: auto !important;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    /* Trailing clearance so the LAST control in the body can always be
       scrolled clear of the browser chrome / home indicator. Without
       this the final element sits flush against the fold. */
    padding: 14px var(--m-gutter) calc(96px + env(safe-area-inset-bottom, 0px)) !important;
  }

  .modal .modal-body > .card-body,
  .modal .modal-body > .card > .card-body {
    padding: 0;
  }

  /* `relative`, not `sticky`: in a fixed-height flex column the footer is
     already outside the scrolling body, so it is permanently visible. Sticky
     only added a stacking context that could overlay the form. This also
     overrides `.footer-fixed { position: fixed; width: 100% }`, which would
     otherwise escape the dialog now that the dialog is full-screen. */
  .modal .modal-footer {
    flex: 0 0 auto;
    position: relative;
    bottom: auto;
    z-index: 3;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    justify-content: flex-end;
    padding: 10px var(--m-gutter) calc(10px + var(--m-safe-bottom)) !important;
    margin: 0;
    background: var(--m-surface);
    border-top: 1px solid var(--m-line);
  }

  .modal .modal-footer > .btn,
  .modal .modal-footer > button {
    flex: 1 1 0;
    min-width: 110px;
    min-height: var(--m-tap);
    margin: 0 !important;
    border-radius: 10px !important;
  }

  /* Some dialogs put the pager in the footer — it needs the whole row. */
  .modal .modal-footer > app-pagination,
  .modal .modal-footer > .row {
    flex: 1 1 100%;
    width: 100%;
    margin: 0;
  }

  /* Entry animation. Bootstrap's own `.modal.fade .modal-dialog` slides in
     from -25% on the Y axis; neutralise it so the two do not compound. */
  .modal.fade .modal-dialog {
    transform: none;
    transition: none;
  }

  /* `backwards`, NOT `both`.

     `both` retains the last keyframe forever, so `transform: translateY(0)`
     stays applied after the animation ends. A transform other than `none`
     makes the element the containing block for `position: fixed` descendants
     AND a new stacking context - so every fixed child inside a dialog (the
     item sheet, its backdrop) resolved against the dialog instead of the
     viewport, and select2's body-appended dropdown computed page coordinates
     that no longer matched where the field actually was. That is the MRP list
     appearing three rows further down, over the Discount and Taxable rows.

     `backwards` applies the FROM state before the animation and releases the
     element afterwards. The final keyframe is `translateY(0); opacity: 1`,
     i.e. the element's natural state, so nothing changes visually. */
  .modal.show .modal-dialog {
    animation: mSheetIn 0.28s var(--m-ease) backwards;
  }

  @keyframes mSheetIn {
    from { transform: translateY(12%); opacity: 0.5; }
    to   { transform: translateY(0);   opacity: 1;   }
  }

  /* Forms inside dialogs: `.col`/`.col-sm-*` do not stack on their own. */
  .modal .form-row > [class*="col-"],
  .modal .form.row > [class*="col-"] {
    padding-left: 0;
    padding-right: 0;
  }

  .modal .form-group {
    margin-bottom: 12px;
  }

  /* Tables inside dialogs keep horizontal scroll rather than being squashed -
     but never the ones that have been converted to cards. */
  .modal table:not(.m-card-table):not(.m-stack-grid):not(.m-settle-grid):not(.m-list-compact) {
    min-width: max-content;
  }

  .modal .form-row > .table-responsive,
  .modal .table-responsive {
    width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }

  /* Belt and braces: the final row of any dialog form gets its own breathing
     room, so a trailing full-width action (Attachments, Add Row, ...) is never
     the element that gets cut. */
  .modal .modal-body > form > .form-row:last-child,
  .modal .modal-body > form > div:last-child,
  .modal .modal-body > div:last-child {
    margin-bottom: 24px;
  }

  /* ==========================================================================
     5. SHARED MOBILE UTILITIES
     ========================================================================== */

  /* Row-as-card table: <td> carries data-label, header is hidden.
     Opt-in per table via .m-card-table — no effect on any other table. */
  /* `min-width: 0` is the important one here.

     style.css sizes the wide report tables for the desktop grid with
     `.fixTable0 { min-width: 5000px !important }` down through
     `.fixTable6 { min-width: 1000px !important }`. Setting `width: 100%`
     does NOT beat a min-width - the box simply takes the larger of the two.

     All ITC is `fixTable6 m-card-table`, so its "cards" were laid out 1000px
     wide inside a ~400px screen. Everything followed from that: the page
     scrolled sideways, each card's content sat off to the right (which is why
     the rows looked like bare lines), and the Eligibility Status field was
     roughly 900px along - so select2, positioning its panel from that field's
     real coordinates, opened it far off the right edge, detached and clipped.

     The other card layouts already reset this (`.m-list-compact` and the
     doubled-class `.m-stack-charge` shell); `m-card-table` was the one that
     did not. */
  .m-card-table,
  .m-card-table tbody,
  .m-card-table tr,
  .m-card-table td {
    display: block;
    width: 100% !important;
    min-width: 0 !important;
    max-width: 100% !important;
  }

  .m-card-table thead {
    display: none;
  }

  .m-card-table tr {
    background: var(--m-surface);
    border: 1px solid var(--m-line);
    border-radius: var(--m-radius);
    padding: 6px 12px;
    margin-bottom: 10px;
    box-shadow: 0 1px 2px rgba(16, 24, 40, 0.05);
  }

  .m-card-table td {
    display: flex !important;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    padding: 7px 0 !important;
    border: 0 !important;
    border-bottom: 1px solid #f3f4f6 !important;
    text-align: right;
    font-size: 0.82rem;
    word-break: break-word;
  }

  .m-card-table td:last-child {
    border-bottom: 0 !important;
  }

  .m-card-table td::before {
    content: attr(data-label);
    flex: 0 0 40%;
    text-align: left;
    font-weight: 600;
    color: var(--m-ink-soft);
    font-size: 0.74rem;
    text-transform: uppercase;
    letter-spacing: 0.02em;
  }

  /* Cells with no label (e.g. an action row) span the full width. */
  .m-card-table td[data-label=""]::before {
    content: none;
  }

  /* ---- editable cells inside a card ---------------------------------------
     `m-card-table` was written for read-only reports, so it never sized the
     controls inside a cell. All ITC is not read-only: every row carries an
     Eligibility Status picker. select2 sizes its container from the original
     table cell, which in a card is meaningless - the closed control came out
     as a stub jammed against its label, and the open panel inherited that
     width.

     The label keeps its 40%; the control takes the rest of the row. */
  .m-card-table td > .select2,
  .m-card-table td > select2,
  .m-card-table td .select2-container,
  .m-card-table td .ng-select,
  .m-card-table td .input-group,
  .m-card-table td > select,
  .m-card-table td > input,
  .m-card-table td > textarea,
  .m-card-table td > .form-control {
    flex: 1 1 auto;
    width: 100% !important;
    min-width: 0 !important;
    max-width: 100% !important;
  }

  /* a picker in a card is a tap target, not a table cell */
  .m-card-table td .select2-container .select2-selection--single {
    height: 40px !important;
    border-radius: 8px;
  }

  .m-card-table td .select2-container .select2-selection--single .select2-selection__rendered {
    line-height: 38px !important;
    font-size: 0.85rem;
  }

  .m-card-table td .select2-container .select2-selection--single .select2-selection__arrow {
    height: 38px !important;
  }


  /* A 13-column report prints 13 rows per card, and roughly half of them are
     routinely blank (a settlement is Cr or Dr, never both). An empty cell adds
     a label and a divider and says nothing, so it is dropped - the card then
     shows only the fields this particular row actually has. */
  .m-card-table td:empty {
    display: none !important;
  }

  /* denser than a data-entry card: a report is read, not filled in */
  .m-card-table tr {
    padding: 4px 10px;
    margin-bottom: 8px;
  }

  .m-card-table td {
    padding: 5px 0 !important;
    font-size: 0.8rem;
  }

  .m-card-table td::before {
    font-size: 0.68rem;
  }

  /* The desktop <tfoot> is one <th> per column, so a 13-column report footer
     rendered as a run of bare numbers. Same treatment as the card body: only
     labelled figures survive, each announced by its label. */
  .m-card-table > tfoot,
  .m-card-table > tfoot > tr {
    display: block;
    width: 100% !important;
  }

  .m-card-table > tfoot > tr {
    padding: 8px 12px;
    border-top: 2px solid var(--m-line);
    font-size: 0.82rem;
    font-weight: 700;
  }

  .m-card-table > tfoot > tr > th {
    display: flex !important;
    justify-content: space-between;
    padding: 3px 0 !important;
    border: 0 !important;
  }

  .m-card-table > tfoot > tr > th:not([data-label]) {
    display: none !important;
  }

  .m-card-table > tfoot > tr > th[data-label]::before {
    content: attr(data-label);
    font-weight: 500;
    text-transform: uppercase;
    font-size: 0.72rem;
    color: var(--m-ink-soft);
  }

  /* `.m-card-table` rows can opt into a compact summary: cells marked .m-adv
     collapse behind the row's own disclosure, .m-sum stay on the face. Used by
     the Sale list, whose 13 desktop columns are unreadable even when scrolled. */
  .m-card-table td.m-adv {
    display: none !important;
  }

  .m-card-table tr:target td.m-adv,
  .m-card-table tr.m-expanded td.m-adv {
    display: flex !important;
  }

  .m-card-table td.m-primary {
    font-weight: 700;
    font-size: 0.9rem;
  }

  .m-card-table td.m-primary::before {
    font-weight: 600;
  }

  /* `w-1000` pins list tables to 1000px below 960px in styleMobile.css. */
  .m-card-table.w-1000 {
    width: 100% !important;
    min-width: 0 !important;
  }

  /* ---- .m-list-compact : dense two-line record rows ----
     For list screens whose desktop table has too many columns to scroll and
     too many fields to render one-per-line. Each record becomes a fixed
     two-line grid, ~62px tall instead of ~200px, so 9-10 records fit a phone
     screen instead of 2-3.

         ┌────────────────────────────────────────────┐
         │ INV-0012   ABC Traders Pvt Ltd        ⚙    │
         │ 12-07-2026                     12,500.00   │
         └────────────────────────────────────────────┘

     Placement is driven by `data-label`, so the DOM/column order is untouched
     and the desktop table is unaffected. Cells not placed below are hidden. */

  .m-list-compact,
  .m-list-compact > tbody {
    display: block;
    width: 100% !important;
    min-width: 0 !important;
    border: 1px solid var(--m-line);
    border-radius: 12px;
    overflow: hidden;
    background: #fff;
  }

  .m-list-compact > thead {
    display: none;
  }

  .m-list-compact > tbody {
    border: 0;
    border-radius: 0;
  }

  .m-list-compact > tbody > tr {
    display: grid;
    /* the action column takes what it needs: master lists put Edit AND
       Delete there, which overflowed a fixed 44px and drifted apart.
       Column 1 is `minmax(0, auto)`, not `auto`: an unplaced cell landing
       there must be allowed to shrink and ellipse rather than size the track
       to its max-content and shove the action off the row. */
    grid-template-columns: minmax(0, auto) minmax(0, 1fr) minmax(44px, auto);
    align-items: center;
    column-gap: 8px;
    row-gap: 1px;
    width: 100%;
    padding: 8px 4px 8px 12px;
    /* hairline divider rather than a card per record - denser and calmer */
    border-bottom: 1px solid #eef0f3;
  }

  .m-list-compact > tbody > tr:last-child {
    border-bottom: 0;
  }

  .m-list-compact > tbody > tr > td {
    display: block;
    width: auto !important;
    min-width: 0 !important;
    max-width: none !important;
    padding: 0 !important;
    border: 0 !important;
    font-size: 0.82rem;
    line-height: 1.35;
    text-align: left;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
  }

  /* no field labels - the layout carries the meaning */
  .m-list-compact > tbody > tr > td::before {
    content: none !important;
  }

  /* anything not explicitly placed is off the compact face */
  .m-list-compact > tbody > tr > td:not(.m-sum) {
    display: none !important;
  }

  /* line 1, col 1 - the record's identifier */
  .m-list-compact td[data-label="Invoice No."],
  .m-list-compact td[data-label="Challan No."],
  .m-list-compact td[data-label="Note No."],
  .m-list-compact td[data-label="Order No."],
  .m-list-compact td[data-label="Quotation No."],
  .m-list-compact td[data-label="Bill No."] {
    grid-column: 1;
    grid-row: 1;
    font-weight: 700;
    color: var(--m-accent);
  }

  /* line 1, col 2 - party name, truncates */
  .m-list-compact td[data-label="Party"] {
    grid-column: 2;
    grid-row: 1;
    font-weight: 600;
    color: var(--m-ink);
  }

  /* line 2, col 1 - date, de-emphasised */
  .m-list-compact td[data-label="Date"] {
    grid-column: 1;
    grid-row: 2;
    font-size: 0.72rem;
    color: var(--m-ink-soft);
  }

  /* Some lists (Purchase, Purchase Challan) pack number + date + a status
     badge into ONE cell separated by <br>, so there is no separate "Date"
     column to place. `.m-id-stack` lets that single cell own col 1 across
     both lines instead of being squashed into line 1. */
  .m-list-compact td.m-id-stack {
    grid-column: 1;
    grid-row: 1 / span 2;
    align-self: center;
    white-space: normal !important;
    line-height: 1.25;
    font-weight: 700;
    color: var(--m-accent);
  }

  /* the date/status that follow the <br> read as secondary */
  .m-list-compact td.m-id-stack > div,
  .m-list-compact td.m-id-stack > span {
    font-size: 0.7rem;
    font-weight: 500;
    color: var(--m-ink-soft);
  }

  /* line 2, col 2 - amount, right-aligned and prominent.
     `m-face-amount` is the opt-in for reports whose headline figure is not
     called "Bill Amt" (Party Proforma Summary leads on Total Outstanding).
     Marking the cell beats relabelling it, which would make the template lie
     about what the column holds. */
  .m-list-compact td[data-label="Bill Amt"],
  .m-list-compact td[data-label="Bill Amount"],
  .m-list-compact td.m-face-amount {
    grid-column: 2;
    grid-row: 2;
    text-align: right;
    font-weight: 700;
    font-size: 0.88rem;
    color: var(--m-ink);
  }

  /* Status pill rides beside the amount on line 2 where a list has one. */
  .m-list-compact td[data-label="Status"] {
    grid-column: 1;
    grid-row: 2;
    justify-self: start;
    margin-left: 8px;
  }

  .m-list-compact td[data-label="Status"] .status-open,
  .m-list-compact td[data-label="Status"] .badge,
  .m-list-compact td[data-label="Status"] span {
    display: inline-block;
    padding: 1px 8px;
    border-radius: 50rem;
    font-size: 0.66rem;
    font-weight: 600;
    line-height: 1.5;
  }

  /* Lists whose identifier cell carries "No.<br>Date" need line 2 free. */
  .m-list-compact td[data-label="Invoice No."] br {
    display: none;
  }

  .m-list-compact td[data-label="Invoice No."] {
    display: flex !important;
    align-items: baseline;
    gap: 6px;
  }

  /* Lists with no money column (challans, orders) put their state here
     instead - same slot, so the face still reads identifier/party/date/X. */
  .m-list-compact td[data-label="Status"] {
    grid-column: 2;
    grid-row: 2;
    text-align: right;
    font-size: 0.72rem;
    white-space: normal !important;
  }

  /* the status pill itself must not stretch to the cell width */
  .m-list-compact td[data-label="Status"] > div {
    display: inline-block;
  }

  /* Lists that allow bulk selection (challan -> bill) keep the checkbox
     reachable: it takes col 3 line 1 and the action menu drops to line 2.
     Without `.m-has-select` the action stays spanning both lines. */
  .m-list-compact td.m-select-cell {
    grid-column: 3;
    grid-row: 1;
    display: flex !important;
    align-items: center;
    justify-content: center;
    min-height: 32px;
  }

  .m-list-compact.m-has-select td[data-label="Action"] {
    grid-row: 2;
  }

  /* Three controls, two slots. The Lead list carries a bulk-select checkbox,
     a one-tap "add follow-up" shortcut AND the cog menu - and the shortcut is
     not repeated inside the menu, so it cannot simply be dropped. They stack
     down the action column instead: select, shortcut, menu. The face keeps
     lines 1-2 (name, status) and the card grows by one short row. */
  .m-list-compact.m-actions-stack td.m-quick-cell {
    grid-column: 3;
    grid-row: 2;
    display: flex !important;
    align-items: center;
    justify-content: center;
  }

  .m-list-compact.m-has-select.m-actions-stack td[data-label="Action"] {
    grid-row: 3;
  }

  .m-list-compact.m-actions-stack td.m-quick-cell > a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: 8px;
    background: #f4f6fa;
  }

  /* Master lists have no party or invoice number - the item name is the whole
     identity, so it takes line 1 across both columns and the classifiers sit
     underneath it. */
  /* `:not([data-label="Party"])` is the whole point of this exclusion.

     A MASTER list has one identity - "Bank Name", "Ledger Name" - and it
     should span both columns of line 1. A TRANSACTION list has TWO things on
     line 1: the document number in column 1 and the party in column 2. Those
     cells are marked `m-primary m-sum data-label="Party"`, so a blanket
     `.m-primary { grid-column: 1 / span 2 }` put the party on top of the
     document number - 19 transaction lists drew the number, the date and the
     status badge stacked over each other. Party keeps its own rule above
     (column 2, line 1); only an unplaced face cell spans. */
  .m-list-compact td[data-label="Item"],
  .m-list-compact td.m-primary:not([data-label="Party"]) {
    grid-column: 1 / span 2;
    grid-row: 1;
    min-width: 0;
    font-weight: 600;
    color: var(--m-ink);
  }

  /* `.m-primary` matters as much as the `[data-label="Item"]` case above, and
     for a while only that one was handled. Placement here is driven by
     data-label against a fixed vocabulary (Invoice No. / Party / Date / Item /
     Category / MRP / Status / Action), and a master list's face column is
     named for its own entity - "Bank Name", "Ledger", "Discount Type". None of
     those match, so the cell fell to AUTO-PLACEMENT in column 1, an `auto`
     track that sizes to max-content: a long value like
     "ICICI Jaipur-1122334455667788" set the track to the full string instead
     of ellipsing, which pushed the action column past the end of the row where
     `overflow: hidden` cut it off. Spanning the flexible track fixes the track
     sizing at source - a spanning item contributes to the `1fr`, so column 1
     collapses and the name truncates.

     The classifiers that follow the name drop to line 2 as secondary text. The
     `~` keeps this to lists that HAVE a `.m-primary` face, so the transaction
     lists - whose cells are all placed explicitly by label - are untouched. */
  /* Again keyed on "is this a master list?". On a TRANSACTION list the cells
     after the face are Date / Status / Bill Amt / the document number, each
     with its own placement - and this selector outranks all of them
     (five class-level components against two), so it was dragging the
     document number down onto line 2 on top of the date and the status
     badge. Restricting it to a NON-Party face means it never matches a
     transaction list at all. */
  .m-list-compact td.m-primary:not([data-label="Party"]) ~ td.m-sum:not([data-label="Action"]):not(.m-select-cell) {
    grid-row: 2;
    min-width: 0;
    font-size: 0.72rem;
    color: var(--m-ink-soft);
  }

  .m-list-compact td[data-label="Category"] {
    grid-column: 1;
    grid-row: 2;
    font-size: 0.72rem;
    color: var(--m-ink-soft);
  }

  .m-list-compact td[data-label="MRP"] {
    grid-column: 2;
    grid-row: 2;
    text-align: right;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
  }

  /* the blanket `td::before { content: none !important }` above needs beating */
  .m-list-compact td[data-label="MRP"]:not(:empty)::before {
    content: "MRP " !important;
    font-weight: 500;
    font-size: 0.68rem;
    color: var(--m-ink-soft);
  }

  /* col 3 - action, spanning both lines, one consistent 44px target */
  .m-list-compact td[data-label="Action"] {
    grid-column: 3;
    grid-row: 1 / span 2;
    display: flex !important;
    align-items: center;
    justify-content: center;
    align-self: stretch;
    text-align: center !important;
  }

  .m-list-compact td[data-label="Action"] .dropdown {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
  }

  .m-list-compact td[data-label="Action"] .dropdown-toggle {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    margin: 0;
    padding: 0;
    border-radius: 8px;
    background: #f4f6fa;
    color: var(--m-ink-soft);
  }

  /* the desktop caret doubles the glyph width and misaligns the cog */
  .m-list-compact td[data-label="Action"] .dropdown-toggle .caret,
  .m-list-compact td[data-label="Action"] .dropdown-toggle::after {
    display: none !important;
  }

  .m-list-compact td[data-label="Action"] .dropdown-toggle i {
    margin: 0 !important;
    font-size: 15px !important;
    line-height: 1;
  }

  /* `.enquiry-tag { position: static; z-index: 999999 }` in style.css is inert
     on desktop - z-index does nothing on a static, non-flex element. Making
     the action cell a flex container promotes it to a FLEX ITEM, where
     z-index DOES apply even while static, so the cog started painting over
     the fixed app header (z-index 1010). Stand it back down. */
  .m-list-compact td[data-label="Action"] .enquiry-tag,
  .m-list-compact td[data-label="Action"] .dropdown {
    z-index: auto !important;
  }

  /* same trap anywhere else a flex row contains one of these action wrappers */
  .modal .enquiry-tag,
  table.cat-table .enquiry-tag {
    z-index: auto !important;
  }

  /* ---- row action menu -> bottom sheet ----
     The Sale row menu carries up to 11 actions; an anchored dropdown cannot
     fit them on a phone at any position. Two overrides are load-bearing:
       * Popper writes `position: absolute` + `transform: translate3d(...)`
         inline, so every positioning property needs !important to win;
       * the items are `<a class="d-b">`, and Bootstrap's `.d-b` is
         `display: block !important`, which silently beat a plain
         `display: flex` - that is why the icon sat under the label. */
  .m-list-compact td[data-label="Action"] .dropdown-menu {
    position: fixed !important;
    top: auto !important;
    bottom: 0 !important;
    left: 0 !important;
    right: 0 !important;
    transform: none !important;
    width: 100% !important;
    min-width: 0 !important;
    max-width: 100% !important;
    max-height: 72vh !important;
    margin: 0 !important;
    padding: 6px 0 calc(6px + env(safe-area-inset-bottom, 0px)) !important;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    border: 0;
    border-radius: 16px 16px 0 0;
    box-shadow: 0 -10px 34px rgba(16, 24, 40, 0.28);
    z-index: 1200;
  }

  /* grab handle so it reads as a sheet */
  .m-list-compact td[data-label="Action"] .dropdown-menu::before {
    content: "";
    display: block;
    width: 38px;
    height: 4px;
    margin: 2px auto 8px;
    border-radius: 2px;
    background: #d1d5db;
  }

  .m-list-compact td[data-label="Action"] .dropdown-menu > li,
  .m-list-compact td[data-label="Action"] .dropdown-menu li {
    display: block !important;
    width: 100%;
    min-height: 0;
    padding: 0 !important;
    border-bottom: 1px solid #f3f4f6;
  }

  .m-list-compact td[data-label="Action"] .dropdown-menu li:last-child {
    border-bottom: 0;
  }

  /* ROOT CAUSE of the merged icon+label, finally traced to style.css:6112 -
         ul.dropdown-menu li a   { position: relative; padding-left: 10px !important }
         ul.dropdown-menu li a i { position: absolute; max-width: 20px }
         ul.dropdown-menu li a span { padding-left: 20px }
     The desktop design pulls the glyph OUT of flow and reserves its gutter
     with padding on the <span>. My earlier attempts fought that - forcing the
     <i> back to static inline-block - and lost, because
     `table.table tbody tr td .dropdown ul.dropdown-menu li a` scores (0,3,7)
     against my (0,3,3): same !important, higher specificity, so the anchor
     kept its 10px padding while the icon sat absolutely at its left edge,
     printing over the first letter.

     So: keep the desktop mechanism, just size it for touch. The doubled class
     below lifts specificity to (0,4,x) - one more CLASS than style.css has -
     which wins on the b-column without another round of !important. */
  .m-list-compact.m-list-compact td[data-label="Action"] .dropdown-menu li > a {
    position: relative;
    display: block !important;
    width: 100%;
    min-height: var(--m-tap);
    /* left padding IS the icon gutter - nothing flows into it */
    padding: 13px 14px 13px 46px !important;
    font-size: 0.9rem;
    line-height: 1.35;
    color: var(--m-ink) !important;
    white-space: normal;
    text-align: left;
  }

  .m-list-compact.m-list-compact td[data-label="Action"] .dropdown-menu li a i {
    position: absolute !important;
    left: 14px;
    top: 50%;
    transform: translateY(-50%) !important;
    width: 20px !important;
    max-width: 20px !important;
    margin: 0 !important;
    font-size: 15px !important;
    line-height: 1 !important;
    text-align: center !important;
  }

  /* the span's own 20px gutter is now doubled up - the anchor supplies it */
  .m-list-compact.m-list-compact td[data-label="Action"] .dropdown-menu li a span {
    padding-left: 0 !important;
  }

  /* status pills stay compact wherever a list uses them */
  .m-list-compact .status-open,
  .m-list-compact .badge {
    font-size: 0.68rem;
    padding: 1px 8px !important;
  }

  /* ---- compact list totals bar ----
     The desktop <tfoot> is one <th> per column, so on mobile it rendered as a
     run of unlabelled numbers ("101.00  0.00  78571..."). Only the figures
     that correspond to a column actually shown on the compact face are kept,
     and they are labelled. */
  .m-list-compact > tfoot {
    display: block;
    width: 100%;
    border-top: 1px solid var(--m-line);
    background: #f8fafc;
  }

  .m-list-compact > tfoot > tr {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: flex-end;
    gap: 4px 16px;
    width: 100%;
    padding: 10px 12px;
  }

  .m-list-compact > tfoot > tr > th {
    display: none;
    width: auto !important;
    padding: 0 !important;
    border: 0 !important;
    background: transparent !important;
    font-size: 0.95rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--m-ink);
  }

  .m-list-compact > tfoot > tr > th.m-sum {
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
  }

  .m-list-compact > tfoot > tr > th.m-sum::before {
    content: attr(data-label);
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: var(--m-ink-soft);
  }

  /* `w-1000` pins list tables to a literal 1000px below 960px */
  .m-list-compact.w-1000 {
    width: 100% !important;
    min-width: 0 !important;
  }

  /* the empty-state row must not inherit the grid */
  .m-list-compact > tbody > tr > td[colspan] {
    display: block !important;
    grid-column: 1 / -1;
    text-align: center;
    white-space: normal;
    padding: 18px 8px !important;
  }

  /* A master-detail list (Order Delivery) hangs an expandable panel off each
     row in a `<td colspan>`. That cell carries no `m-sum`, so the "anything
     not on the face is hidden" rule would have swallowed the whole panel, and
     the empty-state styling above would have centred it and clipped it to one
     nowrap line. `m-detail-cell` opts it back in as a real panel. */
  .m-list-compact > tbody > tr > td.m-detail-cell {
    display: block !important;
    grid-column: 1 / -1;
    padding: 0 0 10px !important;
    text-align: left;
    white-space: normal;
    overflow: visible;
  }

  /* the panel's own scroller and card wrapper are desktop chrome */
  .m-list-compact td.m-detail-cell .table-responsive,
  .m-list-compact td.m-detail-cell [class*="table_height"] {
    max-height: none !important;
    min-height: 0 !important;
    overflow: visible !important;
  }

  .m-list-compact td.m-detail-cell .bgc-white {
    margin-bottom: 0 !important;
    padding-bottom: 0 !important;
    background: transparent !important;
  }

  /* Party Proforma Summary hangs its detail off a `<td colspan class="collapse">`
     that sits DIRECTLY inside <tbody> with no <tr> around it (and wraps a <tr>
     around a <div> inside). Angular keeps that shape, so `> tbody > tr > td`
     never matches and the panel needs its own selector.

     Scoped to `.show` deliberately: an unconditional `display` here would
     outrank Bootstrap's `.collapse:not(.show) { display: none }` and the
     detail would be stuck permanently open. */
  .m-list-compact > tbody > td.m-detail-cell.show {
    display: block !important;
    width: 100% !important;
    padding: 0 0 10px !important;
    text-align: left;
    white-space: normal;
    overflow: visible;
  }

  .m-list-compact > tbody > td.m-detail-cell .table-responsive,
  .m-list-compact > tbody > td.m-detail-cell [class*="table_height"] {
    max-height: none !important;
    min-height: 0 !important;
    overflow: visible !important;
  }

  /* the <tr> the template wraps around a <div> is not a row in any real sense */
  .m-list-compact > tbody > td.m-detail-cell > tr.hide-table-padding {
    display: block !important;
    width: 100%;
  }

  /* Same for a stacked report. Without this the <tfoot> row stacks like any
     other, so every one of its ~25 cells becomes its own line - the blank
     spacer cells included - and the totals read as a tall column of stray
     figures with big gaps between them. As a wrapped strip the labels sit
     beside their numbers and the empties disappear. */
  /* A wide report's <tfoot> is one <th> per column, so wrapping it into a
     strip just produced a run of bare figures - "Total 201 0.00 13955047.00
     0.00 ..." with nothing saying which total was which. Same treatment as
     the card body instead: only LABELLED figures survive, each announced. */
  .m-stack-grid > tfoot > tr {
    display: block !important;
    width: 100% !important;
    padding: 8px 12px !important;
    background: #eef2f9;
    border-top: 2px solid var(--m-line);
    font-weight: 700;
  }

  .m-stack-grid > tfoot > tr > th {
    display: flex !important;
    justify-content: space-between;
    gap: 12px;
    width: auto !important;
    padding: 3px 0 !important;
    border: 0 !important;
    font-size: 0.8rem;
    text-align: right;
  }

  .m-stack-grid > tfoot > tr > th[data-label]::before,
  .m-stack-grid > tfoot > tr > th[data-label]::before {
    content: attr(data-label);
    flex: 0 0 44%;
    text-align: left;
    font-size: 0.68rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    color: var(--m-ink-soft);
  }

  /* an unlabelled footer cell is desktop column alignment, not data */
  .m-stack-grid > tfoot > tr > th:not([data-label]) {
    display: none !important;
  }

  /* ...and a labelled one with no figure in it says nothing either */
  .m-stack-grid > tfoot > tr > th[data-label]:empty {
    display: none !important;
  }

  /* Some reports put their total row inside <tbody> as a run of <th> rather
     than in a <tfoot> (Overdue Bills Outstanding does). Without this it would
     be gridded like a data row and its cells placed as if they were fields. */
  .m-list-compact > tbody > tr.m-total-row {
    display: flex !important;
    flex-wrap: wrap;
    gap: 4px 10px;
    padding: 10px 12px;
    background: #eef2f9;
    border-top: 1px solid var(--m-line);
    border-bottom: 0;
  }

  .m-list-compact > tbody > tr.m-total-row > th {
    padding: 0 !important;
    border: 0 !important;
    font-size: 0.78rem;
    white-space: nowrap;
  }

  .m-list-compact > tbody > tr.m-total-row > th:empty {
    display: none !important;
  }

  /* the figure sits at the far end of the strip */
  .m-list-compact > tbody > tr.m-total-row > th:not(:first-child) {
    margin-left: auto;
    font-weight: 700;
  }

  /* a tfoot grand-total line reads as one strip, not a row of bare figures */
  .m-list-compact > tfoot > tr {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 10px;
    padding: 10px 12px;
    background: #eef2f9;
    border-top: 1px solid var(--m-line);
  }

  .m-list-compact > tfoot > tr > th {
    padding: 0 !important;
    border: 0 !important;
    font-size: 0.76rem;
    white-space: nowrap;
  }

  /* a footer cell with nothing in it is desktop column alignment, not data
     (Voucher Settlement's total row ends with an empty <th> for the action
     column) */
  .m-list-compact > tfoot > tr > th:empty {
    display: none !important;
  }

  /* the collapse row itself must not be gridded like a data row */
  .m-list-compact > tbody > tr.collapse.show,
  .m-list-compact > tbody > tr.collapsing {
    display: block !important;
    padding: 0 10px;
    border-bottom: 1px solid #eef0f3;
  }

  /* An expandable row has to look expandable. The chevron points down while
     collapsed and flips when open, and both face cells that carry the toggle
     get a tap-sized target. */
  .m-list-compact td.accordion-toggle {
    cursor: pointer;
  }

  .m-list-compact td.accordion-toggle .fa-arrow-down {
    margin-left: 6px;
    font-size: 0.7rem;
    transition: transform 0.18s var(--m-ease);
  }

  .m-list-compact td.accordion-toggle:not(.collapsed) .fa-arrow-down {
    transform: rotate(180deg);
  }

  /* the order number reads as the link it now is */
  .m-list-compact td.accordion-toggle[data-label="Order No."]::after {
    content: "\f107";                       /* chevron-down */
    font-family: "Font Awesome 5 Free";
    font-weight: 900;
    margin-left: 6px;
    font-size: 0.72rem;
    opacity: 0.7;
  }

  .m-list-compact td.accordion-toggle[data-label="Order No."]:not(.collapsed)::after {
    content: "\f106";                       /* chevron-up */
  }

  /* Horizontal-scroll fallback with a sticky header, for tables that genuinely
     cannot be card-ified. */
  .m-scroll-table {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
  }

  .m-scroll-table > table thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    background: #f3f4f6;
  }

  /* Touch-target floor for interactive controls in mobile views. */
  .m-tap {
    min-width: var(--m-tap) !important;
    min-height: var(--m-tap) !important;
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
  }

  /* Floating action button */
  .m-fab {
    position: fixed;
    right: 16px;
    bottom: calc(16px + var(--m-safe-bottom));
    z-index: 900;
    width: 54px;
    height: 54px;
    border: 0;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    background: var(--m-accent);
    font-size: 1.3rem;
    box-shadow: 0 6px 18px rgba(66, 133, 244, 0.42);
    transition: transform 0.18s var(--m-ease);
  }

  .m-fab:active {
    transform: scale(0.93);
  }

  /* Toast/spinner overlays must clear the two-row header. */
  .toast-top-right {
    top: calc(var(--app-header-h) + 8px) !important;
    right: 8px !important;
    left: 8px !important;
    width: auto !important;
  }

  /* Respect reduced-motion preferences. */
  @media (prefers-reduced-motion: reduce) {
    .sidebar,
    .sidebar .over-bar,
    .m-fab,
    .modal.m-sheet.show .modal-dialog,
    .modal.m-fullscreen.show .modal-dialog {
      transition: none !important;
      animation: none !important;
    }
  }

  /* ==========================================================================
     ACCOUNTING STATEMENTS
     Group Summary, Trial Balance, Balance Sheet, Trading A/c and Profit & Loss
     all render into `.main-balance`. They are NOT lists, so the card treatment
     used everywhere else would be wrong here: in a statement the indentation IS
     the information ("Sundry Debtors > North Zone > ABC Ltd"), and a card per
     line would throw the hierarchy away. They stay statements; they are just
     made to fit a phone.

     Everything is scoped under `.main-content2` - the on-screen sheet lives
     inside `<main class="main-content2">`, while the print/export copies sit
     outside it. That matters more than usual here: an A4 page is ~794 CSS px,
     so a `max-width: 991.98px` query DOES apply while printing, and an
     unscoped rule would follow the report onto paper.
     ========================================================================== */

  /* The scroll clamp is sized for a desktop viewport - on a phone
     `calc(100vh - 325px)` can leave a ~150px window inside a page that is
     already scrolling. Let the page do the scrolling. */
  .main-content2 .main-balance .tbody {
    max-height: none !important;
    overflow-y: visible !important;
    overflow-x: visible !important;
  }

  /* the sheet should use the full width of the screen */
  .main-content2 .main-balance .row,
  .main-content2 .main-balance .row1 {
    margin-left: 0 !important;
    margin-right: 0 !important;
  }

  .main-content2 .main-balance .balancesheet {
    flex: 0 0 100% !important;
    max-width: 100% !important;
    padding-left: 0 !important;
    padding-right: 0 !important;
  }

  .main-content2 .main-balance .bs_head .name_size {
    font-size: 0.95rem !important;
  }

  .main-content2 .main-balance .bs_head > div {
    font-size: 0.78rem;
  }

  /* ---- statement lines -----------------------------------------------------
     A line is "name .............. amount". Bootstrap's `col-md-*` drops to
     100% below 768px, which breaks every line into two - name on one row, a
     lonely right-aligned figure on the next. Giving the columns their content
     width back restores the desktop reading in a narrower space.

     Keyed off `.tbody .row` rather than the `head1`-`head4` classes because
     Profit & Loss numbers its lines with a plain `.row`. The `.tbody` element
     is itself a `.row`, and a descendant combinator does not match it, so the
     two panels still stack. */
  .main-content2 .main-balance .row.thead,
  .main-content2 .main-balance .row.tfoot,
  .main-content2 .main-balance .tbody .row {
    display: flex !important;
    flex-wrap: nowrap !important;
    align-items: baseline;
  }

  .main-content2 .main-balance .row.thead > div,
  .main-content2 .main-balance .row.tfoot > div,
  .main-content2 .main-balance .tbody .row > div {
    flex: 0 0 auto !important;
    width: auto !important;
    max-width: none !important;
    min-width: 0 !important;
    padding-left: 4px !important;
    padding-right: 4px !important;
    font-size: 0.76rem;
    line-height: 1.35;
  }

  /* the first cell is the account name and takes whatever is left */
  .main-content2 .main-balance .row.thead > div:first-child,
  .main-content2 .main-balance .row.tfoot > div:first-child,
  .main-content2 .main-balance .tbody .row > div:first-child {
    flex: 1 1 auto !important;
    text-align: left;
    overflow-wrap: break-word;
    word-break: break-word;
  }

  /* figures never wrap and stay column-aligned */
  .main-content2 .main-balance .row > div.text-right,
  .main-content2 .main-balance .row > div.amount_bs {
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
    text-align: right;
  }

  .main-content2 .main-balance .treedata a {
    line-height: 1.35 !important;
  }

  /* Indents of 20/40/60px eat a third of a 360px screen before the name even
     starts. Scaled down, they still read as four distinct levels. */
  .main-content2 .main-balance div.d1 { padding-left: 10px !important; }
  .main-content2 .main-balance div.d2 { padding-left: 19px !important; }
  .main-content2 .main-balance div.d3 { padding-left: 28px !important; }

  .main-content2 .main-balance div.d1r,
  .main-content2 .main-balance div.d2r,
  .main-content2 .main-balance div.d3r {
    padding-right: 4px !important;
  }

  /* ---- the T-account header and footer -------------------------------------
     In the two-column layout one header row describes BOTH sides
     ("Liabilities | Amount | Assets | Amount"). Once the sides stack, that row
     sits above the wrong column, so it is dropped and each panel carries its
     own `d-lg-none` heading instead - same words, in the right place. */
  .main-content2 .main-balance .row.m-acct-xhead,
  .main-content2 .main-balance .row.m-acct-xfoot {
    display: none !important;
  }

  /* the per-panel stand-ins; `.thead`/`.tfoot` already give them the grey band */
  .main-content2 .main-balance .row.m-acct-mhead > div,
  .main-content2 .main-balance .row.m-acct-mfoot > div {
    font-size: 0.78rem;
    font-weight: 700;
  }

  /* Profit & Loss labels both of its sides "Particulars", so once they stack
     the right-hand half of the header is a word-for-word duplicate. Keep the
     first half - it reads correctly over either panel - and drop the rest. */
  .main-content2 .main-balance .row.m-acct-xhead-half > div:nth-child(n + 4) {
    display: none !important;
  }

  /* Trading and P&L keep their shared footer - it carries both totals and
     those reports have no per-side footer to fall back on. It wraps into two
     lines instead, one per side; the template appends the side name to each
     "Total" in a `d-lg-none` span so the two lines can be told apart. */
  .main-content2 .main-balance .row.m-acct-xfoot-wrap {
    flex-wrap: wrap !important;
  }

  .main-content2 .main-balance .row.m-acct-xfoot-wrap > div:nth-child(odd) {
    flex: 1 1 60% !important;
    text-align: left !important;
  }

  .main-content2 .main-balance .row.m-acct-xfoot-wrap > div:nth-child(even) {
    margin-left: auto;
    white-space: nowrap;
  }

  /* ---- the two statements that stayed tables -------------------------------
     Group Summary and Trial Balance are laid out with colspans over a 12- or
     20-column grid. Trial Balance can be configured up to seven amount
     columns, which cannot fit any phone, so the container scrolls sideways -
     but only when the configuration actually asks for it. At the default
     (closing balance only) the table fits and nothing scrolls. */
  .m-acct-scroll {
    overflow-x: auto !important;
    -webkit-overflow-scrolling: touch;
    padding-left: 0 !important;
    padding-right: 0 !important;
  }

  table.m-acct-table {
    font-size: 0.70rem !important;
  }

  table.m-acct-table td {
    padding: 4px 3px !important;
    line-height: 1.35;
  }

  table.m-acct-table td.text-right {
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
  }

  /* same reasoning as `div.d1`-`d3` above: Bootstrap's pl-2..pl-5 are
     0.5/1/1.5/3rem, and 3rem of indent on a 360px screen is a third of it */
  table.m-acct-table td.pl-2 { padding-left: 6px !important; }
  table.m-acct-table td.pl-3 { padding-left: 14px !important; }
  table.m-acct-table td.pl-4 { padding-left: 22px !important; }
  table.m-acct-table td.pl-5 { padding-left: 30px !important; }

  /* ==========================================================================
     POS (New 2)  -  `sale-direct-add-pos-new2`
     The phone gets a DEDICATED till view (`.m-pos`, `d-lg-none` in the
     template), not the desktop panes reflowed. Everything here styles that new
     view; the desktop markup is only hidden, never restyled.

     One piece of the desktop IS reused rather than rebuilt: `.bill-summary`.
     It is already `position: fixed; bottom: 0`, already has a working expand
     toggle, and already carries every payment button and payment panel wired
     through `toggleSelectors()` - which drives them by `getElementById`, so
     those nodes have to stay in the DOM anyway. Rebuilding it would have meant
     duplicating payment logic, so it is restyled full-width instead.
     ========================================================================== */

  /* THE GAP BETWEEN CUSTOMER DETAILS AND THE ITEMS.
     `#mainContent` is inline `height: 100vh; position: relative` - a rigid
     full-viewport box. On the desktop that is right: it holds two 100vh panes.
     On a phone all it holds is the customer panel, so it rendered as a screen
     of empty space with the till pushed below it. It has to size to its
     content. Inline `height` is a normal declaration, so `!important` wins. */
  app-sale-direct-add-pos-new2 #mainContent {
    height: auto !important;
    min-height: 0 !important;
  }

  /* style.css gives the desktop container `min-height: calc(100vh - 176px)` to
     hold its two 100vh panes. With those panes hidden it has nothing left to
     hold, but it still reserved a full viewport. */
  app-sale-direct-add-pos-new2 .main-content3 {
    min-height: 0 !important;
    margin-bottom: 8px;      /* normal spacing before the till, nothing more */
  }

  /* the desktop cart pane now holds the customer panel and the pinned summary */
  app-sale-direct-add-pos-new2 .main-content3 > form {
    display: block;
  }

  /* ---- Customer Details, kept (not hidden) and made compact ----
     Three `col-md-*` fields stack to three full-width rows below 768px, which
     is ~200px of the screen before a single product is visible. Mobile number
     takes its own line (it has the country-code select beside it); name and
     email share the next. */
  app-sale-direct-add-pos-new2 .m-pos-cust {
    margin: 0 0 8px !important;
    padding-bottom: 8px !important;
  }

  app-sale-direct-add-pos-new2 .m-pos-cust .customer-h3 {
    width: 100%;
    margin: 0 0 6px;
    font-size: 0.78rem;
    font-weight: 700;
    color: var(--m-ink);
  }

  app-sale-direct-add-pos-new2 .m-pos-cust .collapse1 {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    width: 100%;
    margin: 0;
  }

  app-sale-direct-add-pos-new2 .m-pos-cust .form-group {
    flex: 1 1 calc(50% - 3px);
    max-width: none;
    min-width: 0;
    margin-bottom: 0;
    padding: 0;
  }

  /* the mobile-number group carries a select AND an input - give it the row */
  app-sale-direct-add-pos-new2 .m-pos-cust .form-group:first-child {
    flex: 1 1 100%;
  }

  app-sale-direct-add-pos-new2 .m-pos-cust .mobile_code {
    display: flex;
    gap: 6px;
  }

  app-sale-direct-add-pos-new2 .m-pos-cust .mobile_code .ng-select {
    flex: 0 0 88px;
    width: 88px !important;
  }

  app-sale-direct-add-pos-new2 .m-pos-cust .mobile_code .form-control {
    flex: 1 1 auto;
    min-width: 0;
  }

  app-sale-direct-add-pos-new2 .m-pos-cust .form-control {
    height: 38px;
    padding: 6px 8px !important;
    font-size: 0.78rem;
  }

  app-sale-direct-add-pos-new2 .main-content3 > form > .card {
    width: 100% !important;
    float: none !important;
    height: auto !important;
    overflow: visible !important;
    padding: 0 !important;
    border: 0 !important;
  }

  /* ---- the reused bill summary, pinned across the full width ---- */
  app-sale-direct-add-pos-new2 .bill-summary {
    width: 100% !important;
    left: 0 !important;
    right: 0 !important;
    bottom: 46px !important;         /* sits above the view-cart bar */
    padding: 8px 10px !important;
    box-shadow: 0 -4px 14px rgba(16, 24, 40, 0.12);
  }

  app-sale-direct-add-pos-new2 .bill-summary .bill-summary-box.active {
    max-height: 40vh;
    overflow-y: auto !important;
  }

  app-sale-direct-add-pos-new2 .bill-summary .summary-item {
    font-size: 0.78rem;
  }

  app-sale-direct-add-pos-new2 .payment-options {
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 8px;
  }

  app-sale-direct-add-pos-new2 .payment-options .payment-btn {
    flex: 1 1 auto;
    min-width: 58px;
    min-height: var(--m-tap);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 6px 8px;
  }

  /* ---- the new mobile till ---- */
  .m-pos {
    /* the shell (`.main-content21`) already supplies the side gutter - adding
       more here just narrows the tile grid */
    padding: 0 0 190px;        /* clears the summary + the view-cart bar */
  }

  .m-pos-find {
    display: flex;
    gap: 6px;
    padding: 8px 0;
  }

  .m-pos-find .form-control {
    flex: 1 1 0;
    min-width: 0;
    height: var(--m-tap);
    font-size: 0.8rem;
  }

  .m-pos-find .btn {
    flex: 0 0 auto;
    min-height: var(--m-tap);
    border-radius: 10px;
  }

  /* ---- camera scan button + scanner overlay ---- */
  .m-pos-scan {
    flex: 0 0 auto;
    width: var(--m-tap);
    height: var(--m-tap);
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--m-brand);
    border-radius: 10px;
    background: #fff;
    color: var(--m-brand);
    font-size: 1.05rem;
  }

  .m-pos-scan:active {
    background: var(--m-brand);
    color: #fff;
  }

  .m-scan {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 1300;              /* over the sheet and both pinned bars */
    background: #000;
  }

  .m-scan-video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    background: #000;
  }

  /* the aiming window - a wide, short box suits 1D barcodes */
  .m-scan-frame {
    position: absolute;
    top: 50%;
    left: 8%;
    width: 84%;
    height: 26vh;
    transform: translateY(-50%);
    border: 2px solid rgba(255, 255, 255, 0.9);
    border-radius: 12px;
    box-shadow: 0 0 0 100vmax rgba(0, 0, 0, 0.45);
    pointer-events: none;
  }

  .m-scan-hint {
    position: absolute;
    left: 0;
    right: 0;
    top: calc(50% + 15vh);
    padding: 0 16px;
    text-align: center;
    color: #fff;
    font-size: 0.8rem;
  }

  .m-scan-err {
    color: #ffb4a9;
    font-weight: 600;
  }

  .m-scan-actions {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    display: flex;
    gap: 10px;
    justify-content: center;
    padding: 16px;
    padding-bottom: calc(16px + var(--m-safe-bottom));
  }

  .m-scan-btn {
    min-height: var(--m-tap);
    min-width: 110px;
    padding: 0 18px;
    border: 1px solid rgba(255, 255, 255, 0.6);
    border-radius: 24px;
    background: rgba(255, 255, 255, 0.12);
    color: #fff;
    font-size: 0.84rem;
    font-weight: 600;
  }

  .m-scan-cancel {
    background: #fff;
    color: var(--m-ink);
    border-color: #fff;
  }

  /* categories: one scrolling strip, never a wrapped wall */
  .m-pos-cats {
    display: flex;
    flex-wrap: nowrap;
    gap: 6px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding-bottom: 8px;
  }

  .m-pos-cats::-webkit-scrollbar {
    display: none;
  }

  .m-pos-cat {
    flex: 0 0 auto;
    min-height: 34px;
    padding: 0 12px;
    border: 1px solid var(--m-line);
    border-radius: 17px;
    background: #fff;
    font-size: 0.74rem;
    font-weight: 600;
    color: var(--m-ink);
    white-space: nowrap;
  }

  .m-pos-cat:active {
    background: var(--m-canvas);
  }

  /* the product grid */
  .m-pos-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
  }

  .m-pos-tile {
    display: flex;
    flex-direction: column;
    padding: 8px;
    border: 1px solid var(--m-line);
    border-radius: 10px;
    background: #fff;
    text-align: left;
    cursor: pointer;
  }

  .m-pos-tile:active {
    background: var(--m-canvas);
  }

  .m-pos-tile.out-of-stock {
    opacity: 0.55;
  }

  .m-pos-thumb {
    height: 74px;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 6px;
    overflow: hidden;
  }

  .m-pos-thumb img {
    max-width: 100%;
    max-height: 74px;
    object-fit: contain;
  }

  .m-pos-price {
    font-size: 0.82rem;
    font-weight: 700;
    color: var(--m-brand);
  }

  .m-pos-name {
    font-size: 0.74rem;
    font-weight: 600;
    color: var(--m-ink);
    line-height: 1.25;
    overflow-wrap: break-word;
  }

  .m-pos-sub {
    font-size: 0.64rem;
    color: var(--m-ink-soft);
  }

  .m-pos-tile-add {
    align-items: center;
    justify-content: center;
    text-align: center;
    border-style: dashed;
    font-size: 0.72rem;
    color: var(--m-ink-soft);
  }

  .m-pos-plus {
    font-size: 1.6rem;
    line-height: 1;
    color: var(--m-brand);
  }

  /* ---- pinned "view cart" bar ----
     Empty it is deliberately quiet slate; the moment the cart holds anything
     it turns brand blue and pulses once, so adding the first item is
     unmistakable without a toast. Purely visual - `m-has-items` is bound to
     `Items?.length > 0` and changes nothing about the cart. */
  .m-pos-bar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1002;
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 46px;
    padding: 6px 12px;
    padding-bottom: calc(6px + var(--m-safe-bottom));
    background: #667085;
    color: #fff;
    font-size: 0.82rem;
    transition: background-color 0.25s var(--m-ease),
                box-shadow 0.25s var(--m-ease);
  }

  .m-pos-bar.m-has-items {
    background: var(--m-brand);
    box-shadow: 0 -6px 18px rgba(42, 88, 173, 0.35);
  }

  /* The pulse has to re-run on EVERY add, including a repeat of the same item.
     A CSS animation only restarts when it is (re)applied, so the component
     counts adds in `mCartBump` and the template alternates these two classes
     off its parity - each add swaps a/b, which re-applies the animation. They
     are identical on purpose. */
  .m-pos-bar.m-bump-a,
  .m-pos-bar.m-bump-b {
    animation: mCartPulse 0.45s var(--m-ease) 1;
  }

  .m-pos-bar.m-bump-a .m-pos-view,
  .m-pos-bar.m-bump-b .m-pos-view {
    animation: mCartNudge 0.45s var(--m-ease) 1;
  }

  @keyframes mCartPulse {
    0%   { background: #12b76a; }
    60%  { background: #12b76a; }
    100% { background: var(--m-brand); }
  }

  @keyframes mCartNudge {
    0%   { transform: translateY(3px); opacity: 0.5; }
    100% { transform: translateY(0);   opacity: 1; }
  }

  .m-pos-count {
    flex: 0 0 auto;
    opacity: 0.9;
  }

  .m-pos-bartotal {
    flex: 1 1 auto;
    font-weight: 700;
    font-size: 0.92rem;
  }

  .m-pos-view {
    flex: 0 0 auto;
    font-weight: 600;
  }

  /* ---- the cart sheet ---- */
  .m-pos-scrim {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 1090;
    background: rgba(16, 24, 40, 0.45);
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.2s var(--m-ease), visibility 0.2s var(--m-ease);
  }

  .m-pos-scrim.m-open {
    opacity: 1;
    visibility: visible;
  }

  .m-pos-sheet {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1091;
    display: flex;
    flex-direction: column;
    max-height: 88vh;
    background: #fff;
    border-radius: 16px 16px 0 0;
    transform: translateY(101%);
    transition: transform 0.26s var(--m-ease);
  }

  .m-pos-sheet.m-open {
    transform: translateY(0);
  }

  .m-pos-sheet-head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 14px;
    border-bottom: 1px solid var(--m-line);
    font-size: 0.9rem;
  }

  .m-pos-sheet-head strong {
    flex: 1 1 auto;
  }

  .m-pos-clear,
  .m-pos-close {
    flex: 0 0 auto;
    width: var(--m-tap);
    height: var(--m-tap);
    display: flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: 10px;
    background: transparent;
  }

  .m-pos-clear {
    color: #b42318;
  }

  .m-pos-close {
    font-size: 1.5rem;
    line-height: 1;
    color: var(--m-ink-soft);
  }

  .m-pos-lines {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: 8px 12px;
  }

  .m-pos-empty {
    padding: 24px 0;
    text-align: center;
    color: var(--m-ink-soft);
    font-size: 0.82rem;
  }

  .m-pos-line {
    padding: 8px 0;
    border-bottom: 1px solid var(--m-line);
  }

  .m-pos-line-top {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin-bottom: 5px;
  }

  .m-pos-line-name {
    flex: 1 1 auto;
    font-size: 0.8rem;
    font-weight: 600;
    overflow-wrap: break-word;
  }

  .m-pos-line-total {
    flex: 0 0 auto;
    font-size: 0.84rem;
    font-weight: 700;
    color: var(--m-brand);
  }

  .m-pos-line-ctl {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
  }

  .m-pos-qty {
    display: flex;
    align-items: center;
    border: 1px solid var(--m-line);
    border-radius: 8px;
    overflow: hidden;
  }

  .m-pos-qty button {
    width: 34px;
    height: 34px;
    border: 0;
    background: var(--m-canvas);
    font-size: 1rem;
    font-weight: 700;
    color: var(--m-ink);
  }

  .m-pos-qty input {
    width: 46px;
    height: 34px;
    border: 0;
    text-align: center;
    font-size: 0.8rem;
    font-weight: 700;
    color: var(--m-brand);
  }

  .m-pos-unit {
    font-size: 0.7rem;
    color: var(--m-ink-soft);
  }

  .m-pos-unit-pick {
    display: inline-flex;
    border: 1px solid var(--m-line);
    border-radius: 8px;
    overflow: hidden;
  }

  .m-pos-unit-pick button,
  .m-pos-disctype button {
    min-width: 34px;
    height: 34px;
    border: 0;
    background: #fff;
    font-size: 0.7rem;
    color: var(--m-ink-soft);
  }

  .m-pos-unit-pick button.active,
  .m-pos-disctype button.active {
    background: var(--m-brand);
    color: #fff;
  }

  .m-pos-field {
    display: flex;
    align-items: center;
    gap: 4px;
    margin: 0;
    font-size: 0.62rem;
    color: var(--m-ink-soft);
    text-transform: uppercase;
  }

  .m-pos-field input {
    width: 62px;
    height: 34px;
    border: 1px solid var(--m-line);
    border-radius: 8px;
    text-align: center;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--m-ink);
  }

  .m-pos-disctype {
    display: inline-flex;
    border: 1px solid var(--m-line);
    border-radius: 8px;
    overflow: hidden;
  }

  .m-pos-del {
    margin-left: auto;
    width: 34px;
    height: 34px;
    border: 0;
    border-radius: 8px;
    background: transparent;
    color: #b42318;
  }

  .m-pos-line-tax {
    display: flex;
    justify-content: space-between;
    gap: 8px;
    margin-top: 4px;
    font-size: 0.66rem;
    color: var(--m-ink-soft);
  }

  .m-pos-sheet-foot {
    flex: 0 0 auto;
    display: flex;
    gap: 8px;
    padding: 10px 12px;
    padding-bottom: calc(10px + var(--m-safe-bottom));
    border-top: 1px solid var(--m-line);
    background: #fff;
  }

  .m-pos-sheet-foot .btn {
    flex: 1 1 0;
    min-height: var(--m-tap);
    border-radius: 10px;
    font-size: 0.84rem;
  }

  /* three-up once there is room */
  @media (min-width: 600px) {
    .m-pos-grid {
      grid-template-columns: repeat(3, minmax(0, 1fr));
    }
  }

  /* ==========================================================================
     SETTINGS  (`m-set-list`)
     Master Settings, App Settings, Additional Settings, Additional Master
     Settings and Menu Master Settings are all the same table: an optional
     select checkbox, a serial number, the setup name, and a Value cell that is
     one of five or six mutually exclusive controls (Yes/No radios, text,
     native select, select2, and a sixth type on some pages).

     As a table on a phone the name is squeezed into 30% and the control into a
     sliver. Each row becomes a settings line instead - the checkbox pinned
     left, the name on its own line, its control full width underneath - which
     is how a settings screen should read anyway:

         [x]  Enable batch tracking
              ( ) Yes   ( ) No
     ========================================================================== */
  .m-set-list,
  .m-set-list > tbody,
  .m-set-list > tbody > tr,
  .m-set-list > tbody > tr > td {
    display: block;
    width: 100% !important;
    min-width: 0 !important;
    max-width: 100% !important;
  }

  .m-set-list > thead {
    display: none;
  }

  .m-set-list > tbody > tr {
    position: relative;
    padding: 10px 12px 12px 42px;
    border-bottom: 1px solid var(--m-line);
  }

  .m-set-list > tbody > tr > td {
    padding: 0 !important;
    border: 0 !important;
  }

  /* the select checkbox is pinned into the left gutter the row reserves */
  .m-set-list > tbody > tr > td.m-set-check {
    position: absolute;
    left: 10px;
    top: 12px;
    width: 24px !important;
  }

  /* The serial sits directly UNDER the checkbox in the same gutter. Pinning it
     to the bottom of the row instead left it floating level with the controls,
     visually detached from the row it numbers. */
  .m-set-list > tbody > tr > td.m-set-sno {
    position: absolute;
    left: 10px;
    top: 36px;
    bottom: auto;
    width: 26px !important;
    font-size: 0.62rem;
    line-height: 1;
    color: var(--m-ink-soft);
  }

  /* the "i" description toggle: a compact round target on the name line, not a
     floated block that collides with the setting's text */
  .m-set-list > tbody > tr > td.m-set-name .setting-info {
    float: none !important;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    margin-left: 6px !important;
    border: 1px solid var(--m-line);
    border-radius: 50%;
    color: var(--m-brand);
    font-size: 0.7rem;
    vertical-align: middle;
  }

  .m-set-list > tbody > tr > td.m-set-name .info-description {
    position: relative;
    margin-top: 6px;
    padding: 8px 28px 8px 10px;
    border-radius: 8px;
    background: var(--m-canvas);
    font-size: 0.72rem;
    font-weight: 400;
    line-height: 1.4;
    color: var(--m-ink-soft);
  }

  .m-set-list > tbody > tr > td.m-set-name .info-description .info-close {
    position: absolute;
    top: 4px;
    right: 6px;
    color: var(--m-ink-soft);
  }

  .m-set-list > tbody > tr > td.m-set-name {
    margin-bottom: 8px;
    font-size: 0.82rem;
    font-weight: 600;
    line-height: 1.3;
    color: var(--m-ink);
  }

  .m-set-list > tbody > tr > td.m-set-name .font-weight-bold {
    font-weight: 600 !important;
  }

  /* ---- the value control, whichever of the variants rendered ---- */
  .m-set-list > tbody > tr > td.m-set-value > .form-control,
  .m-set-list > tbody > tr > td.m-set-value > select,
  .m-set-list > tbody > tr > td.m-set-value > input,
  .m-set-list > tbody > tr > td.m-set-value > textarea,
  .m-set-list > tbody > tr > td.m-set-value .input-group,
  .m-set-list > tbody > tr > td.m-set-value .select2,
  .m-set-list > tbody > tr > td.m-set-value select2,
  .m-set-list > tbody > tr > td.m-set-value .select2-container {
    width: 100% !important;
    min-width: 0 !important;
    max-width: 100% !important;
  }

  .m-set-list > tbody > tr > td.m-set-value > .form-control,
  .m-set-list > tbody > tr > td.m-set-value > select,
  .m-set-list > tbody > tr > td.m-set-value > input {
    height: 40px;
    font-size: 0.82rem;
  }

  .m-set-list > tbody > tr > td.m-set-value .select2-container .select2-selection--single {
    height: 40px;
    display: flex;
    align-items: center;
  }

  /* Yes/No: two real targets side by side, not two cramped inline radios */
  .m-set-list > tbody > tr > td.m-set-value fieldset {
    display: flex;
    gap: 18px;
    margin: 0;
    padding: 0;
    border: 0;
  }

  .m-set-list > tbody > tr > td.m-set-value fieldset .custom-control {
    display: flex;
    align-items: center;
    min-height: 34px;
    margin: 0;
  }

  .m-set-list > tbody > tr > td.m-set-value fieldset .custom-control-label {
    font-size: 0.82rem;
    line-height: 1.2;
  }

  /* the row's own checkbox needs a real target too */
  .m-set-list > tbody > tr > td.m-set-check .custom-control-label::before,
  .m-set-list > tbody > tr > td.m-set-check .custom-control-label::after {
    width: 20px;
    height: 20px;
  }

  /* ---- Setup Setting Report (`m-audit-card`) ----
     Not a settings screen - an audit log of who changed which setting, so it
     reads as a change record: what changed, when, and from what to what. Who
     and from where sit behind the tap.

         Enable batch tracking            12/07/2026, 4:32 PM
         FROM No            TO Yes                            */
  .m-rep-card.m-audit-card > tbody > tr.m-committed > td[data-label="Setup Name"] {
    order: 1;
    flex: 1 1 auto;
    font-weight: 700;
    font-size: 0.8rem;
    color: var(--m-ink);
    word-break: break-word;
  }

  .m-rep-card.m-audit-card > tbody > tr.m-committed > td[data-label="Date & Time"] {
    order: 2;
    font-size: 0.68rem;
    color: var(--m-ink-soft);
    white-space: nowrap;
  }

  .m-rep-card.m-audit-card > tbody > tr.m-committed > td[data-label="Last Value"],
  .m-rep-card.m-audit-card > tbody > tr.m-committed > td[data-label="Updated Value"] {
    order: 5;
    display: flex !important;
    gap: 5px;
    margin-top: 3px;
    font-size: 0.76rem;
    font-weight: 600;
  }

  .m-rep-card.m-audit-card > tbody > tr.m-committed > td[data-label="Updated Value"] {
    order: 6;
    margin-left: auto;
    color: var(--m-brand);
  }

  .m-rep-card.m-audit-card > tbody > tr.m-committed > td[data-label="Last Value"]::before {
    content: "FROM" !important;
    font-size: 0.58rem;
    font-weight: 600;
    color: var(--m-ink-soft);
  }

  .m-rep-card.m-audit-card > tbody > tr.m-committed > td[data-label="Updated Value"]::before {
    content: "TO" !important;
    font-size: 0.58rem;
    font-weight: 600;
    color: var(--m-ink-soft);
  }

  /* ---- the settings DIALOG (`#app_settings`) ----
     This is the panel the gear in Sale / Purchase / Item Master / Customer /
     Vendor / POS opens. Its header nests a Bootstrap grid inside the flex
     header, pulls the search box up with an inline `margin-top: -10px`, and
     floats the action cluster - none of which survives stacking. Left alone,
     Save landed on a left-aligned line of its own directly above the first
     setting and read as though it were overlapping the list. */
  #app_settings .modal-header .container-fluid,
  #app_settings .modal-header .container-fluid > .row {
    width: 100%;
    margin: 0 !important;
    padding: 0 !important;
  }

  #app_settings .modal-header .left_side_head {
    padding: 0 !important;
  }

  #app_settings .modal-header .right_saerch_side {
    margin-top: 6px;
    align-items: center;
  }

  /* beats the inline `margin-top: -10px` on the search wrapper */
  #app_settings .modal-header .right_saerch_side > .mr-2 {
    flex: 1 1 auto;
    min-width: 0;
    margin-top: 0 !important;
  }

  /* Save stays inline at the end of the search row instead of taking a
     full-width line of its own */
  #app_settings .modal-header .btn_header {
    position: static !important;
    top: 0 !important;
    float: none !important;
    width: auto !important;
    flex: 0 0 auto;
    justify-content: flex-end;
  }

  #app_settings .modal-header .btn_header > .btn {
    display: inline-flex !important;
    width: auto !important;
    min-height: var(--m-tap);
    padding: 0 18px;
    border-radius: 10px !important;
  }

  /* Field Setting is a single link in a `.col-2` box. `.col-2` is 16.66% at
     EVERY width - only `col-md-*` stacks - so on a phone the link sat in a
     sliver barely wide enough for one character. */
  .m-set-tile {
    flex: 0 0 100% !important;
    max-width: 100% !important;
    min-height: var(--m-tap);
    display: flex;
    align-items: center;
    margin: 0 var(--m-gutter);
    font-size: 0.86rem;
  }

} /* end @media (max-width: 991.98px) */
