/* ==========================================================
   Components. Every rule here belongs to a function in
   components/ui.php, so markup and style change together.
   ========================================================== */

/* ---------- Buttons ---------- */
.u-btn {
    display: inline-flex; align-items: center; gap: var(--s2);
    padding: 9px var(--s4); border-radius: var(--r2);
    border: 1px solid var(--line); background: var(--paper); color: var(--ink);
    font-weight: 600; font-size: 13.5px; line-height: 1.2;
    text-decoration: none; cursor: pointer; white-space: nowrap;
}
.u-btn:hover { background: var(--sunk); }
.u-btn--brand { background: var(--brand); border-color: var(--brand); color: var(--on-brand); }
.u-btn--brand:hover { background: var(--brand-70); border-color: var(--brand-70); color: var(--on-brand); }
.u-btn--soft { background: var(--brand-05); border-color: transparent; color: var(--brand-ink); }
.u-btn--harm { background: var(--harm-bg); border-color: transparent; color: var(--harm); }
.u-btn--ghost { background: transparent; border-color: transparent; color: var(--ink-2); }
.u-btn--ghost:hover { background: var(--sunk); color: var(--ink); }
.u-btn--sm { padding: 6px var(--s3); font-size: 12.5px; }
.u-btn--block { width: 100%; justify-content: center; }
.u-btn[disabled] { opacity: .5; cursor: not-allowed; }
.u-btn--icon { padding: 8px; }
.u-i { flex: none; }

/* ---------- Status and tags ---------- */
.u-status, .u-chip {
    display: inline-flex; align-items: center;
    padding: 3px 8px; border-radius: var(--r-label);
    font-size: 11.5px; font-weight: 650; white-space: nowrap; line-height: 1.4;
    background: var(--sunk); color: var(--ink-2);
}
.u-status--good { background: var(--good-bg); color: var(--good); }
.u-status--brand { background: var(--brand-10); color: var(--brand-ink); }
.u-status--caution { background: var(--caution-bg); color: var(--caution); }
.u-status--harm { background: var(--harm-bg); color: var(--harm); }
.u-chip--brand { background: var(--brand-10); color: var(--brand-ink); }

/* ---------- Cards ---------- */
.u-card {
    background: var(--paper); border: 1px solid var(--line);
    border-radius: var(--r3); box-shadow: var(--lift-1);
    margin-bottom: var(--s4);
}
.u-card__h {
    display: flex; align-items: center; justify-content: space-between; gap: var(--s4);
    padding: var(--s4) var(--s5) 0;
}
.u-card__h h3 { font-size: 15px; }
.u-card__sub { margin: 2px 0 0; font-size: 12.5px; color: var(--ink-3); }
.u-card__a { display: flex; gap: var(--s2); align-items: center; flex-wrap: wrap; }
.u-card__b { padding: var(--s4) var(--s5) var(--s5); }
.u-card__b > *:first-child { margin-top: 0; }
.u-card__b > *:last-child { margin-bottom: 0; }

/* ---------- Metrics ---------- */
/* Flex rather than grid: a wrapping flex row gives the same four-up
   layout, degrades to two-up and one-up on its own, and is understood by
   every engine this has to render in. */
.u-metrics { display: flex; flex-wrap: wrap; gap: var(--s3); margin-bottom: var(--s4); }
.u-metrics > * { flex: 1 1 200px; min-width: 0; }
.u-metric {
    display: block; padding: var(--s4) var(--s5);
    background: var(--paper); border: 1px solid var(--line); border-radius: var(--r3);
    box-shadow: var(--lift-1); text-decoration: none; color: inherit;
}
a.u-metric:hover { border-color: var(--brand); }
.u-metric__top { display: flex; align-items: center; justify-content: space-between;
                 font-size: 12.5px; font-weight: 600; color: var(--ink-2); }
.u-metric__top .u-i { color: var(--ink-3); }
.u-metric__v { font-size: 26px; font-weight: 680; letter-spacing: -.03em; margin: var(--s2) 0 var(--s1); }
.u-metric__b { display: flex; gap: var(--s2); align-items: baseline; font-size: 12px; }
.u-metric__d { margin-right: var(--s2); }
.u-metric__d { font-weight: 650; }
.u-metric__d.is-up { color: var(--good); }
.u-metric__d.is-down { color: var(--harm); }
.u-metric__s { color: var(--ink-3); }

