/* Application look, after Supabase's dashboard: top bar, icon rail, optional submenu column and the pane. Colours are variables with a dark mode. */

/*
 * Google Sans Flex (SIL Open Font License), self-hosted so visitors' IP addresses are not sent to Google.
 * One variable font per character set with all axes: weight 1-1000, width 25-151%, slant 0-10deg,
 * optical size, grade and roundness (the last three through font-variation-settings: opsz, GRAD, ROND).
 */
@font-face {
    font-family: "Google Sans Flex";
    font-style: oblique 0deg 10deg;
    font-weight: 1 1000;
    font-stretch: 25% 151%;
    font-display: swap;
    src: url("fonts/google-sans-flex/google-sans-flex-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;
}

@font-face {
    font-family: "Google Sans Flex";
    font-style: oblique 0deg 10deg;
    font-weight: 1 1000;
    font-stretch: 25% 151%;
    font-display: swap;
    src: url("fonts/google-sans-flex/google-sans-flex-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;
}

:root {
    --bg: #fcfcfc;
    --surface: #f8f8f8;
    --hover: #f1f1f1;
    --selected: #e8e8e8;
    --border: #dfdfdf;
    --border-muted: #ededed;
    --input: #ffffff;
    --text: #171717;
    --text-soft: #525252;
    --muted: #707070;
    --brand: #3ecf8e;
    --brand-border: #34b27b;
    --brand-text: #0b2a1c;
    --brand-strong: #1f8a5a;
    --focus: rgba(62, 207, 142, 0.35);
    --warning-bg: rgba(245, 158, 11, 0.14);
    --warning-text: #9a5b06;
    --error-bg: #fdecec;
    --error-text: #a32020;
    --sensitive-bg: rgba(124, 92, 246, 0.12);
    --sensitive-manual-bg: rgba(124, 92, 246, 0.24);
    --sensitive-line: rgba(124, 92, 246, 0.6);
    --shadow: 0 8px 24px rgba(0, 0, 0, 0.08), 0 1px 3px rgba(0, 0, 0, 0.06);
    --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
    font-family: "Google Sans Flex", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    font-size: 14px;
    color: var(--text);
    color-scheme: light dark;
}

@media (prefers-color-scheme: dark) {
    :root {
        --bg: #171717;
        --surface: #121212;
        --hover: #222222;
        --selected: #2b2b2b;
        --border: #2e2e2e;
        --border-muted: #242424;
        --input: #1f1f1f;
        --text: #ededed;
        --text-soft: #c4c4c4;
        --muted: #a0a0a0;
        --brand-strong: #3ecf8e;
        --focus: rgba(62, 207, 142, 0.4);
        --warning-text: #f5b544;
        --error-bg: #3d1a1a;
        --error-text: #f4b4b4;
        --sensitive-bg: rgba(167, 139, 250, 0.16);
        --sensitive-manual-bg: rgba(167, 139, 250, 0.3);
        --sensitive-line: rgba(167, 139, 250, 0.7);
        --shadow: 0 8px 24px rgba(0, 0, 0, 0.5), 0 1px 3px rgba(0, 0, 0, 0.4);
    }

    /* Emails set their own colours, mostly black text, unreadable on the dark page: in the dark mode their text and
       backgrounds follow the theme instead, as Outlook does. The light mode shows the sender's colours. */
    .mail-html,
    .mail-html *:not(mark.sensitive) {
        background-color: transparent !important;
        color: var(--text) !important;
    }

    .mail-html a,
    .mail-html a * {
        color: var(--brand-strong) !important;
    }
}

*,
*::before,
*::after {
    box-sizing: border-box;
}

body {
    margin: 0;
    background: var(--bg);
}

.muted {
    color: var(--muted);
}

/* Application layout: fills the browser window; only the submenu and the pane scroll, never the window itself.
   100dvh follows Safari's visible height when its toolbars appear or hide; 100vh is the fallback. */

.app {
    display: flex;
    flex-direction: column;
    height: 100vh;
    height: 100dvh;
    overflow: hidden;
}

.topbar {
    display: flex;
    align-items: center;
    gap: 10px;
    height: 48px;
    flex-shrink: 0;
    padding: 0 16px;
    border-bottom: 1px solid var(--border);
}

.topbar__brand {
    display: flex;
    color: var(--brand);
    font-size: 20px;
    text-decoration: none;
}

.topbar__separator {
    color: var(--border);
    font-size: 20px;
    font-weight: 300;
}

.topbar__context {
    font-weight: 500;
}

.topbar__user {
    margin-left: auto;
}

.app__content {
    flex: 1;
    display: flex;
    min-height: 0;
}

/* Icon rail, as each agent chooses (RailMode, the menu at its bottom): rail--hover is narrow and widens over the
   content on hover or keyboard focus to show the names (the default); rail--expanded is always wide and takes its
   place; rail--collapsed is always narrow, the names as tooltips. */

.rail {
    position: relative;
    width: 56px;
    flex-shrink: 0;
}

.rail__nav {
    position: absolute;
    inset: 0 auto 0 0;
    display: flex;
    flex-direction: column;
    z-index: 20;
    width: 56px;
    padding: 8px;
    overflow: hidden;
    background: var(--surface);
    border-right: 1px solid var(--border);
    transition: width 0.15s ease, box-shadow 0.15s ease;
}

/* The short delay keeps the rail from opening when the pointer only passes over it. Only with a mouse (a tap on a
   touch screen counts as hovering) or the keyboard (:focus-visible, not the focus a tap leaves). */
@media (hover: hover) {
    .rail--hover .rail__nav:hover {
        width: 220px;
        box-shadow: var(--shadow);
        transition-delay: 0.1s;
    }

    .rail--hover .rail__nav:hover .rail__label {
        opacity: 1;
    }
}

/* Also while the rail's own menu is open, so its panel does not cover the names. */
.rail--hover .rail__nav:has(:focus-visible),
.rail--hover .rail__nav:has(.rail__mode[open]) {
    width: 220px;
    box-shadow: var(--shadow);
    transition-delay: 0.1s;
}

.rail--expanded,
.rail--expanded .rail__nav {
    width: 220px;
}

.rail--expanded .rail__label,
.rail--hover .rail__nav:has(.rail__mode[open]) .rail__label {
    opacity: 1;
}

/* The menu of the rail's behaviour opens beside the rail; fixed, as the rail clips what sticks out of it. */
.rail__mode summary {
    list-style: none;
    cursor: pointer;
}

.rail__mode summary::-webkit-details-marker {
    display: none;
}

.rail__mode .menu__panel {
    position: fixed;
    top: auto;
    right: auto;
    bottom: 12px;
    left: 228px;
}

.rail--collapsed .rail__mode .menu__panel {
    left: 64px;
}

.rail__mode .menu__item[aria-pressed="false"] .rail__mode-check {
    visibility: hidden;
}

.rail__list {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin: 0;
    padding: 0;
    list-style: none;
}

/* The second list (settings) sits at the bottom of the rail. */
.rail__list--bottom {
    margin-top: auto;
}

.rail__item {
    display: flex;
    align-items: center;
    gap: 12px;
    height: 38px;
    padding: 0 10px;
    border-radius: 6px;
    color: var(--muted);
    text-decoration: none;
    white-space: nowrap;
}

.rail__item .fa-fw {
    flex-shrink: 0;
    font-size: 18px;
}

.rail__item:hover {
    background: var(--hover);
    color: var(--text);
}

.rail__item:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: -2px;
}

.rail__item.is-active {
    background: var(--selected);
    color: var(--text);
}

/* The icon with, for Tickets, a small badge at its top right with the number of open tickets. */
.rail__icon {
    position: relative;
    display: inline-flex;
    flex-shrink: 0;
}

.rail__badge {
    position: absolute;
    top: -7px;
    right: -9px;
    box-sizing: border-box;
    min-width: 17px;
    height: 17px;
    padding: 0 4px;
    border: 2px solid var(--surface);
    border-radius: 9px;
    background: var(--brand);
    color: var(--brand-text);
    font-family: var(--mono);
    font-size: 10px;
    font-weight: 600;
    line-height: 13px;
    text-align: center;
}

/* Transparent rather than hidden, so screen readers still read the names while the rail is narrow. */
.rail__label {
    opacity: 0;
    transition: opacity 0.1s ease;
}

.rail--hover .rail__nav:has(:focus-visible) .rail__label {
    opacity: 1;
}

/* Submenu column: the sections of the chosen part, grouped under small monospace headings. */

.submenu {
    width: 240px;
    flex-shrink: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    background: var(--surface);
    border-right: 1px solid var(--border);
}

/* Its text level with the rail's first icon as well (its middle 27px down), with the same height as before. */
.submenu__title {
    margin: 0;
    padding: 17px 24px 11px;
    border-bottom: 1px solid var(--border);
    font-size: 17px;
    font-weight: 400;
}

/* A main action above the submenu's groups, such as "Nieuw ticket". */
.submenu__action {
    padding: 12px 16px 0;
}

.submenu__action .button--block {
    margin-top: 0;
}

.submenu__group {
    padding: 16px 0;
    border-bottom: 1px solid var(--border);
}

.submenu__heading {
    margin: 0 0 8px;
    padding: 0 24px;
    color: var(--muted);
    font-family: var(--mono);
    font-size: 12px;
    font-weight: 400;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.submenu__list {
    margin: 0;
    padding: 0;
    list-style: none;
}

.submenu__item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin: 0 12px;
    padding: 6px 12px;
    border-radius: 6px;
    color: var(--text-soft);
    text-decoration: none;
}

.submenu__item:hover {
    background: var(--hover);
    color: var(--text);
}

.submenu__item:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: -2px;
}

.submenu__item.is-active {
    background: var(--selected);
    color: var(--text);
    font-weight: 500;
}

.submenu__count {
    color: var(--muted);
    font-family: var(--mono);
    font-size: 12px;
    font-weight: 400;
}

.submenu__icon {
    color: var(--muted);
}

/* Pane: page title and subtitle, then the content. */

/* Positioned, so absolutely positioned content (visually hidden labels, file inputs) is placed inside the pane
   and cannot stretch the window; overscroll-behavior keeps Safari from scrolling the window at the pane's end. */
.pane {
    position: relative;
    flex: 1;
    min-width: 0;
    overflow: auto;
    overscroll-behavior: contain;
}

/* The title's line lies level with the rail's first icon: the rail starts at the same height, and its first item's
   middle is 27px down (8px padding, half of 38px), as is the title's (11px padding, half of the 32px title line).
   The actions on the right are centred on that line too. */
.pane__header {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px 24px;
    padding: 11px 24px 20px;
    border-bottom: 1px solid var(--border);
}

/* The ticket page and the ticket list keep their header at the top of the pane while the content scrolls under it:
   on a ticket the subject, status and side-panel button; on the list the views and the create button. The pane is
   the scroll container, so the header sticks to its top; the page background hides the content behind it, below the
   side panel (z-index 20) so an opened panel still covers it. */
/* Every page keeps its header (the title, its actions and, on the search page, the search bar) at the top of the pane
   while the body scrolls under it. The pane is the scroll container, so the header sticks to its top; the page
   background hides the content behind it, below the side panel (z-index 20) so an opened panel still covers it. */
.pane__header {
    position: sticky;
    top: 0;
    z-index: 10;
    background: var(--bg);
}

/* A header that carries a full-width extra row (pane_header_extra, such as the search bar) wraps to fit it, also on
   wide screens where the title and actions otherwise stay on one line. */
.pane__header:has(.pane__header-extra) {
    flex-wrap: wrap;
}

.pane__header-extra {
    flex: 0 0 100%;
    min-width: 0;
}

.pane__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    min-height: 32px;
}

/* Every button and select in the header has the height of the title's line, whatever its icon or font. */
.pane__actions .button,
.pane__actions .form__input {
    box-sizing: border-box;
    height: 32px;
    padding-top: 0;
    padding-bottom: 0;
}

.pane__actions .button--icon {
    width: 32px;
}

/* A split button in the header (Aanmaken with its menu): its border counts towards the 32 pixels. */
.pane__actions .split .button {
    height: 30px;
}

