/*
 * Bush Telegraph application styles.
 *
 * The brand palette is unchanged. The surface treatment -- shadows, radii,
 * hairline borders, type scale -- follows the NiceDash dashboard design:
 * soft diffuse shadows instead of hard drops, near-invisible borders, and a
 * light airy ground. NiceDash's own colour is Angular Material's stock azure
 * palette, which is deliberately NOT adopted; the green/terracotta/wheat
 * identity stays.
 */

/*
 * Inter, self-hosted.
 *
 * body has named 'Inter' since the stylesheet was written, but nothing ever
 * loaded it, so the system stack was silently what rendered. These are the
 * variable builds (weight axis 100-900), which matters here: the rules below
 * use 550 and 650, and a static face would round both to the nearest 100.
 *
 * Served from webroot/font/, not a font CDN -- no third-party request on any
 * page load. unicode-range means a browser fetches only the subsets a page
 * actually needs; for English that is inter-var-latin.woff2 alone, 48 KB.
 *
 * SIL Open Font License 1.1 -- see webroot/font/Inter-License.txt
 */
/* cyrillic-ext */
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('../font/inter-var-cyrillic-ext.woff2') format('woff2');
    unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('../font/inter-var-cyrillic.woff2') format('woff2');
    unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('../font/inter-var-greek-ext.woff2') format('woff2');
    unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('../font/inter-var-greek.woff2') format('woff2');
    unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}
/* vietnamese */
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('../font/inter-var-vietnamese.woff2') format('woff2');
    unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('../font/inter-var-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('../font/inter-var-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
    /* Brand -- unchanged */
    --bt-primary: #1F5E4B;
    --bt-primary-dark: #174a3b;
    --bt-primary-light: #2a7d65;
    --bt-secondary: #E8D8B5;
    --bt-secondary-dark: #d4c49e;
    --bt-accent: #C85A2E;
    --bt-accent-light: #e06a38;
    --bt-text: #2E2E2E;
    --bt-text-muted: #6c757d;

    /* Surface + form -- adopted from NiceDash, warmed to suit the palette */
    --bt-bg: #F8F6F1;
    --bt-surface: #ffffff;
    --bt-border: #e8e3da;
    --bt-border-strong: #ddd6c9;
    --bt-radius-sm: 0.5rem;
    --bt-radius: 0.875rem;
    --bt-radius-lg: 1.25rem;
    --bt-shadow-xs: rgba(145, 158, 171, 0.16) 0 0 2px 0, rgba(145, 158, 171, 0.06) 0 4px 8px -2px;
    --bt-shadow-sm: rgba(145, 158, 171, 0.2) 0 0 2px 0, rgba(145, 158, 171, 0.08) 0 8px 16px -4px;
    --bt-shadow: rgba(145, 158, 171, 0.3) 0 0 2px 0, rgba(145, 158, 171, 0.12) 0 12px 24px -4px;
    --bt-shadow-lg: rgba(145, 158, 171, 0.3) 0 0 2px 0, rgba(145, 158, 171, 0.18) 0 16px 32px -4px;

    /* Field metrics + the focus halo, so every control rings identically */
    --bt-field-h: 2.5rem;
    --bt-border-hover: #cfc7b6;
    --bt-ring: 0 0 0 3px rgba(31, 94, 75, 0.15);
    --bt-ring-danger: 0 0 0 3px rgba(192, 57, 43, 0.15);
    --bt-row-hover: rgba(31, 94, 75, 0.05);

    /* Status tints. These six pairs were already spelt out literally in the
       badge block below; naming them lets the badges, the contextual alerts
       and the validation states share one set instead of drifting apart. */
    --bt-danger: #c0392b;
    --bt-tint-neutral: #eceef0;  --bt-tint-neutral-fg: #4a5056;
    --bt-tint-info: #d9f3fa;     --bt-tint-info-fg: #0a6b80;
    --bt-tint-warn: #fdf2d0;     --bt-tint-warn-fg: #7a5a00;
    --bt-tint-success: #d9f0e3;  --bt-tint-success-fg: #10603c;
    --bt-tint-accent: #fde6d5;   --bt-tint-accent-fg: #8a3d0c;
    --bt-tint-danger: #fadadd;   --bt-tint-danger-fg: #8b1c28;

    /* DataTables 1.13 reads these to tint row hover, selection and its
       loading spinner. Left at its defaults they are neutral black. */
    --dt-row-hover: 31, 94, 75;
    --dt-row-selected: 31, 94, 75;
    --dt-row-selected-text: 255, 255, 255;
}

/* Global */
body {
    background-color: var(--bt-bg);
    color: var(--bt-text);
    /* 'Inter' is named but never loaded -- no @font-face and no stylesheet link --
       so the system stack below is what actually renders. Kept honest rather than
       pulling a webfont off a CDN. */
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    font-size: 0.875rem;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}
a { color: var(--bt-primary); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--bt-primary-dark); }
h1, h2, h3, h4, h5, h6 { font-weight: 650; letter-spacing: -0.01em; color: var(--bt-text); }
h2 { font-size: 1.5rem; }
h5 { font-size: 1rem; }
hr { border-color: var(--bt-border); opacity: 1; }
.text-muted { color: var(--bt-text-muted) !important; }

