/* Tweets Report — house clothes, sized to a triage tool.
   Tokens and motion copied from the family. The document preview stays Calibri. */
:root {
  --canvas: #07080b;
  --canvas-2: #11141a;
  --surface: #16181c;
  --surface-2: #1c1f26;
  --ink: #f0f0f0;
  --muted: #909099;
  --line: rgba(255,255,255,.08);
  --line-strong: rgba(255,255,255,.14);
  --accent: #14b8a6;
  --accent-dim: rgba(20,184,166,.14);
  --accent-ink: #04120f;
  --warn: #fbbf24;
  --warn-dim: rgba(251,191,36,.14);
  --danger: #fb7185;
  --ok: #4ade80;
  --glass: 1;
  --font: -apple-system,BlinkMacSystemFont,'Inter Variable',system-ui,"Segoe UI",Roboto,sans-serif;
  --radius: 14px;
  --radius-sm: 9px;
  --radius-pill: 999px;
  --wrapmax: 44rem;          /* content column; header + action bar match it */
  --topfloat-h: 128px;       /* set by JS to the real floating-layer height */
  /* LIQUID GLASS light, carried from share/index.html. The rim pools a specular
     highlight toward --lg-x / --lg-y in --lg-tint at --lg-intensity. Defaults are
     the neutral overhead sheen: --lg-y sits just above the top edge, where a
     nothing-in-particular light lives. */
  --lg-x: 0.5;
  --lg-y: -0.14;
  --lg-tint: rgba(255,255,255,.9);
  --lg-intensity: .42;
  --si-t: env(safe-area-inset-top, 0px);
  --si-b: env(safe-area-inset-bottom, 0px);
  --si-l: env(safe-area-inset-left, 0px);
  --si-r: env(safe-area-inset-right, 0px);
  --dur-fast: 140ms;
  --dur-med: 220ms;
  --dur-slow: 360ms;
  --ease-out: cubic-bezier(.16,1,.3,1);
  --ease-spring: cubic-bezier(.22,1.2,.36,1);
  --ease-exit: cubic-bezier(.4,0,1,1);
  --header-h: 56px;
  --dock-h: 72px;
  --x-blue: #1d9bf0;
  color-scheme: dark;
}

html.light {
  --canvas: #dfe6ef;
  --canvas-2: #cfd8e4;
  --surface: #f7f8fb;
  --surface-2: #eef1f6;
  --ink: #12151a;
  --muted: #5c6573;
  --line: rgba(16,22,32,.10);
  --line-strong: rgba(16,22,32,.16);
  --accent-ink: #ffffff;
  --warn: #7c5607;
  --warn-dim: rgba(124,86,7,.12);
  --danger: #be123c;
  --ok: #116b31;
  color-scheme: light;
}

*, *::before, *::after { box-sizing: border-box; }
/* Author display (e.g. .btn{display:inline-flex}) outranks the UA [hidden]
   rule, so toggling the `hidden` property left buttons like Install on iOS and
   the keyword tray Restore/Delete visible. Make hidden win. */
[hidden] { display: none !important; }
/* House style 2A. The PAGE does not scroll and does not bounce: the whole
   viewport is a fixed shell and one bounded region inside it scrolls, which is
   what mortgage does. Without this, iOS rubber-bands the document, fires
   pull-to-refresh at the top, and pans the fixed backgrounds under the content
   so it reads as scrolling into empty space. */
html, body {
  margin: 0;
  height: 100%; height: 100dvh;
  /* share's iOS fill: -webkit-fill-available is the height Safari reports for the
     visible area, so the shell reaches the true bottom edge under the home
     indicator instead of stopping at the old 100vh. */
  min-height: -webkit-fill-available;
  overflow: hidden;
  overscroll-behavior: none;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
@supports not (height: 100dvh) { html, body { height: 100vh; } }
html { -webkit-text-size-adjust: 100%; background: var(--canvas); }
body {
  /* share dropped -webkit-font-smoothing in v23: it is macOS-only and rendered
     text visibly lighter than every other label on the machine. */
  font-family: var(--font);
  background: transparent;            /* the fixed ground below is the floor */
  color: var(--ink);
  display: flex;
  flex-direction: column;
  padding: 0;
}
html.no-motion *, html.no-motion *::before, html.no-motion *::after {
  animation: none !important;
  transition: none !important;
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* A tweet can carry a long unbroken token -- a URL, a hashtag, a run of
   punctuation. Without this the token sets the min-content width of its card,
   which widens the panel, which gives the whole PAGE a horizontal scroll: on a
   phone you can swipe the entire UI sideways into empty space. Every element
   that renders user or document text has to be able to break. */
.body, .tweet-handle, .doc, .doc a, .m-read, .lede, .hint, .rt-sub,
.faq-row p, .pv-row p, .empty, .slot, .fb-name, .hist-row strong,
.triage-summary, .section-head h3, .panel-title, .nav-item-label {
  overflow-wrap: anywhere;
}

:focus { outline: none; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.bg-ground, .bg-scrim, #bg-canvas {
  position: fixed; inset: 0; pointer-events: none;
}
#bg-canvas { width: 100%; height: 100%; display: block; }
.bg-ground { z-index: -5; }
#bg-canvas { z-index: -4; }
.bg-scrim  { z-index: -2; }
#weather-canvas, #weather-glass {
  position: fixed; inset: 0; width: 100%; height: 100%;
  z-index: -1; pointer-events: none; display: block;
}
/* Ground layers reach the LARGE viewport so they bleed under the status bar and
   home indicator with no white gap. position:fixed means they contribute zero
   scroll height however tall they are (house style 2A). */
@supports (height: 100lvh) {
  .bg-ground, .bg-scrim, #bg-canvas, #weather-canvas, #weather-glass { height: 100lvh; }
}
.bg-ground {
  background:
    radial-gradient(1200px 700px at 50% -10%, color-mix(in srgb, var(--canvas-2) 70%, transparent), transparent 60%),
    var(--canvas);
}
.bg-ground::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    linear-gradient(180deg, rgba(255,168,92,var(--dl-warm,0)), transparent 62%),
    linear-gradient(0deg, rgba(64,96,180,var(--dl-cool,0)), transparent 58%);
  transition: background var(--dur-slow) var(--ease-out);
}
.bg-scrim { background: linear-gradient(180deg, rgba(0,0,0,.18), transparent 28%, transparent 72%, rgba(0,0,0,.22)); }
html.light .bg-scrim { background: linear-gradient(180deg, rgba(255,255,255,.2), transparent 30%); }