/* One line: a title too long for it ends in an ellipsis, so the actions beside it stay on the line. */
.pane__title {
    min-width: 0;
    margin: 0;
    overflow: hidden;
    font-size: 24px;
    font-weight: 400;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* A title with a button after it (a ticket's subject and its pencil): the text is cut, the button stays. */
.pane__title:has([data-subject-text]) {
    display: flex;
    align-items: center;
}

.pane__title [data-subject-text] {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* The heading never gets wider than the header, so its title can be cut on a phone too. */
.pane__heading {
    min-width: 0;
    max-width: 100%;
}

/* On wider screens the heading takes the room the actions leave, and the actions never move to a line of their
   own; on a phone they may. */
@media (min-width: 700px) {
    .pane__header {
        flex-wrap: nowrap;
    }

    .pane__heading {
        flex: 1 1 auto;
        min-width: 0;
    }

    .pane__actions {
        flex: 0 0 auto;
        flex-wrap: nowrap;
    }
}

/* The title with, when the page has one, the arrow back to its overview before it. */
.pane__titlebar {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    min-height: 32px;
}

.pane__back {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    margin-left: -8px;
    border-radius: 6px;
    color: var(--muted);
    font-size: 18px;
    text-decoration: none;
}

.pane__back:hover {
    background: var(--hover);
    color: var(--text);
}

.pane__subtitle {
    margin: 6px 0 0;
    color: var(--muted);
    font-size: 15px;
}

.pane__body {
    /* Lets parts of the page adapt to the width of the pane rather than of the window (@container below). */
    container-type: inline-size;
    padding: 16px 24px 48px;
}

/* Filters above a list, such as the audit log's. */
.filters {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 0 0 16px;
}

.filters .form__input {
    width: auto;
    min-width: 180px;
    margin: 0;
}

/* Audit log: the changed fields of an entry. */
.audit__changes {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    gap: 2px 12px;
    margin: 0;
    font-size: 13px;
}

.audit__changes dt {
    color: var(--muted);
}

.audit__changes dd {
    margin: 0;
    overflow-wrap: anywhere;
}

.audit__changes code {
    font-size: 12px;
}

.audit__ip {
    display: block;
    margin-top: 4px;
    font-family: var(--mono);
    font-size: 12px;
}

/* Notices: flash messages after an action. */

.notice {
    margin: 0 0 16px;
    padding: 9px 12px;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--surface);
}

.notice--success {
    border-color: var(--brand-border);
    background: var(--focus);
}

.notice--warning {
    border-color: transparent;
    background: var(--warning-bg);
    color: var(--warning-text);
}

.notice--warning a {
    color: inherit;
    font-weight: 500;
}

/* A message stored but not sent, during a trial; after .badge in weight, as that comes later in this file. */
.timeline__meta .badge--held {
    margin-left: 4px;
    background: var(--warning-bg);
    color: var(--warning-text);
}

.notice--error {
    border-color: transparent;
    background: var(--error-bg);
    color: var(--error-text);
}

/* Search field above a list. */

.search {
    position: relative;
    max-width: 420px;
    margin: 0 0 16px;
}

.search__icon {
    position: absolute;
    top: 50%;
    left: 11px;
    color: var(--muted);
    transform: translateY(-50%);
}

.search__input.form__input {
    margin: 0;
    padding-left: 34px;
}

/* Form sections: title and explanation above the fields, which start on the left. */

/* A form section uses the pane's full width: the title and explanation on the left, the fields on the right. In a
   narrow pane (@container below) the explanation goes above the fields. */
.section {
    display: grid;
    grid-template-columns: minmax(220px, 1fr) minmax(0, 2fr);
    gap: 0 48px;
    align-items: start;
    padding: 24px 0;
    border-bottom: 1px solid var(--border);
}

.section > :not(.section__intro) {
    grid-column: 2;
}

.section__intro {
    margin-bottom: 16px;
}

@container (max-width: 760px) {
    .section {
        grid-template-columns: minmax(0, 1fr);
    }

    .section > :not(.section__intro) {
        grid-column: 1;
    }
}

.section__title {
    margin: 0 0 4px;
    font-size: 15px;
    font-weight: 500;
}

.section__text {
    margin: 0;
    color: var(--muted);
    font-size: 13px;
    line-height: 1.5;
}

.section--danger .section__title {
    color: var(--error-text);
}

.field-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0 16px;
}

.field-grid__wide {
    grid-column: 1 / -1;
}

.field-grid--contact {
    grid-template-columns: 160px minmax(0, 1fr) auto;
    align-items: start;
}

/* A channel connection: its type names the provider too ("WhatsApp (Twilio)"), so it needs more room. On small
   screens the rule for contact rows below takes over. */
.field-grid--connection {
    grid-template-columns: 250px minmax(0, 1fr) auto;
}

/* A manager's own privacy pattern: name, pattern (widest) and the remove button. */
.field-grid--pattern {
    grid-template-columns: 220px minmax(0, 1fr) auto;
    align-items: start;
}

.field-grid--pattern .collection__remove {
    margin-top: 26px;
}

/* A pattern is code: in a fixed-width font. */
.form__input--mono {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* A field with its button on one line, such as adding a text to a list. */
.inline-form {
    display: flex;
    gap: 8px;
    margin-bottom: 16px;
}

.inline-form .form__input {
    flex: 1;
}

/* An agent's own Slack rule: field, where, the text (widest) and the remove button. */
.field-grid--rule {
    grid-template-columns: 150px 150px minmax(0, 1fr) auto;
    align-items: start;
}

/* Lines the remove button up with the inputs, below the labels, so an error message under a field moves nothing. */
.field-grid--contact .collection__remove,
.field-grid--rule .collection__remove {
    margin-top: 26px;
}

/* Name row: given name, a short surname prefix and the family name, which gets the most room. */
.field-grid--name {
    grid-template-columns: minmax(0, 1fr) 110px minmax(0, 1.4fr);
}

.field-grid--address {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* Mail server fields of an email connection: host, port and encryption on one line per server. */
.connection-settings {
    margin: 4px 0 8px;
    padding-top: 12px;
    border-top: 1px solid var(--border-muted);
}

/* One mail server (IMAP or SMTP) within an email connection. */
.server {
    margin: 0 0 4px;
    padding: 0;
    border: 0;
}

.server__title {
    margin: 0 0 8px;
    padding: 0;
    color: var(--muted);
    font-family: var(--mono);
    font-size: 12px;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.field-grid--server {
    grid-template-columns: minmax(0, 1fr) 90px 140px;
}

/* A web chat's opening hours: the days side by side as far as they fit. */
.field-grid--hours {
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}

.field__help + .field-grid--hours,
.server > .field__help + .field {
    margin-top: 16px;
}

.field__help {
    margin: 6px 0 0;
    color: var(--muted);
    font-size: 13px;
    line-height: 1.5;
}

/* Under "Actief" when a setting changed after the connection check (app.js). */
.field__help--warning {
    color: var(--warning-text);
}

/* A field after the help text of a connection's settings, such as a webhook address to copy. */
.connection-settings > .field__help + .field {
    margin-top: 16px;
}

/* Check of an email connection: button, explanation and the result per step. */
.connection-check {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
    margin: 4px 0 12px;
}


.connection-check__result {
    flex-basis: 100%;
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: 13px;
}

.connection-check__result:empty {
    display: none;
}

.connection-check__result li::before {
    margin-right: 6px;
    font-family: var(--mono);
}

.connection-check__result .is-ok {
    color: var(--brand-strong);
}

.connection-check__result .is-ok::before {
    content: "✓";
}

/* A working connection, such as the one with OpenAI under Settings → AI. */
.connection-status {
    margin: 0;
    color: var(--brand-strong);
}

.connection-check__result .is-error {
    color: var(--error-text);
}

.connection-check__result .is-error::before {
    content: "✗";
}


.button:disabled,
input:disabled + .check__label,
input:disabled {
    cursor: not-allowed;
    opacity: 0.5;
}

/* Modal dialog (native <dialog>), such as the result of a failed connection check. */
.dialog {
    width: min(480px, calc(100vw - 32px));
    padding: 20px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--bg);
    color: var(--text);
    box-shadow: var(--shadow);
}

.dialog::backdrop {
    background: rgba(0, 0, 0, 0.4);
}

.dialog__title {
    margin: 0 0 12px;
    font-size: 17px;
    font-weight: 500;
}

.dialog__text {
    margin: 0 0 20px;
    line-height: 1.55;
    /* A long web address in the question wraps instead of widening the dialog. */
    overflow-wrap: anywhere;
}

.dialog__list {
    margin: 0 0 20px;
    line-height: 1.6;
}

.dialog__actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
}

/* Opening a link in a message: a red warning sign before the title, the host in bold, the whole address small in
   a monospaced box, and a phishing warning in red when the link's text names another site. */
.link-dialog__icon {
    color: var(--error-text);
}

.link-dialog__line {
    margin: 0 0 6px;
}

.link-dialog__url {
    display: block;
    margin: 0 0 14px;
    padding: 8px 10px;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--surface);
    font-size: 12px;
    line-height: 1.5;
    overflow-wrap: anywhere;
}

.link-dialog__mismatch {
    color: var(--error-text);
    font-weight: 500;
}

/* Collections: rows that can be added and removed, such as a contact's contact methods. */

.collection__item {
    margin: 0 0 12px;
    padding: 12px 12px 4px;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--input);
}

.collection__options {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 16px;
    margin-bottom: 8px;
}

.collection__options .field {
    margin: 0;
}

/* The vCard types of a contact method or address, folded; open, the boxes take a line of their own. */
.collection__types summary {
    color: var(--muted);
    font-size: 13px;
    cursor: pointer;
}

.collection__types[open] {
    flex-basis: 100%;
    order: 1;
}

.collection__types .checks {
    margin-top: 6px;
}

.collection__remove {
    margin-bottom: 16px;
}

.collection__options .collection__remove {
    margin: 0 0 0 auto;
}

.collection + .button {
    margin-bottom: 4px;
}

/* Result of an import. */

.result {
    margin: 0 0 24px;
    padding: 16px;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--surface);
}

.result__title {
    margin: 0 0 12px;
    font-size: 15px;
    font-weight: 500;
}

.result__heading {
    margin: 16px 0 6px;
    font-size: 13px;
    font-weight: 500;
}

.result__list {
    margin: 0;
    padding-left: 18px;
    color: var(--text-soft);
}

.stats {
    display: flex;
    flex-wrap: wrap;
    gap: 32px;
    margin: 0;
}

.stats dt {
    color: var(--muted);
    font-size: 13px;
}

.stats dd {
    margin: 2px 0 0;
    font-family: var(--mono);
    font-size: 22px;
}

/* Drop-down menu on a <details> element; app.js closes it on a click elsewhere or Escape. */

.menu {
    position: relative;
}

.menu > summary {
    list-style: none;
    cursor: pointer;
}

.menu > summary::-webkit-details-marker {
    display: none;
}

.menu__panel {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 30;
    min-width: 200px;
    padding: 4px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 6px;
    box-shadow: var(--shadow);
}

.menu__heading {
    margin: 0 0 4px;
    padding: 8px 10px;
    border-bottom: 1px solid var(--border-muted);
    color: var(--muted);
    font-size: 13px;
}

.menu__item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 10px;
    border-radius: 4px;
    color: var(--text);
    text-decoration: none;
}

.menu__item:hover,
.menu__item:focus-visible {
    background: var(--hover);
    outline: none;
}

.avatar {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--text);
    color: var(--bg);
    font-size: 12px;
    font-weight: 600;
    user-select: none;
}

.avatar:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
}

/* Tables; wide tables scroll sideways inside .table-wrap instead of widening the page. */

/* Positioned, so hidden labels for screen readers (position: absolute) stay inside it instead of widening the page. */
.table-wrap {
    position: relative;
    overflow-x: auto;
}

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

.table th {
    padding: 8px 12px;
    white-space: nowrap;
    border-bottom: 1px solid var(--border);
    color: var(--muted);
    font-size: 13px;
    font-weight: 400;
    text-align: left;
}

.table td {
    padding: 10px 12px;
    border-bottom: 1px solid var(--border-muted);
    vertical-align: top;
}

.table tbody tr:hover {
    background: var(--hover);
}

.table__nowrap {
    white-space: nowrap;
}

/* A cell whose text is cut off with an ellipsis when it does not fit on one line, such as long titles; the cell
   takes its share of the table's width (max-width 0 lets it shrink below its text). */
.table .table__cut {
    max-width: 0;
    width: 25%;
}

.table .table__cut--wide {
    width: 45%;
}

