/* ============================================================================
   Lasso Media — v2 CLEAN LAYOUT stylesheet
   ----------------------------------------------------------------------------
   Loaded ONLY by templates/layout/lasso_v2.php, AFTER lasso-theme.css.
   PURPOSE: give the re-skinned logged-in pages a clean slate. The clean layout
   loads NO Bootstrap CSS / portal.css / app.css / style.css / backend_header.css.
   This file therefore re-supplies — minimally and cleanly — the handful of
   grid / utility / form / component classes the shared templates still emit
   (search.php, pagination.php, ele_search_limit_bar.php, backend_header.php,
   nav elements, the converted page bodies).

   Design tokens + the .lasso-v2 component library (card/btn/tbl/badge/kpi/…)
   live in lasso-theme.css and are reused as-is. This file only adds what
   Bootstrap used to provide, tuned to the mockups (no fixed/min widths that
   cause horizontal scroll; everything stacks on mobile).

   The whole page is rendered inside <body class="lasso-v2">, so rules can be
   scoped under .lasso-v2 to guarantee they win over lasso-theme.css's own
   `.lasso-v2 .row` etc. (equal specificity → this file loads later → wins).
   ========================================================================== */

/* 1 ── RESET (clean layout only — mirrors the mockups' reset) ─────────────── */
*{ box-sizing:border-box; }
html,body{ margin:0; padding:0; }
body.lasso-v2{
  min-height:100vh;
  background:var(--bg);
  color:var(--text);
  font-family:'Inter',system-ui,-apple-system,'Segoe UI',sans-serif;
  -webkit-font-smoothing:antialiased;
}
.lasso-v2 img{ max-width:100%; }
/* Bootstrap's responsive-image helper, which this theme never defined. The
   `height:auto` half is the point: legacy templates carry hard width/height
   attributes (the category images are marked 900x400 while the files are
   960x540), so capping width alone squeezed them sideways while the attribute
   held the height at 400 — every image on /categories/images rendered
   307x400, stretched tall. Restoring `height:auto` lets them keep shape. */
.lasso-v2 .img-fluid{ max-width:100%; height:auto; }
/* Teal links apply to PAGE CONTENT only — scoped to .clsContent so this never
   overrides the nav's white link rules (.lz-user a / .lz-navstrip a), which
   share specificity with a blanket `.lasso-v2 a` and would otherwise lose to
   it on load order (turning the nav links teal). */
.lasso-v2 .clsContent a{ color:var(--teal-dark); }

/* 2 ── PAGE SHELL + MAIN CONTAINER ───────────────────────────────────────── */
/* flex column so the footer sits at/after the content, never floating mid-page */
.lv2-shell{ display:flex; flex-direction:column; min-height:100vh; }
/* Full-bleed content with a standard gutter. A 1240px centred column was tried on
   2026-08-17 and reverted the same day: this app's pages are dense — wizard steps
   split three ways, list tables run past 1500px, the dashboard sets charts side by
   side — so the cap congested the pages it was meant to tidy, and exempting a few
   of them just made the app look inconsistent from screen to screen.
   The auth pages (login/register) DO keep the centred column; they render through
   layout_lasso_website, not this shell, and are a deliberate exception. */
.lv2-main{
  flex:1 0 auto;
  width:100%;
  max-width:100%;
  margin:0;
  padding:34px var(--lm-gutter) 72px;
}
@media (max-width:640px){ .lv2-main{ padding:20px 14px 48px; } }

/* the shared footer element — full-width band that reads as a distinct "floor".
   On the grey page bg a transparent footer blends into the content, so give it
   the mockup's .app-foot treatment: a top divider line + a slightly-off band
   colour. !important beats footer.php's non-important inline margin/padding so
   the band sits flush and evenly padded without editing the shared element. */
.lv2-shell > .footer,
.lv2-main + .footer{
  margin:0 !important;
  /* 32px — the same gutter the logo, nav and page body sit on. */
  padding:16px var(--lm-gutter) !important;
  background:#E9ECEF;
  border-top:1px solid #D0D5DB;
  box-shadow:0 -5px 14px -10px rgba(0,0,0,.2);
  color:var(--muted);
}
/* footer.php sets its own padding-left/right on the two halves, which pushed
   them off that shared gutter. */
.lv2-shell > .footer > div,
.lv2-main + .footer > div{ padding-left:0 !important; padding-right:0 !important; }

/* On a phone the two halves were jammed edge to edge — the tagline wrapped onto
   two lines and ended exactly where the logo block began, with no gap at all.
   Stack them instead. The inline styles on footer.php (display:flex,
   justify-content, text-align, the logo's height:40px) are why these need
   !important, same as the band rules above. */
@media (max-width:575.98px){
  .lv2-shell > .footer,
  .lv2-main + .footer{
    flex-direction:column !important;
    align-items:flex-start !important;
    gap:14px;
  }
  .lv2-shell > .footer > div:last-child,
  .lv2-main + .footer > div:last-child{ text-align:left !important; }
  .lv2-shell > .footer img,
  .lv2-main + .footer img{ height:30px !important; }
}

