/* =====================================================================
   n360-mobile.css  v1.33  -  3rd Sep 2026
   VERIFY: VERIFY-A11YB4-03SEP2026-R9-W7KPH  (was v1.32 VERIFY-A11YB4-03SEP2026-R8-J5RDF)

   v1.33 - EVERY BOOTSTRAP MODAL WAS UNDER THE MOBILE HEADER. The header sits
   at z-index 10040 (above the results page's 4999 sticky row), the drawer
   backdrop at 10050 and the drawer at 10060 - and Bootstrap's modal is 1055,
   its backdrop 1050. So on a phone a modal opened BEHIND the fixed header:
   its own header row, close button included, was covered (KP: "you cant
   close it"), the header's search box stayed on top and looked live, and
   the burger still opened the drawer over the modal - blurred, because
   results.css blurs .n360-sidebar while a modal is open. One rule below
   puts modal + backdrop above the whole mobile stack. Affects every modal on
   every page at phone width, not only the accessibility statement.

   v1.32 - WCAG 2.2 BATCH 4, the mobile pass. (1) The critical-alerts banner:
   the live dot sat alone on its own line and the dismiss button was nowhere -
   the headline block was wrapping under a 9px dot, and #critDismiss was
   position:absolute against an ancestor that was not positioned. The banner
   is now the positioning context, the headline block shares the dot's line
   and shrinks, the button is 24x24 top-right. (2) 2.5.8 target sizes: the
   small icon controls that CSS did not size explicitly (notice dismiss, chip
   removes, favourites remove, the modal close) get a 24x24 minimum - the
   spacing exception does not apply to them because they sit inside padded
   rows. (3) The drawer's close button was 40px already; the rest of the
   drawer behaviour (inert page, focus in, focus back) is _Sidebar.cshtml v2.3.

   v1.31 - WCAG 2.2 batch 1, ONE line: .n360-mfilters-btn is a white button
   whose text was var(--n360-primary), which is cyan in dark mode - cyan on
   white is 1.6:1. It now uses --n360-primary-fill, the primary that stays
   dark in both modes. Everything else in this sheet waits for batch 4 (the
   mobile pass). Tokens are declared in n360-tokens.css.

   v1.29 - THE ROOT CAUSE OF THE WHOLE HEADER SAGA, found by Sol (second
   AI, fresh eyes) and folded through this file per the standing workflow.
   Supersedes Sol's interim v1.28.

   The v1.19 flex-era rule below put 10px horizontal padding on EVERY
   direct child of a control row. On bare buttons (Dashboard, Theme) that
   padding sits INSIDE the pill border - correct. On wrapped controls
   (clock in .dropdown, Accessibility in .a11y-wrap) it landed on the
   WRAPPER, so the inner button's width:100% filled a containing block 20px
   narrower than the grid column: 160px pills beside 180px pills, exactly
   as measured. Every later fix - stamps, box-model pins, even inline
   !important geometry - was defeated by it, because none of them touched
   PADDING on the wrapper: the one box property never pinned.

   Fixed at the origin (padding removed from the child rule - controls get
   their padding from the unified pill rule), belted with an explicit
   wrapper-cell reset covering ALL THREE headers (Sol's fix was
   #resultsSide-scoped; the provider row matches the same rule and had the
   same hidden deficit), and the JS decree now pins padding too.

   v1.27 - built with the LAST TWO SHEETS finally in hand
   (n360-a11y-toolbar.css and results.css). What they held:
   - the Accessibility button is `.a11y-trigger` inside `.a11y-wrap`, and it
     carries `border: 1.5px solid` - the thicker outline KP kept seeing,
     while every guessed selector matched nothing
   - results.css gives the clock `min-width: 192px` - the THIRD independent
     min-width found on that widget (page-inline 188px on the dashboard,
     108px on the results clock text, now 192px here)
   The real names join every control rule below, so none of this depends on
   the JS stamping any more - the stamps remain as reinforcement.

   v1.26 - KP put guide lines on a screenshot: the four controls are four
   different widths. The harness said equal because it can only load the
   sheets it has - and n360-a11y-toolbar.css and results.css, which style
   these very controls, have never been supplied. This version pins every
   box property that could make width:100% render differently between
   components: box-sizing, margins, min/max-width, transform, float. If a
   difference survives this, it is coming from one of those two files and
   the console snippet in the README will name it.

   v1.25 - THE SPREAD LABELS, FOUND. `.n360-ctlcell > * { width: 100% }`
   was written to make a WRAPPED button fill its cell. But two of the four
   controls are bare buttons that were marked as their own cell, so the rule
   reached their <i> and their <span> instead: icon 100% wide, label 100%
   wide, two flex items splitting the button down the middle. That is the
   icon-left / label-right gap on every page, and it was mine.

   Fill is now applied only to the control and to wrappers between it and
   the cell (marked by n360-mobile.js), never to a control's contents. The
   inside of every control is also normalised explicitly, so three pages
   with three different button markups render identically.

   v1.24 - the control rows become a GRID. Flex with a calc() basis kept
   producing cells that were equal while the buttons inside them were not,
   because a wrapped control and a bare one measure differently. Grid
   columns are equal by definition and there is no arithmetic to get wrong.
   Plus the provider call button, and the footer logo's spacing.

   v1.23 - the header controls are styled through classes n360-mobile.js
   stamps on the real elements, instead of selectors aimed at a wrapper we
   have never seen (the Accessibility partial's markup and stylesheet have
   never been supplied - which is why it kept its own outline weight and
   width while its neighbours fell into line). Also: the call button's
   number stays readable in the stuck-hover state after a tap, and the
   rescued noticeboard gets somewhere to land.

   v1.22 - the control-pill treatment extends to the provider header (its
   Theme button is #themeToggleBtn as well, and its Accessibility is the
   same shared partial, so ONE rule now governs both pages); the provider
   clock takes the same half-row width as Theme below it; the record opens
   closer to the header; and every page gets an evenly spaced hairline
   between the page content and the accessibility footer.

   Also fixed here: `.layer-header > div:first-child` had quietly stopped
   matching in v1.7, when Close became the header's first child - a BUTTON,
   so `div:first-child` matches nothing. The logo row only still looked
   right by luck. It is now selected by the logo it contains.

   v1.21 - the four results header controls stop looking like four
   different products. KP spotted it: Dashboard and Theme square-ish,
   clock and Accessibility pills. Not intentional - four components with
   four owners of their look (page buttons, page clock widget, shared
   toolbar partial), and the equal 2x2 amplified every difference. One
   appearance is now imposed at this layer, by id, so it cannot depend on
   results.css (unseen) or any component's own choices.

   v1.20 - Results.cshtml finally supplied, and with it three answers:
   the results theme button is #themeToggleBtn (not #themeToggle - which is
   why every guessed selector missed for four rounds), the results clock was
   never lost - its wrapper is `d-none d-xl-block`, hidden below 1200px by
   the page's own markup - and the broken provider clock dropdown was THIS
   FILE's round-1 rule: the popover viewport-pin also caught every
   .dropdown-menu.show, and for a menu whose containing block is a ~100px
   .dropdown wrapper, left:8/right:8 computes an 84px menu with our own
   min-width:0 defeating the markup's min-width:320px.

   v1.19 - round 9, CSS only, each fix built from the real markup:
   the Apply Filters button keeps its icon on the line (results.js writes
   `TEXT <i class="fad fa-magnifying-glass ms-2">` into #applyFiltersBtn, and
   the uppercase letter-spacing was what pushed the icon off); the results
   control row becomes an equal 2x2; the Site-Specific heading is a PLAIN
   h4.border-bottom, not the flex wrapper earlier rounds styled; and the
   credential attachment icon centres inside its button.

   v1.18 - THE CLOCK, WITH THE CAUSE FINALLY IN HAND. Index.cshtml carries
   its own inline <style> block, and line 30 of it reads:

       .tz-clock-widget { ... min-width: 188px; ... }
       .tz-clock-text   { min-width: 104px; }

   188px of guaranteed width plus the heading can never share a 390px line -
   which is why five rounds of resizing the clock did nothing. Width, padding
   and font were all being resized while MIN-WIDTH held the floor, and an
   inline <style> in the page body also outranks this linked sheet on load
   order. Every clock rule now kills min-width explicitly and hangs off the
   #tzClockWidget ID so nothing class-based can outrank it.

   v1.17 - round 7. The dashboard clock gets small enough to genuinely share
   the heading line (icon back, chrome down); the results control row is now
   named by the script instead of guessed at; the provider header becomes
   logo+clock / Close / Accessibility+Theme; the category chain wraps; the
   credentials table becomes cards; and the feedback radios stop being 44px
   ovals - that one was this file's own WCAG target-size rule applied to
   controls that must never stretch.

   v1.16 - round 6. Equal pill rows on every page (the results header
   included, which is NOT a .topbar - that is why it kept escaping), the
   clock beside the heading, and the dead vertical space above the Last
   Updated hairline and the footer.

   v1.14 - the clock loses its icon as well as its seconds, and Close moves
   to the top corner of the provider header where a close control belongs.

   v1.13 - round 3. The provider tabs become a real accordion, the provider
   page header stops running off the edge, and the drawer loses its dead
   space at the top.

   WHY ROUND 2 LOOKED HALF-APPLIED: n360-mobile.js was only linked from the
   Results page, because v1.0 of it only did the sort select and the sort bar
   only exists there. Everything from v1.1 onward is needed on the dashboard
   and the provider page too. Index.cshtml v1.14 and Provider.cshtml v1.6 now
   link it. That single missing script tag accounted for the drawer close
   button, the clock not moving, and Last Updated staying put.

   v1.12 - round 2 of KP's feedback. Ten items, and the one that mattered
   most was invisible: tapping a provider tab swapped content that was off
   screen, so the page read as broken. Tabs now announce themselves as
   tappable AND scroll their panel into view.

   Several of these needed a DOM move rather than a style, and those live in
   n360-mobile.js v1.1: the category icon into the provider name, the clock
   into the heading row, Last Updated to the bottom, and a close button in
   the drawer. CSS cannot move a node between two parents.

   v1.11 - the call button no longer uses ANY theme variable, and the sort
   buttons are replaced by a select (see n360-mobile.js).

   v1.8 - result card resequenced, sort bar split onto two rows, and the
   provider page overflows now that this file actually loads there.

   v1.7 - header stacking, and the card CTA properly this time.

   v1.6 - dashboard topbar laid out deliberately, and the alert strip.

   NOTE FOR THE NEXT ROUND: the Access and Theme controls, the accessibility
   panel and the login page all live in _Layout.cshtml, which has not been
   supplied. Two consequences: the accessibility panel still opens off the
   left edge, and NONE of this file loads on the login page - it is linked
   from _Sidebar.cshtml, which Login does not render. Both need _Layout.

   v1.5 - the provider detail page (untouched until now), the dashboard
   search actions, and a proper primary/secondary relationship between the
   two card buttons.

   v1.4 - colour, contrast, and culling the nav.
   The header and call button both took colour from --n360-primary, which is
   navy in the N360 theme but RED in Intaworld and a washed-out salmon in
   Intaworld dark. App chrome should not change colour with the client theme.

   v1.3 is mostly one problem wearing several hats: HORIZONTAL OVERFLOW.
   The sort bar, the Return to dashboard button, View Provider Details and
   the Apply Filters row were each wider than 375px, so the whole page could
   be dragged sideways and everything looked broken in a different way.

   v1.2 fixes the drawer not opening:
     - .n360-sidebar carries Bootstrap's d-none below lg, which is
       display:none !important. Transform cannot move an element that is not
       displayed, so the backdrop appeared and the drawer did not.
     - The backdrop sat at 1050 while #aiParsePanel and #aiHintRow sit at
       5000 and 4999, so the Provider Name row floated above the dim and
       looked like it had been deliberately highlighted.

   v1.1 fixes the real-device problems found in v1.0:
     - Results page did not scroll past the fold. ROOT CAUSE: that page never
       scrolls on body at all - .main-content is height:100vh with #resultsSide
       as an inner scroll container, so a fixed header simply pushed 60px of
       content out of reach. Mobile now uses normal document scroll.
     - Header overlapped page content, and the search box was clipped.
     - Dashboard offered both views and overflowed its toolbar.

   DESIGNED FOR THE HOSPITAL CAR PARK, NOT FOR A SMALLER DESKTOP.

   One hand, poor signal, thirty seconds. Find a provider, get the number,
   call it. Everything else is desktop and is deliberately hidden below
   992px rather than shrunk.

   Loaded by _Sidebar.cshtml so it applies to every page. Loads AFTER the
   page stylesheets, so it wins on order and needs almost no !important.

   Everything here is inside a max-width media query. Nothing in this file
   can affect the desktop layout.
   ===================================================================== */