.table__cut > * {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* A number column, right-aligned with digits of one width, such as a channel's number of tickets. */
.table .table__number {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* A sortable column heading: a link that sorts by the column, again for the other direction; the arrows show
   which column sorts the list and how. */
.table__sort {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: inherit;
    text-decoration: none;
}

.table__sort .fa-arrow-up-arrow-down {
    opacity: .35;
}

.table__sort:hover .fa-arrow-up-arrow-down {
    opacity: .8;
}

.table__sort.is-active {
    color: var(--text);
}

/* A table whose rows hold icons or buttons, such as the channel list: text and icons centred on one line. */
.table--middle td {
    vertical-align: middle;
}

/* A row of .table--links opens its link (app.js), so it shows the pointer. Each cell holds a link over its whole
   area (.table__cell-link, linkRows() in app.js); the links in a cell stay above it. */
.table--links tbody tr {
    cursor: pointer;
}

.table--links tbody td {
    position: relative;
}

.table__cell-link {
    position: absolute;
    inset: 0;
    z-index: 0;
}

/* Above it too: icons with a tooltip of their own (a status, an unanswered dot), so their tooltip still shows. */
.table--links tbody td a:not(.table__cell-link),
.table--links tbody td [title] {
    position: relative;
    z-index: 1;
}

/* Long text on one line, cut off with an ellipsis; the cell's title shows it in full. max-width: 0 lets the
   column shrink while the width gives it its share of the table. */
.table__truncate {
    width: 45%;
    max-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.table__truncate--narrow {
    width: 22%;
}

.table__link {
    color: var(--text);
    text-decoration: none;
}


/* Chips: small labels with an icon, such as a channel's connections; --off for an inactive one. */

.chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin: 0 6px 4px 0;
    padding: 2px 10px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--input);
    color: var(--text-soft);
    font-size: 13px;
    white-space: nowrap;
}

/* A channel's connections in the channel list: an icon each, with the details in its tooltip; a dashed, faded
   icon is switched off. */
.connection-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    margin: 2px 4px 2px 0;
    border: 1px solid var(--border);
    border-radius: 6px;
    vertical-align: middle;
}

.connection-icon--off {
    border-style: dashed;
    color: var(--muted);
    opacity: .6;
}

/* Numbered setup steps, such as those for 3CX under Settings → Telefonie. */
.steps {
    margin: 0 0 16px;
    padding-left: 20px;
    line-height: 1.6;
}

.steps li + li {
    margin-top: 8px;
}

.steps p {
    margin: 8px 0 0;
}

.steps__subtitle {
    margin-top: 24px;
}

/* A read-only value with a copy button beside it, such as a webhook address or a new API key. */
.copy-field {
    display: flex;
    align-items: center;
    gap: 6px;
}

.copy-field .form__input {
    flex: 1;
    min-width: 0;
    font-family: ui-monospace, monospace;
    font-size: 13px;
}

.chip--off {
    color: var(--muted);
    text-decoration: line-through;
}

/* Hidden on screen, read by screen readers. */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* Status badges, one modifier per TicketStatus value. */

.badge {
    display: inline-block;
    padding: 1px 8px;
    border-radius: 999px;
    background: var(--selected);
    color: var(--text-soft);
    font-size: 12px;
    white-space: nowrap;
}

.badge--open {
    background: var(--focus);
    color: var(--brand-strong);
}

.badge--pending {
    background: var(--warning-bg);
    color: var(--warning-text);
}

/* Unanswered ticket in a list: a dot before the subject, which is bold. */
.unanswered {
    display: inline-block;
    width: 8px;
    height: 8px;
    margin-right: 8px;
    border-radius: 50%;
    background: var(--brand);
    vertical-align: middle;
}

/* The exclamation mark of an important ticket in a list, before its subject. */
.importance--list {
    margin-right: 8px;
    vertical-align: middle;
}

/* The AI judged the message spam or phishing (UrgencySignaller). */
.ai-threat {
    margin-right: 6px;
    color: var(--error-text);
    vertical-align: middle;
}

/* The AI judged the contact upset (UrgencySignaller). */
.ai-upset {
    margin-right: 6px;
    color: var(--error-text);
    vertical-align: middle;
}

.ai-signal .fa-fw {
    margin-right: 4px;
}

.ai-signal p {
    margin: 0;
}

.ai-signal p + p {
    margin-top: 4px;
}

.table__link--unanswered {
    font-weight: 600;
}

/* Ticket search: a wide search field with its button, the filters in a row below it, then the results. */
.ticket-search__bar {
    position: relative;
    display: flex;
    gap: 8px;
}

.ticket-search__icon {
    position: absolute;
    top: 50%;
    left: 12px;
    color: var(--muted);
    transform: translateY(-50%);
    pointer-events: none;
}

.ticket-search__bar .ticket-search__input {
    flex: 1;
    margin: 0;
    padding-left: 36px;
}

/* The filters in their side panel, one below the other; the two dates side by side. */
.ticket-search {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.ticket-search__dates {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
}

/* The reset button takes the panel's whole width; the list fades while a search is under way. */
.ticket-search__reset {
    width: 100%;
    justify-content: center;
}

[data-live-list][aria-busy="true"] {
    opacity: 0.6;
    transition: opacity 0.15s ease 0.1s;
}

/* The filter button shows how many filters are set. */
.ticket-search__toggle {
    gap: 6px;
}

.ticket-search__active {
    min-width: 18px;
    padding: 0 5px;
    border-radius: 9px;
    background: var(--brand);
    color: var(--brand-text);
    font-size: 12px;
    line-height: 18px;
    text-align: center;
}

/* Every field, list and button of the search the same height, whatever the browser gives a date field or a
   select of its own. */
.ticket-search .form__input,
.ticket-search .button,
.ticket-search__bar .form__input,
.ticket-search__bar .button {
    box-sizing: border-box;
    height: 38px;
    padding-top: 0;
    padding-bottom: 0;
}

/* Safari puts the date of a date field of a fixed height at the top: a line as high as the field's inside
   (38 pixels less the borders) and no padding of its own centre it. */
.ticket-search input[type="date"] {
    min-width: 0;
    line-height: 36px;
}

.ticket-search input[type="date"]::-webkit-datetime-edit,
.ticket-search input[type="date"]::-webkit-date-and-time-value {
    padding: 0;
    line-height: 36px;
}

.ticket-search__filter {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.ticket-search__filter .form__input {
    width: 100%;
    margin: 0;
}

.ticket-search__label {
    color: var(--muted);
    font-size: 13px;
}

.ticket-search__check {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 38px;
    font-size: 14px;
}

.ticket-search__count,
.list-note {
    margin: 0 0 12px;
    font-size: 14px;
}

.list-note {
    margin-top: 16px;
}

/* Settings → Medewerkers: the agents table, and the search of LENS accounts to add. */
.table tr.is-inactive td {
    color: var(--muted);
}

.form__input.agents__role {
    width: auto;
    min-width: 150px;
    margin: 0;
}

.agents__actions {
    text-align: right;
}

.agents__search {
    display: flex;
    gap: 8px;
    margin-bottom: 12px;
}

.agents__search .form__input {
    flex: 1;
    margin: 0;
}

.agents__add .button {
    align-self: stretch;
}

.agents__results {
    margin: 0;
    padding: 0;
    list-style: none;
}

.agents__result {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px 16px;
    padding: 8px 0;
    border-bottom: 1px solid var(--border-muted);
}

.agents__add {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* Error pages */

.error__text {
    margin: 0 0 20px;
    color: var(--text-soft);
}

.error__text:has(+ .error__code) {
    margin-bottom: 8px;
}

.error__code {
    margin: 0 0 20px;
    color: var(--muted);
    font-family: var(--mono);
    font-size: 12px;
}

/* Ticket page: the timeline of messages with the contact and ticket details beside it. */


.timeline {
    display: flex;
    flex-direction: column;
    gap: 20px;
    margin: 0;
    padding: 0;
    list-style: none;
}

/* Each message: author, type, medium and time above the card that holds the message itself. */
.timeline__header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 2px 10px;
    min-width: 0;
    margin: 0 2px 6px;
    white-space: nowrap;
}

.timeline__card {
    padding: 14px 16px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--input);
}

/* Replies stand out in the brand colour, internal notes in yellow. */
.timeline__item--reply .timeline__card {
    border-left: 3px solid var(--brand);
}

.timeline__item--note .timeline__card {
    border-left: 3px solid var(--warning-text);
    background: var(--warning-bg);
}

/* Transcripts of phone calls (3CX) are set apart in a calm grey. */
.timeline__item--call .timeline__card {
    border-left: 3px solid var(--muted);
}

/* Automatic replies (out of office) are less important than what people wrote. */
.timeline__item--auto_reply .timeline__card {
    opacity: 0.75;
}

/* Forwards look like replies, with a dashed edge as they went to someone else than the contact. */
.timeline__item--forward .timeline__card {
    border-left: 3px dashed var(--brand);
}

/* Small text buttons in a message header and the reply form, such as "Forward", "Cc" and "Bcc". */
.timeline__action {
    flex-shrink: 0;
    padding: 2px 6px;
    border: 0;
    border-radius: 4px;
    background: none;
    color: var(--muted);
    font: inherit;
    font-size: 13px;
    cursor: pointer;
}

.timeline__action:hover,
.timeline__action:focus-visible {
    background: var(--hover);
    color: var(--text);
    outline: none;
}

/* Colleagues with the ticket open, above the messages; yellow while sending is blocked or a new message came in. */
.presence {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 12px 0 16px;
    padding: 10px 14px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface);
    color: var(--text-soft);
    font-size: 14px;
}

.presence[hidden],
.presence [hidden] {
    display: none;
}

.presence--warning {
    border-color: transparent;
    background: var(--warning-bg);
    color: var(--warning-text);
}

.presence__lines {
    flex: 1;
    min-width: 0;
}

.presence__lines p {
    margin: 0;
}

.presence .button {
    flex-shrink: 0;
}

/* Quoted earlier messages under the new text of an email: folded away behind a small button. */
.quoted {
    margin-top: 8px;
}

.quoted__toggle {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 2px 8px;
    border: 1px solid var(--border);
    border-radius: 999px;
    color: var(--muted);
    font-size: 13px;
    list-style: none;
    cursor: pointer;
}

.quoted__toggle::-webkit-details-marker {
    display: none;
}

.quoted__toggle:hover,
.quoted__toggle:focus-visible {
    background: var(--hover);
    color: var(--text);
    outline: none;
}

.quoted[open] .quoted__show,
.quoted:not([open]) .quoted__hide {
    display: none;
}

.quoted__body {
    margin-top: 10px;
    padding-left: 12px;
    border-left: 2px solid var(--border);
    color: var(--text-soft);
}

/* Who a reply or forward was sent to, under its header. */
.timeline__recipients {
    display: flex;
    flex-wrap: wrap;
    gap: 2px 14px;
    margin: -2px 2px 6px;
    font-size: 13px;
    overflow-wrap: anywhere;
}

/* Address field (app.js): chips of addresses with the typing input after them, drawn as one input, and the
   suggested contacts in a list below it. */
.address-field {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px;
    flex: 1;
    min-width: 0;
    min-height: 38px;
    padding: 3px 6px;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--input);
    cursor: text;
}

.address-field:focus-within {
    border-color: var(--brand-border);
    box-shadow: 0 0 0 3px var(--focus);
}

.address-field__chips {
    display: contents;
    margin: 0;
    padding: 0;
    list-style: none;
}

.address-field .chip,
.address-chip {
    margin: 0;
    padding: 1px 4px 1px 10px;
    color: var(--text);
    font-size: 13px;
}

/* A new contact (dashed), and text that is no email address (red). */
.address-chip--new {
    border-style: dashed;
    border-color: var(--brand-border);
}

.address-chip__badge {
    color: var(--brand-strong);
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
}

.address-chip--invalid {
    border-color: var(--error-text);
    background: var(--error-bg);
    color: var(--error-text);
}

.address-field__input {
    flex: 1;
    min-width: 140px;
    padding: 4px 2px;
    border: 0;
    background: transparent;
    color: var(--text);
    font: inherit;
    outline: none;
}

.address-field__suggestions {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    z-index: 30;
    margin: 0;
    padding: 4px;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--bg);
    box-shadow: var(--shadow);
    list-style: none;
}

.address-field__suggestions[hidden] {
    display: none;
}

.address-field__option {
    padding: 6px 10px;
    border-radius: 4px;
    font-size: 14px;
    cursor: pointer;
    overflow-wrap: anywhere;
}

.address-field__option:hover,
.address-field__option.is-active {
    background: var(--hover);
}

.address-field__option--typed {
    color: var(--brand-strong);
}

.address-field__option--hint,
.address-field__option--hint:hover {
    background: none;
    color: var(--muted);
    font-size: 13px;
    cursor: default;
}

/* The details of a new contact under the "to" field of a new ticket, shown while its address is unknown. */
.new-contact {
    margin: -2px 0 10px calc(var(--address-label, 36px) + 10px);
    padding: 12px 14px;
    border: 1px dashed var(--brand-border);
    border-radius: 6px;
}

