/* New pure-JS/CSS app screens. Reuses tokens/components from
   /css/styles.css (--menucolor, --radius, .input, .buttonOK, .page, etc.)
   rather than introducing a second palette. */

#app-root {
    min-height: 100vh;
    box-sizing: border-box;
}

/* Base weight cap: browsers default <h1>-<h6>/<strong>/<b> to bold (700+),
   which is heavier than this app ever wants. Every more specific rule below
   (.fonth1, .modal-title, etc.) already sets its own weight and wins on
   specificity regardless of source order -- this only catches headings/
   emphasis that don't have one of their own. */
h1, h2, h3, h4, h5, h6, strong, b {
    font-weight: 600;
}

/* app.css loads only on public/app/index.html (the new SPA), never on
   legacy PHP pages, so overriding body here is safe -- it can't leak into
   styles.css's shared body{font-size:16px} for the old app. */
/* The smallest text size anywhere in the app: every size that used to be below this uses it instead. */
:root {
    --table-footer-line: #c8cdd2;
    --font-min: 16px;
}

body {
    font-size: 16px;
}

/* Visible keyboard focus for plain links/elements that have no native
   legacy focus style of their own. Inputs/selects/buttons already get a
   border+shadow focus treatment from styles.css (.input:focus, .select:focus,
   .buttonOK:focus) -- adding an outline on top of those doubled the border,
   so this only applies where nothing else provides one. */
#app-root a:focus-visible,
#app-root [tabindex]:focus-visible {
    outline: 3px solid var(--menucolor);
    outline-offset: 2px;
}

/* ---- Auth screens (login/register/mfa) ---- */

.auth-shell {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 16px;
    /* The page's own light gray (whatever the theme makes --background), with the same barely-there circuit board as the body of the app. */
    background: var(--background) url('/public/images/circuit-subtle.svg') center / cover no-repeat;
    padding: 24px;
    box-sizing: border-box;
}

.public-page {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

.public-topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 24px;
    background: white;
    border-bottom: var(--tableborder);
    flex-shrink: 0;
}
.public-topbar .brand {
    display: flex;
    align-items: center;
    gap: 8px;
    font-weight: 500;
    font-size: 16px;
    color: var(--textcolor);
    text-decoration: none;
}
.public-topbar nav {
    display: flex;
    gap: 4px;
}

/* Matches the legacy app's .mainmenu treatment (styles.css), reproduced
   here rather than shared since app.css never renders an actual .mainmenu
   element. */
.public-topbar .public-nav-link {
    text-decoration: none;
    color: var(--textcolor);
    font-weight: 500;
    font-size: 16px;
    border-radius: 8px;
    padding: 6px 8px;
    white-space: nowrap;
}
.public-topbar .public-nav-link:hover {
    background-color: var(--topmenu);
    color: var(--menucolor);
}
.public-topbar .public-nav-link:focus-visible {
    outline: 2px solid var(--menucolor);
    outline-offset: 1px;
}
/* On a phone the brand, the three links and the language box do not fit in one row (the page then scrolls sideways): the bar wraps onto a second row instead. */
@media (max-width: 560px) {
    .public-topbar { flex-wrap: wrap; row-gap: 6px; padding: 10px 14px; }
    .public-topbar nav { flex-wrap: wrap; gap: 2px; }
    .public-topbar .public-nav-link { font-size: 15px; padding: 6px 6px; }
}

.auth-logo {
    text-align: center;
}
.auth-logo img {
    height: 48px;
    width: auto;
}

.auth-card {
    width: 100%;
    max-width: 400px;
    background: white;
    border-radius: var(--window-radius);
    border: var(--window-border);
    box-shadow: var(--auth-card-shadow);
    padding: 32px;
    box-sizing: border-box;
}

.auth-card h1 {
    font-size: 24px;
    font-weight: 500;
    color: #222;
    margin: 0 0 4px;
}

.auth-card p.subtitle {
    font-size: 16px;
    color: #667;
    margin: 0 0 24px;
}

.field-group {
    margin-bottom: 18px;
}

.field-group label {
    display: block;
    font-size: 16px;
    font-weight: 600;
    color: var(--textcolor);
    margin-bottom: 6px;
}

.profile-value {
    margin: 0 0 6px;
    font-size: 16px;
    color: var(--textcolor);
}

.field-group .input,
.field-group select.select {
    width: 100%;
    box-sizing: border-box;
}

.test-group-url-row {
    display: flex;
    gap: 8px;
    align-items: center;
    margin-bottom: 8px;
}
.test-group-url-row .input {
    flex: 1;
}

.field-hint {
    font-size: 14px;
    color: #778;
    margin-top: 6px;
}

/* position:sticky (not just relying on being "near the top") is what actually guarantees
   visibility here -- .form-fields-scroll (the modal/form-page's own scrolling region) can be
   taller than the visible box, and this banner is normally its first child, so a plain static
   position would scroll out of view along with everything else the moment the admin scrolls
   down to reach the Close/Save footer. Sticky keeps it pinned to the top of whatever's
   currently visible in that scroll container, for every form that uses this shared class --
   one rule, no per-form markup changes needed. */
.form-error-banner:not([hidden]) {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    background: #fdecec;
    border: 1px solid var(--documentred);
    color: #7a2a2a;
    border-radius: 8px;
    padding: 10px 12px;
    font-size: 16px;
    margin-bottom: 18px;
    position: sticky;
    top: 0;
    z-index: 5;
}

/* Same shape, sticky behavior, and reasoning as .form-error-banner above -- just green instead
   of red, for a successful save. */
.form-success-banner:not([hidden]) {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    background: #e9f7ea;
    border: 1px solid var(--documentgreen);
    color: #1a5c1a;
    border-radius: 8px;
    padding: 10px 12px;
    font-size: 16px;
    margin-bottom: 18px;
    position: sticky;
    top: 0;
    z-index: 5;
}

.auth-card .buttonOK {
    /* Full-width for the auth-card's single CTA, but same height/radius as
       every other button in the app (base .buttonOK padding) -- not its own
       taller size. */
    width: 100%;
}

.auth-card .buttonOK:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

/* A button that cannot be used yet (Delete monitor while there is still a bill to come). */
.auth-card .buttonClose:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}
.confirm-dialog-panel .buttonOK:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.auth-links {
    margin-top: 20px;
    text-align: center;
    font-size: 16px;
}

.auth-links a {
    color: var(--menucolor);
    text-decoration: none;
    font-weight: 600;
}
.auth-links a:hover { text-decoration: underline; }

/* ---- Global body text conventions: buttons match body font size, plain
   links are blue-only (underline on hover, not always) ---- */

#app-root .buttonOK,
#app-root .buttonClose {
    font-size: 16px;
}
/* The "+" in "+ Add ..."/"+ Invite ..." trigger buttons, made to stand out a bit more than the
   rest of the label -- weight only, not size: a bigger font-size here stretched the whole
   button's line box taller than a plain-text button (Close, Notes, ...) sitting right next to it. */
.btn-plus {
    font-size: 16px;
    font-weight: 700;
}
/* The icon-only "+" before Refresh in a widget header: 8px bigger than the one inside a button. */
.dashboard-widget-actions .btn-plus {
    font-size: 28px;
    line-height: 1;
}
/* Add/Edit page buttons are sometimes plain links (<a href="#/...">) styled
   as buttons -- undo the anchor defaults so they look identical to <button>.
   Specificity must beat ".app-body a" below so they keep their button
   colors instead of falling back to plain-link blue. */
a.buttonOK, a.buttonClose {
    display: inline-block;
    text-decoration: none;
    text-align: center;
}
.app-body a.buttonOK,
.app-body a.buttonClose {
    text-decoration: none;
}
.app-body a.buttonOK:hover,
.app-body a.buttonClose:hover {
    text-decoration: none;
}
.app-body a.buttonOK {
    color: white;
}
.app-body a.buttonOK:hover {
    color: var(--documentblue);
}
.app-body a.buttonClose {
    color: var(--textcolor);
}
.app-body a.buttonClose:hover {
    color: var(--documentred);
}

/* Links are our blue (the menu colour) at weight 500 -- never the browser's blue -- with no underline until
   hovered. The :where() keeps the weight at the lowest specificity, so every component that styles its own links wins. */
:where(#app-root) a {
    color: var(--menucolor);
    font-weight: 500;
    text-decoration: none;
}
:where(#app-root) a:hover {
    text-decoration: underline;
}
.app-body a {
    color: var(--menucolor);
    text-decoration: none;
}
.app-body a:hover {
    text-decoration: underline;
}
/* Links that are really icon buttons, and the list in the ticket bell, keep the body text colour. */
.app-body a.icon-btn {
    color: var(--textcolor);
}
.app-body a.icon-btn:hover {
    color: var(--menucolor);
    text-decoration: none;
}
.ticket-bell-panel li a,
.ticket-bell-all {
    color: var(--textcolor);
    font-weight: 400;
}

/* A chevron inside a link that leads onward ("Evidence >"), in place of a text arrow. */
.chevron-right {
    /* 24px, in the link's own (blue) colour. */
    width: 24px;
    height: 24px;
    vertical-align: -6.5px;
    margin-left: 1px;
}
/* The same chevron, inside a .buttonOK/.buttonClose ("Close >", "Convert >", ...): at 24px it
   stretched that button's line box taller than a plain-text button (Notes, ...) beside it --
   sized down to fit inside the button's own 16px text line instead. */
.buttonOK .chevron-right, .buttonClose .chevron-right {
    width: 16px;
    height: 16px;
    vertical-align: -3px;
    margin-left: 0;
}

/* ---- Breadcrumb trail: on the title's line, right after it (Dashboard > group > page > ...) ---- */

/* The page's <h1> and its trail share one row; the trail drops under the title when the window is narrow. */
.title-with-crumbs {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 2px 18px;
    min-width: 0;
}
.breadcrumbs[hidden] { display: none; }
.breadcrumbs {
    font-size: 15px;
    min-width: 0;
}
/* A page without a heading shows the trail by itself above its content. */
.breadcrumbs-alone { margin-bottom: 12px; }
.breadcrumbs ol {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
}
.breadcrumbs li {
    display: inline-flex;
    align-items: center;
}
/* Our blue (the menu colour) for the whole trail; the page you are on is bold. */
.app-body .breadcrumbs a,
.breadcrumb-heading,
.breadcrumb-ellipsis,
.breadcrumb-current {
    color: var(--menucolor);
}
.breadcrumb-current { font-weight: 600; }
/* The same chevron as on the links (.chevron-right: 24px, in the trail's blue at full strength). */
.breadcrumb-sep svg {
    width: 24px;
    height: 24px;
}
.breadcrumb-sep {
    display: inline-flex;
    margin: 0;
    color: var(--menucolor);
}
.breadcrumb-heading,
.breadcrumb-ellipsis { cursor: default; }

/* ---- Marketing pages (home, pricing) ---- */

.marketing-page {
    flex: 1;
    background: var(--background);
}

