/* ============================================================================
   Mobile app shell and cards — the layout every module shares on a phone.
   Colour comes from the role palette in menu.php (--w-primary and friends), so
   nothing here hardcodes a brand colour: a picker sees green, an admin gold,
   a super admin red, and this file is the same for all three.
   ============================================================================ */

/* One height, used by everything that has to sit clear of the bar. */
:root { --app-tabbar-h: 61px; }

/* ---- app-level bottom tabs: Chat | WMS | HR | Mine ---- */
.app-tabbar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 50;
    display: flex; background: var(--w-surface);
    border-top: 1px solid var(--w-border);
    padding-bottom: env(safe-area-inset-bottom);
}
.app-tab {
    flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 3px;
    padding: 8px 2px 7px; font-size: 11.5px; line-height: 1;
    color: var(--w-muted); text-decoration: none; position: relative;
}
.app-tab > span:not(.app-tab-ico):not(.app-tab-badge) {
    max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.app-tab:hover, .app-tab:focus { color: var(--w-muted); text-decoration: none; }
.app-tab .app-tab-ico {
    width: 100%; max-width: 52px; height: 30px; border-radius: 15px;
    display: flex; align-items: center; justify-content: center;
    font-size: 21px; transition: background .15s ease;
}
.app-tab.active { color: var(--w-primary); font-weight: 600; }
.app-tab.active .app-tab-ico { background: var(--w-primary-soft); }
.app-tab .app-tab-badge {
    position: absolute; top: 2px; left: 50%; margin-left: 4px;
    min-width: 18px; height: 18px; padding: 0 5px;
    border-radius: 9px; background: #e23b3b; color: #fff;
    font-size: 11px; font-weight: 700; line-height: 18px; text-align: center;
}
/* Desktop keeps the bar too. The sidebar is fixed at --sb-w, so the bar starts where the content
   does rather than sliding underneath it — the same treatment .action-bar already gets. */
@media (min-width: 768px) {
    .app-tabbar { left: var(--sb-w, 0px); }
    /* The save bar has to start there too. style.css sets left: var(--sb-w) for it at this width,
       but a later .action-bar rule in the same file resets left: 0 and wins on document order, so
       it had always run under the sidebar on desktop. This file loads last, so it settles it.
       Nothing here may change the bar's height: --app-tabbar-h is what everything else stacks off,
       and a bar 2px taller than the variable leaves the save bar overlapping it. */
    .action-bar { left: var(--sb-w, 0px); }
}

/* pages that show the bar need room for it */
.has-tabbar { padding-bottom: 86px; }

/* ---- greeting ---- */
.m-greet { padding: 18px 2px 14px; }
.m-greet h1 { font-size: 24px; font-weight: 700; margin: 0 0 4px; letter-spacing: -.2px; }
.m-greet p { margin: 0; color: var(--w-muted); font-size: 14.5px; }

/* ---- the one filled card at the top of a hub ---- */
.m-hero {
    background: var(--w-primary-gradient); color: #fff;
    border-radius: 18px; padding: 16px 16px 18px; margin-bottom: 16px;
    position: relative; overflow: hidden;
}
.m-hero::after {                       /* the soft disc in the corner of the reference */
    content: ''; position: absolute; right: -40px; top: -60px;
    width: 180px; height: 180px; border-radius: 50%;
    background: rgba(255, 255, 255, .06);
}
.m-hero h2 { font-size: 16px; font-weight: 700; margin: 0 0 14px; position: relative; }
.m-hero-stats { display: flex; align-items: stretch; position: relative; }
.m-hero-stat { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 6px; text-align: center; }
.m-hero-stat + .m-hero-stat { border-left: 1px solid rgba(255, 255, 255, .22); }
.m-hero-stat i {
    width: 42px; height: 42px; border-radius: 12px; background: rgba(255, 255, 255, .16);
    display: flex; align-items: center; justify-content: center; font-size: 21px;
}
.m-hero-stat small { font-size: 12.5px; opacity: .92; line-height: 1.2; }
.m-hero-stat b { font-size: 24px; font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums; }
/* the stat itself is the link, so colour it directly — a descendant rule never matches here and the
   site's link colour wins, which left white-on-white numbers on the card */
.m-hero-stat, .m-hero-stat:hover, .m-hero-stat:focus,
.m-hero-stat b, .m-hero-stat small { color: #fff; text-decoration: none; }
.m-hero-stat:hover i { background: rgba(255, 255, 255, .26); }

/* ---- plain white card with a heading ---- */
.m-card { background: var(--w-surface); border-radius: 16px; padding: 14px 14px 6px; margin-bottom: 14px; box-shadow: 0 1px 2px rgba(16, 24, 40, .05); }
.m-card.tight { padding-bottom: 14px; }
.m-card-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 10px; }
.m-card-head h2 { font-size: 17px; font-weight: 700; margin: 0; }
.m-card-head a { font-size: 13.5px; font-weight: 600; color: var(--w-primary); text-decoration: none; white-space: nowrap; }
.m-card-head a i { font-size: 12px; }

/* ---- a row that leads somewhere ---- */
.m-row {
    display: flex; align-items: center; gap: 12px;
    padding: 12px 2px; text-decoration: none; color: var(--w-text);
    border-bottom: 1px solid var(--w-border);
}
.m-card > .m-row:last-child, .m-card > form:last-child .m-row { border-bottom: 0; }
.m-row:hover { text-decoration: none; color: var(--w-text); }
.m-row-ico { width: 34px; height: 34px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 19px; flex: none; }
.m-row-ico.warn { background: #fff3e0; color: #ed6c02; }
.m-row-ico.bad  { background: #fdecea; color: #d32f2f; }
.m-row-ico.ok   { background: var(--w-primary-soft); color: var(--w-primary); }
.m-row-body { flex: 1; min-width: 0; }
.m-row-body b { display: block; font-weight: 600; font-size: 15px; line-height: 1.3; }
.m-row-body small { color: var(--w-muted); font-size: 12.5px; }
.m-row-meta { color: var(--w-muted); font-size: 13.5px; white-space: nowrap; }
.m-row > .bi-chevron-right { color: #b9c2be; font-size: 15px; flex: none; }
.m-row-count {
    min-width: 22px; height: 22px; padding: 0 6px; border-radius: 11px;
    background: #e23b3b; color: #fff; font-size: 12px; font-weight: 700;
    line-height: 22px; text-align: center; flex: none;
}
.m-row-count.warn { background: #ed6c02; }

/* ---- the big two-column menu tiles ---- */
.m-tiles { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; padding-bottom: 8px; }
.m-tile {
    background: var(--w-primary-soft); border-radius: 14px;
    padding: 18px 10px 14px; text-align: center; text-decoration: none;
    display: flex; flex-direction: column; align-items: center; gap: 10px;
    color: var(--w-text); min-height: 104px; justify-content: center;
}
.m-tile:hover, .m-tile:focus { text-decoration: none; color: var(--w-text); background: var(--w-primary-soft-active, var(--w-primary-soft)); }
.m-tile i { font-size: 29px; color: var(--w-primary); line-height: 1; }
.m-tile span { font-size: 13.5px; font-weight: 600; line-height: 1.25; }
@media (min-width: 560px) { .m-tiles { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 768px) { .m-tiles { grid-template-columns: repeat(4, 1fr); } }

/* ---- filter chips ---- */
.m-chips { display: flex; gap: 8px; overflow-x: auto; padding: 2px 2px 8px; -webkit-overflow-scrolling: touch; scrollbar-width: none; }
.m-chips::-webkit-scrollbar { display: none; }
.m-chip {
    flex: none; display: inline-flex; align-items: center; gap: 6px;
    padding: 9px 16px; border-radius: 999px; border: 1px solid var(--w-border);
    background: var(--w-surface); color: var(--w-text);
    font-size: 14px; font-weight: 600; text-decoration: none; white-space: nowrap;
}
.m-chip:hover { text-decoration: none; color: var(--w-text); }
.m-chip.active { background: var(--w-primary); border-color: var(--w-primary); color: #fff; }
.m-chip.soft { background: var(--w-primary-soft); border-color: transparent; color: var(--w-primary); }
.m-chip .m-chip-n { opacity: .85; font-weight: 700; }

/* ---- full-width primary action ---- */
.m-action { display: block; width: 100%; padding: 15px 16px; border: 0; border-radius: 12px;
    background: var(--w-primary); color: #fff; font-size: 16px; font-weight: 700; text-align: center; text-decoration: none; }
.m-action:hover, .m-action:focus { color: #fff; text-decoration: none; background: var(--w-primary-dark); }
.m-note { text-align: center; color: var(--w-muted); font-size: 12.5px; margin: 8px 0 0; }

/* ---- status pill used inside cards ---- */
.m-state { display: inline-flex; align-items: center; gap: 7px; padding: 8px 14px; border-radius: 999px; font-size: 14px; font-weight: 600; }
.m-state.bad { background: #fdecea; color: #c62828; }
.m-state.ok { background: var(--w-primary-soft); color: var(--w-primary); }

/* ---- the week strip on the HR hub ---- */
.hr-month { font-size: 17px; font-weight: 600; margin: 2px 0 10px; }
.hr-week { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.hr-day { text-align: center; padding: 6px 0 8px; border-radius: 10px; }
.hr-day small { display: block; font-size: 11.5px; color: var(--w-muted); margin-bottom: 2px; }
.hr-day b { font-size: 17px; font-weight: 600; font-variant-numeric: tabular-nums; }
.hr-day + .hr-day { border-left: 1px solid var(--w-border); }
.hr-day.today { background: var(--w-primary); border-left-color: transparent; }
.hr-day.today small, .hr-day.today b { color: #fff; }
.hr-shift { margin: 12px 0 0; padding-top: 10px; border-top: 1px solid var(--w-border); color: var(--w-muted); font-size: 13.5px; }
.m-card .mt-3 { margin-top: 12px; }

/* ---- chat: the search row and the list in card form ---- */
/* the search box, then announce, then a plus to start a chat. No heading: the magnifier and the
   placeholder already say what the box is, and a title above it only pushed the list further down. */
.chat-filter-head { display: flex; align-items: center; gap: 8px; }
.chat-filter-head .chat-search { flex: 1 1 auto; flex-basis: auto; min-width: 0; margin: 0; order: 0; }
/* starting a chat: where the chevron was, and filled, because it is the one thing on this row that
   makes something rather than narrowing something */
.chat-new-btn {
    flex: none; display: inline-flex; align-items: center; justify-content: center;
    width: 40px; height: 40px; border-radius: 10px;
    background: var(--w-primary); color: #fff; text-decoration: none;
}
.chat-new-btn:hover, .chat-new-btn:focus { background: var(--w-primary-dark); color: #fff; text-decoration: none; }
.chat-new-btn i { font-size: 17px; line-height: 1; }
.chat-list { padding-left: 12px; padding-right: 12px; }
.chat-list .chat-row { border-bottom: 1px solid var(--w-border); }
.chat-list .chat-row:last-child { border-bottom: 0; }

/* Every page carries the bar now, so every page needs the room for it — pages that set
   .has-tabbar themselves keep their own value, this is the floor for the rest. */
/* The bar is on every page at every width now, so every page needs the room for it — pages that set
   .has-tabbar themselves keep their own value, this is the floor for the rest.
   env(safe-area-inset-bottom) resolves to 0 where there is no notch, so these hold on desktop too. */
body { padding-bottom: calc(var(--app-tabbar-h) + env(safe-area-inset-bottom) + 14px); }
body.has-tabbar-none { padding-bottom: 0; }

/* A form's save bar is also fixed to the bottom and sits above the tabs on z-index, which left
   the tabs visible but untappable — a tap there hit the save bar. Stack them instead: the save
   bar rides directly on top of the tab bar, and the page leaves room for both. */
.action-bar { bottom: calc(var(--app-tabbar-h) + env(safe-area-inset-bottom)); }
.has-action-bar, body:has(.action-bar) {
    padding-bottom: calc(var(--app-tabbar-h) + env(safe-area-inset-bottom) + 86px);
}

/* The chat conversation is a full-height flex column that owns the whole viewport, so the bar takes
   its place as the last row instead of floating over the composer someone is typing in. */
body.chat-body .app-tabbar { position: static; flex: none; }
body.chat-body { padding-bottom: 0; }

/* ---- collapsible panel: one row of a settings page, opened by tapping its header ----
   Built on <details> so it works with the keyboard and without JavaScript; the script only
   remembers which panels were left open. */
.m-panel { background: var(--w-surface); border-radius: 16px; margin-bottom: 12px; box-shadow: 0 1px 2px rgba(16, 24, 40, .05); overflow: hidden; }
.m-panel > summary {
    display: flex; align-items: center; gap: 12px;
    padding: 15px 16px; cursor: pointer; list-style: none;
    font-size: 16px; font-weight: 700; color: var(--w-text);
}
.m-panel > summary::-webkit-details-marker { display: none; }
.m-panel > summary:hover { background: var(--w-bg); }
.m-panel-ico {
    width: 34px; height: 34px; border-radius: 10px; flex: none;
    background: var(--w-primary-soft); color: var(--w-primary);
    display: flex; align-items: center; justify-content: center; font-size: 18px;
}
.m-panel-title { flex: 1; min-width: 0; }
.m-panel-title small { display: block; font-size: 12.5px; font-weight: 400; color: var(--w-muted); margin-top: 1px; }
.m-panel-chev { flex: none; color: #b9c2be; font-size: 14px; transition: transform .18s ease; }
.m-panel[open] > summary .m-panel-chev { transform: rotate(180deg); }
.m-panel[open] > summary { border-bottom: 1px solid var(--w-border); }
.m-panel-body { padding: 16px; }
@media (prefers-reduced-motion: reduce) { .m-panel-chev { transition: none; } }

/* ---- a sub-heading and a "see all" link inside a panel ---- */
.m-sub-head { font-size: 13px; font-weight: 700; color: var(--w-muted); text-transform: none; margin: 18px 0 2px; }
.m-panel-body > .m-row:last-of-type { border-bottom: 0; }
.m-see-all { display: inline-flex; align-items: center; gap: 4px; margin-top: 10px; font-size: 13.5px; font-weight: 600; color: var(--w-primary); text-decoration: none; }
.m-see-all:hover { text-decoration: none; color: var(--w-primary-dark); }
.m-panel-body .m-action + .m-sub-head { margin-top: 20px; }

/* HR sets the employee's name, so it reads as text — a box would invite someone to type in it */
.p-name { margin: 2px 0 4px; font-size: 17px; font-weight: 600; color: var(--w-text); line-height: 1.35; }

/* ---- the shared action button ----
   This once lived only in the warehouse stylesheet (removed with the WMS).
   Three screens outside the warehouse use the class — admin/org.php, admin/user_positions.php and
   chat/index.php — so on those the buttons had no rule at all and fell back to the browser's own:
   flat grey, square corners, a 2px outset border, 29px tall beside a 48px input. Defining it here
   puts it on every page, and wms.css no longer carries a second copy to drift from.
   The size matches what the warehouse screens already had, so none of them move. */
.btn-wms {
    display: inline-flex; align-items: center; justify-content: center; gap: 7px;
    min-height: 38px; padding: 0 15px;
    border: 1px solid var(--w-border-strong); border-radius: var(--w-radius-sm);
    background: var(--w-surface); color: var(--w-text);
    font: inherit; font-size: 14px; font-weight: 600; line-height: 1;
    cursor: pointer; white-space: nowrap;
    transition: background .15s ease, border-color .15s ease, color .15s ease;
}
.btn-wms:hover, .btn-wms:focus { background: var(--w-bg); color: var(--w-text); text-decoration: none; }
.btn-wms i { font-size: 16px; line-height: 1; }

.btn-wms.primary { background: var(--w-primary); border-color: var(--w-primary); color: #fff; }
.btn-wms.primary:hover, .btn-wms.primary:focus { background: var(--w-primary-dark); border-color: var(--w-primary-dark); color: #fff; }

.btn-wms.danger { color: var(--w-danger); border-color: var(--w-danger-border); background: var(--w-surface); }
.btn-wms.danger:hover, .btn-wms.danger:focus { background: var(--w-danger-soft); color: var(--w-danger); }

.btn-wms:disabled, .btn-wms.disabled { opacity: .5; cursor: not-allowed; }

/* Beside a form control the button takes the control's height (.form-control is min-height 48px),
   so the row reads as one line rather than a tall field with a short button floating next to it.
   These four are every container in the codebase that puts a field and a button on the same row. */
.wms-toolbar .btn-wms,
.wms-scan .btn-wms,
.wms-actions .btn-wms,
.org-line .btn-wms,
.m-panel-body form .btn-wms { min-height: 48px; padding: 0 18px; }
.wms-actions { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }

/* the pager is a row of its own and keeps its compact size */
.wms-pager-links .btn-wms { min-height: 36px; padding: 6px 10px; }

/* the withdrawal filter row: branch, person and two dates on one line, stacking when narrow */
.checkin-filter-form .wd-date { flex: 1 1 130px; min-width: 120px; margin: 0; display: flex; flex-direction: column; gap: 3px; }
.checkin-filter-form .wd-date small { color: var(--w-muted); font-size: 12px; }

/* the small cash/box marker beside a withdrawal, in the calendar cell and in the day detail */
.cal-wd-ico { font-size: .95em; opacity: .85; margin-right: 1px; }

/* the month's withdrawals at a glance: cash, goods, and the two together */
.wd-sum { border: 1px solid var(--w-border); border-radius: 12px; padding: 10px 12px 12px; margin-bottom: 12px; }
.wd-sum-head { font-size: 13px; font-weight: 600; color: var(--w-muted); margin-bottom: 8px; }
.wd-sum-parts { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.wd-sum-part { display: flex; flex-direction: column; align-items: center; gap: 2px; text-align: center; }
.wd-sum-part + .wd-sum-part { border-left: 1px solid var(--w-border); }
.wd-sum-part i { font-size: 17px; color: var(--w-muted); line-height: 1; }
.wd-sum-part small { font-size: 11.5px; color: var(--w-muted); line-height: 1.2; }
.wd-sum-part b { font-size: 16px; font-weight: 700; font-variant-numeric: tabular-nums; }
.wd-sum-part em { font-style: normal; font-size: 11px; color: var(--w-muted); }
.wd-sum-total i, .wd-sum-total b { color: var(--w-primary); }

/* The days either side of the month fill the first and last week out to seven. They are context,
   not this month, so they sit back: a darker, flatter ground and dimmed contents. Everything on
   them still works — they carry real dates and real data — they just do not compete for attention.
   This comes first so the holiday and weekly-off rules below still tint the ones that need it. */
.cal-cell.is-other-month { background: #eceef0; }
.cal-cell.is-other-month .cal-day-num { color: #9aa2a8; font-weight: 500; }
.cal-cell.is-other-month > *:not(.cal-day-num) { opacity: .55; }

/* The weekly day off is routine, a named holiday is not — so the routine one is grey and the
   named one red. Both say "closed"; only one is worth noticing. */
.cal-cell.is-weekly-off { background: var(--w-bg); }
.cal-cell.is-weekly-off .cal-day-num { color: var(--w-muted); }
.cal-weekly-off {
    display: block; margin-top: 2px; font-size: 9.5px; line-height: 1.15;
    color: var(--w-muted); font-weight: 600;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* a company holiday: the day is closed, so it reads differently from a day someone chose off */
.cal-cell.is-holiday { background: var(--w-danger-soft); }
.cal-cell.is-holiday .cal-day-num { color: var(--w-danger); font-weight: 700; }
.cal-holiday {
    display: block; margin-top: 2px; font-size: 9.5px; line-height: 1.15;
    color: var(--w-danger); font-weight: 600;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ---- clocking in is green, clocking out is red ----
   These two say which direction you are moving, so they are fixed colours rather than the role
   palette. --w-primary is red for a super admin and gold for a company admin, which made the
   "เข้างาน" button red for exactly the people who look at it most — and red next to a red
   "ออกงาน" says nothing at all. One pair of tokens, used by the toggle and the history alike. */
:root {
    --w-in: #1b7f4b;  --w-in-soft: #e8f5ed;  --w-in-strong: #14603a;
    --w-out: #c62828; --w-out-soft: #fdecea; --w-out-strong: #a01d1d;
}
/* later than style.css, so these win over the role-coloured and the blanket locked rules there */
#typeIn:checked + .type-toggle-in,
.type-toggle-in.is-locked  { background: var(--w-in-soft);  border-color: var(--w-in);  color: var(--w-in); }
#typeOut:checked + .type-toggle-out,
.type-toggle-out.is-locked { background: var(--w-out-soft); border-color: var(--w-out); color: var(--w-out); }

/* ---- attendance history: one card per day, check-in on the left, check-out on the right ---- */
.att-day { border: 1px solid var(--w-border); border-radius: 12px; padding: 10px 12px 12px; margin-bottom: 10px; }
.att-date { font-size: 13px; font-weight: 600; color: var(--w-muted); display: flex; align-items: center; gap: 6px; margin-bottom: 8px; }
.att-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.att-pair + .att-pair { margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--w-border); }
.att-side { text-align: center; padding: 8px 6px; border-radius: 10px; }
.att-in  { background: var(--w-in-soft); }
.att-out { background: var(--w-out-soft); }
.att-label { font-size: 12.5px; font-weight: 700; }
.att-in .att-label  { color: var(--w-in); }
.att-out .att-label { color: var(--w-out); }
.att-time { font-size: 19px; font-weight: 700; font-variant-numeric: tabular-nums; margin: 2px 0 8px; }
.att-in .att-time  { color: var(--w-in-strong); }
.att-out .att-time { color: var(--w-out-strong); }
.att-time.att-missing { color: var(--w-muted); font-weight: 500; }
.att-photo { display: block; width: 100%; aspect-ratio: 1 / 1; border-radius: 10px; overflow: hidden; background: rgba(0,0,0,.05); }
.att-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.att-photo-none { display: flex; align-items: center; justify-content: center; color: var(--w-muted); font-size: 20px; }

/* a history row that leads with a photo instead of an icon */
.m-row-media .m-thumb { width: 52px; height: 52px; border-radius: 10px; overflow: hidden; flex: none; display: block; background: rgba(0,0,0,.05); }
.m-row-media .m-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ---- organisation editor: a division, the departments under it, and the position list ---- */
.org-division { border: 1px solid var(--w-border); border-radius: 12px; padding: 10px; margin-bottom: 12px; }
.org-division.is-off { opacity: .55; }
.org-departments { padding-left: 14px; border-left: 2px solid var(--w-primary-soft); margin: 8px 0 0 6px; }
/* Each row is its own little form: change a name, tick active, press save. The row has six things
   in it and the panel is ~570px wide, so it wraps — and when it did, the save button landed on a
   line by itself looking like it belonged to nothing. Pushed to the end and kept with the row. */
/* Each row is its own little form: change a name, tick active, press save. The department row
   carries six things — tag, name, which division, order, active, save — in about 530px, and at the
   old widths the save button was pushed onto a line of its own looking like it belonged to nothing.
   These sizes are what let the whole row sit on one line; the dashed rule keeps a wrapped row
   visibly together when the screen really is too narrow. */
.org-line { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-bottom: 8px;
            padding-bottom: 8px; border-bottom: 1px dashed var(--w-border); }
.org-line:last-child { border-bottom: 0; }
/* the save button is the last thing to fit, so it gets the tighter padding of the two */
.org-line .org-save { margin-left: auto; flex: none; padding: 0 12px; }
.org-line.is-off { opacity: .55; }
/* basis equal to min-width: wrapping is decided on the basis, and shrinking only happens after a
   line is already full — a basis wider than the minimum pushed the button onto its own line */
.org-line .form-control { flex: 1 1 96px; min-width: 96px; }
.org-line .org-sort { flex: 0 0 60px; min-width: 60px; }
.org-line .org-scope, .org-line .org-move { flex: 0 0 auto; width: auto; min-width: 104px; }
.org-tag { flex: none; font-size: 11.5px; font-weight: 700; padding: 3px 8px; border-radius: 999px; }
/* what a position lets its holder do — folded away under each position, since most of the time
   you are renaming or reordering, not changing what the job may do */
.org-perms { margin: -4px 0 10px 0; }
.org-perms > summary {
    display: flex; align-items: center; gap: 7px; cursor: pointer; list-style: none;
    padding: 7px 10px; border-radius: var(--w-radius-sm); background: var(--w-bg);
    font-size: 13px; font-weight: 600; color: var(--w-muted);
}
.org-perms > summary::-webkit-details-marker { display: none; }
.org-perms > summary:hover { color: var(--w-text); }
.org-perm-count {
    margin-left: auto; min-width: 20px; height: 20px; padding: 0 6px; border-radius: 10px;
    background: var(--w-primary-soft); color: var(--w-primary);
    font-size: 11.5px; font-weight: 700; line-height: 20px; text-align: center;
}
.org-perm-form { padding: 10px 2px 2px; }
.org-perm-group + .org-perm-group { margin-top: 10px; }
.org-perm-group-head { font-size: 12px; font-weight: 700; color: var(--w-muted); margin-bottom: 4px; }

.org-tag-company { background: #fde8ef; color: #9d174d; }
.org-tag-division { background: var(--w-primary-soft); color: var(--w-primary); }
.org-tag-department { background: var(--w-bg); color: var(--w-muted); }
.org-rank { flex: none; width: 26px; height: 26px; border-radius: 50%; background: var(--w-primary-soft); color: var(--w-primary);
    display: inline-flex; align-items: center; justify-content: center; font-size: 12.5px; font-weight: 700; }
.org-active { flex: none; display: inline-flex; align-items: center; gap: 5px; margin: 0; font-size: 13px; color: var(--w-muted); }
.org-active input { width: 16px; height: 16px; }
.org-add { padding-top: 6px; border-top: 1px dashed var(--w-border); }
.org-add-division { margin-top: 10px; }

/* ---- a plain table for the non-WMS pages ------------------------------------------------
   .wms-table lived in the warehouse stylesheet (removed with the WMS). Same look, defined where
   every page can reach it. */
.table-wrap { overflow-x: auto; border: 1px solid var(--w-border); border-radius: 10px; background: var(--w-surface); }
.table-lite { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.table-lite th {
    font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--w-muted);
    text-align: left; padding: 8px 10px; background: var(--w-bg);
    border-bottom: 1px solid var(--w-border); white-space: nowrap;
}
.table-lite td { padding: 8px 10px; border-bottom: 1px solid var(--w-border); vertical-align: top; }
.table-lite tr:last-child td { border-bottom: 0; }

/* a notice that is neither good news nor bad — "waiting on somebody else" */
.alert-info { background: #eef4fb; color: #1d4ed8; border-color: #cfe0f5; }

/* ---- the company's @name ---------------------------------------------------------------- */
.slug-now {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    padding: 12px 14px; margin: 10px 0; border: 1px solid var(--w-border);
    border-radius: 10px; background: var(--w-bg);
}
.slug-now-label { font-size: 12.5px; color: var(--w-muted); }
.slug-now-value {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 18px; font-weight: 700;
    color: var(--w-primary); background: var(--w-surface);
    padding: 4px 10px; border-radius: 7px; border: 1px solid var(--w-border);
}
/* the @ sits inside the field so it is plain that only the part after it is being typed */
.slug-input { position: relative; }
.slug-input-at {
    position: absolute; left: 14px; top: 50%; transform: translateY(-50%);
    font-size: 17px; font-weight: 700; color: var(--w-muted); pointer-events: none;
}
.slug-input .form-control { padding-left: 32px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

.slug-req { padding: 14px; border: 1px solid var(--w-border); border-radius: 12px; background: var(--w-surface); }
.slug-req + .slug-req { margin-top: 12px; }
.slug-req-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.slug-req-move { display: inline-flex; align-items: center; gap: 8px; font-size: 14px; }
.slug-req-move code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.slug-req-want { color: var(--w-primary); font-weight: 700; }
.slug-req-fields { max-width: 320px; }

/* ---- announcements ---------------------------------------------------------------------
   The megaphone sits beside the search box, and only a position carrying chat.announce draws it. */
.chat-announce-btn {
    flex: none; display: inline-flex; align-items: center; justify-content: center;
    width: 40px; height: 40px; border: 1px solid var(--w-border); border-radius: 10px;
    background: var(--w-surface); color: var(--w-primary); text-decoration: none;
}
.chat-announce-btn:hover, .chat-announce-btn:focus { background: var(--w-primary-soft); color: var(--w-primary); text-decoration: none; }
.chat-announce-btn i { font-size: 15px; line-height: 1; }
.chat-filter-head .chat-announce-btn { order: 1; }
.chat-filter-head .chat-new-btn { order: 2; }

.announce-branch {
    margin: 12px 0 4px; font-size: 12px; font-weight: 700; letter-spacing: .04em;
    text-transform: uppercase; color: var(--w-muted);
}
.announce-branch:first-of-type { margin-top: 4px; }

/* An announcement lands in a thread that otherwise looks like any other private chat, so it says
   what it is. The stripe is on the leading edge, where the eye already is. */
.msg-bubble.is-announce { border-left: 3px solid var(--w-primary); }
.msg-announce-tag {
    display: flex; align-items: center; gap: 5px; margin-bottom: 5px;
    font-size: 11px; font-weight: 700; letter-spacing: .04em; color: var(--w-primary);
}
.msg-announce-tag i { font-size: 11px; }
/* the company's face on an announcement, where a person's photo would otherwise be */
.chat-avatar.is-company, .msg-avatar.is-company {
    background: var(--w-primary-soft); color: var(--w-primary);
    display: inline-flex; align-items: center; justify-content: center;
}
.login-name-hint { margin: 6px 0 14px; font-size: 12.5px; line-height: 1.45; }
/* who actually pressed send. The announcement is from the company; this says who signed it. */
.msg-announce-by {
    margin-top: 6px; padding-top: 5px; border-top: 1px solid var(--w-border);
    font-size: 11.5px; color: var(--w-muted);
}

/* ---- Dropbox storage pool ---------------------------------------------------------------- */
.dbx-queue { display: flex; gap: 10px; flex-wrap: wrap; margin: 4px 0 10px; }
.dbx-stat {
    flex: 1 1 80px; min-width: 0; padding: 10px 12px; border: 1px solid var(--w-border);
    border-radius: 10px; background: var(--w-bg);
}
.dbx-stat b { display: block; font-size: 21px; line-height: 1.1; font-variant-numeric: tabular-nums; }
.dbx-stat small { display: block; font-size: 11.5px; color: var(--w-muted); margin-top: 2px; }
.dbx-stat.is-bad b { color: var(--w-danger); }

.dbx-acct { padding: 14px 0; border-bottom: 1px solid var(--w-border); }
.dbx-acct:last-of-type { border-bottom: 0; }
.dbx-acct-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; margin-bottom: 7px; }
.dbx-acct-num { margin-left: auto; font-size: 12.5px; color: var(--w-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.dbx-bar { height: 9px; border-radius: 5px; background: var(--w-border); overflow: hidden; }
.dbx-bar span { display: block; height: 100%; border-radius: 5px; }
.dbx-bar span.ok { background: var(--w-in, #2e7d32); }
.dbx-bar span.warn { background: #e8710a; }
.dbx-bar span.crit { background: var(--w-danger, #d32f2f); }
.dbx-bar span.off { background: var(--w-muted); }
.dbx-acct-note { font-size: 12px; color: var(--w-muted); margin-top: 6px; }
.dbx-acct-err { font-size: 12.5px; color: var(--w-danger); margin-top: 5px; }
.dbx-acct-actions { display: flex; gap: 8px; align-items: center; margin-top: 10px; max-width: 320px; }
.dbx-acct-actions .form-control { flex: 1 1 auto; min-width: 0; }
.dbx-inline { margin: 0; }

.dbx-tag { display: inline-block; font-size: 10.5px; font-weight: 700; letter-spacing: .06em; padding: 2px 7px; border-radius: 4px; }
.dbx-tag.ok { background: var(--w-primary-soft); color: var(--w-primary); }
.dbx-tag.warn { background: #fdf0e3; color: #9a5b06; }
.dbx-tag.crit { background: var(--w-danger-soft); color: var(--w-danger); }
.dbx-tag.off { background: var(--w-bg); color: var(--w-muted); }
.ret-row {
    display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap;
    padding: 12px 0; border-bottom: 1px solid var(--w-border);
}
.ret-row:last-of-type { border-bottom: 0; }
.ret-co { flex: 1 1 150px; min-width: 0; }
.ret-co b { display: block; font-size: 15px; }
.ret-co small { display: block; font-size: 12px; color: var(--w-muted); }
.ret-field { flex: 0 1 165px; margin: 0; }
.ret-field span { display: block; font-size: 11.5px; color: var(--w-muted); margin-bottom: 3px; }
/* what a bubble shows once retention has taken the bytes */
.msg-expired {
    display: flex; align-items: center; gap: 7px; padding: 8px 10px;
    border: 1px dashed var(--w-border); border-radius: 8px;
    font-size: 13px; color: var(--w-muted);
}
.ret-pair { display: flex; gap: 10px; flex-wrap: wrap; }
.ret-pair .ret-field { flex: 1 1 160px; }
.dbx-bar.mb-2 { margin-bottom: 12px; }

/* ---- chat file storage: what is there, and clearing some out ----------------------------- */
.cs-total { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; }
.cs-total b { font-size: 26px; line-height: 1.1; font-variant-numeric: tabular-nums; }
.cs-total span { font-size: 14px; color: var(--w-muted); }
.cs-total small { margin-left: auto; font-size: 12.5px; color: var(--w-muted); }

.cs-kinds { display: flex; flex-direction: column; gap: 2px; margin-top: 10px; }
.cs-kind { display: flex; align-items: center; gap: 10px; padding: 9px 0; border-bottom: 1px solid var(--w-border); }
.cs-kind:last-child { border-bottom: 0; }
.cs-kind-ico {
    flex: none; width: 32px; height: 32px; border-radius: 9px; background: var(--w-bg);
    display: inline-flex; align-items: center; justify-content: center; color: var(--w-muted);
}
.cs-kind-body { flex: 1 1 auto; min-width: 0; }
.cs-kind-body b { display: block; font-size: 14.5px; }
.cs-kind-body small { display: block; font-size: 12px; color: var(--w-muted); }
.cs-kind-size { flex: none; font-size: 14px; font-variant-numeric: tabular-nums; }

.cs-days, .cs-range { display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end; }
.cs-days .ret-field { flex: 1 1 150px; }
.cs-range .ret-field { flex: 0 1 165px; }
.cs-purge-kinds { display: flex; flex-direction: column; gap: 2px; margin-bottom: 12px; }

.cs-preview {
    margin-top: 14px; padding: 14px; border: 1px solid var(--w-danger-border, var(--w-border));
    border-radius: 10px; background: var(--w-danger-soft, var(--w-bg));
}
.cs-preview.is-empty { border-color: var(--w-border); background: var(--w-bg); color: var(--w-muted); font-size: 13.5px; }
.cs-preview-head { margin-bottom: 10px; }
.cs-preview-head b { display: block; font-size: 15.5px; }
.cs-preview-head small { display: block; font-size: 12.5px; color: var(--w-muted); margin-top: 2px; }

/* ---- replying, reacting, finding ---------------------------------------------------------- */
.msg-quote {
    display: block; width: 100%; text-align: left; margin: 0 0 6px; padding: 5px 8px;
    border: 0; border-left: 3px solid var(--w-primary); border-radius: 6px;
    background: rgba(0, 0, 0, .05); cursor: pointer; font: inherit;
}
.msg-quote-name { display: block; font-size: 11.5px; font-weight: 700; color: var(--w-primary); }
.msg-quote-text { display: block; font-size: 12.5px; color: var(--w-muted);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.msg-row.is-flash .msg-bubble { animation: msgFlash 1.4s ease; }
@keyframes msgFlash { 0%, 60% { box-shadow: 0 0 0 3px var(--w-primary-soft); } 100% { box-shadow: none; } }
@media (prefers-reduced-motion: reduce) { .msg-row.is-flash .msg-bubble { animation: none; box-shadow: 0 0 0 3px var(--w-primary-soft); } }

.msg-reacts { display: flex; gap: 4px; flex-wrap: wrap; margin: 4px 0 0; }
.msg-react {
    display: inline-flex; align-items: center; gap: 3px; padding: 1px 7px;
    border: 1px solid var(--w-border); border-radius: 999px; background: var(--w-surface);
    font-size: 13px; line-height: 1.6; cursor: pointer;
}
.msg-react.mine { border-color: var(--w-primary); background: var(--w-primary-soft); }
.msg-react span { font-size: 11.5px; font-weight: 700; color: var(--w-muted); }
.msg-react.mine span { color: var(--w-primary); }
.msg-reply-btn, .msg-react-btn {
    border: 0; background: none; padding: 0 6px 0 0; font-size: 11.5px; color: var(--w-muted); cursor: pointer;
}
.msg-reply-btn:hover, .msg-react-btn:hover { color: var(--w-primary); }

.react-picker {
    position: fixed; z-index: 60; display: flex; gap: 2px; padding: 5px 7px;
    background: var(--w-surface); border: 1px solid var(--w-border); border-radius: 999px;
    box-shadow: 0 6px 20px rgba(16, 24, 40, .16);
}
.react-picker button { border: 0; background: none; font-size: 20px; line-height: 1; padding: 3px 4px; cursor: pointer; border-radius: 50%; }
.react-picker button:hover { background: var(--w-bg); }

.composer-reply {
    display: flex; align-items: center; gap: 8px; padding: 7px 10px; margin-bottom: 6px;
    border-left: 3px solid var(--w-primary); border-radius: 6px; background: var(--w-bg);
}
/* the picture being answered, where there is one — small enough to stay a label, not a preview pane */
.composer-reply-thumb {
    flex: none; width: 34px; height: 34px; border-radius: 6px; object-fit: cover;
    background: var(--w-bg);
}
.composer-reply-body { flex: 1 1 auto; min-width: 0; }
.composer-reply-body b { display: block; font-size: 12px; color: var(--w-primary); }
.composer-reply-body small { display: block; font-size: 12px; color: var(--w-muted);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.composer-reply-x { flex: none; border: 0; background: none; color: var(--w-muted); cursor: pointer; padding: 4px; }

.chat-find { padding: 8px 12px; border-bottom: 1px solid var(--w-border); background: var(--w-surface); }
.chat-find-results { max-height: 45vh; overflow-y: auto; margin-top: 6px; }
.chat-find-hit {
    display: block; width: 100%; text-align: left; border: 0; border-bottom: 1px solid var(--w-border);
    background: none; padding: 8px 2px; cursor: pointer; font: inherit;
}
.chat-find-hit:last-child { border-bottom: 0; }
.chat-find-hit b { font-size: 13px; }
.chat-find-hit small { font-size: 11.5px; color: var(--w-muted); margin-left: 6px; }
.chat-find-hit span { display: block; font-size: 13px; color: var(--w-text); margin-top: 2px; }
.chat-find-none { padding: 10px 2px; font-size: 13px; color: var(--w-muted); }
.chat-call-btn.is-on { color: var(--w-danger); }

/* ---- the media list ---- */
.media-row { display: flex; align-items: center; gap: 10px; padding: 9px 0; border-bottom: 1px solid var(--w-border); }
.media-row:last-child { border-bottom: 0; }
.media-row.is-gone { opacity: .55; }
.media-thumb { flex: none; width: 44px; height: 44px; border-radius: 9px; overflow: hidden; background: var(--w-bg); }
.media-thumb img { width: 100%; height: 100%; object-fit: cover; }
.media-ico { display: inline-flex; align-items: center; justify-content: center; color: var(--w-muted); font-size: 18px; }
.media-body { flex: 1 1 auto; min-width: 0; }
.media-body b { display: block; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.media-body small { display: block; font-size: 11.5px; color: var(--w-muted); }
.media-open, .media-jump { flex: none; padding: 6px; color: var(--w-muted); }
.media-gone { flex: none; font-size: 11.5px; color: var(--w-muted); }

/* ---- who read an announcement ---- */
.ar-head { margin-bottom: 8px; }
.ar-body { font-size: 14.5px; }
.ar-head small { font-size: 11.5px; color: var(--w-muted); }
.ar-count { font-size: 13px; color: var(--w-muted); margin-bottom: 5px; }
.ar-count b { font-size: 16px; color: var(--w-text); font-variant-numeric: tabular-nums; }
.ar-group { margin-top: 12px; }
.ar-group-head { font-size: 12.5px; font-weight: 700; margin-bottom: 4px; cursor: pointer; }
.ar-group-head.ar-unread { color: var(--w-danger); }
.ar-group-head.ar-read { color: var(--w-primary); }
.ar-person { font-size: 13.5px; padding: 3px 0 3px 18px; }
.ar-person small { font-size: 11.5px; color: var(--w-muted); margin-left: 6px; }

/* ---- the unread line, the pinned bar, @everyone ------------------------------------------- */
.msg-unread-line {
    display: flex; align-items: center; gap: 10px; margin: 14px 0 8px;
    font-size: 11.5px; font-weight: 700; color: var(--w-danger);
}
.msg-unread-line::before, .msg-unread-line::after {
    content: ''; flex: 1 1 auto; height: 1px; background: var(--w-danger); opacity: .35;
}

.chat-pinned {
    display: flex; align-items: center; gap: 8px; padding: 8px 12px;
    background: var(--w-primary-soft); border-bottom: 1px solid var(--w-border); color: var(--w-primary);
}
.chat-pinned > i { flex: none; font-size: 14px; }
.chat-pinned-body {
    flex: 1 1 auto; min-width: 0; text-align: left; border: 0; background: none;
    padding: 0; cursor: pointer; font: inherit; color: inherit;
}
.chat-pinned-body b { display: block; font-size: 11.5px; }
.chat-pinned-body span {
    display: block; font-size: 12.5px; color: var(--w-text); opacity: .8;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chat-pinned-x { flex: none; border: 0; background: none; color: inherit; cursor: pointer; padding: 4px; }
.msg-pin-btn { border: 0; background: none; padding: 0 6px 0 0; font-size: 12px; color: var(--w-muted); cursor: pointer; }
.msg-pin-btn:hover { color: var(--w-primary); }

.mention-all { font-weight: 700; }

/* ---- the chat header ------------------------------------------------------------------------
   It once carried up to seven round icons in a row: choose, notes, search, pictures, bell, call,
   video, settings. At 390px the last of them sat past the edge and the title had been squeezed to
   nothing — and even where they fitted, nothing said which was which.
   Search keeps its button, because finding a line is the thing done often. Everything else is in
   the menu, where each has its name beside it. */
.chat-header-text { flex: 1 1 auto; min-width: 0; }
.chat-header-menu { position: relative; flex: none; }
.chat-menu {
    position: absolute; top: calc(100% + 8px); right: 0; z-index: 60;
    min-width: 232px; max-width: calc(100vw - 24px);
    padding: 6px; border-radius: 14px;
    background: var(--w-surface); border: 1px solid var(--w-border);
    box-shadow: 0 14px 34px rgba(16, 24, 40, .18);
    animation: chat-menu-in .16s ease;
}
.chat-menu[hidden] { display: none; }
@keyframes chat-menu-in { from { opacity: 0; transform: translateY(-8px); } }
.chat-menu-item {
    display: flex; align-items: center; gap: 11px; width: 100%;
    padding: 10px 11px; border: 0; border-radius: 10px; background: transparent;
    font-size: 14.5px; font-weight: 600; color: var(--w-text); text-align: left; cursor: pointer;
}
.chat-menu-item:hover, .chat-menu-item:focus-visible { background: var(--w-bg); color: var(--w-text); text-decoration: none; }
.chat-menu-item i { flex: none; width: 22px; text-align: center; font-size: 17px; color: var(--w-primary); }
.chat-menu-item span { flex: 1; min-width: 0; }
.chat-menu .chat-video-btn { margin-left: 0; }   /* the gap it took beside a round button indents the row here */
.chat-menu-item.is-on, .chat-menu-item.is-on i { color: var(--w-danger); }
.chat-menu-sep { height: 1px; margin: 5px 9px; background: var(--w-border); }
@media (prefers-reduced-motion: reduce) { .chat-menu { animation: none; } }
@media (max-width: 480px) {
    .chat-header { gap: 6px; padding-left: 10px; padding-right: 10px; }
    .chat-header .chat-call-btn { width: 36px; height: 36px; }
    .chat-header .chat-call-btn i { font-size: 16px; }
    .chat-header .chat-avatar { width: 38px; height: 38px; }
}

/* A quote inside my own bubble sits on the accent colour, where the muted grey it uses on a pale
   bubble is unreadable. Same shape, colours taken from the bubble it is on. */
.msg-row.me .msg-quote { background: rgba(255, 255, 255, .16); border-left-color: rgba(255, 255, 255, .75); }
.msg-row.me .msg-quote-name { color: #fff; }
.msg-row.me .msg-quote-text { color: rgba(255, 255, 255, .88); }

/* ---- choosing messages to keep ------------------------------------------------------------ */
body.is-selecting .msg-row { cursor: pointer; position: relative; }
body.is-selecting .msg-bubble { opacity: .7; }
body.is-selecting .msg-row.is-chosen .msg-bubble { opacity: 1; box-shadow: 0 0 0 2px var(--w-in, #2e7d32); }

/* A ring on every message while choosing, filled with a tick on the ones picked — the empty ring
   is what says "this is choosable", and the difference between the two reads at a glance. */
body.is-selecting .msg-row::after {
    content: ''; position: absolute; top: 50%; right: 4px; transform: translateY(-50%);
    width: 22px; height: 22px; border-radius: 50%;
    border: 2px solid var(--w-border); background: var(--w-surface);
    pointer-events: none; transition: background .12s ease, border-color .12s ease;
}
body.is-selecting .msg-row.is-chosen::after {
    border-color: var(--w-in, #2e7d32); background: var(--w-in, #2e7d32);
    /* a tick, drawn rather than fetched */
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23fff' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 8.5l3.2 3.2L13 5'/%3E%3C/svg%3E");
    background-size: 14px 14px; background-position: center; background-repeat: no-repeat;
}
/* room for the ring, so it never sits on top of the words */
body.is-selecting .msg-col { padding-right: 30px; }
body.is-selecting .msg-reply-btn,
body.is-selecting .msg-react-btn,
body.is-selecting .msg-pin-btn,
body.is-selecting .msg-share-btn,
body.is-selecting .msg-resend-btn,
body.is-selecting .msg-download-btn { visibility: hidden; }

.select-bar {
    display: flex; align-items: center; gap: 10px; padding: 9px 12px;
    background: var(--w-surface); border-top: 1px solid var(--w-border);
}
.select-count { flex: 1 1 auto; font-size: 13.5px; color: var(--w-muted); }
.select-count b { font-size: 16px; color: var(--w-text); font-variant-numeric: tabular-nums; }
.select-done {
    position: fixed; left: 50%; bottom: 90px; transform: translateX(-50%); z-index: 70;
    padding: 9px 16px; border-radius: 999px; background: var(--w-text); color: var(--w-surface);
    font-size: 13.5px; box-shadow: 0 6px 20px rgba(16, 24, 40, .22);
}

.note-picker { position: fixed; inset: 0; z-index: 65; background: rgba(16, 24, 40, .45); display: flex; align-items: flex-end; }
.note-picker-card {
    width: 100%; max-height: 80vh; max-height: 80dvh;
    display: flex; flex-direction: column; overflow: hidden;
    background: var(--w-surface);
    border-radius: 18px 18px 0 0; padding: 18px 16px calc(18px + env(safe-area-inset-bottom));
}
.note-picker-head { flex: none; font-size: 17px; font-weight: 700; margin: 0 0 12px; }
/* the only part that scrolls. min-height:0 or a flex child refuses to shrink below its content
   and the footer goes off the bottom, which is exactly what it did. */
.note-picker-list {
    flex: 1 1 auto; min-height: 0; overflow-y: auto;
    display: flex; flex-direction: column; gap: 2px; margin-bottom: 14px;
}
/* naming a new note never scrolls away: with no notes yet it is the only thing to do here */
.note-picker-foot { flex: none; border-top: 1px solid var(--w-border); padding-top: 12px; }
.note-pick {
    display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
    padding: 11px 12px; border: 1px solid var(--w-border); border-radius: 10px;
    background: var(--w-surface); cursor: pointer; font: inherit;
}
.note-pick:hover { background: var(--w-bg); }
.note-pick b { flex: 1 1 auto; min-width: 0; font-size: 14.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.note-pick small { flex: none; font-size: 12px; color: var(--w-muted); }
.note-picker-new { display: flex; gap: 8px; }
.note-picker-new .form-control { flex: 1 1 auto; min-width: 0; }

/* ---- a note and what is in it ---- */
.note-new, .note-inline { display: flex; gap: 8px; margin: 0; }
.note-new .form-control, .note-inline .form-control { flex: 1 1 auto; min-width: 0; }
.note-item-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 8px; }
.note-item-head b { font-size: 14.5px; }
.note-item-head small { flex: 1 1 auto; font-size: 11.5px; color: var(--w-muted); }
.note-item-x { margin: 0; }
.note-item-x button { border: 0; background: none; color: var(--w-muted); cursor: pointer; padding: 2px 4px; }
.note-item-body { font-size: 14.5px; margin-bottom: 8px; }
.note-item-img { display: block; width: 220px; max-width: 100%; border-radius: 10px; overflow: hidden; background: var(--w-bg); }
.note-item-img img { display: block; width: 100%; height: 160px; object-fit: cover; }
.note-item-go { display: inline-block; margin-top: 10px; font-size: 12.5px; }
.composer-none {
    display: flex; align-items: center; justify-content: center; gap: 8px;
    padding: 14px 12px; font-size: 13px; color: var(--w-muted);
    background: var(--w-bg); border-top: 1px solid var(--w-border);
}

/* ---- signing another browser in by scanning it --------------------------------------------
   Two screens are involved, so each has to say plainly which half it is doing: one shows a code
   to be photographed and then six digits to be read off it; the other holds the camera and then
   asks for those digits. */
.login-or { display: flex; align-items: center; gap: 10px; margin: 18px 0 12px; color: var(--w-muted); font-size: 12.5px; }
.login-or::before, .login-or::after { content: ""; flex: 1; height: 1px; background: var(--w-border); }
.login-qr-btn { width: 100%; justify-content: center; }
.login-qr { margin-top: 14px; text-align: center; }
.login-qr-box {
    display: inline-flex; padding: 10px; border-radius: 14px;
    background: #fff; border: 1px solid var(--w-border); min-height: 60px; min-width: 60px;
}
.login-qr-box svg { width: 190px; height: 190px; display: block; }
/* once it has been scanned there is nothing left to photograph — say so rather than inviting a
   second phone to try */
.login-qr-box.is-spent { opacity: .22; filter: grayscale(1); }
.login-qr-step { margin: 10px 0 0; font-size: 13px; color: var(--w-muted); line-height: 1.5; }
.login-qr-code { margin-top: 12px; }
.login-qr-code small { display: block; font-size: 12px; color: var(--w-muted); }
.login-qr-code b {
    display: block; margin-top: 2px;
    font-size: 34px; font-weight: 700; letter-spacing: .16em;
    font-variant-numeric: tabular-nums; color: var(--w-primary-dark);
}
.login-qr-again { margin-top: 12px; }

.scan-stage {
    position: relative; border-radius: 14px; overflow: hidden; background: #0b1220;
    aspect-ratio: 4 / 3; max-width: 100%; display: flex; align-items: center; justify-content: center;
}
.scan-stage video { width: 100%; height: 100%; object-fit: cover; display: block; }
.scan-frame {
    position: absolute; inset: 16% 14%; border: 2px solid rgba(255, 255, 255, .85); border-radius: 12px;
    box-shadow: 0 0 0 100vmax rgba(8, 14, 25, .35);
}
.scan-device { margin: 0 0 4px; font-weight: 700; font-size: 14.5px; }
.scan-code-input {
    text-align: center; font-size: 30px; font-weight: 700; letter-spacing: .3em;
    font-variant-numeric: tabular-nums; padding: 10px 12px;
}
.scan-err { margin: 10px 0 0; font-size: 13px; color: var(--w-danger); }
.scan-done { text-align: center; padding: 18px 8px 8px; }
.scan-done i { font-size: 42px; color: var(--w-ok, #15803d); }
.scan-done b { display: block; margin-top: 8px; font-size: 16px; }
.scan-done small { display: block; margin-top: 4px; font-size: 12.5px; color: var(--w-muted); line-height: 1.5; }

/* ---- the two browsers an account may be signed in on ---- */
.dev-row { display: flex; align-items: center; gap: 11px; padding: 11px 0; border-bottom: 1px solid var(--w-border); }
.dev-row:last-of-type { border-bottom: 0; }
.dev-ico {
    flex: none; width: 34px; height: 34px; border-radius: 10px;
    background: var(--w-primary-soft); color: var(--w-primary);
    display: flex; align-items: center; justify-content: center; font-size: 16px;
}
.dev-row.is-me .dev-ico { background: var(--w-primary); color: #fff; }
.dev-body { flex: 1; min-width: 0; }
.dev-body b { display: block; font-size: 14.5px; }
.dev-body small { display: block; font-size: 12px; color: var(--w-muted); margin-top: 1px; }
.dev-here { font-size: 11.5px; font-weight: 600; color: var(--w-primary); }
.dev-end { flex: none; margin: 0; }
.dev-end .btn-wms { padding: 6px 10px; font-size: 12.5px; }

/* ---- a message that is on screen before the server has it ---------------------------------
   The bubble is drawn the instant Send is pressed. It is dimmed, and carries a clock rather than
   a time, so the difference between "sent" and "on its way" is visible without being alarming. */
.msg-row.is-pending .msg-bubble { opacity: .62; }
.msg-row.is-pending .msg-image { max-width: 190px; border-radius: 12px; display: block; }
.msg-sending, .msg-failed { display: inline-flex; align-items: center; gap: 4px; font-size: 11.5px; color: var(--w-muted); }
.msg-sending i, .msg-failed i { font-size: 12px; }
.msg-row.is-failed .msg-bubble { opacity: .62; outline: 1px solid var(--w-danger); outline-offset: 1px; }
.msg-failed { color: var(--w-danger); }
.msg-retry-btn {
    border: 0; background: transparent; padding: 0 2px;
    font-size: 11.5px; font-weight: 700; color: var(--w-primary); cursor: pointer;
}
.msg-retry-btn:hover { text-decoration: underline; }
/* the one thing in the header menu that takes something away */
.chat-menu-item.is-danger, .chat-menu-item.is-danger i { color: var(--w-danger); }
.chat-menu-item.is-danger:hover { background: #fdecea; color: var(--w-danger); }

/* ---- a Facebook page or LINE account joined to the chat ------------------------------------ */
.chan-url { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
.chan-url code {
    flex: 1; min-width: 0; overflow-x: auto; white-space: nowrap;
    padding: 9px 10px; border-radius: 10px; background: var(--w-bg);
    font-size: 12px; color: var(--w-text); -webkit-overflow-scrolling: touch;
}
.chan-url .btn-wms { flex: none; padding: 8px 10px; }
.chan-url .form-control { flex: 1; min-width: 0; margin: 0; }
.chan-agents { display: grid; gap: 4px; margin-bottom: 4px; }
.chan-log {
    display: grid; gap: 2px;
    /* a channel keeps its last two hundred events, and setting one up produces a dozen in a minute.
       Fixed height and scroll, so the form above it stays reachable without a long scroll past it. */
    max-height: 150px; overflow-y: auto; -webkit-overflow-scrolling: touch;
    padding-right: 4px;
}
.chan-log-row { display: flex; align-items: center; gap: 9px; padding: 7px 0; border-bottom: 1px solid var(--w-border); }
.chan-log-row:last-child { border-bottom: 0; }
.chan-log-dir {
    flex: none; width: 26px; height: 26px; border-radius: 8px;
    background: var(--w-primary-soft); color: var(--w-primary);
    display: flex; align-items: center; justify-content: center; font-size: 13px;
}
.chan-log-row.is-bad .chan-log-dir { background: #fdecea; color: var(--w-danger); }
.chan-log-body { flex: 1; min-width: 0; }
.chan-log-body b { display: block; font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chan-log-body small { font-size: 11.5px; color: var(--w-muted); }
.chan-add .form-control { margin-bottom: 4px; }

/* the badge a room wears when the person on the other side is a customer, not a colleague */
.chat-ext-tag {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 1px 7px; border-radius: 9px; font-size: 11px; font-weight: 700;
    background: var(--w-primary-soft); color: var(--w-primary);
}
.chat-avatar.is-ext { background: var(--w-primary-soft); color: var(--w-primary); }

/* a reply the platform would not take. It is stored and on screen either way, so this is the only
   thing that stops the person who typed it believing the customer has it. */
.msg-relay-failed {
    display: flex; align-items: flex-start; gap: 5px; margin-top: 3px;
    font-size: 11.5px; line-height: 1.4; color: var(--w-danger);
}
.msg-relay-failed i { flex: none; margin-top: 1px; }

/* ---- the step-by-step for connecting a page or an account ---- */
.chan-guide { margin-bottom: 14px; border: 1px solid var(--w-border); border-radius: 12px; overflow: hidden; }
.chan-guide > summary {
    display: flex; align-items: center; gap: 8px; cursor: pointer; list-style: none;
    padding: 11px 12px; font-size: 14px; font-weight: 700; color: var(--w-primary-dark);
    background: var(--w-primary-soft);
}
.chan-guide > summary::-webkit-details-marker { display: none; }
.chan-guide > .hint { padding: 10px 12px 0; margin: 0; }
.chan-steps { margin: 8px 0 0; padding: 0 14px 0 30px; }
.chan-steps li { margin-bottom: 9px; font-size: 13.5px; line-height: 1.55; }
.chan-steps li::marker { font-weight: 700; color: var(--w-primary); }
.chan-guide-check {
    display: flex; align-items: flex-start; gap: 6px; margin: 4px 12px 12px;
    padding: 9px 10px; border-radius: 10px; background: var(--w-bg);
    font-size: 12.5px; line-height: 1.5; color: var(--w-muted);
}
.chan-guide-check i { flex: none; margin-top: 2px; color: var(--w-primary); }
.chan-warn { color: var(--w-danger); }

/* the shop's own reply, typed in Facebook's or LINE's inbox rather than here. It belongs to neither
   side: not the customer, and not anybody in this room. */
.msg-avatar.is-page { background: var(--w-primary-soft); color: var(--w-primary); display: inline-flex; align-items: center; justify-content: center; }
.msg-row .msg-sender { font-size: 11.5px; color: var(--w-primary); font-weight: 600; }

/* ---- which kind of conversation is being looked at: colleagues, a page, an official account ----
   A tab strip rather than a chip inside the filter fold: an inbox is a shift somebody works, and
   they should not have to unfold anything to get to it. */
.chat-tabs {
    display: flex; gap: 6px; overflow-x: auto; padding: 2px 2px 10px;
    -webkit-overflow-scrolling: touch; scrollbar-width: none;
}
.chat-tabs::-webkit-scrollbar { display: none; }
.chat-tab {
    flex: none; display: inline-flex; align-items: center; gap: 5px;
    padding: 7px 12px; border: 1px solid var(--w-border); border-radius: 999px;
    background: var(--w-surface); color: var(--w-muted);
    font-size: 13px; font-weight: 600; white-space: nowrap; cursor: pointer;
}
.chat-tab i { font-size: 14px; }
.chat-tab.active { background: var(--w-primary); border-color: var(--w-primary); color: #fff; }
.chat-tab-n {
    min-width: 18px; padding: 0 5px; border-radius: 9px;
    background: #e23b3b; color: #fff;
    font-size: 11px; font-weight: 700; line-height: 18px; text-align: center;
}
.chat-tab-n[hidden] { display: none; }
.chat-tab.active .chat-tab-n { background: rgba(255, 255, 255, .28); color: #fff; }

/* The second line of filters, under the tabs. Deliberately lighter than the row above it: the tab
   is the decision, this is which one within it, and two rows of equal weight would read as two
   competing questions. */
.chat-subs {
    display: flex; gap: 6px; overflow-x: auto; padding: 0 2px 10px; margin-top: -4px;
    -webkit-overflow-scrolling: touch; scrollbar-width: none;
}
.chat-subs::-webkit-scrollbar { display: none; }
.chat-sub-set { display: flex; gap: 6px; }
.chat-sub {
    flex: none; display: inline-flex; align-items: center; gap: 5px;
    padding: 5px 11px; border: 1px solid transparent; border-radius: 999px;
    background: var(--w-bg); color: var(--w-muted);
    font-size: 12px; font-weight: 600; white-space: nowrap; cursor: pointer;
    max-width: 180px;
}
.chat-sub > span:not(.chat-sub-n), .chat-sub { overflow: hidden; text-overflow: ellipsis; }
.chat-sub i { font-size: 13px; }
.chat-sub-mark { font-size: 13px; }
.chat-sub.active {
    background: var(--w-primary-soft); border-color: var(--w-primary-soft-border); color: var(--w-primary-dark);
}
.chat-sub-n {
    min-width: 17px; padding: 0 5px; border-radius: 9px;
    background: #e23b3b; color: #fff;
    font-size: 10.5px; font-weight: 700; line-height: 17px; text-align: center;
}
.chat-sub-n[hidden] { display: none; }

/* ---- a customer's own picture, with the platform's mark on it ------------------------------
   A customer and a colleague must never be mistaken for one another at a glance, and a photo alone
   would do exactly that. The mark sits on the picture, so it is there whether or not the picture
   loaded — the platforms hand out signed addresses that expire. */
.chat-avatar.is-ext, .msg-avatar.is-ext { position: relative; overflow: visible; }
.chat-avatar.is-ext.has-img img, .msg-avatar.is-ext.has-img img {
    width: 100%; height: 100%; border-radius: 50%; object-fit: cover; display: block;
}
/* a customer's name opens them on the platform they wrote from. The name is long — it carries the
   page it came from — so it truncates and the little arrow stays put beside it rather than being
   pushed off the row. */
.chat-header-link { display: flex; align-items: baseline; gap: 5px; min-width: 0; color: var(--w-text); text-decoration: none; }
.chat-header-link > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.chat-header-link:hover, .chat-header-link:focus { color: var(--w-primary); text-decoration: none; }
.chat-header-link i { font-size: 11px; color: var(--w-muted); flex: none; }
.chat-header-link:hover i { color: var(--w-primary); }

/* ---- the marks of the places a customer writes from ----------------------------------------
   Facebook's f is drawn inline, in Facebook's own blue, so it is the mark people recognise and
   nothing is fetched from anybody else's server. LINE keeps the icon font's glyph, white on
   LINE's green. */
.pmark { display: inline-flex; align-items: center; justify-content: center; flex: none; line-height: 1; }
.pmark svg { width: 1em; height: 1em; display: block; }
/* The LINE mark carries its own green tile now, the way the Facebook one carries its own blue
   disc, so the wrapper must not paint a circle behind it — that used to be how the icon font got
   its colour, and left on it would show as a green ring around the tile's rounded corners. */
.pmark-line { width: 1em; height: 1em; font-size: inherit; }
/* standing in for a missing photo, it fills the circle */
.pmark-fill { width: 100%; height: 100%; font-size: 1.15rem; }
.pmark-fill.pmark-line { border-radius: 50%; }
.chan-badge.pmark { position: absolute; right: -2px; bottom: -2px; font-size: 16px; box-shadow: 0 0 0 2px var(--w-surface); border-radius: 50%; background: var(--w-surface); }
/* square-ish, because the badge is a clip and LINE's mark is a rounded tile rather than a disc */
.chan-badge.pmark-line { border-radius: 5px; }
.msg-avatar .chan-badge.pmark { font-size: 13px; }
.chat-tab .pmark, .chat-ext-tag .pmark { font-size: 14px; }
.btn-wms .pmark { font-size: 15px; }
.m-panel-ico.is-plain { background: transparent; font-size: 26px; }
/* a group with a picture of its own */
.chat-avatar.is-group.has-img, .msg-avatar.is-group.has-img { background: none; padding: 0; }
.chat-avatar.is-group.has-img img, .msg-avatar.is-group.has-img img {
    width: 100%; height: 100%; border-radius: 50%; object-fit: cover; display: block;
}
.avatar-pick .chat-avatar.avatar-preview { width: 76px; height: 76px; font-size: 28px; }

/* ---- what can be done to a member, beside their name ---------------------------------------
   Two switches, not two sentences. Neither acts on the spot: they arm, the form saves, which is
   why they show a state. Armed is ringed so a row of them can be read before pressing save. */
.member-row { display: flex; align-items: center; gap: 8px; }
.member-row .member-row-text { flex: 1; min-width: 0; }
.mem-btn {
    flex: none; display: inline-flex; align-items: center; gap: 5px;
    height: 32px; padding: 0 10px; border-radius: 16px; cursor: pointer;
    border: 1px solid var(--w-border); background: var(--w-surface); color: var(--w-muted);
    font-size: 12.5px; font-weight: 700; line-height: 1;
}
.mem-btn i { font-size: 13px; }
.mem-admin.is-on { background: #e7f6ec; border-color: #9bd8b0; color: #15803d; }
.mem-remove { width: 32px; padding: 0; justify-content: center; color: var(--w-danger); border-color: #f3c9c4; }
.mem-remove:hover { background: #fdecea; }
/* armed, and not yet saved */
.mem-btn.is-armed { box-shadow: 0 0 0 2px var(--w-primary-soft); border-color: var(--w-primary); }
.mem-remove.is-armed { background: var(--w-danger); border-color: var(--w-danger); color: #fff; box-shadow: none; }
.member-row.is-going .member-row-text { opacity: .45; text-decoration: line-through; }
@media (max-width: 400px) { .mem-admin span { display: none; } .mem-admin { width: 32px; padding: 0; justify-content: center; } }
.chan-add-page { display: flex; gap: 8px; align-items: center; margin-bottom: 6px; }
.chan-add-page .form-control { flex: 1; min-width: 0; margin: 0; }
.chan-add-page .btn-wms { flex: none; white-space: nowrap; }
/* a colleague's reply in a shared inbox: our side of the screen, but named */
.msg-row.me .msg-sender-ours { text-align: right; color: var(--w-muted); }

/* ---- a customer, and which of the company's pages they wrote to ------------------------------
   Two faces rather than a name with a bracket after it: at a glance the row says who is asking and
   where they are asking, and the page name drops to its own line where it reads as context rather
   than as part of the person's name. */
.chat-faces { position: relative; flex: none; display: inline-flex; }
.chat-page-face {
    position: absolute; right: -7px; bottom: -3px;
    width: 22px; height: 22px; border-radius: 50%; object-fit: cover;
    background: var(--w-surface); box-shadow: 0 0 0 2px var(--w-surface);
}
.chat-faces + .chat-row-body { margin-left: 8px; }
.chat-row-page {
    display: block; font-size: 11.5px; line-height: 1.3; color: var(--w-muted);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* LINE's own emoji and stickers. The emoji sits in a sentence and is sized against the text around
   it, so it grows and shrinks with the message; the sticker is the whole message and is given room
   to be looked at, capped so a tall one cannot push the rest of the room off the screen. */
.chat-line-emoji { height: 1.5em; width: auto; vertical-align: -.3em; display: inline-block; }
.chat-line-sticker { max-width: 160px; max-height: 160px; width: auto; height: auto; display: block; margin: 2px 0; }

/* The panel of LINE stickers and emoji. It sits above the composer rather than over the room, so a
   person can still see what they are answering while they pick — and it is capped in height so a
   pack of forty does not swallow the screen. */
.line-art { border-top: 1px solid var(--w-border); background: var(--w-surface); }
.line-art-tabs { display: flex; align-items: center; gap: 4px; padding: 6px 8px; border-bottom: 1px solid var(--w-border); }
.line-art-tab {
    border: 0; background: none; color: var(--w-muted); font: inherit; font-size: 13px; font-weight: 600;
    padding: 5px 12px; border-radius: 999px; cursor: pointer;
}
.line-art-tab.is-on { background: var(--w-primary-soft); color: var(--w-primary-dark); }
.line-art-x { margin-left: auto; border: 0; background: none; color: var(--w-muted); padding: 5px 8px; cursor: pointer; }
.line-art-sets {
    display: flex; gap: 4px; padding: 6px 8px; overflow-x: auto; scrollbar-width: thin;
    border-bottom: 1px solid var(--w-border);
}
.line-art-set {
    flex: none; border: 1px solid var(--w-border); background: none; color: var(--w-muted);
    font: inherit; font-size: 11.5px; padding: 4px 10px; border-radius: 999px; white-space: nowrap; cursor: pointer;
}
.line-art-set.is-on { border-color: var(--w-primary-soft-border); background: var(--w-primary-soft); color: var(--w-primary-dark); }
.line-art-grid {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(64px, 1fr)); gap: 4px;
    padding: 8px; max-height: 210px; overflow-y: auto;
}
.line-art-item { border: 0; background: none; padding: 4px; border-radius: 10px; cursor: pointer; line-height: 0; }
.line-art-item:hover { background: var(--w-primary-soft); }
.line-art-item img { width: 100%; height: auto; aspect-ratio: 1; object-fit: contain; }
.composer-attach.is-on { color: var(--w-primary); }

/* the platform's mark in front of the page name — a touch larger than the text it sits with, so it
   reads as a mark rather than as a letter, and nudged down onto the same baseline */
.chat-row-pmark { font-size: 13px; vertical-align: -2px; margin-right: 4px; }
.chat-row-pmark.pmark-line { border-radius: 4px; }
.login-remember { margin: 4px 0 14px; }

/* the foot of the chat list while the next page is on its way. It is asked for fifteen rows early,
   so this is usually seen for a blink or not at all — which is the point. */
.chat-more { display: flex; justify-content: center; padding: 14px 0 6px; }
.chat-more[hidden] { display: none; }
.chat-more .spinner-border { width: 20px; height: 20px; border-width: 2px; color: var(--w-muted); }

/* Lazada's tile carries its own two colours, the same way Facebook's and LINE's do */
.pmark-laz { width: 1em; height: 1em; font-size: inherit; }
.chan-badge.pmark-laz { border-radius: 5px; }
.chat-row-pmark.pmark-laz { border-radius: 4px; }

/* Saved replies — one person's own phrases, dropped into the box rather than sent. Sits above the
   composer like the LINE panel does, so what is being answered stays in view while one is picked. */
.quick-panel { border-top: 1px solid var(--w-border); background: var(--w-surface); padding: 8px; }
.quick-panel[hidden] { display: none; }
.quick-head { display: flex; align-items: center; gap: 6px; font-size: 13px; padding-bottom: 6px; }
.quick-head b { color: var(--w-text); }
.quick-x { margin-left: auto; border: 0; background: none; color: var(--w-muted); padding: 4px 6px; cursor: pointer; }
.quick-list { max-height: 210px; overflow-y: auto; display: flex; flex-direction: column; gap: 5px; }
.quick-list[hidden] { display: none; }
.quick-item { display: flex; align-items: stretch; gap: 4px; }
.quick-use {
    flex: 1 1 auto; min-width: 0; text-align: left; cursor: pointer;
    border: 1px solid var(--w-border); border-radius: var(--w-radius-sm);
    background: var(--w-bg); color: var(--w-text); font: inherit; font-size: 13px;
    padding: 7px 10px; line-height: 1.4;
    /* three lines of a long one, so forty of them still fit a panel */
    display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.quick-use:hover { border-color: var(--w-primary-soft-border); background: var(--w-primary-soft); }
.quick-del {
    flex: none; border: 1px solid var(--w-border); border-radius: var(--w-radius-sm);
    background: none; color: var(--w-danger); padding: 0 9px; cursor: pointer;
}
.quick-add textarea { resize: vertical; font-size: 14px; line-height: 1.5; }

/* What the plus folds away. Labelled rows rather than a row of icons: this is the one place in the
   composer with room to say what each thing does, and an icon alone is a guess. */
.composer-tray {
    border-top: 1px solid var(--w-border); background: var(--w-surface);
    padding: 6px; display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: 6px;
}
.composer-tray[hidden] { display: none; }
.tray-item {
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px;
    border: 1px solid var(--w-border); border-radius: var(--w-radius-sm);
    background: var(--w-bg); color: var(--w-text);
    font: inherit; font-size: 12px; padding: 12px 6px; cursor: pointer; text-align: center;
}
.tray-item i { font-size: 20px; color: var(--w-primary); }
.tray-item span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
.tray-item:hover { border-color: var(--w-primary-soft-border); background: var(--w-primary-soft); }

/* A saved reply is a heading with its wording under it — the heading is what the eye lands on. */
.quick-use { display: block; }
.quick-use b { display: block; font-size: 13px; line-height: 1.35; color: var(--w-text); }
.quick-use small {
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
    font-size: 12px; line-height: 1.4; color: var(--w-muted); margin-top: 1px;
}
.quick-add .field-label { margin-top: 8px; }
.quick-add .field-label:first-child { margin-top: 0; }
.quick-edit {
    flex: none; border: 1px solid var(--w-border); border-radius: var(--w-radius-sm);
    background: none; color: var(--w-muted); padding: 0 9px; cursor: pointer;
}
.quick-edit:hover { color: var(--w-primary); border-color: var(--w-primary-soft-border); }

/* Putting the list in order. A mode rather than two more buttons on every row: arranging happens
   now and then, choosing a reply happens all day, and the wording is what the row is for. */
.quick-sort { border: 0; background: none; color: var(--w-muted); padding: 4px 6px; cursor: pointer; }
.quick-sort.is-on { color: var(--w-primary); }
.quick-move {
    flex: none; border: 1px solid var(--w-border); border-radius: var(--w-radius-sm);
    background: none; color: var(--w-primary); padding: 0 9px; cursor: pointer;
}
.quick-move:disabled { color: var(--w-border-strong); cursor: default; }
.quick-use:disabled { cursor: default; opacity: .85; }
/* dragging one into place, where there is a mouse to do it with */
.quick-item[draggable="true"] { cursor: grab; }
.quick-item.is-dragging { opacity: .4; cursor: grabbing; }
.quick-list.is-sorting { padding: 2px; }