.new-contact[hidden] {
    display: none;
}

.new-contact__title {
    margin: 0;
    font-weight: 500;
}

.new-contact .field__help {
    margin: 2px 0 10px;
}

.new-contact__fields {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 140px minmax(0, 1.4fr);
    gap: 10px;
}

.new-contact__field {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.new-contact__field .form__input {
    margin: 0;
}

@container (max-width: 760px) {
    .new-contact__fields {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* Reply form: the address fields above the editor, and the parts that differ between a reply and a forward. */
.reply__toggles {
    display: flex;
    gap: 2px;
    margin-left: auto;
}

/* Each open field keeps its own space below it, so the editor's toolbar never touches the last one and closed
   fields leave no gap. */
.reply__address {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 10px;
}

.reply__address[hidden] {
    display: none;
}

.reply__address-label {
    flex: 0 0 var(--address-label, 36px);
    color: var(--muted);
    font-size: 13px;
}

/* The new ticket form has longer labels (Kanaal, Onderwerp). */
.reply--new {
    --address-label: 80px;
    margin-top: 0;
}

/* A field with an error has a red edge, in every form: Symfony forms (.has-error), and the reply and new ticket
   forms, where the error (from the server or app.js) follows the field's row, the editor or the attachments field. */
.has-error .form__input,
.reply__address:has(+ .reply__error) .form__input,
.reply__address:has(+ .reply__error) .address-field,
.reply .jodit-container:not(.jodit_inline):has(+ .reply__error),
.attachments-field:has(+ .reply__error),
.agent-signature .jodit-container:not(.jodit_inline):has(+ .reply__error) {
    border-color: var(--error-text);
}

.has-error .form__input:focus,
.reply__address:has(+ .reply__error) .address-field:focus-within,
.reply .jodit-container:not(.jodit_inline):has(+ .reply__error):focus-within,
.agent-signature .jodit-container:not(.jodit_inline):has(+ .reply__error):focus-within {
    border-color: var(--error-text);
    box-shadow: 0 0 0 3px var(--error-bg);
}

/* An error under a field of the reply or new ticket form, from the server or from app.js: under the input,
   past the label; --wide under the editor or the attachments field. */
.form__errors.reply__error {
    margin: -4px 0 10px calc(var(--address-label, 36px) + 10px);
}

.form__errors.reply__error--wide {
    margin: 6px 0 0;
}

.reply__address-help {
    margin: -6px 0 10px calc(var(--address-label, 36px) + 10px);
}

.reply__address .form__input {
    margin: 0;
}

.reply__forwarding {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0 0 10px;
    padding: 8px 12px;
    border-radius: 6px;
    background: var(--focus);
    color: var(--brand-strong);
    font-size: 13px;
}

.reply__forwarding-text {
    flex: 1;
    min-width: 0;
}

.reply__forwarding .timeline__action {
    color: inherit;
}

.reply:not([data-forwarding]) .reply__forward-only,
.reply[data-forwarding] .reply__reply-only {
    display: none;
}

/* A reply by SMS, WhatsApp, Messenger or Instagram, or a note to a contact who cannot be answered: no copies; by SMS also
   no files, and a counter of characters and SMS parts. */
.reply--note-only:not([data-forwarding]) .reply__toggles,
.reply--note-only:not([data-forwarding]) .reply__addresses,
.reply--text:not([data-forwarding]) .reply__toggles,
.reply--text:not([data-forwarding]) .reply__addresses,
.reply--sms:not([data-forwarding]) .attachments-field {
    display: none;
}

.reply__window {
    margin-left: auto;
    font-size: 13px;
    white-space: nowrap;
}

/* A web chat visitor's state: a dot before it, green in the chat, grey away. */
.reply__chat {
    margin-left: auto;
    font-size: 13px;
    color: var(--muted);
    white-space: nowrap;
}

.reply__chat::before {
    content: "";
    display: inline-block;
    width: 8px;
    height: 8px;
    margin-right: 6px;
    border-radius: 50%;
    background: var(--muted);
    vertical-align: 1px;
}

.reply__chat--present::before,
.reply__chat--typing::before {
    background: var(--brand);
}

.reply__chat--typing {
    color: var(--text);
}

.reply__closed {
    margin: 16px 0 0;
    font-size: 14px;
}

/* The delivery of an SMS or WhatsApp message, after its time: grey checks, read in the brand colour. */
.delivery-status {
    margin-left: 4px;
    color: var(--muted);
}

.delivery-status--read {
    color: var(--brand-strong);
}

.reply__sms-count {
    margin: 4px 0 0;
    font-size: 13px;
}

/* The reply form under the messages: author line, editor, attachments field and buttons. */
.ticket__main {
    min-width: 0;
}

.reply {
    margin-top: 28px;
}

/* Jodit, the reply editor: its colours follow the application's. Set on :root because Jodit shows its popups
   (colours, links) outside the editor; ":root:root" wins from Jodit's own :root, whose stylesheet comes later. */
:root:root {
    --jd-color-background-default: var(--input);
    --jd-color-panel: var(--surface);
    --jd-color-border: var(--border);
    --jd-color-text: var(--text);
    --jd-dark-background-color: var(--input);
    --jd-dark-background-darknes: var(--surface);
    --jd-dark-toolbar-color: var(--surface);
    --jd-dark-text-color: var(--text);
    --jd-dark-border-color: var(--border);
    --jd-dark-icon-color: var(--text-soft);
}

.jodit.jodit_theme_dark,
.jodit_theme_dark .jodit-popup__content {
    --jd-color-border: var(--border);
}

/* The fields of Jodit's popups (a link's address and text): Jodit gives them a fixed white background while their
   text follows the theme, so in dark mode they were white on white. ":root:root" wins from Jodit's own rules, whose
   stylesheet comes later (also those of its dark theme). */
:root:root .jodit-ui-input__wrapper,
:root:root .jodit-ui-input__input,
:root:root .jodit-ui-text-area__wrapper,
:root:root .jodit-ui-text-area__input,
:root:root .jodit-ui-select__wrapper,
:root:root .jodit-ui-select__input {
    background-color: var(--input);
    color: var(--text);
}

:root:root .jodit-ui-input__wrapper,
:root:root .jodit-ui-text-area__wrapper,
:root:root .jodit-ui-select__wrapper {
    border-color: var(--border);
}

/* The confirming button of Jodit's popups ("Invoegen") in the application's colour instead of Jodit's blue. */
:root:root .jodit-ui-button_variant_primary,
:root:root .jodit-ui-button_variant_primary:hover:not([disabled]),
:root:root .jodit-ui-button_variant_primary:active:not([disabled]) {
    background-color: var(--brand);
    color: var(--brand-text);
}

:root:root .jodit-ui-button_variant_primary svg {
    fill: var(--brand-text);
    stroke: var(--brand-text);
}

.reply .jodit-toolbar__box:not(:empty),
.agent-signature .jodit-toolbar__box:not(:empty) {
    border-color: var(--border);
    background: var(--surface);
}

/* Jodit, the reply editor: borders and corners like the other fields. */
.reply .jodit-container:not(.jodit_inline),
.agent-signature .jodit-container:not(.jodit_inline) {
    border-color: var(--border);
    border-radius: 8px;
    /* The toolbar and the writing area have square backgrounds that would cover the rounded corners; Jodit's
       popups and the canned answers picker are placed outside the container, so nothing is cut off. */
    overflow: hidden;
}

/* A reply by SMS, Messenger or Instagram is plain text (app.js): no toolbar, and the writing area takes its place
   (Jodit sets the heights inline, from the editor's height minus the toolbar). By WhatsApp only bold, italic and
   the canned answers. */
.reply--plain:not([data-forwarding]) .jodit-toolbar__box,
.reply--whatsapp:not([data-forwarding]) .jodit-toolbar-button:not(.jodit-toolbar-button_bold, .jodit-toolbar-button_italic, .jodit-toolbar-button_canned),
.reply--whatsapp:not([data-forwarding]) .jodit-ui-separator {
    display: none;
}

.reply--plain:not([data-forwarding]) .jodit-workplace,
.reply--plain:not([data-forwarding]) .jodit-wysiwyg {
    min-height: 218px !important;
}

.reply .jodit-container:not(.jodit_inline):focus-within,
.agent-signature .jodit-container:not(.jodit_inline):focus-within {
    border-color: var(--brand-border);
    box-shadow: 0 0 0 3px var(--focus);
}

/* The colour popup of the editor's text and background colour buttons. */
.editor-colours {
    display: grid;
    grid-template-columns: repeat(5, 22px);
    gap: 6px;
    padding: 8px;
}

.editor-colours__swatch {
    width: 22px;
    height: 22px;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: 4px;
    cursor: pointer;
}

.editor-colours__swatch:hover {
    outline: 2px solid var(--brand);
    outline-offset: 1px;
}

.reply .jodit-workplace,
.agent-signature .jodit-workplace {
    font: inherit;
    line-height: 1.55;
}

/* Paragraphs as in the messages above (.mail-html): no space above, so typing starts at the top of the editor
   rather than one browser margin lower. */
.reply .jodit-wysiwyg p,
.agent-signature .jodit-wysiwyg p {
    margin: 0 0 0.8em;
}

.reply .jodit-wysiwyg a,
.agent-signature .jodit-wysiwyg a {
    color: var(--brand-strong);
}

/* The attachments field under the editor: chips of the files, a button and room to drop files. */
.attachments-field {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 12px;
    margin-top: 8px;
    padding: 10px 12px;
    border: 1px dashed var(--border);
    border-radius: 8px;
}

.attachments-field.is-dragging {
    border-color: var(--brand-border);
    background: var(--focus);
}

.attachments-field__list {
    display: contents;
    margin: 0;
    padding: 0;
    list-style: none;
}

.attachments-field .chip {
    margin: 0;
}

.attachments-field__add {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--text-soft);
    cursor: pointer;
}

.attachments-field__add:hover {
    color: var(--text);
}

.attachments-field__add:focus-within {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
}

.attachments-field__hint {
    color: var(--muted);
    font-size: 13px;
}

.chip__remove {
    padding: 0 2px;
    border: 0;
    background: none;
    color: var(--muted);
    cursor: pointer;
}

.chip__remove:hover {
    color: var(--error-text);
}

.reply__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    margin-top: 12px;
}

/* Every button in the row has the same fixed height, whatever its content: Safari measures the send button's icon
   and its menu toggle (a summary element) differently from plain text. */
.reply__actions > .button,
.reply__actions .split {
    box-sizing: border-box;
    height: 34px;
}

.reply__actions .split .button {
    height: 100%;
}

.reply__notice {
    margin: 8px 0 0;
    font-size: 13px;
    text-align: right;
}

/* A switch of a connection below its help text, such as taking in comments. */
.connection-option {
    margin-top: 16px;
}

/* Above the editor of an answer to a public comment: it is visible to everyone. */
.reply__public {
    margin: 0 0 8px;
    font-size: 13px;
    color: var(--warning-text);
}

/* Split button: one button with the main action and, behind a thin divider, a menu with variants of it. The
   outer element draws the button; its two parts only differ on hover. */
.split {
    display: inline-flex;
    align-items: stretch;
    border: 1px solid var(--brand-border);
    border-radius: 6px;
    background: var(--brand);
}

.split .button {
    border: 0;
    border-radius: 0;
    background: transparent;
    color: var(--brand-text);
}

.split .button:hover {
    background: var(--brand-border);
}

.split .split__main {
    border-radius: 5px 0 0 5px;
}

/* A plain split button, such as "Nieuw ticket" on a contact's pages. */
.split--plain {
    border-color: var(--border);
    background: var(--input);
}

.split--plain .button {
    color: var(--text);
}

.split--plain .button:hover {
    background: var(--hover);
}

.split--plain .split__menu {
    border-left-color: var(--border);
}

.split__menu {
    display: flex;
    border-left: 1px solid rgba(0, 0, 0, 0.18);
}

.split .split__toggle {
    align-items: center;
    padding: 6px 9px;
    border-radius: 0 5px 5px 0;
}

.split__menu .menu__panel--up {
    top: auto;
    bottom: calc(100% + 6px);
    min-width: 240px;
}

.menu__item {
    width: 100%;
    border: 0;
    background: none;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

/* A message that came in while the ticket was open: briefly marked, then like the others. */
.timeline > .is-new .timeline__card {
    animation: new-message 3s ease-out;
}

@keyframes new-message {
    from {
        box-shadow: 0 0 0 2px var(--brand);
    }

    to {
        box-shadow: 0 0 0 2px transparent;
    }
}

/* The preview of an attachment: a large window over the page with the file, its name and buttons above it. */
.preview {
    width: min(1100px, calc(100vw - 32px));
    height: min(900px, calc(100vh - 32px));
    padding: 0;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--bg);
    color: var(--text);
    box-shadow: var(--shadow);
}

.preview[open] {
    display: flex;
    flex-direction: column;
}

.preview::backdrop {
    background: rgba(0, 0, 0, 0.6);
}

.preview__header {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 12px;
    border-bottom: 1px solid var(--border);
}

.preview__header form {
    margin: 0;
}

.preview__title {
    flex: 1;
    min-width: 0;
    margin: 0;
    overflow: hidden;
    font-size: 15px;
    font-weight: 500;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.preview__body {
    display: flex;
    flex: 1;
    align-items: center;
    justify-content: center;
    min-height: 0;
    padding: 12px;
    background: var(--surface);
}

.preview__file--image,
.preview__file--video {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

.preview__file--pdf,
.preview__file--text {
    width: 100%;
    height: 100%;
    border: 0;
    border-radius: 4px;
    background: #ffffff;
}

.preview__file--audio {
    width: min(480px, 100%);
}

/* The header lines of an email, folded away; for when something about an email is odd. */
.raw-headers {
    margin-top: 12px;
    font-size: 12px;
}

.raw-headers summary {
    color: var(--muted);
    cursor: pointer;
}

.raw-headers pre {
    max-height: 320px;
    margin: 8px 0 0;
    padding: 10px;
    overflow: auto;
    border-radius: 6px;
    background: var(--surface);
    font-family: var(--mono);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* The header stays on one line: the author's name gives way first, with an ellipsis. */
.timeline__author {
    min-width: 0;
    overflow: hidden;
    font-weight: 500;
    text-overflow: ellipsis;
}

.timeline__header .badge {
    flex-shrink: 0;
}

.timeline__meta {
    flex-shrink: 0;
    margin-left: auto;
    color: var(--muted);
    font-size: 13px;
}

.timeline__body {
    line-height: 1.55;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.inline-images {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 12px 0 0;
}

/* Images that were part of the email itself, such as a logo in a signature; never wider than the message. */
.inline-images img {
    max-width: 100%;
    max-height: 320px;
    border-radius: 4px;
}

/* Sanitised email HTML: no styles of its own are left, so it follows the application's colours. */
.mail-html {
    white-space: normal;
}

.mail-html p {
    margin: 0 0 0.8em;
}

.mail-html img {
    max-width: 100%;
    height: auto;
}

/* An image in its place in a plain-text email (where Apple Mail marked it in the text). */
.timeline__image {
    max-width: 100%;
    height: auto;
    vertical-align: bottom;
}

/* Images whose source was removed (from other hosts) take no space. */
.mail-html img:not([src]) {
    display: none;
}

.mail-html a {
    color: var(--brand-strong);
}

.mail-html table {
    max-width: 100%;
    border-collapse: collapse;
}

/* Newsletters lay out with tables of a fixed width (width="600") and columns side by side: on a narrow screen the
   tables take the width there is and their cells come below each other, as in a mail app; whatever still does not
   fit scrolls inside the message instead of widening the page. */
@media (max-width: 720px) {
    .mail-html {
        overflow-x: auto;
    }

    .mail-html table,
    .mail-html tbody,
    .mail-html tr,
    .mail-html td,
    .mail-html th {
        display: block;
        width: 100% !important;
        box-sizing: border-box;
    }
}

.mail-html blockquote {
    margin: 0.8em 0;
    padding-left: 12px;
    border-left: 3px solid var(--border);
    color: var(--muted);
}

.mail-html pre {
    white-space: pre-wrap;
}

.attachments {
    display: flex;
    flex-wrap: wrap;
    margin: 12px 0 0;
    padding: 0;
    list-style: none;
}

.attachments .chip {
    color: var(--text-soft);
    text-decoration: none;
}

.attachments .chip:hover {
    background: var(--hover);
}

/* An attachment as a split chip: the name downloads (after a warning), the arrow opens a menu with "download" and
   "add to reply". The outer element draws the chip, like the split send button; the menu opens below the chip. */
.chip-split {
    position: relative;
    display: inline-flex;
    align-items: stretch;
    margin: 0 6px 4px 0;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--input);
}

.chip-split .chip {
    margin: 0;
    border: 0;
    background: transparent;
}

.chip-split .chip-split__main {
    padding-right: 8px;
    border-radius: 999px 0 0 999px;
}

.chip-split__menu {
    position: static;
    display: flex;
    border-left: 1px solid var(--border);
}

.chip-split .chip-split__toggle {
    height: 100%;
    padding: 0 8px 0 6px;
    border-radius: 0 999px 999px 0;
    font-size: 10px;
}

.chip-split .chip:hover,
.chip-split__menu[open] .chip-split__toggle {
    background: var(--hover);
}

.chip-split .menu__panel {
    left: 0;
    right: auto;
    top: calc(100% + 4px);
}

/* A blocked attachment (Settings → Bijlagen): listed, but not offered. */
.chip--blocked {
    color: var(--muted);
    cursor: not-allowed;
}

/* Side panel with the contact and ticket details: it slides in over the content from the right, below the pane's
   header (top: --side-panel-top, set by app.js), like the rail on the left. */
.side-panel {
    position: fixed;
    top: var(--side-panel-top, 48px);
    right: 0;
    bottom: 0;
    z-index: 20;
    display: flex;
    flex-direction: column;
    gap: 12px;
    width: min(320px, calc(100vw - 32px));
    padding: 16px;
    overflow: auto;
    background: var(--surface);
    border-left: 1px solid var(--border);
    box-shadow: var(--shadow);
    transform: translateX(100%);
    visibility: hidden;
    transition: transform 0.15s ease, visibility 0s linear 0.15s;
}

.side-panel.is-open {
    transform: none;
    visibility: visible;
    transition: transform 0.15s ease;
}

.side-panel__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

.side-panel__title {
    margin: 0;
    font-size: 15px;
    font-weight: 500;
}

/* While the panel is open, its button looks pressed. */
.side-panel__toggle[aria-expanded="true"] {
    background: var(--selected);
    color: var(--text);
}

.side-card {
    padding: 14px 16px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface);
}

.side-card__title {
    margin: 0 0 8px;
    color: var(--muted);
    font-family: var(--mono);
    font-size: 12px;
    font-weight: 400;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.side-card__name {
    margin: 0 0 6px;
    font-weight: 500;
}

.side-card__name a {
    color: var(--text);
}

/* A link on a line of the card, such as to all of the contact's tickets: in the text's colour, underlined on hover. */
.side-card__line a {
    color: var(--text);
    text-decoration: none;
}

.side-card__line a:hover {
    text-decoration: underline;
}

.side-card__line {
    margin: 2px 0;
    font-size: 13px;
    overflow-wrap: anywhere;
}

.side-card__list {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    /* Each label on the line of its value's text, also beside a select. */
    align-items: baseline;
    gap: 6px 12px;
    margin: 0;
    font-size: 13px;
}

.side-card__list dt {
    color: var(--muted);
}

.side-card__list dd {
    margin: 0;
}

/* Priority and status of a ticket, side by side above it. */
.status-form {
    display: flex;
    gap: 8px;
}

.status-form .form__input {
    width: auto;
    margin: 0;
}




/* An important message (high priority): a red exclamation mark beside its type. */
.importance {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--error-bg);
    color: var(--error-text);
    font-size: 10px;
}

/* "With high priority" in the send menu, and its mark on the send button while ticked. */
.menu__check {
    gap: 10px;
    margin-top: 4px;
    padding-top: 10px;
    border-top: 1px solid var(--border-muted);
    border-radius: 0 0 4px 4px;
    cursor: pointer;
}

.split__important {
    display: none;
    margin-left: 2px;
    font-size: 11px;
}

.reply:has(input[name="important"]:checked) .split__important {
    display: inline;
}


/* A message that bounced: who could not be reached and why, at the top of its card. */
.delivery-failure {
    display: flex;
    gap: 10px;
    margin: -4px 0 14px;
    padding: 10px 12px;
    border-radius: 6px;
    background: var(--error-bg);
    color: var(--error-text);
    font-size: 14px;
}

.delivery-failure p {
    margin: 0;
}

.delivery-failure__title {
    font-weight: 600;
}

.delivery-failure__time {
    font-weight: 400;
}

.delivery-failure .delivery-failure__diagnostic {
    margin-top: 4px;
    font-family: var(--mono);
    font-size: 12px;
    overflow-wrap: anywhere;
}



/* What happened to a message, before its author (MessageType::icon()): came in, replied, forwarded, note. */
.direction {
    flex-shrink: 0;
    margin-right: -4px;
    color: var(--muted);
    font-size: 13px;
}

.direction--auto_reply {
    opacity: 0.6;
}

/* Login page */

.auth {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    padding: 24px 16px;
}

.auth__panel {
    width: 100%;
    max-width: 360px;
}

/* Logging in with a passkey, below the login form. A browser that used a passkey before starts with the passkey only:
   the form and "or" are hidden until the link asks for the password. */
.auth__panel--passkey .form,
.auth__panel--passkey .auth__or {
    display: none;
}

.auth__other {
    display: none;
    width: 100%;
    margin-top: 12px;
    padding: 4px;
    border: 0;
    background: none;
    color: var(--muted);
    font: inherit;
    font-size: 13px;
    text-decoration: underline;
    cursor: pointer;
}

.auth__panel--passkey .auth__other {
    display: block;
}

.auth__or {
    margin: 16px 0 8px;
    color: var(--muted);
    font-size: 13px;
    text-align: center;
}

/* The second step after the password (templates/mfa): the choices to set one up, the QR code of an authenticator app,
   and plain links below. */
.auth__panel .form + .form,
.auth__passkey + .form,
.auth__panel form + form {
    margin-top: 16px;
}

.mfa-choices {
    display: grid;
    gap: 12px;
}

.mfa-choice {
    padding: 16px;
    border: 1px solid var(--border);
    border-radius: 8px;
}

.mfa-choice__title {
    margin: 0 0 4px;
    font-size: 15px;
    font-weight: 500;
}

.mfa-choice .muted {
    margin: 0 0 12px;
    font-size: 13px;
}

.mfa-qr {
    display: block;
    margin: 0 auto 12px;
    padding: 8px;
    border-radius: 8px;
    background: #fff;
}

.mfa-secret {
    margin-bottom: 16px;
}

.mfa-secret .form__input {
    margin: 0;
    font-size: 12px;
}

.mfa-links {
    margin: 16px 0 0;
    text-align: center;
}

.mfa-link {
    padding: 4px;
    border: 0;
    background: none;
    color: var(--muted);
    font: inherit;
    font-size: 13px;
    text-decoration: underline;
    cursor: pointer;
}

/* An agent's passkeys under Mijn instellingen. */
.passkeys {
    margin: 0 0 16px;
    padding: 0;
    list-style: none;
}

.passkeys__item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 0;
    border-bottom: 1px solid var(--border-muted);
}

.passkeys__name {
    font-weight: 500;
}

.passkeys__dates {
    flex: 1;
    font-size: 13px;
}

.passkeys__item form {
    margin: 0;
}

.passkeys__row {
    display: flex;
    gap: 8px;
}

.passkeys__row .form__input {
    margin: 0;
}

.passkeys__row .button {
    flex: none;
    white-space: nowrap;
}

/* The security key button below the name, with what it needs. */
.passkeys__key {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
    margin: 8px 0 0;
}

/* A public legal page: the text in a readable column. */
.legal__page {
    max-width: 720px;
    margin: 0 auto;
    padding: 48px 16px 64px;
    line-height: 1.6;
}

.legal__brand {
    margin: 0 0 24px;
    color: var(--brand-strong);
    font-weight: 500;
}

/* Settings → Juridische pagina's: the language chosen above the pages, and the button that fills in drafts. */
.legal-language {
    max-width: 420px;
    margin: 0 0 16px;
}

.legal-draft {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 12px;
    margin: 0 0 16px;
}

.legal-address {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 13px;
    word-break: break-all;
}

/* The other languages of a legal page, above its title. */
.legal__languages {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 14px;
    margin: 0 0 8px;
    font-size: 14px;
}

.legal__languages [aria-current] {
    font-weight: 600;
}

.legal__title {
    margin: 0 0 24px;
    font-size: 28px;
    font-weight: 500;
}

.legal__text h2,
.legal__text h3 {
    margin: 28px 0 8px;
    font-weight: 500;
}

.legal__text a {
    color: var(--brand-strong);
}

/* Tables on a legal page, such as the rewards of the security policy. */
.legal__text table {
    width: 100%;
    margin: 12px 0;
    border-collapse: collapse;
}

.legal__text th,
.legal__text td {
    padding: 8px 10px;
    border: 1px solid var(--border);
    text-align: left;
    vertical-align: top;
}

.legal__text pre {
    padding: 12px;
    border-radius: 6px;
    background: var(--surface);
    white-space: pre-wrap;
}

.auth__brand {
    margin: 0;
    font-weight: 500;
}

.auth__brand .fa-solid {
    color: var(--brand);
    font-size: 20px;
    vertical-align: -3px;
}

.auth__title {
    margin: 32px 0 4px;
    font-size: 28px;
    font-weight: 400;
}

.auth__intro {
    margin: 0 0 24px;
    color: var(--muted);
}

/* Forms */

.form__error {
    margin: 0 0 16px;
    padding: 9px 12px;
    border-radius: 6px;
    background: var(--error-bg);
    color: var(--error-text);
}

.form--narrow {
    max-width: 480px;
}

.field {
    margin: 0 0 16px;
}

.field .form__input {
    margin: 0;
}

.field--check {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

/* The help of a checkbox goes on its own line below it. */
.field--check .field__help {
    flex-basis: 100%;
    margin-top: 0;
}

.form__label {
    display: block;
    margin: 0 0 6px;
    color: var(--text-soft);
}

/* A long text beside a checkbox wraps beside it, not below it. */
.field--check .form__label {
    flex: 1;
    min-width: 0;
    margin: 0;
}

.form__label.required::after {
    content: " *";
    color: var(--muted);
}

.form__help {
    margin: -8px 0 16px;
    color: var(--muted);
    font-size: 13px;
    line-height: 1.5;
}

.form__errors {
    margin: 6px 0 0;
    padding: 0;
    color: var(--error-text);
    font-size: 13px;
    list-style: none;
}

.checks {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 14px;
}

/* One choice per line, for longer labels such as a Slack connection's kinds of notifications. */
.checks--stacked {
    flex-direction: column;
    gap: 6px;
}

.check {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--text-soft);
    font-size: 13px;
    cursor: pointer;
}

input[type="checkbox"] {
    accent-color: var(--brand-border);
}

/* Select boxes look like text fields: the native look is removed and a chevron, drawn with two gradients so it
   follows the colour variables, takes the place of the arrow. */
select.form__input {
    padding-right: 34px;
    appearance: none;
    background-image:
        linear-gradient(45deg, transparent 50%, var(--muted) 50%),
        linear-gradient(135deg, var(--muted) 50%, transparent 50%);
    background-position:
        calc(100% - 17px) 50%,
        calc(100% - 12px) 50%;
    background-size: 5px 5px;
    background-repeat: no-repeat;
    cursor: pointer;
}

.form__input {
    display: block;
    width: 100%;
    margin: 0 0 16px;
    padding: 8px 12px;
    border: 1px solid var(--border);
    border-radius: 6px;
    background-color: var(--input);
    color: var(--text);
    font: inherit;
    line-height: 1.4;
}

.form__input:focus {
    border-color: var(--brand-border);
    box-shadow: 0 0 0 3px var(--focus);
    outline: none;
}

.button {
    padding: 6px 12px;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--input);
    color: var(--text);
    font: inherit;
    cursor: pointer;
}

.button:hover {
    background: var(--hover);
}

.button--primary {
    border-color: var(--brand-border);
    background: var(--brand);
    color: var(--brand-text);
}

.button--primary:hover {
    background: var(--brand-border);
}

.form__actions {
    display: flex;
    justify-content: flex-start;
    gap: 8px;
    padding: 24px 0;
}

.form__actions--start {
    justify-content: flex-start;
    padding-top: 0;
}

.button {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    text-decoration: none;
}

.button--icon {
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    color: var(--muted);
}

.button--danger {
    border-color: var(--error-text);
    color: var(--error-text);
}

.button--danger:hover {
    background: var(--error-bg);
}

.button--block {
    justify-content: center;
    width: 100%;
    margin-top: 8px;
    padding: 9px 12px;
}

.button:focus-visible {
    box-shadow: 0 0 0 3px var(--focus);
    outline: none;
}

/* Narrow screens: the submenu moves above the pane as a row of links, sections and field grids become one column, and the margins shrink. */

@media (max-width: 720px) {
    .app__content {
        display: grid;
        grid-template-columns: 56px minmax(0, 1fr);
        grid-template-rows: auto minmax(0, 1fr);
    }

    .rail {
        grid-row: 1 / 3;
    }

    .submenu {
        width: auto;
        border-right: 0;
        border-bottom: 1px solid var(--border);
    }

    .submenu__title,
    .submenu__heading {
        display: none;
    }

    .submenu__group {
        padding: 8px 0;
        border-bottom: 0;
    }

    .submenu__list {
        display: flex;
        flex-wrap: wrap;
        gap: 4px;
        padding: 0 8px;
    }

    .submenu__item {
        margin: 0;
    }

    .field-grid,
    .field-grid--address {
        grid-template-columns: minmax(0, 1fr);
    }

    .field-grid--name {
        grid-template-columns: 90px minmax(0, 1fr);
    }


    .field-grid--name > .field:first-child {
        grid-column: 1 / -1;
    }

    .field-grid--contact {
        grid-template-columns: minmax(0, 1fr) auto;
    }

    .field-grid--rule {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto;
    }

    .field-grid--pattern {
        grid-template-columns: minmax(0, 1fr) auto;
    }

    .field-grid--pattern .collection__remove {
        grid-column: 2;
        grid-row: 1;
    }

    .field-grid--rule > .field:nth-child(3) {
        grid-column: 1 / -1;
        grid-row: 2;
    }

    /* One mail server (IMAP or SMTP) within an email connection. */
.server {
    margin: 0 0 4px;
    padding: 0;
    border: 0;
}

.server__title {
    margin: 0 0 8px;
    padding: 0;
    color: var(--muted);
    font-family: var(--mono);
    font-size: 12px;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.field-grid--server {
        grid-template-columns: minmax(0, 1fr) 80px;
    }

    .field-grid--server > .field:nth-child(3n) {
        grid-column: 1 / -1;
    }

    .field-grid--contact > .field:first-child {
        grid-column: 1 / -1;
    }

    .pane__header {
        padding: 20px 16px 16px;
    }

    .pane__body {
        padding: 8px 16px 32px;
    }
}

/* Sensitive data in messages (SensitiveMarker): found by the detector, or marked by an agent (darker). A click
   opens the menu to take the mark away; selecting text opens it to mark the selection (app.js). */
mark.sensitive {
    padding: 0 1px;
    border-radius: 3px;
    background: var(--sensitive-bg);
    box-shadow: inset 0 -1px 0 var(--sensitive-line);
    color: inherit;
    cursor: pointer;
}

mark.sensitive--manual {
    background: var(--sensitive-manual-bg);
}

.sensitive-menu {
    position: fixed;
    z-index: 30;
    display: flex;
    flex-direction: column;
    gap: 6px;
    max-width: 280px;
    padding: 6px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface);
    box-shadow: var(--shadow);
}

.sensitive-menu[hidden] {
    display: none;
}

.sensitive-menu__info {
    margin: 0;
    padding: 2px 4px;
    color: var(--muted);
    font-size: 12px;
}

.sensitive-menu__info:empty {
    display: none;
}

/* Suggestions under Settings → Gevoelige gegevens: a text or word with how often it was marked, and buttons. */
.suggestions {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.suggestions__item {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px 16px;
    padding: 8px 12px;
    border: 1px solid var(--border);
    border-radius: 8px;
}

.suggestions__actions {
    display: flex;
    gap: 8px;
}

/* The AI's suggestion: the panel under the editor with how far it answers, what is missing and its sources. */
.ai-panel {
    margin: 10px 0 0;
    padding: 10px 14px;
    border: 1px solid var(--border);
    border-left: 3px solid var(--sensitive-line);
    border-radius: 8px;
    background: var(--surface);
    font-size: 13px;
}

.ai-panel[hidden] {
    display: none;
}

.ai-panel--partly {
    border-left-color: var(--warning-text);
}

.ai-panel--no,
.ai-panel--error {
    border-left-color: var(--muted);
}

.ai-panel--error .ai-panel__status {
    color: var(--error-text);
}

.ai-panel__status,
.ai-panel__missing,
.ai-panel__heading {
    margin: 0 0 4px;
}

.ai-panel__missing {
    color: var(--warning-text);
}

.ai-panel__heading {
    margin-top: 8px;
    color: var(--muted);
    font-family: var(--mono);
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.ai-panel__sources {
    margin: 0;
    padding-left: 18px;
}

.ai-panel__heading--actions {
    color: var(--warning-text);
}

.ai-panel__actions {
    margin: 0 0 4px;
    padding-left: 18px;
    font-weight: 500;
}

.ai-panel__sources a {
    color: var(--brand-strong);
}

/* Results of the AI under Settings → AI. */
.ai-stats {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 10px;
    margin: 0;
}

.ai-stats__item {
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: 8px;
}

.ai-stats__item dt {
    color: var(--muted);
    font-size: 12px;
}

.ai-stats__item dd {
    margin: 2px 0 0;
    font-size: 20px;
}

.ai-stats__item dd .muted {
    font-size: 13px;
}

.badge--ai-approved {
    background: var(--brand);
    color: var(--brand-text);
}

.badge--ai-modified {
    background: var(--warning-bg);
    color: var(--warning-text);
}

/* The list of standard answers in the editor (app.js, startCanned). */
.canned-picker {
    position: fixed;
    z-index: 40;
    width: min(420px, calc(100vw - 16px));
    padding: 6px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface);
    box-shadow: var(--shadow);
}

.canned-picker[hidden],
.canned-picker__search[hidden] {
    display: none;
}

.canned-picker__search {
    width: 100%;
    margin-bottom: 6px;
}

.canned-picker__list {
    margin: 0;
    padding: 0;
    list-style: none;
}

.canned-picker__item {
    display: flex;
    flex-direction: column;
    gap: 1px;
    padding: 6px 8px;
    border-radius: 6px;
    cursor: pointer;
}

.canned-picker__item.is-active,
.canned-picker__item:hover {
    background: var(--selected);
}

.canned-picker__meta {
    color: var(--muted);
    font-family: var(--mono);
    font-size: 12px;
}

.canned-picker__note {
    margin: 0;
    padding: 4px 8px;
    color: var(--muted);
    font-size: 13px;
}

.canned-picker__note:empty {
    display: none;
}

/* A machine translation of a message, in place of its text, and the bar after translating a reply. */
.translation__label,
.translate-bar {
    margin: 0 0 6px;
    color: var(--muted);
    font-size: 13px;
}

.translate-bar {
    margin: 8px 0 0;
}

.translation__text {
    white-space: pre-wrap;
}

.translation__toggle {
    padding: 0;
    border: 0;
    background: none;
    color: var(--brand-strong);
    font: inherit;
    cursor: pointer;
}

.translation__back {
    margin-top: 6px;
    font-size: 13px;
}

.translation__back[hidden],
.translation[hidden],
.timeline__body[hidden] {
    display: none;
}

/* A new API key, shown once after saving: one click selects all of it for copying. */
.api-key .copy-field {
    margin: 0 0 20px;
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--input);
}

.api-key__value {
    flex: 1;
    min-width: 0;
    font-family: ui-monospace, monospace;
    overflow-wrap: anywhere;
    user-select: all;
}

/* A ticket's metadata fields in the side panel: label above value, with its buttons beside them. */
.ticket-field {
    display: flex;
    align-items: flex-start;
    gap: 4px;
    margin: 0 0 8px;
    font-size: 13px;
}

.ticket-field form {
    margin: 0;
}

.ticket-field__text {
    flex: 1;
    min-width: 0;
}

.ticket-field__label {
    display: block;
    color: var(--muted);
}

.ticket-field__value {
    display: block;
    overflow-wrap: anywhere;
    white-space: pre-wrap;
}

/* The ticket's parcels from MyParcel in the side panel; one that does not match the contact is marked. */
.orders {
    list-style: none;
    margin: 0;
    padding: 0;
    font-size: 13px;
}

.order + .order {
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px solid var(--border);
}

.order p {
    margin: 2px 0;
}

.order__status {
    font-weight: 500;
}

/* Each shipment of an order sent more than once, under the order number. */
.order__shipment + .order__shipment {
    margin-top: 6px;
    padding-top: 6px;
    border-top: 1px dashed var(--border);
}

/* "In antwoord zetten" under a matched shipment: room above and below, apart from the lines around it. */
.order__insert {
    margin: 8px 0;
}

.order__warning {
    color: var(--warning-text);
}

.order a {
    color: var(--text);
    text-decoration: none;
}

.order a:hover {
    text-decoration: underline;
}

.order__history summary {
    cursor: pointer;
    color: var(--muted);
}

.order__history ul {
    margin: 4px 0 0;
    padding-left: 16px;
}

/* A field holding a link shows its site in the text's colour, underlined on hover, with an icon for "opens elsewhere". */
.ticket-field__link {
    color: var(--text);
    text-decoration: none;
}

.ticket-field__link:hover {
    text-decoration: underline;
}

.ticket-field__link i {
    font-size: 11px;
    color: var(--muted);
}

.button--icon.ticket-field__button {
    width: 26px;
    height: 26px;
    min-height: 0;
    padding: 0;
    border-color: transparent;
    background: none;
    color: var(--muted);
}

.button--icon.ticket-field__button:hover {
    color: var(--text);
}

.ticket-field-add {
    margin-top: 8px;
    font-size: 13px;
}

.ticket-field-add summary {
    cursor: pointer;
    color: var(--muted);
}

.ticket-field-add__form {
    display: grid;
    gap: 4px;
    margin: 8px 0 0;
}

.ticket-field-add__check {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 4px 0;
}

.ticket-field-add__form .button {
    justify-self: start;
}

/* A small select in the side panel, such as the ticket's language. */
.side-card__form {
    display: flex;
    align-items: center;
    margin: 0;
}

.form__input.form__input--small {
    width: 100%;
    margin: 0;
    padding: 2px 6px;
    font-size: 13px;
}

/* A small select keeps room for its arrow, and a name too long for it ends in "…" instead of running under it. */
select.form__input.form__input--small {
    padding-right: 24px;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    background-position:
        calc(100% - 13px) 50%,
        calc(100% - 8px) 50%;
}

/* Adding a language under Settings → Talen: the select and its button on one line. */
.languages__add {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.languages__add .form__input {
    width: auto;
    min-width: 220px;
    margin: 0;
}

/* The check mark after a select that saved without reloading the page (data-async). */
.saved-mark {
    align-self: center;
    margin-left: 6px;
    color: var(--brand-strong);
    opacity: 0;
    transition: opacity 0.2s ease;
}

.saved-mark.is-shown {
    opacity: 1;
}

/* Settings → Kennisbron: the filter row and the list of questions and answers. */
.knowledge-filter {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 16px;
}

.knowledge-filter .search {
    flex: 1;
    min-width: 240px;
    margin: 0;
}

.knowledge-filter > .form__input {
    width: auto;
    margin: 0;
}

.knowledge-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.knowledge-item {
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: 8px;
}

.knowledge-item--off {
    opacity: 0.6;
}

.knowledge-item__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin-bottom: 6px;
    font-size: 13px;
}

.knowledge-item__meta a {
    color: var(--brand-strong);
}

.knowledge-item__text {
    margin: 0 0 6px;
    font-size: 13px;
    overflow-wrap: anywhere;
}

.pagination {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 16px;
}

.ai-panel__off {
    font-size: 12px;
}

/* Several tickets at once: the checkbox column and the bar that appears above the table. */
/* The cell of a row's checkbox is a click target of its own (app.js): wide enough to hit, with room before the
   next column, and without the row's pointer to the link. */
.table__check {
    width: 44px;
    padding-right: 12px;
    cursor: default;
}

.table--links tbody .table__check {
    cursor: default;
}

.table__check input {
    margin: 0;
    cursor: pointer;
}

/* The actions for the checked tickets float at the bottom of the window, so checking a ticket moves nothing in
   the list, and they stay in reach while scrolling to check more. */
.bulk__bar {
    position: fixed;
    bottom: 24px;
    left: 50%;
    z-index: 20;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    max-width: calc(100vw - 32px);
    padding: 8px 8px 8px 16px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--bg);
    box-shadow: var(--shadow);
    transform: translateX(-50%);
}