/* 3 ── FLASH MESSAGES (app.css normally styles these) ────────────────────── */
.lasso-v2 .message,
.lasso-v2 .alert{
  padding:12px 16px; border-radius:10px; margin:0 0 16px;
  font-size:13.5px; font-weight:600; border:1px solid transparent; cursor:pointer;
}
.lasso-v2 .message.success,.lasso-v2 .alert-success{ background:#E6F6EC; color:#188047; border-color:#BEE6CE; }
.lasso-v2 .message.error,.lasso-v2 .message.danger,
.lasso-v2 .alert-danger,.lasso-v2 .alert-error{ background:#FDECEA; color:var(--brand-red); border-color:#F3C9C4; }
.lasso-v2 .message.warning,.lasso-v2 .alert-warning{ background:#FFF3E0; color:#B4690E; border-color:#F3D9B0; }
.lasso-v2 .message.info,.lasso-v2 .alert-info{ background:#E7F0FE; color:var(--blue); border-color:#C6DBFB; }
.lasso-v2 .message.hidden,.lasso-v2 .hidden{ display:none !important; }

/* 4 ── GRID SHIM (flexible columns that compose with the theme's gap-row) ──
   lasso-theme.css already sets `.lasso-v2 .row{display:flex;gap:12px;
   flex-wrap:wrap;align-items:center}` — great for the in-cell button rows.
   For the *grid* rows (search.php, pagination.php, the nav), we give the
   columns flexible bases so they sit side-by-side on desktop and wrap to a
   single column on narrow screens — no Bootstrap 12-col math, no overflow. */
.lasso-v2 .container-fluid{ width:100%; padding:0; margin:0; }

/* full-width columns first … */
.lasso-v2 .col-12,.lasso-v2 .col-sm-12,.lasso-v2 .col-md-12,.lasso-v2 .col-lg-12,
.lasso-v2 [class*="col-12"]{ flex:1 1 100%; max-width:100%; }
/* … then half-width columns override on elements that carry both (col-12 col-lg-6) */
.lasso-v2 .col-6,.lasso-v2 .col-sm-6,.lasso-v2 .col-md-6,.lasso-v2 .col-lg-6,
.lasso-v2 [class*="col-md-6"],.lasso-v2 [class*="col-lg-6"]{ flex:1 1 320px; max-width:100%; }
/* 8/4 split (dashboard charts) — ~2:1 on desktop, stack on mobile */
.lasso-v2 .col-md-8,.lasso-v2 .col-lg-8{ flex:2 1 420px; max-width:100%; }
.lasso-v2 .col-md-4,.lasso-v2 .col-lg-4{ flex:1 1 260px; max-width:100%; }
/* nav's grow / auto columns */
/* Bootstrap's auto-grow column. It had no rule at all, so `<div class="col">` fell
   back to the flex default and shrank to its content — a table inside one rendered
   at ~1100px in a 1536px row instead of filling it. 324 templates use it, so this
   was quietly narrowing pages all over the admin (/navlinks and /plans were how it
   surfaced). Same definition Bootstrap gives it: grow, zero basis. */
.lasso-v2 .col{ flex:1 1 0%; max-width:100%; min-width:0; }
.lasso-v2 .col-lg{ flex:1 1 auto; min-width:0; }

/* A Bootstrap grid nested inside a table cell has nowhere near the ~320px flex
   basis the shim above hands a half-column, so the two halves wrapped onto
   separate lines — the Data | Settings pair on /hibu-campaigns stacked instead
   of sitting either side of its divider. In a cell the columns simply share
   whatever width the cell has. */
.lasso-v2 td .row,
.lasso-v2 th .row{ gap:0; flex-wrap:nowrap; }
.lasso-v2 td .row > [class*="col-"],
.lasso-v2 th .row > [class*="col-"]{ flex:1 1 0; min-width:0; }

/* 4b ── REAL 12-COLUMN SPANS (the shim above deliberately skipped these) ────
   The flexible bases above cover the spans the v2 pages were designed against
   (12/6/8/4). Legacy admin pages also use the other spans, and with no rule at
   all they fell back to shrink-to-fit: the HNC big board's eight `col-lg-3` KPI
   tiles crammed onto one line at ~120px each instead of wrapping 4 + 4.
   These give the remaining spans their true Bootstrap width. The row's
   `gap:12px` is folded into the math — a span of s/12 is
   calc(s/12 * (100% + gap) - gap), so s columns plus their gaps total exactly
   100%. Each starts full-width and takes its span at the matching breakpoint,
   which is how Bootstrap's col-{bp}-{n} behaves. */
.lasso-v2 .col-1{ flex:0 0 calc(1/12 * (100% + 12px) - 12px); max-width:calc(1/12 * (100% + 12px) - 12px); }
.lasso-v2 .col-2{ flex:0 0 calc(2/12 * (100% + 12px) - 12px); max-width:calc(2/12 * (100% + 12px) - 12px); }
.lasso-v2 .col-3{ flex:0 0 calc(3/12 * (100% + 12px) - 12px); max-width:calc(3/12 * (100% + 12px) - 12px); }
.lasso-v2 .col-5{ flex:0 0 calc(5/12 * (100% + 12px) - 12px); max-width:calc(5/12 * (100% + 12px) - 12px); }
.lasso-v2 .col-7{ flex:0 0 calc(7/12 * (100% + 12px) - 12px); max-width:calc(7/12 * (100% + 12px) - 12px); }
.lasso-v2 .col-9{ flex:0 0 calc(9/12 * (100% + 12px) - 12px); max-width:calc(9/12 * (100% + 12px) - 12px); }
.lasso-v2 .col-10{ flex:0 0 calc(10/12 * (100% + 12px) - 12px); max-width:calc(10/12 * (100% + 12px) - 12px); }
.lasso-v2 .col-11{ flex:0 0 calc(11/12 * (100% + 12px) - 12px); max-width:calc(11/12 * (100% + 12px) - 12px); }
/* col-sm-4 and col-sm-8 belong in THIS block, not with the flexible md/lg 8/4
   pair above. They had no rule at either place, so they fell back to the flex
   default and shrank to their content while their col-sm-5 / col-sm-7 siblings
   sized correctly — which is what pulled the HBU order-edit form out of shape
   (it lays out on col-sm-4 eleven times, nested two rows deep). A flexible
   260px basis would not fix it: nested inside a col-lg-4 parent, three such
   columns each demand 260px and wrap onto separate lines. True 12-column math
   is what that markup was written against. */
.lasso-v2 .col-sm-1,.lasso-v2 .col-sm-2,.lasso-v2 .col-sm-3,.lasso-v2 .col-sm-4,.lasso-v2 .col-sm-5,.lasso-v2 .col-sm-7,.lasso-v2 .col-sm-8,.lasso-v2 .col-sm-9,.lasso-v2 .col-sm-10,.lasso-v2 .col-sm-11{ flex:1 1 100%; max-width:100%; }
@media (min-width:576px){
  .lasso-v2 .col-sm-1{ flex:0 0 calc(1/12 * (100% + 12px) - 12px); max-width:calc(1/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-sm-2{ flex:0 0 calc(2/12 * (100% + 12px) - 12px); max-width:calc(2/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-sm-3{ flex:0 0 calc(3/12 * (100% + 12px) - 12px); max-width:calc(3/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-sm-4{ flex:0 0 calc(4/12 * (100% + 12px) - 12px); max-width:calc(4/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-sm-5{ flex:0 0 calc(5/12 * (100% + 12px) - 12px); max-width:calc(5/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-sm-7{ flex:0 0 calc(7/12 * (100% + 12px) - 12px); max-width:calc(7/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-sm-8{ flex:0 0 calc(8/12 * (100% + 12px) - 12px); max-width:calc(8/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-sm-9{ flex:0 0 calc(9/12 * (100% + 12px) - 12px); max-width:calc(9/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-sm-10{ flex:0 0 calc(10/12 * (100% + 12px) - 12px); max-width:calc(10/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-sm-11{ flex:0 0 calc(11/12 * (100% + 12px) - 12px); max-width:calc(11/12 * (100% + 12px) - 12px); }
}
.lasso-v2 .col-md-1,.lasso-v2 .col-md-2,.lasso-v2 .col-md-3,.lasso-v2 .col-md-5,.lasso-v2 .col-md-7,.lasso-v2 .col-md-9,.lasso-v2 .col-md-10,.lasso-v2 .col-md-11{ flex:1 1 100%; max-width:100%; }
@media (min-width:768px){
  .lasso-v2 .col-md-1{ flex:0 0 calc(1/12 * (100% + 12px) - 12px); max-width:calc(1/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-md-2{ flex:0 0 calc(2/12 * (100% + 12px) - 12px); max-width:calc(2/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-md-3{ flex:0 0 calc(3/12 * (100% + 12px) - 12px); max-width:calc(3/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-md-5{ flex:0 0 calc(5/12 * (100% + 12px) - 12px); max-width:calc(5/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-md-7{ flex:0 0 calc(7/12 * (100% + 12px) - 12px); max-width:calc(7/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-md-9{ flex:0 0 calc(9/12 * (100% + 12px) - 12px); max-width:calc(9/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-md-10{ flex:0 0 calc(10/12 * (100% + 12px) - 12px); max-width:calc(10/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-md-11{ flex:0 0 calc(11/12 * (100% + 12px) - 12px); max-width:calc(11/12 * (100% + 12px) - 12px); }
}
.lasso-v2 .col-lg-1,.lasso-v2 .col-lg-2,.lasso-v2 .col-lg-3,.lasso-v2 .col-lg-5,.lasso-v2 .col-lg-7,.lasso-v2 .col-lg-9,.lasso-v2 .col-lg-10,.lasso-v2 .col-lg-11{ flex:1 1 100%; max-width:100%; }
@media (min-width:992px){
  .lasso-v2 .col-lg-1{ flex:0 0 calc(1/12 * (100% + 12px) - 12px); max-width:calc(1/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-lg-2{ flex:0 0 calc(2/12 * (100% + 12px) - 12px); max-width:calc(2/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-lg-3{ flex:0 0 calc(3/12 * (100% + 12px) - 12px); max-width:calc(3/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-lg-5{ flex:0 0 calc(5/12 * (100% + 12px) - 12px); max-width:calc(5/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-lg-7{ flex:0 0 calc(7/12 * (100% + 12px) - 12px); max-width:calc(7/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-lg-9{ flex:0 0 calc(9/12 * (100% + 12px) - 12px); max-width:calc(9/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-lg-10{ flex:0 0 calc(10/12 * (100% + 12px) - 12px); max-width:calc(10/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-lg-11{ flex:0 0 calc(11/12 * (100% + 12px) - 12px); max-width:calc(11/12 * (100% + 12px) - 12px); }
}
.lasso-v2 .col-xl-1,.lasso-v2 .col-xl-2,.lasso-v2 .col-xl-3,.lasso-v2 .col-xl-5,.lasso-v2 .col-xl-7,.lasso-v2 .col-xl-9,.lasso-v2 .col-xl-10,.lasso-v2 .col-xl-11{ flex:1 1 100%; max-width:100%; }
@media (min-width:1200px){
  .lasso-v2 .col-xl-1{ flex:0 0 calc(1/12 * (100% + 12px) - 12px); max-width:calc(1/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-xl-2{ flex:0 0 calc(2/12 * (100% + 12px) - 12px); max-width:calc(2/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-xl-3{ flex:0 0 calc(3/12 * (100% + 12px) - 12px); max-width:calc(3/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-xl-5{ flex:0 0 calc(5/12 * (100% + 12px) - 12px); max-width:calc(5/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-xl-7{ flex:0 0 calc(7/12 * (100% + 12px) - 12px); max-width:calc(7/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-xl-9{ flex:0 0 calc(9/12 * (100% + 12px) - 12px); max-width:calc(9/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-xl-10{ flex:0 0 calc(10/12 * (100% + 12px) - 12px); max-width:calc(10/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-xl-11{ flex:0 0 calc(11/12 * (100% + 12px) - 12px); max-width:calc(11/12 * (100% + 12px) - 12px); }
}
.lasso-v2 .col-lg-auto{ flex:0 0 auto; max-width:100%; }
.lasso-v2 .align-items-center{ align-items:center; }
.lasso-v2 .align-items-start{ align-items:flex-start; }
/* `align-items-end` is on 9 templates and `align-items-baseline` on 2, and
   neither was ever defined here — so a row that explicitly asked to bottom-
   align got top-aligned instead. That is what threw buttons out of line with
   the field beside them: a labelled input is taller than a bare button, so
   top-aligning sits the button level with the LABEL rather than the input.
   The category Google Audience row is the clearest case — it already carries
   `align-items-end` and was ignored. Also given a `.row`-qualified form so it
   outranks the generic `.row{align-items:center}` in lasso-theme.css. */
/* Sizing / auto-margin utilities the shim never picked up, all standard
   Bootstrap. `h-100` is on 41 templates and `mt-auto` on 8 — together they are
   the equal-height-card idiom (`card h-100` + `mt-auto` on the footer), which
   without them collapsed to ragged cards with their buttons at whatever height
   the copy happened to end. `ml-auto` / `mr-auto` push an item to one end of a
   flex row and are on 7 and 8 templates. */
.lasso-v2 .h-100{ height:100%; }
.lasso-v2 .mt-auto{ margin-top:auto; }
.lasso-v2 .mb-auto{ margin-bottom:auto; }
.lasso-v2 .ml-auto,.lasso-v2 .ms-auto{ margin-left:auto; }
.lasso-v2 .mr-auto,.lasso-v2 .me-auto{ margin-right:auto; }
.lasso-v2 .text-nowrap{ white-space:nowrap; }

.lasso-v2 .align-items-end,
.lasso-v2 .row.align-items-end{ align-items:flex-end; }
.lasso-v2 .align-items-baseline,
.lasso-v2 .row.align-items-baseline{ align-items:baseline; }

/* 5 ── DISPLAY / FLEX / SPACING UTILITY SHIMS (subset actually used) ─────── */
.lasso-v2 .d-none{ display:none !important; }
.lasso-v2 .d-block{ display:block !important; }
.lasso-v2 .d-inline-block{ display:inline-block !important; }
.lasso-v2 .d-flex{ display:flex !important; }
.lasso-v2 .flex-wrap{ flex-wrap:wrap; }
.lasso-v2 .font-weight-bold{ font-weight:700; }
.lasso-v2 .text-primary{ color:var(--teal-dark); }
.lasso-v2 .align-top{ vertical-align:top; }
.lasso-v2 .justify-content-start{ justify-content:flex-start; }
.lasso-v2 .justify-content-end{ justify-content:flex-end; }
.lasso-v2 .justify-content-center{ justify-content:center; }
.lasso-v2 .justify-content-between{ justify-content:space-between; }
.lasso-v2 .text-center{ text-align:center; }
.lasso-v2 .text-right,.lasso-v2 .text-md-right{ text-align:right; }
.lasso-v2 .text-left,.lasso-v2 .text-md-left{ text-align:left; }
.lasso-v2 .text-white{ color:#fff; }
.lasso-v2 .text-muted{ color:var(--muted); }
/* Bootstrap position utilities aren't in the clean layout; without them an
   absolutely-positioned dropdown (e.g. the trust-badge autocomplete) escapes
   to the page instead of sitting under its input. */
.lasso-v2 .position-relative{ position:relative!important; }
.lasso-v2 .position-absolute{ position:absolute!important; }
/* common Bootstrap border utilities used by the review summary cards/rows */
.lasso-v2 .border{ border:1px solid var(--line)!important; }
.lasso-v2 .border-0{ border:0!important; }
.lasso-v2 .rounded{ border-radius:10px!important; }
.lasso-v2 .w-100,.lasso-v2 .w100{ width:100%; }
.lasso-v2 .mx-auto{ margin-left:auto; margin-right:auto; }
/* margin/padding steps (Bootstrap-ish 0-3 → 0/.25/.5/1rem) */
.lasso-v2 .m-0{ margin:0; } .lasso-v2 .mb-0{ margin-bottom:0; } .lasso-v2 .mt-0{ margin-top:0; }
.lasso-v2 .mb-1{ margin-bottom:.25rem; } .lasso-v2 .mb-2{ margin-bottom:.5rem; } .lasso-v2 .mb-3{ margin-bottom:1rem; }
.lasso-v2 .mt-1{ margin-top:.25rem; } .lasso-v2 .mt-2{ margin-top:.5rem; } .lasso-v2 .mt-3{ margin-top:1rem; }
.lasso-v2 .my-1{ margin-top:.25rem; margin-bottom:.25rem; }
.lasso-v2 .mr-1,.lasso-v2 .me-1{ margin-right:.25rem; } .lasso-v2 .mr-2,.lasso-v2 .me-2{ margin-right:.5rem; }
.lasso-v2 .ml-1,.lasso-v2 .ms-1{ margin-left:.25rem; } .lasso-v2 .ml-2,.lasso-v2 .ms-2{ margin-left:.5rem; }
.lasso-v2 .p-0{ padding:0; } .lasso-v2 .p-1{ padding:.25rem; } .lasso-v2 .p-2{ padding:.5rem; }
.lasso-v2 .pt-1{ padding-top:.25rem; } .lasso-v2 .pt-2{ padding-top:.5rem; }
.lasso-v2 .pb-0{ padding-bottom:0; } .lasso-v2 .pb-1{ padding-bottom:.25rem; } .lasso-v2 .pb-2{ padding-bottom:.5rem; }
.lasso-v2 .pl-2,.lasso-v2 .ps-2{ padding-left:.5rem; } .lasso-v2 .pr-2,.lasso-v2 .pe-2{ padding-right:.5rem; }
.lasso-v2 .px-2{ padding-left:.5rem; padding-right:.5rem; } .lasso-v2 .py-2{ padding-top:.5rem; padding-bottom:.5rem; }
.lasso-v2 .no-pad{ padding:0 !important; }

/* Steps 4 and 5 (1.5rem / 3rem). The shim stopped at 3, so every -4 and -5
   utility silently did nothing on a converted page — that is 200+ uses across
   templates, `mb-4` alone in 68 of them, and it is why the welcome dashboard's
   lead buttons sat flush against the table above them (`pt-5`). Same Bootstrap
   4 scale as the steps above: 0/.25/.5/1/1.5/3rem. */
.lasso-v2 .m-4{ margin:1.5rem; } .lasso-v2 .m-5{ margin:3rem; }
.lasso-v2 .mt-4{ margin-top:1.5rem; } .lasso-v2 .mt-5{ margin-top:3rem; }
.lasso-v2 .mb-4{ margin-bottom:1.5rem; } .lasso-v2 .mb-5{ margin-bottom:3rem; }
.lasso-v2 .ml-4,.lasso-v2 .ms-4{ margin-left:1.5rem; } .lasso-v2 .ml-5,.lasso-v2 .ms-5{ margin-left:3rem; }
.lasso-v2 .mr-4,.lasso-v2 .me-4{ margin-right:1.5rem; } .lasso-v2 .mr-5,.lasso-v2 .me-5{ margin-right:3rem; }
.lasso-v2 .mx-4{ margin-left:1.5rem; margin-right:1.5rem; } .lasso-v2 .mx-5{ margin-left:3rem; margin-right:3rem; }
.lasso-v2 .my-4{ margin-top:1.5rem; margin-bottom:1.5rem; } .lasso-v2 .my-5{ margin-top:3rem; margin-bottom:3rem; }
.lasso-v2 .p-4{ padding:1.5rem; } .lasso-v2 .p-5{ padding:3rem; }
.lasso-v2 .pt-4{ padding-top:1.5rem; } .lasso-v2 .pt-5{ padding-top:3rem; }
.lasso-v2 .pb-4{ padding-bottom:1.5rem; } .lasso-v2 .pb-5{ padding-bottom:3rem; }
.lasso-v2 .pl-4,.lasso-v2 .ps-4{ padding-left:1.5rem; } .lasso-v2 .pl-5,.lasso-v2 .ps-5{ padding-left:3rem; }
.lasso-v2 .pr-4,.lasso-v2 .pe-4{ padding-right:1.5rem; } .lasso-v2 .pr-5,.lasso-v2 .pe-5{ padding-right:3rem; }
.lasso-v2 .px-4{ padding-left:1.5rem; padding-right:1.5rem; } .lasso-v2 .px-5{ padding-left:3rem; padding-right:3rem; }
.lasso-v2 .py-4{ padding-top:1.5rem; padding-bottom:1.5rem; } .lasso-v2 .py-5{ padding-top:3rem; padding-bottom:3rem; }
/* flex-grow + step-3 (1rem) margin/padding + status text colours: standard
   Bootstrap utilities the shared cards emit (ele_package_usage_cards.php etc.).
   They were unshimmed, so card internals collapsed — icon glued to the text,
   the chevron never pushed to the card edge, the progress track was invisible. */
.lasso-v2 .flex-grow-1{ flex-grow:1; }
.lasso-v2 .align-items-start{ align-items:flex-start; }
.lasso-v2 .mr-3,.lasso-v2 .me-3{ margin-right:1rem; }
.lasso-v2 .ml-3,.lasso-v2 .ms-3{ margin-left:1rem; }
.lasso-v2 .mx-2{ margin-left:.5rem; margin-right:.5rem; }
.lasso-v2 .p-3{ padding:1rem; }
.lasso-v2 .px-3{ padding-left:1rem; padding-right:1rem; }
.lasso-v2 .py-3{ padding-top:1rem; padding-bottom:1rem; }
.lasso-v2 .pt-3{ padding-top:1rem; } .lasso-v2 .pb-3{ padding-bottom:1rem; }
.lasso-v2 .text-success{ color:var(--green); }
.lasso-v2 .text-warning{ color:var(--amber); }
.lasso-v2 .text-decoration-none,.lasso-v2 a.text-decoration-none{ text-decoration:none; }

/* ── Vocabulary the shim never covered ───────────────────────────────────────
   An audit of every class the templates use against everything these two
   sheets define turned up 411 Bootstrap-vocabulary classes that are asked for
   and never answered. Each one fails silently — the markup requests a
   behaviour and simply does not get it, which is why breakage keeps surfacing
   a page at a time rather than all at once. The highest-traffic ones are
   filled in below; the count after each is how many templates use it.
   Audit is re-runnable: python3 tmp/audit-v2-css-coverage.py */

/* Tables. `table-condensed` is the Bootstrap 3 spelling of `table-sm` and is
   still on 243 templates; `table-hover` on 240 had no hover at all. */
.lasso-v2 .table-condensed th, .lasso-v2 .table-condensed td{ padding:6px 10px; }
.lasso-v2 .table-hover tbody tr:hover{ background:#F2F5F8; }
.lasso-v2 .table-borderless th, .lasso-v2 .table-borderless td{ border:0; }
/* Without this a wide table pushes the whole PAGE sideways instead of
   scrolling inside its own box. 53 templates. */
.lasso-v2 .table-responsive{ display:block; width:100%; overflow-x:auto; -webkit-overflow-scrolling:touch; }
.lasso-v2 .align-middle{ vertical-align:middle; }

/* Floats. `pull-right` (Bootstrap 3) was shimmed earlier; its Bootstrap 4
   replacement was not, and 82 templates use that one. */
.lasso-v2 .float-right{ float:right; }
.lasso-v2 .float-left{ float:left; }
.lasso-v2 .float-none{ float:none; }

/* Grid offsets — 68 templates lean on these to indent a form column. */
@media (min-width:992px){
  .lasso-v2 .offset-lg-1{ margin-left:calc(1/12 * 100%); }
  .lasso-v2 .offset-lg-2{ margin-left:calc(2/12 * 100%); }
  .lasso-v2 .offset-lg-3{ margin-left:calc(3/12 * 100%); }
  .lasso-v2 .offset-lg-4{ margin-left:calc(4/12 * 100%); }
}
@media (min-width:768px){
  .lasso-v2 .offset-md-1{ margin-left:calc(1/12 * 100%); }
  .lasso-v2 .offset-md-2{ margin-left:calc(2/12 * 100%); }
  .lasso-v2 .offset-md-3{ margin-left:calc(3/12 * 100%); }
}

/* An offset column must not also grow. col-lg-4/6/8 are shimmed with a flex-grow
   above so dashboard cards fill their row — but a column carrying an offset is
   the centred-form idiom (indent a third, occupy a third). Growing swallowed the
   space the offset had reserved on the other side, so every such form sat pinned
   to the right edge with a blank third beside it (/campaigns/edit was how this
   surfaced). Give an offset column the rigid 12-col share its offset assumes.
   col-lg-10 and the other odd widths already have rigid rules and are untouched. */
@media (min-width:992px){
  .lasso-v2 .col-lg-4[class*="offset-lg-"]{ flex:0 0 calc(4/12 * (100% + 12px) - 12px); max-width:calc(4/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-lg-6[class*="offset-lg-"]{ flex:0 0 calc(6/12 * (100% + 12px) - 12px); max-width:calc(6/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-lg-8[class*="offset-lg-"]{ flex:0 0 calc(8/12 * (100% + 12px) - 12px); max-width:calc(8/12 * (100% + 12px) - 12px); }
}

/* Card sub-parts. The theme styles `.card` as one padded surface, so these
   only need to space and separate themselves rather than add padding again. */
.lasso-v2 .card-header{ font-weight:700; color:var(--ink); padding-bottom:10px; margin-bottom:14px; border-bottom:1px solid var(--line); background:none; }
.lasso-v2 .card-footer{ padding-top:12px; margin-top:14px; border-top:1px solid var(--line); background:none; }
.lasso-v2 .card-title{ font-weight:700; font-size:16px; color:var(--ink); margin:0 0 6px; }
.lasso-v2 .card-text{ color:var(--text); margin:0 0 8px; }

/* Text + background colours still missing from the palette. */
.lasso-v2 .text-danger{ color:var(--brand-red); }
.lasso-v2 .text-info{ color:var(--blue); }
.lasso-v2 .text-dark{ color:var(--ink); }
.lasso-v2 .text-secondary{ color:var(--muted); }
.lasso-v2 .text-uppercase{ text-transform:uppercase; }
.lasso-v2 .text-lowercase{ text-transform:lowercase; }
.lasso-v2 .text-capitalize{ text-transform:capitalize; }
.lasso-v2 .bg-white{ background-color:#fff; }
.lasso-v2 .bg-light{ background-color:var(--bg); }
.lasso-v2 .alert-secondary{ background:#F1F3F5; color:var(--text); border-color:var(--line); }

/* Small control sizes. */
.lasso-v2 input.form-control-sm, .lasso-v2 select.form-control-sm, .lasso-v2 .form-control-sm{ padding:5px 9px!important; font-size:12.5px; }
.lasso-v2 .input-group-sm > .form-control, .lasso-v2 .input-group-sm > .input-group-prepend > .input-group-text,
.lasso-v2 .input-group-sm > .input-group-append > .input-group-text{ padding:5px 9px; font-size:12.5px; }

/* Buttons: the two legacy size/variant names still in the templates, plus the
   grouping wrapper. `btn-xs` is Bootstrap 3; `btn-default` is its neutral. */
.lasso-v2 .btn-xs{ padding:5px 11px; font-size:12.5px; }
.lasso-v2 .btn-default{ background:#fff; color:var(--text); border:1.5px solid var(--line); }
.lasso-v2 .btn-default:hover{ border-color:#CBD1D8; color:var(--ink); }
.lasso-v2 .btn-link{ background:none; border-color:transparent; color:var(--teal-dark); padding:0; box-shadow:none; }
.lasso-v2 .btn-link:hover{ text-decoration:underline; }
.lasso-v2 .btn-group{ display:inline-flex; gap:6px; vertical-align:middle; }

/* Position + shadow. `sticky-top` is on 15 templates INCLUDING the category
   sub-nav sidebar, which has been asking to stay in view and never did. */
.lasso-v2 .sticky-top{ position:sticky; top:0; z-index:1020; }
.lasso-v2 .shadow-sm{ box-shadow:0 1px 2px rgba(20,25,35,.08); }
.lasso-v2 .shadow{ box-shadow:var(--card-shadow); }
.lasso-v2 .shadow-none{ box-shadow:none; }

/* Remaining spacing steps in the 1/3 range that were skipped. */
.lasso-v2 .pl-0,.lasso-v2 .ps-0{ padding-left:0; }
.lasso-v2 .pr-0,.lasso-v2 .pe-0{ padding-right:0; }
.lasso-v2 .pl-1,.lasso-v2 .ps-1{ padding-left:.25rem; }
.lasso-v2 .pr-1,.lasso-v2 .pe-1{ padding-right:.25rem; }
.lasso-v2 .pl-3,.lasso-v2 .ps-3{ padding-left:1rem; }
.lasso-v2 .pr-3,.lasso-v2 .pe-3{ padding-right:1rem; }
.lasso-v2 .py-1{ padding-top:.25rem; padding-bottom:.25rem; }
.lasso-v2 .py-2{ padding-top:.5rem; padding-bottom:.5rem; }
.lasso-v2 .px-1{ padding-left:.25rem; padding-right:.25rem; }
.lasso-v2 .px-2{ padding-left:.5rem; padding-right:.5rem; }

/* Bootstrap 5 gutter classes used on a few rows already converted by hand. */
.lasso-v2 .g-2{ gap:.5rem; }
.lasso-v2 .g-3{ gap:1rem; }

/* Wider modal — 10 templates open a large dialog and got the default width. */
.lasso-v2 .modal-lg{ max-width:800px; }

/* ── Second pass: the shared names still unanswered ──────────────────────────
   Same audit, filtered to classes used by two or more templates so page-local
   names (which their own page styles) drop out. Public marketing pages are
   left out of this: they render on a different shell entirely, so a carousel
   or a site navbar is not this theme's problem. */

/* The extra-large column set skipped exactly the spans people use: 1,2,3,5,7,
   9,10,11 were defined and 4, 6, 8 and 12 were not, so a `col-xl-4` shrank to
   fit its content instead of taking a third. The task board is laid out on it. */
@media (min-width:1200px){
  .lasso-v2 .col-xl-4{ flex:0 0 calc(4/12 * (100% + 12px) - 12px); max-width:calc(4/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-xl-6{ flex:0 0 calc(6/12 * (100% + 12px) - 12px); max-width:calc(6/12 * (100% + 12px) - 12px); }
  .lasso-v2 .col-xl-8{ flex:0 0 calc(8/12 * (100% + 12px) - 12px); max-width:calc(8/12 * (100% + 12px) - 12px); }
}
.lasso-v2 .col-xl-12{ flex:1 1 100%; max-width:100%; }

/* Dropdowns. Only the open/closed switch was defined, so the panel appeared
   but sat in the page flow unstyled with bare links inside it.
   NB: the red-strip mega-menu is excluded from both rules. It carries the same
   Bootstrap classes but is styled by `.lz-dropdown` / `.lz-dropdown-panel` in
   lasso-theme.css, which loads FIRST — so an unqualified rule here silently
   wins on equal specificity and undoes it: `position:relative` on the <li>
   makes the narrow nav link the panel's containing block (it must stay
   `static` so the panel can span the page), and the box styles override the
   panel's own padding, margin and 1120px max-width. Together they collapse a
   wide multi-column menu into a single narrow column. */
.lasso-v2 .dropdown:not(.lz-dropdown){ position:relative; }
.lasso-v2 .dropdown-menu:not(.lz-dropdown-panel){
  min-width:180px; padding:6px 0; margin-top:4px; list-style:none;
  background:#fff; border:1px solid var(--line); border-radius:10px;
  box-shadow:0 8px 20px rgba(20,25,35,.12);
}
.lasso-v2 .dropdown-menu-right{ right:0; left:auto; }
.lasso-v2 .dropdown-item{
  display:block; width:100%; padding:7px 14px; font-size:13.5px;
  color:var(--text); text-decoration:none; background:none; border:0; text-align:left;
}
.lasso-v2 .dropdown-item:hover{ background:#F2F5F8; color:var(--ink); text-decoration:none; }
.lasso-v2 .dropdown-toggle{ cursor:pointer; }

/* The Actions menu (element/ele_dropdown_buttons) holds buttons, not dropdown-items:
   one action per row, each filling the panel. app.css states the same rule, but this
   layout deliberately does not load app.css — so without a copy here `.lasso-v2 .btn`'s
   inline-flex wins and four full-size actions wrap two-per-row inside the panel.
   Qualified with .dropdown-menu so it ties the :not(.lz-dropdown-panel) rule above on
   specificity and wins on order; the bare class alone would lose its padding. */
.lasso-v2 .dropdown-menu.clsDropdownMenuLinks{ min-width:190px; padding:6px; }
.lasso-v2 .clsDropdownMenuLinks > .btn{
  display:flex; justify-content:center; width:100%;
  margin:0 0 6px; padding:8px 12px; font-size:13px;
}
.lasso-v2 .clsDropdownMenuLinks > .btn:last-child{ margin-bottom:0; }

/* Contextual borders — used to colour-code a panel by state. */
.lasso-v2 .border-danger{ border-color:var(--brand-red)!important; }
.lasso-v2 .border-warning{ border-color:var(--amber)!important; }
.lasso-v2 .border-success{ border-color:var(--green)!important; }
.lasso-v2 .border-info{ border-color:var(--blue)!important; }
.lasso-v2 .border-top{ border-top:1px solid var(--line)!important; }
.lasso-v2 .border-bottom{ border-bottom:1px solid var(--line)!important; }
.lasso-v2 .border-left,.lasso-v2 .border-start{ border-left:1px solid var(--line)!important; }
.lasso-v2 .border-right,.lasso-v2 .border-end{ border-right:1px solid var(--line)!important; }
.lasso-v2 .rounded-2{ border-radius:8px!important; }
.lasso-v2 .rounded-circle{ border-radius:50%!important; }

/* Button variants and the full-width modifier. */
.lasso-v2 .btn-block{ display:flex; width:100%; }
.lasso-v2 .btn-lg{ padding:13px 24px; font-size:15px; }
.lasso-v2 .btn-light{ background:#F1F3F5; color:var(--text); border-color:var(--line); }
.lasso-v2 .btn-light:hover{ background:#E7EAEE; color:var(--ink); }
.lasso-v2 .btn-outline-warning{ background:#fff; color:var(--amber); border:1.5px solid var(--amber); }
.lasso-v2 .btn-outline-warning:hover{ background:var(--amber); color:#fff; }
/* The file-input idiom: a styled button with a transparent file field laid over
   it. Without the overlay the raw browser file control shows through. */
.lasso-v2 .btn-file{ position:relative; overflow:hidden; display:inline-block; }
.lasso-v2 .btn-file input[type="file"]{
  position:absolute; top:0; right:0; min-width:100%; min-height:100%;
  opacity:0; cursor:pointer; display:block;
}

/* Form helpers. */
.lasso-v2 .form-label{ display:block; font-weight:600; font-size:13px; color:var(--ink); margin-bottom:6px; }
.lasso-v2 .form-text{ display:block; font-size:12px; color:var(--muted); margin-top:4px; }
.lasso-v2 .form-check{ position:relative; display:block; padding-left:1.5rem; }
.lasso-v2 .form-check-input{ position:absolute; left:0; margin-top:.2rem; }
.lasso-v2 .form-check-inline{ display:inline-flex; align-items:center; gap:6px; padding-left:0; margin-right:1rem; }
.lasso-v2 .form-lh{ line-height:2; }

/* List groups — the audience-segment picker is built on these. */
.lasso-v2 .list-group{ display:flex; flex-direction:column; padding-left:0; margin-bottom:0; list-style:none; border-radius:10px; }
.lasso-v2 .list-group-item{
  position:relative; display:block; padding:10px 14px;
  background:#fff; border:1px solid var(--line); border-bottom-width:0; color:var(--text);
}
.lasso-v2 .list-group-item:first-child{ border-top-left-radius:10px; border-top-right-radius:10px; }
.lasso-v2 .list-group-item:last-child{ border-bottom-width:1px; border-bottom-left-radius:10px; border-bottom-right-radius:10px; }
.lasso-v2 .list-group-item.active{ background:#FEF6F5; border-color:var(--brand-red); color:var(--ink); }

/* A tall modal body needs its own scroll, or the dialog runs off the screen. */
.lasso-v2 .modal-dialog-scrollable{ max-height:calc(100% - 3.5rem); }
.lasso-v2 .modal-dialog-scrollable .modal-content{ max-height:100%; overflow:hidden; }
.lasso-v2 .modal-dialog-scrollable .modal-body{ overflow-y:auto; }

/* Odds and ends still in use. */
.lasso-v2 .spinner-border-sm{ width:1rem; height:1rem; border-width:.15em; }
.lasso-v2 .w-auto{ width:auto!important; }
.lasso-v2 .flex-shrink-0{ flex-shrink:0; }
.lasso-v2 .fixed-bottom{ position:fixed; right:0; bottom:0; left:0; z-index:1030; }
.lasso-v2 .nav-fill > .nav-item{ flex:1 1 auto; text-align:center; }
/* Visually hidden but still read aloud — the accessible label on 5 templates. */
.lasso-v2 .sr-only,.lasso-v2 .visually-hidden{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0;
}
@media (min-width:768px){ .lasso-v2 .d-md-block{ display:block!important; } .lasso-v2 .d-md-none{ display:none!important; } .lasso-v2 .d-md-flex{ display:flex!important; } }

/* Remaining spacing steps. */
.lasso-v2 .m-2{ margin:.5rem; } .lasso-v2 .m-3{ margin:1rem; }
.lasso-v2 .mx-1{ margin-left:.25rem; margin-right:.25rem; }
.lasso-v2 .my-2{ margin-top:.5rem; margin-bottom:.5rem; }
.lasso-v2 .my-0{ margin-top:0; margin-bottom:0; }
.lasso-v2 .py-0{ padding-top:0; padding-bottom:0; }
@media (min-width:576px){
  .lasso-v2 .mr-sm-2,.lasso-v2 .me-sm-2{ margin-right:.5rem; }
  .lasso-v2 .my-sm-0{ margin-top:0; margin-bottom:0; }
}
/* Bootstrap progress bar (usage cards): supply track + fill (CSS not loaded) */
.lasso-v2 .progress{ background:var(--bg); border-radius:6px; overflow:hidden; }
.lasso-v2 .progress-bar{ height:100%; }

/* responsive display (Bootstrap-4 lg breakpoint = 992px) */
@media (min-width:992px){
  .lasso-v2 .d-lg-none{ display:none !important; }
  .lasso-v2 .d-lg-block{ display:block !important; }
  .lasso-v2 .d-lg-flex{ display:flex !important; }
}
@media (max-width:991.98px){
  .lasso-v2 .d-lg-block,.lasso-v2 .d-lg-flex{ display:none; }  /* shown only ≥lg */
}

/* 6 ── COLLAPSE / NAVBAR SHIM (Bootstrap JS toggles `.show`) ──────────────── */
.lasso-v2 .collapse:not(.show){ display:none; }
@media (min-width:992px){
  /* desktop nav is always visible via d-lg-flex (…!important above wins over :not(.show)) */
  .lasso-v2 .navbar-collapse.d-lg-flex{ display:flex !important; }
}
.lasso-v2 .navbar-collapse{ flex-basis:100%; flex-grow:1; align-items:center; }
@media (max-width:991.98px){
  /* Mobile: BS4 collapse JS opens #mobileNav by adding `.show`, but the element
     also carries `d-lg-flex`, whose ≤lg rule (display:none) otherwise keeps it
     hidden — so the hamburger looked dead. Re-reveal the opened nav below lg.
     Specificity (4 classes) + !important beats the d-lg-flex display:none. */
  .lasso-v2 .navbar-collapse.collapse.show{ display:block !important; }
}

/* Dropdowns: Bootstrap CSS (which hides .dropdown-menu until its JS adds .show)
   is not loaded — without this the admin mega-menu panels all render expanded.
   BS4 dropdown JS + Popper toggle `.show` and position the open panel inline. */
.lasso-v2 .dropdown-menu{ position:absolute; z-index:1000; display:none; }
.lasso-v2 .dropdown-menu.show{ display:block; }

/* Bootstrap's `.nav-link` base — `display:block` plus no underline — is part of
   the same missing stylesheet. Without it a tab strip built on a container the
   theme doesn't name (`.meta-tabs`, not `.nav-tabs`/`.nav-pills`) renders as
   inline underlined anchors: the 9px/16px padding the page sets cannot lay out
   against an inline box, and the active tab's bottom border sits on the text
   rather than under the tab. Deliberately bare, so any custom tab container
   gets it; `.lz-partner .navbar-nav .nav-link` re-sets its own padding after
   this and is unaffected. */
.lasso-v2 .nav-link{ display:block; text-decoration:none; }
.lasso-v2 .nav-link:hover, .lasso-v2 .nav-link:focus{ text-decoration:none; }

/* Tabs: the same story as the dropdowns above. `.tab-pane` is hidden by
   Bootstrap CSS, not by the tab JS — the JS only moves `.show`/`.active`
   between panes. With Bootstrap CSS absent nothing hides the inactive ones, so
   every pane rendered at once and the tab strip above them degraded into a row
   of plain links over a wall of stacked content. Reported on
   /hnc-orders/campaign-validation/{id}?partner=meta, whose panes are
   `.tab-content.meta-tabpane > .tab-pane` and whose hand-rolled activate()
   (meta_tab.php) toggles exactly these two classes.
   22 templates use .tab-content, so this is a shared shim, not a page fix.
   Scoped `.tab-content > .tab-pane` rather than a bare `.tab-pane` so a nested
   sub-tab set (.meta-subpane) only answers to its own container. */
.lasso-v2 .tab-content > .tab-pane{ display:none; }
.lasso-v2 .tab-content > .tab-pane.active{ display:block; }
/* `.fade` without Bootstrap is inert, so a pane that never gains `.show` would
   sit at full opacity anyway; defining both halves keeps the transition the
   markup already asks for instead of snapping. */
.lasso-v2 .tab-content > .tab-pane.fade{ opacity:0; transition:opacity .15s linear; }
.lasso-v2 .tab-content > .tab-pane.fade.show{ opacity:1; }

/* dev_header (LOGS / timestamp — admin only, right of the red strip) emits
   Bootstrap `navbar-nav flex-row`, which the clean layout doesn't style, so its
   <ul> renders disc bullets stacked vertically. Reset to a bullet-free inline row. */
.lasso-v2 .lz-partner .navbar-nav{
  list-style:none; margin:0; padding:0;
  display:flex; flex-direction:row; flex-wrap:wrap;
  align-items:center; justify-content:flex-end; gap:2px 16px;
}
.lasso-v2 .lz-partner .navbar-nav .nav-item{ list-style:none; margin:0; }
.lasso-v2 .lz-partner .navbar-nav .nav-link{ padding:0; }
/* Match the primary nav links' type — without this the LOGS counter, the clock
   and the release badge inherit body size and read noticeably larger than
   "Dashboard … Navpage" sitting beside them. */
.lasso-v2 .lz-partner .navbar-nav .nav-link{
  font-family:'Inter',system-ui,sans-serif; font-size:13.5px; font-weight:600;
}

/* 7 ── FORM SHIMS (search bar: ele_search_limit_bar.php) ─────────────────── */
.lasso-v2 .form-inline{ display:flex; flex-flow:row wrap; align-items:center; }
.lasso-v2 .form-row{ display:flex; flex-wrap:wrap; align-items:center; gap:8px; }
/* `.form-group` was written for the search toolbar and made EVERY one of them a
   centred flex row. That is only Bootstrap's behaviour inside `.form-inline`;
   on its own a form group is an ordinary block, and legacy forms rely on that —
   several override CakePHP's field wrapper to emit one. Made flex everywhere,
   it laid each label alongside its own field and sized the field to its text,
   so the invoice pages showed "Bill Monthly" and "Bill Weekly" beside two
   different-width selects, with the longer label wrapping onto two lines.
   Restored to the real rule: block by default, flex in a toolbar. The toolbar
   markup carries `form-inline` (the search bar and the shared page heading both
   do). A form group that ALSO carries a layout class must keep that class's
   layout — this file loads after the one defining `.row`, so at equal
   specificity a bare `display:block` here silently outranked it and stacked
   rows that were meant to run across: the Key / Value / Add row on
   /hnc-orders/consolidated-targeting is `form-group row`. */
.lasso-v2 .form-group{ margin:0 0 12px; display:block; }
.lasso-v2 .form-inline .form-group,
.lasso-v2 .form-group.form-inline,
.lasso-v2 .form-group.row,
.lasso-v2 .form-group.form-row{ margin:0; display:flex; align-items:center; }
.lasso-v2 .form-group.replaceThisClass{ margin:0; }
/* ...and the same stacked label -> full-width field rhythm the `div.input`
   wrapper gets above, since a form group is the other wrapper legacy forms
   emit. Toolbars opt back out: there the label belongs beside its control and
   the control is sized to its own content. */
.lasso-v2 .form-group > label{ display:block; font-weight:600; font-size:13px; color:var(--ink); margin-bottom:6px; }
.lasso-v2 .form-group > input.form-control,
.lasso-v2 .form-group > select.form-control,
.lasso-v2 .form-group > textarea.form-control{ display:block; width:100%; max-width:100%; }
.lasso-v2 .form-inline .form-group > label{ display:inline-block; margin-bottom:0; }
.lasso-v2 .form-inline .form-group > input.form-control,
.lasso-v2 .form-inline .form-group > select.form-control{ display:inline-block; width:auto; }

/* A short form on a wide admin page reads badly stretched edge to edge. */
.lasso-v2 .form-narrow{ max-width:520px; margin-left:auto; margin-right:auto; }

/* The invoice form wants TRUE half-width columns, not the flexible bases the
   v2-designed pages are built on. At `flex:1 1 320px` four half-columns packed
   onto ONE row, so Memo, Notes, Attachment and Payment Link shared a line and
   the Notes text was clipped inside a quarter-width box. Same treatment the
   category asset forms get, scoped to this form. */
@media (min-width:992px){
  .lasso-v2 #invoiceForm .row > .col-lg-6{
    flex:0 0 calc(6/12 * (100% + 12px) - 12px); max-width:calc(6/12 * (100% + 12px) - 12px);
  }
}

/* Bootstrap's inline list, used by the month/week quick-links. Unstyled here it
   fell back to a bulleted block list, so "This Month | Last Month" stacked
   vertically with a stray separator between the bullets. */
.lasso-v2 .list-inline{ list-style:none; margin:0; padding-left:0; display:inline-flex; flex-wrap:wrap; align-items:center; gap:4px; }
.lasso-v2 .list-inline-item{ display:inline-block; list-style:none; }

/* The search bar's extra-content and download slots carry `w100`, which the
   utility shim honours as width:100% — that forces its own line and pushed the
   Download button above the page title instead of leaving it inline with the
   search controls, where the old layout puts it. */
.lasso-v2 .clsSearchBarDiv .clsBlockDiv,
.lasso-v2 .clsSearchBarDiv .clsDownloadBtnDiv{ width:auto; }
/* Inside modals (Special Offer, Lead Form URL) the global inline .form-group
   above jams the label against the field. Stack them with real spacing. */
.lasso-v2 .modal-body .form-group{ display:block; margin-bottom:1rem; }
.lasso-v2 .modal-body .form-group:last-child{ margin-bottom:0; }
.lasso-v2 .modal-body .form-group > label{ display:block; font-weight:600; font-size:13px; color:var(--ink); margin-bottom:6px; }
.lasso-v2 .modal-body .form-control{ width:100%; }
/* Search toolbar controls (ele_search_limit_bar): Bootstrap's .form-control
   padding/height is NOT loaded in this clean layout, so the raw search input
   renders short and cramped. Size the field, limit-select and Search/Reset
   buttons to one consistent ~40px row and give the field the mockup's width. */
.lasso-v2 #searchForm .form-control{ height:40px; }
.lasso-v2 #searchForm input.form-control,
.lasso-v2 #searchForm select.form-control{ padding:8px 14px; }
.lasso-v2 input[type="search"].form-control{ min-width:260px; }
.lasso-v2 .custom-select,.lasso-v2 select.form-control{ min-height:40px; }
.lasso-v2 .btn-sm{ padding:8px 14px; font-size:12.5px; border-radius:9px; }
/* the Search button carries .form-control.btn — keep it button-sized, not block */
.lasso-v2 button.form-control,.lasso-v2 a.form-control.btn{ width:auto; display:inline-flex; }

/* Legacy edit/add forms (`.formDiv`, ~386 templates) built with plain
   $this->Form->control(). Bootstrap's `.form-control{display:block;width:100%}`
   and its block-ish label are NOT loaded in this layout, and the shims above are
   scoped to #searchForm / .modal-body — so every field on a converted form page
   collapsed to the browser's intrinsic size (textarea 221px, text input 236px)
   and its label sat *inline beside* the box instead of above it. Selects even
   overflowed their grid column. Symptom: /hnc-call-recordings/edit/<sid> had
   "Call Summary", "Call Transcription" and "Remarks" labels hanging off the
   bottom-left of undersized boxes. Restore the stacked label -> full-width field
   rhythm the legacy stack gave these forms. Element-scoped so button/anchor
   .form-control (the Search button above) is untouched. */
.lasso-v2 .formDiv input.form-control,
.lasso-v2 .formDiv select.form-control,
.lasso-v2 .formDiv textarea.form-control{ display:block; width:100%; max-width:100%; }
/* ...but NOT when the field is inside an input-group. The shim above is
   `width:100%` at specificity (0,3,1), which outranks the generic input-group
   rule in lasso-theme.css (0,3,0) — so the field ate the whole row and pushed
   its own addons onto separate lines. That is what stacked the index, the field
   and the character count vertically on the category Headlines and Descriptions
   pages, both of which sit inside a `.formDiv`. Listed with `.formDiv` first so
   this outranks the shim rather than merely tying with it. */
.lasso-v2 .formDiv .input-group > input.form-control,
.lasso-v2 .formDiv .input-group > select.form-control,
.lasso-v2 .formDiv .input-group > textarea.form-control,
.lasso-v2 .input-group > input.form-control,
.lasso-v2 .input-group > select.form-control,
.lasso-v2 .input-group > textarea.form-control{
  display:block; flex:1 1 auto; width:1%; max-width:none; min-width:0;
}
.lasso-v2 .formDiv .input > label{ display:block; font-weight:600; font-size:13px; color:var(--ink); margin-bottom:6px; }
.lasso-v2 .formDiv .input{ margin-bottom:10px; }

/* Same treatment keyed off the field wrapper instead of the page wrapper. Not
   every legacy form remembered the `.formDiv` div — /hibus/edit is the worst
   case, a ~60-field form with none of it, where every control fell back to the
   browser's intrinsic size and the page read as scattered boxes. `div.input` is
   what $this->Form->control() emits for a stacked field on EVERY legacy form,
   so it reaches them whether or not the page wrapper is there. Scoped to the
   direct child so `.input-group` / `.input-date-select` are untouched. */
.lasso-v2 .input > input.form-control,
.lasso-v2 .input > select.form-control,
.lasso-v2 .input > textarea.form-control{ display:block; width:100%; max-width:100%; }
.lasso-v2 .input > label{ display:block; font-weight:600; font-size:13px; color:var(--ink); margin-bottom:6px; }
/* ...except when that wrapper is itself a toolbar. The stacked rhythm above is the right
   default for a form field, and the wrong one for a row of controls meant to read as a
   sentence. The month picker shared by every report (ele_month_quicklinks) wraps its label,
   field and Submit in `div.input.select.form-inline`, so the field took the full row and
   put "Month:" above it and Submit below — three stacked lines where one was intended.
   Listed after and one class heavier than the `.input >` rules so it outranks them rather
   than tying, the same reason the `.input-group` exception above is written this way. */
.lasso-v2 .input.form-inline > input.form-control,
.lasso-v2 .input.form-inline > select.form-control,
.lasso-v2 .input.form-inline > .custom-select{ display:inline-block; width:auto; max-width:none; vertical-align:middle; }
.lasso-v2 .input.form-inline > label{ display:inline-flex; align-items:center; width:auto; margin-bottom:0; margin-right:6px; }

/* ...except when a small info icon follows the label. The icon is part of the
   label — the legacy markup emits `<label>Rate</label>&nbsp;<i class="fa
   fa-info-circle">` — and a block label pushed it onto a line of its own, with
   the field then dropping to a third line. On the invoice form that left the
   Rate column a full row lower than Qty and Amount beside it, and the same on
   Invoice Type. Seven templates use the pattern, so it is fixed here rather
   than in each one. Keyed on the icon actually being there, so every other
   label keeps its own line. */
.lasso-v2 .input > label:has(+ i.fa-info-circle),
.lasso-v2 .form-group > label:has(+ i.fa-info-circle),
.lasso-v2 .formDiv .input > label:has(+ i.fa-info-circle){
  display:inline-block; margin-bottom:4px;
}

/* Radio choices meant to read across the row, not down it. Without this every
   option became a block and the Direction question on the invoice form listed
   Outbound and Inbound on separate lines. Values from app.css, which this
   layout does not load. */
.lasso-v2 .radioInline{ display:inline-block; }
.lasso-v2 .radioInline input[type="radio"]{ margin:0 10px; }
.lasso-v2 .radioInline > label{ display:inline-block; font-weight:400; margin-bottom:0; }
.lasso-v2 .radioInline > label > p{ display:inline; padding-left:20px; padding-right:5px; margin:0; }

/* The one label that is SUPPOSED to sit beside its field rather than above it
   — "Total Invoice Amount" on the invoice form. Without the float it took the
   full column width, wrapped onto two lines and left the amount box stranded
   beside a two-line label. */
.lasso-v2 .clsLabelInputInline{ float:left; margin-right:15px; margin-bottom:0; line-height:37px; }

/* Extra breathing room between fields on forms that ask for it. */
.lasso-v2 .formSpacing div.input{ margin-bottom:15px; }

/* File pickers. With no rule the raw browser control sat flush against the
   field above it on the invoice attachment block. */
.lasso-v2 .form-control-file{ display:block; width:100%; font-size:13.5px; }

/* "OR" separators between two alternative ways to fill a form — a vertical
   rule with the word floating mid-height (used between the two panels on the
   invoice start step) and a plain horizontal one. app.css carries these and is
   not loaded here, so the rule and its centring vanished and only the bare
   word was left. `.wrapper` is a common name, so the positioning context is
   keyed on the divider line actually being inside it. */
.lasso-v2 .wrapper:has(> .line){ position:relative; }
.lasso-v2 .wrapper > .line{
  position:absolute; left:50%; top:0; bottom:0; width:1px;
  background:var(--line); z-index:1;
}
.lasso-v2 .wordwrapper{
  text-align:center; height:12px; position:absolute;
  left:0; right:0; top:50%; margin-top:-12px; z-index:2;
}
.lasso-v2 .word{
  color:var(--muted); text-transform:uppercase; letter-spacing:1px;
  padding:3px; font-weight:700; font-size:12px; background:#fff; text-align:center;
}
/* The horizontal counterpart, where the two choices sit one above the other.
   The templates used to draw it as a row of hyphens around the word, which
   read as broken markup rather than a divider. */
.lasso-v2 .or-divider{
  display:flex; align-items:center; gap:10px; margin:14px 0;
  color:var(--muted); font-weight:700; font-size:12px;
  letter-spacing:.08em; text-transform:uppercase;
}
.lasso-v2 .or-divider::before,
.lasso-v2 .or-divider::after{ content:""; flex:1 1 auto; height:1px; background:var(--line); }

/* Legacy form rows must top-align. `.lasso-v2 .row{align-items:center}` (the
   nav/toolbar default) vertically centres every column, so a row mixing a tall
   textarea with short text inputs pushed the short fields to the middle and
   their labels out of line with each other — the "Setting value" column on
   /settings/edit sat visibly higher than Name/Skey/Category beside it.
   `.form-row` is a Bootstrap row variant that this layout never defined, so its
   children were not laid out at all. */
/* ...but only as a DEFAULT. Qualified with three classes, this used to beat
   every `align-items-*` utility (two classes), so a form row that explicitly
   asked to bottom- or centre-align was silently top-aligned anyway. Rows that
   state their own alignment now opt out. */
.lasso-v2 .formDiv .row:not(.align-items-end):not(.align-items-center):not(.align-items-baseline),
.lasso-v2 .row.form:not(.align-items-end):not(.align-items-center):not(.align-items-baseline),
.lasso-v2 .form-row:not(.align-items-end):not(.align-items-center):not(.align-items-baseline){ align-items:flex-start; }
.lasso-v2 .form-row{ display:flex; flex-wrap:wrap; gap:12px; }

/* The category asset forms need TRUE 12-column spans, not the flexible bases.
   `.col-lg-6` is `flex:1 1 320px` and `.col-lg-4` is `flex:1 1 260px` above —
   deliberately flexible, because the v2-designed pages want half-cards that
   reflow on narrow screens. Legacy markup written against real Bootstrap does
   not survive that: inside the ~1500px `main` column, a 320px basis packs FOUR
   `col-lg-6` fields per row and a 260px basis packs FIVE `col-lg-4` fields, so
   Descriptions laid out 4-across instead of 2 and Headlines 5-across instead
   of 3. Scoped to `.form-categories` (the 10 category asset templates) rather
   than fixing the global bases, which the v2 pages are built on.
   Applies to the plain `.row` inside these forms as well as the `.form-row`:
   the images page tiles its thumbnails in a plain row, where the flexible
   basis packed four across and then let a lone fifth tile grow to the full
   width of the page — one image three times the size of its neighbours. */
@media (min-width:992px){
  .lasso-v2 .form-categories .form-row > .col-lg-4,
  .lasso-v2 .form-categories .row > .col-lg-4{ flex:0 0 calc(4/12 * (100% + 12px) - 12px); max-width:calc(4/12 * (100% + 12px) - 12px); }
  .lasso-v2 .form-categories .form-row > .col-lg-6,
  .lasso-v2 .form-categories .row > .col-lg-6{ flex:0 0 calc(6/12 * (100% + 12px) - 12px); max-width:calc(6/12 * (100% + 12px) - 12px); }
}
/* inline choice rows keep their own compact rhythm */
.lasso-v2 .formDiv .form-check-label,
.lasso-v2 .formDiv .radio label{ display:inline-block; font-weight:400; margin-bottom:0; }
.lasso-v2 .formDiv .input.radio,
.lasso-v2 .formDiv .input.checkbox{ margin-bottom:0; }

/* 8 ── LEGACY PORTAL CLASS SHIMS (portal.css is not loaded) ──────────────── */

/* Highlight swatches from app.css, which this layout deliberately does not load.
   Both set their own white text, and `.text-white` IS defined here — so on a
   converted page the text colour applied and the background did not, leaving
   white-on-white. Symptom: the Price / Call column on /hnc-orders/report4 read
   as blank cells. decidePriceColor() in app_functions.php emits `bg_blue
   text-white`, and LassoRates/lasso.php uses the same pair on its duration
   cells. Values copied verbatim from app.css so converted and unconverted pages
   render identically. */
.lasso-v2 .bg_blue{ background-color:#00b0f0 !important; color:#fff !important; }
.lasso-v2 .bg_gold{ background-color:#ffc000 !important; color:#fff !important; }

/* Page-title underline.
   This only ever matched `.row.underline`, which is how search.php marks its
   heading up (210 templates). The SHARED heading element, ele_page_heading,
   uses `form-row form-inline underline` instead — and it is included by 262
   templates, so every one of those pages lost the rule under its title when
   they moved onto this theme. Another ~37 templates put `underline` on a bare
   div. app.css gave `.underline` a flat black border with no spacing; this is
   the v2 equivalent, applied to all three shapes so page headings share one
   rhythm rather than depending on which wrapper the template happened to use. */
.lasso-v2 .underline{
  border-bottom:1px solid var(--line);
  padding-bottom:14px; margin-bottom:22px;
}
.lasso-v2 .row.underline{ align-items:center; }
/* Keep the page title (+ Add button) and the search toolbar on ONE row from
   tablet up. The col-md-6/col-lg-6 grid shim otherwise locks each half to
   ~flex:1 1 320px, so a wider search field pushes Search/Reset onto a second
   line, misaligned with the title. Instead: title sizes to its content, the
   search controls take the remaining width and right-align. Below md they stack
   (the search form collapses behind a toggle on phones anyway). */
@media(min-width:768px){
  .lasso-v2 .row.underline{ flex-wrap:nowrap; }
  .lasso-v2 .row.underline > .clsSearchHeading{ flex:0 1 auto; min-width:0; }
  .lasso-v2 .row.underline > .clsSearchBarDiv{ flex:1 1 auto; margin-left:auto; justify-content:flex-end; }
}
.lasso-v2 .clsSearchHeading{ align-items:center; }
.lasso-v2 .clsSearchHeading h3{
  font-family:'Montserrat','Inter',sans-serif; font-weight:800;
  font-size:24px; color:var(--ink); margin:0; display:inline-flex; align-items:center; gap:10px;
}
.lasso-v2 .clsSearchBarDiv{ align-items:center; }
/* the "+" add-new affordance next to the page title.
   Sized by `min-*` + padding rather than a fixed 32x32 box: the class is not
   always icon-only. The category Logos and Images pages, and the HNC campaign
   data preview, put a full text label on it ("Add New LOGO", "Link a Image"),
   and a hard 32px box crushed those into an unreadable red square with the
   words spilling out. Icon-only anchors still measure exactly 32x32 — a ~13px
   glyph plus 2x9px padding lands under the 32px floor — so the index pages
   this was designed for are unchanged. */
.lasso-v2 .clsAddNew{
  display:inline-flex; align-items:center; justify-content:center; gap:7px;
  min-width:32px; min-height:32px; padding:0 9px; border-radius:9px;
  background:var(--brand-red); color:#fff !important; text-decoration:none;
  font-size:15px; line-height:1; white-space:nowrap;
  box-shadow:0 6px 14px rgba(232,54,43,.22);
}
.lasso-v2 .clsAddNew:hover{ background:var(--brand-red-dark); color:#fff !important; text-decoration:none; }
.lasso-v2 .indexDiv{ /* no frame — the container provides the padding */ }

/* "Results Filtered" info banner (search.php uses .bg-info.text-white) */
.lasso-v2 .bg-info{ background:#E7F0FE !important; }
.lasso-v2 .bg-info.text-white{ color:var(--blue) !important; border-radius:10px; }

/* 9 ── PAGINATION (theme styles .page-link; ensure clean base + counter row) */
.lasso-v2 .pagination{ list-style:none; display:flex; flex-wrap:wrap; padding:0; margin:0; }
.lasso-v2 .pagination .page-link{
  display:inline-flex; align-items:center; justify-content:center;
  min-width:34px; height:34px; padding:0 10px; text-decoration:none; font-size:13px; font-weight:600;
}
.lasso-v2 .pagination .page-item.disabled .page-link{ opacity:.45; pointer-events:none; }
.lasso-v2 .pagination + *,
.lasso-v2 .businesses + .row{ margin-top:6px; }

/* 10 ── BADGES: never wrap the status pill in a narrow cell ────────────────── */
.lasso-v2 .badge{ white-space:nowrap; }

/* 11 ── MODAL SHIM (Bootstrap CSS is not loaded; BS4 JS still drives open/close)
   The shared iframe_modal.php + two-step confirm modals emit Bootstrap-4 modal
   markup. Without this, `.modal` has no `display:none` and renders inline. BS4
   JS sets inline display:block + adds `.show` + injects `.modal-backdrop`. */
.lasso-v2 .modal{
  position:fixed; inset:0; z-index:1050; display:none;
  width:100%; height:100%; overflow-x:hidden; overflow-y:auto; outline:0;
}
.lasso-v2 .modal-dialog{
  position:relative; width:auto; margin:1.75rem auto; max-width:600px; pointer-events:none;
}
.lasso-v2 .modal.fade .modal-dialog{ transition:transform .25s ease-out; transform:translateY(-40px); }
.lasso-v2 .modal.show .modal-dialog{ transform:none; }
.lasso-v2 .modal-dialog-centered{ display:flex; align-items:center; min-height:calc(100% - 3.5rem); }
.lasso-v2 .modal-content{
  position:relative; display:flex; flex-direction:column; width:100%; pointer-events:auto;
  background:#fff; border:1px solid var(--line); border-radius:16px;
  box-shadow:0 24px 60px rgba(20,25,35,.25); outline:0;
}
.lasso-v2 .modal-header{
  display:flex; align-items:flex-start; justify-content:space-between; gap:12px;
  padding:16px 20px; border-bottom:1px solid var(--line);
}
.lasso-v2 .modal-title{ margin:0; font-family:'Montserrat','Inter',sans-serif; font-weight:800; font-size:18px; color:var(--ink); }
.lasso-v2 .modal-body{ position:relative; flex:1 1 auto; padding:20px; }
.lasso-v2 .modal-footer{
  display:flex; align-items:center; justify-content:flex-end; flex-wrap:wrap; gap:8px;
  padding:14px 20px; border-top:1px solid var(--line);
}
.lasso-v2 .modal .close{
  background:none; border:0; font-size:22px; line-height:1; color:var(--muted); cursor:pointer; opacity:.7; padding:2px 6px;
}
.lasso-v2 .modal .close:hover{ opacity:1; color:var(--ink); }
.lasso-v2 .modal-backdrop{ position:fixed; inset:0; z-index:1040; width:100vw; height:100vh; background:#141923; }
.lasso-v2 .modal-backdrop.fade{ opacity:0; transition:opacity .15s linear; }
.lasso-v2 .modal-backdrop.show{ opacity:.5; }
.lasso-v2 .mw-100{ max-width:100% !important; }
.lasso-v2 .w-75{ width:75%; }

/* 12 ── MOBILE LIST CARDS (a wide data table becomes stacked cards on phones)
   Mirrors the customers-redesign mockup's .ccard. The desktop table stays in
   the DOM (E2E tests pin `.businesses table tbody tr`); it is simply hidden
   below the md breakpoint while the card list takes over. */
.lasso-v2 .lv2-cards{ display:none; }
@media (max-width:767.98px){
  .lasso-v2 .lv2-desktop-table{ display:none; }
  .lasso-v2 .lv2-cards{ display:block; }
}
.lasso-v2 .lv2-ccard{
  background:#fff; border:1px solid var(--line); border-radius:14px;
  padding:15px; box-shadow:var(--card-shadow); margin-bottom:12px;
}
.lasso-v2 .lv2-ccard .cc-top{ display:flex; align-items:flex-start; justify-content:space-between; gap:10px; }
.lasso-v2 .lv2-ccard .cc-nm{ font-weight:700; color:var(--ink); font-size:15px; line-height:1.3; }
.lasso-v2 .lv2-ccard .cc-oid{ font-size:11.5px; color:var(--muted); font-weight:600; margin-top:3px; }
.lasso-v2 .lv2-ccard .cc-addr{ font-size:12.5px; color:var(--muted); margin:10px 0 14px; display:flex; align-items:center; gap:6px; }
.lasso-v2 .lv2-ccard .cc-acts{ display:flex; flex-direction:column; gap:8px; }
.lasso-v2 .lv2-ccard .cc-acts .btn{ justify-content:center; width:100%; }
.lasso-v2 .lv2-ccard .cc-url-row{ display:flex; gap:8px; }
.lasso-v2 .lv2-ccard .cc-url-row .btn{ flex:1 1 0; min-width:0; }

/* Customers list (.businesses): one full-width row per customer. The Actions /
   URLs cells wrap their buttons in .row, which is globally flex-wrap:wrap — on a
   wide desktop we have the room, so keep each group on a single line. The table
   already lives in .lv2-desktop-table (overflow-x:auto), so if a viewport is
   genuinely too narrow it scrolls horizontally instead of stacking buttons. */
.lasso-v2 .businesses .tbl th,
.lasso-v2 .businesses .tbl td{ white-space:nowrap; }
.lasso-v2 .businesses td.actions .row{ flex-wrap:nowrap; gap:8px; }

/* 13 ── CAMPAIGN DASHBOARD (active-business hero + charts) ──────────────────
   These metric/chart classes are styled only in portal.css (not loaded here);
   restyle them to the v2 language so the active dashboard matches the mockup.
   The consolidated element JS-builds .hero-card / .metric-card, so we style the
   existing class names rather than change the shared (admin+portal) markup. */
/* period selector → v2 segmented pills (red active, not Bootstrap blue) */
.lasso-v2 .period-pills{
  display:inline-flex; flex-wrap:wrap; gap:4px;
  background:#F1F3F5; border:1px solid var(--line); border-radius:11px; padding:3px;
}
.lasso-v2 .period-pills .btn{
  border:0; background:none; color:var(--muted);
  font-size:13px; font-weight:600; padding:7px 14px; border-radius:8px; box-shadow:none;
}
.lasso-v2 .period-pills .btn:hover{ color:var(--ink); }
.lasso-v2 .period-pills .btn.active{ background:#fff; color:var(--brand-red); box-shadow:0 1px 3px rgba(0,0,0,.12); }

/* hero KPI cards (Clicks / Calls) → v2 .kpi look */
.lasso-v2 .hero-section{ display:grid; grid-template-columns:repeat(2,1fr); gap:20px; margin-bottom:20px; }
.lasso-v2 .hero-card{
  background:#fff; border:1px solid var(--line); border-left:4px solid var(--blue);
  border-radius:16px; padding:22px 24px; box-shadow:var(--card-shadow);
  transition:box-shadow .2s, transform .2s;
}
.lasso-v2 .hero-card:hover{ box-shadow:var(--card-shadow),0 8px 18px rgba(20,25,35,.08); transform:translateY(-2px); }
.lasso-v2 .hero-card.hero-calls{ border-left-color:var(--green); }
.lasso-v2 .hero-card .hero-label{ font-size:11px; font-weight:700; letter-spacing:.08em; text-transform:uppercase; color:var(--muted); margin-bottom:6px; }
.lasso-v2 .hero-card .hero-value{ font-family:'Montserrat','Inter',sans-serif; font-weight:900; font-size:clamp(28px,4vw,36px); color:var(--ink); line-height:1.15; }

/* secondary metric tiles */
.lasso-v2 .secondary-metrics{ display:grid; grid-template-columns:repeat(auto-fit,minmax(190px,1fr)); gap:14px; margin-bottom:20px; }
.lasso-v2 .metric-card{ background:#fff; border:1px solid var(--line); border-radius:14px; padding:16px; text-align:center; box-shadow:var(--card-shadow); }
.lasso-v2 .metric-card .metric-label{ font-size:11px; color:var(--muted); text-transform:uppercase; letter-spacing:.06em; margin-bottom:4px; font-weight:700; }
.lasso-v2 .metric-card .metric-value{ font-family:'Montserrat','Inter',sans-serif; font-weight:800; font-size:clamp(20px,3vw,24px); color:var(--ink); line-height:1.2; }
.lasso-v2 .trend-indicator{ display:inline-block; font-size:13px; margin-top:4px; font-weight:600; }
.lasso-v2 .trend-up{ color:var(--green); } .lasso-v2 .trend-down{ color:var(--brand-red); } .lasso-v2 .trend-flat{ color:var(--muted); }
.lasso-v2 .trend-label{ font-size:11px; color:#9CA3AF; margin-top:2px; }

/* chart cards + loading + empty states */
.lasso-v2 .chart-card{ background:#fff; border:1px solid var(--line); border-radius:16px; box-shadow:var(--card-shadow); margin-bottom:16px; }
.lasso-v2 .chart-card .card-body{ padding:14px 18px; }
.lasso-v2 .chart-container{ position:relative; }
.lasso-v2 .no-data-msg{ text-align:center; color:#AEB4BC; padding:60px 0; }
.lasso-v2 .no-data-msg i{ font-size:2rem; margin-bottom:8px; }
.lasso-v2 .loading-overlay{ position:absolute; inset:0; background:rgba(255,255,255,.7); display:flex; align-items:center; justify-content:center; z-index:10; border-radius:14px; }
/* Bootstrap spinner-border (Bootstrap CSS not loaded) */
.lasso-v2 .spinner-border{
  display:inline-block; width:1.6rem; height:1.6rem; vertical-align:-.125em;
  border:.22em solid currentColor; border-right-color:transparent; border-radius:50%;
  animation:lv2spin .75s linear infinite; color:var(--brand-red);
}
@keyframes lv2spin{ to{ transform:rotate(360deg); } }
@media (max-width:767.98px){ .lasso-v2 .hero-section{ grid-template-columns:1fr; gap:14px; } }

/* 14 ── ADD-BUSINESS WIZARD CHROME (shared my_customer_step_layout /
   ele_page_heading / ele_customer_steps_form_actions across all 11 steps) ──── */
/* Three-column layout (steps | form | tips): the global `.lasso-v2 .row` centres
   columns vertically (right for in-cell button rows, wrong here), and the grid
   shim defines no col-md-3, so the sidebar/tips floated mid-height and mis-sized.
   Top-align the row and give this layout real 3 / 6 / 3 proportions on desktop;
   stack full-width on mobile. Scoped to .customer-step-layout so the global row
   behaviour is untouched. */
.lasso-v2 .customer-step-layout .row{ align-items:flex-start; }
.lasso-v2 .customer-step-layout .col-md-3{ flex:1 1 100%; max-width:100%; }
@media (min-width:768px){
  .lasso-v2 .customer-step-layout .col-md-3{ flex:1 1 0; }
  .lasso-v2 .customer-step-layout .col-md-6{ flex:2 1 0; }
  /* review step is stepper (col-md-3) + content (col-md-9) → keep the stepper
     a narrow 25% rail instead of letting it grow full-width */
  .lasso-v2 .customer-step-layout .col-md-9{ flex:3 1 0; min-width:0; }
}
/* Form fields live in ONE .row and rely on flex-wrap to form visual rows, so
   they need real 12-col PERCENTAGE bases to wrap correctly (3×col-lg-4 -> a row
   of thirds, col-lg-9+col-lg-3 -> 75/25, 2×col-lg-6 -> halves). box-sizing is
   border-box, so the 8px column padding sits INSIDE the width and the
   percentages still sum to 100% and never overflow. The row's -8px margin
   pulls the outer columns back to the card edge. Every visual row in the step
   templates sums to 12. Stack full-width on mobile. The grid shim defined no
   col-lg-3 / col-lg-9, which is why undefined columns collapsed to content
   width and wasted space. */
.lasso-v2 .customer-step-layout .card .row{ gap:0; margin-left:-8px; margin-right:-8px; }
.lasso-v2 .customer-step-layout .card .row > [class*="col-"]{ padding:0 8px; margin-bottom:4px; flex:0 0 100%; max-width:100%; }
/* tighter, even label→input rhythm on the wizard form grid */
.lasso-v2 .customer-step-layout .field-label{ margin-bottom:4px; }
/* wizard fields fill their grid column — the global .inp max-width:320px cap
   left big empty gaps in wide columns (e.g. Tagline at 75%) */
.lasso-v2 .customer-step-layout .inp{ margin-bottom:0; max-width:none; }
@media (min-width:768px){
  .lasso-v2 .customer-step-layout .card .row > .col-lg-2{ flex-basis:16.666%; max-width:16.666%; }
  .lasso-v2 .customer-step-layout .card .row > .col-lg-3{ flex-basis:25%; max-width:25%; }
  .lasso-v2 .customer-step-layout .card .row > .col-lg-4{ flex-basis:33.333%; max-width:33.333%; }
  .lasso-v2 .customer-step-layout .card .row > .col-lg-6{ flex-basis:50%; max-width:50%; }
  .lasso-v2 .customer-step-layout .card .row > .col-lg-8{ flex-basis:66.666%; max-width:66.666%; }
  .lasso-v2 .customer-step-layout .card .row > .col-lg-9{ flex-basis:75%; max-width:75%; }
  .lasso-v2 .customer-step-layout .card .row > .col-lg-12{ flex-basis:100%; max-width:100%; }
  /* col-md-* used by the recommendations (3-up plan cards) + other steps */
  .lasso-v2 .customer-step-layout .card .row > .col-md-3{ flex-basis:25%; max-width:25%; }
  .lasso-v2 .customer-step-layout .card .row > .col-md-4{ flex-basis:33.333%; max-width:33.333%; }
  .lasso-v2 .customer-step-layout .card .row > .col-md-6{ flex-basis:50%; max-width:50%; }
  /* numeric cols used by the geo-targets rows (name / type / remove = 5 / 5 / 2) */
  .lasso-v2 .customer-step-layout .card .row > .col-2{ flex-basis:16.666%; max-width:16.666%; }
  .lasso-v2 .customer-step-layout .card .row > .col-5{ flex-basis:41.666%; max-width:41.666%; }
}
.lasso-v2 legend{
  font-family:'Montserrat','Inter',sans-serif; font-weight:800; font-size:24px;
  color:var(--ink); margin:0; padding:0; border:0; width:auto; display:block; line-height:1.2;
}
/* The browser's own fieldset chrome — a 2px groove border and its own padding —
   is zeroed by Bootstrap's reboot, which this layout does not load. So every
   fieldset on a converted page came back as a raw browser box: the Attachment
   and Payment Link groups on the invoice form were framed in grey groove with
   their captions sitting across the top edge. */
.lasso-v2 fieldset{ min-width:0; padding:0; margin:0; border:0; }
/* On the invoice form a legend captions a group of fields rather than the page
   — Attachment and Payment Link — so the 24px display size above turned two
   field labels into headings competing with the page title. NOT global: the
   ~370 baked add/edit templates put the PAGE title in a legend inside a bare
   fieldset, and 24px is right for those. */
.lasso-v2 #invoiceForm fieldset > legend{
  font-family:'Inter',system-ui,sans-serif; font-weight:700; font-size:13px;
  color:var(--ink); margin-bottom:8px; line-height:1.4;
}
.lasso-v2 .list-unstyled{ list-style:none; padding-left:0; margin:0; }
.lasso-v2 .gap-2{ gap:.5rem; }
.lasso-v2 .form-actions{ display:flex; gap:12px; justify-content:space-between; align-items:center; margin-top:26px; flex-wrap:wrap; }
/* SAVE (stay) → ghost; SAVE & CONTINUE (advance) → v2 primary red */
.lasso-v2 .customer-step-btn-return{
  background:#fff; color:var(--text); border:1.5px solid var(--line); border-radius:10px;
  font-family:inherit; font-weight:700; font-size:14px; padding:11px 22px; cursor:pointer;
}
.lasso-v2 .customer-step-btn-return:hover{ border-color:#CBD1D8; color:var(--ink); }
.lasso-v2 .customer-step-btn-continue{
  background:var(--brand-red); color:#fff; border:0; border-radius:10px;
  font-family:inherit; font-weight:700; font-size:14px; padding:11px 22px; cursor:pointer;
  box-shadow:0 8px 18px rgba(232,54,43,.26);
}
.lasso-v2 .customer-step-btn-continue:hover{ background:var(--brand-red-dark); color:#fff; }

/* 8 ── HNC Google Ads index: one row, one line ───────────────────────────── */
/* Fifteen columns, and every value in them is short — an order id, a status word, a
   budget, and eight one-word buttons. Left to wrap, the narrow columns broke their own
   contents rather than the table growing: "Re-Create" split across two lines, the
   campaign name broke mid-token at "SRC-", and every row cost 61px to show 40px of
   content. Scanning the table meant reading two lines per row for no added information.
   Wrapping off, and the table scrolls sideways instead — a horizontal scrollbar on a
   fifteen-column admin grid is the honest trade for rows you can scan down. */
.lasso-v2 .hncGoogleAds .no-more-tables{ overflow-x:auto; }
.lasso-v2 .hncGoogleAds table th,
.lasso-v2 .hncGoogleAds table td{ white-space:nowrap; }

/* ── DataTables chrome ───────────────────────────────────────────────────────
   The controls above a table — export button, "Show N entries", "Search:" — are
   block-level divs, and each report page arranges them with its own `dom`
   string: `Bfrtip` on fourteen of them, `<"wrapper"B><"length-wrap"l>frtip` on
   the account-manager report, and a hand-built flex row in ele_table_theme2.
   Only the last one put them on a single line, so everywhere else they stacked
   and pushed the table a row or two down the page for nothing.

   Laying the wrapper out as a wrapping flex row fixes all three shapes without
   touching a single `dom` string: the control divs become items on one line,
   and the table, the per-page flex row, the "Showing x of y" line and the pager
   are forced onto their own by a full-width basis. New report pages inherit it
   whatever `dom` they pick.

   Scoped to .lasso-v2 — the legacy layout has Bootstrap, which the DataTables
   bootstrap4 skin was written against, and does not need this. */
.lasso-v2 .dataTables_wrapper{ display:flex; flex-wrap:wrap; align-items:center; gap:10px 14px; }
.lasso-v2 .dataTables_wrapper > table,
.lasso-v2 .dataTables_wrapper > .dt-top,
.lasso-v2 .dataTables_wrapper > .dataTables_info,
.lasso-v2 .dataTables_wrapper > .dataTables_paginate{ flex:0 0 100%; }
.lasso-v2 .dataTables_wrapper .dt-buttons,
.lasso-v2 .dataTables_wrapper .dataTables_length,
.lasso-v2 .dataTables_wrapper .dataTables_filter{ margin:0; padding:0; }
/* Labels wrap their control in a <label>; flex keeps "Show […] entries" and
   "Search: […]" on the baseline instead of stacking inside the label. */
.lasso-v2 .dataTables_wrapper .dataTables_length label,
.lasso-v2 .dataTables_wrapper .dataTables_filter label{ margin:0; display:flex; align-items:center; gap:8px; }
/* Last, so it survives the margin reset above: search sits at the far right,
   matching the row ele_table_theme2 builds by hand. */
.lasso-v2 .dataTables_wrapper > .dataTables_filter{ margin-left:auto; }