/* ---------- Tables ---------- */
.u-tw { overflow-x: auto; }
.u-t { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.u-t th {
    text-align: left; padding: var(--s3) var(--s5);
    font-size: 11px; letter-spacing: .06em; text-transform: uppercase;
    font-weight: 700; color: var(--ink-3);
    border-bottom: 1px solid var(--line); white-space: nowrap;
}
.u-t td { padding: var(--s3) var(--s5); border-bottom: 1px solid var(--line-2); vertical-align: middle; }
.u-t tbody tr:last-child td { border-bottom: none; }
.u-t tbody tr.is-click { cursor: pointer; }
.u-t tbody tr.is-click:hover { background: var(--sunk); }
.ta-right { text-align: right; }
.ta-center { text-align: center; }
.u-t .u-num { font-variant-numeric: tabular-nums; }

/* ---------- Pagination ---------- */
.u-pager {
    display: flex; align-items: center; justify-content: space-between; gap: var(--s4);
    padding: var(--s3) var(--s5); border-top: 1px solid var(--line-2); flex-wrap: wrap;
}
.u-pager__c { font-size: 12.5px; color: var(--ink-3); }
.u-pgs { display: flex; gap: var(--s1); }
.u-pg {
    min-width: 32px; padding: 6px 10px; border-radius: var(--r-label);
    font-size: 12.5px; font-weight: 600; text-align: center;
    color: var(--ink-2); text-decoration: none;
}
.u-pg:hover { background: var(--sunk); color: var(--ink); }
.u-pg.is-on { background: var(--brand); color: var(--on-brand); }
.u-pg.is-off { color: var(--ink-3); opacity: .5; }

/* ---------- Empty, error, skeleton ---------- */
.u-empty { text-align: center; padding: var(--s7) var(--s5); color: var(--ink-3); }
.u-empty .u-i { color: var(--ink-3); opacity: .65; }
.u-empty b { display: block; margin: var(--s3) 0 var(--s1); color: var(--ink); font-size: 15px; }
.u-empty p { margin: 0; font-size: 13px; }
.u-empty__a { margin-top: var(--s4); display: flex; gap: var(--s2); justify-content: center; }
.u-empty--harm .u-i { color: var(--harm); opacity: 1; }

.u-skel { padding: var(--s2) 0; }
.u-skel__r { display: flex; align-items: center; gap: var(--s3); padding: var(--s3) var(--s5); }
.u-skel__c, .u-skel__l {
    display: block; border-radius: var(--r1);
    background: linear-gradient(90deg, var(--sunk) 25%, var(--line-2) 50%, var(--sunk) 75%);
    background-size: 320% 100%; animation: u-shim 1.2s linear infinite;
}
.u-skel__c { width: 32px; height: 32px; border-radius: var(--r2); flex: none; }
.u-skel__l { height: 10px; }
.u-skel__l--sm { height: 8px; margin-left: auto; }
@keyframes u-shim { from { background-position: 100% 0; } to { background-position: -100% 0; } }

/* ---------- Notes ---------- */
.u-note {
    padding: var(--s3) var(--s4); border-radius: var(--r2);
    font-size: 13px; line-height: 1.55; margin-bottom: var(--s4);
    background: var(--info-bg); color: var(--info);
}
.u-note--good { background: var(--good-bg); color: var(--good); }
.u-note--warn { background: var(--caution-bg); color: var(--caution); }
.u-note--harm { background: var(--harm-bg); color: var(--harm); }
.u-note--brand { background: var(--brand-05); color: var(--brand-ink); }

/* ---------- Avatars ---------- */
.u-av {
    display: inline-flex; align-items: center; justify-content: center; flex: none;
    width: 32px; height: 32px; border-radius: var(--r2);
    background: var(--brand-10); color: var(--brand-ink);
    font-weight: 700; font-size: 11.5px;
}
.u-av--lg { width: 56px; height: 56px; border-radius: var(--r3); font-size: 18px; }
.u-av--sm { width: 26px; height: 26px; font-size: 10px; }

/* ---------- Tabs ---------- */
.u-tabs { display: flex; gap: var(--s1); border-bottom: 1px solid var(--line); overflow-x: auto; }
.u-tab {
    padding: var(--s3) var(--s4); font-size: 13.5px; font-weight: 600;
    color: var(--ink-2); text-decoration: none; white-space: nowrap;
    border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.u-tab:hover { color: var(--ink); }
.u-tab.is-on { color: var(--brand-ink); border-bottom-color: var(--brand); }

/* ---------- Forms ---------- */
.u-field { margin-bottom: var(--s4); }
.u-label { display: block; font-size: 12.5px; font-weight: 650; margin-bottom: 6px; }
.u-in {
    width: 100%; padding: 9px var(--s3);
    border: 1px solid var(--line); border-radius: var(--r2);
    background: var(--paper); color: var(--ink); font: inherit; font-size: 13.5px;
}
.u-in:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-10); }
textarea.u-in { min-height: 96px; resize: vertical; }
.u-sel {
    -webkit-appearance: none; -moz-appearance: none; appearance: none; padding-right: 34px;
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235A554C' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: right 10px center; background-size: 15px;
}
[data-theme="dark"] .u-sel {
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23B0ABA1' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
}
.u-help { margin: 6px 0 0; font-size: 12px; color: var(--ink-3); line-height: 1.5; }
.u-row { display: flex; gap: var(--s3); flex-wrap: wrap; }
.u-row > * { flex: 1 1 200px; min-width: 0; }
.u-actions { display: flex; gap: var(--s2); flex-wrap: wrap; margin-top: var(--s5); }

/* Filter bar above every list */
.u-filters {
    display: flex; gap: var(--s2); align-items: center; flex-wrap: wrap;
    padding: var(--s3) var(--s5); border-bottom: 1px solid var(--line-2);
}
.u-filters .u-in { width: auto; min-width: 150px; }
.u-filters .u-search { flex: 1 1 240px; min-width: 200px; position: relative; display: flex; align-items: center; }
.u-filters .u-search .u-i { position: absolute; left: 11px; color: var(--ink-3); pointer-events: none; }
.u-filters .u-search .u-in { width: 100%; padding-left: 34px; }

/* ---------- Charts ---------- */
.u-legend > span { margin-right: var(--s4); }
.u-legend { display: flex; gap: var(--s4); font-size: 12.5px; color: var(--ink-2); font-weight: 600; margin-bottom: var(--s3); flex-wrap: wrap; }
.u-legend__k { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 6px; vertical-align: -1px; }
.u-chart { display: flex; align-items: flex-end; gap: 3px; }
.u-chart__g { flex: 1; display: flex; align-items: flex-end; gap: 2px; height: 100%; min-width: 0; }
.u-chart__g i { flex: 1; border-radius: 3px 3px 1px 1px; min-height: 2px; }
.u-chart__x { display: flex; justify-content: space-between; margin-top: var(--s2); font-size: 11.5px; color: var(--ink-3); }
.u-k1 { background: var(--brand); }
.u-k2 { background: var(--brand-40); }
.u-k3 { background: var(--brand-20); }
.u-k4 { background: var(--harm); }