/* Buttons */
.btn { border-radius: var(--bt-radius-sm); font-weight: 550; font-size: 0.875rem; padding: 0.5rem 1rem; transition: background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease, color 0.15s ease; }
.btn-sm { border-radius: 0.4rem; padding: 0.3rem 0.7rem; font-size: 0.8125rem; }
.btn-lg { border-radius: var(--bt-radius); font-size: 1rem; padding: 0.7rem 1.4rem; }
.btn:focus, .btn:focus-visible { box-shadow: 0 0 0 3px rgba(31, 94, 75, 0.15); outline: none; }
.btn-primary { background-color: var(--bt-primary); border-color: var(--bt-primary); }
.btn-primary:hover, .btn-primary:focus { background-color: var(--bt-primary-dark); border-color: var(--bt-primary-dark); }
.btn-primary:active { background-color: var(--bt-primary-dark) !important; border-color: var(--bt-primary-dark) !important; }
.btn-outline-primary { color: var(--bt-primary); border-color: var(--bt-border-strong); }
.btn-outline-primary:hover { background-color: var(--bt-primary); border-color: var(--bt-primary); }
.btn-accent { background-color: var(--bt-accent); border-color: var(--bt-accent); color: #fff; }
.btn-accent:hover { background-color: var(--bt-accent-light); border-color: var(--bt-accent-light); color: #fff; }

/* Form controls */
.form-control, .form-select {
    border-radius: var(--bt-radius-sm);
    border-color: var(--bt-border-strong);
    font-size: 0.875rem;
    padding: 0.5rem 0.75rem;
    background-color: var(--bt-surface);
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.form-control:focus, .form-select:focus {
    border-color: var(--bt-primary-light);
    box-shadow: 0 0 0 3px rgba(31, 94, 75, 0.12);
}
.form-control::placeholder { color: #adb5bd; }
.form-label { font-size: 0.8125rem; font-weight: 600; color: var(--bt-text); margin-bottom: 0.35rem; }
.input-group-text { background-color: var(--bt-bg); border-color: var(--bt-border-strong); border-radius: var(--bt-radius-sm); font-size: 0.875rem; }
.form-check-input:checked { background-color: var(--bt-primary); border-color: var(--bt-primary); }
.form-check-input:focus { box-shadow: 0 0 0 3px rgba(31, 94, 75, 0.12); border-color: var(--bt-primary-light); }
.form-check-input { border-color: var(--bt-border-strong); }
.form-check-label { font-size: 0.875rem; }
.form-switch .form-check-input { width: 2.25rem; height: 1.15rem; background-color: #d8d2c6; border: none; }
/* The switch is wider than Bootstrap's, so its gutter has to grow with it or
   the label sits hard against the toggle. */
.form-switch { padding-left: 3rem; }
.form-switch .form-check-input { margin-left: -3rem; }
.form-switch .form-check-label { padding-left: .1rem; }
.form-switch .form-check-input:checked { background-color: var(--bt-primary); }
.form-text { font-size: 0.8125rem; color: var(--bt-text-muted); }
textarea.form-control { min-height: 6rem; line-height: 1.6; }
.form-control-sm, .form-select-sm { font-size: 0.8125rem; padding: 0.3rem 0.6rem; border-radius: 0.4rem; }
.form-control-lg, .form-select-lg { font-size: 1rem; padding: 0.65rem 0.9rem; border-radius: var(--bt-radius); }
.form-control[type="file"]::file-selector-button {
    background: var(--bt-bg); border: 0; border-right: 1px solid var(--bt-border-strong);
    color: var(--bt-text); font-weight: 550; padding: 0.5rem 0.85rem; margin: -0.5rem 0.75rem -0.5rem -0.75rem;
    transition: background-color 0.15s ease;
}
.form-control[type="file"]::file-selector-button:hover { background: var(--bt-secondary); }
.form-control[type="color"] { padding: 0.25rem; width: 3.5rem; }
.form-range::-webkit-slider-thumb { background: var(--bt-primary); }
.form-range::-moz-range-thumb { background: var(--bt-primary); border: none; }
.form-range:focus::-webkit-slider-thumb { box-shadow: 0 0 0 3px rgba(31, 94, 75, 0.18); }

/* Validation */
.form-control.is-invalid, .form-select.is-invalid { border-color: #c0392b; background-image: none; }
.form-control.is-invalid:focus, .form-select.is-invalid:focus { box-shadow: 0 0 0 3px rgba(192, 57, 43, 0.12); }
.form-control.is-valid, .form-select.is-valid { border-color: var(--bt-primary-light); background-image: none; }
.form-control.is-valid:focus, .form-select.is-valid:focus { box-shadow: 0 0 0 3px rgba(31, 94, 75, 0.12); }
.invalid-feedback { font-size: 0.8125rem; color: #c0392b; }
.valid-feedback { font-size: 0.8125rem; color: var(--bt-primary); }
/* CakePHP FormHelper marks failed fields with .error rather than Bootstrap's .is-invalid */
.input.error .form-control, .input.error input, .input.error select, .input.error textarea { border-color: #c0392b; }
.error-message { font-size: 0.8125rem; color: #c0392b; margin-top: 0.25rem; }

/* Button + input groups */
.btn-group > .btn { border-radius: var(--bt-radius-sm); }
.btn-group > .btn:not(:last-child) { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.btn-group > .btn:not(:first-child) { border-top-left-radius: 0; border-bottom-left-radius: 0; }
.input-group > .form-control:not(:last-child), .input-group > .form-select:not(:last-child) { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.input-group > .form-control:not(:first-child), .input-group > .form-select:not(:first-child) { border-top-left-radius: 0; border-bottom-left-radius: 0; }

/* Pagination, accordion, spinners */
.pagination { --bs-pagination-border-radius: var(--bt-radius-sm); font-size: 0.875rem; }
.page-link { color: var(--bt-primary); border-color: var(--bt-border); }
.page-link:hover { background-color: rgba(31, 94, 75, 0.08); color: var(--bt-primary-dark); border-color: var(--bt-border-strong); }
.page-item.active .page-link { background-color: var(--bt-primary); border-color: var(--bt-primary); }
.page-item.disabled .page-link { color: var(--bt-text-muted); }
.accordion { --bs-accordion-border-color: var(--bt-border); --bs-accordion-border-radius: var(--bt-radius); }
.accordion-button { font-size: 0.875rem; font-weight: 600; background: transparent; }
.accordion-button:not(.collapsed) { background-color: rgba(31, 94, 75, 0.06); color: var(--bt-primary); box-shadow: none; }
.accordion-button:focus { box-shadow: 0 0 0 3px rgba(31, 94, 75, 0.12); border-color: transparent; }
.spinner-border, .spinner-grow { color: var(--bt-primary); }
.tooltip-inner { background: #2E2E2E; border-radius: var(--bt-radius-sm); font-size: 0.8125rem; padding: 0.4rem 0.65rem; }

/* Main Content */
.main-content {
    margin-left: 0;
    min-height: 100vh;
}
.page-shell { max-width: 1600px; margin: 0 auto; }


/* ── Horizontal primary navigation ────────────────────────────────────────
   Replaces the fixed vertical sidebar. One bar: brand, destinations, and the
   account menu at the right end. The second "topbar" that used to repeat the
   page title under it is gone; the page header carries the title once.
   ──────────────────────────────────────────────────────────────────────── */
.mainnav {
    background: linear-gradient(180deg, var(--bt-primary) 0%, var(--bt-primary-dark) 100%);
    position: sticky; top: 0; z-index: 1040;
}
.mainnav-inner {
    max-width: 1600px; margin: 0 auto;
    padding: 0 1.5rem;
    display: flex; align-items: center; gap: 1.5rem;
    min-height: 58px;
}
.mainnav-brand { display: flex; align-items: center; flex: none; padding: .5rem 0; }
.mainnav-brand img { height: 30px; width: auto; }
.mainnav-toggle {
    background: none; border: 0; color: #fff;
    font-size: 1.35rem; line-height: 1; padding: .25rem .5rem;
    border-radius: var(--bt-radius-sm); cursor: pointer;
}
.mainnav-toggle:focus-visible { outline: 2px solid rgba(255,255,255,.6); outline-offset: 2px; }
.mainnav-list {
    list-style: none; margin: 0; padding: 0;
    display: flex; align-items: center; gap: .125rem; flex-wrap: wrap;
}
.mainnav-link {
    display: flex; align-items: center; gap: .5rem;
    padding: .5rem .8rem; border-radius: var(--bt-radius-sm);
    color: rgba(255,255,255,.78); font-size: .875rem; font-weight: 500;
    text-decoration: none; white-space: nowrap;
    transition: background-color .15s ease, color .15s ease;
}
.mainnav-link:hover { color: #fff; background: rgba(255,255,255,.1); }
.mainnav-link.active { color: #fff; background: rgba(255,255,255,.18); font-weight: 600; }
.mainnav-link i { font-size: 1rem; }
.mainnav-link.dropdown-toggle::after { margin-left: .1rem; opacity: .7; }
.mainnav-link:focus-visible { outline: 2px solid rgba(255,255,255,.6); outline-offset: 2px; }
.mainnav .dropdown-menu { margin-top: .35rem; min-width: 13rem; }
.mainnav .dropdown-item.active { background: rgba(31,94,75,.1); color: var(--bt-primary); font-weight: 600; }
.mainnav-admin { background: linear-gradient(180deg, #1a1a2e 0%, #16213e 100%); }
.mainnav-admin .mainnav-link.active { background: rgba(233,69,96,.25); }

@media (min-width: 992px) {
    /* Bootstrap's .collapse:not(.show) sets display:none and is only undone by
       .navbar-expand-* inside a .navbar, which this nav is not. Without this the
       entire link list is hidden at every width. */
    .mainnav .mainnav-collapse { display: flex !important; flex: 1 1 auto; }
}

@media (max-width: 991.98px) {
    .mainnav-inner { flex-wrap: wrap; padding: .5rem 1rem; }
    /* Brand and account menu share the first row; the expanded list drops
       under them rather than between them. */
    .mainnav-collapse { flex-basis: 100%; order: 10; }
    .mainnav-list { flex-direction: column; align-items: stretch; gap: 0; padding-bottom: .5rem; }
    .mainnav-link { padding: .6rem .75rem; }
    .mainnav-list .dropdown-menu {
        border: 0; box-shadow: none; background: rgba(0,0,0,.18);
        margin: 0 0 .25rem .75rem; padding: .25rem;
    }
    .mainnav-list .dropdown-item { color: rgba(255,255,255,.8); }
    .mainnav-list .dropdown-item:hover { background: rgba(255,255,255,.1); color: #fff; }
    .mainnav-end { margin-left: auto; }
}

/* Account menu at the right end of the bar */
.mainnav-end { display: flex; align-items: center; gap: .5rem; margin-left: auto; flex: none; }
.mainnav-user-toggle {
    display: flex; align-items: center; gap: .55rem;
    background: none; border: 0; color: rgba(255,255,255,.9);
    padding: .3rem .4rem .3rem .3rem; border-radius: 10rem; cursor: pointer;
    transition: background-color .15s ease;
}
.mainnav-user-toggle:hover, .mainnav-user-toggle[aria-expanded="true"] { background: rgba(255,255,255,.12); color: #fff; }
.mainnav-user-toggle:focus-visible { outline: 2px solid rgba(255,255,255,.6); outline-offset: 2px; }
.mainnav-avatar {
    width: 32px; height: 32px; border-radius: 50%; flex: none;
    background: var(--bt-secondary); color: var(--bt-primary-dark);
    display: inline-flex; align-items: center; justify-content: center;
    font-weight: 700; font-size: .8125rem;
}
.mainnav-admin .mainnav-avatar { background: #e94560; color: #fff; }
.mainnav-user-name { font-size: .875rem; font-weight: 500; white-space: nowrap; max-width: 12rem; overflow: hidden; text-overflow: ellipsis; }
.mainnav-user-caret { font-size: .7rem; opacity: .7; }
.mainnav-user .dropdown-menu { min-width: 15rem; }
.mainnav-user .dropdown-header { padding-top: .6rem; padding-bottom: .6rem; }
.mainnav-pill {
    font-size: .6875rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
    color: #fff; background: rgba(233,69,96,.85); border-radius: 10rem; padding: .2rem .55rem;
}

/* Top Bar */
/* Cards -- flatter and roomier, following the theme's widget tiles */
.card { border: 1px solid var(--bt-border); border-radius: var(--bt-radius-lg); background: var(--bt-surface); }
.card.shadow-sm { box-shadow: var(--bt-shadow-xs) !important; border-color: transparent; }
.card.shadow, .card.shadow-lg { box-shadow: var(--bt-shadow-sm) !important; border-color: transparent; }
.card-header {
    background: transparent; border-bottom: 1px solid var(--bt-border);
    padding: 1.15rem 1.5rem; font-weight: 650; font-size: .95rem; letter-spacing: -.01em;
}
.card-header.bg-white { background: transparent !important; }
.card-header h5 { font-size: .95rem; font-weight: 650; margin: 0; }
.card-body { padding: 1.5rem; }
.card-header + .card-body { padding-top: 1.25rem; }

/* Chart canvases.
   Chart.js with maintainAspectRatio:false sizes the canvas to its parent. If
   that parent's own height is derived from the canvas -- a card-body, more so
   inside an h-100 card in a flex row -- each resize grows the parent, which
   grows the canvas, and the chart expands without bound. Fixing the box height
   and taking the canvas out of flow breaks the loop. */
.chart-box { position: relative; width: 100%; }
.chart-box > canvas {
    position: absolute; top: 0; left: 0;
    width: 100% !important; height: 100% !important;
}

/* Tinted icon chip -- the theme leads most widgets with one instead of a
   low-opacity glyph floating in the corner. */
.stat-chip {
    width: 44px; height: 44px; flex: none;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: var(--bt-radius); font-size: 1.25rem;
    background: rgba(31, 94, 75, .1); color: var(--bt-primary);
}
.stat-chip.accent { background: rgba(200, 90, 46, .12); color: var(--bt-accent); }
.stat-chip.success { background: rgba(25, 135, 84, .12); color: #198754; }
.stat-chip.info { background: rgba(13, 202, 240, .14); color: #0a92ad; }
.card-footer { background: transparent; border-top: 1px solid var(--bt-border); }
/* The left colour rail is a Bootstrap-admin idiom the theme does not use; the
   tinted chip carries the same signal without slicing the card edge. */
.stat-card { border-left: 0; }
.stat-card .stat-icon { display: none; }
.stat-card .stat-value { font-size: 2rem; font-weight: 700; color: var(--bt-text); letter-spacing: -0.025em; line-height: 1.15; }
.stat-card .stat-label { font-size: 0.75rem; color: var(--bt-text-muted); text-transform: uppercase; letter-spacing: 0.06em; font-weight: 600; }
.stat-card .stat-icon { font-size: 2rem; opacity: 0.25; }
/* dashboard2 uses the stat type scale outside a .stat-card wrapper */
.stat-value { font-size: 2rem; font-weight: 700; color: var(--bt-text); letter-spacing: -0.025em; line-height: 1.15; font-variant-numeric: tabular-nums; }
.stat-label { font-size: 0.75rem; color: var(--bt-text-muted); text-transform: uppercase; letter-spacing: 0.06em; font-weight: 600; }
.stat-icon { font-size: 2rem; opacity: 0.25; }

/* Tables */
.table { font-size: 0.875rem; --bs-table-bg: transparent; }
.table th { font-weight: 600; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--bt-text-muted); border-bottom: 1px solid var(--bt-border-strong); padding: 0.75rem 0.75rem; }
.table td { padding: 0.75rem; border-color: var(--bt-border); vertical-align: middle; }
.table > :not(caption) > * > * { background-color: transparent; }
.table-hover > tbody > tr:hover > * { background-color: rgba(31, 94, 75, 0.04); }

/* Status Badges -- soft tints rather than solid fills, semantics unchanged */
.badge { font-weight: 600; font-size: 0.75rem; padding: 0.35em 0.65em; border-radius: 0.4rem; letter-spacing: 0.01em; }
.badge-draft { background-color: var(--bt-tint-neutral); color: var(--bt-tint-neutral-fg); }
.badge-scheduled { background-color: var(--bt-tint-info); color: var(--bt-tint-info-fg); }
.badge-sending { background-color: var(--bt-tint-warn); color: var(--bt-tint-warn-fg); }
.badge-sent { background-color: var(--bt-tint-success); color: var(--bt-tint-success-fg); }
.badge-sent_with_errors { background-color: var(--bt-tint-accent); color: var(--bt-tint-accent-fg); }
.badge-paused { background-color: var(--bt-tint-accent); color: var(--bt-tint-accent-fg); }
.badge-cancelled { background-color: var(--bt-tint-danger); color: var(--bt-tint-danger-fg); }
.badge-subscribed { background-color: var(--bt-tint-success); color: var(--bt-tint-success-fg); }
.badge-unsubscribed { background-color: var(--bt-tint-danger); color: var(--bt-tint-danger-fg); }
.badge-pending { background-color: var(--bt-tint-warn); color: var(--bt-tint-warn-fg); }
.badge-cleaned { background-color: var(--bt-tint-neutral); color: var(--bt-tint-neutral-fg); }
.badge-active { background-color: var(--bt-tint-success); color: var(--bt-tint-success-fg); }
.badge-inactive { background-color: var(--bt-tint-neutral); color: var(--bt-tint-neutral-fg); }
.badge-closed { background-color: var(--bt-tint-danger); color: var(--bt-tint-danger-fg); }
.badge-archived { background-color: var(--bt-tint-neutral); color: var(--bt-tint-neutral-fg); }
/* Campaign / queue / delivery states */
.badge-queued { background-color: var(--bt-tint-info); color: var(--bt-tint-info-fg); }
.badge-waiting { background-color: var(--bt-tint-info); color: var(--bt-tint-info-fg); }
.badge-processing { background-color: var(--bt-tint-warn); color: var(--bt-tint-warn-fg); }
.badge-completed { background-color: var(--bt-tint-success); color: var(--bt-tint-success-fg); }
.badge-delivered { background-color: var(--bt-tint-success); color: var(--bt-tint-success-fg); }
.badge-opened { background-color: var(--bt-tint-info); color: var(--bt-tint-info-fg); }
.badge-clicked { background-color: var(--bt-tint-success); color: var(--bt-tint-success-fg); }
.badge-bounced { background-color: var(--bt-tint-danger); color: var(--bt-tint-danger-fg); }
.badge-complained { background-color: var(--bt-tint-danger); color: var(--bt-tint-danger-fg); }
.badge-failed { background-color: var(--bt-tint-danger); color: var(--bt-tint-danger-fg); }
.badge-skipped { background-color: var(--bt-tint-neutral); color: var(--bt-tint-neutral-fg); }
.badge-verified { background-color: var(--bt-tint-success); color: var(--bt-tint-success-fg); }
.badge-unverified { background-color: var(--bt-tint-warn); color: var(--bt-tint-warn-fg); }
.badge-xs { font-size: 0.65rem; }

/* Impersonation banner (admin acting as a customer) */
.impersonation-banner { background: #f59e0b; color: #000; text-align: center; padding: 6px 16px; font-size: 13px; font-weight: 500; position: fixed; top: 0; left: 0; right: 0; z-index: 9999; }
.impersonation-stop { background: #000; color: #f59e0b; border: 0; border-radius: 4px; padding: 2px 10px; font-size: 12px; font-weight: 600; cursor: pointer; }

/* Public respondent pages (polls, surveys, signup, unsubscribe) */
.public-page { padding-top: 2rem; min-height: 90vh; }
.public-container { max-width: 600px; }
.public-container-wide { max-width: 720px; }
.public-icon { font-size: 4rem; line-height: 1; }
.public-icon-muted { opacity: 0.3; }
.nps-btn { min-width: 36px; }
.nps-btn:focus-within { outline: 3px solid rgba(31,94,75,0.35); outline-offset: 2px; }
.input-narrow { max-width: 200px; }
.input-narrow-md { max-width: 250px; }
.public-logo { max-height: 60px; max-width: 200px; margin-bottom: 12px; }
.public-progress { height: 20px; }
.public-progress .progress-bar { transition: width 0.5s ease; }

/* Clickable choice cards (template pickers) */
.pick-card { cursor: pointer; transition: all 0.2s; }
.pick-card:hover { border-color: var(--bt-primary) !important; }
.pick-card:focus-visible { outline: 3px solid rgba(31,94,75,0.35); outline-offset: 2px; }

/* Question builder */
.reorder-rail { min-width: 28px; }
.scale-inputs { max-width: 320px; }

/* Sticky side card (builder previews) */
.sticky-card { position: sticky; top: 1rem; }
.form-image-thumb { max-width: 200px; max-height: 200px; }

/* Image gallery tiles */
.media-tile { height: 150px; overflow: hidden; background: #f8f8f8; display: flex; align-items: center; justify-content: center; border-radius: var(--bt-radius-lg) var(--bt-radius-lg) 0 0; }
.media-tile img { max-width: 100%; max-height: 150px; object-fit: contain; }
.upload-preview-img { max-width: 100%; max-height: 200px; }

/* Settings: logo preview */
.logo-preview-box { min-width: 200px; }
.logo-preview { max-width: 180px; max-height: 80px; }
.logo-preview-default { opacity: 0.5; }

/* Template picker cards in the campaign editor */
.template-preview-frame { height: 120px; overflow: hidden; background: #fff; border-radius: 0.375rem 0.375rem 0 0; position: relative; }

/* Repeated inline patterns promoted to classes */
.preview-frame { width: 100%; border: 0; min-height: 300px; display: block; background: #fff; }
.preview-frame-lg { min-height: 400px; }
.stat-card .stat-value.stat-value-sm { font-size: 1.1rem; }
.empty-state-inline { text-align: center; padding: 3rem 1rem; }
.empty-state-inline .empty-state-icon { font-size: 3rem; opacity: 0.3; margin-bottom: 0.5rem; }
.form-check-input.visually-hidden:focus-visible + .form-check-label,
.form-check-input.visually-hidden:focus-visible + label { outline: 3px solid rgba(31, 94, 75, 0.35); outline-offset: 2px; }

/* Login Layout */
.login-bg {
    min-height: 100vh;
    background: linear-gradient(135deg, var(--bt-primary) 0%, var(--bt-primary-dark) 40%, #0f3d2f 100%);
    display: flex; align-items: center; justify-content: center;
    position: relative; overflow: hidden;
}
.login-bg::before {
    content: ''; position: absolute; top: -50%; right: -50%;
    width: 100%; height: 200%;
    background: radial-gradient(ellipse, rgba(200,90,46,0.15) 0%, transparent 70%);
    animation: loginGlow 8s ease-in-out infinite alternate;
}
@keyframes loginGlow {
    0% { transform: translate(0, 0); }
    100% { transform: translate(-5%, 5%); }
}
.login-card {
    background: var(--bt-surface); border-radius: var(--bt-radius-lg);
    box-shadow: rgba(0,0,0,0.18) 0 0 2px 0, rgba(0,0,0,0.22) 0 20px 48px -8px;
    width: 100%; max-width: 420px;
    padding: 2.5rem; position: relative; z-index: 1;
}
.login-card .brand-logo { text-align: center; margin-bottom: 2rem; }
.login-card .brand-logo img { height: 48px; }

/* Live preview of a signup form on its edit screen.
   The preview renders the same element the embed and the hosted page use, so it
   cannot drift from what a visitor sees. Those pages supply their own styling
   for .bt-form; inside the admin theme it has none, so the essentials are
   restated here rather than pulling the embed's stylesheet into this page. */
.form-preview {
    background: #fff;
    border: 1px solid var(--bt-border);
    border-radius: var(--bt-radius-sm);
    padding: 1.25rem 1rem 0.75rem;
}
.form-preview .bt-form { max-width: none; margin: 0; }
.form-preview .btn-primary { background-color: var(--bt-primary); border-color: var(--bt-primary); }
.form-preview .bt-powered { text-align: center; margin-top: 0.5rem; font-size: 0.7rem; color: #999; }
.form-preview .bt-success { text-align: center; padding: 2rem 1rem; }
.form-preview .bt-success i { font-size: 2rem; color: var(--bt-primary); }
/* Nothing in a preview is operable -- it is a picture of the form. */
.form-preview input, .form-preview select, .form-preview textarea, .form-preview button { pointer-events: none; }

/* Template previews.
   The card listed a name, a category and a description, which says nothing
   about what the email actually looks like. The real html_content is rendered
   in a sandboxed iframe and scaled down to card width -- 600px is the width
   these templates are built to, and the scale factor is set from the wrapper's
   real width on load and resize, so the preview fits at every breakpoint. */
.tpl-preview {
    position: relative;
    width: 100%;
    height: 190px;
    overflow: hidden;
    background: #fff;
    border-bottom: 1px solid var(--bt-border);
    border-radius: var(--bt-radius) var(--bt-radius) 0 0;
}
.tpl-preview iframe {
    position: absolute;
    top: 0; left: 0;
    width: 600px;
    height: 900px;
    border: 0;
    transform: scale(0.42);
    transform-origin: 0 0;
    /* The preview is a picture, not a page: clicks belong to the card. */
    pointer-events: none;
}
.tpl-preview::after {
    content: '';
    position: absolute;
    inset: 0;
    box-shadow: inset 0 -28px 24px -24px rgba(0,0,0,.10);
}
.tpl-card { overflow: hidden; }
.tpl-card:hover .tpl-preview::after { box-shadow: inset 0 -28px 24px -24px rgba(0,0,0,.18); }

/* Flash Messages -- one fixed stack; each message is a plain block inside it
   so several flashes never overlap. Errors and warnings stay until dismissed;
   success/info auto-dismiss (app.js). */
#flash-messages {
    position: fixed; top: 4rem; right: 1.5rem; z-index: 9999;
    display: flex; flex-direction: column; gap: 0.5rem;
    width: min(480px, calc(100vw - 2rem)); min-width: 0;
    pointer-events: none;
}
#flash-messages .flash-message, #flash-messages .alert { pointer-events: auto; }
.flash-message { animation: slideIn 0.3s ease-out; }
.flash-inline .flash-message { animation: none; }
.flash-inline .alert { box-shadow: none; margin-bottom: 1rem; }
@keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }

/* Breadcrumbs */
.breadcrumb { font-size: 0.8125rem; margin-bottom: 0.5rem; }
.breadcrumb-item a { text-decoration: none; }

/* Page headers */
.container-fluid h2 i { opacity: 0.7; }

/* Nav Tabs (status filters on Campaigns, Surveys, etc.) */
.nav-tabs { border-bottom: 1px solid var(--bt-border-strong); }
.nav-tabs .nav-link {
    color: var(--bt-text-muted);
    font-weight: 500;
    font-size: 0.875rem;
    padding: 0.65rem 1.25rem;
    border: none;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    transition: color 0.2s ease, border-color 0.2s ease;
    border-radius: 0;
}
.nav-tabs .nav-link:hover {
    color: var(--bt-primary);
    border-color: transparent;
    border-bottom-color: var(--bt-secondary-dark);
    background: transparent;
}
.nav-tabs .nav-link.active {
    color: var(--bt-primary);
    font-weight: 600;
    background: transparent;
    border: none;
    border-bottom: 2px solid var(--bt-primary);
}
.nav-tabs.card-header-tabs { margin-bottom: -1px; }

/* Nav Pills (alternative tab style) */
.nav-pills .nav-link {
    color: var(--bt-text-muted);
    font-weight: 500;
    font-size: 0.875rem;
    border-radius: var(--bt-radius-sm);
    padding: 0.5rem 1rem;
    transition: all 0.2s ease;
}
.nav-pills .nav-link:hover { color: var(--bt-primary); background: rgba(31, 94, 75, 0.08); }
.nav-pills .nav-link.active { background-color: var(--bt-primary); color: #fff; }

/* Settings sidebar list-group tabs */
.list-group-item-action {
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--bt-text);
    border: none;
    border-left: 3px solid transparent;
    border-radius: 0 !important;
    padding: 0.75rem 1rem;
    transition: all 0.2s ease;
}
.list-group-item-action:hover {
    color: var(--bt-primary);
    background-color: rgba(31, 94, 75, 0.05);
    border-left-color: var(--bt-secondary-dark);
}
.list-group-item-action.active {
    background-color: rgba(31, 94, 75, 0.08);
    color: var(--bt-primary);
    border-color: transparent;
    border-left-color: var(--bt-primary);
    font-weight: 600;
}
.list-group { border-radius: var(--bt-radius); overflow: hidden; box-shadow: var(--bt-shadow-xs); }

/* Tab content transitions */
.tab-pane { animation: tabFadeIn 0.25s ease-in; }
@keyframes tabFadeIn { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: translateY(0); } }

/* Dropdowns + modals pick up the same surface treatment */
.dropdown-menu { border: 1px solid var(--bt-border); border-radius: var(--bt-radius); box-shadow: var(--bt-shadow); padding: 0.375rem; font-size: 0.875rem; }
.dropdown-item { border-radius: var(--bt-radius-sm); padding: 0.5rem 0.75rem; }
.dropdown-item:hover, .dropdown-item:focus { background-color: rgba(31, 94, 75, 0.08); color: var(--bt-primary); }
.modal-content { border: none; border-radius: var(--bt-radius-lg); box-shadow: var(--bt-shadow-lg); }
.modal-header, .modal-footer { border-color: var(--bt-border); }
.alert { border-radius: var(--bt-radius); border: 1px solid var(--bt-border); font-size: 0.875rem; }
.progress { border-radius: 10rem; background-color: rgba(31, 94, 75, 0.08); }
.progress-bar { border-radius: 10rem; }

/* DataTables overrides */
.dataTables_wrapper .dataTables_paginate .paginate_button.current { background: var(--bt-primary) !important; color: #fff !important; border-color: var(--bt-primary) !important; border-radius: var(--bt-radius-sm) !important; }
.dataTables_wrapper .dataTables_paginate .paginate_button:hover { background: var(--bt-secondary) !important; border-color: var(--bt-secondary) !important; border-radius: var(--bt-radius-sm) !important; }
.dataTables_wrapper .dataTables_filter input, .dataTables_wrapper .dataTables_length select { border-radius: var(--bt-radius-sm); border: 1px solid var(--bt-border-strong); padding: 0.35rem 0.6rem; }

/* Landing Page */
.landing-hero {
    min-height: 90vh; display: flex; align-items: center;
    background: linear-gradient(135deg, var(--bt-primary) 0%, var(--bt-primary-dark) 100%);
    color: #fff; position: relative; overflow: hidden;
}
.landing-hero::after {
    content: ''; position: absolute; bottom: -2px; left: 0; right: 0;
    height: 80px; background: var(--bt-bg);
    clip-path: polygon(0 100%, 100% 100%, 100% 0);
}
.landing-hero h1 { font-size: 3.5rem; font-weight: 800; line-height: 1.1; letter-spacing: -0.02em; color: #fff; }
.landing-hero .lead { font-size: 1.25rem; opacity: 0.9; }
.feature-card {
    text-align: center; padding: 2rem;
    border-radius: var(--bt-radius-lg); transition: transform 0.3s ease, box-shadow 0.3s ease;
    background: var(--bt-surface); height: 100%;
    box-shadow: var(--bt-shadow-xs);
}
.feature-card:hover { transform: translateY(-5px); box-shadow: var(--bt-shadow-lg); }
.pricing-card { text-align: center; padding: 2rem; border-radius: var(--bt-radius-lg); background: var(--bt-surface); transition: transform 0.3s ease, box-shadow 0.3s ease; box-shadow: var(--bt-shadow-xs); }
.pricing-card:hover { transform: translateY(-5px); box-shadow: var(--bt-shadow-lg); }
.pricing-card.featured { border: 2px solid var(--bt-accent); position: relative; }
.pricing-card.featured::before {
    content: 'POPULAR'; position: absolute; top: -12px; left: 50%; transform: translateX(-50%);
    background: var(--bt-accent); color: #fff; padding: 0.2rem 1rem; border-radius: 2rem;
    font-size: 0.7rem; font-weight: 700; letter-spacing: 0.1em;
}
.pricing-card .price { font-size: 3rem; font-weight: 800; color: var(--bt-primary); letter-spacing: -0.02em; }
.pricing-card .price span { font-size: 1rem; font-weight: 400; color: var(--bt-text-muted); }

/* ══════════════════════════════════════════════════════════════════════════
   NiceDash treatment, part two: forms, tables and the shared components.

   Part one restyled the shell -- nav, cards, buttons, the surface tokens.
   This section carries the same treatment into the things every screen is
   actually made of. Everything below is additive: it re-declares properties
   on rules above rather than replacing them, so no selector that a template
   depends on has been removed.

   Three constraints shaped it:

   1. CakePHP's FormHelper, not Bootstrap, renders most fields. It wraps each
      control in `<div class="input {type}{ required}">`, marks failures with
      `.error` on that wrapper and `.error-message` on the note -- never
      `.is-invalid`/`.invalid-feedback`. Both vocabularies are styled here.
   2. DataTables 1.13 with the Bootstrap 5 integration supplies its own
      chrome and, worse, its own colours: row hover is a flat black wash and
      the sort arrows are stock. Those are overridden rather than left to
      fight the palette.
   3. No new literal colours. The status-tint values that were already spelt
      out in the badge block are promoted to tokens above and reused, so the
      badges, alerts and validation states now draw from one set.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Fields ───────────────────────────────────────────────────────────────
   A field is a 40px box with a hairline that warms on hover and takes a
   3px halo on focus. The halo is a box-shadow rather than an outline so it
   sits under neighbouring controls in an input group instead of clipping.
   ──────────────────────────────────────────────────────────────────────── */
.form-control, .form-select {
    color: var(--bt-text);
    line-height: 1.5;
    min-height: var(--bt-field-h);
    box-shadow: none;
}
.form-control:hover:not(:disabled):not([readonly]):not(:focus),
.form-select:hover:not(:disabled):not(:focus) { border-color: var(--bt-border-hover); }
.form-control:focus, .form-select:focus { box-shadow: var(--bt-ring); }
.form-control:disabled, .form-control[readonly], .form-select:disabled {
    background-color: var(--bt-bg);
    color: var(--bt-text-muted);
    border-color: var(--bt-border);
    opacity: 1;
}
.form-control:disabled, .form-select:disabled { cursor: not-allowed; }

/* Bootstrap's chevron is near-black and sits tight to the edge. */
.form-select {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%236c757d' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6.5 8 10.5 12 6.5'/%3E%3C/svg%3E");
    background-position: right 0.7rem center;
    background-size: 14px 14px;
    padding-right: 2.25rem;
}
.form-select-sm { background-position: right 0.5rem center; background-size: 12px 12px; padding-right: 1.9rem; }
.form-control-sm, .form-select-sm { min-height: 2rem; }
.form-control-lg, .form-select-lg { min-height: 3rem; }
textarea.form-control { min-height: 6rem; }

/* Labels. Templates pass `['label' => ['class' => 'form-label']]` almost
   everywhere, but FormHelper emits a bare <label> when they don't, so the
   container selector matches that case too. Checkbox and radio containers
   are excluded: there the label wraps the input and must stay inline. */
.form-label,
.col-form-label,
.input:not(.checkbox):not(.radio) > label {
    display: block;
    font-size: 0.8125rem;
    font-weight: 600;
    line-height: 1.4;
    color: var(--bt-text);
    margin-bottom: 0.35rem;
}

/* Required marker. FormHelper puts `required` on the wrapper; the class is
   also honoured directly on a label for the hand-written fields. */
.input.required > label::after,
.form-label.required::after {
    content: '*';
    color: var(--bt-danger);
    font-weight: 700;
    margin-left: 0.15rem;
}

/* Help text sits under the field, not welded to it. */
.form-text { margin-top: 0.375rem; line-height: 1.5; }

/* Rhythm. Where a control is wrapped in `.mb-3` that utility already sets the
   gap, so this only fires for consecutive FormHelper containers with no
   wrapper -- exactly the case that currently has none. */
.input + .input { margin-top: 1.25rem; }

/* Form footer: Cancel/Back on the left, primary action on the right. */
.form-actions {
    display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem;
    margin-top: 1.5rem; padding-top: 1.25rem; border-top: 1px solid var(--bt-border);
}
.form-actions .ms-auto { margin-left: auto; }

/* ── Checks, radios and switches ─────────────────────────────────────────
   Geometry is left to Bootstrap -- its `.form-check .form-check-input` rules
   out-specify anything set here, and the em-based offsets are already right.
   Only the finish is changed.
   ──────────────────────────────────────────────────────────────────────── */
.form-check-input {
    border-color: var(--bt-border-strong);
    transition: background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
.form-check-input:hover:not(:checked):not(:disabled) { border-color: var(--bt-primary-light); }
.form-check-input:focus { box-shadow: var(--bt-ring); border-color: var(--bt-primary-light); }
.form-check-input:disabled { opacity: 0.5; }
.form-check-input:disabled ~ .form-check-label { opacity: 0.6; }
.form-check-label { color: var(--bt-text); cursor: pointer; }
.form-check-input:not(:disabled) { cursor: pointer; }

/* The knob. Bootstrap ships a translucent black circle unchecked and a pale
   azure one on focus -- the azure being stock Material, the one colour this
   theme deliberately does not adopt. White in every state instead. */
.form-switch .form-check-input,
.form-switch .form-check-input:focus,
.form-switch .form-check-input:checked {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='%23fff'/%3E%3C/svg%3E");
}
.form-switch .form-check-input {
    height: 1.25rem;
    background-color: #d8d2c6;
    border: none;
    transition: background-color 0.2s ease, background-position 0.2s ease-in-out, box-shadow 0.15s ease;
}
.form-switch .form-check-input:focus { box-shadow: var(--bt-ring); }
.form-switch .form-check-label { padding-top: 0.05rem; }

/* Colour and range inputs. The file input's padding is left alone: the
   ::file-selector-button above cancels it with matching negative margins. */
.form-control[type="color"], .form-control-color { padding: 0.25rem; width: 3.5rem; min-height: var(--bt-field-h); }
.form-range::-webkit-slider-runnable-track { background: var(--bt-border-strong); border-radius: 10rem; }
.form-range::-moz-range-track { background: var(--bt-border-strong); border-radius: 10rem; }
.form-range:focus::-moz-range-thumb { box-shadow: 0 0 0 3px rgba(31, 94, 75, 0.18); }

/* ── Input and button groups ─────────────────────────────────────────────
   The radius rules above only cover `.form-control`/`.form-select`; addons
   and buttons need the same treatment, and the group should read as one
   control when anything inside it has focus.
   ──────────────────────────────────────────────────────────────────────── */
.input-group > .btn:not(:last-child),
.input-group > .input-group-text:not(:last-child) { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.input-group > .btn:not(:first-child),
.input-group > .input-group-text:not(:first-child) { border-top-left-radius: 0; border-bottom-left-radius: 0; }
.input-group-text { color: var(--bt-text-muted); }
.input-group:focus-within .input-group-text { border-color: var(--bt-primary-light); color: var(--bt-primary); }
.input-group > .form-control:focus, .input-group > .form-select:focus { z-index: 5; }
.input-group-sm > .form-control, .input-group-sm > .form-select,
.input-group-sm > .btn, .input-group-sm > .input-group-text {
    font-size: 0.8125rem; padding: 0.3rem 0.6rem; border-radius: 0.4rem; min-height: 2rem;
}
.input-group-lg > .form-control, .input-group-lg > .form-select,
.input-group-lg > .btn, .input-group-lg > .input-group-text {
    font-size: 1rem; padding: 0.65rem 0.9rem; border-radius: var(--bt-radius); min-height: 3rem;
}
.btn-group > .btn:focus, .btn-group > .btn:focus-visible, .btn-group > .btn:active { z-index: 2; }
.btn-group .btn + .btn { margin-left: -1px; }

/* ── Validation ──────────────────────────────────────────────────────────
   Two vocabularies, one appearance. FormHelper marks a failed field three
   ways at once -- `.error` on the container, `.form-error` on the control
   itself (its `templates.errorClass`) and `.error-message` on the note --
   and never uses Bootstrap's `.is-invalid`/`.invalid-feedback`, which the
   hand-written forms do. All of it is matched here.

   `.invalid-feedback` is deliberately not given `display`: Bootstrap uses
   that property to keep it hidden until its sibling field actually fails.
   ──────────────────────────────────────────────────────────────────────── */
.form-control.is-invalid, .form-select.is-invalid,
.form-control.form-error, .form-select.form-error,
.input.error .form-control, .input.error .form-select,
.input.error input, .input.error select, .input.error textarea {
    border-color: var(--bt-danger);
}
.form-control.is-invalid:focus, .form-select.is-invalid:focus,
.form-control.form-error:focus, .form-select.form-error:focus,
.input.error .form-control:focus, .input.error .form-select:focus,
.input.error input:focus, .input.error select:focus, .input.error textarea:focus {
    border-color: var(--bt-danger);
    box-shadow: var(--bt-ring-danger);
}
.input.error > label, .input.error > .form-label { color: var(--bt-danger); }
.form-check-input.is-invalid, .form-check-input.form-error,
.input.error .form-check-input { border-color: var(--bt-danger); }
.error-message, .invalid-feedback { font-size: 0.8125rem; font-weight: 500; color: var(--bt-danger); }
.error-message { display: block; margin-top: 0.375rem; }
.form-control.is-valid, .form-select.is-valid { border-color: var(--bt-primary-light); }

/* ── Tables ──────────────────────────────────────────────────────────────
   Denser than Bootstrap's default, ruled in hairlines rather than the stock
   double border under the head, and set in tabular figures so columns of
   numbers line up on the digit rather than drifting.
   ──────────────────────────────────────────────────────────────────────── */
.table {
    --bs-table-color: var(--bt-text);
    --bs-table-border-color: var(--bt-border);
    font-variant-numeric: tabular-nums;
}
/* Bootstrap draws a 2px rule under <thead> via a border-top on <tbody>. */
.table > :not(:first-child) { border-top: 0; }
.table > thead > tr > th {
    background: transparent;
    white-space: nowrap;
    padding-top: 0.625rem;
    padding-bottom: 0.625rem;
    border-bottom: 1px solid var(--bt-border-strong);
}
.table > tbody > tr > td, .table > tbody > tr > th { border-color: var(--bt-border); }
/* The last row's rule would otherwise hang under the table with nothing below it. */
.table:not(.table-bordered) > tbody > tr:last-child > * { border-bottom-width: 0; }
.table-hover > tbody > tr { transition: background-color 0.12s ease; }
.table-hover > tbody > tr:hover > * { background-color: var(--bt-row-hover); }
.table-sm > :not(caption) > * > * { padding: 0.45rem 0.5rem; }
.table-bordered > :not(caption) > * > * { border-color: var(--bt-border); }
.table caption { color: var(--bt-text-muted); font-size: 0.8125rem; padding-top: 0.75rem; }
.table a:not(.btn):not(.dropdown-item) { text-decoration: none; }
.table a:not(.btn):not(.dropdown-item):hover { text-decoration: underline; }
/* Keep an actions column from wrapping mid-control. */
.table td > .btn-group, .table td > .dropdown, .table th > .btn-group { white-space: nowrap; }
.table .badge { vertical-align: middle; }
.table-responsive { scrollbar-width: thin; scrollbar-color: var(--bt-border-strong) transparent; }
.table-responsive::-webkit-scrollbar { height: 6px; }
.table-responsive::-webkit-scrollbar-thumb { background: var(--bt-border-strong); border-radius: 4px; }
.table-responsive::-webkit-scrollbar-track { background: transparent; }

/* Nothing-to-show panel. Used in place of the ad-hoc icon-and-heading blocks
   the index pages grew independently. */
.empty-state { text-align: center; padding: 3.25rem 1.5rem; }
.empty-state .empty-state-icon {
    width: 64px; height: 64px; margin: 0 auto 1.15rem;
    display: flex; align-items: center; justify-content: center;
    border-radius: var(--bt-radius-lg);
    background: rgba(31, 94, 75, 0.08);
    color: var(--bt-primary);
    font-size: 1.75rem;
}
.empty-state h4, .empty-state h5 { font-size: 1.0625rem; font-weight: 650; margin: 0 0 0.35rem; }
.empty-state p { color: var(--bt-text-muted); max-width: 34rem; margin: 0 auto 1.25rem; }
.empty-state p:last-child { margin-bottom: 0; }

/* ── DataTables chrome ───────────────────────────────────────────────────
   app.js builds the wrapper with dom '<"row"<"col-sm-6"l><"col-sm-6"f>>rtip',
   so the length and filter controls sit in a Bootstrap row while the info
   line and pagination are plain block siblings of the table -- which stacks
   them one above the other, full width. Floating them puts the count left and
   the pager right without turning the wrapper into a flex or grid container,
   which a wide table could otherwise blow out.
   ──────────────────────────────────────────────────────────────────────── */
.dataTables_wrapper { position: relative; font-size: 0.875rem; }
.dataTables_wrapper::after { content: ''; display: table; clear: both; }
.dataTables_wrapper > .row:first-child { align-items: center; row-gap: 0.75rem; margin-bottom: 0.35rem; }
.dataTables_wrapper table.dataTable { margin-top: 0 !important; margin-bottom: 0 !important; }

.dataTables_wrapper .dataTables_length label {
    display: flex; align-items: center; gap: 0.5rem;
    margin: 0; font-size: 0.8125rem; font-weight: 500; color: var(--bt-text-muted);
}
.dataTables_wrapper .dataTables_length select { width: auto; min-width: 4.25rem; }

.dataTables_wrapper .dataTables_filter label { margin: 0; width: 100%; max-width: 20rem; }
.dataTables_wrapper .dataTables_filter input {
    margin-left: 0;
    width: 100%;
    padding: 0.35rem 0.6rem 0.35rem 2rem;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%236c757d' stroke-width='1.6' stroke-linecap='round'%3E%3Ccircle cx='7' cy='7' r='4.5'/%3E%3Cpath d='M10.6 10.6 14 14'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: left 0.65rem center;
    background-size: 14px 14px;
}
.dataTables_wrapper .dataTables_filter input:focus { border-color: var(--bt-primary-light); box-shadow: var(--bt-ring); }

.dataTables_wrapper > .dataTables_info {
    float: left; padding-top: 1rem;
    font-size: 0.8125rem; color: var(--bt-text-muted);
}
.dataTables_wrapper > .dataTables_paginate { float: right; padding-top: 0.75rem; }
.dataTables_wrapper .dataTables_paginate ul.pagination { margin: 0; }
/* Neutralise the stock highlight painted on the <li>; the Bootstrap 5
   renderer puts the real one on the .page-link sitting on top of it. */
.dataTables_wrapper .dataTables_paginate li.paginate_button,
.dataTables_wrapper .dataTables_paginate li.paginate_button:hover,
.dataTables_wrapper .dataTables_paginate li.paginate_button.current {
    background: transparent !important; border: 0 !important;
}

/* Row hover: DataTables paints a flat black inset over the background colour,
   so the brand tint set on .table-hover never shows through on these tables. */
table.dataTable.table-hover > tbody > tr:hover > * { box-shadow: inset 0 0 0 9999px var(--bt-row-hover); }

/* Sort indicators: stock is a pair of near-invisible black triangles. */
table.dataTable thead > tr > th.sorting::before, table.dataTable thead > tr > th.sorting::after,
table.dataTable thead > tr > th.sorting_asc::before, table.dataTable thead > tr > th.sorting_asc::after,
table.dataTable thead > tr > th.sorting_desc::before, table.dataTable thead > tr > th.sorting_desc::after {
    right: 8px; font-size: 0.6em; line-height: 9px; opacity: 0.3; color: var(--bt-text-muted);
}
table.dataTable thead > tr > th.sorting_asc::before,
table.dataTable thead > tr > th.sorting_desc::after { opacity: 1; color: var(--bt-primary); }
table.dataTable thead > tr > th.sorting:hover { color: var(--bt-text); }
table.dataTable thead > tr > th.sorting:focus-visible { outline: 2px solid var(--bt-primary-light); outline-offset: -2px; }

table.dataTable td.dataTables_empty { padding: 2.75rem 1rem; color: var(--bt-text-muted); }
div.dataTables_processing {
    background: var(--bt-surface); border: 1px solid var(--bt-border);
    border-radius: var(--bt-radius); box-shadow: var(--bt-shadow-sm);
}
div.dataTables_processing > div:last-child > div { background: var(--bt-primary); }

@media (max-width: 767.98px) {
    .dataTables_wrapper > .dataTables_info,
    .dataTables_wrapper > .dataTables_paginate { float: none; text-align: center; }
    .dataTables_wrapper .dataTables_filter label { max-width: none; }
}

/* ── Pagination ──────────────────────────────────────────────────────────
   Separated pills rather than Bootstrap's welded strip. CakePHP's Paginator
   emits bare `<li><a>` with no .page-item/.page-link classes, so those get
   the same treatment by position.
   ──────────────────────────────────────────────────────────────────────── */
.pagination { gap: 0.25rem; margin-bottom: 0; }
.page-link, .pagination > li > a, .pagination > li > span {
    display: block;
    min-width: 2.25rem;
    padding: 0.375rem 0.7rem;
    font-size: 0.875rem;
    font-weight: 550;
    text-align: center;
    text-decoration: none;
    color: var(--bt-primary);
    background: var(--bt-surface);
    border: 1px solid var(--bt-border);
    border-radius: var(--bt-radius-sm);
    transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.pagination > li > a:hover, .pagination > li > span:hover { background: rgba(31, 94, 75, 0.08); border-color: var(--bt-border-strong); }
.pagination > li.active > a, .pagination > li.active > span { background: var(--bt-primary); border-color: var(--bt-primary); color: #fff; }
.pagination > li.disabled > a, .pagination > li.disabled > span { color: var(--bt-text-muted); pointer-events: none; }
/* The Paginator's ellipsis template has no inner <a> to hang the box on. */
.pagination > li.ellipsis { display: flex; align-items: center; padding: 0 0.35rem; color: var(--bt-text-muted); }
.pagination .page-item .page-link { border-radius: var(--bt-radius-sm); }
.pagination .page-item:not(:first-child) .page-link { margin-left: 0; }
.page-link:focus, .page-link:focus-visible { box-shadow: var(--bt-ring); z-index: 3; }

/* ── Cards ───────────────────────────────────────────────────────────────
   A header that carries tabs loses its own padding at the foot so the tab
   underline lands on the header's hairline instead of floating above it.
   ──────────────────────────────────────────────────────────────────────── */
.card-body > :last-child { margin-bottom: 0; }
.card-header:has(> .nav-tabs) { padding-top: 0.75rem; padding-bottom: 0; border-bottom-color: var(--bt-border-strong); }
.nav-tabs.card-header-tabs { margin-left: -0.5rem; margin-right: -0.5rem; border-bottom: none; }
.card-header .btn-sm, .card-header .btn-group-sm > .btn { font-weight: 550; }
.card-title { font-size: 0.95rem; font-weight: 650; letter-spacing: -0.01em; }
.card-subtitle { font-size: 0.8125rem; color: var(--bt-text-muted); }
.card-footer { padding: 1rem 1.5rem; }
/* A list group nested in a card is already inside a shadowed surface. */
.card .list-group { box-shadow: none; border-radius: 0; }

/* ── Badges ──────────────────────────────────────────────────────────────
   The .badge-<status> family is soft-tinted; Bootstrap's contextual .bg-*
   badges were solid, so the two read as different components on the same
   row. Both now draw from the tint tokens.
   ──────────────────────────────────────────────────────────────────────── */
.badge { display: inline-flex; align-items: center; gap: 0.3rem; line-height: 1.45; vertical-align: middle; }
.badge i { font-size: 0.95em; }
.badge.bg-primary { background-color: rgba(31, 94, 75, 0.12) !important; color: var(--bt-primary-dark) !important; }
.badge.bg-secondary, .badge.bg-dark { background-color: var(--bt-tint-neutral) !important; color: var(--bt-tint-neutral-fg) !important; }
.badge.bg-success { background-color: var(--bt-tint-success) !important; color: var(--bt-tint-success-fg) !important; }
.badge.bg-danger { background-color: var(--bt-tint-danger) !important; color: var(--bt-tint-danger-fg) !important; }
.badge.bg-warning { background-color: var(--bt-tint-warn) !important; color: var(--bt-tint-warn-fg) !important; }
.badge.bg-info { background-color: var(--bt-tint-info) !important; color: var(--bt-tint-info-fg) !important; }
.badge.bg-light { background-color: var(--bt-bg) !important; color: var(--bt-text) !important; }

/* ── Alerts ──────────────────────────────────────────────────────────────
   Same tints as the badges, no border, so an alert reads as a tinted panel
   rather than a boxed one.
   ──────────────────────────────────────────────────────────────────────── */
.alert { padding: 0.85rem 1rem; border-color: transparent; }
.alert-info, .alert-primary { background-color: var(--bt-tint-info); color: var(--bt-tint-info-fg); }
.alert-success { background-color: var(--bt-tint-success); color: var(--bt-tint-success-fg); }
.alert-warning { background-color: var(--bt-tint-warn); color: var(--bt-tint-warn-fg); }
.alert-danger { background-color: var(--bt-tint-danger); color: var(--bt-tint-danger-fg); }
.alert-secondary, .alert-light, .alert-dark { background-color: var(--bt-tint-neutral); color: var(--bt-tint-neutral-fg); }
.alert-primary { background-color: rgba(31, 94, 75, 0.09); color: var(--bt-primary-dark); }
.alert .alert-link, .alert a { color: inherit; font-weight: 600; }
.alert-dismissible { padding-right: 3rem; }
.alert-heading { font-size: 0.9375rem; font-weight: 650; color: inherit; }

/* The alert carries the box; the wrapper is only for stacking. */
.flash-message .alert { border-radius: var(--bt-radius); box-shadow: var(--bt-shadow-lg); margin-bottom: 0; }

/* ── Dropdowns ───────────────────────────────────────────────────────────*/
.dropdown-item { display: flex; align-items: center; }
.dropdown-item i { flex: none; width: 1rem; text-align: center; }
.dropdown-item:active { background-color: rgba(31, 94, 75, 0.12); color: var(--bt-primary); }
.dropdown-item.text-danger:hover, .dropdown-item.text-danger:focus {
    background-color: var(--bt-tint-danger);
    color: var(--bt-tint-danger-fg) !important;
}
.dropdown-item.disabled, .dropdown-item:disabled { color: var(--bt-text-muted); }
.dropdown-divider { border-top-color: var(--bt-border); margin: 0.375rem 0.25rem; }
.dropdown-header {
    padding: 0.5rem 0.75rem 0.25rem;
    font-size: 0.6875rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.08em;
    color: var(--bt-text-muted);
}
.dropdown-item-text { padding: 0.35rem 0.75rem; }
.dropdown-menu-end { --bs-position: end; }

/* ── Modals ──────────────────────────────────────────────────────────────*/
.modal-header { padding: 1.15rem 1.5rem; }
.modal-title { font-size: 1rem; font-weight: 650; letter-spacing: -0.01em; }
.modal-body { padding: 1.5rem; }
.modal-footer { padding: 1rem 1.5rem; gap: 0.5rem; }
.modal-footer > * { margin: 0; }
.modal-backdrop.show { opacity: 0.4; }
.btn-close { --bs-btn-close-focus-shadow: none; opacity: 0.5; }
.btn-close:hover { opacity: 0.9; }
.btn-close:focus-visible { box-shadow: var(--bt-ring); }

/* ── Tabs, pills and list groups ─────────────────────────────────────────*/
.nav-tabs .nav-link:focus-visible, .nav-pills .nav-link:focus-visible {
    outline: 2px solid var(--bt-primary-light); outline-offset: -2px;
}
.nav-tabs .nav-link.disabled { color: var(--bt-border-strong); }
.list-group-item { font-size: 0.875rem; padding: 0.75rem 1rem; color: var(--bt-text); }
.list-group-item:not(.list-group-item-action) { border-color: var(--bt-border); }
.list-group-item-action i, .list-group-item i { width: 1.1rem; text-align: center; }
.list-group-item-action:focus-visible { outline: 2px solid var(--bt-primary-light); outline-offset: -2px; }

/* ── Breadcrumbs ─────────────────────────────────────────────────────────*/
.breadcrumb { --bs-breadcrumb-divider: '\203A'; }
.breadcrumb-item + .breadcrumb-item::before { color: var(--bt-border-strong); padding-right: 0.45rem; }
.breadcrumb-item + .breadcrumb-item { padding-left: 0.45rem; }
.breadcrumb-item a { color: var(--bt-text-muted); }
.breadcrumb-item a:hover { color: var(--bt-primary); text-decoration: underline; }
.breadcrumb-item.active { color: var(--bt-text-muted); font-weight: 550; }

/* ── Buttons: the two used across every table and toolbar ────────────────*/
.btn-outline-secondary {
    color: var(--bt-text);
    background-color: var(--bt-surface);
    border-color: var(--bt-border-strong);
}
.btn-outline-secondary:hover, .btn-outline-secondary:focus {
    color: var(--bt-primary);
    background-color: var(--bt-bg);
    border-color: var(--bt-border-strong);
}
.btn-outline-secondary:active, .btn-outline-secondary.active {
    color: var(--bt-text) !important;
    background-color: var(--bt-secondary) !important;
    border-color: var(--bt-secondary-dark) !important;
}
.btn-danger:focus, .btn-danger:focus-visible,
.btn-outline-danger:focus, .btn-outline-danger:focus-visible { box-shadow: var(--bt-ring-danger); }
.btn i { vertical-align: -0.05em; }

/* Page-header action groups.
   The header .row and its .col-auto both default to align-items: stretch, so an
   <a class="btn"> stretched to the full height of the title block beside it,
   while an <button> wrapped in a <form> (Impersonate on the account page) did
   not -- the form is the flex item, not the button. Pinning the group to centre
   gives every action its natural height, and the min-width makes labels of
   different lengths come out the same width. */
.page-actions { align-items: center; }
.page-actions .btn {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 10.5rem;
}
.page-actions form { display: flex; }
.page-actions form .btn { width: 100%; }
@media (max-width: 575.98px) {
    .page-actions .btn { min-width: 0; }
}
.btn-link { color: var(--bt-primary); text-decoration: none; }
.btn-link:hover { color: var(--bt-primary-dark); text-decoration: underline; }

/* ── Progress, spinners, tooltips, popovers ──────────────────────────────*/
.progress-bar { background-color: var(--bt-primary); }
.spinner-border-sm { border-width: 0.15em; }
.tooltip { --bs-tooltip-opacity: 1; }
.tooltip .tooltip-arrow::before { border-top-color: #2E2E2E; border-bottom-color: #2E2E2E; }
.popover {
    border-color: var(--bt-border);
    border-radius: var(--bt-radius);
    box-shadow: var(--bt-shadow);
    font-size: 0.8125rem;
}
.popover-header { background: var(--bt-bg); border-bottom-color: var(--bt-border); font-size: 0.875rem; font-weight: 650; }


/* Responsive */
@media (max-width: 992px) {
    .landing-hero h1 { font-size: 2.5rem; }
}

/* Signal animation for landing */
.signal-lines { position: absolute; right: 10%; top: 50%; transform: translateY(-50%); }
.signal-line {
    width: 200px; height: 200px; border: 2px solid rgba(255,255,255,0.1);
    border-radius: 50%; position: absolute;
    animation: signalPulse 3s ease-out infinite;
}
.signal-line:nth-child(2) { animation-delay: 0.5s; }
.signal-line:nth-child(3) { animation-delay: 1s; }
.signal-line:nth-child(4) { animation-delay: 1.5s; }
@keyframes signalPulse {
    0% { transform: scale(0.5); opacity: 0.8; }
    100% { transform: scale(3); opacity: 0; }
}

/* Scrollbar */

/* Transitions */
.fade-in { animation: fadeIn 0.3s ease-in; }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; }
}

/* ── Public landing pages ─────────────────────────────────────────────────
   Merged in from templates/layout/landing.php, where these shipped inline so
   the redesign could be verified before app.css was free to edit. Every rule
   is .lp-prefixed and uses existing tokens; nothing here introduces a colour,
   radius or shadow of its own.
   ──────────────────────────────────────────────────────────────────────── */
/* ═══════════════════════════════════════════════════════════════════════════
   Landing pages -- proposed addition to webroot/css/app.css
   ═══════════════════════════════════════════════════════════════════════════

   These rules are currently LIVE: they are served from a <style> block in
   templates/layout/landing.php, because app.css was being edited concurrently
   and merging into it would have collided. Nothing here is speculative -- it
   is exactly what / and /pricing render with today.

   To adopt: paste this block into app.css (it is self-contained, and every
   selector is prefixed .lp- so it cannot touch anything else), then delete the
   <style> block from templates/layout/landing.php. The two must not both be
   present, or the same rules are shipped twice.

   Everything is built on the existing tokens -- no new colours, no new radii,
   no new shadows. Where an existing component already did the job it is
   reused rather than reimplemented:
     .signal-line + @keyframes signalPulse   (hero transmitter rings)
     .pricing-card / .price                  (plan cards)
     .feature-card                           (feature grid, re-aligned)
     .stat-chip                              (tinted icon chips)
     .btn / .btn-accent / .accordion / .card (untouched)
   ─────────────────────────────────────────────────────────────────────────── */


/* ── Sticky top navigation ────────────────────────────────────────────────
   Was position:fixed with a translucent green wash, which forced every page
   below it to guess a top padding (/pricing hard-coded 120px) and let hero
   text scroll under it. Sticky keeps the bar visible without taking the page
   out from under it, and the gradient is the same one .mainnav uses inside
   the app, so the public and signed-in shells now read as one product.
   ──────────────────────────────────────────────────────────────────────── */
.lp-nav {
    background: linear-gradient(180deg, var(--bt-primary) 0%, var(--bt-primary-dark) 100%);
    position: sticky; top: 0; z-index: 1040;
    box-shadow: rgba(23, 74, 59, 0.18) 0 1px 12px -2px;
}
.lp-nav .navbar-brand { gap: .6rem; }
.lp-nav .navbar-brand span { color: #fff; font-weight: 650; letter-spacing: -.01em; }
.lp-nav .nav-link {
    color: rgba(255,255,255,.78); font-size: .875rem; font-weight: 500;
    padding: .5rem .8rem; border-radius: var(--bt-radius-sm);
    transition: background-color .15s ease, color .15s ease;
}
.lp-nav .nav-link:hover, .lp-nav .nav-link:focus { color: #fff; background: rgba(255,255,255,.1); }
.lp-nav .navbar-toggler { padding: .25rem .5rem; }
.lp-nav .navbar-toggler:focus { box-shadow: none; outline: 2px solid rgba(255,255,255,.6); outline-offset: 2px; }
/* The global .btn focus ring is brand green, which disappears against the
   green bar and the green hero. Both places get a white ring instead. */
.lp-nav .btn:focus-visible, .lp-hero .btn:focus-visible, .lp-cta .btn:focus-visible,
.lp-footer a:focus-visible, .lp-nav a:focus-visible {
    box-shadow: 0 0 0 3px rgba(255,255,255,.55); outline: none; border-radius: var(--bt-radius-sm);
}
.lp-nav .btn-outline-light { border-color: rgba(255,255,255,.45); }
@media (max-width: 991.98px) {
    .lp-nav .navbar-collapse { padding: .5rem 0 .75rem; }
    .lp-nav .navbar-nav { align-items: stretch !important; gap: .25rem !important; }
    .lp-nav .navbar-nav .btn { width: 100%; }
}

/* Sticky bar means in-page anchors would otherwise land under it. */
section[id] { scroll-margin-top: 4.5rem; }


/* ── Hero ─────────────────────────────────────────────────────────────────
   Extends .landing-hero (gradient, white text, overflow clip) and drops two
   things it carried: the 90vh minimum, which pushed the first real content
   off a laptop screen once a sticky bar sat above it, and the clip-path
   wedge, which is a hard diagonal in a design system built on soft shadows
   and 20px radii. Padding scales with the viewport instead of the height.
   ──────────────────────────────────────────────────────────────────────── */
.lp-hero {
    min-height: 0; display: block;
    padding: clamp(2.75rem, 6vw, 5rem) 0 clamp(3rem, 7vw, 5.5rem);
    background: linear-gradient(135deg, var(--bt-primary) 0%, var(--bt-primary-dark) 58%, #123a2e 100%);
}
.lp-hero::after { display: none; }
/* One warm off-centre glow, the terracotta accent at low opacity -- the same
   trick .login-bg uses, without the animation. */
.lp-hero::before {
    content: ''; position: absolute; z-index: 0; pointer-events: none;
    top: -30%; right: -15%; width: 70%; height: 160%;
    background: radial-gradient(ellipse at center, rgba(200,90,46,.26) 0%, transparent 62%);
}
.lp-hero-inner { position: relative; z-index: 1; }
.lp-hero h1 {
    color: #fff; font-weight: 750;
    font-size: clamp(2.125rem, 5.4vw, 3.375rem);
    line-height: 1.08; letter-spacing: -.03em;
    margin-bottom: 1rem;
}
.lp-hero .lp-lead {
    font-size: clamp(1rem, 1.9vw, 1.1875rem); line-height: 1.6;
    color: rgba(255,255,255,.84); max-width: 34rem;
}
.lp-hero .lp-fineprint { color: rgba(255,255,255,.62); font-size: .8125rem; }
.lp-hero .btn-outline-light { border-color: rgba(255,255,255,.5); }

/* ── Station photographs ────────────────────────────────────────────────
   Four photos under img/landing give the page some country. Each one sits
   behind the same green gradient the sections already use, at partial
   opacity, so the palette and the text contrast do not change; the picture
   shows through as light and texture rather than as a backdrop the copy has
   to fight. .lp-photo is the one photo shown as itself, beside the steps.
   ──────────────────────────────────────────────────────────────────────── */
.lp-photo-bg {
    position: absolute; inset: 0; width: 100%; height: 100%;
    object-fit: cover; z-index: 0; pointer-events: none; user-select: none;
}
.lp-hero-photo .lp-photo-bg { object-position: center 70%; opacity: .34; }
/* The pricing hero has no panel on the right, so the photo sits lower and
   the gradient darkens evenly behind the centred copy. */
.lp-hero-photo-centred .lp-photo-bg { object-position: center 55%; opacity: .3; }
.lp-hero-photo-centred .lp-hero-inner::before { top: 0; }
.lp-hero-photo::before { z-index: 1; }
/* Keep the bottom of the hero solid so the panel and pills read cleanly. */
.lp-hero-photo .lp-hero-inner::before {
    content: ''; position: absolute; z-index: -1; left: -50vw; right: -50vw; top: 40%; bottom: -6rem;
    background: linear-gradient(180deg, transparent 0%, rgba(18,58,46,.55) 100%); pointer-events: none;
}

.lp-band {
    position: relative; overflow: hidden; isolation: isolate;
    background: var(--bt-primary-dark); color: #fff;
    padding: clamp(3.5rem, 9vw, 7rem) 0;
}
.lp-band .lp-photo-bg { object-position: center 60%; opacity: .55; }
.lp-band::before {
    content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
    background: linear-gradient(90deg, rgba(18,58,46,.92) 0%, rgba(18,58,46,.72) 45%, rgba(18,58,46,.25) 100%);
}
.lp-band-inner { position: relative; z-index: 1; max-width: 40rem; }
.lp-band h2 { color: #fff; font-size: clamp(1.5rem, 3.4vw, 2.25rem); font-weight: 700; letter-spacing: -.02em; line-height: 1.15; }
.lp-band p { color: rgba(255,255,255,.84); font-size: clamp(1rem, 1.6vw, 1.0625rem); line-height: 1.6; margin-bottom: 0; }

.lp-figure { border-radius: var(--bt-radius-lg); overflow: hidden; box-shadow: var(--bt-shadow); }
.lp-photo { display: block; width: 100%; height: 100%; aspect-ratio: 4 / 3; object-fit: cover; }

.lp-cta-photo { isolation: isolate; }
.lp-cta-photo .lp-photo-bg { object-position: center 45%; opacity: .28; }
.lp-cta-photo::before {
    content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
    background: radial-gradient(ellipse at 50% 100%, rgba(200,90,46,.35) 0%, transparent 60%);
}
.lp-cta-inner { position: relative; z-index: 1; }

@media (prefers-reduced-transparency: reduce) {
    .lp-photo-bg { display: none; }
}

/* Small factual pills under the hero buttons. Deliberately not statistics. */
.lp-facts { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: .5rem; }
.lp-facts li {
    display: inline-flex; align-items: center; gap: .4rem;
    font-size: .8125rem; color: rgba(255,255,255,.82);
    background: rgba(255,255,255,.08); border: 1px solid rgba(255,255,255,.16);
    border-radius: 10rem; padding: .3rem .75rem;
}
.lp-facts i { color: var(--bt-secondary); }


/* ── Hero transmitter: the signal rings, given something to come from ─────
   .signal-lines pinned the rings at right:10%/top:50% of the hero with the
   ring's own top-left corner as the anchor, so they expanded from an empty
   point of nothing. Here the wrapper is a zero-size origin centred on the
   product panel and each ring is centred on it (margin:-100px of its 200px
   box), so the pulse reads as a transmission leaving the screen being sent.
   Rings sit behind the panel (z-index 0 vs 1) and are decorative only.
   ──────────────────────────────────────────────────────────────────────── */
.lp-signal { position: absolute; top: 50%; left: 50%; width: 0; height: 0; z-index: 0; pointer-events: none; }
.lp-signal .signal-line {
    top: 50%; left: 50%; margin: -100px 0 0 -100px;
    border-color: rgba(232,216,181,.28);
}
@media (max-width: 991.98px) { .lp-signal { display: none; } }
/* app.css already collapses every animation under reduced motion, which would
   freeze these rings mid-expansion. Remove them outright instead. */
@media (prefers-reduced-motion: reduce) { .lp-signal { display: none; } }

/* The stylised compose panel the rings radiate from. Structure only -- it
   shows what the screen looks like, and states no numbers. */
.lp-panel {
    position: relative; z-index: 1;
    background: var(--bt-surface); color: var(--bt-text);
    border-radius: var(--bt-radius-lg); overflow: hidden;
    box-shadow: rgba(0,0,0,.16) 0 0 2px 0, rgba(0,0,0,.26) 0 24px 48px -12px;
}
.lp-panel-head {
    display: flex; align-items: center; gap: .5rem;
    padding: .8rem 1.1rem; border-bottom: 1px solid var(--bt-border);
    font-size: .8125rem; font-weight: 650;
}
.lp-panel-body { padding: 1.1rem; }
.lp-field { border: 1px solid var(--bt-border); border-radius: var(--bt-radius-sm); padding: .5rem .7rem; }
.lp-field-label { font-size: .6875rem; font-weight: 650; text-transform: uppercase; letter-spacing: .08em; color: var(--bt-text-muted); }
.lp-field-value { font-size: .875rem; font-weight: 550; }
.lp-bar { height: 8px; border-radius: 4px; background: var(--bt-border); }


/* ── Section scaffolding ──────────────────────────────────────────────────
   .landing-section is not reused: its 5rem is fixed at every width, and its
   :nth-child(even) striping is keyed to the section's position in the document,
   which reshuffles the moment a section is added, removed, or a
   flash message renders above it. Backgrounds are stated per section here.
   ──────────────────────────────────────────────────────────────────────── */
.lp-section { padding: clamp(2.75rem, 5.5vw, 4.75rem) 0; }
.lp-section-white { background: var(--bt-surface); }
.lp-section-ground { background: var(--bt-bg); }
.lp-eyebrow {
    display: inline-block; font-size: .75rem; font-weight: 650;
    letter-spacing: .12em; text-transform: uppercase;
    color: var(--bt-accent); margin-bottom: .6rem;
}
.lp-eyebrow-light { color: var(--bt-secondary); }
.lp-head { max-width: 46rem; }
.lp-head h2 {
    font-size: clamp(1.5rem, 3.2vw, 2.125rem); font-weight: 700;
    letter-spacing: -.02em; line-height: 1.2; margin-bottom: .6rem;
}
.lp-head p { font-size: 1rem; color: var(--bt-text-muted); margin-bottom: 0; }

/* Feature tiles: .feature-card, left-aligned and given a hairline so it still
   reads as a tile on a white section, where a shadow alone does not. The
   centred text and the 2.5rem bare glyph were the two most dated parts of
   the old page; the icon is now the app's own .stat-chip. */
.lp-feature { text-align: left; padding: 1.5rem; border: 1px solid var(--bt-border); }
.lp-feature:hover { transform: translateY(-3px); box-shadow: var(--bt-shadow); }
.lp-feature h3 { font-size: 1rem; font-weight: 650; margin: .95rem 0 .4rem; }
.lp-feature p { font-size: .875rem; color: var(--bt-text-muted); margin-bottom: 0; }

/* Numbered steps */
.lp-step-num {
    width: 2.25rem; height: 2.25rem; flex: none; border-radius: 50%;
    display: inline-flex; align-items: center; justify-content: center;
    background: rgba(31,94,75,.1); color: var(--bt-primary);
    font-weight: 700; font-size: .9375rem; font-variant-numeric: tabular-nums;
}
.lp-step h3 { font-size: 1rem; font-weight: 650; margin-bottom: .35rem; }
.lp-step p { font-size: .875rem; color: var(--bt-text-muted); margin-bottom: 0; }

/* Tick lists */
.lp-checklist { list-style: none; margin: 0; padding: 0; }
.lp-checklist li { display: flex; gap: .65rem; padding: .5rem 0; font-size: .9375rem; line-height: 1.55; }
.lp-checklist > li > i { color: var(--bt-primary); font-size: 1rem; line-height: 1.55; flex: none; }
.lp-checklist strong { font-weight: 650; }

/* A plain bordered panel for the "what we don't do" list -- deliberately not
   a card with a shadow, so it reads as a statement rather than a feature. */
.lp-note {
    background: var(--bt-bg); border: 1px solid var(--bt-border);
    border-radius: var(--bt-radius-lg); padding: 1.75rem;
}
.lp-note h3 { font-size: 1rem; font-weight: 650; margin-bottom: 1rem; }
.lp-note .lp-checklist > li > i { color: var(--bt-accent); }


/* ── Plan cards ───────────────────────────────────────────────────────────
   .pricing-card, made flex so three cards with unequal feature lists still
   line their buttons up along the bottom, and given the hairline the rest of
   the surface treatment uses. The featured ribbon said POPULAR, which is a
   claim about other customers that nothing here can support; it now says
   RECOMMENDED, which is a claim about us.
   ──────────────────────────────────────────────────────────────────────── */
.lp-plan { display: flex; flex-direction: column; border: 1px solid var(--bt-border); padding: 2rem 1.75rem; }
.lp-plan.featured { border: 2px solid var(--bt-accent); }
.lp-plan.featured::before { content: 'RECOMMENDED'; }
.lp-plan h2, .lp-plan h3 { font-size: 1.125rem; font-weight: 700; margin-bottom: .15rem; }
.lp-plan .lp-plan-for { font-size: .875rem; color: var(--bt-text-muted); margin-bottom: 1rem; }
.lp-plan .price { line-height: 1; margin-bottom: .35rem; }
.lp-plan .lp-plan-cycle { font-size: .8125rem; color: var(--bt-text-muted); min-height: 1.2rem; }
.lp-plan .lp-checklist { text-align: left; margin: 1.25rem 0 1.5rem; }
.lp-plan .lp-checklist li { padding: .3rem 0; font-size: .875rem; }
.lp-plan .lp-plan-cta { margin-top: auto; }
.lp-included {
    background: var(--bt-surface); border: 1px solid var(--bt-border);
    border-radius: var(--bt-radius-lg); padding: 1.25rem 1.5rem;
}
.lp-included h3 { font-size: .8125rem; font-weight: 650; text-transform: uppercase; letter-spacing: .08em; color: var(--bt-text-muted); margin-bottom: .75rem; }
.lp-included ul { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: .4rem .5rem; }
.lp-included li { font-size: .8125rem; background: var(--bt-bg); border: 1px solid var(--bt-border); border-radius: 10rem; padding: .25rem .7rem; }

/* Plan comparison table (pricing page). Scrolls inside itself rather than
   forcing the page sideways on a phone. */
.lp-compare { background: var(--bt-surface); border: 1px solid var(--bt-border); border-radius: var(--bt-radius-lg); overflow: hidden; }
.lp-compare-scroll { overflow-x: auto; }
.lp-compare table { min-width: 34rem; margin: 0; }
.lp-compare th, .lp-compare td { padding: .8rem 1rem; border-bottom: 1px solid var(--bt-border); vertical-align: middle; }
.lp-compare thead th { font-size: .75rem; text-transform: uppercase; letter-spacing: .06em; color: var(--bt-text-muted); font-weight: 650; }
.lp-compare tbody th { font-weight: 550; font-size: .875rem; text-align: left; }
.lp-compare td { font-size: .875rem; text-align: center; }
.lp-compare tr:last-child th, .lp-compare tr:last-child td { border-bottom: 0; }
.lp-compare .lp-col-featured { background: rgba(200,90,46,.05); }


/* ── Closing call to action ───────────────────────────────────────────────
   A contained panel on the ground rather than a full-bleed green band, so
   the page ends on the same rounded-surface language it has used throughout
   instead of a second full-width slab immediately above the green footer.
   ──────────────────────────────────────────────────────────────────────── */
.lp-cta {
    background: linear-gradient(135deg, var(--bt-primary) 0%, var(--bt-primary-dark) 100%);
    color: #fff; border-radius: var(--bt-radius-lg);
    padding: clamp(2.25rem, 5vw, 3.5rem) clamp(1.25rem, 4vw, 3rem);
    text-align: center; position: relative; overflow: hidden;
}
.lp-cta h2 { color: #fff; font-size: clamp(1.5rem, 3.2vw, 2.125rem); font-weight: 700; letter-spacing: -.02em; }
.lp-cta p { color: rgba(255,255,255,.82); max-width: 38rem; margin-inline: auto; }
.lp-cta .lp-fineprint { color: rgba(255,255,255,.6); font-size: .8125rem; }


/* ── Footer ───────────────────────────────────────────────────────────── */
.lp-footer {
    background: linear-gradient(180deg, var(--bt-primary) 0%, var(--bt-primary-dark) 100%);
    color: rgba(255,255,255,.72);
    padding: clamp(2.5rem, 5vw, 3.5rem) 0 1.5rem;
}
.lp-footer h6 { color: #fff; font-size: .75rem; font-weight: 650; text-transform: uppercase; letter-spacing: .1em; margin-bottom: .9rem; }
.lp-footer ul { list-style: none; margin: 0; padding: 0; }
.lp-footer li { margin-bottom: .5rem; }
.lp-footer a { color: rgba(255,255,255,.72); font-size: .875rem; text-decoration: none; }
.lp-footer a:hover { color: #fff; text-decoration: underline; }
.lp-footer p { font-size: .875rem; }
.lp-footer hr { border-color: rgba(255,255,255,.14); opacity: 1; }

/* ── Dashboard action tiles ───────────────────────────────────────────────
   Optional polish on the signed-in home page's action tiles. The markup
   already carries these classes and the page is correct without them.
   ──────────────────────────────────────────────────────────────────────── */
/*
 * Proposed additions for webroot/css/app.css, from the /dashboard rebuild.
 *
 * Nothing here is required: the home page is built entirely from classes that
 * already exist and renders correctly without a single one of these rules.
 * They are polish on the one genuinely new component on that page -- the
 * "What would you like to do?" action tiles -- which are currently plain
 * bordered boxes with no hover feedback despite being links.
 *
 * The markup already carries the class, so merging this file is enough.
 */

/* Action tiles on the /dashboard home page.
   Each tile is an <a> wrapping a stat-chip, a label and a blurb. Without this
   the only hover affordance is the cursor: the border and background do not
   move, which reads as a static panel rather than the primary call to action
   the page is built around. Matches the surface treatment used elsewhere --
   hairline border, soft shadow, brand green -- rather than introducing a new
   one. */
.action-tile {
    border-color: var(--bt-border) !important;
    background: var(--bt-surface);
    transition: border-color 0.15s ease, box-shadow 0.15s ease, background-color 0.15s ease;
}
.action-tile:hover {
    border-color: var(--bt-primary-light) !important;
    background-color: rgba(31, 94, 75, 0.03);
    box-shadow: var(--bt-shadow-xs);
}
/* The chevron is a hint, not a control: it only asserts itself on hover. */
.action-tile .bi-chevron-right {
    font-size: 0.875rem;
    opacity: 0.35;
    transition: opacity 0.15s ease, transform 0.15s ease;
}
.action-tile:hover .bi-chevron-right {
    opacity: 1;
    transform: translateX(2px);
}
/* Keyboard parity with the hover state -- these are links, and the page is a
   plausible first stop for someone tabbing through. */
.action-tile:focus-visible {
    outline: none;
    border-color: var(--bt-primary) !important;
    box-shadow: 0 0 0 3px rgba(31, 94, 75, 0.15);
}

/* ── Legal pages ──────────────────────────────────────────────────────────
   Privacy, terms and anti-spam share one shell. Long-form prose, so the
   measure is held near 70 characters and the headings get room; nothing here
   introduces a colour or radius of its own.
   ──────────────────────────────────────────────────────────────────────── */
.lp-legal { padding: 4rem 0 5rem; }
.lp-legal-title { font-size: clamp(2rem, 5vw, 2.75rem); font-weight: 800; letter-spacing: -.02em; margin-bottom: .75rem; }
.lp-legal h2 {
    font-size: 1.25rem; font-weight: 700; letter-spacing: -.01em;
    margin: 2.5rem 0 .75rem; padding-top: 1.5rem;
    border-top: 1px solid var(--bt-border);
}
.lp-legal h3 { font-size: 1rem; font-weight: 650; margin: 1.5rem 0 .5rem; color: var(--bt-primary); }
.lp-legal p, .lp-legal li { font-size: .9375rem; line-height: 1.75; max-width: 70ch; }
.lp-legal ul { padding-left: 1.15rem; }
.lp-legal li { margin-bottom: .5rem; }
.lp-legal h2:first-of-type { border-top: 0; padding-top: 0; margin-top: 0; }

/* Drag-to-reorder (bt-sortable.js) */
.bt-dragging { opacity: .45; }
.drag-handle { cursor: grab; }
.drag-handle:active { cursor: grabbing; }


/* ── Registration card ────────────────────────────────────────────────────
   The login card's wide variant: a "what happens next" panel on the left,
   the form on the right. The panel reuses the landing page's green gradient
   with a station photograph showing through at low opacity, and a small
   signal graphic -- the telegraph pulse leaving an envelope. Below lg the
   panel sits above the form and drops to its heading and steps.
   ──────────────────────────────────────────────────────────────────────── */
.login-card.login-card-wide { max-width: 900px; padding: 0; overflow: hidden; }
.login-card-wide .brand-logo { padding: 2rem 2rem 0; margin-bottom: 1.25rem; }
.login-card-wide .flash-inline { padding: 0 2rem; }
.register-grid { display: grid; grid-template-columns: 5fr 7fr; }
.register-form { padding: 1.25rem 2.25rem 2.25rem; }
.register-aside {
    position: relative; overflow: hidden; isolation: isolate;
    background: linear-gradient(160deg, var(--bt-primary) 0%, var(--bt-primary-dark) 55%, #0f3d2f 100%);
    color: #fff; padding: 2rem 1.75rem 2rem;
    display: flex; align-items: center;
}
.register-aside .lp-photo-bg { opacity: .28; object-position: center 65%; }
.register-aside::before {
    content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
    background: linear-gradient(180deg, rgba(18,58,46,.35) 0%, rgba(18,58,46,.85) 100%);
}
.register-aside-inner { position: relative; z-index: 1; }
.register-aside h2 {
    color: #fff; font-size: 1.375rem; font-weight: 700; letter-spacing: -.02em;
    line-height: 1.25; margin: 0 0 1.25rem;
}
.register-aside-fine { color: rgba(255,255,255,.7); font-size: .8125rem; margin: 1.25rem 0 0; }

/* The signal: two rings pulsing out from the envelope, in the same rhythm as
   the landing hero's transmitter. Static under prefers-reduced-motion. */
.register-signal { position: relative; width: 72px; height: 72px; margin-bottom: 1.25rem; }
.register-signal-core {
    position: absolute; inset: 14px; border-radius: 50%;
    background: var(--bt-secondary); color: var(--bt-primary-dark);
    display: flex; align-items: center; justify-content: center; font-size: 1.25rem;
    box-shadow: 0 6px 16px rgba(0,0,0,.25);
}
.register-signal-ring {
    position: absolute; inset: 0; border-radius: 50%;
    border: 2px solid rgba(232,216,181,.55);
    animation: registerPulse 2.8s ease-out infinite;
}
.register-signal-ring:nth-child(2) { animation-delay: 1.4s; }
@keyframes registerPulse {
    0% { transform: scale(.55); opacity: .9; }
    100% { transform: scale(1.6); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
    .register-signal-ring { animation: none; transform: scale(1); opacity: .45; }
    .register-signal-ring:nth-child(2) { transform: scale(.75); }
}

.register-steps { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .6rem; }
.register-steps li { display: flex; align-items: center; gap: .7rem; font-size: .9375rem; color: rgba(255,255,255,.9); }
.register-step-num {
    width: 1.75rem; height: 1.75rem; flex: none; border-radius: 50%;
    display: inline-flex; align-items: center; justify-content: center;
    background: rgba(255,255,255,.14); border: 1px solid rgba(255,255,255,.25);
    font-weight: 700; font-size: .8125rem; font-variant-numeric: tabular-nums;
}

/* ── Terms acceptance card ────────────────────────────────────────────────
   The login card at reading width. The terms scroll inside their own panel
   with the legal pages' typography, so the checkbox and button stay in view
   beneath them instead of at the foot of a very long card.
   ──────────────────────────────────────────────────────────────────────── */
.login-card.login-card-terms { max-width: 720px; padding: 2.25rem 2.5rem 2.5rem; }
.login-card-terms .brand-logo { margin-bottom: 1.5rem; }
.terms-accept-heading { font-size: 1.5rem; font-weight: 700; letter-spacing: -.02em; margin-bottom: .35rem; }
.terms-accept-body {
    max-height: min(48vh, 26rem); overflow-y: auto; overscroll-behavior: contain;
    padding: 1.25rem 1.5rem; margin-bottom: 1.25rem;
    background: var(--bt-bg); border: 1px solid var(--bt-border); border-radius: var(--bt-radius);
}
.terms-accept-body h2 {
    font-size: 1rem; font-weight: 700; letter-spacing: -.01em;
    margin: 1.5rem 0 .5rem; padding-top: 1.25rem; border-top: 1px solid var(--bt-border);
}
.terms-accept-body h2:first-child { border-top: 0; padding-top: 0; margin-top: 0; }
.terms-accept-body p { font-size: .9rem; line-height: 1.65; }
.terms-accept-body p:last-child { margin-bottom: 0; }
.terms-accept .form-check-label { font-size: .9375rem; }
@media (max-width: 575.98px) {
    .login-card.login-card-terms { padding: 1.75rem 1.25rem 2rem; }
    .terms-accept-body { padding: 1rem 1.1rem; max-height: 44vh; }
}

/* The same panel beside an in-app form (element explainer_aside): what the
   thing being created is for. Shares the register-aside inner pieces; the
   element itself is d-none below md, so phones only get the form. */
.explainer-aside {
    position: relative; overflow: hidden; isolation: isolate;
    background: linear-gradient(160deg, var(--bt-primary) 0%, var(--bt-primary-dark) 55%, #0f3d2f 100%);
    color: #fff; padding: 2rem 1.75rem; border-radius: var(--bt-radius-lg);
    align-items: center; height: 100%; box-shadow: var(--bt-shadow-xs);
}
.explainer-aside .lp-photo-bg { opacity: .28; object-position: center 65%; }
.explainer-aside::before {
    content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
    background: linear-gradient(180deg, rgba(18,58,46,.35) 0%, rgba(18,58,46,.85) 100%);
}
.explainer-aside h2 {
    color: #fff; font-size: 1.25rem; font-weight: 700; letter-spacing: -.02em;
    line-height: 1.25; margin: 0 0 1rem;
}
.explainer-points { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .6rem; }
.explainer-points li { display: flex; align-items: flex-start; gap: .6rem; font-size: .9rem; line-height: 1.45; color: rgba(255,255,255,.9); }
.explainer-points i { color: var(--bt-secondary); flex: none; margin-top: .1rem; }

@media (max-width: 991.98px) {
    .login-card.login-card-wide { max-width: 560px; }
    .register-grid { grid-template-columns: 1fr; }
    .register-aside { padding: 1.5rem 1.75rem; }
    .register-aside h2 { font-size: 1.1875rem; margin-bottom: .9rem; }
    .register-signal, .register-aside-fine { display: none; }
    .register-form { padding: 1.5rem 1.75rem 2rem; }
}