/* THE FLOATING TOP LAYER. Background < scrolling UI < this. The header and the
   action bar float over the content, which slides under them (liquid glass).
   The wrapper is transparent and lets pointer events through its gutters so the
   content beside the floating card still scrolls; only the bars themselves
   catch input. A gentle scrim keeps the header text legible over whatever
   scrolls beneath without hiding it. Overlays and the menu sit above this. */
.topfloat {
  position: fixed; top: 0; left: 0; right: 0; z-index: 40;
  pointer-events: none;
}
.topfloat > * { pointer-events: auto; }
.topfloat::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0;
  height: calc(var(--si-t) + 66px); pointer-events: none;
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--canvas) 78%, transparent),
    color-mix(in srgb, var(--canvas) 30%, transparent) 62%, transparent);
}

/* The action bar is a floating translucent glass card, like /tweet's counter
   bar: the sky (and the content) shows through it. It has NO full-width slab
   behind it -- just the rounded card. The Due status takes the counter's place
   on the left as coloured text (no pill, no status dot -- the AI-slop tell),
   Preview and Copy on the right. */
.actionbar {
  position: relative; z-index: 1; flex: none;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: min(var(--wrapmax), calc(100% - 40px)); margin: 2px auto 0;
  min-height: 54px; padding: 8px 14px; border-radius: var(--radius);
  background: color-mix(in srgb, var(--surface) 72%, transparent);
  -webkit-backdrop-filter: blur(18px) saturate(1.2);
          backdrop-filter: blur(18px) saturate(1.2);
  border: 1px solid var(--line-strong);
  box-shadow: 0 10px 30px rgba(0,0,0,.28);
}
.actionbar-btns { display: flex; align-items: center; gap: 8px; flex: none; }
.actionbar .btn, .actionbar .btn.fixed { flex: none; min-width: 66px; padding: 0 12px; }
/* Until there is a report, Preview and Copy do nothing but toast. Dim them so
   the persistent bar stays honest -- they still respond (and explain) on tap. */
body:not(.has-report) .actionbar #preview-btn,
body:not(.has-report) .actionbar #copy-btn { opacity: .5; }

/* Coloured like /tweet's counter -- the level is the colour, nothing else. It
   wraps rather than clips: one line where it fits, two on the narrowest phones,
   so the label is never shortened. */