/* ---------- Meters ---------- */
.u-meter { margin-bottom: var(--s4); }
.u-meter__t { display: flex; justify-content: space-between; gap: var(--s3); font-size: 13px; margin-bottom: 6px; }
.u-meter__t span { color: var(--ink-3); font-variant-numeric: tabular-nums; }
.u-meter__b { height: 8px; border-radius: var(--r-pill); background: var(--sunk); overflow: hidden; }
.u-meter__b i { display: block; height: 100%; background: var(--brand); border-radius: var(--r-pill); }
.u-meter.is-warn .u-meter__b i { background: var(--caution); }
.u-meter.is-full .u-meter__b i { background: var(--harm); }

/* ---------- Modal ---------- */
.u-modal { position: fixed; inset: 0; z-index: 90; display: flex; align-items: center; justify-content: center; padding: var(--s4); }
.u-modal[hidden] { display: none; }
.u-modal__s { position: absolute; inset: 0; background: rgba(20,18,14,.5); }
.u-modal__p {
    position: relative; width: 100%; max-width: 440px;
    background: var(--paper); border-radius: var(--r3); box-shadow: var(--lift-2);
    padding: var(--s5); border: 1px solid var(--line);
    /* A long form used to run off the bottom of the screen with no way to
       reach its buttons. It scrolls inside itself instead. The dynamic
       viewport unit accounts for a phone's address bar appearing. */
    max-height: calc(100dvh - 32px);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
}
@media (max-width: 620px) {
    /* On a phone the dialog takes the bottom of the screen the way a sheet
       does, so its actions land under the thumb rather than off-screen. */
    .u-modal { align-items: flex-end; padding: 0; }
    .u-modal__p {
        max-width: none; max-height: 88dvh;
        border-radius: var(--r3) var(--r3) 0 0; border-bottom: none;
        padding: var(--s5) var(--s4) 0;
    }
    /* The buttons stay put while the fields scroll behind them. */
    .u-modal__a {
        position: sticky; bottom: 0;
        margin: var(--s4) calc(var(--s4) * -1) 0;
        padding: var(--s3) var(--s4) calc(var(--s3) + env(safe-area-inset-bottom));
        background: var(--paper); border-top: 1px solid var(--line);
    }
}
.u-modal__p h3 { font-size: 17px; margin-bottom: var(--s2); }
.u-modal__p p { margin: 0; color: var(--ink-2); font-size: 13.5px; line-height: 1.6; }
.u-modal__a { display: flex; gap: var(--s2); justify-content: flex-end; margin-top: var(--s5); }

/* ---------- Toast ---------- */
.u-toasts { position: fixed; right: var(--s4); bottom: var(--s4); z-index: 95; display: flex; flex-direction: column; gap: var(--s2); }
.u-toast {
    display: flex; align-items: center; gap: var(--s2);
    padding: var(--s3) var(--s4); border-radius: var(--r2);
    background: var(--paper); border: 1px solid var(--line); box-shadow: var(--lift-2);
    font-size: 13.5px; font-weight: 600;
}
.u-toast--good { color: var(--good); }
.u-toast--harm { color: var(--harm); }

/* ---------- Narrow screens ----------
   The table becomes a stack of labelled rows rather than a second
   design: same markup, same components, laid out for one column. */
@media (max-width: 760px) {
    .u-metrics > * { flex-basis: calc(50% - var(--s3)); }
    .u-card__h, .u-card__b, .u-filters, .u-pager { padding-left: var(--s4); padding-right: var(--s4); }
    .u-t thead { display: none; }
    .u-t, .u-t tbody, .u-t tr, .u-t td { display: block; width: 100%; }
    .u-t tr { border-bottom: 1px solid var(--line); padding: var(--s3) 0; }
    .u-t td { border: none; padding: 5px var(--s4); display: flex; justify-content: space-between; gap: var(--s4); }
    .u-t td::before {
        content: attr(data-label);
        font-size: 11.5px; font-weight: 650; color: var(--ink-3); flex: none;
    }
    .u-t td.ta-right, .u-t td.ta-center { text-align: left; }
    .u-pager { flex-direction: column; align-items: flex-start; }
}
@media (max-width: 480px) {
    .u-metrics > * { flex-basis: 100%; }
}
@media (prefers-reduced-motion: reduce) {
    .u-skel__c, .u-skel__l { animation: none; }
    * { transition: none !important; }
}

/* Cell that pairs an avatar with a name and a second line. */
.u-cell { display: flex; align-items: center; gap: var(--s2); text-decoration: none; color: inherit; }
.u-cell > .u-av { margin-right: var(--s2); }
.u-cell b { display: block; font-weight: 620; }
.u-cell em { display: block; font-style: normal; font-size: 11.5px; color: var(--ink-3); }
.u-sort { color: inherit; text-decoration: none; }
.u-sort:hover { color: var(--brand-ink); }
.u-check { width: 16px; height: 16px; accent-color: var(--brand); }

/* Bulk bar. Hidden until something is selected — it is never in the way
   of the ordinary case of just reading the list. */
.u-bulk {
    display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap;
    padding: var(--s2) var(--s5); background: var(--brand-05);
    border-bottom: 1px solid var(--line-2); font-size: 13px;
}
.u-bulk > * { margin-right: var(--s2); }
.u-bulk[hidden] { display: none; }

/* ---------- Tile grid, used by segments, forms, integrations ---------- */
.p-grid { display: flex; flex-wrap: wrap; gap: var(--s4); align-items: flex-start; }
.p-grid > * { flex: 1 1 320px; min-width: 0; margin-bottom: 0; }
.p-tile__h { display: flex; align-items: center; justify-content: space-between; gap: var(--s3); margin-bottom: var(--s3); }
.p-tile__h h3 { font-size: 15px; }
.p-rules { list-style: none; margin: 0 0 var(--s3); padding: 0; }
.p-rules li { padding: 6px 0; border-bottom: 1px solid var(--line-2); font-size: 12.5px; color: var(--ink-2); }
.p-rules li:last-child { border-bottom: none; }
.p-rules b { color: var(--ink); font-weight: 620; }

