/* icookfont is not imported here. Rails 8's stylesheet_link_tag :app includes
   every stylesheet under app/assets/stylesheets, so the vendored files are
   already linked -- and a CSS @import would load them a second time, since
   Propshaft has no bundler and leaves @import to the browser. */
/* Internal back office and the customer-facing help centre. Plain CSS on
   Propshaft: the surface is small and a build step here would earn nothing. */
:root {
  --ink: #2b2b2b;
  --muted: #8a8a8a;
  --line: #e8e6e4;
  --surface: #ffffff;
  --canvas: #faf8f7;
  --accent: #f0563c;      /* iCook red */
  --accent-soft: #fdeeea;
  --accent-line: #f8d5cc;
  --note: #fffbeb;
  --note-line: #f2d98c;
  --ok: #2f8f4e;
  --warn: #b42318;
  /* The logo's own ink. The help centre lockup is not an accent, it is
     the name of the place, so it does not compete with everything the
     red is actually pointing at. */
  --brand-ink: #564e4a;

  /* One hue per channel, so a source is recognised before it is read. The
     outside ones are the platform's own colour; web and app are ours. Each is
     a shade or two down from the brand swatch: these colour 11px text as well
     as the mark, and Messenger blue or LINE green straight off the brand sheet
     is barely legible at that size on white. */
  --ch-web: #0f766e;
  --ch-app: #d8452c;
  --ch-email: #6b7280;
  --ch-facebook: #0b74d4;
  --ch-instagram: #c1265c;
  --ch-line: #06923f;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font: 15px/1.6 system-ui, -apple-system, "Noto Sans TC", "PingFang TC", sans-serif;
  color: var(--ink);
  background: var(--canvas);
}
button, select, textarea, input { font: inherit; color: inherit; }
a { color: var(--accent); }

/* The support centre's logo, recoloured through currentColor. Square (64x64),
   and it carries its own padding, so it is sized larger inside the avatar
   than the old wide mark was. */