.bulk__bar[hidden] {
    display: none;
}

/* Room below the list while the bar floats, so it never covers the last tickets. */
.pane__body:has(.bulk__bar:not([hidden])) {
    padding-bottom: 104px;
}

.bulk__bar .form__input {
    width: auto;
    margin: 0;
}

/* Merging tickets: the choice of the ticket the others merge into. */
.merge-choice {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 0 0 12px;
    padding: 0;
    border: 0;
}

.merge-choice__option {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: 8px;
    cursor: pointer;
}

.merge-choice__option > span {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.merge-choice__option .muted {
    font-size: 13px;
}

/* The verified mark of a contact (contact/_verification.html.twig): green for a known relation, a warning colour
   for a company disabled in the LENS API. */
.verified {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    margin: 4px 0 8px;
    color: var(--brand-strong);
    font-size: 13px;
}

.verified > span {
    display: flex;
    flex-direction: column;
    gap: 1px;
}

.verified__detail {
    color: var(--muted);
}

/* A detail that differs on purpose from the LENS API, with the button that takes the LENS API's value. */
.lens-deviation {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 10px;
    margin: 0 0 8px;
    color: var(--muted);
    font-size: 13px;
}

.lens-deviation .button {
    padding: 3px 10px;
    font-size: 13px;
}

/* The verified status as a short label in a list. */
.verified-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: var(--brand-strong);
    font-size: 13px;
}