/* ---------- Automation nodes ---------- */
.a-flow { margin: var(--s3) 0; }
.a-node { padding: var(--s2) var(--s3); border-radius: var(--r2); background: var(--sunk); margin-bottom: 6px; position: relative; }
.a-node em { display: block; font-style: normal; font-size: 10.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3); }
.a-node b { font-size: 13px; font-weight: 600; }
.a-node--t { background: var(--brand-05); }
.a-node--a { background: var(--good-bg); }

/* ---------- Campaign wizard ---------- */
.w-steps { display: flex; gap: var(--s1); overflow-x: auto; margin-bottom: var(--s4); padding-bottom: var(--s1); }
.w-step { display: flex; align-items: center; gap: var(--s2); flex: none; padding: 8px var(--s3);
          border-radius: var(--r2); background: var(--sunk); color: var(--ink-3);
          text-decoration: none; font-size: 12.5px; font-weight: 620; white-space: nowrap; }
.w-step > i { margin-right: var(--s2); }
.w-step i { display: grid; place-items: center; width: 20px; height: 20px; border-radius: 50%;
            background: var(--paper); font-style: normal; font-size: 11px; }
.w-step.is-on { background: var(--brand); color: var(--on-brand); }
.w-step.is-on i { background: rgba(0,0,0,.15); }
.w-step.is-done { background: var(--brand-05); color: var(--brand-ink); }
.w-pick { display: flex; align-items: center; gap: var(--s3); padding: var(--s3); border: 1px solid var(--line);
          border-radius: var(--r2); margin-bottom: var(--s2); cursor: pointer; }
.w-pick > input { margin-right: var(--s3); accent-color: var(--brand); }
.w-pick:hover { border-color: var(--brand); }
.w-pick span { flex: 1; min-width: 0; }
.w-pick b { display: block; font-size: 13.5px; }
.w-pick em { display: block; font-style: normal; font-size: 12px; color: var(--ink-3); }
.w-hint { margin: 0; padding-left: var(--s4); color: var(--ink-2); font-size: 13px; line-height: 1.8; }
.w-hint b { color: var(--ink); }

/* ---------- Sequences ---------- */
.q-line { display: flex; gap: var(--s2); overflow-x: auto; padding-bottom: var(--s2); }
.q-step { flex: 1 1 160px; min-width: 150px; padding: var(--s3); border-radius: var(--r2);
          background: var(--sunk); border-left: 3px solid var(--brand); }
.q-step i { display: block; font-style: normal; font-size: 10.5px; font-weight: 700;
            letter-spacing: .06em; text-transform: uppercase; color: var(--brand-ink); }
.q-step b { display: block; margin-top: 3px; font-size: 13px; font-weight: 600; }

/* ---------- Integrations ---------- */
.g-top { display: flex; align-items: center; gap: var(--s3); }
.g-top > .g-mark { margin-right: var(--s3); }
.g-mark { display: grid; place-items: center; width: 40px; height: 40px; flex: none;
          border-radius: var(--r2); background: var(--brand-10); color: var(--brand-ink); font-weight: 700; font-size: 13px; }
.g-top h3 { font-size: 14.5px; }
.g-top > div { flex: 1; min-width: 0; }

/* ---------- Templates preview ---------- */
.t-prev { padding: var(--s4); border-radius: var(--r3); background: var(--sunk); }
.t-bub { background: var(--paper); border-radius: var(--r3); padding: var(--s3); box-shadow: var(--lift-1); font-size: 13.5px; }
.t-h { display: block; margin-bottom: var(--s1); }
.t-bub p { margin: 0; line-height: 1.6; }
.t-f { display: block; margin-top: var(--s2); font-style: normal; font-size: 11.5px; color: var(--ink-3); }
.t-b { border-top: 1px solid var(--line-2); margin-top: var(--s2); padding-top: var(--s1); }
.t-b span { display: block; padding: 6px; text-align: center; color: var(--brand-ink); font-weight: 620; font-size: 12.5px; }

/* ---------- Webhooks, code ---------- */
.u-code { font-family: ui-monospace, Menlo, monospace; font-size: 12px; background: var(--sunk);
          padding: 2px 7px; border-radius: var(--r1); word-break: break-all; }
.w-hook { padding: var(--s3) 0; border-bottom: 1px solid var(--line-2); }
.w-hook:last-child { border-bottom: none; }
.w-hook__t { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap; margin-bottom: var(--s1); }
.w-hook__t > * { margin-right: var(--s2); }
.w-hook__e { display: flex; flex-wrap: wrap; gap: 6px; margin: var(--s2) 0; }
.w-hook__e > * { margin-right: 6px; margin-bottom: 6px; }
.d-code { background: var(--sunk); padding: var(--s3); border-radius: var(--r2); font-size: 12px;
          overflow-x: auto; margin: 0; line-height: 1.7; }
.d-ep { padding: var(--s3) var(--s5); display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap; }
.d-ep > * { margin-right: var(--s3); }
.d-ep p { flex: 1 1 200px; margin: 0; }
.d-m { padding: 3px 9px; border-radius: var(--r1); font-size: 11px; font-weight: 700; letter-spacing: .04em; }
.d-m--get { background: var(--info-bg); color: var(--info); }
.d-m--post { background: var(--good-bg); color: var(--good); }