.brand-avatar,
.hc-top-mark,
.wb-rail-mark { display: inline-flex; align-items: center; justify-content: center; }
.brand-avatar { background: var(--accent); border-radius: 50%; color: #fff; flex: none; }
.brand-avatar-mark svg,
.brand-avatar svg { width: 74%; height: auto; display: block; }
.brand-avatar-mark { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; }
.hc-top-mark svg { width: 40px; height: 40px; display: block; }
.hc-top-mark { color: var(--brand-ink); }
.wb-rail-mark { color: var(--brand-ink); }
.wb-rail-mark svg { width: 38px; height: 38px; display: block; }

/* ── Sign-in and other single-purpose pages ───────────────────────────── */
.auth { max-width: 30rem; margin: 5rem auto; padding: 2.5rem; background: var(--surface); border: 1px solid var(--line); border-radius: 16px; }
.auth h1 { margin: 0 0 1.25rem; font-size: 1.3rem; }
.auth-alert { padding: .75rem 1rem; background: var(--accent-soft); color: var(--warn); border-radius: 8px; }
.auth-hint { color: var(--muted); font-size: .9em; }
.auth form { margin: 0 0 1rem; }
.auth button { padding: .6rem 1.4rem; border: 1px solid var(--line); border-radius: 8px; background: var(--surface); cursor: pointer; }


/* ══ Customer help centre ═════════════════════════════════════════════ */
/* The page fills the window and does not scroll; the two panes inside it do.
   With min-height the shell grew past the viewport, so a long conversation
   list scrolled the document as well as itself -- two scrollbars, doing
   different things, and the composer pushed off the bottom of the screen.
   dvh so a phone's collapsing address bar does not leave a gap. */
.cc { height: 100vh; height: 100dvh; display: flex; flex-direction: column; overflow: hidden; }
.cc > .hc-top { flex: none; }

/* min-height: 0 on all three, or a flex item refuses to shrink below its
   content and the overflow: auto inside it never has anything to do. */
.cc-body { flex: 1; min-height: 0; display: grid; grid-template-columns: minmax(16rem, 22rem) 1fr; gap: 0; max-width: 74rem; width: 100%; margin: 1.5rem auto; padding: 0 1.5rem; }
.cc-list { min-height: 0; background: var(--surface); border: 1px solid var(--line); border-right: 0; border-radius: 14px 0 0 14px; display: flex; flex-direction: column; }
.cc-main { min-height: 0; background: var(--surface); border: 1px solid var(--line); border-radius: 0 14px 14px 0; display: flex; flex-direction: column; }

.cc-list-head { display: flex; align-items: center; gap: .5rem; padding: 1.1rem 1.25rem .75rem; }
.cc-list-head h2 { margin: 0; font-size: 1.05rem; }
.cc-count { padding: .05rem .5rem; border-radius: 999px; background: var(--canvas); color: var(--muted); font-size: .85rem; }
.cc-new { margin: 0 1.25rem 1rem; padding: .7rem; border: 0; border-radius: 10px; background: var(--accent); color: #fff; font-weight: 600; cursor: pointer; }

.cc-empty { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: .3rem; padding: 2rem; text-align: center; }
.cc-empty-icon { font-size: 2.6rem; opacity: .3; }
.cc-empty-title { margin: .5rem 0 0; font-weight: 600; font-size: 1.1rem; }
.cc-empty-hint { margin: 0; color: var(--muted); font-size: .9rem; }

.cc-items { list-style: none; margin: 0; padding: 0; flex: 1; overflow-y: auto; border-top: 1px solid var(--line); }
.cc-item { display: flex; flex-direction: column; gap: .3rem; width: 100%; padding: .85rem 1.25rem; border: 0; border-bottom: 1px solid var(--line); background: none; text-align: start; cursor: pointer; }
.cc-item:hover { background: var(--canvas); }
.cc-item.is-active { background: var(--accent-soft); box-shadow: inset 3px 0 0 var(--accent); }
.cc-item-top { display: flex; align-items: center; justify-content: space-between; gap: .5rem; }
.cc-item-title { font-size: .95rem; }
.cc-item-foot { display: flex; justify-content: space-between; gap: .5rem; color: var(--muted); font-size: .82rem; }
.cc-item-preview { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cc-list-foot { margin: 0; padding: .9rem 1.25rem; border-top: 1px solid var(--line); color: var(--muted); font-size: .82rem; text-align: center; }

.cc-badge { padding: .1rem .55rem; border-radius: 999px; font-size: .78rem; white-space: nowrap; }
.cc-badge-waiting { background: var(--accent-soft); color: #c2410c; }
.cc-badge-answered { background: #e8f6ec; color: var(--ok); }
.cc-badge-closed { background: var(--canvas); color: var(--muted); }

.cc-main-head { display: flex; align-items: center; gap: 1rem; padding: 1.25rem 1.5rem; border-bottom: 1px solid var(--line); }
.cc-main-head h2 { margin: 0; font-size: 1.15rem; }
.cc-main-head p { margin: .2rem 0 0; color: var(--muted); font-size: .9rem; }
.cc-thread-sub { display: flex; align-items: center; gap: .5rem; }

.cc-form { padding: 1.5rem; display: flex; flex-direction: column; gap: 1.25rem; }
.cc-field { display: flex; flex-direction: column; gap: .4rem; }
.cc-label { font-weight: 600; }
.cc-label em { margin-left: .3rem; color: var(--accent); font-style: normal; font-size: .85rem; }
.cc-label em.cc-optional { color: var(--muted); }
.cc-field textarea, .cc-field input { padding: .75rem; border: 1px solid var(--line); border-radius: 10px; background: var(--surface); }
.cc-field textarea { resize: vertical; }
.cc-help { color: var(--muted); font-size: .85rem; }
.cc-help-lock { display: flex; gap: .3rem; align-items: center; }
.cc-submit { align-self: flex-start; padding: .7rem 1.6rem; border: 0; border-radius: 10px; background: var(--accent); color: #fff; font-weight: 600; cursor: pointer; }
.cc-submit:disabled { background: var(--line); color: var(--muted); cursor: not-allowed; }
.cc-error { margin: 0; color: var(--warn); }

.cc-thread { flex: 1; overflow-y: auto; padding: 1.25rem 1.5rem; }
.cc-day { display: flex; align-items: center; gap: .75rem; margin: .75rem 0 1rem; color: var(--muted); font-size: .82rem; }
.cc-day::before, .cc-day::after { content: ''; flex: 1; height: 1px; background: var(--line); }
.cc-msg { display: flex; gap: .6rem; margin-bottom: 1rem; }
.cc-msg-you { justify-content: flex-end; }
.cc-msg-col { display: flex; flex-direction: column; max-width: 78%; }
.cc-msg-you .cc-msg-col { align-items: flex-end; }
/* overflow-wrap: anywhere on every body that renders what somebody typed.
   A pasted URL, order id or token is one unbroken word, and without this it
   ran straight out of its bubble -- in the internal note it painted over the
   byline beside it. */
.cc-bubble { padding: .7rem 1rem; border-radius: 14px; white-space: pre-wrap; overflow-wrap: anywhere; }
.cc-msg-support .cc-bubble { background: var(--surface); border: 1px solid var(--line); border-bottom-left-radius: 4px; }
.cc-msg-you .cc-bubble { background: var(--accent-soft); border: 1px solid var(--accent-line); border-bottom-right-radius: 4px; }
.cc-msg-col time { margin-top: .25rem; color: var(--muted); font-size: .78rem; }

.cc-closed { margin: 0 1.5rem; padding: .7rem 1rem; background: var(--canvas); border-radius: 10px; color: var(--muted); font-size: .9rem; }
.cc-linklike { border: 0; background: none; color: var(--accent); cursor: pointer; padding: 0; }

/* One row of three controls -- attach, the box, send -- on one height. They
   were 33.4 / 48.4 / 46.4 px sharing a bottom edge, so nothing lined up with
   anything: the attach button sat visibly low and small beside the box.
   The line-height matters here: at 24px the box computed taller than
   --cc-control and won, which is what put the send button 2px below it. */
.cc-composer { --cc-control: 2.9rem; display: flex; gap: .75rem; align-items: flex-end; padding: 1rem 1.5rem 1.25rem; border-top: 1px solid var(--line); }
.cc-composer textarea { flex: 1; padding: .7rem 1rem; border: 1px solid var(--line); border-radius: 999px; resize: none; line-height: 1.45; min-height: var(--cc-control); }
.cc-send { width: var(--cc-control); height: var(--cc-control); flex: none; border: 0; border-radius: 50%; background: var(--accent); color: #fff; cursor: pointer; }
.cc-send:disabled { background: var(--line); color: var(--muted); cursor: not-allowed; }

@media (max-width: 48rem) {
  /* Here the page scrolls, because the panes stack instead of sitting side by
     side and neither would have room in a locked viewport. The 34rem floor
     comes back with it: it is what keeps the thread readable when the page,
     not the pane, is what scrolls. */
  .cc { height: auto; min-height: 100dvh; overflow: visible; }
  .cc-body { grid-template-columns: 1fr; padding: 0; margin: 0; }
  .cc-list { border-radius: 0; border-right: 1px solid var(--line); }
  .cc-main { border-radius: 0; min-height: 34rem; }
}

/* ══ Help centre (public) ═════════════════════════════════════════════ */
.hc-page { background: var(--surface); }
.hc-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }

/* One measure for every band, so the header, the hero and the content line up
   down the page rather than each finding its own edge. */
.hc-top-inner, .hc-hero-inner, .hc-body-wrap, .hc-foot-inner, .hc-searchbar > .hc-search,
.hc.hc-with-side { max-width: 68rem; margin: 0 auto; padding: 0 1.25rem; }

.hc-top { border-bottom: 1px solid var(--line); background: var(--surface); }
/* Three parts rather than one row that pushes: brand, tabs, actions. With a
   flex row the tabs sit wherever the things after them leave room, so the chat
   -- which also shows a sign-in state -- put them 136px left of where the help
   centre did. Their own column means nothing beside them can move them. */
.hc-top-inner { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 1rem; height: 3.5rem; }
.hc-top-lead { display: flex; align-items: center; gap: 1rem; min-width: 0; }
.hc-top-actions { display: flex; align-items: center; justify-content: flex-end; gap: 1rem; min-width: 0; }
.hc-top-brand { display: inline-flex; align-items: center; gap: .5rem; color: var(--brand-ink); text-decoration: none; font-weight: 600; }
/* The name of the place does not wrap. On a narrow phone it was breaking into
   愛料理 / 客服中 / 心; the row wraps instead, which is what it is for. */
.hc-top-name { white-space: nowrap; }

/* The two places somebody can be. Underlined rather than filled, so the header
   stays quiet next to the hero below it. */
.hc-tabs { display: flex; gap: 1.25rem; }
.hc-tab { padding: .2rem 0; border-bottom: 2px solid transparent; color: var(--muted); text-decoration: none; font-size: .92rem; }
.hc-tab:hover { color: var(--ink); }
.hc-tab.is-on { border-bottom-color: var(--accent); color: var(--accent); font-weight: 600; }
.hc-top-back { color: var(--muted); text-decoration: none; font-size: .88rem; }
/* Only the chat shows these -- the help centre needs no account to read -- but
   they belong to this header rather than to a second one. */
.hc-top-status { color: var(--muted); font-size: .88rem; }
.hc-top-signin { padding: .3rem 1rem; border: 1px solid var(--accent); border-radius: 8px; color: var(--accent); text-decoration: none; font-size: .88rem; }

.hc-hero { background: var(--accent-soft); border-bottom: 1px solid var(--accent-line); }
.hc-hero-inner { padding-block: 2.75rem 2.25rem; text-align: center; }
.hc-hero-label { margin: 0 0 .4rem; color: var(--muted); font-size: .85rem; }
.hc-hero-title { margin: 0 0 .4rem; font-size: 1.85rem; }
.hc-hero-note { margin: 0 0 1.5rem; color: var(--muted); }

.hc-search { display: flex; gap: .6rem; max-width: 36rem; margin: 0 auto; }
.hc-search-box { flex: 1; min-width: 0; display: flex; align-items: center; gap: .5rem; padding: 0 1rem; border: 1px solid var(--line); border-radius: 10px; background: var(--surface); color: var(--muted); }
.hc-search-box input { flex: 1; min-width: 0; padding: .8rem 0; border: 0; background: none; outline: none; color: var(--ink); }
.hc-search button { padding: .8rem 1.6rem; border: 0; border-radius: 10px; background: var(--accent); color: #fff; font-weight: 600; cursor: pointer; }

/* On an answer page the search box leads to the next question rather than
   being the point of the page, so it gets a strip instead of the hero. */
.hc-searchbar { padding-block: 1rem; background: var(--accent-soft); border-bottom: 1px solid var(--accent-line); }
.hc-search-slim { max-width: 30rem; margin-inline-start: auto; margin-inline-end: 0; }
.hc-search-slim button { padding: .55rem 1.2rem; }
.hc-search-slim .hc-search-box input { padding: .55rem 0; }

.hc-body-wrap { padding-block: 2.5rem 3rem; }
.hc-h2 { margin: 0 0 1rem; font-size: 1.15rem; }
.hc-h2 a { text-decoration: none; }
.hc-body-wrap > section { margin-bottom: 2.75rem; }

/* Cards, because a category is a place to go rather than a heading over a
   list -- six of them read faster than six lists of four. */
/* Three across, because there are six of them: auto-fit gave four and then a
   row of two, which reads as a leftover rather than a grid. */
.hc-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr)); gap: .75rem; }
@media (min-width: 62rem) { .hc-cards { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.hc-card { display: flex; align-items: flex-start; gap: .85rem; padding: 1.1rem 1.15rem; border: 1px solid var(--line); border-radius: 12px; background: var(--surface); color: var(--ink); text-decoration: none; }
.hc-card:hover { border-color: var(--accent-line); background: var(--accent-soft); }
.hc-card-mark { flex: none; width: 1.9rem; font-size: 1.5rem; line-height: 1.5; text-align: center; }
/* One hue each, so the six are told apart before they are read. */
.hc-card-mark-vip { color: #d99b0a; }
.hc-card-mark-account { color: #2f6fd0; }
.hc-card-mark-recipe { color: #1f8a5c; }
.hc-card-mark-device { color: #7a4fd0; }
.hc-card-mark-market { color: var(--accent); }
.hc-card-mark-announcement { color: #c2410c; }
.hc-card-mark-help { color: var(--muted); }
.hc-card-words { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: .15rem; }
.hc-card-name { font-weight: 600; }
/* Two lines rather than one with an ellipsis: these descriptions are real
   sentences somebody wrote, and "針對 VIP 訂閱或 VI…" tells a reader nothing.
   Clamped so a long one cannot make its card taller than its neighbours. */
.hc-card-note { color: var(--muted); font-size: .85rem; line-height: 1.5; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }

.hc-chevron { flex: none; align-self: center; color: var(--line); font-size: .9rem; }
.hc-card:hover .hc-chevron, .hc-row:hover .hc-chevron { color: var(--accent); }

.hc-rows { list-style: none; margin: 0; padding: 0; }
.hc-row { display: flex; align-items: center; gap: .85rem; padding: .95rem .25rem; border-bottom: 1px solid var(--line); color: var(--ink); text-decoration: none; }
.hc-row:hover { background: var(--canvas); }
.hc-row-words { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: .2rem; }
.hc-row-title { line-height: 1.5; }
.hc-row-note { color: var(--muted); font-size: .85rem; }
/* Which area it came from, for a list that mixes them. */
.hc-row-aside { flex: none; color: var(--muted); font-size: .82rem; }

.hc-empty { padding: 1.5rem; border: 1px dashed var(--line); border-radius: 12px; background: var(--canvas); color: var(--muted); }

/* The way out of a page that did not answer the question. One band, because it
   is one decision. */
.hc-cta { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem; padding: 1.25rem 1.5rem; border: 1px solid var(--accent-line); border-radius: 12px; background: var(--accent-soft); }
.hc-cta-mark { flex: none; font-size: 1.5rem; color: var(--accent); }
.hc-cta-words { flex: 1; min-width: 12rem; }
.hc-cta-words h2 { margin: 0 0 .2rem; font-size: 1.05rem; }
.hc-cta-words p { margin: 0; color: var(--muted); font-size: .9rem; }
.hc-cta-actions { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem; }
.hc-cta-primary { padding: .6rem 1.5rem; border-radius: 8px; background: var(--accent); color: #fff; text-decoration: none; font-weight: 600; }
.hc-cta-secondary { padding: .6rem 1.3rem; border: 1px solid var(--line); border-radius: 8px; background: var(--surface); color: var(--ink); text-decoration: none; }
.hc-cta-mail { color: var(--muted); font-size: .85rem; }

/* The other answers in the same area, which is what somebody who did not find
   theirs needs next. */
.hc.hc-with-side { display: grid; grid-template-columns: 14rem minmax(0, 1fr); gap: 2.5rem; padding-block: 2.5rem 3rem; align-items: start; }
.hc-side { position: sticky; top: 1.5rem; }
.hc-side-title { margin: 0 0 .75rem; font-size: 1.05rem; }
.hc-side-nav { display: flex; flex-direction: column; gap: .1rem; }
.hc-side-link { display: flex; align-items: center; justify-content: space-between; gap: .5rem; padding: .5rem .75rem; border-radius: 8px; color: var(--ink); text-decoration: none; font-size: .92rem; }
.hc-side-link:hover { background: var(--canvas); }
.hc-side-link.is-on { background: var(--accent-soft); color: var(--accent); font-weight: 600; }
.hc-side-all { display: inline-block; margin-top: 1rem; padding-top: 1rem; border-top: 1px solid var(--line); color: var(--muted); text-decoration: none; font-size: .88rem; }

.hc-main { min-width: 0; }
.hc-crumbs { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; margin-bottom: 1rem; color: var(--muted); font-size: .85rem; }
.hc-kicker { margin: 0 0 .35rem; color: var(--accent); font-size: .85rem; font-weight: 600; }
.hc-title { margin: 0 0 .5rem; font-size: 1.6rem; line-height: 1.4; }
.hc-lede { margin: 0 0 2rem; color: var(--muted); }
.hc-updated { margin: 0 0 2rem; color: var(--muted); font-size: .85rem; }
.hc-group { margin-bottom: 2.5rem; }
.hc-more { margin-top: 2.5rem; }
.hc-main > .hc-cta { margin-top: 2.5rem; }

/* The article body. These rules style content we did not write, so they cover
   the tags the import actually produced and nothing else. */
.hc-body { line-height: 1.9; }
.hc-body h2 { margin: 2rem 0 .75rem; font-size: 1.2rem; }
.hc-body h3 { margin: 1.5rem 0 .5rem; font-size: 1.05rem; }
.hc-body h4 { margin: 1.25rem 0 .5rem; font-size: .98rem; }
.hc-body p { margin: 0 0 1rem; }
.hc-body ul, .hc-body ol { margin: 0 0 1rem; padding-inline-start: 1.4rem; }
.hc-body li { margin-bottom: .35rem; }
.hc-body img { max-width: 100%; height: auto; border-radius: 8px; }
.hc-body blockquote { margin: 0 0 1rem; padding: .75rem 1rem; border-inline-start: 3px solid var(--accent-line); background: var(--canvas); }
/* Keeps an embed inside the column on a phone, which is where most of these
   are read. */
.hc-video { margin: 0 0 1rem; aspect-ratio: 16 / 9; }
.hc-video iframe { width: 100%; height: 100%; border: 0; border-radius: 8px; }

.hc-foot { border-top: 1px solid var(--line); background: var(--canvas); }
.hc-foot-inner { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1rem; padding-block: 1.5rem; color: var(--muted); font-size: .85rem; }
.hc-foot-brand { color: var(--accent); font-weight: 600; }
.hc-foot-links { display: flex; flex-wrap: wrap; gap: 1rem; margin-inline-start: auto; }
.hc-foot-links a { color: var(--muted); text-decoration: none; }
.hc-foot-links a:hover { color: var(--accent); }

@media (max-width: 48rem) {
  /* Two rows on a phone: identity above, the two places below. */
  .hc-top-inner { display: flex; flex-wrap: wrap; height: auto; padding-block: .6rem; }
  /* min-content, overriding the min-width: 0 above: with the name set not to
     wrap, letting the lead shrink below its content made it run underneath
     the sign-in state instead of pushing it to the next row. */
  .hc-top-lead { flex: 1 1 auto; min-width: min-content; }
  /* Beside the name while it fits, on its own line when it does not. */
  .hc-top-actions { margin-inline-start: auto; }
  .hc-tabs { order: 3; width: 100%; }
  /* Not hidden any more. It used to be safe to drop because the logo also
     went to icook.tw; now the logo goes to the help centre front page and
     this is the only way back to the main site. */
  .hc-top-back { white-space: nowrap; }
  .hc-hero-title { font-size: 1.5rem; }
  .hc-search { flex-direction: column; }
  /* The sidebar becomes what it is on a phone: the list that follows the
     answer rather than a column beside it. */
  .hc.hc-with-side { grid-template-columns: minmax(0, 1fr); gap: 1.5rem; }
  .hc-side { position: static; order: 2; padding-top: 1.5rem; border-top: 1px solid var(--line); }
  .hc-main { order: 1; }
  .hc-search-slim { margin-inline: auto; }
  .hc-cta-actions { width: 100%; }
  .hc-cta-primary, .hc-cta-secondary { flex: 1; text-align: center; }
}

/* ══ Agent workbench ══════════════════════════════════════════════════ */
/* One screen, and the row is pinned to it: a grid with a fixed height still
   sizes an implicit auto row to its content, so a long list grew the row past
   100vh and the whole page scrolled instead of the column. */
.wb { display: grid; grid-template-columns: 4.5rem 1fr; grid-template-rows: minmax(0, 1fr); height: 100vh; overflow: hidden; }
/* The rail is server-rendered and #inbox-root is React's mount point, so it
   has to disappear as a box or it would sit between the grid and .wb-body. */
#inbox-root { display: contents; }
.wb-body { display: flex; flex-direction: column; min-width: 0; min-height: 0; }
/* Toolbar spans the columns: search and the quick views apply to the list, but
   they are the page's controls, not the list's. */
/* The sides are what the agent dragged, but never more than a share of the
   window: a fixed side column crushing the thread as the window narrows is the
   bug this replaces. The middle takes what is left, and 0 as its minimum is
   what stops it forcing an overflow instead. */
.wb-columns { flex: 1; display: grid; min-height: 0;
  grid-template-columns:
    max(11rem, min(var(--list-w, 20rem), 30vw))
    auto
    minmax(0, 1fr)
    auto
    min(var(--detail-w, 18rem), 32vw);
}
.wb-columns.is-resizing { cursor: col-resize; }

/* Below this the sides yield harder than the drag asked for: the thread is
   what an agent is reading, and honouring a 440px list on a 900px window is
   honouring the wrong thing. The stored width comes back untouched as soon as
   there is room for it again. */
@media (max-width: 1200px) {
  .wb-columns {
    grid-template-columns:
      max(9rem, min(var(--list-w, 20rem), 24vw))
      auto
      minmax(0, 1fr)
      auto
      min(var(--detail-w, 18rem), 22vw);
  }
}

/* Wider than it looks: the visible line is 1px but the grab area is not, or
   catching it becomes a game. */
.wb-grip { width: 5px; margin: 0 -2px; cursor: col-resize; background: none; border: 0; z-index: 5; }
.wb-grip:hover, .wb-columns.is-resizing .wb-grip { background: var(--accent-line); }
body.is-resizing { user-select: none; }

.wb-toolbar { border-bottom: 1px solid var(--line); background: var(--surface); }
.wb-toolbar-top { display: flex; align-items: center; gap: .75rem; padding: .55rem .85rem .5rem; }
.wb-toolbar-top h1 { margin: 0; font-size: 1rem; white-space: nowrap; }
.wb-search { flex: 1; max-width: 34rem; display: flex; align-items: center; gap: .5rem; padding: .4rem .8rem; border: 1px solid var(--line); border-radius: 10px; color: var(--muted); }
.wb-search input { flex: 1; border: 0; background: none; outline: none; }
.wb-search input:disabled { cursor: not-allowed; }
.wb-filter-button { padding: .4rem 1rem; border: 1px solid var(--line); border-radius: 10px; background: var(--surface); color: var(--muted); cursor: not-allowed; }

.wb-rail { display: flex; flex-direction: column; align-items: center; gap: .8rem; padding: .7rem .35rem; min-height: 0; overflow-y: auto; background: var(--surface); border-right: 1px solid var(--line); }
/* The logo alone. It says 愛料理客服中心 on hover and goes to the inbox; the
   word underneath was a caption for a picture that is already the name. */
.wb-rail-brand { display: flex; align-items: center; justify-content: center; text-decoration: none; }
/* text-decoration: none, which these never had: the base `a` rule underlines
   every link, and on a column of icon-and-label buttons that read as an
   underline under each label. */
.wb-rail-item { display: flex; flex-direction: column; align-items: center; gap: .15rem; width: 2.9rem; padding: .35rem 0; border-radius: 10px; color: var(--muted); text-decoration: none; }
.wb-rail-item i { font-size: 1.1rem; }
.wb-rail-item em { font-style: normal; font-size: .68rem; }
.wb-rail-item.is-active { background: var(--accent-soft); color: var(--accent); }
.wb-rail-me { margin-top: auto; display: flex; flex-direction: column; align-items: center; gap: .4rem; }
.wb-rail-initials { display: flex; align-items: center; justify-content: center; width: 2.1rem; height: 2.1rem; border-radius: 50%; background: var(--canvas); border: 1px solid var(--line); font-size: .78rem; font-weight: 600; color: var(--muted); }
.wb-rail-me button { padding: .25rem .45rem; border: 1px solid var(--line); border-radius: 6px; background: none; color: var(--muted); font-size: .7rem; cursor: pointer; }

.wb-list { background: var(--surface); border-right: 1px solid var(--line); display: flex; flex-direction: column; overflow: hidden; container: wb-list / inline-size; }
.wb-list-head { display: flex; align-items: baseline; gap: .5rem; padding: .3rem .85rem .3rem; }
/* Named for the control that follows it, not visible: the select's own value
   already reads as an order, and a label repeating it would cost a line of a
   column that is short of them. */
.wb-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.wb-list-sort { margin-left: auto; display: flex; align-items: center; gap: .15rem; }
.wb-list-sort select { border: 0; background: none; color: var(--muted); font-size: .78rem; cursor: pointer; }
.wb-list-direction { display: inline-flex; align-items: center; gap: .2rem; padding: .1rem .35rem; border: 1px solid var(--line); border-radius: 6px; background: var(--surface); color: var(--muted); font-size: .74rem; cursor: pointer; }
.wb-list-direction:hover { border-color: var(--accent-line); color: var(--accent); }
/* Two selects rather than a row of pills: views are mutually exclusive and
   there are eight of them, labels are a separate axis that grows without
   bound, and a flat row could express neither. */
.wb-list-count { margin: 0; color: var(--muted); font-size: .78rem; }
.wb-list-empty { padding: 1rem .85rem; color: var(--muted); font-size: .88rem; }

.wb-items { list-style: none; margin: 0; padding: 0; flex: 1; overflow-y: auto; border-top: 1px solid var(--line); }
/* Warm, because it is a state the agent chose and can leave, not a warning. */
.wb-list-paused { display: flex; align-items: center; gap: .5rem; margin: 0; padding: .35rem .85rem; background: var(--note); border-top: 1px solid var(--note-line); color: #6b4e00; font-size: .76rem; font-weight: 500; }
.wb-list-paused button { margin-left: auto; padding: .1rem .45rem; border: 1px solid var(--note-line); border-radius: 6px; background: var(--surface); color: inherit; font-size: .74rem; cursor: pointer; }
/* The end of the list, which is also what triggers the next page. It keeps a
   height whether or not it says anything, so the observer has something to
   see and the list does not jump as the word appears. */
.wb-list-more { padding: .6rem .85rem 1rem; text-align: center; color: var(--muted); font-size: .78rem; }
.wb-item { display: flex; gap: .6rem; width: 100%; padding: .65rem .95rem; border: 0; border-bottom: 1px solid var(--line); background: var(--surface); text-align: start; cursor: pointer; }
/* Warm ground means they are waiting on us -- it replaces the words the count
   already said. Answered rows stay white: greying them put a grey against a
   warm grey, which is harder to tell apart than warm against white. */
.wb-item:hover { background: var(--canvas); }
/* A resolved ticket is still in the list because a filter asked for it, not
   because it wants attention -- so the whole row fades rather than being
   restyled piece by piece. Hover and selection bring it back, since reading a
   closed ticket is the reason it is here at all. */
.wb-item.is-resolved { opacity: .5; }
.wb-item.is-resolved:hover { opacity: .8; }
.wb-item.is-resolved.is-selected { opacity: 1; }
.wb-item.is-selected, .wb-item.is-selected:hover { background: var(--accent-soft); box-shadow: inset 3px 0 0 var(--accent); }
.wb-item-avatar, .wb-msg-avatar, .wb-view-avatar { display: flex; align-items: center; justify-content: center; flex: none; border-radius: 50%; background: var(--canvas); border: 1px solid var(--line); color: var(--muted); font-weight: 600; }
.wb-item-avatar { width: 2rem; height: 2rem; font-size: .85rem; }
.wb-item-side { display: flex; flex-direction: column; align-items: center; gap: .2rem; flex: none; }

/* One value from a fixed set, so it reads as a state rather than as another
   label. Two characters keeps the column one width; the full word is the title
   attribute, because an abbreviation nobody can expand is a guess. */
.wb-item-status { padding: 0 .25rem; border-radius: 4px; font-size: .68rem; line-height: 1.5; white-space: nowrap; background: var(--canvas); color: var(--muted); }
/* A tint like the rest. Solid accent on white made 新單 the loudest thing on
   the page, on every row that had not been answered yet -- which is most of
   them, most of the time. The unread count is the one strong colour a row
   needs. */
.wb-item-status.is-open { background: var(--accent-soft); color: var(--accent); font-weight: 600; }
.wb-item-status.is-pending { background: var(--accent-soft); color: #b3411f; }
.wb-item-status.is-on_hold { background: var(--note); color: #8a6100; }
.wb-item-status.is-resolved { background: #e8f6ec; color: var(--ok); }

/* Where it came from, beside who it is from. A mark plus a word rather than a
   chip, so it does not read as one of the labels. */
.wb-item-channel { display: inline-flex; align-items: center; gap: .2rem; flex: none; color: var(--muted); font-size: .72rem; font-weight: 500; }
.wb-item-channel i { font-size: .8rem; }
.wb-item-channel em { font-style: normal; }
.wb-item-channel.is-web { color: var(--ch-web); }
.wb-item-channel.is-app { color: var(--ch-app); }
.wb-item-channel.is-email { color: var(--ch-email); }
.wb-item-channel.is-facebook { color: var(--ch-facebook); }
.wb-item-channel.is-instagram { color: var(--ch-instagram); }
.wb-item-channel.is-line { color: var(--ch-line); }
/* Measured against the column, not the window: the column is draggable, so a
   viewport media query would answer the wrong question. */
@container wb-list (max-width: 17rem) {
  .wb-item-channel em { display: none; }
}

/* min-width: 0 is what lets the preview truncate at all. A flex item defaults
   to min-width: auto and so refuses to shrink below its content, which pushes
   the whole row past the edge of the column no matter what the child says
   about ellipsis. Every level of the chain needs it. */
.wb-msg-avatar { width: 1.9rem; height: 1.9rem; font-size: .8rem; }
.wb-view-avatar { width: 2.3rem; height: 2.3rem; }
.wb-item-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: .1rem; }
.wb-item-top { display: flex; align-items: center; gap: .35rem; min-width: 0; }
/* The ticket number leads, so truncating the name keeps the part agents quote
   to each other. Wrapping instead would give every row a different height,
   which is what makes a list hard to scan. */
.wb-item-top > strong { flex: 1 1 auto; min-width: 3.5rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: .92rem; }
.wb-item-top time { margin-left: auto; flex: none; color: var(--muted); font-size: .74rem; white-space: nowrap; }
.wb-item-line { display: flex; align-items: center; gap: .4rem; min-width: 0; }
.wb-item-preview { flex: 1; min-width: 0; color: var(--muted); font-size: .8rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* How many messages are waiting, not how many this agent has not read. */
.wb-unread { flex: none; min-width: 1.15rem; padding: 0 .3rem; border-radius: 999px; background: var(--accent); color: #fff; font-size: .7rem; text-align: center; }
/* wrap, and chips that refuse to shrink. Without flex: none a chip gets
   squeezed until its text breaks one character per line, and without wrapping
   the rest run off the edge of the column. */
.wb-item-foot { display: flex; flex-wrap: wrap; align-items: center; gap: .2rem .3rem; margin-top: .15rem; }
.wb-chip { flex: none; max-width: 9rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: .05rem .45rem; border: 1px solid var(--line); border-radius: 5px; color: var(--muted); font-size: .74rem; }
.wb-chip-label { border-color: var(--accent-line); background: var(--accent-soft); color: #b3411f; }
/* The number is what agents quote to each other and to customers. */
.wb-item-id, .wb-view-id { color: var(--muted); font-weight: 600; }
.wb-dot { width: .5rem; height: .5rem; border-radius: 50%; background: var(--accent); }

.wb-main { overflow: hidden; display: flex; flex-direction: column; }
.wb-placeholder, .wb-error { padding: 1.1rem; color: var(--muted); }
.wb-error { color: var(--warn); }

.wb-view { display: flex; flex-direction: column; height: 100%; }
.wb-view-head { display: flex; align-items: center; gap: .7rem; padding: .6rem .9rem; border-bottom: 1px solid var(--line); background: var(--surface); }
.wb-view-who h2 { margin: 0; font-size: 1rem; }
/* Hiding the panel is what gives the thread the width back on a narrow window,
   so the control sits beside the thread rather than inside the panel -- once
   the panel is gone there would be nothing left to click. */
.wb-view-detail { margin-left: auto; flex: none; display: flex; align-items: center; justify-content: center; width: 2rem; height: 2rem; border: 1px solid var(--line); border-radius: 8px; background: var(--surface); color: var(--muted); cursor: pointer; }
.wb-view-detail.is-on { border-color: var(--accent-line); background: var(--accent-soft); color: var(--accent); }
.wb-view-who p { margin: .15rem 0 0; color: var(--muted); font-size: .85rem; }
.wb-view-notice { margin: .6rem .9rem 0; padding: .5rem .75rem; background: var(--note); border-radius: 8px; }

.wb-thread { list-style: none; margin: 0; padding: .85rem .9rem; flex: 1; overflow-y: auto; }
.wb-day { display: flex; align-items: center; gap: .75rem; margin: .35rem 0 .7rem; color: var(--muted); font-size: .8rem; }
.wb-day::before, .wb-day::after { content: ''; flex: 1; height: 1px; background: var(--line); }
.wb-msg { display: flex; gap: .5rem; margin-bottom: .65rem; }
.wb-msg-out { justify-content: flex-end; }
.wb-msg-col { display: flex; flex-direction: column; max-width: 76%; }
.wb-msg-out .wb-msg-col { align-items: flex-end; }
.wb-bubble { padding: .5rem .8rem; border-radius: 12px; white-space: pre-wrap; overflow-wrap: anywhere; }
.wb-msg-in .wb-bubble { background: var(--surface); border: 1px solid var(--line); }
.wb-msg-out .wb-bubble { background: #eaf2fd; border: 1px solid #cfe0f7; }
.wb-msg-meta { display: flex; gap: .4rem; align-items: center; margin-top: .2rem; color: var(--muted); font-size: .76rem; }
.wb-ticks { color: var(--line); }
.wb-ticks.is-seen { color: #3b82f6; }
.wb-msg-failed { margin: .3rem 0 0; color: var(--warn); font-size: .82rem; }

/* An internal note must never be mistaken for something the customer saw. */
.wb-note { display: flex; flex-wrap: wrap; align-items: baseline; gap: .5rem; margin-bottom: .65rem; padding: .55rem .8rem; background: var(--note); border: 1px dashed var(--note-line); border-radius: 10px; }
.wb-note-tag { padding: .05rem .45rem; border-radius: 5px; background: var(--note-line); color: #6b4e00; font-size: .74rem; }
.wb-note-body { flex: 1; min-width: 12rem; white-space: pre-wrap; overflow-wrap: anywhere; }
.wb-note-meta { color: var(--muted); font-size: .76rem; }

.wb-composer { border-top: 1px solid var(--line); background: var(--surface); padding: .55rem .9rem .7rem; }
.wb-composer.is-note { background: var(--note); }
.wb-tabs { display: flex; gap: 1rem; margin-bottom: .4rem; }
.wb-tabs button { padding: .3rem 0; border: 0; border-bottom: 2px solid transparent; background: none; color: var(--muted); cursor: pointer; }
.wb-tabs button.is-active { color: var(--accent); border-bottom-color: var(--accent); }
.wb-composer textarea { width: 100%; padding: .7rem; border: 1px solid var(--line); border-radius: 10px; resize: vertical; background: var(--surface); }
.wb-composer-foot { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-top: .45rem; }
.wb-composer-hint { color: var(--muted); font-size: .78rem; }
/* The submit button, not every button in the row: this also matched the
   canned-reply toggle beside it and overrode its outlined style, so the
   secondary action was the loudest thing in the composer and the primary one
   next to it looked identical. */
.wb-composer-foot button[type="submit"] { padding: .5rem 1.4rem; border: 0; border-radius: 8px; background: var(--accent); color: #fff; font-weight: 600; cursor: pointer; }
.wb-composer-foot button[type="submit"]:disabled { background: var(--line); color: var(--muted); cursor: not-allowed; }

/* icookfont: the classes come from the vendored stylesheet, these only place
   them. Icons are decorative next to their own labels, so they are hidden from
   assistive technology rather than read out twice. */
[class^="icon-"], [class*=" icon-"] { line-height: 1; }
.cc-send i, .wb-composer-foot button i { font-size: 1rem; }
.cc-empty-icon i { font-size: 2.8rem; }

/* Labels on the open conversation. Adding one is how work is routed to an
   area, which is why it sits above the composer rather than in a menu. */
.wb-labels { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; }
.wb-label { display: inline-flex; align-items: center; gap: .3rem; padding: .12rem .5rem; border: 1px solid var(--accent-line); border-radius: 999px; background: var(--accent-soft); color: #b3411f; font-size: .8rem; }
.wb-label button { border: 0; background: none; color: inherit; cursor: pointer; padding: 0; line-height: 1; opacity: .6; }
.wb-label button:hover { opacity: 1; }
.wb-label-new { padding: .12rem .6rem; border: 1px dashed var(--line); border-radius: 999px; background: none; color: var(--muted); font-size: .8rem; cursor: pointer; }
/* Picking a label. Full width of the panel rather than a pill wedged between
   two buttons: the input is what is being used, and at 15rem there was room
   for about four characters of it. */
.wb-picker { position: relative; width: 100%; }
.wb-picker-input { width: 100%; padding: .25rem .6rem; border: 1px solid var(--accent-line); border-radius: 999px; background: var(--surface); font: inherit; font-size: .8rem; }
.wb-picker-input:focus { outline: 2px solid var(--accent-soft); outline-offset: 1px; border-color: var(--accent); }
/* Ours, not the browser's: a datalist popup is styled by the platform and
   looks like nothing else here. */
.wb-picker-list { position: absolute; z-index: 30; top: calc(100% + .25rem); left: 0; right: 0; list-style: none; margin: 0; padding: .2rem; max-height: 13rem; overflow-y: auto; background: var(--surface); border: 1px solid var(--line); border-radius: 10px; box-shadow: 0 8px 24px rgb(0 0 0 / 12%); }
.wb-picker-option { display: block; width: 100%; padding: .3rem .5rem; border: 0; border-radius: 6px; background: none; color: var(--ink); font: inherit; font-size: .82rem; text-align: start; cursor: pointer; }
.wb-picker-option.is-active { background: var(--accent-soft); color: #b3411f; }
/* Set apart, because it is the one row that changes the taxonomy rather than
   using it. */
.wb-picker-new { margin-top: .2rem; border-top: 1px solid var(--line); border-radius: 0 0 6px 6px; color: var(--muted); }
.wb-picker-new.is-active { color: #b3411f; }

/* One person's whole history, across channels. */
/* Right-hand panel: everything that acts on the ticket, and everything known
   about the person. Beside the conversation rather than above it -- tools
   stacked over the messages interrupt reading them. */
.wb-panel { border-left: 1px solid var(--line); background: var(--surface); overflow-y: auto; }
.wb-panel-section { padding: .7rem .8rem; border-bottom: 1px solid var(--line); }
.wb-panel-section h2 { margin: 0 0 .5rem; font-size: .82rem; color: var(--muted); font-weight: 600; letter-spacing: .04em; }
.wb-panel-field { display: flex; flex-direction: column; gap: .2rem; margin-bottom: .55rem; font-size: .78rem; color: var(--muted); }
.wb-panel-field select { padding: .4rem .5rem; border: 1px solid var(--line); border-radius: 8px; background: var(--surface); color: var(--ink); font-size: .9rem; }
/* Status, as three targets rather than a dropdown. An agent sets it dozens of
   times a day and a select costs a click before the options are even visible.
   Vertical because the panel is 15rem wide: three Chinese labels side by side
   read as a toolbar, stacked they read as one choice. */
.wb-seg { display: flex; flex-direction: column; border: 1px solid var(--line); border-radius: 8px; background: var(--surface); overflow: hidden; }
.wb-seg-option, .wb-seg-current { display: flex; align-items: center; gap: .35rem; width: 100%; padding: .34rem .5rem; border: 0; border-bottom: 1px solid var(--line); background: none; color: var(--ink); font: inherit; font-size: .85rem; text-align: start; }
.wb-seg > :last-child { border-bottom: 0; }
.wb-seg-option { cursor: pointer; }
.wb-seg-option:hover:not(:disabled) { background: var(--canvas); }
.wb-seg-option:disabled { cursor: default; }
/* The mark, so the choice is not carried by colour alone. Always laid out, so
   selecting one does not shunt the labels sideways. */
.wb-seg-option::before, .wb-seg-current::before { content: ""; flex: none; width: .9em; color: currentcolor; }
.wb-seg-option.is-on::before, .wb-seg-current::before { content: "\2713"; }
.wb-seg-option.is-on { font-weight: 600; }
.wb-seg-option.is-on.is-pending { background: var(--accent-soft); color: #b3411f; }
.wb-seg-option.is-on.is-on_hold { background: var(--note); color: #8a6100; }
.wb-seg-option.is-on.is-resolved { background: #e8f6ec; color: var(--ok); }
/* 新工單 is a state, not a choice -- replying leaves it on its own -- so it is
   shown as where the ticket is and nothing happens if you press it. */
.wb-seg-current { background: var(--accent); color: #fff; font-weight: 600; }

.wb-panel-who { display: flex; gap: .6rem; align-items: flex-start; margin-bottom: .55rem; }
.wb-panel-avatar { display: flex; align-items: center; justify-content: center; flex: none; width: 2.2rem; height: 2.2rem; border-radius: 50%; background: var(--canvas); border: 1px solid var(--line); color: var(--muted); font-weight: 600; }
.wb-panel-badge { display: inline-block; margin-left: .4rem; padding: .05rem .45rem; border-radius: 5px; background: var(--accent-soft); color: #b3411f; font-size: .72rem; }
.wb-panel-badge-guest { background: var(--canvas); color: var(--muted); }
.wb-panel-badge-vip { background: var(--note); color: #8a6100; border: 1px solid var(--note-line); }
.wb-panel-badge-staff { background: #e8f6ec; color: var(--ok); }
/* Quiet, because it qualifies what is above it rather than adding to it. */
.wb-panel-asof { margin: .35rem 0 0; color: var(--muted); font-size: .74rem; }
/* A deleted or locked account explains most of what somebody is writing in
   about, so it is said before anything else in the section rather than as one
   more field among the dates. */
.wb-panel-alarm { margin: 0 0 .5rem; padding: .4rem .6rem; border-radius: 6px; background: var(--accent-soft); border: 1px solid var(--accent-line); color: var(--warn); font-size: .8rem; }
.wb-panel-flags { display: flex; flex-wrap: wrap; gap: .25rem; margin: .1rem 0 .5rem; }
/* Client-supplied strings: a build number or a model wraps rather than
   stretching the column, and it is monospaced so a version is scannable. */
.wb-panel-report-value { text-align: end; word-break: break-word; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .8rem; }
/* Oldest first, so it reads the way they walked it. */
.wb-panel-trail { list-style: none; margin: .1rem 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: .15rem .3rem; font-size: .78rem; color: var(--ink); }
.wb-panel-trail li + li::before { content: "›"; margin-inline-end: .3rem; color: var(--muted); }
.wb-panel-id { margin: .2rem 0 0; color: var(--muted); font-size: .82rem; word-break: break-all; }
.wb-panel-list { display: flex; justify-content: space-between; gap: 1rem; margin: 0 0 .4rem; font-size: .85rem; }
.wb-panel-list dt { color: var(--muted); }
.wb-panel-list dd { margin: 0; }
.wb-panel-link { display: inline-block; margin-top: .3rem; padding: 0; border: 0; background: none; color: var(--accent); font-size: .85rem; cursor: pointer; text-decoration: none; }
.wb-panel-pending { margin: .6rem 0 0; padding: .5rem .6rem; background: var(--canvas); border-radius: 8px; color: var(--muted); font-size: .78rem; }
.wb-panel-history { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .1rem; }
.wb-panel-history button { display: flex; flex-direction: column; gap: .1rem; width: 100%; padding: .35rem .4rem; border: 0; border-radius: 6px; background: none; text-align: start; cursor: pointer; }
.wb-panel-history button:hover { background: var(--canvas); }
.wb-panel-history-top { display: flex; align-items: center; gap: .3rem; width: 100%; font-size: .76rem; color: var(--muted); }
.wb-panel-history-id { font-weight: 600; }
.wb-panel-history-top time { margin-left: auto; }
/* What it was about. Truncated rather than wrapped so five of them stay five
   rows -- the section is for recognising a pattern at a glance. */
.wb-panel-history-preview { width: 100%; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: .8rem; }
.wb-panel-history-more { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: .5rem; }
/* A count, quiet, that happens to be the way to the rest of them. In accent
   red it was the loudest thing in the panel while saying the least. */
.wb-panel-history-more .wb-panel-link { margin: 0; padding: .1rem .45rem; border-radius: 999px; background: var(--canvas); color: var(--muted); font-size: .76rem; }
.wb-panel-history-more .wb-panel-link:hover { background: var(--accent-soft); color: var(--accent); }

/* ══ Settings (server-rendered, under /admin/settings) ════════════════ */
.st { display: grid; grid-template-columns: 14rem minmax(0, 1fr); grid-template-rows: minmax(0, 1fr); min-width: 0; height: 100vh; overflow: hidden; }

.st-rail { padding: 1.25rem 1rem; background: var(--surface); border-right: 1px solid var(--line); overflow-y: auto; }
.st-rail-title { margin: .35rem 0 1rem; font-size: 1.15rem; }
.st-rail-nav { display: flex; flex-direction: column; gap: .15rem; }
.st-rail-link { padding: .5rem .75rem; border-radius: 8px; color: var(--ink); text-decoration: none; font-size: .95rem; }
.st-rail-link:hover { background: var(--canvas); }
.st-rail-link.is-active { background: var(--accent-soft); color: var(--accent); font-weight: 600; }
.st-rail-divider { margin: .9rem .75rem .15rem; padding-top: .7rem; border-top: 1px solid var(--line); display: block; color: var(--muted); font-size: .74rem; }

.st-main { padding: 2rem 2.5rem 4rem; overflow-y: auto; }
.st-main > * { max-width: 56rem; }
.st-flash { padding: .7rem 1rem; border-radius: 8px; background: #e8f6ec; color: var(--ok); }
.st-flash-alert { background: var(--accent-soft); color: var(--warn); }

.st-head { margin-bottom: 1.75rem; }
.st-head h2 { margin: 0 0 .35rem; font-size: 1.35rem; }
.st-head p { margin: 0 0 1rem; color: var(--muted); }
.st-head code { padding: .1rem .35rem; border-radius: 4px; background: var(--canvas); font-size: .9em; }

.st-form { display: flex; flex-direction: column; gap: 1.25rem; }
.st-field { display: flex; flex-direction: column; gap: .4rem; }
.st-field-inline { flex-direction: row; align-items: center; gap: .5rem; }
.st-label { font-weight: 600; }
.st-input { padding: .6rem .75rem; border: 1px solid var(--line); border-radius: 8px; background: var(--surface); }
.st-input-narrow { max-width: 8rem; }
.st-code { padding: .75rem; border: 1px solid var(--line); border-radius: 8px; background: var(--surface); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 13px; line-height: 1.6; tab-size: 2; }
.st-help { margin: 0; color: var(--muted); font-size: .87rem; }
.st-help code { padding: .05rem .3rem; border-radius: 4px; background: var(--canvas); }
.st-errors { margin: 0; padding: .75rem 1rem .75rem 2rem; border-radius: 8px; background: var(--accent-soft); color: var(--warn); }

.st-actions { display: flex; align-items: center; gap: 1rem; }
.st-submit { padding: .6rem 1.5rem; border: 0; border-radius: 8px; background: var(--accent); color: #fff; font-weight: 600; text-decoration: none; cursor: pointer; }
.st-cancel { color: var(--muted); text-decoration: none; }
.st-meta { color: var(--muted); font-size: .87rem; }

.st-preview { margin-top: 3rem; }
.st-preview h3 { margin: 0 0 .75rem; font-size: 1.05rem; }
.st-preview-frame { width: 100%; height: 30rem; border: 1px solid var(--line); border-radius: 10px; background: #fff; }

.st-empty { padding: 2rem; border: 1px dashed var(--line); border-radius: 12px; color: var(--muted); text-align: center; }
.st-list { list-style: none; margin: 0; padding: 0; border: 1px solid var(--line); border-radius: 12px; background: var(--surface); overflow: hidden; }
.st-list-item { display: flex; align-items: center; gap: 1rem; padding: .9rem 1.25rem; border-bottom: 1px solid var(--line); }
.st-list-item:last-child { border-bottom: 0; }
.st-list-item.is-off { background: var(--canvas); }
.st-list-main { flex: 1; min-width: 0; }
.st-list-title { font-weight: 600; }
.st-list-body { margin: .2rem 0 0; color: var(--muted); font-size: .88rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.st-list-actions { display: flex; align-items: center; gap: .9rem; font-size: .9rem; }
.st-list-actions form { margin: 0; }
.st-tag { padding: .1rem .5rem; border-radius: 999px; background: var(--canvas); color: var(--muted); font-size: .8rem; }
.st-link-danger { padding: 0; border: 0; background: none; color: var(--warn); font-size: .9rem; cursor: pointer; text-decoration: underline; }

/* Canned replies in the composer */
.wb-canned { position: relative; }
.wb-canned-toggle { padding: .3rem .8rem; border: 1px solid var(--line); border-radius: 8px; background: var(--surface); font-size: .87rem; cursor: pointer; }
.wb-canned-toggle:hover:not(:disabled) { border-color: var(--accent-line); color: var(--accent); }
.wb-canned-menu { position: absolute; bottom: calc(100% + .4rem); left: 0; z-index: 20; width: 24rem; max-height: 20rem; overflow-y: auto; background: var(--surface); border: 1px solid var(--line); border-radius: 10px; box-shadow: 0 8px 24px rgb(0 0 0 / 12%); }
.wb-canned-note { margin: 0; padding: .9rem 1rem; color: var(--muted); font-size: .88rem; }
.wb-canned-item { display: flex; flex-direction: column; gap: .15rem; width: 100%; padding: .65rem 1rem; border: 0; border-bottom: 1px solid var(--line); background: none; text-align: start; cursor: pointer; }
.wb-canned-item:last-child { border-bottom: 0; }
.wb-canned-item:hover { background: var(--accent-soft); }
.wb-canned-title { font-weight: 600; font-size: .9rem; }
.wb-canned-preview { color: var(--muted); font-size: .83rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Members and permissions */
.st-static { margin: 0; color: var(--muted); }
.st-muted { color: var(--muted); }
.st-tag-warn { background: var(--accent-soft); color: #c2410c; }
.st-link-plain { padding: 0; border: 0; background: none; color: var(--accent); font-size: .9rem; cursor: pointer; text-decoration: underline; }

.st-fieldset { margin: 0; padding: 0; border: 0; }
.st-fieldset legend { padding: 0; }
.st-choice { display: flex; align-items: flex-start; gap: .6rem; padding: .7rem .85rem; border: 1px solid var(--line); border-radius: 10px; background: var(--surface); cursor: pointer; }
.st-choice + .st-choice { margin-top: .4rem; }
.st-choice:hover { border-color: var(--accent-line); }
.st-choice:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); }
.st-choice input { margin-top: .25rem; }
.st-choice-name { display: block; font-weight: 600; }
.st-choice-note { display: block; color: var(--muted); font-size: .87rem; }

.st-note { padding: 1rem 1.25rem; border: 1px solid var(--note-line); border-radius: 10px; background: var(--note); }
.st-note p { margin: 0 0 .5rem; }
.st-note ul { margin: 0; padding-left: 1.25rem; }
.st-note code { font-size: .87rem; }

/* Assignment rules: a page with two things on it, so each says what it is. */
.st-section { margin-bottom: 2.5rem; }
.st-section-title { margin: 0 0 .35rem; font-size: 1.05rem; }
.st-section .st-help { margin-bottom: .9rem; }
.st-inline-form { display: inline-flex; align-items: center; gap: .75rem; margin: 0; }
.st-input-medium { max-width: 18rem; }
/* Numbered, because the order is the policy: rule 1 beats rule 2. */
.st-list-numbered { counter-reset: st-rule; }
.st-list-numbered .st-list-item::before { counter-increment: st-rule; content: counter(st-rule); flex: none; width: 1.4rem; color: var(--muted); font-size: .85rem; font-variant-numeric: tabular-nums; }

/* ══ Attachments ══════════════════════════════════════════════════════ */
.att-list { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: .5rem; }

.att-image { display: block; line-height: 0; border-radius: 10px; overflow: hidden; border: 1px solid var(--line); }
.att-image img { max-width: 220px; max-height: 180px; object-fit: cover; display: block; }

.att-video { max-width: 320px; border-radius: 10px; border: 1px solid var(--line); background: #000; }

.att-card { display: flex; align-items: center; gap: .6rem; max-width: 260px; padding: .6rem .8rem; border: 1px solid var(--line); border-radius: 10px; background: var(--surface); color: var(--ink); text-decoration: none; text-align: start; cursor: pointer; font: inherit; }
.att-card:hover { border-color: var(--accent-line); background: var(--accent-soft); }
.att-card i { font-size: 1.2rem; color: var(--accent); flex: none; }
.att-card-main { min-width: 0; display: flex; flex-direction: column; }
.att-card-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: .9rem; }
.att-card-note { color: var(--muted); font-size: .8rem; }
.att-video-load:disabled { opacity: .6; cursor: progress; }

/* The tray of files waiting to be sent */
.up-tray { list-style: none; margin: .5rem 0 0; padding: 0; display: flex; flex-direction: column; gap: .3rem; }
.up-item { display: flex; align-items: center; gap: .5rem; padding: .35rem .6rem; border: 1px solid var(--line); border-radius: 8px; background: var(--canvas); font-size: .85rem; }
.up-item.is-error { border-color: var(--accent-line); background: var(--accent-soft); }
.up-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.up-note { color: var(--muted); font-size: .8rem; white-space: nowrap; }
.up-item.is-error .up-note { color: var(--warn); }
.up-item button { border: 0; background: none; color: var(--muted); font-size: 1.1rem; line-height: 1; cursor: pointer; padding: 0 .2rem; }

.up-add { display: inline-flex; align-items: center; gap: .35rem; padding: .3rem .7rem; border: 1px solid var(--line); border-radius: 8px; background: var(--surface); color: var(--muted); font-size: .85rem; cursor: pointer; }
.up-add:hover:not(:disabled) { border-color: var(--accent-line); color: var(--accent); }
.up-add:disabled { opacity: .5; cursor: not-allowed; }

/* A + in a circle, matching the send button across the row. The label was
   13.6px beside a 15px box, which read as an afterthought; the name lives on
   as aria-label and as the title, so it is still announced and still one
   hover away. */
.up-add-compact { width: var(--cc-control, 2.9rem); height: var(--cc-control, 2.9rem); padding: 0; justify-content: center; border-radius: 50%; }
.up-add-compact i { font-size: 1.15rem; }

.cc-uploads { display: flex; flex-direction: column; gap: .4rem; align-items: flex-start; }

.st-tag-ok { background: #e8f6ec; color: var(--ok); }

/* ══ The search box, which is also the filter ═════════════════════════ */
.fb { position: relative; flex: 1; min-width: 0; max-width: 46rem; }

.fb-box { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem; padding: .3rem .6rem; border: 1px solid var(--line); border-radius: 10px; background: var(--surface); cursor: text; }
.fb-box:focus-within { border-color: var(--accent); }
.fb-box > i { color: var(--muted); font-size: .95rem; flex: none; }
.fb-box input { flex: 1; min-width: 8rem; padding: .25rem 0; border: 0; background: none; outline: none; font-size: .9rem; }

/* A condition in the box. Labels and people carry the marker everyone already
   reads as tag and person; the rest are distinctive words and need none. */
.fb-token { display: inline-flex; align-items: center; gap: .15rem; padding: .1rem .2rem .1rem .45rem; border-radius: 6px; background: var(--canvas); font-size: .82rem; white-space: nowrap; }
.fb-token button { border: 0; background: none; color: var(--muted); font-size: .95rem; line-height: 1; padding: 0 .2rem; cursor: pointer; }
.fb-token button:hover { color: var(--warn); }
.fb-token-statuses { background: var(--canvas); }
.fb-token-response { background: var(--accent-soft); color: #b3411f; }
.fb-token-labels { background: var(--accent-soft); color: #b3411f; }
.fb-token-assignees { background: #eef2ff; color: #3730a3; }
.fb-token-channels { background: var(--canvas); }

.fb-clear { flex: none; border: 0; background: none; color: var(--muted); font-size: .8rem; cursor: pointer; text-decoration: underline; }
.fb-clear:hover { color: var(--accent); }

.fb-panel { position: absolute; top: calc(100% + .3rem); left: 0; right: 0; z-index: 30; max-height: 24rem; overflow-y: auto; background: var(--surface); border: 1px solid var(--line); border-radius: 10px; box-shadow: 0 10px 30px rgb(0 0 0 / 12%); }

/* A row per dimension: the label, then every option across the line. A single
   vertical list of every option in every dimension reads longer and scans
   worse than the same options grouped on their own row. */
.fb-row { display: flex; align-items: center; gap: 1rem; padding: .5rem .9rem; border-bottom: 1px solid var(--line); }
.fb-row-clear { flex: none; margin-left: auto; width: 1.3rem; height: 1.3rem; border: 0; border-radius: 5px; background: none; color: var(--muted); font-size: 1rem; line-height: 1; cursor: pointer; }
.fb-row-clear:hover { background: var(--accent-soft); color: var(--accent); }
.fb-more { padding: .3rem .6rem; border: 1px dashed var(--line); border-radius: 8px; background: none; color: var(--muted); font-size: .82rem; cursor: pointer; }
.fb-more:hover { border-color: var(--accent-line); color: var(--accent); }
.fb-row:last-of-type { border-bottom: 0; }
.fb-row-title { flex: none; width: 3.5rem; color: var(--muted); font-size: .8rem; }
.fb-option-count { margin-left: .35rem; color: var(--muted); font-style: normal; font-size: .8em; }
.fb-option.is-on .fb-option-count { color: inherit; opacity: .7; }
.fb-row-options { display: flex; flex-wrap: wrap; gap: .2rem; min-width: 0; }

/* The whole option is the target, and the chosen one is a filled pill --
   which is what says "on" from across the room, before anyone reads the tick. */
.fb-option { display: inline-flex; align-items: center; gap: .4rem; padding: .3rem .6rem; border-radius: 8px; font-size: .87rem; cursor: pointer; white-space: nowrap; }
.fb-option:hover { background: var(--canvas); }
.fb-option.is-on { background: var(--accent-soft); color: #b3411f; }

/* The browser's own checkbox cannot be recoloured, so it is replaced. Drawn
   rather than an image: one less asset to load and it inherits the accent. */
.fb-option input { appearance: none; -webkit-appearance: none; position: relative; flex: none; width: 1.05rem; height: 1.05rem; margin: 0; border: 1.5px solid var(--line); border-radius: 5px; background: var(--surface); cursor: pointer; }
.fb-option input:checked { border-color: var(--accent); background: var(--accent); }
.fb-option input:checked::after { content: ''; position: absolute; left: 50%; top: 50%; width: .27rem; height: .5rem; border: solid #fff; border-width: 0 2px 2px 0; transform: translate(-50%, -60%) rotate(45deg); }
.fb-option input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.fb-panel-foot { margin: 0; padding: .5rem .9rem; border-top: 1px solid var(--line); color: var(--muted); font-size: .8rem; }


/* ══ API docs ═════════════════════════════════════════════════════════ */
/* Scalar paints its own full-height page, so this is only the strip above it
   that gets you back and hands you the file. */
.doc-page { display: flex; flex-direction: column; height: 100vh; }
.doc-head { display: flex; align-items: center; gap: 1rem; padding: .5rem .9rem; border-bottom: 1px solid var(--line); background: var(--surface); font-size: .85rem; }
.doc-raw { margin-left: auto; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

/* ══ Help centre admin ════════════════════════════════════════════════ */
/* Grouped by section, because position is per section: a flat list would make
   the order look arbitrary. */
.hca-group { margin-bottom: 2rem; }
.hca-group-title { margin: 0 0 .5rem; color: var(--muted); font-size: .85rem; font-weight: 600; }

/* Up and down rather than drag-and-drop: it works without JavaScript, it works
   with a keyboard, and eighty articles get reordered a few times a year. */
.hca-move-form { display: inline; }
.hca-move { padding: .1rem .45rem; border: 1px solid var(--line); border-radius: 6px; background: var(--surface); color: var(--muted); cursor: pointer; }
.hca-move:hover { border-color: var(--accent-line); color: var(--accent); }
.hca-publish { padding: .15rem .6rem; border: 1px solid var(--accent-line); border-radius: 6px; background: var(--accent-soft); color: var(--accent); font-size: .85rem; cursor: pointer; }

.hca-sections { list-style: none; margin: .5rem 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: .3rem .75rem; font-size: .85rem; }
.hca-sections li { display: inline-flex; align-items: center; gap: .3rem; }
.hca-count { padding: 0 .35rem; border-radius: 999px; background: var(--canvas); color: var(--muted); font-size: .74rem; }

/* Bordered, because it is the article as the public will see it rather than
   part of the form around it. */
.hca-preview { margin-top: .75rem; padding: 1.25rem; border: 1px solid var(--line); border-radius: 10px; background: var(--surface); }

.hca-danger { padding: .5rem 1.2rem; border: 1px solid var(--warn); border-radius: 8px; background: var(--surface); color: var(--warn); cursor: pointer; }
.hca-danger:hover { background: var(--accent-soft); }