.verified--answered {
    color: var(--muted);
}

.verified--disabled {
    color: var(--error-text);
}

/* Changing a ticket's subject: the pencil after the title, quiet until hovered, and the field above the timeline. */
.pane__edit {
    flex: 0 0 auto;
    width: 22px;
    height: 22px;
    margin-left: 4px;
    font-size: 13px;
    vertical-align: middle;
    border-color: transparent;
    background: none;
    opacity: .6;
}

.pane__edit:hover,
.pane__edit:focus-visible {
    opacity: 1;
}

.subject-form {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 0 0 16px;
}

.subject-form[hidden] {
    display: none;
}

.subject-form .form__input {
    flex: 1 1 320px;
    margin: 0;
}

/* Marking tickets as spam: one line per contact, with what is deleted, or why it is kept. */
.spam-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 0 0 16px;
    padding: 0;
    list-style: none;
}

.spam-list__item {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: 6px 16px;
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: 8px;
}

.spam-list__item--kept {
    background: var(--surface);
}

.badge--danger {
    background: var(--error-bg);
    color: var(--error-text);
}

/* Merging tickets of different contacts: the choice to merge the contacts too. */
.merge-contacts {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    margin: 0 0 12px;
    cursor: pointer;
}

.merge-contacts > span {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.merge-contacts .muted {
    font-size: 13px;
}

/* Merging contacts: one contact in short (name, contact details, tickets), and the buttons of a suggested pair. */
.contact-summary {
    display: flex;
    flex-direction: column;
    gap: 2px;
    font-size: 13px;
}

.contact-summary > a {
    font-size: 14px;
    font-weight: 500;
}

.contact-summary > a:hover {
    text-decoration: underline;
}

/* Deleting a contact from a list, such as spam among the duplicate contacts: a quiet red text button. */
.contact-delete {
    margin-top: 6px;
}

.contact-delete__button {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 2px 0;
    border: 0;
    background: none;
    color: var(--error-text);
    font: inherit;
    font-size: 13px;
    cursor: pointer;
}

.contact-delete__button:hover {
    text-decoration: underline;
}

/* A button or link waiting for the next page (data-busy in app.js). */
.is-busy {
    pointer-events: none;
    opacity: .8;
}

.table__actions {
    text-align: right;
    white-space: nowrap;
}

.table__actions > form {
    display: inline;
}

/* The pages of a ticket list, below it: which tickets are shown, then previous, page numbers and next. */
.pagination {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px 16px;
    margin-top: 16px;
}

.pagination__summary {
    margin: 0;
    font-family: var(--mono);
    font-size: 12px;
}

.pagination__pages {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.pagination__pages .button {
    box-sizing: border-box;
    min-width: 34px;
    height: 34px;
    justify-content: center;
}

.pagination__pages .button.is-disabled {
    color: var(--muted);
    cursor: default;
    opacity: .5;
}

.pagination__jump {
    margin: 0;
}

/* The current page as a field: as wide as a button, the number centred, without the browser's arrows. */
.pagination__pages .pagination__field {
    box-sizing: border-box;
    width: 52px;
    height: 34px;
    margin: 0;
    padding: 0 4px;
    border-color: var(--text-soft);
    background: var(--selected);
    text-align: center;
    -moz-appearance: textfield;
}

.pagination__field::-webkit-outer-spin-button,
.pagination__field::-webkit-inner-spin-button {
    margin: 0;
    -webkit-appearance: none;
}

.pagination__gap {
    padding: 0 4px;
    color: var(--muted);
}

/* The views at the top of the ticket screens: buttons side by side, the active one pressed, with a count. */
.views {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.views .button.is-active {
    border-color: var(--text-soft);
    background: var(--selected);
}

.views__count {
    color: var(--muted);
    font-family: var(--mono);
    font-size: 12px;
}

/* The share sent unchanged stands out among the AI's results: it tells how far replies can be automated. */
.ai-stats__item--key {
    border-color: var(--brand-border);
}

/* A floating notice, such as why a reply could not be sent; it stays in view until closed. */
.toast {
    position: fixed;
    top: 16px;
    left: 50%;
    z-index: 50;
    display: flex;
    align-items: flex-start;
    gap: 10px;
    width: min(560px, calc(100vw - 32px));
    padding: 12px 12px 12px 16px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--surface);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18);
    transform: translateX(-50%);
}

.toast--error {
    border-color: var(--error-text);
    background: var(--error-bg);
    color: var(--error-text);
}

.toast--error > i {
    margin-top: 2px;
}

.toast > span {
    flex: 1;
}

.toast__close {
    margin: -4px -4px -4px 0;
}

/* A message the page opens at (after sending) is not hidden under the top bar. */
.timeline__item {
    scroll-margin-top: 24px;
}

/* New web chats waiting for an agent: floating windows at the bottom right, above everything else. */
.chat-alerts {
    position: fixed;
    right: 16px;
    bottom: 16px;
    z-index: 60;
    display: flex;
    flex-direction: column;
    gap: 10px;
    width: min(360px, calc(100vw - 32px));
}

.chat-alert {
    padding: 12px 14px;
    border: 1px solid var(--brand);
    border-radius: 10px;
    background: var(--surface);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.2);
}