/* ---------- Notifications ---------- */
.n-list { list-style: none; margin: 0; padding: 0; }
.n-list li { border-bottom: 1px solid var(--line-2); }
.n-list li:last-child { border-bottom: none; }
.n-list a { display: flex; align-items: flex-start; gap: var(--s3); padding: var(--s3) var(--s5); text-decoration: none; color: inherit; }
.n-list a > .n-dot { margin-right: var(--s3); }
.n-list li.is-new { background: var(--brand-05); }
.n-dot { display: grid; place-items: center; width: 30px; height: 30px; flex: none; border-radius: 50%; background: var(--sunk); color: var(--ink-2); }
.n-dot--success { background: var(--good-bg); color: var(--good); }
.n-dot--error { background: var(--harm-bg); color: var(--harm); }
.n-dot--warn { background: var(--caution-bg); color: var(--caution); }
.n-b { flex: 1; min-width: 0; }
.n-b b { display: block; font-size: 13.5px; font-weight: 620; }
.n-b span { display: block; font-size: 12.5px; color: var(--ink-2); }
.n-t { flex: none; font-size: 11.5px; color: var(--ink-3); }

/* ---------- Contact detail, settings ---------- */
.c-head { display: flex; align-items: center; gap: var(--s4); margin-bottom: var(--s4); }
.c-head > .u-av { margin-right: var(--s4); }
.c-head h2 { font-size: 20px; }
.c-head p { margin: 3px 0 0; }
.set-nav { display: flex; flex-direction: column; gap: 2px; }
.set-nav a { padding: 8px var(--s3); border-radius: var(--r2); text-decoration: none;
             color: var(--ink-2); font-size: 13.5px; font-weight: 570; }
.set-nav a:hover { background: var(--sunk); color: var(--ink); }
.set-nav a.is-on { background: var(--brand-05); color: var(--brand-ink); font-weight: 650; }

/* On a phone the settings nav is a scrolling strip, not a column. Wrapping
   cut "Business profile" in half and left Notifications, Security and Data
   unreachable off the right edge. Placed here, beside the rule it
   overrides, so it does not depend on stylesheet order. */
@media (max-width: 760px) {
    .set-nav, .u-tabs {
        flex-direction: row; flex-wrap: nowrap;
        overflow-x: auto; gap: var(--s2);
        scrollbar-width: none; -webkit-overflow-scrolling: touch;
        /* Pulled out to the card's edges and given the padding back
           inside, so the strip scrolls all the way rather than stopping
           short of the edge. The negative margin must equal the card's
           padding at this width — s4 — or the last tab is cut mid-word,
           which is what happened to "Drafts".

           There were two rules doing this, mine written later without
           noticing this one; the two disagreed and the later one only
           sometimes won. One rule now. */
        /*
         * No negative margin.
         *
         * Pulling the strip out to the card's edges makes the element wider
         * than the card, and since the card has a rounded border the strip
         * visibly spills past it — which is the tab hanging outside, and
         * why "Drafts" appeared beyond the corner. Kept inside the padding
         * box instead: it still scrolls, it simply starts and ends where
         * the card does.
         */
        margin: 0 0 var(--s4);
        padding: 0 0 var(--s2);
        max-width: 100%;
    }
    .u-tabs > .u-tab { flex: none; white-space: nowrap; }
    .set-nav::-webkit-scrollbar, .u-tabs::-webkit-scrollbar { display: none; }
    .set-nav a, .u-tabs a {
        flex: 0 0 auto; white-space: nowrap;
        padding: 7px var(--s3); border-radius: var(--r-label);
        font-size: 13px; border-bottom: none; border-left: none;
    }
    .set-nav a.is-on, .u-tabs a.is-on {
        background: var(--brand-05); color: var(--brand-ink);
        border-bottom: none; border-left: none;
    }
}
.set-tog { display: flex; align-items: center; gap: var(--s3); padding: 9px 0; border-bottom: 1px solid var(--line-2); font-size: 13.5px; }
.set-tog > input { margin-right: var(--s3); accent-color: var(--brand); width: 16px; height: 16px; }
.set-tog:last-of-type { border-bottom: none; }
.b-plan { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s3); margin-bottom: var(--s3); }
.b-plan b { font-size: 19px; }
.b-plan span { font-size: 17px; font-weight: 650; }
.b-plan em { font-style: normal; font-size: 12px; font-weight: 500; color: var(--ink-3); }
.u-ph { display: block; width: 32px; height: 32px; border-radius: var(--r1); background: var(--sunk); flex: none; }

@media (max-width: 760px) {
  .set-nav { flex-direction: row; overflow-x: auto; }
  .c-head { gap: var(--s3); }
}

/* The contact fields a template may use, offered as buttons so a variable
   is never typed from memory. */
.t-vars { display: flex; flex-wrap: wrap; gap: 6px; margin: calc(var(--s2) * -1) 0 var(--s4); }
.t-vars > * { margin-right: 6px; margin-bottom: 6px; }
.t-var { font-family: ui-monospace, Menlo, monospace; font-size: 11.5px; padding: 4px 9px; }

/* ---------- Toasts ----------
   Bottom right, above the phone tab bar, and they leave on their own —
   except an error, which waits to be dismissed because it should be read. */
.u-toasts { position: fixed; right: var(--s4); bottom: var(--s4); z-index: 95;
            display: flex; flex-direction: column; gap: var(--s2); max-width: min(380px, calc(100vw - 32px)); }
.u-toast {
    display: flex; align-items: center; gap: var(--s2);
    padding: var(--s3) var(--s4); border-radius: var(--r2);
    background: var(--paper); border: 1px solid var(--line);
    box-shadow: var(--lift-2); font-size: 13.5px; font-weight: 600;
    animation: u-toast-in .22s ease;
}
.u-toast > .u-i { margin-right: var(--s2); flex: none; }
.u-toast span { flex: 1; min-width: 0; }
.u-toast--good { color: var(--good); border-color: var(--good-bg); }
.u-toast--harm { color: var(--harm); border-color: var(--harm-bg); }
.u-toast.is-going { opacity: 0; transform: translateY(6px); transition: opacity .24s, transform .24s; }
.u-toast__x { border: none; background: none; color: inherit; opacity: .55; cursor: pointer; padding: 2px; display: flex; }
.u-toast__x:hover { opacity: 1; }
@keyframes u-toast-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@media (max-width: 760px) { .u-toasts { bottom: 84px; left: var(--s4); right: var(--s4); max-width: none; } }