.marketing-hero {
    /* Green from logo.svg; same notched radius as dashboard widgets; margin
       + border set it visibly apart from the top nav bar instead of butting
       up against it. */
    /* The traces are translucent: the green is still this one. The first layer is the same green, thick over the middle (where the words are) and fading out to the edges, so the text stays easy to read. */
    background: radial-gradient(ellipse 62% 72% at 50% 50%, rgba(107, 171, 132, 0.93) 0%, rgba(107, 171, 132, 0.78) 50%, rgba(107, 171, 132, 0) 100%),
                #6bab84 url('/public/images/circuit-green.svg') center / cover no-repeat;
    color: white;
    text-align: center;
    padding: 48px 24px;
    margin: 20px 24px 0;
    border: var(--tableborder, 1px solid #a2a9b1);
    border-radius: var(--radius);
    border-top-left-radius: 0;
    border-bottom-right-radius: 0;
}
.marketing-hero-compact { padding: 30px 24px; }

.marketing-hero h1 {
    font-size: 32px;
    font-weight: 600;
    margin: 0 0 16px;
    max-width: 1000px;
    margin-left: auto;
    margin-right: auto;
}

.marketing-hero p {
    font-size: 17px;
    color: #e8ecf5;
    max-width: 720px;
    margin: 0 auto 20px;
    line-height: 1.5;
}
.marketing-hero p strong { color: white; font-weight: 700; }

.marketing-cta {
    display: inline-block;
    background: white;
    color: var(--menucolor);
    font-weight: 600;
    font-size: 16px;
    text-decoration: none;
    padding: 14px 32px;
    border-radius: 8px;
}
.marketing-cta:hover { background: #eef3fb; }
.marketing-cta-light { background: white; color: var(--menucolor); }
.marketing-cta-row { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; }
.marketing-cta-ghost { background: transparent; color: white; border: 2px solid white; padding: 12px 30px; }
.marketing-cta-ghost:hover { background: rgba(255, 255, 255, 0.16); }
.marketing-cta-outline {
    background: transparent;
    color: var(--menucolor);
    border: 1px solid var(--menucolor);
}
.marketing-cta-outline:hover { background: var(--tdhover); }

.marketing-section {
    max-width: 1100px;
    margin: 0 auto;
    padding: 60px 24px;
}
.marketing-section-alt { background: white; max-width: none; }
.marketing-section-alt > * { max-width: 1100px; margin-left: auto; margin-right: auto; }

.marketing-section h2 {
    font-size: 26px;
    font-weight: 600;
    color: #0d1b2a;
    text-align: center;
    /* centred as a box too (not only its words), so it sits over the middle of what is under it even in a full-width (alternate) section */
    margin: 0 auto 16px;
    max-width: 1100px;
}

.marketing-lede {
    font-size: 16px;
    color: var(--textcolor);
    text-align: center;
    max-width: 720px;
    margin: 0 auto 40px;
    line-height: 1.6;
}

.feature-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 20px;
    /* Three to a row at most, so nine cards make three full rows. */
    max-width: 1000px;
    margin: 0 auto;
}

.feature-card {
    background: white;
    border: var(--tableborder, 1px solid #a2a9b1);
    border-radius: var(--radius);
    border-top-left-radius: 0;
    border-bottom-right-radius: 0;
    padding: 22px;
}
.feature-card h3 {
    font-size: 18px;
    font-weight: 600;
    color: #0d1b2a;
    margin: 0 0 10px;
}
.feature-card p {
    font-size: 15px;
    color: var(--textcolor);
    line-height: 1.5;
    margin: 0;
}

.marketing-table-wrap {
    overflow: hidden;
    overflow-x: auto;
    border: var(--tableborder, 1px solid #a2a9b1);
    border-radius: var(--radius);
    border-top-left-radius: 0;
    border-bottom-right-radius: 0;
}
.marketing-table {
    width: 100%;
    border-collapse: collapse;
    background: white;
}
.marketing-table th, .marketing-table td {
    padding: 12px 16px;
    text-align: left;
    border-bottom: var(--tdborder);
    font-size: 15px;
}
.marketing-table th {
    background: var(--thbackground);
    font-weight: 600;
    color: var(--textcolor);
}

.marketing-cta-section {
    /* Blue from logo.svg; same notched radius as dashboard widgets. */
    background: radial-gradient(ellipse 62% 72% at 50% 50%, rgba(68, 112, 175, 0.93) 0%, rgba(68, 112, 175, 0.78) 50%, rgba(68, 112, 175, 0) 100%),
                #4470af url('/public/images/circuit-blue.svg') center / cover no-repeat;
    color: white;
    text-align: center;
    padding: 70px 24px;
    border-radius: var(--radius);
    border-top-left-radius: 0;
    border-bottom-right-radius: 0;
    max-width: 1100px;
    /* the same 24px of space at each side that the green box above has, on a narrow screen; centred on a wide one */
    box-sizing: border-box;
    width: calc(100% - 48px);
    margin: 40px auto;
}
.marketing-cta-section h2 { color: white; }
/* The circuit traces run behind the words: a soft shadow keeps them crisp. */
.marketing-hero h1, .marketing-hero p, .marketing-cta-section h2, .marketing-cta-section p { text-shadow: 0 1px 3px rgba(0, 0, 0, 0.28); }
.marketing-cta-section p { color: #e8ecf5; max-width: 600px; margin: 0 auto 28px; }

.marketing-footer {
    display: flex;
    justify-content: center;
    gap: 20px;
    padding: 24px;
    font-size: 14px;
    color: var(--textcolor);
}
.marketing-footer a { color: var(--menucolor); text-decoration: none; }
.marketing-footer a:hover { text-decoration: underline; }

.pricing-plans {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0 24px;   /* the rows are shared by the cards (subgrid below), so only the columns have a gap */
    max-width: 480px;
    margin: 0 auto;
}
@media (min-width: 960px) {
    .pricing-plans { grid-template-columns: repeat(3, 1fr); max-width: 1100px; }
    /* the calculator sits in the middle column, in the row below the cards, under the blue box */
    .pricing-plans > .pricing-calculator { grid-column: 2; grid-row: 5; }
}
/* In one column (a phone or a narrow window) the price calculator is the last box, after the add-on card. */
@media (max-width: 959px) { .pricing-plans > .pricing-calculator { order: 1; } }
.pricing-section { padding-top: 20px; }
/* The price calculator: a small box under the blue plan box, so it reads as a tool for that plan. */
.pricing-calculator {
    margin: 0 0 24px;
    padding: 20px 22px 22px;
    background: white;
    border: 2px solid var(--menucolor);
    border-radius: var(--radius);
    border-top-left-radius: 0;
    border-bottom-right-radius: 0;
}
.pricing-calculator h2 { margin: 0 0 14px; font-size: 18px; text-align: center; color: #0d1b2a; }
.pricing-calculator-body { display: grid; grid-template-columns: 1fr; gap: 10px; }
.pricing-calculator .pricing-calc-row { margin-bottom: 6px; }
.pricing-calculator .pricing-calc-included { margin-bottom: 8px; }
.pricing-calculator-result { text-align: center; background: var(--tdhover); padding: 12px 12px; border-radius: var(--radius); }
.pricing-calculator-label { font-size: 14px; color: var(--textcolor); margin-bottom: 4px; }
.pricing-plan-desc strong, .pricing-calc-included strong, .pricing-calc-breakdown strong { color: var(--menucolor); font-weight: 700; }
.pricing-calc-included { margin: 0 0 16px; font-size: 14px; line-height: 1.5; color: var(--textcolor); }
/* min-height: room for the longest breakdown (two lines), so the box never grows as the pages or the add-on change */
.pricing-calc-breakdown { min-height: 2.8em; font-size: 14px; color: var(--textcolor); opacity: 0.85; line-height: 1.4; }
@media (max-width: 700px) { .pricing-calculator-body { grid-template-columns: 1fr; gap: 20px; } }
.pricing-plan-card {
    background: white;
    border: var(--tableborder, 1px solid #a2a9b1);
    border-radius: var(--radius);
    border-top-left-radius: 0;
    border-bottom-right-radius: 0;
    padding: 32px;
    text-align: center;
    margin-bottom: 24px;
    /* Heading, description, feature list and button each sit in a row shared by all the cards, so every
       feature list starts on the same line whatever the text above it. */
    display: grid;
    grid-template-rows: subgrid;
    grid-row: span 4;
    row-gap: 0;
}
.pricing-card-head { margin-bottom: 16px; }
/* Light blue line above the feature list, a little darker than the blue card (--tdhover, #d5e5ff). The list row is shared by the cards, so the lines align. */
.pricing-plan-card .pricing-feature-list { border-top: 1px solid #b4cdf5; padding-top: 12px; }
.pricing-plan-card .pricing-plan-desc { margin-bottom: 18px; }
.pricing-card-foot { align-self: end; }
.pricing-card-foot > .pricing-plan-desc { margin: 0; }
.pricing-plan-card-alt { background: var(--tdhover); }
.pricing-plan-card h3 { font-size: 20px; margin: 0 0 12px; color: #0d1b2a; }
.pricing-amount { font-size: 36px; font-weight: 600; color: var(--menucolor); margin-bottom: 8px; }
.pricing-amount span { font-size: 15px; font-weight: 400; color: var(--textcolor); }
.pricing-tax-inline { font-size: 14px; color: var(--textcolor); opacity: 0.8; margin: -2px 0 12px; }
.price-guarantee-note { margin: 4px 0 14px; font-weight: 600; color: var(--menucolor); }
.marketing-hero .pricing-guarantee { max-width: 720px; margin: 14px auto 20px; font-size: 19px; font-weight: 600; line-height: 1.4; }
.pricing-tax-note { max-width: 720px; margin: 14px auto 0; text-align: center; font-size: 15px; color: var(--textcolor); opacity: 0.85; line-height: 1.5; }
.pricing-plan-desc { font-size: 15px; color: var(--textcolor); margin: 0 0 24px; line-height: 1.5; }

.pricing-calc-row {
    text-align: left;
    margin-bottom: 16px;
}
.pricing-calc-row label {
    display: block;
    font-size: 14px;
    color: var(--textcolor);
    margin-bottom: 6px;
}
.pricing-calc-row input[type="range"] { width: 100%; }
.pricing-calc-checkbox label {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 14px;
    cursor: pointer;
}

.pricing-feature-list {
    list-style: none;
    margin: 0 0 24px;
    padding: 0;
    text-align: left;
    font-size: 14px;
    color: var(--textcolor);
}
.pricing-feature-list li {
    padding: 6px 0 6px 24px;
    position: relative;
    line-height: 1.4;
}
.pricing-feature-list li::before {
    content: '\2713';
    position: absolute;
    left: 0;
    color: var(--documentgreen, #2a8a4a);
    font-weight: 600;
}
.pricing-feature-list li.pricing-feature-excluded {
    color: #999999;
}
.pricing-feature-list li.pricing-feature-excluded::before {
    content: '\00D7';   /* a real cross; the old ballot-X glyph looked like a broken letter */
    font-size: 20px;
    line-height: 1;
    top: 5px;
    color: #999999;
}

@media (max-width: 640px) {
    .marketing-hero h1 { font-size: 28px; }
    .marketing-hero { padding: 56px 20px; }
}

/* ---- Authenticated app shell: persistent topbar + collapsible left sidebar ---- */

:root {
    --topbar-height: 60px;
    /* "Window" container look (dashboard widgets, table boxes, modals) -- Standard theme
       default here expresses today's existing hardcoded per-corner overrides as one shorthand.
       [data-theme="flat"] below overrides these three; every consumer just reads the variable. */
    --window-radius: 0 var(--radius) 0 var(--radius);
    --window-shadow: 0 4px 14px var(--boxShadow);
    --window-drag-shadow: 0 10px 28px var(--boxShadow);
    --window-border: none;
    /* The modal's own shadow is deliberately stronger than the widget/table one above (it floats
       over a dimmed backdrop, not just sitting on the page) -- kept as its own variable so
       unifying the theme doesn't quietly weaken it in the Standard theme. */
    --modal-shadow: 0 20px 50px rgba(0, 0, 0, 0.3);
    /* .auth-card (Profile, Company & billing, login/register) has its own shadow too, stronger
       again than the widget/table one -- same reasoning, kept separate. */
    --auth-card-shadow: 0 10px 26px var(--boxShadow);
}

[data-theme="flat"] {
    --window-radius: 10px;
    --window-shadow: none;
    --window-drag-shadow: none;
    /* Lighter than --tableborder (used as-is elsewhere for actual table/cell borders) --
       a window's outline should read as subtle, not as strong as a data grid line. */
    --window-border: 1px solid #d8dbde;
    --modal-shadow: none;
    --auth-card-shadow: none;
    /* Slightly darker than the standard page background so a borderless white window still
       reads as a distinct surface against the page behind it. */
    --background: #ececeb;
}

.brand-logo {
    height: 28px;
    width: auto;
    display: block;
    flex-shrink: 0;
}

.app-shell-page {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

/* Same always-on-top bar treatment as the pre-login .public-topbar,
   kept visible (sticky) after login too instead of being replaced by nav. */
.app-topbar {
    position: sticky;
    top: 0;
    z-index: 300;
    height: var(--topbar-height);
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 0 16px;
    background: white;
    border-bottom: var(--tableborder);
    box-sizing: border-box;
}

.app-sidebar-toggle-btn {
    background: none;
    border: none;
    cursor: pointer;
    padding: 8px;
    min-width: 44px;
    min-height: 44px;
    border-radius: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
.app-sidebar-toggle-btn:hover { background: var(--topmenu); }
.hamburger-icon, .hamburger-icon span {
    display: block;
    width: 20px;
    height: 2px;
    background: var(--textcolor);
    position: relative;
}
.hamburger-icon span::before, .hamburger-icon span::after {
    content: '';
    position: absolute;
    left: 0;
    width: 20px;
    height: 2px;
    background: var(--textcolor);
}
.hamburger-icon span::before { top: -6px; }
.hamburger-icon span::after { top: 6px; }

.app-topbar-brand {
    display: flex;
    align-items: center;
    gap: 8px;
    font-weight: 500;
    color: var(--textcolor);
    font-size: 16px;
    text-decoration: none;
    white-space: nowrap;
}

.app-topbar-right {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 12px;
}
/* The language picker, at the top right the same way the public pages have it. */
.app-topbar .app-topbar-language { width: 68px; min-width: 0; padding: 4px 22px 4px 8px; }

/* Reuses the exact plain-link treatment as the legacy app's .mainmenu
   (no button box around Logout -- matches the reference site). */
.app-topbar .logout-link {
    display: flex;
    align-items: center;
    gap: 8px;
    background: none;
    border: none;
    cursor: pointer;
    font-family: inherit;
    color: var(--textcolor);
    font-weight: 500;
    font-size: 16px;
    border-radius: 8px;
    padding: 6px 10px;
    white-space: nowrap;
    flex-shrink: 0;
}
.app-topbar .logout-link:hover { background-color: var(--topmenu); color: var(--documentred); }
.app-topbar .logout-link .icon { width: 20px; height: 20px; }

.app-layout {
    display: flex;
    flex: 1;
    min-height: calc(100vh - var(--topbar-height));
}

/* Scrolling lives on .app-sidebar-nav (below), not here -- an overflow value other than
   visible on this element would clip anything that flies out past its own box, which is
   exactly what both the collapsed rail's submenu flyout and the profile menu's own
   collapsed flyout (further down) need to do (position: absolute; left: 100%). */
.app-sidebar {
    width: 240px;
    flex-shrink: 0;
    background: white;
    border-right: var(--tableborder);
    box-sizing: border-box;
    position: sticky;
    top: var(--topbar-height);
    height: calc(100vh - var(--topbar-height));
    transition: width 0.2s ease;
    display: flex;
    flex-direction: column;
}

.app-sidebar-nav {
    padding: 12px 8px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
}

/* Theme picker, pinned just above the profile block. */
.app-sidebar-theme {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 8px;
    border-top: var(--tableborder);
    flex-shrink: 0;
}
.app-sidebar-theme select { flex-shrink: 0; max-width: 110px; }
/* Same treatment as .app-sidebar-subnav under collapse (line ~833) -- no room for a label +
   select in the 64px collapsed rail, so the whole row hides rather than trying to shrink it. */
.app-sidebar.collapsed .app-sidebar-theme { display: none; }

/* User identity + account menu, pinned to the bottom of the sidebar. */
.app-sidebar-profile {
    position: relative;
    border-top: var(--tableborder);
    padding: 8px;
    flex-shrink: 0;
}

.app-sidebar-profile-btn {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    background: none;
    border: none;
    cursor: pointer;
    font-family: inherit;
    padding: 8px;
    border-radius: 8px;
    text-align: left;
}
.app-sidebar-profile-btn:hover { background-color: var(--topmenu); }

.app-sidebar-profile-email {
    font-weight: 500;
    color: var(--textcolor);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 16px !important;
}

.app-sidebar-profile-menu {
    position: absolute;
    bottom: calc(100% + 4px);
    left: 8px;
    right: 8px;
    background: white;
    border: var(--tableborder);
    border-radius: 8px;
    box-shadow: 0 4px 14px var(--boxShadow);
    padding: 6px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    z-index: 10;
    font-size:16px !important;
}
.app-sidebar-profile-menu[hidden] { display: none; }
.app-sidebar-profile-menu a,
.app-sidebar-profile-menu button {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    box-sizing: border-box;
    background: none;
    border: none;
    text-align: left;
    font-family: inherit;
    cursor: pointer;
    padding: 8px 10px;
    border-radius: 6px;
    font-size: 15px;
    font-weight: 500;
    color: var(--textcolor);
    text-decoration: none;
    white-space: nowrap;
}
.app-sidebar-profile-menu a:hover,
.app-sidebar-profile-menu button:hover { background-color: var(--topmenu); color: var(--menucolor); }
.app-sidebar-profile-menu .icon { width: 20px; height: 20px; flex: 0 0 20px; }

.app-sidebar.collapsed .app-sidebar-profile-email { display: none; }
.app-sidebar.collapsed .app-sidebar-profile-btn { justify-content: center; }
.app-sidebar.collapsed .app-sidebar-profile-menu { left: 100%; bottom: 0; margin-left: 8px; width: 200px; }

.app-sidebar-nav a,
.app-sidebar-nav button {
    display: flex;
    align-items: center;
    gap: 12px;
    text-decoration: none;
    color: var(--textcolor);
    font-weight: 400;
    font-size: 15px;
    border-radius: 8px;
    padding: 10px 12px;
    white-space: nowrap;
    min-height: 44px;
    box-sizing: border-box;
    /* A parent-with-submenu row is a <button>, not a link -- undo the
       browser's own button chrome so it's indistinguishable from the
       plain nav links above/below it. */
    width: 100%;
    background: none;
    border: none;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}
.app-sidebar-nav a:hover,
.app-sidebar-nav button:hover { background-color: var(--topmenu); color: var(--menucolor); }
/* Was --tdhover (light blue) -- now a paler tint of the logo's own green.
   Text stays --textcolor (dark gray, same as the resting items) rather
   than the blue accent -- the tint + extra weight carry the highlight. */
.app-sidebar-nav a.active-nav,
.app-sidebar-nav button.active-nav { background-color: color-mix(in srgb, var(--logo-green) 22%, white); color: var(--textcolor); font-weight: 600; }
/* Icons stay this fixed color always -- they'd otherwise inherit currentColor from whichever
   text color is active on the row (resting/hover/active all differ above), so the source SVGs'
   own baked color (already normalized to the same value) would never actually show through. */
.app-sidebar-nav a .icon,
.app-sidebar-nav button .icon { flex-shrink: 0; width: 20px; height: 20px; color: #53676c; }
.app-sidebar-nav a .nav-label,
.app-sidebar-nav button .nav-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; font-size: 16px !important;}

/* The chevron is purely decorative now -- the whole button (not just the
   chevron) toggles the submenu, so it shares the row's own hover/active
   color like the label and its icon do, instead of staying an isolated
   lighter gray patch. */
.app-sidebar-nav button .app-sidebar-nav-chevron {
    flex-shrink: 0;
    width: 16px;
    height: 16px;
    color: currentColor;
}
.app-sidebar.collapsed .app-sidebar-nav-chevron { display: none; }

.app-sidebar-subnav {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin: 2px 0 4px 34px;
}
.app-sidebar-subnav[hidden] { display: none; }
.app-sidebar-subnav a {
    display: block;
    /* .app-sidebar-nav a's min-height leaks in here too (subnav links live
       inside the same #sidebar-nav container that selector matches against)
       and, combined with display:block, pushed the text to the top of that
       taller box instead of centering it -- reset it explicitly. */
    min-height: 0;
    text-decoration: none;
    color: var(--textcolor);
    font-weight: 400;
    font-size: 15px;
    border-radius: 8px;
    padding: 8px 12px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.app-sidebar-subnav a:hover { background-color: var(--topmenu); color: var(--menucolor); }
.app-sidebar-subnav a.active-nav { background-color: color-mix(in srgb, var(--logo-green) 22%, white); color: var(--textcolor); font-weight: 600; }

.app-sidebar.collapsed .app-sidebar-subnav { display: none; }

/* Collapsed rail: a submenu can't expand inline (there's no room, and every other
   row's label is already hidden), so clicking its icon instead opens this as a
   small flyout next to it -- visually the same idea as .app-sidebar-profile-menu's
   own flyout below, but appended straight to <body> by app-shell.js (position:
   fixed, left/top set per click) rather than positioned inside .app-sidebar-nav,
   since that list scrolls internally now and would clip anything positioned past
   its own right edge. */
.app-sidebar-flyout {
    position: fixed;
    width: 200px;
    background: white;
    border: var(--tableborder);
    border-radius: 8px;
    box-shadow: 0 4px 14px var(--boxShadow);
    padding: 6px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    z-index: 200;
}
.app-sidebar-flyout a {
    display: block;
    text-decoration: none;
    color: var(--textcolor);
    font-weight: 400;
    font-size: 15px;
    border-radius: 8px;
    padding: 8px 12px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.app-sidebar-flyout a:hover { background-color: var(--topmenu); color: var(--menucolor); }
.app-sidebar-flyout a.active-nav { background-color: color-mix(in srgb, var(--logo-green) 22%, white); color: var(--textcolor); font-weight: 600; }

/* Collapsed (desktop icon rail) */
.app-sidebar.collapsed { width: 64px; }
.app-sidebar.collapsed .nav-label { display: none; }
.app-sidebar.collapsed .app-sidebar-nav a,
.app-sidebar.collapsed .app-sidebar-nav button { justify-content: center; padding: 10px; }

.app-sidebar-backdrop {
    display: none;
}

.app-main {
    flex: 1;
    min-width: 0;
}

.app-body {
    padding: 13px 24px 22px;
    background: var(--background);
    min-height: calc(100vh - var(--topbar-height));
    box-sizing: border-box;
	font-size: 16px !important;
}

/* The empty space under the last box (the page's bottom padding) must not make a scrollbar of its own: with
   the last box ending inside that space the page would scroll by a few pixels for nothing. Pulling the last
   child down by the padding takes it out of the scrollable height; the box still ends where it did. (A list page
   that fills the window itself, see #table-root below, already accounts for its padding.) */
.app-body:not(:has(> #table-root:last-child)) > :last-child {
    margin-bottom: -22px;
}

/* Responsive: sidebar becomes an off-canvas drawer on small screens */
@media (max-width: 768px) {
    .app-sidebar {
        position: fixed;
        top: var(--topbar-height);
        left: 0;
        bottom: 0;
        height: auto;
        z-index: 200;
        transform: translateX(-100%);
        transition: transform 0.2s ease;
        width: 260px;
    }
    .app-sidebar.mobile-open { transform: translateX(0); }
    .app-sidebar.collapsed { width: 260px; } /* collapse is a desktop-only concept */
    .app-sidebar.collapsed .nav-label { display: block; }
    .app-sidebar.collapsed .app-sidebar-nav a,
    .app-sidebar.collapsed .app-sidebar-nav button { justify-content: flex-start; padding: 10px 12px; }

    .app-sidebar-backdrop {
        display: block;
        position: fixed;
        inset: 0;
        top: var(--topbar-height);
        background: rgba(0, 0, 0, 0.4);
        z-index: 150;
        opacity: 0;
        pointer-events: none;
        transition: opacity 0.2s ease;
    }
    .app-sidebar-backdrop.visible { opacity: 1; pointer-events: auto; }

    .app-body { padding: 16px; 
    	font-size: 16px !important;
    }
    .app-body:not(:has(> #table-root:last-child)) > :last-child { margin-bottom: -16px; }
}

/* ---- Configurable dashboard: drag/resize widget grid ---- */

.dashboard-heading-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    margin-bottom: 11px;
}
.dashboard-heading-row h1 { margin: 0; display: flex; align-items: center; gap: 8px; }

.dashboard-toolbar { display: flex; }
.dashboard-toolbar .select { width: 220px; }

/* Rows track the grid's own rendered width (via a container query on its
   wrapper, not the viewport) rather than a fixed px height, so a cell's
   proportions stay the same on a laptop and on a wide external monitor
   instead of turning into short, wide strips as the fluid 1fr columns
   grow. --dash-row-ratio is a row's height as a fraction of one column's
   width -- 1 would be a square cell, but at 12 columns a column is
   already much wider than the old fixed 45px row was, so 1 made every
   widget roughly twice as tall as before; 0.5 landed close to the
   original proportions, and 0.25 (four rows per column-width) doubles
   that again for finer drag-resize granularity. --dash-cols changes at
   the mobile breakpoint below; the row formula reads both custom
   properties back so nothing here can drift out of sync with it or
   with dashboard-grid.js's own copy of the ratio.
   The query container has to be #dashboard-grid-root, not .dashboard-grid
   itself -- an element can't use cqw in its own property values (there's
   nothing to query yet), only its descendants can, and .dashboard-grid
   fills 100% of this wrapper's width anyway. */
#dashboard-grid-root { container-type: inline-size; }
.dashboard-grid {
    display: grid;
    --dash-cols: 12;
    --dash-gap: 16px;
    --dash-row-ratio: 0.25;
    grid-template-columns: repeat(var(--dash-cols), 1fr);
    grid-auto-rows: calc(((100cqw - (var(--dash-cols) - 1) * var(--dash-gap)) / var(--dash-cols)) * var(--dash-row-ratio));
    gap: var(--dash-gap);
}

/* Matches .data-table-box exactly -- white throughout, no inset/embossed
   shadow, an underline below the header instead. */
.dashboard-widget {
    background: white;
    border-radius: var(--window-radius);
    box-shadow: var(--window-shadow);
    border: var(--window-border);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    position: relative;
    min-width: 0;
}
.dashboard-widget.dragging-active,
.dashboard-widget.resizing-active {
    opacity: 0.9;
    box-shadow: var(--window-drag-shadow);
    z-index: 50;
}

.dashboard-widget-header {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 8px 15px 10px 15px;
    background: white;
    font-weight: 600;
    font-size: 16px;
    cursor: grab;
    user-select: none;
    touch-action: none;
}
.dashboard-widget-header.dragging { cursor: grabbing; }
/* Same inset underline treatment as .data-table-box-header. */
.dashboard-widget-header::after {
    content: '';
    position: absolute;
    left: 10px;
    right: 10px;
    bottom: 0;
    border-bottom: 2px solid #aaaaaa;
}

.dashboard-widget-title {
    display: flex;
    align-items: center;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: #3d5a80;
}

/* Same layout as .data-table-box-actions -- refresh/download/columns (when
   the widget has a real table) plus the remove button, left to right. */
.dashboard-widget-actions {
    display: flex;
    align-items: center;
    gap: 2px;
    flex-shrink: 0;
}

.dashboard-widget-remove {
    /* Same 32px grey-on-hover box as the icon buttons beside it (it is one, see .icon-btn); the X itself is bold. */
    font-size: 18px;
    font-weight: 800;
    line-height: 1;
    touch-action: none;
}
.dashboard-widget-remove:hover { color: var(--documentred); }

.dashboard-widget-body {
    flex: 1;
    overflow: hidden;
    padding: 10px 14px;
    font-size: 16px;
    background: white;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

/* Monthly Charges widget: the real data-table (search/sort/filter/pagination) takes the
   flexible space above; the aggregate total/commission isn't row data, so it sits in its
   own fixed-height strip below the table rather than inside it. */
.dashboard-widget-table-wrap {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 0;
}
/* A total shown inside a data-table, in a strip just above the page arrows. */
.data-table-footer {
    flex: none;
    margin-top: auto;
    border-top: 1px solid var(--table-footer-line);
    padding: 11px 0 6px;
    font-size: 14px;
}
.data-table-footer + .data-table-pagination { margin-top: 0; border-top: 0; padding-top: 0; }
.data-table-footer .tr-legend { margin: 0; }
/* The same, on the left of the pagination row itself (footerInline): the page info and arrows stay at the right. */
.data-table-footer-inline { margin-right: auto; font-size: 14px; }
.data-table-footer-inline .tr-legend { margin: 0; }

/* Widgets for menu items with no natural table (settings/config pages) --
   a small shortcut card instead. */
.dashboard-widget-shortcut {
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    gap: 12px;
}
.dashboard-widget-shortcut p {
    margin: 0;
    color: var(--textcolor);
    font-size: 14px;
}

.dashboard-widget-resize-handle {
    position: absolute;
    right: 0;
    bottom: 0;
    width: 18px;
    height: 18px;
    cursor: nwse-resize;
    touch-action: none;
}
.dashboard-widget-resize-handle::after {
    content: '';
    position: absolute;
    right: 4px;
    bottom: 4px;
    width: 8px;
    height: 8px;
    border-right: 2px solid var(--textcolor);
    border-bottom: 2px solid var(--textcolor);
    opacity: 0.4;
}

@media (max-width: 640px) {
    /* Widgets are forced full-width below (grid-column: 1 / -1), so the
       container really only has one effective column here -- --dash-cols
       is set to match, or the row-height formula above would size each
       row as if there were still two columns side by side. */
    .dashboard-grid { --dash-cols: 1; }
    .dashboard-widget { grid-column: 1 / -1 !important; }
}

.role-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 14px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--tdhover);
    color: var(--menucolor);
}

/* ---- Data tables: filter + sort + read-only rows, used by every list page ---- */

/* styles.css's own .table-td is 2px padding and a border on every cell
   (meant for a much denser legacy grid) -- every list in the new app needs
   at least 10px, left-aligned headers rather than the browser's centered
   <th> default, and no full-grid borders: styles.css's own thead th::after
   already draws the header/body divider, and zebra striping on the body
   rows (below) replaces the rest of the grid. */
.table-td {
    padding: 10px;
    text-align: left;
    border: none;
}
/* Table headers otherwise inherit the browser's default bold <th> weight --
   pulled down further than before so it reads as a label, not a heading. */
th.table-td {
    font-weight: 500;
}

/* Rows were transparent, showing the page's own light-gray background
   (#f4f4f3) through -- nearly indistinguishable from the header's #f0f0f0.
   Give rows an explicit white background (on the row, not the cells, so
   the more-specific .data-tr-selected/.data-tr-disabled rules below still
   win), with even rows tinted for zebra striping in place of a border
   between them. The stripe is a light blue so it cannot be mistaken for the gray of a disabled/inactive row. */
.data-tr { background: white; }
.data-tr:nth-child(even) { background: #f3f8fd; }
/* A very light gray hairline above and below each tinted row (an inset shadow, so the rows keep their height). */
.data-tr:nth-child(even) > td { box-shadow: inset 0 1px 0 #e8eaec, inset 0 -1px 0 #e8eaec; }

.list-page-heading {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    margin-bottom: 11px;
}
.list-page-heading h1 { margin: 0; }
/* Same fix as .fonth1 + p below, for pages that wrap the title (and an "+ Add X" button
   alongside it) in .list-page-heading -- there the description paragraph is a sibling of that
   wrapper, not of the h1 directly, so .fonth1 + p never matched it and it kept its own
   browser-default margin-top stacking on top of .list-page-heading's margin-bottom above.
   Zeroed so the wrapper's own margin-bottom is the only gap, matching every other
   .list-page-heading page that goes straight into a table with no subtitle at all. */
.list-page-heading + p { margin-top: 0; }

/* .fonth1 has no margin rule of its own anywhere in this app -- what looked like intentional
   spacing was actually just the browser's own default <h1> bottom margin (0.67em against its
   24px font-size) stacking with a following <p>'s own default top margin, on every page that
   puts a one-line description right under the title (script-inventory.js, reports.js, etc.).
   Zeroed here and replaced with one deliberate value on the adjacent-paragraph case specifically,
   rather than the two browser defaults happening to add up to whatever they added up to. */
.fonth1 { margin: 0; }
.fonth1 + p,
.title-with-crumbs + p { margin-top: 12px; }

/* Page/widget titles prefixed with the same icon as their nav menu entry. */
.fonth1 .icon,
.dashboard-widget-header .icon {
    vertical-align: -4px;
    margin-right: 8px;
}
/* Only the icon leading the title gets that gap -- one inside a header button (refresh, download, settings) sits
   centred in its button. */
.dashboard-widget-actions .icon {
    margin: 0;
    vertical-align: middle;
}
/* 2px bigger than the base 16px .icon size, since it leads the widget title. */
.dashboard-widget-header .icon {
    width: 18px;
    height: 18px;
}

/* ---- Table box: every table reached from the menu is wrapped in this,
   styled the same as a dashboard widget (see .dashboard-widget above) --
   white throughout, no inset/embossed shadow, an underline below the
   header separating it from the body. ---- */
.data-table-box {
    position: relative;
    background: white;
    border-radius: var(--window-radius);
    box-shadow: var(--window-shadow);
    border: var(--window-border);
    overflow: hidden;
}
.data-table-box-header {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 8px 15px 10px 15px;
    background: white;
    font-weight: 600;
    font-size: 16px;
}
/* The underline stops 10px short of each edge instead of spanning the full
   header width, so it reads as a rule under the title rather than a border. */
.data-table-box-header::after {
    content: '';
    position: absolute;
    left: 10px;
    right: 10px;
    bottom: 0;
    border-bottom: 2px solid #aaaaaa;
}
.data-table-box-title {
    display: flex;
    align-items: center;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: #3d5a80;
}
.data-table-box-title .icon { vertical-align: -4px; margin-right: 8px; }
.data-table-box-actions {
    display: flex;
    align-items: center;
    gap: 2px;
    flex-shrink: 0;
}
.data-table-box-body {
	padding: 14px 14px 5px;
	font-size: 16px !important;
	display: flex;
	flex-direction: column;
	min-height: 420px;
}

/* Menu-driven list pages render a single heading + `#table-root` box, with
   nothing else on the page -- for exactly that shape, let the box grow to
   fill the rest of the window instead of just sizing to its min-height, so
   the row list scrolls internally rather than the whole page. Detail pages
   with several stacked tables (their own ids, not #table-root) and the
   dashboard's widget grid are unaffected. */
.app-body:has(> #table-root:last-child) {
    display: flex;
    flex-direction: column;
    height: calc(100vh - var(--topbar-height));
    box-sizing: border-box;
}
.app-body:has(> #table-root:last-child) > #table-root {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
}
.app-body:has(> #table-root:last-child) .data-table-box {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
}
.app-body:has(> #table-root:last-child) .data-table-box.data-table-box-sized {
    flex: none;               /* resized by the person using it: no longer stretched to fill the window */
    align-self: flex-start;
}
.data-table-box { position: relative; }
.data-table-resize-handle {
    position: absolute; right: 0; bottom: 0; width: 18px; height: 18px; cursor: nwse-resize; z-index: 5; touch-action: none;
    background: linear-gradient(135deg, transparent 0 50%, #b7bec5 50% 58%, transparent 58% 68%, #b7bec5 68% 76%, transparent 76%);
    border-bottom-right-radius: inherit;
}
.data-table-resize-handle:hover { background: linear-gradient(135deg, transparent 0 50%, var(--menucolor) 50% 58%, transparent 58% 68%, var(--menucolor) 68% 76%, transparent 76%); }
.data-table-box-resizing { user-select: none; }
/* Only menu pages' tables have a grip (data-table.js), and not on a phone. */
@media (max-width: 768px) { .data-table-resize-handle { display: none; } }
.app-body:has(> #table-root:last-child) .data-table-box-body {
    flex: 1;
    min-height: 0;
}

.data-table-toolbar {
    margin-bottom: 12px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
}

.data-table-search-group {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
}

/* "PCI Monitor: Unsafe" / "PCI Monitor: Safe" under a status that says something else, in the decision's colour. */
.says-tag { display: block; width: fit-content; margin-top: 4px; padding: 0 8px; border: 1px solid; border-radius: 10px; font-size: var(--font-min); font-weight: 600; white-space: nowrap; }
.says-unsafe { color: #a3243b; background: #fde8ec; border-color: #e7a9b5; }
.says-safe { color: #1e5e22; background: #e6f4ea; border-color: #a8d3ae; }
.data-table-column-searches {
    display: flex;
    align-items: center;
    gap: 8px;
}
.data-table-column-search {
    width: 180px;
    flex-shrink: 0;
}

/* Right-aligned, half the old width -- pushed right by the toolbar's
   space-between with the search group staying left. */
.data-table-filter-wrap {
    position: relative;
    display: block;
    width: 160px;
    margin-left: auto;
}

.data-table-columns-menu {
    position: absolute;
    top: 52px;
    right: 14px;
    z-index: 100;
    background: white;
    border: var(--tableborder, 1px solid #a2a9b1);
    border-radius: 8px;
    box-shadow: 0 8px 20px var(--boxShadow);
    min-width: 240px;
    overflow: hidden;
}
/* Same title-bar-with-inset-underline treatment as a table box/widget
   header, so the dropdown reads as a little box of its own. */
.data-table-columns-menu-header {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 8px 15px 10px 15px;
    font-weight: 600;
    font-size: 16px;
}
.data-table-columns-menu-header::after {
    content: '';
    position: absolute;
    left: 10px;
    right: 10px;
    bottom: 0;
    border-bottom: var(--tableborder, 1px solid #a2a9b1);
}
.data-table-columns-menu-body {
    padding: 8px;
}
.data-table-columns-list { margin-bottom: 8px; }
.data-table-columns-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 6px 8px;
    font-size: 16px;
    color: var(--textcolor);
    border-radius: 6px;
    white-space: nowrap;
}
.data-table-columns-item:hover { background-color: var(--topmenu); }
.data-table-columns-item label {
    display: flex;
    align-items: center;
    gap: 6px;
    cursor: pointer;
}
.data-table-columns-item .data-table-columns-searchable {
    font-size: 16px;
    color: #778;
}
.data-table-columns-menu .data-table-page-size {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    font-size: 16px;
    color: var(--textcolor);
    padding: 6px 8px;
    border-top: var(--tableborder, 1px solid #a2a9b1);
}
.data-table-columns-menu .data-table-page-size .select {
    width: auto;
    min-width: 70px;
}

.data-table-pagination {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 20px;
    margin-top: auto;
    /* A gray line at the end of the table, the footer (page arrows and any message beside them) 5px under it. */
    border-top: 1px solid var(--table-footer-line);
    padding: 5px 0 0;
    flex-shrink: 0;
    flex-wrap: wrap;
}
.data-table-page-info {
    font-size: 16px;
    color: var(--textcolor);
}
.data-table-page-nav {
    display: flex;
    gap: 4px;
}
/* Same 14x14 size as the column-sort chevrons, for visual consistency. */
.data-table-page-nav .icon-btn .icon { width: 16px; height: 16px; }
.data-table-page-nav .icon-btn:disabled {
    opacity: 0.35;
    cursor: not-allowed;
}
.data-table-page-nav .icon-btn:disabled:hover { background: none; }
#app-root .data-table-filter-input {
    border-radius: var(--radius);
    padding: 10px 34px 10px 10px;
    width: 100%;
    box-sizing: border-box;
}
.data-table-filter-clear:not([hidden]) {
    position: absolute;
    top: 50%;
    right: 6px;
    transform: translateY(-50%);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    background: none;
    border: none;
    border-radius: 50%;
    cursor: pointer;
    font-size: 22px;
    font-weight: 600;
    line-height: 1;
    color: var(--textcolor);
}
.data-table-filter-clear:hover { background-color: var(--topmenu); color: var(--documentred); }

/* The scrolling part of a table and, over it but not inside it, the loading indicator -- so the indicator stays in the middle of what is on
   screen however far the rows are scrolled (inside the scrolling part it would scroll away with them). */
.data-table-wrap-outer {
    position: relative;
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
}
.data-table-wrap {
    overflow: auto;
    flex: 1;
    min-height: 0;
}

/* Centered over the table area (not the whole box -- toolbar/pagination stay visible and
   usable) while a fetch is in flight, on first load, Refresh, and Search alike. */
.data-table-loading {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, 0.7);
    z-index: 5;
}
.data-table-loading img { width: 32px; height: 32px; }
/* An author-stylesheet class rule beats the browser's own [hidden]{display:none} regardless
   of write order (user-agent styles always lose to author styles of equal specificity) -- so
   toggling .hidden alone never actually hid this without an explicit override here. Same class
   of bug as an inline style beating [hidden]; this is the class-selector version of it. */
.data-table-loading[hidden] { display: none; }

/* Sole content of a dashboard widget's body until its real content (a table or a custom
   render) replaces it -- centered the same way regardless of what the widget ends up showing. */
.widget-loading {
    height: 100%;
    min-height: 60px;
    display: flex;
    align-items: center;
    justify-content: center;
}
.widget-loading img { width: 28px; height: 28px; }

.data-table {
    width: 100%;
    border-collapse: collapse;
}

/* Lets a long unbroken token (a URL, an id) wrap inside a narrowed column instead of forcing
   the column -- and the whole table -- wider than its declared width. */
.cell-wrap-anywhere {
    overflow-wrap: anywhere;
    word-break: break-word;
}

/* Pairs with a tiny width (e.g. '1%') on a short-value column (a count, a status word) --
   the column shrinks to fit its value on one line, while its header is free to wrap. */
.cell-nowrap {
    white-space: nowrap;
}

/* The same, but only while the full layout is showing: on a small screen (where the sidebar turns into a drawer, 768px and below) the cell wraps again. */
.cell-nowrap-desktop,
.cell-nowrap-desktop .link-btn,
.cell-nowrap-desktop .cell-link { white-space: nowrap; }
@media (max-width: 768px) {
    .cell-nowrap-desktop,
    .cell-nowrap-desktop .link-btn,
    .cell-nowrap-desktop .cell-link { white-space: normal; }
}

.data-table-sortable {
    cursor: pointer;
    user-select: none;
    white-space: nowrap;
}
.data-table-sortable:hover { background-color: var(--topmenu); }

.data-table-sort-icon {
    display: inline-flex;
    vertical-align: middle;
    width: 14px;
    height: 14px;
}
.data-table-sort-icon .icon { width: 14px; height: 14px; }

/* The far-left column with the row-actions menu icon: it stays in view when the table is scrolled sideways (a row's own background is
   inherited, so the stripes and the selected / disabled colours carry across). */
.data-table-menu-cell { position: sticky; left: 0; z-index: 2; width: 1%; padding: 0 4px !important; background: inherit; }
/* The menu column's heading sticks at the top as well as the left, above the rows' own menu cells (z-index 2) and above the other headings (49), so rows scroll under it. */
.data-table-menu-head { background: #f0f0f0; z-index: 51; }
.data-table-menu-btn { display: inline-flex; align-items: center; justify-content: center; }
/* The menu itself, opening where it was asked for. */
.row-menu {
    position: fixed; z-index: 3000; min-width: 190px; padding: 6px 0; background: #ffffff; border: 1px solid #c8cdd2; border-radius: 8px;
    box-shadow: 0 12px 34px rgba(0, 0, 0, 0.32), 0 2px 8px rgba(0, 0, 0, 0.2); font-size: 16px;
}
.row-menu-item {
    display: flex; align-items: center; gap: 12px; width: 100%; padding: 8px 16px; border: 0; background: none; color: var(--textcolor); text-align: left;
    font: inherit; cursor: pointer; white-space: nowrap;
}
.row-menu-item:hover:not([disabled]), .row-menu-item:focus-visible { background: #e9f1fb; outline: none; }
.row-menu-item[disabled] { opacity: 0.45; cursor: not-allowed; }
.row-menu-sep { height: 1px; margin: 4px 12px; background: #e3e6ea; }
.row-menu-icon { display: inline-flex; flex: none; width: var(--row-menu-icon, 20px); height: var(--row-menu-icon, 20px); color: var(--documentblue); }
.row-menu-icon svg { width: var(--row-menu-icon, 20px); height: var(--row-menu-icon, 20px); }
.row-menu-danger, .row-menu-danger .row-menu-icon { color: var(--documentred, #b32d2e); }
.row-menu-head { display: flex; align-items: center; justify-content: space-between; padding: 0 6px 5px 16px; margin-bottom: 4px; border-bottom: 1px solid #e3e6ea; }
.row-menu-title { font-size: 15px; font-weight: 500; letter-spacing: 0.02em; color: #6a737b; }
.row-menu-x { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; padding: 0; border: 0; border-radius: 4px; background: none; color: #6a737b; cursor: pointer; }
.row-menu-x:hover { background: #e9f1fb; color: var(--textcolor); }
.data-table-actions {
    white-space: nowrap;
    text-align: right;
}
.data-table-actions .icon-btn + .icon-btn { margin-left: 6px; }

/* Links that share a row or line ("View results > . Create report >") get 10px of air before each one after the first. */
.data-table-actions a:not(.icon-btn):not(:first-child),
.data-table-actions .link-btn:not(:first-child),
.link-row a:not(:first-child),
.auth-links a:not(:first-child) { margin-left: 10px; }

.data-table-empty {
    padding: 16px 0;
    color: var(--textcolor);
}

/* Only one row is ever selected at a time (data-table.js clears the class
   off any previously-selected row before adding it to the clicked one).
   Selected takes priority over disabled; hover styling is untouched by
   either -- both come from the browser default row background, so neither
   rule here touches :hover. */
.data-tr, .data-tr:hover td { cursor: default; }   /* styles.css gives a row's cells a hand on hover; a row is not a link */
.data-tr.data-tr-selected { background-color: #ccdddd; }
/* An inactive row's text is a lighter gray than an active row's (still readable on its gray); selected, it goes back to the darker one. The row menu icon keeps its own color. */
.data-tr.data-tr-disabled { background-color: #f0f0f0; color: #6b6b6b; }
.data-tr.data-tr-disabled .data-table-menu-btn { color: #444444; }
.data-tr.data-tr-disabled.data-tr-selected { background-color: #ccdddd; color: #444444; }

/* Small icon-only Edit/Delete row actions. */
.icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    background: none;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    color: var(--textcolor);
}
.icon-btn:hover { background-color: var(--topmenu); color: var(--menucolor); }
.icon-btn.icon-btn-danger:hover { color: var(--documentred); }
/* The Edit pencil of a list row is a stronger shade of the PCI Monitor green (the logo's own is too pale: it looks disabled), the trash can PCI Monitor red (greyed out when it cannot be used yet). */
.icon-btn[data-edit], .icon-btn-run { color: var(--pcim-green); }
.icon-btn-run:disabled { opacity: 0.35; cursor: not-allowed; background: none; }
.icon-btn[data-edit]:hover, .icon-btn-run:hover:not(:disabled) { color: var(--pcim-green-dark); }

/* Schedule-a-test dialog (Monitors list > clock): Run now / Schedule, the latter's fields greyed until it is chosen. */
.schedule-option { border: 1px solid var(--border-color, #c8d0d3); border-radius: 8px; padding: 12px 14px; margin-bottom: 12px; }
.schedule-option-label { display: flex; gap: 8px; align-items: center; margin: 0; font-weight: 600; }
.schedule-option-hint { margin: 4px 0 0 26px; }
.schedule-option-fields { margin: 12px 0 0 26px; }
.schedule-fields-off { opacity: 0.55; }
.field-group .schedule-type { display: flex; flex-wrap: wrap; gap: 8px; align-items: baseline; margin: 4px 0 0; font-weight: 400; }
.schedule-type .field-hint { margin: 0; }
/* A type that can't be chosen (Compliance without an active, paid monitor; both until Schedule is picked) reads gray, hint included. */
.schedule-type:has(input:disabled), .schedule-type:has(input:disabled) .field-hint { color: #999999; }
.icon-btn.icon-btn-trash { color: var(--logo-red); }
.icon-btn.icon-btn-trash:hover { background-color: var(--topmenu); }
.icon-btn.icon-btn-trash:disabled { opacity: 0.35; cursor: not-allowed; background: none; }
.icon-btn .icon { width: 18px; height: 18px; }

/* ---- Add/Edit pages: a Close + Save/Add action bar ---- */

.form-actions {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    gap: 10px;
    margin-top: 8px;
    /* Only takes effect when a parent (.modal-body/.form-page-body's form,
       below) is a flex column -- keeps this footer at its natural size
       instead of being stretched/shrunk by the surrounding flex layout. */
    flex-shrink: 0;
}

/* Wraps a form's fields (everything above its Close/Save footer) so only
   this region scrolls. A sticky footer *inside* the scrolling box still
   reserves its own space in that box's scrollable content, so the
   browser's scrollbar track visibly runs the full height of the box --
   behind the footer, not stopping above it. Making the footer a sibling
   that sits after this box (both children of a flex-column <form>) instead
   removes it from the scrolling content entirely, so the scrollbar only
   ever spans the fields between the header and the footer. */
.form-fields-scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    /* Reserves the scrollbar's own width up front, whether or not content is currently tall
       enough to need one -- without this, content narrows (reflows) at the exact moment a
       scrollbar switches on, which is exactly when anything sitting near the right edge (e.g.
       an accordion header's help icon) can end up clipped or overlapped by it. */
    scrollbar-gutter: stable;
    /* A clear gap between the fields and the scrollbar when there is one. */
    padding-right: 15px;
}

/* ---- Modal (below) and standalone Add/Edit "form pages" (further below)
   both give their form a fixed height to fill, so form-fields-scroll/
   form-actions can split it into a scrolling region and a fixed footer. */
.modal-body,
.form-page-body {
    display: flex;
    flex-direction: column;
}
.modal-body > form,
.form-page-body > form {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}

/* Standalone (non-modal) Add/Edit pages -- e.g. Edit Profile -- get the same
   fixed header/footer, scrolling-fields-only treatment as the modal (and as
   a dashboard widget's own header/pagination): wrap the page in .form-page,
   put everything below the <h1> in .form-page-body. */
.form-page {
    display: flex;
    flex-direction: column;
    /* max-height (not height) -- a short form should stay its natural
       height instead of always stretching to fill the viewport, matching
       the modal's own max-height cap. */
    max-height: calc(100vh - var(--topbar-height) - 48px);
}
.form-page > h1 { flex-shrink: 0; }
.form-page-body {
    flex: 1 1 auto;
    min-height: 0;
}
.form-page-body .form-actions { border-top: 2px solid #aaaaaa; padding-top: 12px; }
/* Override .auth-card .buttonOK's width:100% (meant for a single full-width
   login/register button) so Close and Save/Add end up the same standard
   button size instead of Save/Add stretching to fill the row. */
.form-actions .buttonOK,
.form-actions .buttonClose {
    width: auto;
    min-width: 100px;
    box-sizing: border-box;
}

/* ---- Every input/select/filter field site-wide: 12px font, 10px padding,
   the same resulting height (including "Rows per page") -- default option
   text reads "-- Select --" (see user-form.js's company picker). ---- */

#app-root .select,
#app-root .input {
    font-size: 16px;
    padding: 10px;
    height: auto;
    box-sizing: border-box;
}
/* Dropdowns draw their own arrow so it can sit 5px further in from the right edge than the browser's
   built-in one, which hugs the border. The right padding keeps long option text clear of the arrow. */
.select,
#app-root .select {
    -webkit-appearance: none;
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%23556666' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 10px center;
    background-size: 12px 8px;
}
#app-root .select { padding-right: 34px; }

#app-root .input:read-only,
#app-root .input:disabled,
#app-root .select:disabled {
    /* styles.css's shared .input/.select rules set background-color: white
       !important -- match it to actually win instead of losing to a rule
       with a stronger declaration regardless of source order/specificity. */
    background-color: #eeeeee !important;
    color: #444444;
}

/* A field that's only readonly as an anti-autofill trick (removed on first focus -- see
   test-group-form.js's login username/password) is fully editable, not disabled; it shouldn't
   look greyed out like the rule above, which is for fields the user genuinely can't change. */
#app-root .input.input-focus-enables:read-only {
    background-color: white !important;
    color: inherit;
    cursor: text;
}

/* Same for the fields marked data-no-autofill (js/no-autofill.js), also inside windows (which are not inside #app-root). */
#app-root .input[data-no-autofill]:read-only,
.input[data-no-autofill]:read-only {
    background-color: white !important;
    color: inherit;
    cursor: text;
}

/* ---- Modal (Add/Edit overlay) -- keeps the list page underneath (its
   filter, sort, page, and scroll position) untouched while open ---- */

.modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(13, 27, 42, 0.5);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    z-index: 1000;
}
.modal-panel {
    background: white;
    border-radius: var(--window-radius);
    border: var(--window-border);
    /* Clips the header's and sticky footer's own opaque backgrounds to this
       rounded shape -- without it those full-width rectangles square off
       the top-right/bottom-left corners since they no longer sit inside an
       overflow:auto panel (scrolling moved to .modal-body alone, below). */
    overflow: hidden;
    box-shadow: var(--modal-shadow);
    width: 100%;
    max-width: 560px;
    max-height: 90vh;
    /* Header/divider and the fields area are laid out as fixed-size flex
       children (below) so only .modal-body scrolls -- the header, divider,
       and Close/Save footer stay in place regardless of form length. */
    display: flex;
    flex-direction: column;
}
/* Opt-in (modal.js's fixedHeight option): takes max-height immediately instead of
   shrink-wrapping to content, so a form whose content changes size while open (an accordion
   section expanding/collapsing) scrolls within a stable-sized window instead of visibly
   growing/shrinking the whole modal every time a section is toggled. */
.modal-panel-fixed-height { height: 90vh; }
.modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 12px 18px 0;
    flex-shrink: 0;
}
.modal-title { margin: 0; font-size: 20px; font-weight: 600; color: #3d5a80; }

/* View (read-only) windows: a grey header with a READ-ONLY tag before the title, and a faint READ-ONLY watermark across the panel, so they are never mistaken for Add / Edit.
   The watermark sits over the panel but lets every click through. */
.modal-title-wrap { display: flex; align-items: center; gap: 10px; min-width: 0; }
.modal-panel-view { position: relative; container-type: inline-size; }   /* (the watermark is sized by the window's width) */
.modal-panel-view .modal-header { background: #e4e8ec; padding-top: 7px; padding-bottom: 5px; }
.modal-panel-view .page-title-divider { margin: 0; border-top: 1px solid #c3cad1; }
.modal-panel-view::after {
    content: attr(data-watermark);
    position: absolute; left: 50%; top: 55%; transform: translate(-50%, -50%) rotate(-24deg);
    font-size: min(96px, 12cqw); font-weight: 800; letter-spacing: 0.06em; white-space: nowrap; text-transform: uppercase;
    color: rgba(61, 90, 128, 0.057); pointer-events: none; user-select: none; z-index: 5;
}
.modal-readonly-tag {
    display: inline-block; flex: none; padding: 1px 9px;
    border: 1px solid #8793a0; border-radius: 4px; background: #f6f7f8; color: #4a5560;
    font-size: 12px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase;
}

/* Groups the maximize toggle with the close (X) button at the header's far right, so they read as one cluster. */
.modal-header-actions { display: flex; align-items: center; gap: 2px; flex-shrink: 0; }
.modal-maximize-btn { flex-shrink: 0; }

/* Divider beneath a page/modal title -- inset 15px from each edge instead
   of spanning full-bleed. flex-shrink:0 only matters inside .modal-panel's
   flex column -- harmless on the non-modal standalone Add/Edit pages that
   reuse this same class. */
.page-title-divider {
    margin: 8px 15px 0;
    border-top: 2px solid #aaaaaa;
    flex-shrink: 0;
}
.modal-close-btn {
    background: none;
    border: none;
    cursor: pointer;
    font-size: 28px;
    font-weight: 600;
    line-height: 1;
    color: var(--textcolor);
    padding: 4px 8px;
    border-radius: 6px;
    flex-shrink: 0;
}
.modal-close-btn:hover { background-color: var(--topmenu); color: var(--documentred); }
.modal-body {
    padding: 20px;
    font-size: 16px !important;
    flex: 1 1 auto;
    min-height: 0;
}
/* Nested inside .modal-panel, which already has its own border/shadow/radius -- without this,
   the Flat theme's border (and Standard's shadow) would double up, showing a visible second
   border/edge around the form area inside the modal's own. */
.modal-body .auth-card { max-width: none !important; margin-top: 0 !important; box-shadow: none; border: none; border-radius: 0; padding: 0; }
.modal-body .form-actions { border-top: 2px solid #aaaaaa; padding-top: 12px; }

/* ---- confirm-dialog.js -- replaces window.confirm() everywhere with an in-app modal that
   matches the rest of the app. Reuses .modal-overlay/.modal-panel, just smaller (this is a
   one-sentence question, never a form) and above everything else (1200): a confirm can be
   triggered from inside an already-open modal (deleting a row) or the recording overlay
   (Close discarding unsaved steps), and must never end up hidden behind either. */
.confirm-dialog-overlay { z-index: 1200; }
.confirm-dialog-panel { max-width: 420px; }
.confirm-dialog-panel .form-actions { border-top: none; padding-top: 16px; }

/* ---- AIM recording overlay -- full-screen, like .modal-overlay/.modal-panel, sitting above
   the Edit Monitoring Group modal it's opened from (and covering the top bar/sidebar too).
   Same dimmed-backdrop + floating panel look as that modal, just a fixed 15px inset instead
   of a 560px-wide shrink-wrapped panel -- .recording-panel reads the same --window-* theme
   variables as every other "window" in the app (dashboard widgets, modals), so Flat vs
   Standard is consistent here too instead of this one panel looking hardcoded. ---- */
.recording-overlay {
    position: fixed;
    inset: 0;
    background: rgba(13, 27, 42, 0.5);
    display: flex;
    padding: 15px;
    box-sizing: border-box;
    z-index: 1100;
}
.recording-panel {
    width: 100%;
    height: 100%;
    background: var(--background);
    border-radius: var(--window-radius);
    border: var(--window-border);
    box-shadow: var(--modal-shadow);
    overflow: auto;
    box-sizing: border-box;
}

/* ---- Interactive manual test window (interactive-test.js) -- reuses .recording-overlay/.recording-panel
   above for its outer chrome (same "large window" look as the AIM recorder), .modal-header/.modal-title/
   .modal-close-btn/.page-title-divider for its header (same as every other window in the app), and only
   needs its own classes for what's specific to it: the narrated step, the live screenshot, and the
   six-step check list. ---- */
.itest-panel { display: flex; flex-direction: column; }
.itest-panel .modal-header-actions { gap: 10px; }
.itest-body { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 20px; display: flex; flex-direction: column; }
.itest-intro { max-width: 560px; margin: auto; text-align: center; }
.itest-intro h3 { margin: 0 0 12px; color: #3d5a80; }
.itest-intro p { margin: 0 0 20px; color: var(--textcolor); line-height: 1.5; }

/* The narration/screenshot/checklist (.itest-left) on the left, a live-updating panel of what's
   been detected so far (.itest-right) on the right -- so the wait isn't just narration text, it's
   an actual, growing, scrollable record of findings as the real run turns them up. */
/* height: 100% (not just flex: 1 1 auto) gives the row an actual, concrete height to stretch its
   children into -- without it, a flex row's own height is just whichever child's content is
   tallest, and "Detected so far" (which can grow to dozens of rows by the time the run is
   wrapping up) was that child: the row kept growing with it instead of capping there, dragging
   the whole window taller until only the outer body's own scrollbar caught it -- at which point
   scrolling to see later findings scrolled the screenshot and narration out of view too. */
.itest-running { flex: 1 1 auto; min-height: 0; height: 100%; display: flex; flex-direction: row; align-items: stretch; gap: 28px; max-width: 1900px; margin: 0 auto; width: 100%; }
/* The preview/narration/checklist only need to be as wide as the screenshot itself -- a fixed
   width, not a flex share of the window, so "Detected so far" gets everything left over instead
   of an even (and mostly wasted) split. Twice its earlier size (a small on-page detail -- a
   validation message, an error banner -- was unreadable at the old width); the narration text and
   checklist rows below it stay their own normal size rather than scaling up to match, so the
   preview is what actually grew, not the whole left column getting visually heavier too. */
.itest-left { flex: 0 0 840px; width: 840px; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 12px; }
.itest-right {
    flex: 1 1 auto; min-width: 280px; align-self: stretch;
    display: flex; flex-direction: column; min-height: 0;
    border: var(--tableborder, 1px solid #a2a9b1); border-radius: 8px; background: #fbfcfd; overflow: hidden;
}
.itest-right-header { flex: none; padding: 12px 16px; font-weight: 700; color: var(--textcolor); background: #fff; border-bottom: var(--tableborder, 1px solid #a2a9b1); }
.itest-right-count { font-weight: 400; color: #6a737b; font-size: var(--font-min); }
/* The one part of this window meant to scroll -- everything else stays put while this fills in. */
.itest-right-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 6px 16px 16px; }
.itest-right-empty { color: #9aa4ae; font-size: var(--font-min); text-align: center; padding: 28px 8px; }
.itest-right-group-title.itest-found-page { text-transform: none; letter-spacing: normal; word-break: break-all; }
.itest-right-group + .itest-right-group { margin-top: 16px; }
.itest-right-group-title { font-size: var(--font-min); font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: #6a737b; margin: 10px 0 6px; }
.itest-live-row { padding: 8px 0; border-bottom: 1px solid #eef0f2; }
.itest-live-row:last-child { border-bottom: none; }
.itest-live-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.itest-live-page { font-size: var(--font-min); color: #6a737b; word-break: break-all; margin-top: 2px; }
.itest-live-summary { font-size: var(--font-min); color: var(--textcolor); margin-top: 2px; }
.itest-live-logins { font-size: var(--font-min); color: #9aa4ae; margin-top: 2px; }
.itest-live-badge { flex: none; font-size: var(--font-min); font-weight: 400; text-transform: uppercase; letter-spacing: 0.03em; padding: 2px 8px; border-radius: 10px; white-space: nowrap; }
.itest-live-badge-new, .itest-live-badge-modified { background: #fdecea; color: var(--documentred, #b32d2e); }
.itest-live-badge-suspected { background: #fdecea; color: var(--documentred, #b32d2e); }
.itest-live-badge-approved, .itest-live-badge-changed_approved { background: #fff2e0; color: var(--logo-orange, #c9750a); }
.itest-live-badge-unchanged, .itest-live-badge-baseline { background: #e8f5e9; color: var(--pcim-green, #2e7d32); }
.itest-live-badge-deleted, .itest-live-badge-removed { background: #eceff1; color: #6a737b; }
.itest-live-badge-medium { background: #fff2e0; color: var(--logo-orange, #c9750a); }
.itest-live-badge-low { background: #e8f5e9; color: var(--pcim-green, #2e7d32); }
.itest-live-badge-high { background: #fdecea; color: var(--documentred, #b32d2e); }
/* .itest-left alone is 840px wide -- the row layout needs at least that plus the gap plus
   .itest-right's own min-width (280px) to fit without squeezing "Detected so far" down to
   nothing, which read as it vanishing rather than properly moving below. Stacks well above that
   point instead of only right at it, so there's no narrow dead zone in between. */
@media (max-width: 1180px) {
    .itest-running { flex-direction: column; max-width: 840px; }
    .itest-left { flex: 1 1 auto; width: 100%; }
    .itest-right { max-width: none; width: 100%; max-height: 320px; }
}

/* Below the preview now (the preview itself leads, top-aligned with "Detected so far" on the
   right), so this reads as a small caption rather than the first thing in the window. */
.itest-meta-row { align-self: stretch; display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.itest-login-header { font-size: 15px; color: var(--textcolor); font-weight: 700; margin-left: auto; }
.itest-step-line { display: flex; align-items: center; gap: 10px; }
.itest-step-line[hidden] { display: none; }
/* A pulsing blue dot, then the step and what it is doing, in document blue. */
.itest-step-dot { flex: none; width: 10px; height: 10px; border-radius: 50%; background: var(--menucolor); box-shadow: 0 0 0 4px rgba(61, 90, 128, 0.15); animation: itest-pulse 1s ease-in-out infinite; }
.itest-step-count { font-size: var(--font-min); color: var(--documentblue); font-weight: 600; }
.itest-step-status { font-size: var(--font-min); color: var(--documentblue); font-weight: 400; }
/* A plain address-bar readout, like recording-window.js's own -- set once per page/step and left
   alone until the next one, so it never disappears into (or gets overwritten by) the narration
   text below, which changes constantly while this stays exactly as it is. */
.itest-url-bar {
    /* .itest-left's own flex gap (12px) applies between every child uniformly -- this negative
       margin cancels it for just this one boundary, so the URL bar sits flush against the preview
       right below it, like a real browser's address bar against its own viewport, while every
       other gap in the column stays exactly as it is. */
    align-self: stretch; padding: 5px 10px; margin-bottom: -12px; background: var(--topmenu, #eee);
    border: 1px solid #a2a9b1; border-radius: 6px 6px 0 0; font-size: var(--font-min); color: #444;
    word-break: break-all;
}
.itest-frame-wrap {
    width: 100%; aspect-ratio: 16 / 9; background: #f0f2f4; border: var(--tableborder, 1px solid #a2a9b1); border-radius: 0 0 8px 8px;
    display: flex; align-items: center; justify-content: center; overflow: hidden; flex-shrink: 0;
}
.itest-frame { max-width: 100%; max-height: 100%; object-fit: contain; }
.itest-frame[hidden] { display: none; }
.itest-frame-wrap:has(.itest-frame[hidden])::after { content: attr(data-empty-label); color: #9aa4ae; font-size: 15px; }
/* The narration text and the checklist below it now scroll together, as one box -- a technical
   failure reason (a full URL, a selector) plus six check rows underneath it could run taller than
   the space available, and scrolling them separately (or not at all) either cut one of them off or
   grew the whole window past the screen. This is the one thing that scrolls; everything else
   (screenshot, header) stays put above it. */
/* 340px comfortably fits the normal case (two lines of narration plus all six checklist rows,
   which alone run close to 230px) without ever scrolling -- the cap only actually matters for a
   genuinely long technical failure message (a full URL, a selector), which still scrolls in place
   here rather than growing the window past the screen the way it used to. */
.itest-bottom { align-self: stretch; max-height: 340px; overflow-y: auto; display: flex; flex-direction: column; }
.itest-narration { text-align: center; }
.itest-narration-text { margin: 0; font-size: 16px; font-weight: 600; color: #3d5a80; }
.itest-narration-text.itest-url { word-break: break-all; }
.itest-narration-text.itest-slow-notice { margin-top: 10px; font-size: var(--font-min); font-weight: 400; color: #6a737b; }
/* A login failure is never just informational text -- it's called out in red, and (see showCompletion)
   it's the one narration message that's never overwritten by anything shown after it. */
.itest-narration-text.itest-failed { color: var(--documentred, #b32d2e); font-weight: 400; }

@keyframes itest-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
.itest-live-row-in { animation: itest-row-in 0.25s ease-out; }
@keyframes itest-row-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

/* The six checks, walked one at a time after each page: only the one being worked on pulses; one already passed is simply no longer waiting. Nothing
   here says what was found -- the findings are written into the box on the right once the whole test is done. */
.itest-checklist { align-self: stretch; display: flex; flex-direction: column; gap: 8px; border-top: 1px solid #dfe3e7; padding-top: 14px; margin-top: 4px; }
.itest-checklist[hidden] { display: none; }
.itest-check-row { display: flex; align-items: center; gap: 10px; padding: 4px 0; }
.itest-check-dot { flex: none; width: 12px; height: 12px; border-radius: 50%; background: #d8dbde; }
.itest-check-label { font-weight: 600; color: var(--textcolor); }
.itest-check-pending .itest-check-label { opacity: 0.55; }
.itest-check-done .itest-check-dot { background: var(--menucolor); }
.itest-check-active .itest-check-dot { background: var(--menucolor); box-shadow: 0 0 0 4px rgba(61, 90, 128, 0.15); animation: itest-pulse 1s ease-in-out infinite; }

.itest-actions { align-self: stretch; text-align: center; padding-top: 14px; }

.itest-final { display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto; }
.itest-final h3 { margin: 0 0 6px; color: #3d5a80; }
.itest-final-table-wrap { flex: 1 1 auto; min-height: 0; overflow: auto; border: var(--tableborder, 1px solid #a2a9b1); border-radius: 8px; margin: 10px 0; }
.itest-final-table-wrap table { width: 100%; }

/* ---- Inline help trigger (Material Symbols "help" glyph) -- next to a window title or a
   field label, opens help-panel.js scrolled to that topic. One fixed size everywhere (matching
   a window title's own icon size) regardless of context, so it doesn't look like a different,
   smaller control when it happens to sit next to a field label instead of a heading. Color is
   a dark, muted slate-teal (not a bright accent) matching the rest of this app's own icon set
   (e.g. account.svg's #556666) rather than drawing attention away from the label it sits next
   to. Deliberately smaller than .icon-btn (32px, meant for table-row action buttons with a
   real touch target). */

.help-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    margin-left: 6px;
    padding: 0;
    border-radius: 50%;
    border: none;
    background: none;
    color: #556666;
    cursor: pointer;
    vertical-align: middle;
    flex-shrink: 0;
}
.help-icon svg { width: 20px; height: 20px; }
.help-icon:hover { color: var(--menucolor); background-color: var(--topmenu); }

/* ---- Help panel -- opened by any .help-icon (or anything else with data-help-topic) via
   help-panel.js's single delegated click handler. Higher z-index than .modal-overlay (1000)
   since most of this app's help icons live inside an already-open Add/Edit modal. ---- */

.help-panel-overlay {
    position: fixed;
    inset: 0;
    background: rgba(13, 27, 42, 0.5);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    z-index: 1100;
}
/* Same selector's own `display: flex` above otherwise beats the browser's default
   [hidden]{display:none} UA rule (author CSS always wins over UA styles at equal
   specificity) -- without this, toggling the `hidden` property closes nothing visually. */
.help-panel-overlay[hidden] { display: none; }
.help-panel {
    background: white;
    border-radius: var(--window-radius);
    border: var(--window-border);
    overflow: hidden;
    box-shadow: var(--modal-shadow);
    width: 100%;
    max-width: 640px;
    height: 80vh;
    display: flex;
    flex-direction: column;
}
.help-panel-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    /* Matches .modal-header exactly (12px 18px 0) -- the divider line right below this comes
       from the shared .page-title-divider class, not a border on this element, so there's
       never a second line stacked under it. */
    padding: 12px 18px 0;
    flex-shrink: 0;
}
.help-panel-search {
    position: relative;
    padding: 12px 18px;
    flex-shrink: 0;
}
.help-panel-search .input { width: 100%; box-sizing: border-box; padding-right: 34px; }
/* Mirrors .data-table-filter-clear's own pattern, offset for this container's own padding. */
.help-panel-search-clear:not([hidden]) {
    position: absolute;
    top: 50%;
    right: 24px;
    transform: translateY(-50%);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    background: none;
    border: none;
    border-radius: 50%;
    cursor: pointer;
    font-size: 15px;
    line-height: 1;
    color: var(--textcolor);
}
.help-panel-search-clear:hover { background-color: var(--topmenu); color: var(--documentred); }
.help-panel-list {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding: 0 18px 18px;
}
.help-panel-footer {
    display: flex;
    justify-content: flex-end;
    padding: 12px 18px;
    flex-shrink: 0;
}
.help-panel-group + .help-panel-group { margin-top: 18px; }
.help-panel-group-title {
    font-size: var(--font-min);
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: #7a828a;
    margin: 0 0 6px;
    padding-bottom: 4px;
    border-bottom: 1px solid #dddddd;
}
.help-topic {
    border-bottom: 1px solid #eeeeee;
    padding: 8px 0;
}
.help-topic summary {
    cursor: pointer;
    font-weight: 600;
    color: #3d5a80;
    padding: 2px 0;
}
.help-topic summary::marker { color: #8a9199; }
.help-topic-body {
    margin-top: 8px;
    font-size: 16px;
    line-height: 1.5;
    color: var(--textcolor);
}
.help-topic-body p:first-child { margin-top: 0; }
.help-topic-body p:last-child { margin-bottom: 0; }
.help-topic-body code {
    background: #f0f0f0;
    border-radius: 3px;
    padding: 1px 4px;
    font-size: var(--font-min);
}
.help-highlight {
    background: #fff176;
    color: inherit;
    border-radius: 2px;
    padding: 0 1px;
}

/* ---- Toasts ---- */

#toast-root {
    position: fixed;
    top: 16px;
    right: 16px;
    display: flex;
    flex-direction: column;
    gap: 8px;
    z-index: 1000;
}

.toast {
    min-width: 240px;
    max-width: 360px;
    padding: 12px 14px;
    border-radius: 8px;
    box-shadow: 0 4px 14px var(--boxShadow);
    font-size: 15px;
    color: white;
    display: flex;
    align-items: center;
    gap: 8px;
}

.toast.info { background: var(--documentblue); }
.toast.error { background: var(--documentred); }
.toast.success { background: var(--documentgreen); }

.icon {
    display: inline-block;
    width: 1em;
    height: 1em;
    vertical-align: -0.15em;
    color: currentColor;
}
.icon svg { width: 100%; height: 100%; fill: currentColor; }

/* Company Settings: profile form and billing summary sit side by side when
   there's room for both; wrapping (not a fixed viewport breakpoint) drops
   the billing column below the form once the available width -- which
   depends on the sidebar's own width/collapsed state -- can't fit both. */
.report-logo-box { display: flex; align-items: center; min-height: 64px; margin-bottom: 8px; padding: 8px; border: 1px dashed #a2a9b1; border-radius: 4px; background: #f8f9fa; }
.report-logo-box img { max-height: 56px; max-width: 100%; }
.report-logo-actions { display: flex; justify-content: flex-end; gap: 10px; }
.report-logo-actions[hidden] { display: none; }
.partner-payout-window { max-width: 760px; display: flex; flex-direction: column; }
.partner-payout-window .data-table-box-header { flex: none; }
.partner-payout-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 20px 15px 20px 20px; }
.partner-payout-body > form:first-child .field-group:first-of-type { margin-top: 0; }
.partner-payout-footer { flex: none; display: flex; justify-content: flex-end; padding: 12px 20px; border-top: 1px solid #e3e6ea; background: #fff; }
.field-inline { display: flex; align-items: center; gap: 12px; }
.field-inline .input { flex: 0 0 140px; }
.field-inline button { flex: none; white-space: nowrap; }
.partner-payout-body .fonth2 { margin: 22px 0 8px; }
.partner-payout-body form { max-width: 460px; }
.field-mark { font-weight: 400; font-size: 14px; opacity: 0.7; }
.field-mark-required { color: var(--documentred, #b32d2e); opacity: 1; }
.payout-destination { display: grid; grid-template-columns: max-content 1fr; gap: 4px 16px; margin: 10px 0 0; }
.payout-destination dt { font-weight: 600; }
.payout-destination dd { margin: 0; }
.contract-terms-window { max-width: none; }
.contract-terms-text { padding-bottom: 8px; }
.contract-terms-actions { align-items: center; }
.contract-terms-actions .partner-terms-accept { margin: 0 auto 0 0; }
.contract-terms-text ul { margin: 6px 0 10px; padding-left: 22px; }
.contract-terms-text li { margin: 4px 0; }
.contract-terms-text p { margin: 6px 0 10px; }
.partner-terms-title { margin: 14px 0 4px; font-size: 16px; }
.partner-terms-accept { display: flex; align-items: flex-start; gap: 10px; margin: 12px 0 4px; cursor: pointer; }
.partner-terms-accept input { margin-top: 4px; }
.partner-billing-card { max-width: 560px; margin: 12px 0 16px; padding: 16px; background: #fff; border: var(--tableborder, 1px solid #a2a9b1); border-radius: var(--window-radius); }
.partner-billing-details { display: grid; grid-template-columns: max-content 1fr; gap: 6px 16px; margin: 0 0 14px; }
.partner-billing-details dt { font-weight: 600; }
.partner-billing-details dd { margin: 0; }
.company-settings-columns {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 24px;
}
.company-settings-form-col {
    flex: 0 1 560px;
    min-width: 280px;
}
/* .auth-card's own max-width:400px (sized for the narrow login/register
   card) would otherwise leave the form visibly narrower than its column,
   even though the column is wider than the card. */
.company-settings-form-col .auth-card {
    max-width: none;
}

/* ---- Accordion: collapsible form sections (Monitoring Group Add/Edit) --
   same title-bar-with-chevron look as a data-table box/dashboard widget,
   stacked as independently expandable panels. ---- */
.accordion {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin: 16px 0;
}
.accordion-section {
    background: white;
    border: var(--tableborder, 1px solid #a2a9b1);
    border-radius: var(--window-radius);
    overflow: hidden;
}
/* A plain div, not a button -- the help icon sits inside .accordion-title-group (between the
   title and the chevron), and a real <button> can't contain another interactive element
   without either being invalid HTML (nested buttons) or the click bubbling up and toggling
   the section every time the help icon is used. role="button"/tabindex/keydown (wired below)
   restore the keyboard/a11y behavior a real button would give for free. */
.accordion-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    padding: 10px 15px;
    /* Without this, width:100% + padding renders 30px wider than the section that clips it
       (content-box is the default) -- exactly enough to push the chevron (and, before it moved
       next to the title, the help icon) outside the visible box at all times, not just when a
       scrollbar narrows things further. */
    box-sizing: border-box;
    background: #e9e9e8;
    font-weight: 500;
    font-size: 16px;
    color: var(--textcolor);
    cursor: pointer;
}
.accordion-header:hover { background-color: var(--tdhover); }
.accordion-title-group {
    display: flex;
    align-items: center;
    gap: 6px;
    flex: 1 1 auto;
    min-width: 0;
}
.accordion-header .help-icon { flex-shrink: 0; }
.accordion-title { display: flex; align-items: center; gap: 8px; min-width: 0; }
.accordion-title .icon { width: 18px; height: 18px; }
.accordion-chevron { flex-shrink: 0; margin-left: 10px; color: #6b7680; }
.accordion-body {
    padding: 16px;
    border-top: 2px solid #aaaaaa;
}

/* ---- A page split into sections by a menu down its left side (components/side-menu.js) ---- */
/* The one-line reason under an extra check, lined up with the checkbox label. */
.check-why { margin: 0 0 12px 24px; }
/* All the small explanatory text on the monitor form is a little larger than elsewhere. */
#tg-form .field-hint { font-size: 16px; }
/* A light gray line between two groups of fields. */
.field-divider { border: none; border-top: 1px solid #dfe3e7; margin: 20px 0; }
.tg-banners { flex-shrink: 0; }
.tg-banners .form-error-banner ul { margin: 4px 0 0 18px; padding: 0; }
.tg-banners .form-error-banner a { color: inherit; text-decoration: underline; }
/* min-width:0 on both -- without it, a flex item defaults to a content-based automatic minimum
   width instead of shrinking to fit, so a wide table two levels down inside .side-panes (which
   already sets min-width:0 itself) was still pushing this whole chain past the modal's right
   edge, out to the browser window's own edge, instead of scrolling inside the table's own box. */
.tg-sections { flex: 1 1 auto; min-height: 0; min-width: 0; display: flex; }
.side-layout { flex: 1 1 auto; min-height: 0; min-width: 0; display: flex; gap: 20px; }
.side-menu { flex: 0 0 190px; display: flex; flex-direction: column; gap: 2px; padding-right: 12px; border-right: 2px solid #aaaaaa; overflow-y: auto; }
.side-menu-item { display: flex; align-items: center; justify-content: space-between; gap: 8px; width: 100%; padding: 9px 12px; border: none; border-left: 4px solid transparent; border-radius: 4px;
    background: none; font: inherit; font-size: 16px; text-align: left; color: var(--textcolor); cursor: pointer; }
.side-menu-item:hover { background: var(--tdhover); }
.side-menu-item.active { border-left-color: var(--menucolor); background: #e9f1fb; color: var(--menucolor); font-weight: 600; }
.side-menu-mark { flex: none; width: 12px; height: 12px; border-radius: 50%; background: var(--logo-red, #c8324b); }
.side-menu-mark[hidden] { display: none; }
/* A mark that says how many: a small red number instead of a dot. */
.side-menu-mark.side-menu-mark-count { width: auto; min-width: 20px; height: 20px; padding: 0 6px; box-sizing: border-box; border-radius: 10px;
    color: #fff; font-size: 13px; font-weight: 600; line-height: 20px; text-align: center; }
/* The sections of a test result (Scripts, the page-check groups). In the test window they take all the room under the counts, down to the
   Close button: the menu and its line run the full height, the table's header stays put, and only the rows scroll. */
.tr-sections { margin-top: 12px; }
.tr-sections .side-menu { flex-basis: 200px; }
.tr-modal > .tr-sections { flex: 1 1 200px; min-height: 200px; display: flex; flex-direction: column; }
.tr-sections .side-layout { min-height: 0; }
.tr-modal .tr-sections .side-panes { display: flex; flex-direction: column; overflow: hidden; padding-right: 0; }
.tr-modal .tr-sections .side-pane:not([hidden]) { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.tr-modal .tr-sections .side-pane-body { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.tr-modal .tr-sections .side-pane-body > div { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.side-panes { flex: 1 1 auto; min-width: 0; overflow-y: auto; padding-right: 15px; }
.side-pane-title { display: flex; align-items: center; gap: 6px; margin: 0 0 12px 0; font-size: 18px; color: #3d5a80; }

/* ---- Audit Logs filter bar -- a plain row of field-groups (not data-table.js's own
   per-column filter system, which has no date-range support), each sized to its own content
   rather than stretched full-width. ---- */
.audit-log-filters {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 12px;
    margin-bottom: 12px;
}
.audit-log-filters .field-group { margin: 0; }
.audit-log-filters .select,
.audit-log-filters .input { width: auto; min-width: 160px; }

/* ---- "Working on" picker (PCI Monitor and Partner users): which company the menus and pages show ---- */
.app-topbar-scope { position: relative; min-width: 0; }
.scope-picker { position: relative; }
/* Each kind has a colour (home red, partner orange, client green) used as text/icon colour and, as its
   rgb triplet, as a semi-transparent tint behind the button and the rows. */
.scope-kind-home { --kind: #c62828; --kind-rgb: 198, 40, 40; color: var(--kind); }
.scope-kind-partner { --kind: #ef6c00; --kind-rgb: 239, 108, 0; color: var(--kind); }
.scope-kind-client { --kind: #2e7d32; --kind-rgb: 46, 125, 50; color: var(--kind); }
/* One line: icon, kind, name, chevron. */
.scope-btn {
    display: flex; align-items: center; gap: 8px;
    height: 40px; max-width: 360px; box-sizing: border-box;
    padding: 0 10px; background: rgba(var(--kind-rgb), 0.14); border: 2px solid var(--kind); border-radius: 8px;
    cursor: pointer; font-family: inherit; text-align: left;
}
.scope-btn:hover { background: rgba(var(--kind-rgb), 0.24); }
/* A client user has no picker -- just their own company's name as plain text (see scope-picker.js). */
.scope-static-name { font-size: 16px; font-weight: 500; color: var(--textcolor); }
.scope-btn .icon { width: 20px; height: 20px; flex: 0 0 20px; }
.scope-btn .scope-chevron { display: inline-flex; flex: 0 0 auto; }
.scope-btn .scope-chevron .icon { width: 14px; height: 14px; flex: 0 0 14px; }
.scope-btn-kind { font-size: var(--font-min); font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--kind); flex: 0 0 auto; }
.scope-name { font-size: 16px; font-weight: 500; color: var(--textcolor); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.scope-panel {
    position: absolute; top: calc(100% + 6px); left: 0; z-index: 400;
    width: 400px; max-width: calc(100vw - 32px);
    background: white; border: var(--tableborder); border-radius: 8px; box-shadow: 0 6px 18px var(--boxShadow);
    padding: 8px;
}
.scope-panel[hidden] { display: none; }
.scope-search { width: 100%; box-sizing: border-box; margin-bottom: 6px; }
.scope-list { max-height: min(60vh, 460px); overflow-y: auto; }
/* A row: connector cells, then a body (the +/-, the icon, the name, the kind). The connector cells stretch the
   full row height so their lines run unbroken from row to row. */
.scope-item { display: flex; align-items: stretch; min-height: 32px; padding: 0 6px; border-radius: 6px; cursor: pointer; font-size: 15px; white-space: nowrap;
    background: rgba(var(--kind-rgb), 0.10); box-shadow: inset 0 -1px 0 rgba(255, 255, 255, 0.9); }
.scope-item:hover, .scope-item.scope-active { background: rgba(var(--kind-rgb), 0.22); }
.scope-item.scope-current { font-weight: 700; box-shadow: inset 3px 0 0 var(--kind), inset 0 -1px 0 rgba(255, 255, 255, 0.9); }
.scope-item-body { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }
.scope-item .icon { width: 18px; height: 18px; flex: 0 0 18px; }
.scope-item-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--textcolor); }
.scope-item-kind { font-size: var(--font-min); font-weight: 400; text-transform: uppercase; letter-spacing: 0.06em; color: var(--kind); flex: 0 0 auto; }
.scope-item-note { font-size: var(--font-min); color: #778; font-weight: 400; }
/* Connector cells: the line runs down at 8px in (under the parent's +/-), with an elbow or tee across to the row. */
.scope-g { position: relative; flex: 0 0 auto; align-self: stretch; }
.scope-g-line::before, .scope-g-tee::before, .scope-g-elbow::before { content: ''; position: absolute; left: 8px; top: 0; border-left: 1px solid #9aa4ae; }
.scope-g-line::before, .scope-g-tee::before { bottom: 0; }
.scope-g-elbow::before { height: 50%; }
.scope-g-tee::after, .scope-g-elbow::after { content: ''; position: absolute; left: 8px; right: 3px; top: 50%; border-top: 1px solid #9aa4ae; }
.scope-toggle, .scope-toggle-gap { flex: 0 0 16px; width: 16px; }
.scope-toggle { height: 16px; box-sizing: border-box; border: 1px solid #7d8791; border-radius: 3px; background: white; color: #33414d;
    font-size: 14px; line-height: 13px; font-weight: 700; text-align: center; cursor: pointer; user-select: none; }
.scope-toggle:hover { border-color: var(--kind); color: var(--kind); }
.scope-empty { padding: 12px; color: #667; font-size: 14px; }
@media (max-width: 768px) { .scope-btn { max-width: 190px; } .scope-btn-kind { display: none; } }

/* ---- Test results: script counts in the logo's colours ---- */
:root {
    --logo-green: #7db496;
    --logo-orange: #ff8f2a;
    --logo-red: #c8324b;
    /* The logo's green is pale; this is its stronger shade for anything that has to read as clickable (icons, links, marks). */
    --pcim-green: #2b9a5f;
    --pcim-green-dark: #1f7d49;
}
.tr-green { --tr: var(--logo-green); }
.tr-orange { --tr: var(--logo-orange); }
.tr-red { --tr: var(--logo-red); }

/* A count: the logo colour as its border and a light wash of it behind the number. */
.tr-count {
    display: inline-block;
    min-width: 32px;
    box-sizing: border-box;
    padding: 1px 8px;
    text-align: center;
    font-weight: 600;
    color: var(--textcolor);
    border: 2px solid var(--tr);
    border-radius: 12px;
    background: color-mix(in srgb, var(--tr) 22%, white);
}
.tr-count.tr-zero { opacity: 0.45; }
/* Counts side by side in one table cell: all the same width -- room for three digits -- and 10px apart. */
.tr-counts { display: inline-flex; align-items: center; gap: 10px; }
.tr-counts .tr-count { box-sizing: border-box; width: calc(3ch + 22px); min-width: 0; padding: 1px 0; }
.tr-none { color: #8a9096; }

/* A script's result label in the detail list. */
.tr-state {
    display: inline-block;
    padding: 1px 8px;
    font-weight: 600;
    border-left: 6px solid var(--tr);
    background: color-mix(in srgb, var(--tr) 16%, white);
    color: var(--textcolor);
}

.tr-dot {
    display: inline-block;
    width: 14px;
    height: 14px;
    margin-right: 6px;
    border-radius: 50%;
    background: var(--tr);
    vertical-align: -1px;
}
.tr-legend { display: flex; flex-wrap: wrap; gap: 4px 20px; margin: 8px 0 12px; }
/* The legend's markers are small empty versions of the count circles in the table (same border and light wash), not solid dots. */
.tr-legend .tr-dot {
    box-sizing: border-box;
    width: 20px;
    height: 12px;
    margin-right: 6px;
    border: 2px solid var(--tr);
    border-radius: 6px;
    background: color-mix(in srgb, var(--tr) 22%, white);
    vertical-align: -1px;
}
.tr-summary {
    display: grid; grid-template-columns: max-content repeat(4, max-content); align-items: center; gap: 8px 24px; margin: 0;
}
/* The line's own name (Script checks (n) / Page checks (n)), then one column per state: the same state sits in the same column on both lines. */
.tr-summary-lead { font-weight: 600; }
/* Caption then count, the count at the column's right edge -- so the counts line up whatever the caption's length. */
.tr-summary-item { justify-self: end; }
/* Counts here are all the same width too -- room for three digits. */
.tr-summary .tr-count { box-sizing: border-box; width: calc(3ch + 22px); min-width: 0; padding: 1px 0; }
/* The top of the test: the summary on the left, the two buttons stacked at the right. */
.tr-view-head { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: 12px 24px; margin: 8px 0 12px; }
.tr-summary-item { display: inline-flex; align-items: center; gap: 6px; }

.tr-hold { font-weight: 600; color: var(--logo-red); }
/* The suggested fix of a finding: neutral gray, like in the compliance report -- green would read as fine. */
.tr-title-when { font-weight: 400; }
.suggested-fix { background: #eef1f4; border-left: 3px solid #6a737b; padding: 8px 12px; margin: 12px 0; }
.tr-auto {
    display: inline-block;
    padding: 0 6px;
    font-size: var(--font-min);
    border: 1px solid var(--logo-orange);
    border-radius: 8px;
    color: var(--textcolor);
    cursor: default;
}
/* A held compliance test: what is held, and the Release button. */
.tr-release {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px 16px;
    margin: 0 0 12px;
    padding: 10px 14px;
    border: 1px solid #d8dbde;
    border-left: 6px solid var(--logo-orange);
    background: color-mix(in srgb, var(--logo-orange) 10%, white);
}
.tr-release[hidden] { display: none; }

/* ---- Top bar: the logo block ends in a vertical line that continues the sidebar's right border ---- */
.app-topbar { gap: 0; padding: 0 16px 0 0; }
.app-topbar-lead {
    align-self: stretch;
    /* The sidebar's width, so this line and the sidebar's right border are one continuous line. The menu button's
       three lines start at the same x as the sidebar's icons (8px padding + the button's own 12px), and the logo
       follows it closely (6px after the button, 18px after the lines). */
    width: 240px;
    box-sizing: border-box;
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 6px;
    padding: 0 15px 0 8px;
    border-right: var(--tableborder);
    flex-shrink: 0;
}
/* 15px between the line and the company picker. */
.app-topbar-scope { margin-left: 15px; }
/* The collapsed rail (64px) is too narrow for the logo block, so the line simply follows the logo. */
.app-shell-page:has(.app-sidebar.collapsed) .app-topbar-lead { width: auto; }
/* Small screens: the menu is a drawer, and only the logo is kept -- no "PCI Monitor" text. */
@media (max-width: 768px) {
    .app-topbar-lead { width: auto; justify-content: flex-start; gap: 12px; }
    .brand-text { display: none; }
}

/* ---- Support tickets ---- */
.ticket-bell { position: relative; }
.ticket-bell-btn {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    min-width: 40px;
    height: 40px;
    padding: 0 8px;
    box-sizing: border-box;
    background: none;
    border: none;
    border-radius: 8px;
    color: var(--textcolor);
    cursor: pointer;
}
.ticket-bell-btn:hover { background: var(--topmenu); }
.ticket-bell-btn .icon { width: 24px; height: 24px; flex: none; }
/* The count sits beside the bell, not over it: the whole bell shows, and the number is centered in its red pill. */
.ticket-bell-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    box-sizing: border-box;
    padding: 0 6px;
    font-size: var(--font-min);
    font-weight: 700;
    line-height: 1;
    text-align: center;
    color: white;
    background: var(--logo-red);
    border-radius: 10px;
}
.ticket-bell-badge[hidden] { display: none; }
.ticket-bell-panel {
    position: absolute;
    right: 0;
    top: 100%;
    z-index: 400;
    width: 340px;
    max-width: 90vw;
    background: white;
    border: var(--tableborder);
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
    padding: 6px 0;
}
.ticket-bell-panel[hidden] { display: none; }
.ticket-bell-panel ul { list-style: none; margin: 0; padding: 0; }
.ticket-bell-panel li a,
.ticket-bell-all { display: block; padding: 8px 14px; }
.ticket-bell-panel li a:hover,
.ticket-bell-all:hover { background: var(--topmenu); text-decoration: none; }
.ticket-bell-with { display: block; font-size: var(--font-min); color: #6a737b; }
.ticket-bell-empty { margin: 0; padding: 10px 14px; color: #6a737b; }
.ticket-bell-all { border-top: 1px solid #e2e5e8; font-weight: 600; }

.ticket-status { display: inline-block; padding: 1px 8px; font-weight: 600; border-radius: 10px; border: 2px solid var(--logo-green); background: color-mix(in srgb, var(--logo-green) 22%, white); }
.ticket-status-closed { border-color: #9aa4ae; background: #eef0f2; color: #55616b; }
.ticket-unread-dot { display: inline-block; width: 9px; height: 9px; margin-right: 6px; border-radius: 50%; background: var(--logo-red); vertical-align: 1px; }
.ticket-unread { font-weight: 700; }
.ticket-waiting-tag { display: inline-block; margin-left: 6px; padding: 1px 8px; border-radius: 999px; background: #fdeacc; border: 1px solid #f0b866; color: #8a4b00; font-size: 13px; font-weight: 600; white-space: nowrap; }

.ticket-layout { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 20px; align-items: start; margin-top: 12px; }
@media (max-width: 900px) { .ticket-layout { grid-template-columns: minmax(0, 1fr); } }
.ticket-thread { display: flex; flex-direction: column; gap: 10px; }
/* The ticket in a window over the list: the whole conversation scrolls inside the window, not the window itself. */
.modal-body .ticket-view { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding-right: 6px; }
.ticket-message { background: white; border: var(--tableborder); border-radius: 8px; padding: 10px 14px; }
.ticket-message-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; margin-bottom: 6px; }
.ticket-message-company { font-size: var(--font-min); padding: 0 8px; border: 1px solid #c3c9ce; border-radius: 8px; color: #55616b; }
.ticket-message-body { white-space: pre-wrap; overflow-wrap: anywhere; }
.ticket-event { text-align: center; font-size: var(--font-min); color: #6a737b; }
.ticket-reply { margin-top: 14px; margin-bottom: 20px; }
.ticket-reply textarea { width: 100%; box-sizing: border-box; }
.ticket-reply-actions { display: flex; align-items: center; justify-content: flex-end; gap: 12px; margin-top: 8px; }
.ticket-side { background: white; border: var(--tableborder); border-radius: 8px; padding: 12px 14px; position: sticky; top: 8px; }
/* The status line: the badge, and Close ticket / Reopen at the right of it. */
.ticket-status-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
/* In the window the conversation scrolls on its own and the side panel stays where it is. */
.modal-body .ticket-view { overflow: hidden; display: flex; flex-direction: column; padding-right: 0; }
.modal-body .ticket-view .ticket-layout { flex: 1 1 auto; min-height: 0; align-items: stretch; margin-top: 0; }
.modal-body .ticket-view .ticket-main { overflow-y: auto; min-height: 0; padding-right: 6px; }
.modal-body .ticket-view .ticket-side { position: static; overflow-y: auto; min-height: 0; }
.ticket-facts { display: grid; grid-template-columns: 1fr; margin: 0; }
.ticket-facts dt { margin-top: 10px; font-size: var(--font-min); color: #6a737b; }
.ticket-facts dt:first-child { margin-top: 0; }
.ticket-facts dd { margin: 2px 0 0; }
.ticket-facts .select { width: 100%; }
.ticket-notes { margin-top: 16px; padding-top: 12px; border-top: 1px solid #e2e5e8; display: flex; flex-direction: column; gap: 8px; }
.ticket-notes .fonth2 { margin: 0; }

/* ---- Notes about a partner or client ---- */
/* .modal-body already pads 20px each side, so the content is 40px narrower than the panel it should fill. */
.notes-dialog { width: min(688px, calc(80vw - 40px)); max-width: 100%; display: flex; flex-direction: column; min-height: 0; max-height: calc(90vh - 130px); }
.notes-dialog > * { flex-shrink: 0; }
/* The dialog stops growing once the list reaches this height; the list then scrolls (the panel itself clips overflow). */
.notes-dialog .notes-list { flex: 1 1 auto; min-height: 80px; max-height: 50vh; overflow-y: auto; scrollbar-gutter: stable; }
.notes-add textarea { width: 100%; box-sizing: border-box; }
.notes-add { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; margin-bottom: 14px; }
.notes-add-actions { display: flex; gap: 10px; }
.note { display: grid; grid-template-columns: 40px minmax(0, 1fr); column-gap: 8px; border-top: 1px solid #e2e5e8; padding: 10px 0; }
/* The menu icon has a column of its own, at the left of the note (empty for a note that cannot be changed, so the notes line up). */
.note-menu-col { display: flex; align-items: flex-start; justify-content: center; }
.note-main { min-width: 0; }
.note-meta { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; font-size: 14px; }
.note-meta span { color: #6a737b; }
/* Same size as the dialog's other text and links (the meta line around them is smaller). */
.note-body { white-space: pre-wrap; overflow-wrap: anywhere; margin-top: 4px; }
.notes-edit-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 6px; }
.note textarea { width: 100%; box-sizing: border-box; }
.link-btn { background: none; border: none; padding: 0; font: inherit; font-weight: 500; color: var(--menucolor); cursor: pointer; }
.link-btn:hover { text-decoration: underline; }
.tr-head-actions { display: flex; flex-wrap: wrap; gap: 8px; }

/* Ticket messages: coloured by who wrote them (the company picker's colours), the other side indented. */
.ticket-by-pcimonitor { --by: #c62828; --by-rgb: 198, 40, 40; }
.ticket-by-partner { --by: #ef6c00; --by-rgb: 239, 108, 0; }
.ticket-by-client { --by: #2e7d32; --by-rgb: 46, 125, 50; }
.ticket-message[class*="ticket-by-"] {
    background: rgba(var(--by-rgb), 0.07);
    border-left: 5px solid var(--by);
}
.ticket-message[class*="ticket-by-"] .ticket-message-company {
    color: var(--by);
    border-color: var(--by);
    background: rgba(var(--by-rgb), 0.10);
}
.ticket-other-side { margin-left: 24px; }

/* The open-and-reply icon at the end of a ticket row. */
.ticket-open-btn:hover { background: var(--topmenu); text-decoration: none; }
.ticket-open-unread { color: var(--logo-red); }

.ticket-closed-note { margin: 14px 0 0; padding: 10px 14px; border: 1px dashed #b7bec5; border-radius: 8px; color: #55616b; }

/* A wide modal (a table inside), and one stacked above another. */
.modal-panel-wide { max-width: 1200px; }
.modal-panel-medium { max-width: 940px; }
.modal-overlay-stacked { z-index: 1100; }
/* The script viewer: details on top, the script text taking the rest of the fixed-height window and scrolling
   in its own box, Close / Copy pinned at the bottom right. min-width:0 lets long lines wrap instead of widening it. */
.script-viewer { flex: 1 1 auto; min-height: 0; min-width: 0; display: flex; flex-direction: column; }
.script-viewer > * { flex-shrink: 0; }
.script-viewer .script-viewer-text {
    flex: 1 1 auto; flex-shrink: 1; min-height: 80px; min-width: 0; margin: 0; padding: 10px; box-sizing: border-box;
    overflow: auto; scrollbar-gutter: stable; border: 1px solid #a2a9b1; border-radius: 4px; background: #f8f9fa;
    font: 14px/1.45 Consolas, 'Courier New', monospace; white-space: pre-wrap; overflow-wrap: anywhere;
}
.script-viewer .form-actions { margin-top: 12px; }
/* What the window shows about the script (where it is, where it came from, its standing, the text) scrolls as a whole, so a very long address cannot
   push the "Change status to" panel and the Close button out of the window: those two stay in place below it. */
.script-viewer-scroll { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; overflow-y: auto; padding-right: 6px; }
.script-viewer-scroll > * { flex-shrink: 0; }
.script-viewer-scroll .script-code { flex: 1 0 260px; }
/* The script text with its copy icon at the top right. */
.script-code { position: relative; flex: 1 1 auto; min-height: 80px; display: flex; }
.script-code .script-viewer-text { flex: 1 1 auto; min-width: 0; }
.script-copy-btn { position: absolute; top: 6px; right: 22px; width: 32px; height: 32px; padding: 0; display: inline-flex; align-items: center; justify-content: center;
    border: 1px solid #c5ccd3; border-radius: 6px; background: rgba(255, 255, 255, 0.92); color: #3d5a80; cursor: pointer; }
.script-copy-btn:hover { background: #e9f1fb; }
/* "Change status to": the list of choices under the text, what the choice does, and the reason. */
.script-change { flex-shrink: 0; margin-top: 12px; padding-top: 10px; border-top: 1px solid #d8dbde; }
.script-change-row { display: flex; align-items: center; gap: 10px; }
.script-change-row label { font-weight: 600; white-space: nowrap; }
.script-change-row .select { flex: 1 1 auto; max-width: 520px; }
.script-change-explain { margin: 8px 0; padding: 8px 10px; background: #f3f5f7; border-left: 3px solid var(--menucolor); }
.script-change-explain.warn { background: #fde8ec; border-left-color: #c8324b; }
.script-change .field-group { margin-bottom: 6px; }
.script-change textarea { width: 100%; box-sizing: border-box; }
.script-change-apply { display: flex; justify-content: flex-end; gap: 8px; margin-top: 6px; }
/* The test result window: its content only scrolls when the window is very short, so no room is kept back for a scrollbar -- the table
   then reaches the right end of the line above the Close button. */
.tr-modal { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
.tr-view-actions { display: flex; flex-direction: column; align-items: stretch; gap: 8px; margin: 0; }
/* The window's content is a column: the description, counts, release box and any error message keep their
   size, and the scripts table takes all the rest, down to the divider above the Close button -- so an error
   message just makes the table a little shorter instead of pushing anything out of place. The table's rows
   scroll inside it; if the window is very short, the whole content scrolls instead. */
.tr-modal { display: flex; flex-direction: column; }
.tr-modal > * { flex-shrink: 0; }
.tr-modal > #table-root { flex: 1 1 320px; min-height: 320px; display: flex; flex-direction: column; }
.tr-modal .data-table-box { flex: 1; min-height: 0; display: flex; flex-direction: column; box-shadow: none; border: 1px solid #d8dbde; }
.tr-modal .data-table-box-body { flex: 1; min-height: 0; }
.tr-modal .form-error-banner { max-height: 96px; overflow-y: auto; overflow-wrap: anywhere; }

/* The test's description on the left, its actions on the same line at the right. */
.tr-view-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 16px; margin: 0 0 8px; }
.tr-view-head p { margin: 0; min-width: 0; overflow-wrap: anywhere; }
.tr-view-head .tr-view-actions { margin: 0; }

/* A note in a table: cut off, the whole text on hover. */
.note-cell { cursor: help; }
.note-dialog-check { display: flex; align-items: center; gap: 8px; margin: 0 0 12px; }

.tr-history-toggle { display: inline-flex; align-items: center; gap: 8px; margin: 0 24px 8px 0; cursor: pointer; }
.tr-release#history-box { border-left-color: #9aa4ae; background: #eef0f2; }

/* ---- KPI widget: a ring of the latest test's green / orange / red script counts ---- */
/* KPI and Monthly trend on a page of their own (Reports): the widget sits in a white card. */
.report-card { max-width: 900px; background: white; border-radius: var(--window-radius); box-shadow: var(--window-shadow); border: var(--window-border); padding: 14px; }
.report-widget { display: flex; flex-direction: column; min-height: 320px; }
.report-widget-tall { height: clamp(380px, calc(100vh - 300px), 720px); }
/* The monthly trend page: the chart takes the width of the window, with 15px to each side. */
.report-card-wide { max-width: none; margin: 0 -9px; }
.report-card { position: relative; box-sizing: border-box; }
/* Once resized by the person using it, the card takes the size it was given and its chart fills it. */
.report-card.data-table-box-sized { max-width: none; display: flex; flex-direction: column; overflow: hidden; }
.report-card.data-table-box-sized .report-widget { flex: 1 1 auto; height: auto; min-height: 0; }
.kpi { flex: 1; min-height: 0; display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 12px 24px; overflow: auto; }
/* On the KPI page the ring sits the same distance from the card's left and top edges (instead of floating in the middle). */
.report-card .kpi { --kpi-margin: 20px; justify-content: flex-start; align-items: flex-start; padding: calc(var(--kpi-margin) - 14px) 0 0 calc(var(--kpi-margin) - 14px); }
/* The ring's drawing has an empty border of 11 of its 200 units (5.5%) all round; moving the ring by that much makes the visible edge, not the empty box, sit --kpi-margin from the corner. */
.report-card .kpi-ring { transform: translate(-5.5%, -5.5%); }
/* The rings take what room there is, up to 210px, and shrink with the window or the card down to 130px before the next one wraps below. */
.kpi-ring { position: relative; flex: 1 1 150px; max-width: 210px; min-width: 150px; aspect-ratio: 1; container-type: inline-size; }
/* Two rings side by side (scripts, page checks), each with its name above it. */
.kpi-set { flex: 1 1 150px; max-width: 210px; min-width: 150px; }
.kpi-set .kpi-ring { flex: none; width: 100%; min-width: 0; }
.kpi-set-title { margin: 0 0 4px; font-size: 16px; font-weight: 600; color: #3d5a80; text-align: center; }
.report-card .kpi-set-title { text-align: left; }
.kpi-legend-title { margin: 8px 0 4px; font-size: 16px; font-weight: 600; color: #3d5a80; }
.kpi-legend-title:first-of-type { margin-top: 0; }
.kpi-legend + .kpi-legend-title { margin-top: 12px; }
.kpi-ring svg { display: block; width: 100%; height: 100%; }
.kpi-track { fill: none; stroke: #e6e9ec; stroke-width: 22; }
.kpi-seg { fill: none; stroke-width: 22; stroke-linecap: butt; }
.kpi-seg-green { stroke: var(--logo-green); }
.kpi-seg-orange { stroke: var(--logo-orange); }
.kpi-seg-red { stroke: var(--logo-red); }
.kpi-center { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding: 0 18%; }
/* The verdict's size follows the ring's (not the window's), so it always fits inside it; the line under it is left out of the smallest rings. */
.kpi-verdict { font-size: clamp(18px, 14cqw, 30px); font-weight: 700; line-height: 1.1; }
@container (max-width: 169px) { .kpi-sub { display: none; } }
.kpi-tone-green { color: #4c8a68; }
.kpi-tone-red { color: var(--logo-red); }
.kpi-tone-none { color: var(--textcolor); }
.kpi-sub { margin-top: 2px; font-size: 16px; color: #55616b; }
.kpi-scripts { margin-top: 4px; font-size: 16px; font-weight: 600; color: var(--textcolor); }
.kpi-side { min-width: 170px; }
.kpi-legend { list-style: none; margin: 0 0 8px; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.kpi-legend li { display: grid; grid-template-columns: 20px 1fr auto 50px; align-items: center; gap: 4px; font-size: 16px; cursor: default; }
.kpi-legend .tr-dot { margin: 0; }
.kpi-pct { text-align: right; color: #6a737b; }
.kpi-caption { font-size: 16px; color: #6a737b; margin-bottom: 6px; }
.kpi-link { font-size: 16px; }

/* Deleted scripts: grey. */
.tr-gray { --tr: #9aa4ae; }
.kpi-seg-gray { stroke: #9aa4ae; }
.kpi-select { width: 100%; margin: 0 0 10px; }
/* The trend chart's controls: Scripts | Page checks, and the monitor drop-down. Exactly the same recipe as
   .select's own box (styles.css: 2px border, 10px/12px padding, border-box, 16px font) instead of a stretch
   or a guessed height -- the two are built the same way, so they come out the same height by construction. */
.trend-controls { display: flex; flex-wrap: wrap; gap: 8px 12px; }
.trend-controls .kpi-select { flex: 1 1 180px; width: auto; margin: 0 0 4px; }
/* An explicit height, matching .select's own real rendered height exactly (measured: both built from the
   same 2px/10px/16px recipe) -- .trend-views's OWN border would otherwise add on top of its content's
   height instead of being absorbed within it, since box-sizing only reinterprets an *explicit* height/width,
   never how a box with height:auto sizes itself. The button then matches this box exactly via height:100%,
   which only resolves correctly (not as auto) once its parent's height, like this one now, is definite. */
.trend-views { display: inline-flex; flex: none; height: 43px; box-sizing: border-box; border: 2px solid #cccccc; border-radius: 6px; overflow: hidden; }
.trend-view { height: 100%; box-sizing: border-box; display: inline-flex; align-items: center; padding: 0 14px; border: none; background: white; font: inherit; font-size: 16px; color: var(--textcolor); cursor: pointer; }
.trend-view + .trend-view { border-left: 2px solid #cccccc; }
.trend-view:hover { background: var(--tdhover); }
.trend-view-active, .trend-view-active:hover { background: #e9f1fb; color: var(--menucolor); font-weight: 600; }

/* ---- Trend widget: monthly line chart ---- */
.trend { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: 6px; overflow: auto; }
.trend-chart { flex: 1 1 auto; min-height: 140px; position: relative; overflow: hidden; }
/* Taken out of the flow so the chart's own size never decides the size of the box it is drawn in. */
.trend-svg { position: absolute; left: 0; top: 0; width: 100%; height: 100%; }
.trend-grid { stroke: #e6e9ec; stroke-width: 1; }
.trend-tick { fill: #6a737b; font-size: var(--font-min); }
.trend-year { fill: #8a9096; font-size: var(--font-min); }
.trend-line { fill: none; stroke-width: 2.5; stroke-linejoin: round; stroke-linecap: round; }
.trend-line-total, .trend-dot-total { stroke: var(--menucolor); }
.trend-line-total { stroke-width: 3; }
.trend-line-green, .trend-dot-green { stroke: var(--logo-green); }
.trend-line-orange, .trend-dot-orange { stroke: var(--logo-orange); }
.trend-line-red, .trend-dot-red { stroke: var(--logo-red); }
.trend-line-gray, .trend-dot-gray { stroke: #9aa4ae; }
.trend-dot { fill: white; stroke-width: 2.5; }
.trend-legend { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 4px 16px; font-size: var(--font-min); }
.trend-legend li { display: inline-flex; align-items: center; gap: 6px; cursor: default; }
.trend-key { display: inline-block; width: 18px; height: 0; border-top: 3px solid; border-radius: 2px; }
.trend-key-total { border-color: var(--menucolor); }
.trend-key-green { border-color: var(--logo-green); }
.trend-key-orange { border-color: var(--logo-orange); }
.trend-key-red { border-color: var(--logo-red); }
.trend-key-gray { border-color: #9aa4ae; }
.trend-caption { font-size: var(--font-min); color: #6a737b; }
.trend-empty { margin: 12px 0; }

/* A deleted script that was removed from the baseline: still listed on the test, tagged, its row muted. */
.tr-resolved-tag { display: inline-block; margin-left: 6px; padding: 1px 8px; border-radius: 10px; background: #eef0f2; color: #5a646d; font-size: var(--font-min); }
tr.data-tr-disabled .cell-wrap-anywhere { text-decoration: line-through; }

/* A suspected script whose change PCI Monitor or the partner marked unsafe: there is no Approve for it. */
.tr-unsafe-tag { display: inline-block; padding: 2px 10px; border-radius: 10px; background: #fbe3e7; color: var(--logo-red); font-size: 14px; font-weight: 500; cursor: default; }

/* Suggestions: the review window. */
/* Approved scripts: the decision cells (a link to the reason), the "needs a decision" tag and the menu count. */
.decision-link { text-align: left; }
.decision-meta { font-size: var(--font-min); color: #6a737b; }
.decision-overridden { opacity: 0.45; }
.decision-under { margin-top: 2px; font-size: var(--font-min); color: #8a9096; }
.decision-under .link-btn { font-size: var(--font-min); }
.tr-needs { display: inline-block; padding: 1px 8px; border-radius: 10px; background: #fff1de; color: #a85d00; font-size: var(--font-min); font-weight: 500; }
.nav-count { flex: none; min-width: 20px; padding: 0 6px; margin-left: 6px; border-radius: 10px; background: var(--logo-orange); color: white; font-size: var(--font-min); font-weight: 600; line-height: 20px; text-align: center; }
.suggestion-partner-choice { display: flex; align-items: center; gap: 10px; margin: 0 0 12px; }
.suggestion-partner-choice .select { width: auto; min-width: 280px; }
.suggestion-change { margin: 0 0 8px; }
.suggestion-heading { margin: 16px 0 6px; font-size: 16px; }
.suggestion-reasons { list-style: none; margin: 0 0 16px; padding: 0; max-height: 260px; overflow: auto; border-top: 1px solid #e2e5e8; }
.suggestion-reasons li { padding: 8px 0; border-bottom: 1px solid #e2e5e8; }
.suggestion-who { font-size: 14px; color: #6a737b; }
.suggestion-note { white-space: pre-wrap; overflow-wrap: anywhere; margin-top: 2px; }

/* The test window's tabs: Scripts | Page checks. Both tables fill the window the same way. */
.tr-tabs { display: flex; gap: 4px; margin: 10px 0 8px; border-bottom: 1px solid #d8dbde; }
.tr-tab { background: none; border: none; border-bottom: 3px solid transparent; padding: 8px 14px; font: inherit; font-weight: 500; color: var(--textcolor); cursor: pointer; margin-bottom: -1px; }
.tr-tab:hover { color: var(--menucolor); }
.tr-tab-active { color: var(--menucolor); border-bottom-color: var(--menucolor); }
.tr-tab-count { display: inline-block; min-width: 20px; padding: 0 6px; margin-left: 4px; border-radius: 10px; background: var(--logo-red); color: white; font-size: var(--font-min); font-weight: 600; line-height: 20px; text-align: center; }
.tr-tab-count[hidden] { display: none; }
.tr-modal > #checks-root { flex: 1 1 320px; min-height: 320px; display: flex; flex-direction: column; }
.tr-modal > [hidden] { display: none !important; }
.tr-failed { border-color: #e6b3bc; background: #fbeef0; }
.check-list { margin: 4px 0 8px; padding-left: 20px; }
.check-list li { margin: 2px 0; overflow-wrap: anywhere; }
.check-evidence { max-height: 260px; overflow: auto; margin: 4px 0 0; padding: 10px; background: #f4f6f8; border-radius: 6px; font-size: var(--font-min); white-space: pre-wrap; overflow-wrap: anywhere; }

/* The window that says why a test failed. */
.failure-note .failure-reason { font-size: 16px; font-weight: 500; margin: 6px 0 10px; overflow-wrap: anywhere; }

/* The top of a review window: what is being reviewed on the left, the ticket (or the Create ticket button) on the right. */
.review-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }
.review-head-main { flex: 1 1 auto; min-width: 0; }
.review-head-side { flex: none; text-align: right; }
/* The review window of a page-check finding: the finding scrolls, the "Change status to" form and the Close button stay in view. */
.check-review { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.check-review-scroll { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding-right: 6px; }
.check-review .script-change { flex: none; margin-top: 10px; }
.check-review .form-actions { flex: none; }

/* Above every page of a suspended company (read-only until it pays). */
.account-banner { margin: 0 0 14px; padding: 10px 14px; border: 1px solid var(--logo-orange, #ff8f2a); border-left-width: 6px; border-radius: 6px; background: #fff4e6; color: var(--textcolor); }
.account-banner a { margin-left: 8px; font-weight: 600; }

/* The one-line statement of what the product does and does not promise, under the call to action on the Features page. */
.marketing-note { margin: 18px auto 0; max-width: 720px; font-size: 16px; opacity: 0.85; }
.marketing-cta-section .marketing-note { margin: 15px auto 0; }   /* 15px below the button (the section's own p rule would otherwise win) */

/* ---- The free trial page (pages/free-trial.js) ---- */
.trial-section { padding-top: 20px; }
.trial-card { max-width: 760px; margin: 0 auto; background: white; border: var(--tableborder, 1px solid #a2a9b1); border-radius: var(--radius); border-top-left-radius: 0; border-bottom-right-radius: 0; padding: 28px 32px; text-align: center; }
.trial-card .marketing-cta { background: var(--menucolor); color: white; border: 0; cursor: pointer; }
.trial-card .marketing-cta:hover { filter: brightness(1.1); }
.trial-card .marketing-cta[disabled] { opacity: 0.6; cursor: default; }
.trial-label { display: block; text-align: left; font-weight: 600; margin-bottom: 6px; }
.trial-card .input { width: 100%; box-sizing: border-box; font-size: 16px; padding: 10px 12px; }
.trial-captcha { margin: 16px 0 6px; min-height: 0; display: flex; justify-content: center; }
.trial-card .form-error-banner { margin: 12px 0; text-align: left; }
.trial-card button.marketing-cta { margin-top: 14px; }
.trial-fine { font-size: 14px; opacity: 0.8; margin: 12px 0 0; }
.trial-closed { margin: 0; }
.trial-running h2, .trial-failed h2, .trial-result h2 { margin: 0 0 14px; font-size: 22px; color: #0d1b2a; }
.trial-bar { height: 8px; background: var(--tdhover); border-radius: 4px; overflow: hidden; margin: 18px 0; }
.trial-bar span { display: block; height: 100%; width: 35%; background: var(--menucolor); border-radius: 4px; animation: trial-slide 2.8s ease-in-out infinite; }
@keyframes trial-slide { 0% { margin-left: -35%; } 100% { margin-left: 100%; } }
.trial-kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(125px, 1fr)); gap: 12px; margin: 0 0 20px; }
.trial-kpi { background: var(--tdhover); border-radius: var(--radius); padding: 14px 10px; }
.trial-kpi-number { font-size: 34px; font-weight: 600; color: var(--menucolor); line-height: 1.1; }
.trial-kpi-label { font-weight: 600; margin-top: 2px; }
.trial-kpi-detail { font-size: 13px; opacity: 0.8; margin-top: 2px; }
.trial-result h3 { text-align: left; font-size: 17px; margin: 20px 0 8px; color: #0d1b2a; }
.trial-masked { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 8px; }
.trial-masked li { background: #f2f4f7; border: 1px solid #dde1e6; border-radius: 14px; padding: 3px 12px; font-family: monospace; font-size: 14px; }
.trial-cats { list-style: none; margin: 0; padding: 0; text-align: left; }
.trial-cats li { display: flex; align-items: center; gap: 12px; padding: 9px 4px; border-bottom: 1px solid #e3e6ea; }
.trial-cat-name { flex: 1; }
.trial-cat-count { display: flex; gap: 6px; }
.trial-sev { font-size: 13px; font-weight: 600; border-radius: 10px; padding: 2px 9px; }
.trial-sev-high { background: #fde4e1; color: #a1281c; }
.trial-sev-medium { background: #fff0d9; color: #8a5200; }
.trial-sev-low { background: #e6f0ff; color: #1f4f9b; }
.trial-locked { opacity: 0.55; }
.trial-cta { margin-top: 26px; padding-top: 6px; border-top: 1px solid #b4cdf5; }
.trial-cta h3 { text-align: center; }
.trial-cta p { max-width: 520px; margin: 0 auto 16px; }
.trial-link { display: block; margin: 14px auto 0; background: none; border: 0; color: var(--menucolor); cursor: pointer; font-size: 15px; text-decoration: underline; }
/* The page as the test's browser saw it (script-check.js), above the walk through the checks. */
.trial-picture { margin: 0 0 16px; text-align: left; }
.trial-picture img { display: block; width: 100%; height: auto; border: 1px solid #a2a9b1; border-radius: 8px 2px 8px 2px; background: #ffffff; }
.trial-picture figcaption { margin-top: 6px; font-size: 14px; line-height: 1.45; opacity: 0.85; }
.trial-walk { margin: 4px 0 6px; padding: 12px 6px 4px; text-align: left; }
.trial-scripts { text-align: left; border: 1px solid #dde1e6; border-radius: var(--radius); background: #fafbfc; padding: 4px 0; }
.trial-script-row { display: flex; align-items: center; gap: 12px; padding: 6px 12px; border-bottom: 1px solid #eceff2; animation: trial-line-in 0.25s ease-out; }
.trial-script-row:last-child { border-bottom: 0; }
.trial-script-name { flex: 1 1 auto; min-width: 0; font-family: Consolas, 'Courier New', monospace; font-size: 14px; overflow-wrap: anywhere; color: #1b2a3a; }
.trial-script-tags { flex: none; font-size: 13px; opacity: 0.75; }
.trial-risk { flex: none; min-width: 64px; text-align: center; font-size: 13px; font-weight: 600; border-radius: 10px; padding: 2px 10px; }
.trial-risk-low { background: #e4f3e8; color: #1f6b3a; }
.trial-risk-medium { background: #fff0d9; color: #8a5200; }
.trial-boxes-in { animation: trial-line-in 0.5s ease-out; }
@keyframes trial-line-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
@media (max-width: 640px) { .trial-script-row { flex-wrap: wrap; } .trial-script-tags { order: 3; flex-basis: 100%; } }
@media (prefers-reduced-motion: reduce) { .trial-script-row, .trial-boxes-in, .trial-bar span { animation: none; } }
.trial-risk-high { background: #fde4e1; color: #a1281c; }
.trial-check-name { flex: 1 1 auto; min-width: 0; font-size: 15px; overflow-wrap: anywhere; color: #1b2a3a; }
.trial-callout { margin: 22px 0 0; padding: 16px 20px; text-align: left; background: var(--tdhover); border: 1px solid #b4cdf5; border-left: 6px solid var(--menucolor); border-radius: var(--radius); }
.trial-callout strong { display: block; font-size: 18px; color: var(--menucolor); margin-bottom: 6px; }
.trial-callout p { margin: 0; font-size: 16px; line-height: 1.5; }

/* ---- Billing report (pages/billing-report.js) ---- */
.billing-report-domain { font-size: 13px; opacity: 0.7; margin-left: 6px; }
/* A second line in a table cell: a payment note under "Paid on ...", the partner and account under a client, the date under a status. */
.cell-note { display: block; font-size: 15px; opacity: 0.7; }
.billing-report-status { font-weight: 600; }
.billing-report-paid { color: #1f6b3a; }
.billing-report-open, .billing-report-not_invoiced { color: #8a5200; }
.billing-report-failed { color: #a1281c; }
.billing-report-zero { opacity: 0.65; font-weight: 400; }


/* ---- Invoices (pages/invoices.js) ---- */
.invoice-lines { width: 100%; border-collapse: collapse; margin: 6px 0 12px; }
.invoice-lines th, .invoice-lines td { padding: 6px 8px; border-bottom: 1px solid #e3e6ea; text-align: left; }
.invoice-lines th.num, .invoice-lines td.num { text-align: right; white-space: nowrap; }
.invoice-lines tfoot td { border-bottom: 0; }
.invoice-totals { margin-top: 8px; }
.invoice-totals td { border-bottom: 0; }

/* ---- Commissions (pages/commissions.js) ---- */
.commission-owed-title { font-size: 18px; margin: 18px 0 6px; }
.commission-owed { max-width: 760px; margin-bottom: 18px; }
.payout-account { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin: 10px 0 12px; padding: 14px 18px; background: white; border: 1px solid #b4cdf5; border-left: 6px solid var(--menucolor); border-radius: var(--radius); }
/* Stripe's own colour (their blurple) for what is Stripe's: the payout account card and the buttons that go to Stripe. */
.payout-account, .payout-account-ready, .payout-account-none, .payout-account-pending { border-left-color: #635bff; }
#app-root .buttonOK.buttonStripe { background: #635bff; border-color: #635bff; color: #fff; }
#app-root .buttonOK.buttonStripe:hover:not(:disabled) { background: #5249e6; border-color: #5249e6; }
#app-root .buttonOK.buttonStripe:disabled { opacity: 0.6; }
.payout-account-actions { display: flex; gap: 8px; }
.commission-pay-off { opacity: 0.4; cursor: not-allowed; font-weight: 600; }
.invoice-details .invoice-lines thead th { position: sticky; top: 0; background: white; box-shadow: 0 1px 0 #e3e6ea; }
.invoice-footer { flex: none; padding-top: 8px; border-top: 2px solid #aaaaaa; }
.invoice-footer .invoice-totals { margin: 0 0 6px; }
.invoice-footer p { margin: 4px 0; }

.invoice-history { margin-top: 4px; }
.invoice-history td { vertical-align: top; padding: 4px 8px 4px 0; }
.invoice-history .nowrap { white-space: nowrap; color: #5f6b76; }

.end-partnership-clients { max-height: 140px; overflow-y: auto; margin: 4px 0 12px; padding-left: 20px; }

.marketing-footer-full { flex-direction: column; align-items: center; gap: 10px; }
.marketing-footer-links { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px 24px; font-weight: 600; }
.public-text-section { max-width: 760px; margin: 0 auto; text-align: left; }
.site-map-list { list-style: none; margin: 0; padding: 0; line-height: 2.1; }

/* The privacy policy: headings, contents list and tables, in the window and on the page of its own. */
.public-text h2, .contract-terms-text h2 { font-size: 18px; margin: 22px 0 6px; scroll-margin-top: 4px; }
.public-text ul, .public-text ol { margin: 6px 0 10px; padding-left: 22px; }
.public-text li { margin: 4px 0; }
/* The screenshots on the Email and text messages page (content/messaging-policy.js): the picture, then what it shows. */
.consent-proof { margin: 14px 0 18px; }
.consent-proof img { display: block; width: 100%; height: auto; border: 1px solid #a2a9b1; border-radius: 6px; }
.consent-proof figcaption { margin-top: 6px; font-size: 14px; line-height: 1.45; }
.privacy-updated { color: #5f6b76; margin-top: 0; }
.privacy-toc { margin: 10px 0 4px; padding: 10px 14px; background: #f4f4f3; border-radius: 6px; }
.privacy-toc ol { list-style: none; margin: 0; padding: 0; columns: 2; column-gap: 24px; }
.privacy-toc li { margin: 3px 0; break-inside: avoid; }
.privacy-table { width: 100%; border-collapse: collapse; margin: 8px 0 14px; font-size: 15px; }
.privacy-table th, .privacy-table td { border: 1px solid #d8dbde; padding: 6px 10px; text-align: left; vertical-align: top; }
.privacy-table th { background: #f4f4f3; font-weight: 600; }
@media (max-width: 640px) { .privacy-toc ol { columns: 1; } }

.privacy-table { table-layout: fixed; }
.privacy-table th, .privacy-table td { overflow-wrap: anywhere; }
.contract-terms-text { overflow-x: hidden; }

/* The Contact us form inside a window: the labels and fields as the page has them. */
.modal-body .trial-label { display: block; font-weight: 600; margin-bottom: 6px; text-align: left; }
.modal-body .contract-terms-window .input { width: 100%; box-sizing: border-box; }
.modal-body .trial-captcha { margin: 8px 0; }

.register-terms { margin: 4px 0 14px; }
.public-window-hint { margin: 0 auto 0 0; align-self: center; }

/* Scrolling stays inside the window in front: no scroll area in a window hands the wheel on to what is behind it when it reaches its end. */
.modal-overlay, .modal-overlay * { overscroll-behavior: contain; }

/* A table cell whose text is a link (a column with `link`): the app's link blue, underlined on hover, in the cell's own font. */
.app-body a.cell-link, a.cell-link { color: var(--menucolor); text-decoration: none; font: inherit; }
.app-body a.cell-link:hover, a.cell-link:hover { text-decoration: underline; }

.report-view { max-width: none; }
.report-view .field-group > label { font-weight: 600; }
.report-view-value { padding: 2px 0 4px; overflow-wrap: anywhere; }

/* The View window of a report: its data listed the way the PDF is laid out. */
.report-view-scroll h3 { margin: 18px 0 6px; font-size: 20px; }
.report-view-scroll h4 { margin: 14px 0 4px; font-size: 17px; }
.report-view-scroll h5 { margin: 10px 0 4px; font-size: 15px; font-weight: 600; color: #3d5a80; }
.report-view-scroll section:first-of-type h3 { margin-top: 4px; }
.tr-report-mark { color: var(--documentblue); }
/* the icon and the word, with a space between them (the link, when there is one, holds both) */
.tr-report-mark, .tr-report-mark a { display: inline-flex; align-items: center; gap: 6px; }
/* A button with the hidden attribute is hidden, whatever display its own class gives it (the Send button still showed after the Contact us message went). */
button[hidden], a.buttonOK[hidden], a.buttonClose[hidden] { display: none !important; }
/* The client's script consent: the state, the signature, the document, the form. The mark before the menu title is a check (consented) or an X. */
/* The Consents page is a window with a border, like Company Settings: a card the width of the page content, not the 400px of a sign-in card. */
.consents-card { max-width: 1000px; margin: 16px 0; padding: 0 24px; overflow: hidden; display: flex; flex-direction: column; }
.consents-card #consent-page { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.consents-card .report-tabs { flex: none; }
.consent-lang { margin-left: auto; align-self: center; display: inline-flex; align-items: center; gap: 8px; font-size: 14px; }
.consent-lang select { width: auto; padding: 2px 8px; }
.consent-panels { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding-bottom: 24px; }   /* what scrolls: everything under the tab headers */
.consents-card > p:first-child { margin-top: 20px; }   /* (no top padding: the tabs stick flush to the top edge of the card) */
.consent-mark { display: inline-block; min-width: 1.1em; margin-right: 4px; font-weight: 700; }
.consent-marks { display: inline-flex; gap: 1px; margin-right: 4px; }
.consent-marks .consent-mark { min-width: 0; margin-right: 0; }
.consent-mark-on { color: #1d7a3a; }
.consent-mark-off { color: #b32d2e; }
.consent-mark-mixed { color: #e08a1e; }
.consent-mark-icon { display: inline-flex; align-items: center; margin-left: 3px; }

.review-consent-line { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; }
.review-consent-state { border-width: 2px; }
.review-consent-state p { margin: 0 0 6px; }
.review-consent-state-on { background: #eaf6ee; border-color: #6bab84; }
.review-consent-state-off { background: #fdeeee; border-color: #d98a8a; }
.review-consent-facts { display: grid; grid-template-columns: max-content 1fr; gap: 4px 16px; margin: 8px 0 12px; }
.review-consent-facts dt { color: #6a737b; }
.review-consent-facts dd { margin: 0; }
.review-consent-signature { font-family: "Brush Script MT", "Segoe Script", cursive; font-size: 24px; }
.review-consent-document { border: 1px solid #c9d1d9; border-radius: 6px; padding: 8px 20px 12px; margin: 14px 0; background: #fff; max-width: 920px; }
.review-consent-doc-title { margin: 12px 0 8px; font-size: 22px; }
.review-consent-sign { border-top: 1px solid #c9d1d9; padding-top: 10px; max-width: 920px; }
.review-consent-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 0 16px; }
.review-consent-note { background: #fff6e5; border-color: #e0a23a; }
.report-tabs { display: flex; flex-wrap: wrap; gap: 0 4px; margin-bottom: 10px; border-bottom: 1px solid #c9d1d9; position: sticky; top: 0; background: white; z-index: 60; }
.report-tabs button { appearance: none; background: none; border: 0; border-bottom: 3px solid transparent; margin-bottom: -1px; padding: 9px 14px 8px; font: inherit; color: #53676c; cursor: pointer; border-radius: 4px 4px 0 0; }
.report-tabs button:hover { background: #eef3f8; color: var(--documentblue); }
.report-tabs button[aria-selected="true"] { color: var(--documentblue); border-bottom-color: var(--documentblue); font-weight: 600; }
.report-tabs button:focus-visible { outline: 2px solid var(--documentblue); outline-offset: -2px; }
.report-sub { margin: 0 0 8px; color: #3d5a80; font-size: 18px; }
.report-meta { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 8px 16px; margin: 8px 0; }
.report-meta-item .k { display: block; font-size: 13px; letter-spacing: .04em; text-transform: uppercase; color: #6a737b; }
.report-box { border: 1px solid #b8c2cc; padding: 8px 10px; margin: 8px 0; }
.report-box p { margin: 0 0 4px; }
.report-verdict { padding: 10px 14px; margin: 10px 0; font-weight: 600; }
.report-verdict-pass { background: #e6f4ea; color: #1e5e22; }
.report-verdict-attention { background: #fde8ec; color: #a3243b; }
.report-note, .report-ok { color: #3b5f8f; }
.report-view-error { color: #c8324b; margin-top: 4px; }
.report-finding { border: 1px solid #e3e6e9; border-left: 4px solid #3d5a80; padding: 6px 10px; margin: 6px 0; }
.report-finding-high { border-left-color: #c8324b; }
.report-finding-medium { border-left-color: #ef6c00; }
.report-pill { display: inline-block; padding: 1px 8px; border-radius: 10px; font-size: 14px; font-weight: 600; background: #eceff1; color: #6a737b; }
.report-pill-high, .report-pill-needs_review, .report-pill-suspected { background: #fde8ec; color: #c8324b; }
.report-pill-medium, .report-pill-approved { background: #fff1e0; color: #ef6c00; }
.report-pill-low { background: #e9eff6; color: #3d5a80; }
.report-pill-pass, .report-pill-unchanged { background: #e6f4ea; color: #2e7d32; }
.report-count { display: inline-block; margin-right: 12px; background: none !important; padding: 0; }
.report-count.report-pill-pass, .report-count.report-pill-unchanged { color: #2e7d32; }
.report-count.report-pill-approved { color: #ef6c00; }
.report-count.report-pill-needs_review, .report-count.report-pill-suspected { color: #c8324b; }
.report-count.report-pill-not_tested, .report-count.report-pill-deleted { color: #6a737b; }
.report-table { width: 100%; border-collapse: collapse; margin: 6px 0 12px; font-size: 15px; table-layout: auto; }
.report-table th, .report-table td { border: 1px solid #e3e6e9; padding: 5px 8px; text-align: left; vertical-align: top; overflow-wrap: anywhere; }
.report-table th { background: #f4f4f3; font-weight: 600; }
.report-table tbody tr:nth-child(even) { background: #fafbfc; }

/* A column of a report table whose text stays on one line (a type, a severity). */
.report-table .report-nowrap { white-space: nowrap; overflow-wrap: normal; width: 1%; }
/* The tables' own headings (the app's tables stick to the top of a scroll area, above everything: styles.css) stick right under the menu and never over it. */
.report-table thead th { top: var(--jump-h, 34px); z-index: 10; }
/* One line, shortened with an ellipsis (the whole text is the cell's title): a very long address would otherwise make the table thousands of pixels wide. */
.report-table .report-ellipsis { max-width: 420px; overflow: hidden; text-overflow: ellipsis; width: auto; }
/* A long script address in a finding wraps inside the window instead of running out of it. */
.report-finding, .report-finding * { overflow-wrap: anywhere; min-width: 0; }


/* ---- The home page: the section navigation at the top left (home-nav.js), and the logos of the Partners, Clients and Integrations sections ---- */
.public-page [data-nav] { scroll-margin-top: 12px; }
.home-nav {
    position: fixed; left: 14px; top: 50%; transform: translateY(-50%); z-index: 40;   /* vertically centred, so it stays out of the way of the headings and the top of the sections */
    display: flex; flex-direction: column; gap: 2px; padding: 8px 6px; box-sizing: border-box; width: max-content;   /* as wide as the longest label in the language shown, and fixed: choosing an item never changes the size of the menu */
    background: rgba(255, 255, 255, 0.94); border: var(--tableborder, 1px solid #a2a9b1);
    border-radius: var(--radius); border-top-left-radius: 0; border-bottom-right-radius: 0;
    box-shadow: 0 4px 14px rgba(13, 27, 42, 0.14);
}
.home-nav[hidden] { display: none; }
.home-nav a { display: flex; align-items: center; gap: 9px; padding: 5px 10px 5px 6px; color: var(--textcolor); font-size: 15px; font-weight: 400; line-height: 1.3; text-decoration: none; border-radius: 6px; white-space: nowrap; }
.home-nav a:hover { background: #eef3f8; color: var(--documentblue, #1959b8); }
.home-nav a:focus-visible { outline: 2px solid var(--documentblue, #1959b8); outline-offset: 1px; }
.home-nav-label { display: inline-flex; flex-direction: column; }
/* a hidden copy of the label in the selected weight keeps its room, so the selected item never makes the menu wider */
.home-nav-label::after { content: attr(data-text); font-weight: 500; height: 0; overflow: hidden; visibility: hidden; }
.home-nav-dot { flex: none; width: 9px; height: 9px; border: 2px solid #8a98a6; border-radius: 50%; background: transparent; }
.home-nav a.home-nav-active { font-weight: 500; color: #0d1b2a; }
.home-nav a.home-nav-active .home-nav-dot { background: var(--logo-green, #4f9d6c); border-color: var(--logo-green, #4f9d6c); }
/* On a window too narrow to leave the page its margin, only the dots show, and the words come out when the pointer or the keyboard is on the list. */
@media (max-width: 1500px) {
    .home-nav { padding: 8px 4px; width: auto; }
    .home-nav .home-nav-label { display: none; }
    .home-nav:hover .home-nav-label, .home-nav:focus-within .home-nav-label { display: inline-flex; }
    .home-nav:hover, .home-nav:focus-within { width: max-content; padding: 8px 6px; }
}
/* Not on a small screen. */
@media (max-width: 760px) { .home-nav { display: none; } }
@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }

/* The consent for text messages under the mobile number field (pages/profile-mfa.js): ordinary text at a readable size and colour, not the faint grey hint. */
.sms-consent {
    margin: 8px 0 6px;
    font-size: 15px;
    line-height: 1.45;
    color: #1d2530;
}
/* The line under it: what happens next, and after "Send code" a green confirmation that the code was sent. */
.sms-status { margin: 6px 0; font-size: 15px; line-height: 1.45; color: #1d2530; }
.sms-status.sent { padding: 10px 12px; font-weight: 600; color: #3f7f5b; background: #ffffff; border: 2px solid #6bab84; border-radius: 8px; }

/* ---- The Trust Center (pages/trust.js) ---- */
.trust-table td:first-child { font-weight: 600; white-space: nowrap; }
/* The security measures: one table, a heading row for each area, then a row per measure (a short name and what it does). */
.trust-measures-table .trust-group-row th { background: var(--thbackground); font-size: 16px; padding-top: 14px; }
.trust-measures-table td:first-child { width: 28%; white-space: normal; }
.trust-note { max-width: 760px; margin: 14px auto 0; text-align: center; font-size: 15px; line-height: 1.5; opacity: 0.85; }
.trust-disclaimer { font-size: 14px; }
.trust-doc-list { list-style: none; max-width: 760px; margin: 0 auto 22px; padding: 0; }
.trust-doc-list li { padding: 10px 0; border-bottom: 1px solid #d5dbe1; line-height: 1.5; }
.trust-doc-list li span { display: block; opacity: 0.8; font-size: 15px; }
@media (max-width: 700px) { .trust-table td:first-child { white-space: normal; } }

.showcase-grid { display: flex; flex-wrap: wrap; justify-content: center; gap: 16px; max-width: 1000px; margin: 0 auto; }
.showcase-item {
    display: flex; align-items: center; justify-content: center; min-width: 150px; max-width: 220px; height: 72px; padding: 8px 18px;
    background: white; border: var(--tableborder, 1px solid #a2a9b1); border-radius: var(--radius); border-top-left-radius: 0; border-bottom-right-radius: 0;
    color: #0d1b2a; text-decoration: none; text-align: center;
}
a.showcase-item:hover { border-color: var(--documentblue, #1959b8); box-shadow: 0 2px 8px rgba(13, 27, 42, 0.14); }
.showcase-item img { max-width: 100%; max-height: 52px; object-fit: contain; }
.showcase-name { font-size: 19px; font-weight: 700; line-height: 1.25; overflow-wrap: anywhere; }

/* ---- How a company is shown on the public pages (Company Settings, and PCI Monitor's review window) ---- */
.public-listing-status { margin: 4px 0 0; padding: 8px 12px; border-left: 4px solid #9aa4ae; background: #f3f5f6; border-radius: 0 6px 6px 0; }
.public-listing-status-none, .public-listing-status-approved { border-left-color: var(--logo-green, #4f9d6c); background: #eef7f1; }
.public-listing-status-pending { border-left-color: #e5a100; background: #fff7e0; }
.public-listing-status-declined { border-left-color: #c0392b; background: #fdecea; }

/* the integrators' list: a small picture of the logo before the name */
.integrator-thumb { display: block; max-width: 96px; max-height: 32px; object-fit: contain; }

/* A logo as it will look on the home page: the same card, in the settings, the review window and the integrators' form, and small in the lists. */
.showcase-preview { display: inline-flex; margin: 4px 0; }
.showcase-item-small { min-width: 96px; max-width: 150px; height: 44px; padding: 4px 10px; }
.showcase-item-small img { max-height: 30px; }
.showcase-item-small .showcase-name { font-size: 13px; }

/* A logo with a caption under it (none by default: many logos already say the name; or the company's name; or a text of its own): the card grows to hold it. */
.showcase-item-captioned { flex-direction: column; gap: 4px; height: auto; min-height: 72px; padding: 8px 18px 6px; }
.showcase-item-captioned img { max-height: 44px; }
.showcase-caption { font-size: 15px; font-weight: 500; line-height: 1.2; color: #44525e; overflow-wrap: anywhere; }
.showcase-item-small.showcase-item-captioned { height: auto; min-height: 44px; padding: 4px 10px; }
.showcase-item-small .showcase-caption { font-size: 13px; }

/* The cookie and analytics banner (public/js/consent.js): a bar at the bottom of the public pages, shown only when analytics is switched on and the visitor has not chosen yet. */
.consent-bar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 3000;
    display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 12px 24px;
    padding: 14px 20px;
    background: #ffffff; color: #1d2530;
    border-top: 2px solid #4470af; box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.12);
    font-size: 15px; line-height: 1.45;
}
.consent-bar p { margin: 0; max-width: 760px; }
.consent-bar a { color: #4470af; font-weight: 600; text-decoration: underline; }
.consent-buttons { display: flex; gap: 10px; flex: 0 0 auto; }
.consent-buttons button {
    min-width: 96px; padding: 9px 18px; font: inherit; font-weight: 600; cursor: pointer;
    border: 2px solid #4470af; border-radius: 10px 2px 10px 2px;
}
.consent-accept { background: #4470af; color: #ffffff; }
.consent-decline { background: #ffffff; color: #4470af; }
.consent-buttons button:focus-visible { outline: 3px solid #6bab84; outline-offset: 2px; }
@media (max-width: 640px) { .consent-bar { padding: 12px 16px; } .consent-buttons { width: 100%; } .consent-buttons button { flex: 1; } }