.chat-alert p {
    margin: 0 0 6px;
}

.chat-alert__title {
    font-weight: 600;
}

.chat-alert__title i {
    color: var(--brand);
}

.chat-alert__text {
    display: block;
    margin: 0 0 8px;
    color: var(--text);
    text-decoration: none;
}

.chat-alert__text:hover {
    text-decoration: underline;
}

.chat-alert__overdue,
.chat-alert__error {
    font-size: 13px;
    color: var(--warning-text);
}

.chat-alert__actions {
    display: flex;
    gap: 8px;
}

.chat-alert__notify {
    margin-top: 8px;
    padding: 0;
    border: 0;
    background: none;
    color: var(--muted);
    font: inherit;
    font-size: 12px;
    text-decoration: underline;
    cursor: pointer;
}

.chat-alert__taken {
    color: var(--muted);
}


/* Phones (up to 720px wide). The rail becomes a tab bar at the bottom, as in apps; the submenu a row to swipe; the
   pane's header compact and no longer sticky, its actions one row to swipe; the ticket and contact lists cards
   instead of wide tables; fields at 16px, below which Safari on the iPhone zooms in when one is tapped. env() keeps
   clear of the iPhone's home indicator. */
@media (max-width: 720px) {
    .topbar {
        height: 44px;
        padding: 0 12px;
        padding-top: env(safe-area-inset-top);
    }

    .app__content {
        display: flex;
        flex-direction: column;
    }

    .submenu {
        order: 1;
    }

    .pane {
        order: 2;
        flex: 1;
        min-height: 0;
    }

    /* The tab bar: every part of the application as an icon in one row; the names stay for screen readers. */
    .rail {
        order: 3;
        width: auto;
        flex-shrink: 0;
    }

    .rail__nav,
    .rail--hover .rail__nav:hover,
    .rail--hover .rail__nav:has(:focus-visible),
    .rail--hover .rail__nav:has(.rail__mode[open]),
    .rail--expanded .rail__nav {
        position: static;
        flex-direction: row;
        width: auto;
        padding: 4px 4px calc(4px + env(safe-area-inset-bottom));
        border-top: 1px solid var(--border);
        border-right: 0;
        box-shadow: none;
    }

    .rail__list,
    .rail__list--bottom {
        flex: 1 1 auto;
        flex-direction: row;
        justify-content: space-around;
        margin: 0;
    }

    .rail__list li {
        flex: 1 1 0;
    }

    .rail__item {
        justify-content: center;
        height: 44px;
        padding: 0;
    }

    .rail__item .fa-fw {
        font-size: 20px;
    }

    /* The choice of the rail's behaviour is for a computer; on a phone the rail is a tab bar. */
    .rail__mode-item {
        display: none;
    }

    .rail__label,
    .rail--hover .rail__nav:hover .rail__label,
    .rail--hover .rail__nav:has(:focus-visible) .rail__label,
    .rail--expanded .rail__label {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }

    /* The submenu (settings and the like) as one row of links to swipe through. */
    .submenu {
        display: flex;
        width: auto;
        max-height: none;
        overflow-x: auto;
        overflow-y: hidden;
        border-right: 0;
        border-bottom: 1px solid var(--border);
        scrollbar-width: none;
    }

    .submenu::-webkit-scrollbar {
        display: none;
    }

    .submenu__action,
    .submenu__title,
    .submenu__heading {
        display: none;
    }


    .submenu__group {
        flex-shrink: 0;
        padding: 6px 0;
        border-bottom: 0;
    }

    .submenu__list {
        flex-wrap: nowrap;
        padding: 0 8px;
    }

    .submenu__item {
        white-space: nowrap;
    }

    /* The pane's header: compact, scrolling with the page, its actions in one row to swipe. */
    .pane__header {
        position: static;
        gap: 10px;
        padding: 12px 16px;
    }

    .pane__title {
        font-size: 22px;
    }

    .pane__subtitle {
        margin-top: 2px;
        font-size: 14px;
    }

    .pane__actions {
        flex-wrap: nowrap;
        width: calc(100% + 32px);
        margin: 0 -16px;
        padding: 0 16px 2px;
        overflow-x: auto;
        scrollbar-width: none;
    }

    .pane__actions::-webkit-scrollbar {
        display: none;
    }

    .pane__actions > * {
        flex-shrink: 0;
    }

    .pane__body {
        padding: 12px 16px 24px;
    }

    /* Fields at 16px, so Safari does not zoom in on them; the editor's text too. */
    .form__input,
    .form__input.form__input--small,
    select.form__input.form__input--small,
    input:not([type="checkbox"]):not([type="radio"]),
    select,
    textarea,
    .jodit-wysiwyg {
        font-size: 16px;
    }

    /* Filter rows (the audit log's) two by two, the search over the whole width. */
    .filters {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .filters .form__input {
        width: 100%;
        min-width: 0;
    }

    .filters input[type="search"] {
        grid-column: 1 / -1;
    }

    /* The audit log as cards: time and who on the first line, then the action and its object, then the details. */
    .table.audit thead {
        display: none;
    }

    .table.audit,
    .table.audit tbody {
        display: block;
    }

    .table.audit tr {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        gap: 2px 10px;
        padding: 10px 0;
        border-bottom: 1px solid var(--border-muted);
    }

    .table.audit td {
        padding: 0;
        border: 0;
        white-space: normal;
    }

    .table.audit td:nth-child(1) { order: 2; font-size: 13px; text-align: right; }
    .table.audit td:nth-child(2) { order: 1; font-size: 13px; color: var(--muted); }
    .table.audit td:nth-child(3) { order: 3; grid-column: 1 / -1; font-weight: 500; }
    .table.audit td:nth-child(4),
    .table.audit td:nth-child(5) { order: 4; grid-column: 1 / -1; }

    .table.audit td:empty {
        display: none;
    }

    /* Simple lists (.table--stack: standard answers, agents, channels): the first column as the row's title, the
       others on a line under it, small and apart. */
    .table--stack thead {
        display: none;
    }

    .table--stack,
    .table--stack tbody {
        display: block;
    }

    .table--stack tr {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: 2px 12px;
        padding: 10px 0;
        border-bottom: 1px solid var(--border-muted);
    }

    .table--stack td {
        width: auto;
        max-width: none;
        padding: 0;
        border: 0;
        color: var(--muted);
        font-size: 13px;
    }

    .table--stack td:first-child {
        flex: 1 0 100%;
        width: auto;
        max-width: none;
        color: var(--text);
        font-size: inherit;
        white-space: normal;
    }

    .table--stack td:empty {
        display: none;
    }

    .table--stack .table__cut > * {
        white-space: normal;
    }

    /* The name's parts: the family name on a line of its own. */
    .field-grid--name > .field:nth-child(4) {
        grid-column: 1 / -1;
    }

    /* A web chat visitor's state and the reply window's end may take two lines. */
    .reply__chat,
    .reply__window {
        white-space: normal;
    }

    /* The side panel takes the whole width; menus and dialogs stay within the screen. */
    .side-panel {
        width: 100%;
        border-left: 0;
    }

    .menu__panel {
        max-width: calc(100vw - 24px);
    }

    /* An attachment's menu opens to the left, as the chip may sit near the right edge. */
    .chip-split .menu__panel {
        right: 0;
        left: auto;
    }

    .dialog {
        max-width: calc(100vw - 24px);
    }

    /* Floating bars above the tab bar; the bulk bar on one line over the whole width. */
    .bulk__bar {
        right: 12px;
        bottom: calc(68px + env(safe-area-inset-bottom));
        left: 12px;
        flex-wrap: nowrap;
        max-width: none;
        padding: 8px;
        transform: none;
    }

    .bulk__bar [data-bulk-count] {
        flex-shrink: 0;
        font-size: 14px;
    }

    .bulk__bar .form__input {
        flex: 1 1 auto;
        width: 100%;
        min-width: 0;
    }

    .bulk__bar .button {
        flex-shrink: 0;
    }

    /* The filter button only shows its icon and count. */
    .ticket-search__toggle-label {
        display: none;
    }

    .chat-alerts {
        right: 12px;
        bottom: calc(68px + env(safe-area-inset-bottom));
        width: calc(100vw - 24px);
    }
}

/* Up to tablet width, the ticket and contact lists are cards instead of wide tables (see the phone block above). */
@media (max-width: 960px) {
    /* Tickets as cards: the subject over two lines at most, then the contact and time, then channel, medium and
       status. The checkbox stays on the left for the bulk actions. */
    .table--tickets thead,
    .table--contacts thead {
        display: none;
    }

    .table--tickets,
    .table--tickets tbody,
    .table--contacts,
    .table--contacts tbody {
        display: block;
    }

    .table--tickets tr,
    .table--contacts tr {
        display: grid;
        column-gap: 10px;
        row-gap: 2px;
        padding: 12px 0;
        border-bottom: 1px solid var(--border-muted);
    }

    .table--tickets td,
    .table--contacts td {
        width: auto;
        max-width: none;
        min-width: 0;
        padding: 0;
        border: 0;
    }

    .table--tickets tr {
        grid-template-columns: 24px minmax(0, 1fr) auto auto;
        grid-template-areas:
            "check subject subject subject"
            "check contact contact time"
            "check channel via status";
    }

    .table--tickets td:nth-child(1) { grid-area: check; }
    .table--tickets td:nth-child(2) { grid-area: channel; }
    .table--tickets td:nth-child(3) { grid-area: contact; }
    .table--tickets td:nth-child(4) { grid-area: subject; }
    .table--tickets td:nth-child(5) { grid-area: via; }
    .table--tickets td:nth-child(6) { grid-area: status; }
    .table--tickets td:nth-child(7) { grid-area: time; }

    .table--tickets td:nth-child(4) {
        display: -webkit-box;
        -webkit-box-orient: vertical;
        -webkit-line-clamp: 2;
        overflow: hidden;
        white-space: normal;
        font-weight: 500;
    }

    .table--tickets td:nth-child(2),
    .table--tickets td:nth-child(3),
    .table--tickets td:nth-child(5),
    .table--tickets td:nth-child(7) {
        overflow: hidden;
        color: var(--muted);
        font-size: 13px;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .table--tickets td:nth-child(6) {
        justify-self: end;
    }

    /* Contacts as cards: the name with its mark, then email address and phone number, then the organisation. */
    .table--contacts tr {
        grid-template-columns: 24px minmax(0, 1fr) auto;
        grid-template-areas:
            "check name status"
            "check email email"
            "check tel tel"
            "check org org";
    }

    .table--contacts td:nth-child(1) { grid-area: check; }
    .table--contacts td:nth-child(2) { grid-area: name; font-weight: 500; }
    .table--contacts td:nth-child(3) { grid-area: email; }
    .table--contacts td:nth-child(4) { grid-area: tel; }
    .table--contacts td:nth-child(5) { grid-area: org; }
    .table--contacts td:nth-child(6),
    .table--contacts td:nth-child(7) { display: none; }
    .table--contacts td:nth-child(8) { grid-area: status; }

    .table--contacts td:nth-child(n+3) {
        font-size: 13px;
    }

    .table--contacts td:empty {
        display: none;
    }
}

/* A button below the details in a side card, such as downloading the ticket. */
/* The panel's actions (print, download) take the card's whole width. */
.side-card__action {
    width: 100%;
    justify-content: center;
    margin-top: 12px;
    font-size: 13px;
}

/* The hidden frame a ticket's print page loads in (printInFrame, app.js): out of sight, but laid out at a page's
   width, as some browsers print a frame of no size as an empty page. */
.print-frame {
    position: fixed;
    top: 0;
    left: -10000px;
    width: 800px;
    height: 600px;
    border: 0;
}

/* A ticket on paper (ticket/print.html.twig): black on white in any theme, the bar with its buttons only on screen.
   Notes are framed as internal; a message is not split over two pages where that can be avoided. */
/* Black on white whatever the agent's theme: the colour tokens of the light theme, and every text black, also the
   colours and backgrounds an email sets itself. */
.print-page {
    color-scheme: light;
    --text: #000000;
    --text-soft: #000000;
    --muted: #000000;
    --brand-strong: #000000;
    background: #ffffff;
    color: #000000;
}

.print,
.print * {
    color: #000000 !important;
}

.print__body * {
    background-color: transparent !important;
}

.print a {
    text-decoration: underline;
}

.print-toolbar {
    display: flex;
    gap: 8px;
    padding: 12px 16px;
    border-bottom: 1px solid #dfdfdf;
}

.print {
    max-width: 800px;
    margin: 0 auto;
    padding: 24px 16px;
    font-size: 14px;
    line-height: 1.5;
}

.print__brand {
    margin: 0;
    color: #000000;
    font-size: 12px;
}

.print__title {
    margin: 4px 0 12px;
    font-size: 20px;
    font-weight: 600;
}

.print__details,
.print__fields {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 6px 16px;
    margin: 0;
}

.print__details dt,
.print__fields dt {
    color: #000000;
    font-size: 12px;
}

.print__details dd,
.print__fields dd {
    margin: 0;
    overflow-wrap: anywhere;
}

.print__section {
    margin-top: 20px;
    padding-top: 12px;
    border-top: 1px solid #cccccc;
}

.print__section h2 {
    margin: 0 0 8px;
    font-size: 15px;
    font-weight: 600;
}

.print__section p {
    margin: 0 0 4px;
}

.print__message {
    margin-bottom: 12px;
    padding: 10px 12px;
    border: 1px solid #cccccc;
    border-radius: 6px;
    break-inside: avoid;
}

.print__message--note {
    border-style: dashed;
    background: #f6f6f6;
}

.print__internal {
    margin-left: 4px;
    padding: 0 6px;
    border: 1px solid #000000;
    border-radius: 4px;
    font-size: 11px;
    text-transform: uppercase;
}

.print__meta,
.print__recipients,
.print__files {
    color: #000000;
    font-size: 12px;
}

.print__recipients span + span::before {
    content: " · ";
}

.print__body {
    margin-top: 6px;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.print__body.mail-html {
    white-space: normal;
}

/* The marks of sensitive data are for the screen only: on paper the text reads as written. */
.print mark.sensitive {
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    box-shadow: none;
    text-decoration: none;
}

.print__body img,
.print__image {
    max-width: 100%;
    height: auto;
}

@media print {
    .print-toolbar {
        display: none;
    }

    .print {
        max-width: none;
        padding: 0;
    }

    @page {
        margin: 16mm 14mm;

        @bottom-right {
            content: counter(page) " / " counter(pages);
            font-size: 10px;
        }
    }
}