/* The confirmation dialog gets an icon, so the weight of what is about to
   happen is visible before the words are read. */
.u-confirm__i {
    width: 42px; height: 42px; border-radius: 50%; margin-bottom: var(--s3);
    display: flex; align-items: center; justify-content: center;
    background: var(--harm-bg); color: var(--harm);
}
.u-modal__p h3 { margin-bottom: var(--s2); }

/* ---------- A list on a phone shows only what identifies a row ----------
   The stacked table repeated every column as a labelled line, so one
   contact filled the screen and two were a scroll. A row here has one job:
   let you recognise the person and tap through. Everything else belongs on
   the page you tap into.

   Columns opt in with data-key; the rest are hidden on a narrow screen. */
@media (max-width: 760px) {
    .u-t--brief tr { display: flex; flex-wrap: wrap; align-items: center; gap: 0 var(--s2); padding: var(--s3) var(--s4); }
    .u-t--brief td { display: none; padding: 0; }
    .u-t--brief td[data-brief] { display: block; }
    .u-t--brief td::before { content: none; }
    .u-t--brief td[data-brief="main"] { flex: 1 1 100%; }
    .u-t--brief td[data-brief="sub"] { color: var(--ink-3); font-size: 12.5px; }
    .u-t--brief td[data-brief="tag"] { margin-left: auto; }
    .u-t--brief td[data-brief="pick"] { flex: none; order: -1; margin-right: var(--s2); }
    .u-t--brief .u-cell em { display: none; }
}

/* The placeholder name shown beside a profile field, so it is obvious what
   a template would write there. */
/* The placeholder goes under its label, not beside it. Beside it, a long
   one like {{preferred_language}} wrapped into the value column and the row
   read as two broken lines. */
.c-var {
    display: block; width: fit-content; max-width: 100%;
    margin: 3px 0 0; font-size: 10.5px; opacity: .75;
    overflow-wrap: anywhere;
}
/* The label column gets room for two lines without squeezing the value.
   Marked with a class rather than :has(), which is too new to depend on
   for layout that must not break on an older phone. */
/* Written as .s-kv.s-kv--var rather than .s-kv--var alone. The base .s-kv
   rule lives in shell.css, which loads after this file, so a single-class
   selector here loses to it on source order. Two classes wins on
   specificity instead, and no longer depends on which file loads first. */
.s-kv.s-kv--var { align-items: flex-start; }
.s-kv.s-kv--var > span { flex: 1 1 55%; min-width: 0; }
.s-kv.s-kv--var > b { flex: 0 1 auto; text-align: right; min-width: 0; overflow-wrap: anywhere; }

@media (max-width: 620px) {
    /* On a phone there is no room for a label, its placeholder and a value
       side by side — the value was pushed off the right edge. The row
       stacks: what the field is, what a template writes there, then the
       value, all left aligned. */
    .s-kv.s-kv--var { display: block; }
    .s-kv.s-kv--var > span { display: block; }
    .s-kv.s-kv--var > b { display: block; text-align: left; margin-top: 3px; font-size: 14.5px; }
}
.c-note { padding: var(--s4) var(--s5); }
.c-note__h { display: flex; align-items: center; gap: var(--s2); margin-bottom: var(--s2); }
.c-note__h > * { margin-right: var(--s2); }
.c-note__b { font-size: 13.5px; line-height: 1.6; white-space: pre-wrap; }
.c-note__edit textarea { margin-bottom: var(--s2); }

/* A phone number is a country and a number, side by side. The same shape
   the rest of the installation uses, so a field looks the same wherever
   somebody types a number. */
.u-phone { display: flex; gap: var(--s2); align-items: stretch; }
.u-phone .phone-cc-select {
    flex: 0 0 auto; width: auto; min-width: 108px; max-width: 44%;
    padding: 9px 26px 9px 10px; font-size: 13.5px;
    border: 1px solid var(--line); border-radius: var(--r2);
    background: var(--paper) var(--chev) no-repeat right 8px center;
    background-size: 14px; appearance: none; color: var(--ink);
}
.u-phone input[type="tel"] { flex: 1; min-width: 0; }
@media (max-width: 420px) { .u-phone .phone-cc-select { min-width: 92px; font-size: 12.5px; } }

/* A secret: masked value, an eye to reveal it, a copy button. */
.u-sec { display: inline-flex; align-items: center; gap: 6px; max-width: 100%; }
.u-sec__v {
    flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    font-size: 12px;
}
.u-sec.is-open .u-sec__v { color: var(--brand-ink); }
.u-sec__d { letter-spacing: 1px; opacity: .55; }
.u-sec__b {
    flex: none; border: 1px solid var(--line); background: var(--paper);
    border-radius: var(--r-label); padding: 4px 6px; cursor: pointer;
    color: var(--ink-2); display: inline-flex;
}
.u-sec__b:hover { background: var(--sunk); color: var(--ink); }
.u-sec__b:disabled { opacity: .5; cursor: default; }


/* The settings navigation column. On a desktop it is a narrow sidebar; on a
   phone it is a full-width strip that scrolls sideways. Stated here rather
   than inline on the element, so the phone rule can actually win. */
.s-col-nav { order: -1; max-width: 220px; }
@media (max-width: 760px) {
    .s-col-nav {
        max-width: none; width: 100%;
        /* Pulled out to the screen edges, cancelling the body's padding,
           so the strip runs off the side rather than stopping short. */
        margin: 0 calc(var(--s4) * -1) var(--s3);
        padding: 0;
    }
    .s-col-nav .set-nav { padding-left: var(--s4); padding-right: var(--s4); margin: 0; }
}

/* A secret inside a table cell has to be allowed to shrink, or the copy
   button is pushed past the edge of a phone. */