.due-text {
  flex: 1 1 auto; min-width: 0;
  font-size: clamp(15px, 4vw, 21px); font-weight: 800; letter-spacing: -.02em;
  line-height: 1.12; color: var(--due-ink); overflow-wrap: break-word;
}
.due-text[data-level="today"]    { --due-ink: #12a874; }
.due-text[data-level="hours"]    { --due-ink: #4a9e2f; }
.due-text[data-level="soon"]     { --due-ink: #b8860b; }
.due-text[data-level="vsoon"]    { --due-ink: #d1770c; }
.due-text[data-level="now"]      { --due-ink: #e0620c; }
.due-text[data-level="critical"] { --due-ink: #e11d48; }
.due-text[data-level="tomorrow"] { --due-ink: #3b82f6; }
html.light .due-text[data-level="today"]    { --due-ink: #0e8f62; }
html.light .due-text[data-level="hours"]    { --due-ink: #3f8a28; }
html.light .due-text[data-level="soon"]     { --due-ink: #9a6f09; }
html.light .due-text[data-level="vsoon"]    { --due-ink: #b3630a; }
html.light .due-text[data-level="now"]      { --due-ink: #c0530a; }
html.light .due-text[data-level="critical"] { --due-ink: #c81e43; }
html.light .due-text[data-level="tomorrow"] { --due-ink: #2f6fd6; }

.wrap {
  position: relative; z-index: 1; width: 100%; max-width: var(--wrapmax); margin: 0 auto;
  flex: 1; min-height: 0;
  overflow-y: auto; overflow-x: hidden;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  /* clears the floating layer, whose real height JS writes to --topfloat-h */
  padding: var(--topfloat-h) 20px calc(var(--si-b) + 24px);
}
.wrap::-webkit-scrollbar { display: none; }

.topbar {
  /* Above the action bar (z-1): the header and the bar are equal-z siblings of
     .topfloat, and the bar paints later, so a menu living inside the header
     could never rise above the bar no matter its own z-index -- its stacking
     context is the header's. Lifting the whole header clears its dropdowns. */
  position: relative; z-index: 3; flex: none;
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px;
  width: min(var(--wrapmax), calc(100% - 8px)); max-width: none; margin: 0 auto;
  padding: calc(10px + var(--si-t)) 20px 6px;
  background: transparent;
}
.brand { display: flex; flex-direction: column; gap: 1px; min-width: 0; text-decoration: none; color: inherit; }
.brand-eye {
  font-size: 10px; letter-spacing: .18em; font-weight: 600;
  color: var(--muted); text-transform: uppercase; line-height: 1;
}
.brand-name { font-size: 16px; font-weight: 750; letter-spacing: -.02em; line-height: 1.15; }
.top-actions { display: flex; align-items: center; gap: 8px; position: relative; }

.icon-btn {
  width: 36px; height: 36px; border-radius: 999px;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; color: var(--ink);
  border: 1px solid var(--line-strong);
  cursor: pointer; padding: 0;
  transition: transform var(--dur-fast) var(--ease-spring), background var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
.icon-btn:hover { background: color-mix(in srgb, var(--surface) 70%, transparent); }
.icon-btn:active { transform: scale(.94); }
.icon-btn svg { width: 18px; height: 18px; stroke: currentColor; fill: none; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }

.glyph { position: relative; width: 18px; height: 18px; }
.glyph span {
  position: absolute; left: 2px; right: 2px; height: 1.5px; background: currentColor;
  border-radius: 2px; transition: transform var(--dur-med) var(--ease-out), opacity var(--dur-fast) linear, top var(--dur-med) var(--ease-out);
}
.burger span:nth-child(1) { top: 4px; }
.burger span:nth-child(2) { top: 8.25px; }
.burger span:nth-child(3) { top: 12.5px; }
.icon-btn.open .burger span:nth-child(1) { top: 8.25px; transform: rotate(45deg); }
.icon-btn.open .burger span:nth-child(2) { opacity: 0; }
.icon-btn.open .burger span:nth-child(3) { top: 8.25px; transform: rotate(-45deg); }

.sunmoon { width: 18px; height: 18px; position: relative; }
.sunmoon svg { position: absolute; inset: 0; transition: opacity var(--dur-med) var(--ease-out), transform var(--dur-med) var(--ease-out); }
html.light .sunmoon .moon { opacity: 0; transform: rotate(45deg) scale(.6); }
html:not(.light) .sunmoon .sun { opacity: 0; transform: rotate(-45deg) scale(.6); }

.panel {
  position: relative;
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 22px 22px 20px;
  margin-bottom: 14px;
}
/* LIQUID GLASS rim (share v45): not a top line but a hairline ring around the
   whole edge, pooling a specular highlight toward the light. The border-only
   band is the padding + mask-exclude ring, so nothing paints over content. */
/* Every surface and every control wears the material, not just the panels:
   "all the elements and buttons need reflection and refraction capable liquid
   glass styling, same as /share" (owner, 2026-09-04). The rim is cheap at any
   size -- it is one masked gradient -- so it goes on buttons and pills too. */
.panel, .overlay-card, .nav, .actionbar, .toast, .tweet, .mcard, .filerow,
.hist-row, .undo-row, .undo-box summary, .doc-frame, .btn, .pill, .tag,
.wx-menu { position: relative; }
details.skipped summary { position: relative; }
.panel::after, .overlay-card::after, .nav::after, .actionbar::after, .toast::after, .tweet::after, .mcard::after, .filerow::after,
.hist-row::after, .undo-row::after, .undo-box summary::after, .doc-frame::after, .btn::after, .pill::after, .tag::after,
.wx-menu::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  pointer-events: none; padding: 1px;
  background:
    radial-gradient(150% 130% at calc(var(--lg-x) * 100%) calc(var(--lg-y) * 100%), var(--lg-tint) 0%, transparent 46%),
    linear-gradient(180deg, rgba(255,255,255,.16), transparent 32%);
  opacity: calc(.5 + .5 * var(--lg-intensity));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  transition: opacity var(--dur-med) var(--ease-out);
}
/* On a light panel a white sheen is nothing, so the light rim leans on a faint
   dark hairline for definition plus the same light-pooled highlight. */
html.light :is(.panel, .overlay-card, .nav, .actionbar, .toast, .tweet, .mcard, .filerow, .hist-row, .undo-row, .undo-box summary, .doc-frame, .btn, .pill, .tag, .wx-menu)::after {
  background:
    radial-gradient(150% 130% at calc(var(--lg-x) * 100%) calc(var(--lg-y) * 100%), var(--lg-tint) 0%, transparent 42%),
    linear-gradient(180deg, rgba(255,255,255,.55), transparent 24%),
    linear-gradient(0deg, rgba(16,20,30,.12), rgba(16,20,30,.12));
  opacity: calc(.42 + .42 * var(--lg-intensity));
}

/* The refract half (share v45): the edge borrows the displacement filter
   through backdrop-filter, so the background bends as it passes the rim and the
   centre is untouched. Large surfaces only -- a url() backdrop-filter behind
   every pill costs far more than it shows -- and it steps aside for
   reduced-motion. Where backdrop-filter cannot take a url() it contributes
   nothing and the specular rim carries the look alone. */
@media (prefers-reduced-motion: no-preference) {
  .panel::before, .overlay-card::before, .nav::before, .actionbar::before {
    content: ""; position: absolute; inset: 0; border-radius: inherit;
    pointer-events: none; padding: 5px;
    -webkit-backdrop-filter: blur(.5px) url(#lg-refract);
            backdrop-filter: blur(.5px) url(#lg-refract);
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
            mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor; mask-composite: exclude;
  }
  html.no-motion .panel::before, html.no-motion .overlay-card::before,
  html.no-motion .nav::before,
  html.no-motion .actionbar::before { display: none; }
}

.kicker {
  font-size: 11px; font-weight: 650; letter-spacing: .08em; text-transform: uppercase;
  color: var(--muted); margin: 0 0 6px;
}
h2.panel-title { margin: 0 0 6px; font-size: 20px; letter-spacing: -.025em; font-weight: 800; }
.lede { margin: 0 0 16px; color: var(--muted); font-size: 14px; line-height: 1.45; }
.lede a { color: var(--accent); text-decoration: none; font-weight: 600; }
.lede a:hover { text-decoration: underline; }

.drop {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 8px; min-height: 168px; padding: 24px 16px; text-align: center; cursor: pointer;
  border: 1.5px dashed var(--line-strong); border-radius: var(--radius);
  background: color-mix(in srgb, var(--surface-2) 55%, transparent);
  transition: border-color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
}
.drop:hover, .drop.over { border-color: var(--accent); background: var(--accent-dim); transform: translateY(-1px); }
.drop svg { width: 28px; height: 28px; color: var(--accent); }
.drop strong { font-weight: 650; }
.drop span { font-size: 12px; color: var(--muted); }
.file-chip { display: none; margin-top: 12px; font-size: 13px; font-weight: 600; color: var(--accent); }
.file-chip.on { display: block; }

.row-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
.btn {
  appearance: none; cursor: pointer;
  white-space: nowrap;
  -webkit-user-select: none; user-select: none;
  -webkit-touch-callout: none;
  height: 36px; padding: 0 14px; border-radius: 999px;
  font-weight: 600; font-size: 13px; line-height: 1; font-family: inherit; letter-spacing: -.01em; color: var(--ink);
  background: var(--surface-2); border: 1px solid var(--line-strong);
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  transition: transform var(--dur-fast) var(--ease-spring), background var(--dur-fast) var(--ease-out);
}
.btn:hover { background: color-mix(in srgb, var(--surface-2) 70%, var(--ink) 8%); }
.btn:active { transform: scale(.97); }
.btn.primary { background: var(--accent); color: var(--accent-ink); border-color: transparent; }
.btn.primary:hover { filter: brightness(1.06); }
.btn.ghost { background: transparent; }
/* Irreversible, so it should not look like the two resets above it. */
.btn.danger { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 45%, var(--line-strong)); }
.btn.danger:hover { background: color-mix(in srgb, var(--danger) 12%, transparent); }
.btn.danger[data-step="1"] { background: var(--danger); color: #fff; border-color: transparent; }
.btn svg { width: 15px; height: 15px; }
.btn.fixed { min-width: 132px; }

.section-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  margin-bottom: 12px;
}
.section-head h3 { margin: 0; font-size: 15px; font-weight: 750; letter-spacing: -.01em; }
.count { font-size: 12px; color: var(--muted); font-weight: 550; font-variant-numeric: tabular-nums; }
/* Was "3 / 3 . over the usual cap", which wrapped off a narrow phone. The count
   is now the warning, so it survives at any width. */
.count.over {
  color: var(--warn); background: var(--warn-dim);
  border: 1px solid color-mix(in srgb, var(--warn) 35%, transparent);
  padding: 3px 8px; border-radius: 999px; white-space: nowrap;
}
.section-head { flex-wrap: wrap; }

/* Step 1 stops competing once the file is in. */
.panel.done .kicker { color: var(--accent); display: flex; align-items: center; gap: 6px; }
.panel.done .kicker::before {
  content: ""; width: 9px; height: 5px; flex: none;
  border-left: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(-45deg); margin-top: -3px;
}
.panel.done .drop { min-height: 108px; opacity: .7; }
.panel.done .drop:hover { opacity: 1; }

.cat-box { margin-bottom: 18px; }
.cat-box:last-child { margin-bottom: 0; }

.tweet {
  position: relative;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 14px 14px 12px;
  margin-bottom: 8px;
  transition: border-color var(--dur-fast) var(--ease-out), transform var(--dur-slow) var(--ease-out), box-shadow var(--dur-med) var(--ease-out);
}
/* When an account has a picture, it tints its cards: the image blurred behind a
   scrim, the content and the glass rim on top. Per account, from the image
   already stored on the device -- no network. */
.tweet.has-bg { overflow: hidden; background: color-mix(in srgb, var(--surface-2) 66%, transparent); }
/* Only the content sits above the backdrop; the absolutely-positioned remove
   button must keep its own positioning (a bare `> *` rule turned it relative and
   dropped it into the top-left of the card). */
.tweet.has-bg > *:not(.tw-remove) { position: relative; z-index: 1; }
.tweet.has-bg > .tw-remove { z-index: 2; }
.tweet.has-bg::before {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  /* scrim on top of the blurred photo, in one layer so the rim ::after stays
     the rim; the flat gradient is unaffected by the blur. */
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--surface-2) 42%, transparent), color-mix(in srgb, var(--surface-2) 72%, transparent)),
    var(--card-bg);
  background-size: cover, cover; background-position: center, center;
  filter: blur(16px) saturate(1.12); transform: scale(1.18); opacity: .5;
}
html.light .tweet.has-bg::before { opacity: .4; }
.tweet.auto { border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.tweet.over { border-color: color-mix(in srgb, var(--warn) 55%, var(--line)); }
.tweet.flash { box-shadow: 0 0 0 2px var(--accent); animation: flashin var(--dur-slow) var(--ease-out); }
@keyframes flashin {
  from { transform: translateY(6px); opacity: .4; }
  to { transform: none; opacity: 1; }
}

/* Shaped like /tweet's post preview: avatar beside a single column holding the
   head line and the body. */
.tw-row { display: flex; gap: 12px; align-items: flex-start; }
.tw-main { flex: 1 1 auto; min-width: 0; }
.tw-head { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; padding-right: 26px; }
.tweet-handle { font-weight: 700; font-size: 15px; }
.body { margin: 3px 0 0; font-size: 15px; line-height: 1.45; color: color-mix(in srgb, var(--ink) 88%, var(--muted)); }

.avatar {
  /* aspect-ratio + overflow keep it a true circle and clip the photo to it, so
     a non-square source (or any flex pressure) can never leave a rectangular
     inset or squash the circle into an oval. */
  width: 40px; height: 40px; aspect-ratio: 1 / 1; overflow: hidden;
  border-radius: 50%; flex: none;
  display: flex; align-items: center; justify-content: center;
  background-color: var(--tint-bg); color: var(--tint-ink); font-weight: 700; font-size: 15px;
  border: 1px solid transparent; padding: 0; cursor: pointer;
  background-size: cover; background-position: center; background-repeat: no-repeat;
  -webkit-user-select: none; user-select: none;
  transition: transform var(--dur-fast) var(--ease-spring), box-shadow var(--dur-fast) var(--ease-out);
}
.avatar:hover { transform: scale(1.04); }
.avatar:active { transform: scale(.96); }
/* A dashed ring on hover/focus says "this takes a picture" without shouting it
   on every card at rest. Once an image is set, the letter steps out of the way. */
.avatar:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--canvas), 0 0 0 4px var(--accent); }
.avatar.has-img .avatar-let { display: none; }
.avatar.has-img { color: transparent; }
/* Six fixed tints, picked from the handle. Nearly every card is @NYPDnews, so a
   uniform grey initial carried no information; this makes the poster scannable. */
.avatar[data-tint="0"] { --tint-bg: hsl(174 44% 90%); --tint-ink: hsl(174 62% 24%); }
.avatar[data-tint="1"] { --tint-bg: hsl(212 52% 91%); --tint-ink: hsl(212 68% 34%); }
.avatar[data-tint="2"] { --tint-bg: hsl(268 44% 92%); --tint-ink: hsl(268 52% 42%); }
.avatar[data-tint="3"] { --tint-bg: hsl(334 52% 93%); --tint-ink: hsl(334 58% 40%); }
.avatar[data-tint="4"] { --tint-bg: hsl(28 62% 90%); --tint-ink: hsl(28 68% 32%); }
.avatar[data-tint="5"] { --tint-bg: hsl(142 38% 90%); --tint-ink: hsl(142 52% 26%); }
html:not(.light) .avatar[data-tint="0"] { --tint-bg: hsl(174 42% 16%); --tint-ink: hsl(174 60% 68%); }
html:not(.light) .avatar[data-tint="1"] { --tint-bg: hsl(212 46% 18%); --tint-ink: hsl(212 78% 74%); }
html:not(.light) .avatar[data-tint="2"] { --tint-bg: hsl(268 38% 20%); --tint-ink: hsl(268 70% 78%); }
html:not(.light) .avatar[data-tint="3"] { --tint-bg: hsl(334 40% 19%); --tint-ink: hsl(334 72% 76%); }
html:not(.light) .avatar[data-tint="4"] { --tint-bg: hsl(28 46% 18%); --tint-ink: hsl(28 76% 70%); }
html:not(.light) .avatar[data-tint="5"] { --tint-bg: hsl(142 36% 16%); --tint-ink: hsl(142 52% 66%); }

/* Removing a tweet is a different act from choosing its section, so it is the
   card's own control rather than a sixth pill competing with the five. */
.tw-remove {
  position: absolute; top: 8px; right: 8px;
  width: 30px; height: 30px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; border: 1px solid transparent; color: var(--muted);
  cursor: pointer; padding: 0;
  transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
.tw-remove svg { width: 15px; height: 15px; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; }
.tw-remove:hover { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 40%, transparent); background: color-mix(in srgb, var(--danger) 10%, transparent); }

.badge {
  font-size: 10px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  padding: 3px 7px; border-radius: 6px; border: 1px solid var(--line);
  color: var(--accent); background: var(--accent-dim);
}
.badge.warn { color: var(--warn); background: var(--warn-dim); border-color: transparent; }

.pills { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; }
.pill {
  appearance: none; border: 1px solid var(--line-strong); background: transparent;
  color: var(--muted); padding: 7px 10px; border-radius: 999px; cursor: pointer;
  display: inline-flex; align-items: center;
  font-weight: 600; font-size: 11px; line-height: 1; font-family: inherit;
  transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-spring);
}
.pill:active { transform: scale(.94); }
/* Selection was carried by colour alone. The drawn check gives it a second,
   non-colour channel and is the thing that morphs in when a card is moved. */
.pill::before {
  content: ""; flex: none;
  width: 0; height: 0; margin: -2px 0 0 0;
  border: 0 solid currentColor; border-radius: 1px;
  transform: rotate(-45deg) scale(.3); opacity: 0;
  transition: width var(--dur-med) var(--ease-spring), height var(--dur-med) var(--ease-spring),
              margin var(--dur-med) var(--ease-spring), opacity var(--dur-fast) var(--ease-out),
              transform var(--dur-med) var(--ease-spring);
}
.pill.on::before {
  width: 9px; height: 5px;
  border-left-width: 2px; border-bottom-width: 2px;
  margin: -2px 6px 0 0;
  transform: rotate(-45deg) scale(1); opacity: 1;
}
.pill.on { background: var(--accent); color: var(--accent-ink); border-color: transparent; }
/* Applied after insertion, so only the pill actually clicked pops. The list is
   re-rendered wholesale, so a plain state transition would never fire. */
.pill.just { animation: pillpop var(--dur-slow) var(--ease-spring); }
@keyframes pillpop {
  0% { transform: scale(.86); }
  55% { transform: scale(1.08); }
  100% { transform: scale(1); }
}

/* One row per held-back tweet, the same shape as the undo row, because they are
   the same idea: something is out of the report and here is the way back. */
.slot {
  border: 1px dashed var(--line-strong); border-radius: var(--radius-sm);
  padding: 12px 14px; margin-bottom: 8px;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  font-size: 13px; color: var(--muted); background: color-mix(in srgb, var(--surface-2) 40%, transparent);
}
.slot.over { border-color: color-mix(in srgb, var(--warn) 40%, var(--line-strong)); }
.slot button {
  background: none; border: 0; color: var(--accent); cursor: pointer; padding: 0; flex: none;
  font-weight: 650; font-size: 13px; font-family: inherit;
}
.slot.over button { color: var(--warn); }

/* Step one, once a file is in. The Hootsuite link stays on screen, because
   fetching today's export is the returning user's first move -- the old bar
   dropped the link entirely and offered only Replace. */
.panel.source { padding-bottom: 18px; }
/* Title then a full-width Hootsuite button, block-stacked. Full width in both
   the empty state and here means the button is the same size in both, and its
   edges line up with the title and the panel -- no half-width button whose text
   floats off the title's left edge. */
.src-head { margin-bottom: 12px; }
.src-head .panel-title { margin: 0 0 12px; }
.btn.hoot { width: 100%; height: 42px; padding: 0 18px; font-size: 14px; }
#upload-panel .btn.hoot { margin-bottom: 16px; }
.filerow {
  display: flex; align-items: center; gap: 10px; margin-top: 14px;
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--radius-sm); padding: 10px 10px 10px 14px;
}
.fb-ic { flex: none; width: 20px; height: 20px; color: var(--accent); }
.fb-ic svg { width: 20px; height: 20px; }
.fb-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.fb-name { font-size: 13px; font-weight: 650; overflow-wrap: anywhere; }
.fb-meta { font-size: 12px; color: var(--muted); }
.filerow .btn { flex: none; height: 32px; padding: 0 12px; }
#fb-remove { flex: none; width: 32px; height: 32px; }

/* One collapsed row for a section's removals, not a stack of identical ones.
   The lines inside are what tells you which tweet you are bringing back. */
.undo-box, .over-box { margin-bottom: 10px; }
.over-box summary { color: var(--warn); }
.over-box .undo-body { padding-top: 8px; }
.undo-box summary, .over-box summary {
  cursor: pointer; list-style: none;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 10px 14px; border-radius: var(--radius-sm);
  background: var(--surface-2); border: 1px solid var(--line);
  font-size: 13px; font-weight: 600; color: var(--muted);
}
.undo-box summary::-webkit-details-marker, .over-box summary::-webkit-details-marker { display: none; }
.undo-box summary:hover, .over-box summary:hover { border-color: var(--line-strong); }
.undo-body, .over-body { display: flex; flex-direction: column; gap: 6px; padding: 8px 0 2px; }
.undo-row {
  display: flex; align-items: center; gap: 10px; min-width: 0;
  padding: 8px 10px 8px 12px; border-radius: var(--radius-sm);
  border: 1px solid var(--line);
}
.undo-h { flex: none; font-size: 12.5px; font-weight: 650; color: var(--accent); }
.undo-t {
  flex: 1 1 auto; min-width: 0; font-size: 12.5px; color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.undo-row .btn { flex: none; height: 30px; padding: 0 12px; font-size: 12px; }

details.skipped { border-top: 1px solid var(--line); padding-top: 14px; margin-top: 8px; }
details.skipped summary {
  cursor: pointer; list-style: none; display: flex; justify-content: space-between; align-items: center;
  font-weight: 650; font-size: 15px;
}
details.skipped summary::-webkit-details-marker { display: none; }
details.skipped .skipped-body { margin-top: 12px; }

.drop-alt { display:block; margin-top:6px; font-size:12px; color:var(--muted); opacity:.85; }
.empty { font-size: 13px; color: var(--muted); font-style: italic; padding: 4px 0 8px; }
.body.empty-body { color: var(--muted); font-style: italic; }

.doc-frame { border: 1px solid var(--line); border-radius: var(--radius-sm); overflow: hidden; background: var(--surface-2); }
.doc {
  padding: 20px 22px;
  font-family: Calibri, Cambria, "Segoe UI", Arial, sans-serif;
  font-size: 11pt; line-height: 1.15; color: var(--ink);
}
.doc a { color: var(--x-blue); }
html.light .doc { background: #fff; color: #000; }

/* Manual mode: the same sections, one card per entry, two fields. */
.mcard {
  position: relative;
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 14px 44px 14px 14px; margin-bottom: 10px;
}
.mcard .field { margin-bottom: 10px; }
.mcard .field:last-child { margin-bottom: 0; }
.mcard textarea { resize: vertical; min-height: 64px; }
.m-read {
  margin: 6px 0 0; font-size: 12px; color: var(--muted);
  overflow-wrap: anywhere;
}
.mcard input:not(:placeholder-shown) + .m-read { color: var(--accent); font-weight: 600; }
.add-entry { width: 100%; }
.hist { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
.hist-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 12px 14px; border-radius: var(--radius-sm);
  background: var(--surface-2); border: 1px solid var(--line);
}
.hist-row strong { font-size: 13px; }

.nav {
  position: absolute; top: calc(100% + 8px); right: 0;
  width: min(280px, calc(100vw - 24px));
  /* Expanding Other Tools can outgrow the screen; the menu scrolls inside
     itself instead of running off the bottom. */
  max-height: calc(100dvh - var(--si-t) - 88px);
  overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
  background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: 12px; padding: 6px; z-index: 50;
  box-shadow: 0 18px 40px rgba(0,0,0,.35);
  visibility: hidden; opacity: 0; transform: translateY(-6px);
  transition: opacity var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out), visibility var(--dur-fast);
}
.nav.open { visibility: visible; opacity: 1; transform: none; }
.nav-toggle-item { justify-content: flex-start; }
.nav-switch {
  flex: none; margin-left: auto; width: 34px; height: 20px; border-radius: 999px;
  background: var(--line-strong); position: relative;
  transition: background var(--dur-fast) var(--ease-out);
}
.nav-switch::after {
  content: ""; position: absolute; top: 2px; left: 2px; width: 16px; height: 16px;
  border-radius: 50%; background: #fff;
  transition: transform var(--dur-fast) var(--ease-spring);
}
.nav-toggle-item[aria-checked="true"] .nav-switch { background: var(--accent); }
.nav-toggle-item[aria-checked="true"] .nav-switch::after { transform: translateX(14px); }
.nav-item, .nav-fold {
  display: flex; align-items: center; gap: 10px;
  width: 100%; text-align: left; background: transparent; border: 0; color: var(--ink);
  padding: 10px; border-radius: 8px; font-weight: 550; font-size: 14px; font-family: inherit; cursor: pointer; text-decoration: none;
}
.nav-item:hover, .nav-fold:hover { background: var(--surface-2); }
/* Icon rail: the family menus lead every action with a glyph, and the label
   carries the remaining width so badges sit hard right. */
.nav-item-ic { flex: none; width: 18px; height: 18px; display: inline-flex; color: var(--muted); }
.nav-item-ic svg { width: 18px; height: 18px; stroke: currentColor; fill: none; }
.nav-item:hover .nav-item-ic { color: var(--accent); }
.nav-item-label { flex: 1 1 auto; min-width: 0; }
.nav-badge {
  flex: none; font-size: 10px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  padding: 3px 7px; border-radius: 999px; border: 1px solid var(--line); color: var(--muted);
}
.nav-badge.badge-active { color: var(--accent); background: var(--accent-dim); border-color: transparent; }
.nav-all { margin-top: 6px; padding-top: 12px; border-top: 1px solid var(--line); border-radius: 0; }
.nav-fold {
  font-weight: 650; font-size: 10px; line-height: 1; font-family: inherit; letter-spacing: .14em; text-transform: uppercase;
  color: var(--muted); margin-top: 6px; padding: 10px;
}
.nav-fold-label { flex: 1 1 auto; }
.nav-item.soon { opacity: .55; }
.nav-item.soon.denied { animation: shake .4s var(--ease-out); }
@keyframes shake {
  0%,100% { transform: none; }
  25% { transform: translateX(-4px); }
  75% { transform: translateX(4px); }
}
.nav-sub { padding: 2px 0 6px 6px; }
.nav-label {
  font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: var(--muted);
  padding: 8px 10px 4px; font-weight: 650;
}
.chev { transition: transform var(--dur-fast) var(--ease-out); }
.nav-fold[aria-expanded="true"] .chev { transform: rotate(90deg); }

.overlay {
  position: fixed; inset: 0; z-index: 80;
  display: flex; align-items: flex-end; justify-content: center;
  background: rgba(0,0,0,.45);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  visibility: hidden; opacity: 0;
  transition: opacity var(--dur-med) var(--ease-out), visibility var(--dur-med);
}
.overlay.open { visibility: visible; opacity: 1; }
.overlay-card {
  position: relative;
  width: min(420px, 100%); max-height: min(88dvh, 720px);
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line-strong);
  border-radius: 18px 18px 0 0;
  padding: 10px 18px calc(18px + var(--si-b));
  overflow: hidden; display: flex; flex-direction: column;
  transform: translateY(18px);
  transition: transform var(--dur-med) var(--ease-out);
}
.overlay.open .overlay-card { transform: none; }
.overlay-card.dragging { transition: none; }
.handle { width: 36px; height: 4px; border-radius: 4px; background: var(--line-strong); margin: 4px auto 10px; }
.overlay-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.overlay-head h2 { margin: 0; font-size: 20px; font-weight: 800; letter-spacing: -.02em; }
.overlay-inner {
  overflow: auto; overscroll-behavior: contain; padding-bottom: 8px;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.overlay-inner::-webkit-scrollbar { display: none; }
.field { margin: 0 0 14px; }
.field label { display: block; font-size: 12px; font-weight: 650; margin-bottom: 6px; }
.field input[type="text"], .field input[type="url"], .field input[type="number"], .field textarea {
  width: 100%; background: var(--surface-2); color: var(--ink);
  border: 1px solid var(--line-strong); border-radius: 10px;
  padding: 10px 12px; font-weight: 400; font-size: 16px; font-family: inherit; outline: none;
}
/* Keyword lists run 3-4 lines; 64px clipped every one of them mid-line. */
.field textarea { min-height: 96px; resize: vertical; line-height: 1.5; }
.hint { font-size: 12px; color: var(--muted); margin: 0 0 12px; line-height: 1.45; }
.sample-hint { margin-top: 14px; }

/* Privacy as promises: a glyph, a claim in the accent, then the detail.
   Same shape as Tweet Draft and Mortgage. */
.privacy-body { display: flex; flex-direction: column; gap: 16px; margin-bottom: 16px; }
.pv-row { display: flex; gap: 12px; align-items: flex-start; }
.pv-ic { flex: none; width: 20px; height: 20px; color: var(--accent); margin-top: 1px; }
.pv-ic svg { width: 20px; height: 20px; }
.pv-row p { margin: 0; font-size: 13px; line-height: 1.55; color: var(--muted); }
.pv-row strong { color: var(--accent); font-weight: 650; }

.faq-row { padding: 14px 0; }
.faq-row + .faq-row { border-top: 1px solid var(--line); }
.faq-row h3 { margin: 0 0 5px; font-size: 14px; font-weight: 650; letter-spacing: -.01em; }
.faq-row p { margin: 0; font-size: 13px; line-height: 1.55; color: var(--muted); }
.faq-row em { font-style: normal; color: var(--accent); font-weight: 600; }

.steps { margin: 14px 0 0; padding-left: 20px; }
.steps li { font-size: 13px; line-height: 1.6; color: var(--muted); margin-bottom: 6px; }
.steps strong { color: var(--ink); font-weight: 650; }

.seg { display: flex; gap: 4px; background: var(--surface-2); padding: 4px; border-radius: 999px; }
.seg button {
  flex: 1; border: 0; background: transparent; color: var(--muted);
  height: 32px; border-radius: 999px; font-weight: 650; font-size: 12px; font-family: inherit; cursor: pointer;
}
.seg button.sel { background: var(--surface); color: var(--ink); }

/* The .sel ring is a 2px outward box-shadow and the row sits flush against
   .overlay-inner, which scrolls -- so the ring on the first swatch was being
   clipped. The padding gives every ring room on all four sides. */
.swatches { display: flex; flex-wrap: wrap; gap: 8px; padding: 3px; }
.swatch { width: 28px; height: 28px; border-radius: 50%; border: 2px solid transparent; cursor: pointer; padding: 0; }
.swatch.sel { box-shadow: 0 0 0 2px var(--ink); }

.switch {
  width: 44px; height: 26px; border-radius: 999px; border: 0; padding: 0; cursor: pointer;
  background: var(--line-strong); position: relative;
  transition: background var(--dur-fast) var(--ease-out);
}
/* The track carries the state; the knob stays white in both states, as in the
   family sheets. Tying the knob to --ink made "off" read as a black dot. */
.switch::after {
  content: ""; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px; border-radius: 50%;
  background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,.28);
  transition: transform var(--dur-med) var(--ease-spring);
}
.switch.on { background: var(--accent); }
.switch.on::after { transform: translateX(18px); }
.switch-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 0 0 14px; }
.switch-row span { font-size: 14px; font-weight: 600; }

/* Settings sheet, shaped like Tweet Draft and Mortgage: a labelled group per
   decision, and every switch carries a line saying what it actually does. */
.set-group { margin: 0 0 22px; }
.set-group:last-child { margin-bottom: 0; }
.set-label {
  font-size: 10px; font-weight: 650; letter-spacing: .14em; text-transform: uppercase;
  color: var(--muted); margin-bottom: 10px;
}
.row-toggle {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 14px;
  padding: 10px 0;
}
.row-toggle + .row-toggle { border-top: 1px solid var(--line); }
.rt-copy { min-width: 0; }
.rt-text { font-size: 14px; font-weight: 600; }
.rt-sub { font-size: 12px; color: var(--muted); line-height: 1.45; margin: 3px 0 0; }
.row-toggle .switch { flex: none; margin-top: 2px; }
.field .rt-sub { margin-top: 6px; }

.reset-row { padding: 10px 0; }
.reset-row + .reset-row { border-top: 1px solid var(--line); }
.reset-row .btn { width: 100%; justify-content: flex-start; }
.reset-row .rt-sub { margin-top: 6px; }

.set-link {
  display: flex; align-items: center; gap: 10px; width: 100%;
  background: transparent; border: 1px solid var(--line-strong); color: var(--ink);
  padding: 12px; border-radius: var(--radius-sm); cursor: pointer;
  font-weight: 600; font-size: 14px; font-family: inherit; text-align: left;
  transition: background var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
.set-link:hover { background: var(--surface-2); border-color: var(--accent); }
.set-link svg { width: 16px; height: 16px; flex: none; color: var(--accent); }

/* A phone tray is 420 because that is the phone. A desktop sheet has no reason
   to be, and the keyword lists in particular want the room. */
@media (min-width: 720px) {
  .overlay { align-items: center; }
  .overlay-card { width: min(560px, 100%); border-radius: 16px; transform: translateY(10px) scale(.98); }
  .overlay.open .overlay-card { transform: none; }
  .handle { display: none; }
}

/* Keyword rows in Settings, and the tray they open. */
/* Reset confirms live in the row they belong to. */
.reset-confirm { padding: 4px 0 2px; }
.rc-q { margin: 0 0 10px; font-size: 13px; line-height: 1.55; color: var(--ink); }
.rc-list { margin: 0 0 12px; padding-left: 18px; }
.rc-list li { font-size: 13px; line-height: 1.6; color: var(--muted); }
.rc-gate { margin: 0 0 12px; }
.rc-gate label { display: block; font-size: 12px; font-weight: 650; margin-bottom: 6px; }
.rc-gate input {
  width: 100%; background: var(--surface-2); color: var(--ink);
  border: 1px solid var(--line-strong); border-radius: 10px; padding: 10px 12px;
  font-weight: 400; font-size: 16px; font-family: inherit; outline: none;
  text-transform: uppercase; letter-spacing: .12em;
}
.rc-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.rc-yes:disabled { opacity: .45; cursor: not-allowed; }

/* A disclosure says whether it is open by the chevron, not by a verb that goes
   stale the moment you tap it. */
.skipped summary .count { display: inline-flex; align-items: center; gap: 8px; }
.skipped summary .chev, .undo-box summary .chev, .over-box summary .chev {
  width: 8px; height: 8px; flex: none;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translate(-1px, -1px);
  transition: transform var(--dur-fast) var(--ease-out);
}
.skipped[open] summary .chev,
.undo-box[open] summary .chev,
.over-box[open] summary .chev { transform: rotate(-135deg) translate(-2px, -2px); }

/* The destination acknowledges an arrival where it sits, instead of the page
   throwing the reader at it. */
.section-head.bump h3 { animation: headbump 700ms var(--ease-out); }
@keyframes headbump {
  0% { color: var(--ink); }
  22% { color: var(--accent); }
  100% { color: var(--ink); }
}

#kw-hint { margin-bottom: 18px; }
.kw-list { display: flex; flex-direction: column; }
.kw-row { display: flex; align-items: center; gap: 10px; padding: 10px 0; }
.kw-row + .kw-row { border-top: 1px solid var(--line); }
.kw-name { flex: 1 1 auto; min-width: 0; font-size: 14px; font-weight: 600; overflow-wrap: anywhere; }
.kw-count { flex: none; font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }
#cat-add { margin-top: 12px; width: 100%; }
.kw-edit { flex: none; height: 32px; padding: 0 14px; }

.tagbox { display: flex; flex-wrap: wrap; gap: 6px; padding: 2px; margin-bottom: 16px; }
.tag {
  display: inline-flex; align-items: center; gap: 4px;
  background: var(--accent-dim); color: var(--accent);
  border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
  border-radius: 999px; padding: 5px 5px 5px 11px;
  font-size: 13px; font-weight: 600; overflow-wrap: anywhere;
}
.tag button {
  flex: none; width: 18px; height: 18px; border-radius: 50%; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; border: 0; color: inherit; cursor: pointer; opacity: .7;
  transition: opacity var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out);
}
.tag button svg { width: 11px; height: 11px; stroke: currentColor; fill: none; stroke-width: 2.4; stroke-linecap: round; }
.tag button:hover { opacity: 1; background: color-mix(in srgb, var(--accent) 22%, transparent); }

.confirm-list { margin: 0 0 14px; padding-left: 18px; }
.confirm-list li { font-size: 13px; line-height: 1.6; color: var(--muted); }
#confirm-yes:disabled { opacity: .45; cursor: not-allowed; }

.hidden { display: none !important; }

.toast {
  position: fixed; left: 50%; bottom: calc(var(--si-b) + 20px);
  transform: translateX(-50%) translateY(8px);
  background: var(--surface); color: var(--ink); border: 1px solid var(--line-strong);
  padding: 8px 14px; border-radius: 999px; font-size: 13px; font-weight: 600;
  z-index: 90; opacity: 0; pointer-events: none;
  transition: opacity var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
}
.toast.on { opacity: 1; transform: translateX(-50%) translateY(0); }

@media (max-width: 520px) {
  body { padding-left: 14px; padding-right: 14px; }
  .panel { padding: 18px 16px 16px; }
  .dock-note { display: none; }
}


/* ---- Weather picker ------------------------------------------------------
   Same dismissal grammar as the Other Tools menu (tap, Escape, tap-outside,
   trigger again), and the two are mutually exclusive. Deliberately opaque:
   picking a season spawns a <canvas>, and a new compositing layer behind a live
   backdrop-filter makes iOS Safari recompute the visual viewport, which reads
   on screen as a sudden zoom-out. */
.wx-btn.on { color: var(--accent); border-color: var(--accent); }
.wx-btn svg { width: 18px; height: 18px; }
.wx-menu {
  position: absolute; top: calc(100% + 8px); right: 0;
  width: min(248px, calc(100vw - 24px));
  background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: 12px; padding: 6px; z-index: 50;
  box-shadow: 0 18px 40px rgba(0,0,0,.35);
  visibility: hidden; opacity: 0; transform: translateY(-6px);
  transition: opacity var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out), visibility var(--dur-fast);
}
.wx-menu.open { visibility: visible; opacity: 1; transform: none; }
.wx-menu-title {
  font-size: 10px; font-weight: 650; letter-spacing: .14em; text-transform: uppercase;
  color: var(--muted); padding: 6px 8px 4px;
}
.wx-menu-sep { height: 1px; background: var(--line); margin: 6px 2px; }
.wx-opt {
  display: flex; align-items: center; gap: 10px; width: 100%;
  background: transparent; border: 0; color: var(--ink); cursor: pointer;
  padding: 9px 8px; border-radius: 8px; text-align: left;
  font-weight: 550; font-size: 14px; font-family: inherit;
  transition: background var(--dur-fast) var(--ease-out);
}
.wx-opt:hover { background: var(--surface-2); }
.wx-opt:active { transform: scale(.98); }
.wx-opt-g { width: 20px; flex: none; color: var(--muted); display: flex; align-items: center; justify-content: center; }
.wx-opt-g svg { width: 18px; height: 18px; }
.wx-opt-t { flex: 1 1 auto; }
.wx-opt.sel, .wx-opt.sel .wx-opt-g { color: var(--accent); }
/* The tick is a drawn mark, not a glyph font or an emoji (house style 3). */
.wx-opt.sel::after {
  content: ""; flex: none; width: 9px; height: 5px; margin-left: auto; margin-top: -3px;
  border-left: 2px solid var(--accent); border-bottom: 2px solid var(--accent);
  transform: rotate(-45deg);
}
.wx-tod { display: grid; grid-template-columns: repeat(3, 1fr); gap: 5px; padding: 2px 2px 4px; }
.chip-btn {
  height: 32px; border-radius: 999px; cursor: pointer;
  background: var(--surface-2); border: 1px solid var(--line-strong); color: var(--muted);
  font-weight: 650; font-size: 12px; font-family: inherit;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
.chip-btn:hover { color: var(--ink); }
.chip-btn.sel { background: var(--accent); color: var(--accent-ink); border-color: transparent; }

/* ============================================================================
   DESKTOP (a real pointer and room to work). The mobile shell is a fixed screen
   with one bounded scroller -- right for iOS, wrong for a mouse, where the wheel
   only worked over the 44rem column and the ground swallowed it everywhere else.
   Here the whole page scrolls (wheel anywhere), the header and action bar stick,
   and the wider display earns its keep: the Outlook preview docks as a sticky
   right-hand column so you can read the report while you fix the sorting.
   ========================================================================== */
@media (min-width: 940px) {
  :root { --wrapmax: 72rem; }
  html { overflow-y: auto; overflow-x: hidden; }
  html, body { height: auto; min-height: 100dvh; }
  body { overflow: visible; }

  /* The floating layer stays fixed and the same width as the content column, so
     header, action bar and the panels below all share one left and right edge. */
  .wrap {
    display: grid; align-items: start; gap: 18px;
    overflow: visible;
    grid-template-columns: minmax(0, 1fr);
    padding-bottom: 40px;
  }
  body.has-report .wrap { grid-template-columns: minmax(0, 1fr) minmax(320px, 400px); }

  /* Left column, in source order. */
  #upload-panel, #filebar, #triage-section, #manual-section { grid-column: 1; }

  /* The preview rides the right column, always shown once there is a report,
     regardless of the mobile toggle's hidden state. */
  #preview-btn { display: none; }
  /* The docked preview is a bounded flex column, capped to the space between
     the floating layer and the bottom of the viewport. The title and lede take
     their natural height; the doc-frame flexes to fill the rest and scrolls
     inside itself. Budgeting the frame's max-height from the column top was the
     bug -- the frame starts BELOW the title, so it ran off the bottom edge and
     the last lines could not be scrolled to. */
  body.has-report #output-section {
    display: flex !important; flex-direction: column;
    grid-column: 2; grid-row: 1 / span 999;
    position: sticky; top: calc(var(--topfloat-h) + 8px);
    align-self: start; margin-bottom: 0;
    max-height: calc(100dvh - var(--topfloat-h) - 32px);
  }
  body.has-report #output-section .doc-frame {
    flex: 1 1 auto; min-height: 0;
    overflow: auto; scroll-padding-bottom: 40px;
  }
  /* Room after the last line so reaching the end reads as the end, not a
     mid-line clip against the frame edge. */
  body.has-report #output-section .doc { padding-bottom: 40px; }
}