@media (max-width: 991.98px) {

/* ---------------------------------------------------------------------
   1. MOBILE HEADER
   results.css already hides .n360-sidebar below 991px, which also removed
   the only navigation AND the quick provider search. This puts both back
   in a fixed top bar.
   --------------------------------------------------------------------- */
.n360-mtop {
    display: flex !important;
    /* The results page has a sticky Provider Name / Smart Search row at
       z-index 4999, which was sliding over the header. Sit above it, but
       below the drawer (10060) and its backdrop (10050) so an open menu
       still covers the header. */
    position: fixed; top: 0; left: 0; right: 0; z-index: 10040;
    align-items: center; gap: 10px;
    padding: 8px 10px;
    padding-top: calc(8px + env(safe-area-inset-top));   /* clear the notch */
    /* NOT var(--n360-primary): navy in N360, red in Intaworld, salmon in
       Intaworld dark. Chrome stays put while the client theme changes around
       it, so this is a fixed dark surface matching the sidebar. */
    background: #12161b;
    border-bottom: 2px solid rgba(255,255,255,.14);
    box-shadow: 0 2px 12px rgba(0,0,0,.18);
}
.n360-mtop-btn {
    flex: 0 0 38px; width: 38px; height: 38px; border: 0; border-radius: 11px;
    background: rgba(255,255,255,.12); color: #fff; font-size: 17px;
    display: grid; place-items: center; cursor: pointer;
}
.n360-mtop-btn:active { background: rgba(255,255,255,.22); }
/* The logo is wide. Capping it is what stops the search box being squeezed
   off the right-hand edge, which is what v1.0 did on a 375px screen. */
.n360-mtop-logo { height: 24px; width: auto; max-width: 96px; object-fit: contain; flex: 0 0 auto; }

/* The search box IS the page on mobile, so it takes the space. */
.n360-mtop-search { position: relative; flex: 1 1 auto; min-width: 0; }
.n360-mtop-search i {
    position: absolute; left: 12px; top: 50%; transform: translateY(-50%);
    color: var(--n360-cyan, #00bde7); font-size: 15px; pointer-events: none;
}
.n360-mtop-search input {
    width: 100%; height: 38px;
    background: rgba(255,255,255,.13); border: 1px solid rgba(255,255,255,.2);
    border-radius: 11px; color: #fff; font-size: 16px;   /* 16px stops iOS zooming on focus */
    padding: 0 12px 0 36px; outline: none;
}
.n360-mtop-search input::placeholder { color: rgba(255,255,255,.6); }
.n360-mtop-search input:focus { border-color: var(--n360-cyan, #00bde7); background: rgba(255,255,255,.18); }

/* ---------------------------------------------------------------------
   LAYOUT AND SCROLL  -  the fix that matters most

   The Results page does NOT scroll on body. results.css gives .main-content
   height:100vh as a flex column, .split-container overflow:hidden, and makes
   #resultsSide the scroll container. So padding the body did nothing, and the
   fixed header pushed 60px of content permanently below the fold - which is
   why scrolling stopped at the country dropdown.

   On mobile we convert the whole thing to ordinary document scroll. Nested
   scroll containers are miserable on a phone anyway: no momentum, and it is
   easy to trap a finger in the wrong one.
   --------------------------------------------------------------------- */
body { padding-top: 0; }

/* ---------------------------------------------------------------------
   NO HORIZONTAL SCROLL, ANYWHERE

   Several elements are wider than a 375px screen - the sort group, the
   Return to dashboard button, the card CTA. Any one of them lets the whole
   page be dragged sideways, which is what made everything look broken.
   Contain it once, at the top, then fix the individual offenders below.
   --------------------------------------------------------------------- */
html, body { overflow-x: hidden !important; max-width: 100vw; }
.main-content, .split-container, #resultsSide, .dash-shell, .std-shell,
.topbar, .result-card, .n360-card {
    max-width: 100% !important;
    overflow-x: hidden;
}
img, svg, table, iframe { max-width: 100% !important; height: auto; }

.main-content {
    margin-top: calc(54px + env(safe-area-inset-top)) !important;
    height: auto !important;
    min-height: 0 !important;
    padding-left: 10px !important;
    padding-right: 10px !important;
}
.split-container { display: block !important; overflow: visible !important; height: auto !important; }
#resultsSide {
    overflow-y: visible !important; height: auto !important;
    width: 100% !important; flex: none !important;
    padding: 10px 0 40px !important;
}

/* ---------------------------------------------------------------------
   2. SIDEBAR AS A SLIDE-IN DRAWER
   The sidebar is already translated off-screen by results.css. This gives
   it a way back on, rather than leaving it unreachable.
   --------------------------------------------------------------------- */
.n360-sidebar {
    /* 100dvh accounts for the iOS URL bar; 100vh is the fallback for anything
       that does not know dvh. Without this the drawer bottom is cut off. */
    position: fixed; top: 0; left: 0;
    height: 100vh; height: 100dvh;
    /* Above #aiParsePanel (5000) and .fuzzy-suggestion-box (9999), or those
       float over the drawer and the dim. */
    z-index: 10060;
    transition: transform .22s ease;
    overflow-y: auto;
}
/* THE FIX: the markup carries d-none d-lg-flex, so below lg this element is
   display:none !important. A transform cannot move something that is not
   displayed - the drawer has to be given back its display before it can
   slide. */
body.nav-open .n360-sidebar {
    display: flex !important;
    transform: translateX(0) !important;
}
.n360-navback {
    position: fixed; inset: 0; z-index: 10050;
    background: rgba(2, 15, 24, .55); backdrop-filter: blur(2px);
    opacity: 0; pointer-events: none; transition: opacity .22s ease;
}
body.nav-open .n360-navback { opacity: 1; pointer-events: auto; }
body.nav-open { overflow: hidden; }

/* Anything sticky inside the page must start below the fixed header, or it
   parks on top of it as soon as you scroll. */
#aiHintRow, #aiParsePanel, .position-sticky, .sticky-top {
    top: calc(54px + env(safe-area-inset-top)) !important;
}

/* The skip link is correct behaviour - it only appears on focus - but it
   focuses to top:0, which is underneath our fixed header. Push it clear. */
.skip-link:focus {
    top: calc(54px + env(safe-area-inset-top)) !important;
    z-index: 100001;
}

/* ---------------------------------------------------------------------
   3. RESULTS - THE FIELD SCREEN
   --------------------------------------------------------------------- */
#resultsSide { padding: 12px !important; }
.split-container { display: block !important; }

/* Cards get tighter, and lose the hover machinery that means nothing on
   a touch screen. */
.result-card { padding: 14px !important; margin-bottom: 10px; }
.result-card:hover { transform: none !important; }
.cat-tree-box, .cat-hover-wrapper:hover .cat-tree-box { display: none !important; }

/* THE POINT OF THE PAGE: click-to-call becomes a full-width button.

   v1.2 styled the <a> itself and injected an icon with ::before. Two things
   were wrong with that. The anchor sits inside a wrapper div, so width:100%
   on the anchor did not fill the card - and the ::before rendered as an
   empty box because this site uses Font Awesome PRO (fad) under a different
   family name than the one guessed at.

   v1.3 styles the WRAPPER as the button instead, which makes it genuinely
   full width and keeps the real fad phone icon that is already in the
   markup. No JavaScript or Razor change either way. */
.result-card div:has(> a[href^="tel:"]) {
    display: flex !important; align-items: center; justify-content: center; gap: 10px;
    width: 100% !important; min-height: 52px; margin: 12px 0 4px !important;
    /* FIXED COLOURS, NO THEME VARIABLE.

       This is the third time a theme var has bitten this button: navy in
       N360, red in Intaworld, salmon in Intaworld dark, and near-white in
       dark mode - which made a white button with white text.

       The card behind it can be light, dark, or the hover state (which is
       itself --n360-primary). Nothing derived from the theme can be
       guaranteed to contrast against all three, so this button is fixed
       dark with white text and inverts on hover. It is the single most
       important control on the page; it does not get to be theme-dependent. */
    background: #12161b;
    border-radius: 12px; box-shadow: 0 2px 10px rgba(0,0,0,.16);
    font-size: 19px !important;
}
.result-card div:has(> a[href^="tel:"]) i,
.result-card div:has(> a[href^="tel:"]) a { color: #fff !important; }
.result-card div:has(> a[href^="tel:"]) i { font-size: 18px; margin: 0 !important; }
.result-card div:has(> a[href^="tel:"]) a {
    font-weight: 800 !important; font-size: 19px; letter-spacing: .02em;
    text-decoration: none !important;
}
.result-card div:has(> a[href^="tel:"]):active { filter: brightness(.94); }

/* HOVER STATE COLLISION.

   results.css sets `.result-card:hover { background-color: var(--n360-primary) }`
   - the SAME variable this call button uses as its fill, so the button
   dissolved into the card and the outline CTA disappeared entirely.

   It matters more on mobile than desktop: on a touchscreen :hover sticks
   after a tap, so the card sits in its dark state indefinitely.

   Both buttons invert on hover rather than the hover state being suppressed -
   their white-text rules are well designed and worth keeping. */
.result-card:hover div:has(> a[href^="tel:"]) { background: #ffffff !important; }
/* v1.23 - EVERY descendant, not just the <a> and its icon. The number sits
   in a nested span, and results.css colours the whole hovered card's text
   white with enough specificity to reach past an <a>-level rule - so the
   button went white-on-white the moment it was tapped. On a touchscreen
   :hover STICKS after the tap, so this was not a hover nicety: it made the
   phone number unreadable exactly when someone had reached for it.
   :active and :focus-within are covered too, for the tap itself and for
   keyboard focus. text-fill-color as well as color, because a background-
   clipped heading rule elsewhere would otherwise win. */
.result-card:hover div:has(> a[href^="tel:"]) *,
.result-card:active div:has(> a[href^="tel:"]) *,
.result-card:focus-within div:has(> a[href^="tel:"]) *,
.result-card:hover div:has(> a[href^="tel:"]),
.result-card:active div:has(> a[href^="tel:"]),
.result-card:focus-within div:has(> a[href^="tel:"]) {
    color: #12161b !important;
    -webkit-text-fill-color: #12161b !important;
}
.result-card:active div:has(> a[href^="tel:"]),
.result-card:focus-within div:has(> a[href^="tel:"]) {
    background: #ffffff !important;
}
.result-card:hover .btn.rounded-pill {
    border-color: rgba(255,255,255,.65) !important;
    color: #ffffff !important;
    background: rgba(255,255,255,.08) !important;
}

/* Fallback for anything without :has() - still readable, just not a button. */
.result-card a[href^="tel:"] { font-size: 17px; font-weight: 800; }

/* The card CTA carries inline white-space:nowrap, so it runs off the edge.
   Full width under the phone button, where a thumb expects it. */
/* Two full-width buttons of equal weight fight each other. Call is the
   primary action in the field, so View Provider Details becomes a secondary
   outline button - same width, same alignment, clearly subordinate.

   v1.7: flex-basis was still losing to the parent row, which is a
   justify-content-between flex containing an empty feedback span that kept
   claiming space. Rather than out-arguing the flex container, take it out of
   flex on mobile - then plain width:100% behaves. */
.result-card div:has(> .btn.rounded-pill) {
    display: block !important;
    width: 100% !important;
    /* The parent row carried its own horizontal padding, which is why the
       CTA sat inset from the call button above it rather than aligned. */
    padding: 0 !important;
    margin: 10px 0 0 !important;
}
.result-card .btn.rounded-pill {
    display: flex !important; align-items: center; justify-content: center;
    width: 100% !important; max-width: 100% !important;
    white-space: normal !important;
    font-size: 13px !important; min-height: 46px;
    margin: 0 !important;
    background: transparent !important;
    /* currentColor means this outline follows whatever the card's text colour
       is, so it flips by itself between the normal and hover states without
       needing to know the theme. */
    border: 1.5px solid currentColor !important;
    box-shadow: none !important;
}
.result-card .btn.rounded-pill i { color: inherit !important; }
/* The feedback button sits in the same row and pushes the CTA off-centre. */
.result-card .btn-link { flex: 0 0 auto; }
.result-card .d-flex.justify-content-between { flex-wrap: wrap !important; }

/* CARD ORDER, RETHOUGHT.

   Source order puts the 24/7 and accreditation badges BETWEEN the call
   button and the CTA, which splits the two actions and makes the badges look
   like they belong to the phone number.

   On mobile the card reads: identity, then what qualifies this provider,
   then what you can do about it. So the badges move up next to the address
   and the two buttons sit together at the bottom, call first.

   Everything not given an order stays at 0 and keeps its source position. */
/* v1.9 - this was `.result-card > div, .result-card .flex-grow-1` in v1.8,
   which also caught the card's outer d-flex row. That is what pushed the
   category icon onto its own line under the name and let the call button
   overrun the card edge. Only the inner content column should stack. */
.result-card > .d-flex > .flex-grow-1 {
    display: flex !important; flex-direction: column !important;
    min-width: 0;
}
.result-card > .d-flex { display: flex !important; flex-direction: row !important; }
.result-card * { max-width: 100%; }
.result-card .acc-group { order: 5; margin: 10px 0 0 !important; }
.result-card div:has(> a[href^="tel:"]) { order: 6; }
.result-card div:has(> .btn.rounded-pill) { order: 7; }

/* Secondary detail stays available but stops competing. */
.result-card .cat-path { font-size: 12px; }
.result-card .preferred-badge { font-size: 10px; }

/* The page heading is set for a desktop column and wraps to three lines at
   375px, pushing everything down before a single result is visible. */
#resultsSide h1, .page-title, .results-title {
    font-size: 1.35rem !important; letter-spacing: .02em !important;
    line-height: 1.2 !important; word-break: normal;
}
#resultsSide header { flex-wrap: wrap !important; gap: 8px; }

/* Return to dashboard and its neighbours: let them wrap instead of running
   off the edge. */
#resultsSide header .btn, .results-actions .btn { font-size: 12px !important; white-space: normal !important; }

/* SORT BAR, SPLIT ACROSS TWO ROWS.
   The label, the sort buttons and the export/Brief me actions were all one
   nowrap row. Row one is now SORT BY plus the sort buttons; everything else
   drops to row two. The calc reserves room for the label so the sort group
   still claims the rest of the line. */
#sortBar { flex-wrap: wrap !important; gap: 8px !important; padding: 0 !important; }
#sortBar > small { flex: 0 0 auto; align-self: center; }
/* min-width:0 is the bit that makes an overflow-x child actually scroll
   instead of being clipped - a flex item defaults to min-width:auto. */
#sortBar > .sort-toggle-group { flex: 1 1 calc(100% - 86px); min-width: 0 !important; }
#sortBar > *:not(small):not(.sort-toggle-group) { flex: 0 0 auto; }
/* Brief me is the last control - let it take the space left on row two
   rather than leaving a gap beside the three icon buttons. */
#sortBar > *:last-child { flex: 1 1 auto !important; justify-content: center; }

/* SORT AS A SELECT (built by n360-mobile.js).
   Four side-by-side buttons will never fit 375px. Every CSS attempt either
   clipped them or produced a scroll strip nobody would find. A select is the
   native control for "pick one of these" and costs one line. */
body.n360-msort-on #sortBar .sort-toggle-group { display: none !important; }
.n360-msort {
    flex: 1 1 100% !important; min-width: 0;
    min-height: 46px; padding: 0 34px 0 12px;
    font-size: 15px; font-weight: 700;
    color: var(--bs-body-color, #1a1a1a);
    background-color: var(--bs-body-bg, #fff);
    border: 1.5px solid var(--bs-border-color, #ced4da);
    border-radius: 10px; cursor: pointer;
    -webkit-appearance: none; appearance: none;
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23666' d='M8 11L3 6h10z'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: right 12px center; background-size: 14px;
}
.n360-msort:focus-visible { outline: 3px solid var(--n360-cyan, #00bde7); outline-offset: 2px; }

/* SORT BY is a btn-group of four. It cannot wrap without looking broken, so
   let it scroll horizontally inside its own strip instead - the row stays
   usable and the page stops moving. */
.sort-toggle-group {
    display: flex !important; flex-wrap: nowrap !important;
    max-width: 100% !important; overflow-x: auto !important;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
}
.sort-toggle-group::-webkit-scrollbar { display: none; }
.sort-toggle-group .btn { flex: 0 0 auto; font-size: 11px !important; white-space: nowrap; }

/* Clear search and Apply Filters sit side by side and squeeze the label into
   four lines. Stack them, and put the primary action first. */
/* width:100% is not enough inside a flex row - the parent hands out space by
   basis, so these need flex-basis:100% to be forced onto their own line. */
#applyFiltersBtn, #clearSearchBtn {
    flex: 1 0 100% !important; width: 100% !important;
    margin: 0 0 8px !important; white-space: normal !important; min-height: 50px;
}
#applyFiltersBtn { order: -1; font-size: 15px !important; }

/* The dashboard standard form uses different classes to the results page:
   .btn-search-main ("Start searching") and .btn-clear-search. That trailing
   box on the right was the clear button refusing to wrap. */
.btn-search-main, .btn-clear-search {
    flex: 1 0 100% !important; width: 100% !important;
    margin: 0 0 8px !important; white-space: normal !important; min-height: 50px;
}
.btn-search-main { order: -1; }
#stdSearchForm .d-flex, #masterSearchForm .d-flex { flex-wrap: wrap !important; }

/* ---------------------------------------------------------------------
   4. FILTERS - COLLAPSED BY DEFAULT
   Two filters matter in the field: category and distance. The rest are a
   desktop concern and are put behind a toggle rather than deleted, so
   nothing is lost if someone does need them.
   --------------------------------------------------------------------- */
.n360-mfilters-btn {
    display: flex !important; align-items: center; justify-content: center; gap: 8px;
    width: 100%; min-height: 46px; margin-bottom: 10px;
    background: #fff; border: 1px solid #d7dee4; border-radius: 12px;
    font-size: 15px; font-weight: 700; color: var(--n360-primary-fill, #003450); /* v1.31: primary ink that stays dark in dark mode */
    cursor: pointer;
}
body:not(.filters-open) .n360-mfilter-panel { display: none !important; }

/* THE ACCESSIBILITY PANEL.
   .a11y-panel is position:absolute with right:0 inside .a11y-wrap, and is up
   to 300px wide. When the trigger sits near the right edge the panel extends
   leftwards past the viewport, which is why it was clipped down its left
   side. Pin it to the screen instead of to its trigger. */
.a11y-panel {
    position: fixed !important;
    top: calc(62px + env(safe-area-inset-top)) !important;
    left: 8px !important; right: 8px !important;
    width: auto !important; max-width: none !important;
    max-height: calc(100vh - 80px); overflow-y: auto;
}

/* Access and Theme popovers anchor to buttons near the right edge and open
   leftwards, so half the panel sits off-screen. Pin them to the viewport.

   v1.20 - `.dropdown-menu.show` REMOVED from this list. left/right offsets
   position an absolute box against its CONTAINING BLOCK, and a clock menu's
   containing block is its own ~100px .dropdown wrapper - so this rule was
   computing an 84px-wide menu and its min-width:0 was defeating the
   markup's inline min-width:320px. The named popovers keep the treatment;
   clock menus get their own below. */
#accMenu, .acc-detail-float, .acc-detail-box, .theme-menu {
    left: 8px !important; right: 8px !important;
    width: auto !important; min-width: 0 !important;
    max-width: calc(100vw - 16px) !important;
    transform: none !important;
}
/* Any other dropdown gets only a gentle sanity cap, nothing structural. */
.dropdown-menu { max-width: calc(100vw - 16px); }

/* THE CLOCK MENUS - dashboard (.topbar), provider (.n360-provclock) and
   results (.n360-ctlrow). All three toggles sit at the right edge, so the
   menu anchors to its cell's right corner and grows leftwards into the
   page: explicit width, so no containing-block arithmetic can squeeze it,
   and Popper's transform is overridden the same way for all three. */
.topbar .dropdown-menu,
.n360-provclock .dropdown-menu,
.n360-ctlrow .dropdown-menu {
    position: absolute !important;
    inset: auto !important;
    top: 100% !important; right: 0 !important; left: auto !important;
    transform: none !important; margin-top: 8px !important;
    width: min(300px, calc(100vw - 24px)) !important;
    min-width: 0 !important;
    max-width: calc(100vw - 24px) !important;
}

/* ---------------------------------------------------------------------
   5. DASHBOARD - STANDARD VIEW ONLY
   Smart view is a desk tool: it wants a description typed into it and then
   reading. In the field the standard search form is the faster path, so the
   choice is removed rather than offered.
   --------------------------------------------------------------------- */
#viewSeg, .seg-caption { display: none !important; }
#smartView { display: none !important; }
#standardView { display: block !important; }

/* v1.12 - THE TOPBAR, REDONE.
   v1.11 gave the clock a full row of its own because it is wide. That was
   solving the wrong problem: the clock is wide because it carries a 26px
   icon, seconds, a zone abbreviation, the words "Local time" and a chevron.
   On a phone the only part anyone reads is the time.

   So it shrinks and moves up beside the heading (the move itself is in
   n360-mobile.js - it lives in the other half of the header and CSS cannot
   reparent it). That buys back a whole row AND stops Access overlapping it,
   which is what the screenshot showed. Tapping still opens the full zone
   list, so nothing is lost - it is only the resting state that is smaller. */
.topbar { gap: 10px !important; margin-bottom: 14px !important; }
.topbar > div { width: 100% !important; }
.topbar .d-flex, .topbar > div > div { flex-wrap: wrap !important; }

/* Heading row: title left, compact clock hard right. */
.topbar > div:first-child {
    display: flex !important; align-items: center;
    gap: 8px !important; flex-wrap: wrap !important;
}
/* 1.15rem, not 1.25: "Operations Dashboard" plus the compact clock must fit
   one 390px line, and the heading is the flexible one of the two. */
.topbar h1 { font-size: 1.15rem; margin: 0; flex: 1 1 auto; min-width: 0; }
.topbar > div:first-child > .dropdown { flex: 0 0 auto; margin-left: auto; }
.welcome-chip { font-size: 12px; flex: 1 1 100%; }

/* THE COMPACT CLOCK, v1.18. Every selector hangs off the ID: the page's own
   inline <style> block styles these by class and loads after this sheet, so
   class-vs-class it always won. The ID settles it. And every width-bearing
   element gets min-width: 0, because the inline sheet's min-width: 188px
   (and 104px on the text) is what actually kept the pill off the heading
   line for five rounds - width: auto never touches a min-width floor.
   (This block also had two competing .tz-time sizes; the ID rule is now the
   only one.) */
#tzClockWidget {
    padding: 3px 10px !important; gap: 6px !important;
    min-height: 32px !important;
    min-width: 0 !important; width: auto !important; max-width: 100% !important;
    overflow: hidden;
}
#tzClockWidget .tz-clock-text {
    min-width: 0 !important; width: auto !important; text-align: left;
}
#tzClockWidget .tz-clock-icon {
    display: grid !important; place-items: center;
    width: 20px !important; height: 20px !important; min-width: 0 !important;
    font-size: 10px !important; flex: 0 0 auto;
}
#tzClockWidget .tz-clock-icon i { font-size: 10px !important; }
#tzClockWidget .tz-label { display: none !important; }
#tzClockWidget .tz-time { font-size: 12px !important; letter-spacing: 0 !important; }
#tzClockWidget .tz-abbr { font-size: 10px !important; margin-left: 4px; }
#tzClockWidget > .fa-chevron-down { display: none !important; }

/* v1.15 - Accessibility and Theme SHARE A ROW, always.
   v1.13 used a two-column grid with a fallback that collapsed to one column
   when the clock had not been moved. That fallback then stacked all three,
   which is the opposite of what it was for. Flex instead: the two controls
   size to their content and sit side by side, so "Accessibility" can be the
   wider of the two without forcing "Theme" to match it. If the clock is
   still in this group it takes a row to itself and the other two pair up
   underneath - degrading without ever stacking them. */
.topbar > div:last-child {
    display: flex !important;
    flex-wrap: wrap !important;
    gap: 8px !important;
    align-items: stretch;
}
.topbar > div:last-child > * {
    /* v1.16 - basis 0, not auto: the two pills get EQUAL widths regardless
       of label length, which "1 1 auto" never gave ("Accessibility" kept
       claiming more than "Theme"). */
    flex: 1 1 0; min-width: 0;
    justify-content: center; white-space: nowrap;
    font-size: 13px;
}
.topbar > div:last-child > .dropdown:has(#tzClockWidget) { flex: 1 1 100%; }

/* Full width. The dashboard and standard-search shells are centred narrow
   columns by design, which wastes most of a phone screen. */
.dash-shell, .std-shell { max-width: 100% !important; padding-left: 0 !important; padding-right: 0 !important; }
.n360-card { border-radius: 12px; }
.n360-card.p-4 { padding: 14px !important; }

.dash-grid, .kpi-grid, .stat-grid { grid-template-columns: 1fr !important; }
.dash-card, .kpi-card { margin-bottom: 10px; }

/* Alert bar full width, and everything inside allowed to wrap so the View
   board action stops being clipped off the right edge. */
.alert-strip, .critical-alerts, .alert-bar { width: 100% !important; flex-wrap: wrap !important; }
.alert-strip *, .critical-alerts *, .alert-bar * { max-width: 100%; }
.alert-strip .btn, .critical-alerts .btn, .alert-bar .btn {
    white-space: normal !important; margin-top: 8px;
    flex: 1 0 100% !important; width: 100% !important;
    justify-content: center;
}

/* The critical-alerts strip has no class of its own - it is identified here
   by the dismiss button it contains. View board was being clipped because
   the strip is a nowrap flex row. */
div:has(> #critDismiss) { flex-wrap: wrap !important; position: relative; padding-right: 44px !important; }
/* v1.32: the headline block sits BESIDE the 9px dot and shrinks to fit, instead of wrapping under it
   and leaving the dot alone on a line. Chips wrap inside the block. */
div:has(> #critDismiss) > .flex-grow-1 { flex: 1 1 0 !important; min-width: 0; }
div:has(> #critDismiss) .pill-btn {
    flex: 1 0 100% !important; width: 100% !important;
    justify-content: center; margin-top: 10px; white-space: nowrap;
}
div:has(> #critDismiss) .ct-chip { max-width: 100%; white-space: normal; }
/* v1.32: absolute against the banner (now position:relative), and a 24x24 target (2.5.8). */
#critDismiss { position: absolute; top: 8px; right: 8px; min-width: 24px; min-height: 24px; display: inline-flex; align-items: center; justify-content: center; }

/* ---------------------------------------------------------------------
   6. PROVIDER DETAIL - CONTACT FIRST
   The reason someone opened this page in the field is the phone number.
   --------------------------------------------------------------------- */
.provider-contact-block { order: -1; }
.provider-detail a[href^="tel:"] {
    display: flex; align-items: center; justify-content: center; gap: 9px;
    width: 100%; min-height: 52px;
    background: var(--n360-cyan, #00bde7);
    color: var(--n360-on-cyan, #04222c) !important;
    font-size: 18px; font-weight: 800; border-radius: 12px;
    text-decoration: none !important; margin: 8px 0 14px;
}

/* ---------------------------------------------------------------------
   6b. NAV, CULLED FOR THE FIELD

   Nobody standing in a car park needs Network Intelligence, Platform
   Preferences or the documentation. Leaving them in makes the drawer scroll,
   which buries the two links that actually matter.

   Done by href and by the section wrapper, so no markup change is needed. A
   link added later simply appears, and can be added here if it should not.
   --------------------------------------------------------------------- */
.n360-sidebar nav a[href="/NetworkIntelligence"] { display: none !important; }
.n360-sidebar:not([data-preview-navigation]) nav > div.border-top { display: none !important; }
.n360-sidebar nav { flex-grow: 0 !important; }

/* ---------------------------------------------------------------------
   6c. PROVIDER DETAIL PAGE

   This page carries its OWN dark sticky header - logo, PROVIDER INFORMATION,
   a quick search input group, provider local time, Access, Theme and Close -
   all in one nowrap flex row. At 375px it collapsed into the mess in the
   screenshots, with Close pushed off the right edge.

   The quick search is removed rather than reflowed: the global mobile header
   already carries one two pixels above it, and two search boxes stacked on a
   phone is worse than none. Close stays, because on this page it is the way
   back.
   --------------------------------------------------------------------- */
.d-flex.flex-grow-1:has(#topSearchInput) { display: none !important; }

/* Let the rest of that bar wrap instead of overflowing. */
header:has(#topSearchGo), .position-sticky:has(#topSearchGo) {
    flex-wrap: wrap !important; gap: 8px; padding: 8px 10px !important;
}

/* Close must always be reachable - it is the only way back off this page. */
.btn-close, .btn-close-white { flex: 0 0 auto; margin-left: auto; }

/* Provider tabs stack full width and get a real tap target. */
.pv-tabs .nav-link, .nav-pills .nav-link { min-height: 46px; font-size: 13px; }

/* Action row - AI summary toggle, PDF, Word, print, email, Edit record -
   is six controls in a nowrap row, and Edit Record was running off the
   right. Identified by the AI summary toggle it contains, since the row
   itself has no usable class. */
.pv-actions, .provider-actions { flex-wrap: wrap !important; gap: 8px !important; }
/* The row is <div class="d-flex gap-2 flex-shrink-0 align-items-center"> -
   flex-shrink-0 is precisely why Edit Record could not give way and ran off
   the edge. Let it wrap and shrink. */
.d-flex.gap-2.flex-shrink-0.align-items-center {
    flex-wrap: wrap !important; flex-shrink: 1 !important;
    width: 100%; justify-content: flex-start; gap: 8px !important;
}
/* Edit Record takes its own full-width line rather than being clipped. */
.pv-edit-btn, a[href*="/cms/"][class*="btn"], .btn:has(> .fa-pen-to-square) {
    flex: 1 0 100% !important; width: 100% !important;
    white-space: normal !important; justify-content: center;
}

/* The category breadcrumb is a long nowrap chain that runs off the edge.
   Let it scroll in place rather than clipping the last segment. */
/* CATEGORY CHAIN: WRAP, DO NOT SCROLL.
   v1.9 made these scroll horizontally, which still cut words off at the edge
   and - because the chain was nowrap - left the leading category icon
   stranded on its own line above the text.

   Wrapping fixes both: nothing is truncated, and the icon stays inline with
   the first segment. A three-level chain taking two lines on a phone is
   entirely reasonable. */
.cat-hover-wrapper, .cat-path, .pv-breadcrumb, .breadcrumb-chain {
    max-width: 100% !important;
    overflow: visible !important;
    white-space: normal !important;
    word-break: normal; overflow-wrap: anywhere;
    display: block !important;
}
/* Keep the icon on the same baseline as the first segment it belongs to. */
.cat-hover-wrapper > i, .cat-path > i:first-child { display: inline !important; vertical-align: baseline; }

/* Provider local time, Access and Theme sit in the page's own dark bar and
   still overflow. Same treatment as the dashboard topbar: wrap, and let the
   time block take a full row. */
header:has(#topSearchGo) > *, .position-sticky:has(#topSearchGo) > * { min-width: 0; }
header:has(#topSearchGo) .d-flex, .position-sticky:has(#topSearchGo) .d-flex {
    flex-wrap: wrap !important;
}

/* ---------------------------------------------------------------------
   7. DESKTOP-ONLY FEATURES, HIDDEN RATHER THAN SHRUNK
   Cutting these is the design, not a compromise. Someone who wanted a
   dossier would wait until they were sat down.
   --------------------------------------------------------------------- */
#mapSide, #resizerGutter,
.export-toolbar, .results-export, .brief-me-btn,
.ai-brief-panel, .country-brief-inline,
.sort-bar-desktop, .search-eg { display: none !important; }

/* ---------------------------------------------------------------------
   8. TOUCH AND TYPOGRAPHY
   --------------------------------------------------------------------- */
/* v1.17 - checkboxes and radios EXCLUDED. This rule was inflating the
   feedback modal's radio circles into 44px ovals: a radio must stay a small
   circle, and its 44px target comes from the label wrapped around it, not
   from stretching the control itself. */
button, .btn, select, a.btn,
input:not([type="checkbox"]):not([type="radio"]) { min-height: 44px; }   /* WCAG 2.5.8 target size */
input[type="checkbox"], input[type="radio"] {
    width: 20px; height: 20px; min-height: 0 !important;
    flex: 0 0 auto; margin-top: 0.15em;
}
input, select, textarea { font-size: 16px !important; }    /* no iOS zoom on focus */
.small, .text-muted { font-size: 13px; }
table { font-size: 13px; }

/* Modals become sheets - full width, anchored to the bottom, thumb-reachable. */
/* v1.33: the modal and its backdrop above the header (10040), the drawer backdrop (10050) and the
   drawer (10060). Bootstrap 5.3 reads these two custom properties for its z-index; the explicit
   z-index is the belt for any build that does not. A modal is the top-most thing on the screen. */
.modal-backdrop { --bs-backdrop-zindex: 10070; z-index: 10070 !important; }
.modal { --bs-modal-zindex: 10080; z-index: 10080 !important; }
.modal-dialog { margin: 0; max-width: 100%; align-items: flex-end; min-height: 100%; }
.modal-content { border-radius: 16px 16px 0 0; }

/* =====================================================================
   9. v1.12  -  ROUND 2
   ===================================================================== */

/* ---------------------------------------------------------------------
   9a. RESULT CARD - the category icon and that stray dot

   The icon sat on its own line because the row is a wrapping flex and the
   category chain is a block-level wrapper that claimed the full width. It
   is now moved INTO the provider name by n360-mobile.js, which is where it
   reads as a label for the provider rather than as a lost glyph.

   The dot was never a list bullet. The markup is
   `<span class="mx-1">&bull;</span> Intelligence Verified` - a separator
   that reads correctly inline on desktop and lands at the start of a
   wrapped line on a phone, looking exactly like a bullet. It goes, and the
   text it separated becomes a badge instead (wrapped by the JS, because a
   bare text node cannot be styled).
   --------------------------------------------------------------------- */
.result-card h5 .n360-cat-icon {
    font-size: 15px; margin-right: 7px;
    vertical-align: baseline; flex: 0 0 auto;
}
.result-card .cat-hover-wrapper + span.mx-1 { display: none !important; }
.result-card .n360-verified {
    display: inline-flex; align-items: center;
    font-size: 11px; font-weight: 700; letter-spacing: .02em;
    padding: 2px 8px; border-radius: 999px;
    background: rgba(0, 189, 231, .14);
    color: var(--n360-cyan, #00bde7);
    margin-top: 2px;
}

/* ---------------------------------------------------------------------
   9b. DRAWER - AN EXPLICIT WAY OUT

   Tap-outside-to-close is a convention, not an affordance: there is nothing
   on screen telling you it exists. The button is injected into the drawer
   by n360-mobile.js so no markup change is needed, and Escape works too.
   --------------------------------------------------------------------- */
/* v1.32 - 2.5.8 TARGET SIZE on the small icon controls this sheet did not size explicitly. Each sits
   inside a padded row next to other controls, so the "24px spacing" exception does not rescue it. */
.notice-x, .pill-x, .n360-chip .x, .fav-x, .btn-close, .pin-btn, .sb-quick-item, .a11y-ctl button {
    min-width: 24px; min-height: 24px;
}

.n360-navclose {
    position: absolute; top: 10px; right: 10px; z-index: 2;
    width: 40px; height: 40px; min-height: 40px;
    border: 1px solid rgba(255,255,255,.22); border-radius: 11px;
    background: rgba(255,255,255,.12); color: #fff;
    font-size: 22px; line-height: 1; font-weight: 300;
    display: grid; place-items: center; cursor: pointer; padding: 0;
}
.n360-navclose:active { background: rgba(255,255,255,.24); }

/* v1.13 - v1.12 reserved 56px at the top for the close button. The drawer
   already had generous padding above the logo, so that stacked into a large
   band of nothing. The button is absolutely positioned in the corner and
   needs no reserved space at all; the padding comes DOWN instead. */
.n360-sidebar { position: fixed; padding-top: 10px !important; }
.n360-sidebar > *:first-child { margin-top: 0 !important; }

/* ---------------------------------------------------------------------
   9c. PROVIDER - THE ACTION ROW

   Six controls of three different shapes in one nowrap flex row. v1.11 let
   it wrap, which stopped the overflow but left the AI summary toggle
   sharing a line with the export icons and pushing email onto a second row
   on its own.

   A grid instead: the toggle takes a full row as a proper labelled control,
   the five icon actions take one column each, and Edit Record spans the
   bottom. Identified by the toggle it contains - the row has no class.
   --------------------------------------------------------------------- */
div:has(> .ai-export-toggle) {
    display: grid !important;
    grid-template-columns: repeat(5, 1fr);
    gap: 8px !important;
    width: 100%; margin-top: 10px;
}
.ai-export-toggle {
    grid-column: 1 / -1;
    display: flex !important; justify-content: space-between !important;
    margin: 0 !important; padding: 11px 14px; min-height: 48px;
    background: rgba(0,0,0,.035);
    border: 1px solid rgba(0,0,0,.12); border-radius: 12px;
}
.ai-export-toggle-label {
    font-size: 13px; font-weight: 700; letter-spacing: .02em;
    text-transform: none;
}
/* The switch rendered as a plain grey circle because it inherited no width.
   Size it explicitly rather than relying on the desktop sheet. */
.n360-switch { padding-left: 0 !important; min-height: 0 !important; }
.n360-switch .form-check-input {
    width: 46px !important; height: 26px !important;
    margin: 0 !important; float: none !important;
    min-height: 0 !important; border-radius: 999px !important;
}
div:has(> .ai-export-toggle) > .action-btn {
    width: 100% !important; height: 48px; min-height: 48px;
    margin: 0 !important; display: grid !important; place-items: center;
}
div:has(> .ai-export-toggle) > .btn-primary,
div:has(> .ai-export-toggle) > .btn:has(.fa-pen-to-square) {
    grid-column: 1 / -1; width: 100% !important; justify-content: center;
}

/* Long uppercase provider names wrap badly at 375px. */
.provider-detail h1, h1.fw-bold { font-size: 1.35rem !important; letter-spacing: 0 !important; }

/* ---------------------------------------------------------------------
   9d. PROVIDER TABS - LOOK TAPPABLE, AND PROVE SOMETHING HAPPENED

   Two separate faults wearing one coat. The pills were styled as a quiet
   desktop sidebar list, so on a phone they read as headings rather than
   controls. And because the panel they switch is below the fold, tapping
   one changed something nobody could see - which is indistinguishable from
   a dead link.

   Styling fixes the first. The scroll-into-view in n360-mobile.js fixes the
   second, and it is the more important of the two.

   The chevron is drawn in CSS, not Font Awesome. A wrong or Pro-only icon
   name renders NOTHING, silently - which has already cost us once on this
   project. Borders cannot fail that way.
   --------------------------------------------------------------------- */
.n360-nav-pills { gap: 8px; }
.n360-nav-pills .nav-link {
    position: relative;
    background: #fff;
    border: 1px solid rgba(0,0,0,.13);
    border-radius: 12px;
    box-shadow: 0 1px 2px rgba(0,0,0,.05);
    padding: 14px 46px 14px 14px !important;
    min-height: 54px; font-size: 14px !important; font-weight: 700;
    text-align: left; display: flex; align-items: center; gap: 10px;
}
.n360-nav-pills .nav-link::after {
    content: ""; position: absolute; right: 18px; top: 50%;
    width: 9px; height: 9px; margin-top: -6px;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(-45deg); opacity: .4;
    transition: transform .18s ease, opacity .18s ease;
}
/* Active points DOWN - "the section you asked for is below this". */
.n360-nav-pills .nav-link.active::after { transform: rotate(45deg); opacity: .95; }
.n360-nav-pills .nav-link.active {
    box-shadow: 0 2px 10px rgba(0,0,0,.16);
}
.n360-nav-pills .nav-link:active { transform: scale(.99); }

/* Tapping a tab scrolls to the panel; it needs to clear the fixed header. */
.tab-content { scroll-margin-top: calc(64px + env(safe-area-inset-top)); }

/* The tab column must not be sticky on a phone - it pins a full-height list
   of buttons over the content it just scrolled you to. */
.col-lg-3 > .position-sticky { position: static !important; }

/* ---------------------------------------------------------------------
   9e. PROVIDER - LAST UPDATED GOES LAST

   It sits in the left column with the tab list, so on a stacked phone
   layout it landed between the tabs and the content it describes. Moved
   below everything by n360-mobile.js; this is just its resting style.
   --------------------------------------------------------------------- */
.n360-lastupdated {
    margin: 22px 0 0 !important; padding-top: 16px !important;
    border-top: 1px solid rgba(0,0,0,.12);
}

/* ---------------------------------------------------------------------
   9f. PANEL HEADERS - TITLE AND ACTION STOP FIGHTING

   Every tab panel opens with a title and an action button in a
   space-between row. At 375px the title wraps to three lines and the
   button sits on top of it. Stack them.
   --------------------------------------------------------------------- */
.tab-pane .d-flex.justify-content-between.align-items-center.border-bottom {
    flex-direction: column; align-items: stretch !important; gap: 12px;
}
.tab-pane .d-flex.justify-content-between.align-items-center.border-bottom > h4,
.tab-pane .d-flex.justify-content-between.align-items-center.border-bottom > h5 {
    font-size: 1.05rem; line-height: 1.3;
}
.tab-pane .d-flex.justify-content-between.align-items-center.border-bottom > .btn {
    width: 100%; justify-content: center; white-space: normal;
}

/* =====================================================================
   10. v1.13  -  ROUND 3
   ===================================================================== */

/* ---------------------------------------------------------------------
   10a. PROVIDER PAGE HEADER - Theme was running off the right edge

   v1.11 tried to fix this with
       header:has(#topSearchGo), .position-sticky:has(#topSearchGo)
   but the element is neither: it is `<div class="layer-header">`. The rule
   has never matched anything, which is why the header has looked the same
   through three rounds. Target the class that is actually there.

   The provider clock gets the same treatment as the dashboard one - it
   carries the words "Provider Local Time" and a chevron, which is most of
   its width and none of its value on a phone.
   --------------------------------------------------------------------- */
.layer-header {
    flex-wrap: wrap !important;
    gap: 8px !important;
    padding: 8px 10px !important;
}
.layer-header > div:last-child {
    width: 100% !important;
    display: flex !important; flex-wrap: wrap !important;
    gap: 8px !important; align-items: center;
}
/* v1.17 - basis 0: with the clock lifted out (n360-mobile.js) the group is
   Accessibility and Theme only, and they share the row as EQUALS - auto let
   the longer label claim more. */
.layer-header > div:last-child > * {
    flex: 1 1 0; min-width: 0; margin: 0 !important;
    display: inline-flex; align-items: center; justify-content: center;
    min-height: 42px; font-size: 13px; white-space: nowrap;
}
.layer-header > div:last-child .btn-close,
.layer-header > div:last-child .btn-close-white { flex: 0 0 auto; }

#providerTimeToggle { padding: 6px 10px !important; justify-content: center; }
#providerTimeToggle .text-white-50 { display: none !important; }   /* "Provider Local Time" */
#providerTimeToggle .fa-chevron-down { display: none !important; }
#providerTimeToggle .me-2 { margin-right: 6px !important; }

/* ---------------------------------------------------------------------
   10b. THE TABS BECOME AN ACCORDION

   A vertical list of seven headings where tapping one reveals content is an
   accordion, not a tab set. Each panel is moved directly beneath its own
   heading by n360-mobile.js, and tapping the open heading collapses it.

   The heading and its open panel are drawn as one object - square corners
   where they meet, and no gap - so it reads as the heading having opened
   rather than as two stacked cards.
   --------------------------------------------------------------------- */
.n360-acc { display: block !important; }
.n360-acc .nav-link { width: 100%; margin: 0 0 8px !important; }
.n360-acc .nav-link.active {
    margin-bottom: 0 !important;
    border-radius: 12px 12px 0 0;
    border-bottom-color: transparent;
}
.n360-acc-pane { display: none !important; }
.n360-acc-pane.show.active {
    display: block !important;
    opacity: 1 !important;
    border: 1px solid rgba(0,0,0,.13);
    border-top: 0;
    border-radius: 0 0 12px 12px;
    background: #fff;
    padding: 14px !important;
    margin: 0 0 10px !important;
}
/* The panel already sits in a bordered container now, so the card inside it
   would be a second box around the same content. */
.n360-acc-pane .n360-claude-card {
    border: 0 !important; box-shadow: none !important;
    padding: 0 !important; background: transparent !important;
    border-radius: 0 !important;
}
/* The emptied tab-content would otherwise leave a gap and a stray border. */
.n360-acc-empty { display: none !important; }

/* Wide tables inside a panel scroll rather than stretching the page. */
.n360-acc-pane table { min-width: 0; }
.n360-acc-pane .table-responsive { -webkit-overflow-scrolling: touch; }

/* ---------------------------------------------------------------------
   10c. LAST UPDATED - genuinely last

   Moved below the accordion by the script. This keeps it quiet: it is
   metadata about the record, not content.
   --------------------------------------------------------------------- */
.n360-lastupdated {
    margin: 26px 0 0 !important; padding-top: 16px !important;
    border-top: 1px solid rgba(0,0,0,.12);
    opacity: .85;
}

/* ---------------------------------------------------------------------
   10d. v1.14 - CLOSE BELONGS IN THE CORNER

   Close was sitting in the control group with the clock, Access and Theme,
   which made it read as a fourth option rather than as "leave this page".
   Top right of the header is where a close control is looked for, and
   pinning it there also takes it out of the row that was overflowing.

   Identified by the xmark it carries: the button has no class of its own
   and the page uses .btn-close for alert dismissals, so matching on that
   would have moved the wrong things.
   --------------------------------------------------------------------- */
.layer-header { position: relative; }
.layer-header button:has(.fa-xmark) {
    position: absolute !important;
    top: 8px; right: 10px; z-index: 3;
    margin: 0 !important; flex: 0 0 auto !important;
    min-height: 38px; padding: 6px 14px !important;
}
/* Keep the logo row clear of it. */
.layer-header > div:first-child { padding-right: 96px; }

/* =====================================================================
   11. v1.15  -  ROUND 5
   ===================================================================== */

/* ---------------------------------------------------------------------
   11a. VIEW PROVIDER DETAILS WAS INVISIBLE, NOT MISSING

   The card CTA is a .btn-primary, and Bootstrap gives .btn-primary
   `color: #fff`. v1.7 turned it into an outline button with
   `background: transparent` and `border: 1.5px solid currentColor` - so on
   a white card it became white text inside a white border on white.

   currentColor was chosen so the outline would follow the card's text
   through the hover state without knowing the theme. That is the same
   mistake as the call button in v1.4: anything needing guaranteed contrast
   gets a fixed value, never an inherited or theme-derived one.
   --------------------------------------------------------------------- */
.result-card .btn.rounded-pill {
    color: #12161b !important;
    border-color: #12161b !important;
}
.result-card .btn.rounded-pill i { color: #12161b !important; }
/* results.css sets the whole card to the theme colour on hover, so the
   button inverts with it rather than disappearing again. */
.result-card:hover .btn.rounded-pill,
.result-card:hover .btn.rounded-pill i {
    color: #ffffff !important;
    border-color: #ffffff !important;
}

/* ---------------------------------------------------------------------
   11b. CLOSE, FULL WIDTH, ON ITS OWN ROW

   v1.14 pinned it to the top corner, which made it small and easy to miss.
   It is the way off this page, so it gets the width. Lifted out of the
   control group by n360-mobile.js and dropped in directly under the logo.
   --------------------------------------------------------------------- */
.layer-header button.n360-closerow {
    position: static !important;
    flex: 1 1 100% !important;
    width: 100% !important;
    order: 0;
    justify-content: center;
    min-height: 46px; margin: 0 !important;
    font-size: 15px;
}
/* The corner positioning and the space reserved for it both go. */
.layer-header > div:first-child { padding-right: 0; }

/* ---------------------------------------------------------------------
   11c. LAST UPDATED ON ONE LINE

   Two short values on two lines, each with an icon, in a full-width block.
   They fit side by side with room to spare.
   --------------------------------------------------------------------- */
.n360-lastupdated {
    display: flex; flex-wrap: wrap;
    align-items: baseline; gap: 4px 18px;
    width: 100%;
}
.n360-lastupdated > .data-label { flex: 1 1 100%; margin-bottom: 2px !important; }
.n360-lastupdated > .small { flex: 0 1 auto; white-space: nowrap; }

/* =====================================================================
   12. v1.16  -  ROUND 6
   ===================================================================== */

/* ---------------------------------------------------------------------
   12a. THE RESULTS HEADER IS NOT A .topbar

   Every row-of-controls rule so far targeted .topbar, which the results
   page does not have - its Return-to-dashboard / Accessibility / Theme row
   is a different container. That is why Theme kept hanging off the edge
   there while the dashboard behaved. Target the one stable thing the row
   is guaranteed to contain on every page: the theme toggle.

   The link is shortened to "Dashboard" by n360-mobile.js, so three equal
   controls fit one row.
   --------------------------------------------------------------------- */
/* v1.17 - .n360-ctlrow is set by n360-mobile.js on the row that holds the
   shortened Dashboard link. The :has() selector stays as a fallback, but the
   class is deterministic - this row's markup has never been supplied, and
   guessing at it is what kept Theme hanging off the edge for three rounds. */
div:has(> #themeToggle), .n360-ctlrow {
    display: flex !important;
    flex-wrap: wrap !important;
    gap: 8px !important;
    align-items: stretch;
    width: 100%; max-width: 100%;
}
div:has(> #themeToggle) > * {
    flex: 1 1 0; min-width: 0;
    display: inline-flex; align-items: center; justify-content: center;
    white-space: nowrap; font-size: 13px;
    margin: 0 !important;
}
/* v1.20 - Results.cshtml is in hand: the row's real children are
   #returnDashboardBtn, the clock's .dropdown (d-none d-xl-block), the
   Accessibility partial and #themeToggleBtn - in exactly the 2x2 order KP
   wants. div:has(> #themeToggleBtn) joins as a no-JS fallback now the real
   id is known (#themeToggle, guessed earlier, exists only on the
   dashboard). */
div:has(> #themeToggleBtn) {
    display: flex !important; flex-wrap: wrap !important;
    gap: 8px !important; align-items: stretch;
    width: 100%; max-width: 100%;
}

/* v1.19 - EQUAL 2x2. KP wants two per row, all the same size: basis
   calc(50% - half the gap) gives every control exactly half the row, and
   grow 1 lets an odd last control take a full row rather than half an
   empty one. */
div:has(> #themeToggleBtn) > *,
.n360-ctlrow > * {
    flex: 1 1 calc(50% - 4px); min-width: calc(50% - 4px); max-width: 100%;
    display: inline-flex; align-items: center; justify-content: center;
    white-space: nowrap; font-size: 13px; min-height: 44px;
    margin: 0 !important;
    /* v1.29 - the 10px horizontal padding that used to sit here was the
       root cause of the entire equal-buttons saga: on WRAPPER cells it
       shrank the inner button's containing block by 20px. Controls get
       their padding from the unified pill rule (section 17); cells get
       NONE - see section 20. Found by Sol. */
    overflow: hidden;
}
/* The shortened link must not wrap back onto two lines. */
[data-n360dash="1"] { white-space: nowrap !important; }

/* ---------------------------------------------------------------------
   12b. DEAD VERTICAL SPACE

   Above the Last Updated hairline: the page's main grid is a Bootstrap
   row.g-5, and g-5 is a 3rem gutter in BOTH axes - so when the two columns
   stack on a phone, 3rem of gutter-y opens up between the accordion and
   the metadata below it. Desktop keeps its 3rem; this only changes the
   stacked layout.

   Above the footer: the accessibility statement sits in
   <footer class="container-xxl pb-4 pt-2"> after a container carrying its
   own bottom padding. Trim both ends of the join.
   --------------------------------------------------------------------- */
.row.g-5 {
    --bs-gutter-y: 0.75rem;
    --bs-gutter-x: 0.75rem;
}
.n360-lastupdated {
    margin: 8px 0 0 !important;
    padding-top: 12px !important;
}
footer.container-xxl { padding-top: 0 !important; margin-top: 4px; }
footer.container-xxl > * { margin-top: 0 !important; }

/* =====================================================================
   13. v1.17  -  ROUND 7
   ===================================================================== */

/* ---------------------------------------------------------------------
   13a. PROVIDER HEADER, FINAL SHAPE
   Row 1: Close, full width.
   Row 2: logo, clock at the right (moved there by n360-mobile.js).
   Row 3: Accessibility and Theme, equal.

   v1.22 - the logo row is selected by the LOGO it contains. It used to be
   `> div:first-child`, which stopped matching the moment v1.7 made Close
   the header's first child - Close is a <button>, so `div:first-child`
   matched nothing at all and the row only still looked right by accident.
   --------------------------------------------------------------------- */
.layer-header > div:has(> img) {
    display: flex !important; align-items: center;
    width: 100% !important; min-width: 0;
}
/* The clock takes the same half-row the Theme button takes two rows down,
   so the header reads as a grid rather than three unrelated arrangements. */
.n360-provclock {
    margin-left: auto !important;
    flex: 0 0 calc(50% - 4px) !important;
    max-width: calc(50% - 4px);
}
.n360-provclock #providerTimeToggle {
    width: 100% !important; justify-content: center !important;
    padding: 4px 10px !important; min-height: 44px !important;
    border-radius: 999px !important;
}

/* ---------------------------------------------------------------------
   13b. THE CATEGORY CHAIN WRAPS

   It is a Bootstrap .badge, and .badge is white-space: nowrap - which is
   the entire reason "Military and Defence..." ran off the edge. Let it
   wrap like the text it is.
   --------------------------------------------------------------------- */
.badge:has(> .fa-sitemap) {
    white-space: normal !important;
    display: inline-flex !important; flex-wrap: wrap !important;
    row-gap: 2px; text-align: left; line-height: 1.5;
    max-width: 100%;
}

/* ---------------------------------------------------------------------
   13c. CREDENTIALS: CARDS, NOT A CLIPPED TABLE

   Six columns will never fit 375px, and a sideways-scrolling table hides
   exactly the columns that matter (expiry). Each row becomes a card: the
   document details lead, the status badge and dates follow, each date
   carrying its label back from the murdered thead via ::before.

   Scoped to the one table on this page (#tab-credentials .table-modern) -
   the nth-child labels below are THIS table's column order and would be
   wrong anywhere else.
   --------------------------------------------------------------------- */
#tab-credentials .table-responsive { overflow: visible !important; }
#tab-credentials .table-modern,
#tab-credentials .table-modern tbody,
#tab-credentials .table-modern tr,
#tab-credentials .table-modern td {
    display: block !important; width: 100% !important;
}
#tab-credentials .table-modern thead { display: none !important; }
#tab-credentials .table-modern tr.data-row {
    border: 1px solid rgba(0,0,0,.13) !important;
    border-radius: 12px; background: #fff;
    padding: 12px 14px; margin: 0 0 10px;
    box-shadow: 0 1px 2px rgba(0,0,0,.05);
}
#tab-credentials .table-modern td {
    padding: 3px 0 !important; border: 0 !important;
}
#tab-credentials .table-modern td:empty { display: none !important; }
/* The dates get their thead labels back. Column order: 1 details, 2 status,
   3 receipt, 4 valid from, 5 expiry, 6 attachment. */
#tab-credentials .table-modern td:nth-child(3)::before { content: "Received: "; }
#tab-credentials .table-modern td:nth-child(4)::before { content: "Valid from: "; }
#tab-credentials .table-modern td:nth-child(5)::before { content: "Expires: "; }
#tab-credentials .table-modern td:nth-child(3)::before,
#tab-credentials .table-modern td:nth-child(4)::before,
#tab-credentials .table-modern td:nth-child(5)::before {
    font-size: 11px; font-weight: 700; text-transform: uppercase;
    letter-spacing: .03em; color: rgba(0,0,0,.55); margin-right: 4px;
}
/* Attachment action reads as the card's button. */
#tab-credentials .table-modern td:nth-child(6) { padding-top: 8px !important; }
#tab-credentials .table-modern td:nth-child(6) .btn,
#tab-credentials .table-modern td:nth-child(6) a {
    width: 100%; justify-content: center;
}

/* =====================================================================
   14. v1.18  -  ROUND 8
   ===================================================================== */

/* ---------------------------------------------------------------------
   14a. PANEL TITLES ON ONE LINE
   "Site-Specific Operational Files" wrapped at 1.05rem. 0.95rem clears it
   at 375px, and these are section labels, not reading text.
   --------------------------------------------------------------------- */
.tab-pane .d-flex.justify-content-between.align-items-center.border-bottom > h4,
.tab-pane .d-flex.justify-content-between.align-items-center.border-bottom > h5 {
    font-size: 0.95rem !important; letter-spacing: 0 !important;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    max-width: 100%;
}
.tab-pane .d-flex.justify-content-between.align-items-center.border-bottom > h4 i,
.tab-pane .d-flex.justify-content-between.align-items-center.border-bottom > h5 i {
    margin-right: 6px !important;
}

/* ---------------------------------------------------------------------
   14b. THE FOOTER MOVES UP
   #mainContent is container-xxl py-5 - 3rem of bottom padding sitting
   directly above the footer. Trimmed below lg only; desktop keeps it.
   --------------------------------------------------------------------- */
/* py-5 is 3rem top AND bottom. The top pushed the status pills a long way
   down the screen; the bottom stranded the footer. Both trimmed on mobile
   only - desktop keeps its 3rem. */
#mainContent { padding-top: 14px !important; padding-bottom: 16px !important; }
/* v1.22 - a hairline between the page content and the accessibility
   statement, on every page. The 16px above it comes from #mainContent's
   trimmed padding-bottom and the 16px below from the footer's padding-top,
   so the rule sits evenly between the two. Theme-aware, so it survives
   dark mode. */
footer.container-xxl {
    margin-top: 0 !important;
    /* Longhand, not the `border-top: 1px solid var(...)` shorthand: a
       shorthand containing var() is unverifiable in the harness (jsdom
       drops the whole declaration), and an untestable rule is how the
       silent failures in this file started. Longhand is identical to a
       browser and provable here. */
    border-top-width: 1px;
    border-top-style: solid;
    border-top-color: var(--bs-border-color, rgba(0,0,0,.12));
    padding-top: 16px !important;
    padding-bottom: 16px !important;
}

/* =====================================================================
   15. v1.19  -  ROUND 9
   ===================================================================== */

/* ---------------------------------------------------------------------
   15a. APPLY FILTERS - ICON STAYS ON THE LINE

   results.js writes `APPLY FILTERS (9 RESULTS) <i ...magnifying-glass>`
   into #applyFiltersBtn. At 375px the uppercase text with its wide
   letter-spacing filled the line and the icon wrapped beneath. The spacing
   and size come down and the whole content is declared unwrappable - the
   text is the flexible part, the icon never leaves the line.
   --------------------------------------------------------------------- */
#applyFiltersBtn {
    white-space: nowrap !important;
    font-size: 13px !important;
    letter-spacing: .02em !important;
    display: flex !important; align-items: center; justify-content: center;
    gap: 6px; overflow: hidden;
}
#applyFiltersBtn > i { flex: 0 0 auto; margin-left: 0 !important; }

/* ---------------------------------------------------------------------
   15b. SITE-SPECIFIC OPERATIONAL FILES, ONE LINE

   Round 8 styled panel headers that sit inside a flex
   .justify-content-between wrapper - and THIS one is not in one. It is a
   bare `h4.fw-bold.mb-4.border-bottom.pb-3` directly in the pane, so the
   earlier rule never matched it. Matched directly now, sized to clear
   375px on one line.
   --------------------------------------------------------------------- */
.n360-acc-pane h4.fw-bold.border-bottom {
    font-size: 0.95rem !important; letter-spacing: 0 !important;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    max-width: 100%;
    margin-bottom: 14px !important; padding-bottom: 10px !important;
}
.n360-acc-pane h4.fw-bold.border-bottom i { margin-right: 6px !important; }

/* ---------------------------------------------------------------------
   15c. THE ATTACHMENT ICON CENTRES

   The download control is `a.btn.btn-sm.btn-light` holding one fs-5 icon.
   Stretched to full width by 13c, the anchor kept its inline baseline
   alignment, which floats a lone icon high. Flex centring on both axes.
   --------------------------------------------------------------------- */
#tab-credentials .table-modern td:nth-child(6) .btn {
    display: inline-flex !important;
    align-items: center !important; justify-content: center !important;
    min-height: 44px; line-height: 1 !important;
    padding: 10px !important;
}
#tab-credentials .table-modern td:nth-child(6) .btn i {
    line-height: 1 !important; vertical-align: middle;
}

/* =====================================================================
   16. v1.20  -  ROUND 10: THE RESULTS CLOCK RETURNS
   ===================================================================== */

/* The wrapper is `d-none d-xl-block` - the page hides its clock below
   1200px. n360-mobile.js removes the d-none on mobile and stamps the
   wrapper .n360-clockcell (and puts d-none back at teardown): a class on
   the real element, provable in the harness, no specificity arithmetic
   against .d-none's !important. The :has() forms remain as a no-JS
   fallback. DOM order is already Dashboard, clock, Accessibility, Theme,
   so the 2x2 lands as row 1 Dashboard + clock, row 2 Accessibility +
   Theme. overflow stays visible on this one cell - the cells clip
   spilling text by design, and this cell has a menu to open. */
.n360-clockcell,
.n360-ctlrow > div:has(> #tzClockWidget),
div:has(> #themeToggleBtn) > div:has(> #tzClockWidget) {
    display: inline-flex !important;
    overflow: visible !important;
    position: relative;
}
.n360-clockcell #tzClockWidget,
.n360-ctlrow #tzClockWidget,
div:has(> #themeToggleBtn) #tzClockWidget {
    width: 100% !important; justify-content: center !important;
}

/* =====================================================================
   17. v1.21  -  ONE LOOK FOR THE RESULTS HEADER CONTROLS

   Dashboard and Theme carry rounded-pill in the markup yet render with
   small corners - whatever strips it lives in results.css, which has
   never been supplied. It does not matter: ids outrank it wherever it
   loads. All four controls share the pill shape, the same theme-aware
   border, the same height; wrapper cells (clock, Accessibility partial)
   have their inner button fill the cell so the pill IS the cell, like
   its neighbours.
   ===================================================================== */
/* v1.23 - .n360-ctlcell / .n360-ctlbtn are stamped by n360-mobile.js on
   every control row: the cell is whatever child the row has, the button is
   whatever button or link sits inside it. Structure-agnostic, so the
   Accessibility partial is covered without knowing its markup.

   Longhand border properties, not the `border:` shorthand: the shorthand
   would need var() to stay theme-aware, and a shorthand containing var()
   cannot be verified in the harness. */
.n360-ctlbtn, #returnDashboardBtn, #themeToggleBtn, .a11y-wrap .a11y-trigger,
.n360-ctlrow #tzClockWidget,
/* No-JS fallback: the wrappers we CAN see, kept alongside the stamps so a
   blocked or failed script still leaves the visible controls consistent. */
.n360-ctlrow .dropdown > button,
.layer-header > div:last-child .dropdown > button,
.topbar > div:last-child .dropdown > button {
    border-radius: 999px !important;
    border-width: 1px !important;
    border-style: solid !important;
    border-color: var(--bs-border-color, #cfd6dd) !important;
    background: var(--bs-body-bg, #fff);
    box-shadow: 0 1px 2px rgba(0,0,0,.06) !important;
    min-height: 44px !important;
    width: 100% !important;
    justify-content: center !important;
    padding-left: 10px !important; padding-right: 10px !important;
    font-size: 13px !important;
}
/* Cells share the row equally; the button fills its cell, so every control
   is the same size whatever it is wrapped in. */
.n360-ctlcell { display: inline-flex !important; min-width: 0; }
.n360-ctlcell > .n360-ctlbtn { flex: 1 1 auto; }
.n360-ctlrow > .dropdown, .layer-header > div:last-child > .dropdown,
.topbar > div:last-child > .dropdown { display: inline-flex !important; min-width: 0; }

/* ---------------------------------------------------------------------
   18. v1.23 - THE RESCUED NOTICEBOARD

   "View board" links to #noticeboard, which lives inside #smartView - the
   half THIS file hides on mobile. The link was scrolling to a hidden
   element, so nothing happened. n360-mobile.js moves the board out to sit
   after the standard view; this gives it room and stops the fixed header
   covering its heading when the link jumps to it.
   --------------------------------------------------------------------- */
.n360-noticeboard {
    display: block !important;
    margin: 16px 0 0 !important;
    scroll-margin-top: calc(64px + env(safe-area-inset-top));
}
.n360-noticeboard.h-100 { height: auto !important; }

/* =====================================================================
   19. v1.24  -  ROUND 14
   ===================================================================== */

/* ---------------------------------------------------------------------
   19a. CONTROL ROWS: GRID, NOT FLEX

   Two of the four controls are bare buttons and two are wrapped by a
   component, so under flex the bare ones sized from their own content and
   the wrapped ones from their wrapper - equal cells, unequal buttons.
   `grid-template-columns: 1fr 1fr` makes the columns identical by
   definition, and every control fills its column whatever it is wrapped
   in. Covers all three rows: results, provider header, dashboard.
   --------------------------------------------------------------------- */
.n360-ctlrow,
div:has(> #themeToggleBtn),
.layer-header > div:last-child,
.topbar > div:last-child {
    display: grid !important;
    grid-template-columns: 1fr 1fr !important;
    gap: 8px !important;
    align-items: stretch !important;
    width: 100% !important;
}
/* The flex basis and its min-width floor must not survive into the grid -
   a 50% min-width inside a 1fr column overflows the row. */
.n360-ctlrow > *,
div:has(> #themeToggleBtn) > *,
.layer-header > div:last-child > *,
.topbar > div:last-child > * {
    min-width: 0 !important; max-width: 100% !important;
    margin: 0 !important;
}
.n360-ctlcell, .n360-clockcell, .n360-ctlfill,
.n360-ctlrow > .dropdown,
.layer-header > div:last-child > .dropdown,
.topbar > div:last-child > .dropdown { width: 100% !important; }
/* .n360-ctlfill is the chain BETWEEN cell and control - never the control's
   own children. See the header note. */
.n360-ctlbtn { width: 100% !important; }

/* v1.26 - width: 100% only renders identically if every OTHER box property
   agrees. Two of these controls come from stylesheets never supplied, so
   nothing is assumed: the same box model is pinned on all of them.
   - box-sizing: a content-box button renders WIDER than a border-box one
     from the same width:100% - that alone produces mismatched pills
   - margin: a component margin insets the button inside its cell
   - min/max-width: a component floor or cap defeats the track width
   - transform/float: anything a component uses to nudge itself */
.n360-ctlbtn, .n360-ctlcell, .n360-clockcell, .n360-ctlfill,
.a11y-trigger, .a11y-wrap {
    box-sizing: border-box !important;
    margin: 0 !important;
    min-width: 0 !important;
    max-width: none !important;
    transform: none !important;
    float: none !important;
}

/* ---------------------------------------------------------------------
   19a-ii. THE INSIDE OF A CONTROL

   Three pages, three markups for the same button:
     dashboard  <button class="pill-btn"><i></i> Theme</button>   (bare text)
     results    <button class="d-flex"><i class="me-2"></i> <span>Theme</span>
     provider   same as results
   Left alone they space their contents three different ways. Declaring the
   flex context, the gap and the icon margin here makes all three identical
   regardless of what each page's own stylesheet does.

   Scoped through the row as well as the control so the selector carries
   two classes - enough to outrank a component's own single-class
   !important rule, whichever sheet it lives in.
   --------------------------------------------------------------------- */
.n360-ctlrow .n360-ctlbtn,
.topbar .n360-ctlbtn,
.layer-header .n360-ctlbtn,
.n360-ctlbtn {
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    gap: 8px !important;
    text-align: center !important;
}
/* The a11y trigger by its REAL name (from n360-a11y-toolbar.css, finally
   supplied): its own 1.5px border and .85rem font matched to its
   neighbours, with no dependence on the JS stamp. */
.a11y-trigger {
    border-width: 1px !important;
    font-size: 13px !important;
    width: 100% !important;
    justify-content: center !important;
}
.a11y-wrap { width: 100% !important; display: inline-flex !important; }

/* The icon keeps its size and nothing else - its me-2 would double the gap,
   and any inherited width is what split the button in half. */
.n360-ctlbtn > i,
.n360-ctlbtn > svg,
.n360-ctlbtn > span,
.n360-ctlbtn > div {
    flex: 0 0 auto !important;
    width: auto !important;
    margin: 0 !important;
}

/* ---------------------------------------------------------------------
   19b. THE CALL BUTTON ON THE PROVIDER RECORD

   Built by n360-mobile.js from the Main Telephone link, and styled to
   match the result cards deliberately - the same action should not look
   like two different things across two screens.

   Fixed colours, never theme variables: this is the button that has to be
   readable, and --n360-primary is the result card's own hover fill. That
   lesson has been paid for twice on this project.
   --------------------------------------------------------------------- */
.n360-callbtn {
    display: flex !important; align-items: center; justify-content: center;
    gap: 10px; width: 100%; min-height: 54px;
    margin: 4px 0 12px;
    background: #12161b !important;
    color: #ffffff !important;
    -webkit-text-fill-color: #ffffff !important;
    border-radius: 999px;
    font-size: 18px; font-weight: 800; letter-spacing: .01em;
    text-decoration: none !important;
}
.n360-callbtn i { font-size: 18px; color: #ffffff !important; }
.n360-callbtn:active { filter: brightness(1.25); }

/* ---------------------------------------------------------------------
   19c. THE SORT BAR, WHEN APPLY FILTERS SCROLLS TO IT
   --------------------------------------------------------------------- */
#sortBar { scroll-margin-top: calc(64px + env(safe-area-inset-top)); }

/* ---------------------------------------------------------------------
   19d. THE FOOTER LOGO
   Room above it, and a tap target worth aiming at now it is a link.
   --------------------------------------------------------------------- */
.n360-footerlogo {
    display: inline-block; margin-top: 22px; padding: 6px 4px;
    line-height: 0;
}
.n360-footerlogo img { height: 26px !important; }

/* =====================================================================
   20. v1.29 - WRAPPER CELLS MUST NOT EAT THE TRACK  (Sol's finding)

   A cell that wraps a component (clock .dropdown, Accessibility
   .a11y-wrap) must contribute ZERO horizontal padding: the button inside
   sizes from the cell's content box, and any cell padding is subtracted
   straight off the button. Sol proved this on results; the provider row
   matches the same child rule, so this covers all three headers rather
   than #resultsSide alone. overflow stays visible - both these wrappers
   own pop-out panels.
   ===================================================================== */
.n360-ctlcell, .n360-clockcell,
.n360-ctlrow > .dropdown, .n360-ctlrow > .a11y-wrap,
div:has(> #themeToggleBtn) > .dropdown,
div:has(> #themeToggleBtn) > .a11y-wrap,
.layer-header > div:last-child > .dropdown,
.layer-header > div:last-child > .a11y-wrap,
.topbar > div:last-child > .dropdown,
.topbar > div:last-child > .a11y-wrap {
    padding-left: 0 !important;
    padding-right: 0 !important;
    overflow: visible !important;
}


/* ---------------------------------------------------------------------
   LOGIN PAGE (round 22, 17th Aug 2026, VERIFY-LOGINMOB-17AUG2026-R1-9QXTF)
   Login renders no sidebar and none of the app chrome above, so nothing
   earlier in this file reaches it. Everything here is scoped under
   .login-wrapper, which exists only on Login.cshtml - zero leak risk.

   KP's iPhone SE screenshots showed the Access + Theme toolbar sitting
   ON TOP of the brand logo: the wrapper is .position-absolute top-0
   end-0 p-4 - Bootstrap utilities, all carrying !important, hence the
   !importants below (the one fight load order cannot win).

   Fix: on mobile the toolbar joins the document flow as the app's
   standard two-up control row - grid 1fr 1fr, both pills equal width,
   44px targets - and .login-wrapper stacks as a column so the row sits
   above the form instead of beside it (it is display:flex ROW on
   desktop, where the toolbar floats over the brand panel).

   The other two login defects are markup fixes in Login.cshtml v2.0:
   the neo optic logo paths (/includes/imgs/ predates the flagship
   rebuild and 404s - now /img/) and the Bootstrap-blue checkbox
   (n360-forms.css now linked; Login never renders _Sidebar, which is
   how every other page loads it).

   No n360-mobile.js on login - deliberate. Every behaviour in that file
   targets dashboard/results/provider structures; the login needs none
   of them, and a page linking the script without its structures just
   logs bail-outs. CSS-only here.
   --------------------------------------------------------------------- */
.login-wrapper {
    flex-direction: column;
}
.login-wrapper .n360-theme-wrapper {
    position: static !important;        /* beats .position-absolute */
    display: grid !important;           /* beats .d-flex */
    grid-template-columns: 1fr 1fr;
    gap: 8px;
    width: 100%;
    /* beats .p-4; safe-area keeps the row clear of a notch, matching
       the .n360-mtop treatment at the top of this file */
    padding: 12px 12px 0 !important;
    padding-top: calc(12px + env(safe-area-inset-top)) !important;
}
/* Cells are wrappers only - horizontal padding on a cell subtracts from
   the child's containing block (the Sol round-21 lesson). Fill comes
   from the controls themselves. */
.login-wrapper .n360-theme-wrapper > .a11y-wrap,
.login-wrapper .n360-theme-wrapper > #themeToggleBtn {
    width: 100%;
    margin: 0;
    min-width: 0;
}
.login-wrapper .n360-theme-wrapper .a11y-trigger,
.login-wrapper .n360-theme-wrapper > #themeToggleBtn {
    width: 100% !important;
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;                   /* WCAG 2.5.8 target size */
}
/* The a11y pop-out panel must not be clipped by the grid cell. */
.login-wrapper .n360-theme-wrapper > .a11y-wrap { overflow: visible; }

}   /* end max-width 991.98px */

/* Desktop keeps the mobile chrome out of the way entirely. */
@media (min-width: 992px) {
  .n360-mtop, .n360-navback, .n360-mfilters-btn { display: none !important; }
  /* v1.15 belt and braces. The script no longer injects this above the
     breakpoint, but if one ever survives a resize it must not be visible -
     an unstyled close button above the desktop sidebar is how round 4
     started. */
  .n360-navclose { display: none !important; }
}

@media (prefers-reduced-motion: reduce) {
  .n360-sidebar, .n360-navback { transition: none !important; }
}