.u-t td .u-sec { max-width: 100%; }
@media (max-width: 760px) {
    .u-t--brief td[data-brief="sub"] .u-sec { width: 100%; }
    .u-t--brief td[data-brief="sub"] .u-sec__v { flex: 1 1 auto; min-width: 0; font-size: 11.5px; }
    /* The delete button goes under the row rather than beside it: three
       controls on one line is what pushed it off the screen. */
    .u-t--brief td[data-brief="tag"] { flex: 1 1 100%; margin-left: 0; margin-top: 6px; }
}

/* The button rows in the template builder, and the preview's own buttons. */
.t-btnrow { align-items: flex-end; }
.t-prevbtns { margin-top: 8px; border-top: 1px solid var(--line-2); padding-top: 8px;
              display: flex; flex-direction: column; gap: 4px; }
.t-prevbtn { display: flex; align-items: center; justify-content: center; gap: 5px;
             padding: 5px 9px; border-radius: var(--r-label);
             background: var(--sunk); color: var(--brand-ink); font-size: 12px; font-weight: 620; }
@media (max-width: 620px) { .t-btnrow { display: block; } .t-btnrow .u-field { margin-bottom: 8px; } }

/* The city picker: a text box with its own list underneath. */
.u-city { position: relative; }
.u-city__q.is-bad { border-color: var(--caution); }
.u-city__list {
    position: absolute; z-index: 40; top: calc(100% + 4px); left: 0; right: 0;
    max-height: 240px; overflow-y: auto;
    background: var(--paper); border: 1px solid var(--line);
    border-radius: var(--r2); box-shadow: var(--lift-2); padding: 4px;
}
.u-city__list button {
    display: flex; align-items: baseline; gap: var(--s2); width: 100%;
    padding: 8px 10px; border: none; background: none; border-radius: var(--r-label);
    text-align: left; cursor: pointer; font-size: 13.5px; color: var(--ink);
}
.u-city__list button > b { margin-right: var(--s2); font-weight: 620; }
.u-city__list button span { font-size: 11.5px; color: var(--ink-3); }
.u-city__list button:hover, .u-city__list button.is-on { background: var(--brand-05); }
.u-city__note { margin: 4px 0 0; font-size: 11.5px; color: var(--caution); }

/* The message-and-OK dialog. Narrower than a form dialog and centred, so it
   reads as an answer rather than as another thing to fill in. */
.u-modal__p--alert { max-width: 380px; text-align: center; }
.u-modal__p--alert h3 { margin-bottom: var(--s2); }
.u-modal__p--alert p { color: var(--ink-2); font-size: 14px; line-height: 1.55; }
.u-alert__i {
    width: 44px; height: 44px; border-radius: 50%; margin: 0 auto var(--s3);
    display: flex; align-items: center; justify-content: center;
}
.u-alert__i.is-good { background: var(--good-bg); color: var(--good); }
.u-alert__i.is-harm { background: var(--harm-bg); color: var(--harm); }
.u-modal__p--alert .u-modal__a { margin-top: var(--s4); }
@media (max-width: 620px) {
    /* Centred rather than a bottom sheet: this one is read, not filled in. */
    .u-modal:has(.u-modal__p--alert) { align-items: center; padding: var(--s4); }
    .u-modal__p--alert { border-radius: var(--r3); padding: var(--s5) var(--s4); }
    .u-modal__p--alert .u-modal__a { position: static; margin: var(--s4) 0 0; padding: 0; border-top: none; background: none; }
}

/* Three choices stack, because they are not equal: saving is the likely
   one, leaving loses work, staying is the escape. Side by side they read
   as interchangeable. */
.u-modal__a--stack { flex-direction: column; gap: var(--s2); }
.u-modal__a--stack .u-btn { width: 100%; }

/* One button per group, so three rows of boxes read as three buttons
   rather than nine unrelated fields. */
.t-btn {
    border: 1px solid var(--line); border-radius: var(--r2);
    padding: var(--s3) var(--s3) 2px; margin-bottom: var(--s3);
}
.t-btn > legend {
    padding: 0 6px; font-size: 12px; font-weight: 700;
    color: var(--ink-2); text-transform: uppercase; letter-spacing: .04em;
}
.t-btn > legend span { font-weight: 500; text-transform: none; letter-spacing: 0; color: var(--ink-3); }

/* ---------- The template preview ----------
   Built to match what arrives on a phone, because a preview that looks
   roughly right is worse than none: it is trusted, and then the real
   message does not match it. WhatsApp puts quick replies outside the
   bubble as separate chips and website/call buttons inside it under a
   divider, so this does too. */
.t-phone {
    max-width: 320px; margin: 0 auto;
    border: 1px solid var(--line); border-radius: 18px; overflow: hidden;
    background: #ECE5DD;
}
.t-phone__bar {
    display: flex; align-items: center; gap: 8px;
    padding: 10px var(--s3); background: #075E54; color: #fff;
}
.t-phone__bar > .u-i { color: rgba(255,255,255,.85); }
.t-phone__av {
    width: 30px; height: 30px; border-radius: 50%;
    background: rgba(255,255,255,.25); color: #fff;
    display: flex; align-items: center; justify-content: center;
    font-size: 13px; font-weight: 700; flex: none;
}
.t-phone__bar b { display: block; font-size: 13.5px; line-height: 1.2; }
.t-phone__bar em { font-style: normal; font-size: 11px; opacity: .8; }

.t-phone__chat { padding: var(--s3); display: flex; flex-direction: column; align-items: flex-start; gap: 5px; }

.t-bub {
    position: relative; max-width: 92%;
    background: #fff; border-radius: 8px; border-top-left-radius: 0;
    padding: 7px 9px 5px; box-shadow: 0 1px 1px rgba(0,0,0,.13);
    font-size: 14px; line-height: 1.45; color: #111B21;
}
.t-bub .t-h { display: block; font-weight: 700; margin-bottom: 3px; }
.t-bub .t-body { margin: 0; white-space: pre-wrap; word-break: break-word; }
.t-bub .t-f { display: block; margin-top: 5px; font-style: normal; font-size: 12px; color: #667781; }
.t-bub > time {
    display: flex; justify-content: flex-end; align-items: center; gap: 3px;
    margin-top: 2px; font-size: 10.5px; color: #667781;
}
.t-bub > time > .u-i { color: #53BDEB; }

/* A website or call button: inside the bubble, above a hairline divider. */
.t-cta {
    display: flex; align-items: center; justify-content: center;
    /* Same breathing room as the thread: the message ends, then the things
       you can do about it begin. */
    margin: 8px -9px 0; padding: 9px 8px 4px;
    border-top: 1px solid #E9EDEF;
    color: #027EB5; font-size: 13.5px; font-weight: 500;
}
.t-cta + .t-cta { margin-top: 0; }

/* The plans, listed where somebody is deciding between them. A dropdown of
   three names and three prices does not say what separates them. */
.b-plans { margin-top: var(--s3); display: grid; gap: var(--s2); }
.b-plan {
    border: 1px solid var(--line); border-radius: var(--r2);
    padding: var(--s3); font-size: 13.5px;
}
.b-plan > b { display: inline-block; margin-right: var(--s2); }
.b-plan > span { color: var(--brand-ink); font-weight: 620; }
.b-plan > em { display: block; margin-top: 3px; font-style: normal; color: var(--ink-2); font-size: 12.5px; }

/* Tags, picked rather than typed. A typed tag is a tag misspelt, and the
   whole point of giving them ids was that "customer" and "Customer" stop
   being two different groups. */
.u-tagpick { display: flex; flex-wrap: wrap; gap: 6px; }
.u-tagpick__i {
    display: inline-flex; align-items: center;
    padding: 6px 12px; border-radius: var(--r-label);
    border: 1px solid var(--line); background: var(--paper);
    font-size: 13px; cursor: pointer; user-select: none;
}
.u-tagpick__i input { position: absolute; opacity: 0; pointer-events: none; }
.u-tagpick__i:has(input:checked) {
    background: var(--brand-05); border-color: var(--brand); color: var(--brand-ink); font-weight: 620;
}
.u-tagpick__i:hover { background: var(--sunk); }

/* The tag list page. */
.t-grid { display: grid; gap: var(--s3); grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }
.t-card { border: 1px solid var(--line); border-radius: var(--r3); background: var(--paper); padding: var(--s4); }
.t-card__h { display: flex; align-items: center; gap: var(--s2); margin-bottom: var(--s2); }
.t-card .u-help { margin: 0; }

/*
 * A guaranteed gap, not one that depends on flex `gap`.
 *
 * The label was a bare text node beside the icon's <svg> — no element of
 * its own — and `gap` between an element and a raw text node is exactly
 * the pairing some renderers do not space correctly, wkhtmltoimage's
 * WebKit among them. The icon and word rendered touching: "↩I want
 * support" with no space at all.
 *
 * Wrapping the label in its own <span> and using a margin on the icon
 * works everywhere, old engines included, because it does not depend on
 * gap recognising a bare text node as a flex item.
 *
 * A quick reply is now drawn with this same class, at Deepak's request,
 * rather than as WhatsApp's own separate chip — see the comment beside
 * $allBtns in templates.php.
 */
.t-cta > .u-i { margin-right: 6px; }

/* ---------- The template list ----------
   Built for what somebody scans for: the name, what the message says, and
   whether it can be sent. A generic six-column table turned into six
   stacked key-value rows on a phone, so one template filled the screen and
   comparing two meant scrolling. */
.tpl-list { display: flex; flex-direction: column; }
.tpl-row {
    display: block; padding: var(--s3) var(--s4);
    border-bottom: 1px solid var(--line);
    color: inherit; text-decoration: none;
}
.tpl-row:last-child { border-bottom: 0; }
.tpl-row:hover { background: var(--sunk); }
.tpl-row.is-on { background: var(--brand-05); box-shadow: inset 3px 0 0 var(--brand); }

.tpl-row__h { display: flex; align-items: center; gap: var(--s2); }
.tpl-row__h > b { font-size: 14.5px; color: var(--ink); flex: 1; min-width: 0;
                  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* The message itself, two lines at most: enough to tell two templates apart
   without letting a long one push the next out of view. */
.tpl-row__b {
    margin: 3px 0 6px; font-size: 12.5px; line-height: 1.45; color: var(--ink-2);
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* Everything else on one quiet line, separated by dots rather than by
   labels — "Utility · English · Updated 7 Sep" needs no headings. */
.tpl-row__m { display: flex; flex-wrap: wrap; gap: 4px 10px; font-size: 11.5px; color: var(--ink-3); }
.tpl-row__m > span + span::before { content: '·'; margin-right: 10px; color: var(--line-2); }
.tpl-row__d { margin-left: auto; }
@media (max-width: 480px) { .tpl-row__d { margin-left: 0; } }

/* The share link on a form card. The URL is long and must not push the
   card wide, so it clips with an ellipsis and the full value sits in the
   title and in the copy button. */
.p-link { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; margin: var(--s3) 0 0; }
.p-link__u { flex: 1; min-width: 0; font-size: 12px; color: var(--ink-2); font-family: ui-monospace, monospace;
             overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.p-link em { flex-basis: 100%; font-size: 11.5px; color: var(--caution); font-style: normal; }

/* Install app: revealed by assets/js/pwa.js once the browser offers it.
   .u-btn sets display:inline-flex, which overrides the [hidden] attribute's
   display:none, so without this the button would never hide. */
.u-btn[hidden], [data-pwa-install][hidden] { display: none; }
