/* Approvals page. Mobile first (iPhone Home Screen app), light and dark. */
:root {
  --bg: #f2f2f7; --card: #fff; --fg: #1c1c1e; --muted: #6c6c72; --line: #e2e2e7; --soft: #f4f4f7;
  --accent: #0a7a55; --approve: #1e8e3e; --approve-fg: #fff;
  --bad: #c0261c; --bad-bg: #fdebea; --good: #1e7d3a; --good-bg: #e4f4e8; --warn: #8a5a00; --warn-bg: #fdf1d8;
  --grey: #6c6c72; --grey-bg: #ececf0;
  --t-login: #1d4e89; --t-login-bg: #e3edf9; --t-wa: #11683a; --t-wa-bg: #dcf5e5; --t-pay: #8a5300; --t-pay-bg: #fdefd3;
  --t-danger: #a4231a; --t-danger-bg: #fde4e2; --t-deploy: #5b3497; --t-deploy-bg: #eee6fb; --t-config: #3d4a5c; --t-config-bg: #e7ebf1;
  --t-neutral: #4a4a50; --t-neutral-bg: #ececf0; --t-agent: #2f6b1f; --t-agent-bg: #e4f2dc; --t-update: #0b6470; --t-update-bg: #dcf2f4;
  --fab-shadow: 0 4px 14px rgba(0, 0, 0, 0.16);
  --me: #007AFF;
  color-scheme: light dark;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #000; --card: #1c1c1e; --fg: #f2f2f7; --muted: #9a9aa1; --line: #2e2e32; --soft: #242427;
    --accent: #4fd1a1; --approve: #2ea44f; --approve-fg: #fff;
    --bad: #ff8178; --bad-bg: #3a1714; --good: #5ad17a; --good-bg: #12301c; --warn: #f0b84a; --warn-bg: #3a2c0c;
    --grey: #a5a5ac; --grey-bg: #2c2c30;
    --t-login: #9cc4f5; --t-login-bg: #18304d; --t-wa: #7fe0a6; --t-wa-bg: #123823; --t-pay: #f5c46b; --t-pay-bg: #3d2c0d;
    --t-danger: #ff9b92; --t-danger-bg: #431915; --t-deploy: #c8adf5; --t-deploy-bg: #2d2045; --t-config: #c2cad6; --t-config-bg: #2a3038;
    --t-neutral: #c9c9cf; --t-neutral-bg: #2c2c30; --t-agent: #9fdc8a; --t-agent-bg: #1d3316; --t-update: #7dd6e0; --t-update-bg: #12363b;
    --fab-shadow: 0 4px 16px rgba(0, 0, 0, 0.6);
    --me: #0A84FF;
  }
}
* { box-sizing: border-box; }
[hidden] { display: none !important; }
html { -webkit-text-size-adjust: 100%; }
body { margin: 0; background: var(--bg); color: var(--fg); font: 17px/1.45 -apple-system, system-ui, "Segoe UI", Arial, sans-serif; }
main { max-width: 560px; margin: 0 auto; padding: max(12px, env(safe-area-inset-top)) 16px max(28px, env(safe-area-inset-bottom)); }
h1 { font-size: 1.75em; margin: 0; letter-spacing: -0.01em; }
h2 { font-size: 0.8em; margin: 26px 4px 8px; color: var(--muted); font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em;
  display: flex; align-items: center; gap: 8px; }
h3 { font-size: 0.95em; margin: 0 0 8px; }
p { margin: 8px 0; }
a { color: var(--accent); }
.muted { color: var(--muted); }
.small { font-size: 0.85em; }
.center { text-align: center; }
.bad-text { color: var(--bad); }
.empty { color: var(--muted); margin: 4px 4px 8px; }
.count { background: var(--approve); color: var(--approve-fg); border-radius: 999px; padding: 0 8px; font-size: 0.95em; letter-spacing: 0; }

/* header: title left, notifications indicator right */
.top { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 48px; margin-bottom: 6px; }
.back { margin: 0; font-weight: 600; text-decoration: none; }
.icon { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; flex: none; }
button.bell { display: inline-flex; align-items: center; gap: 6px; width: auto; min-height: 40px; margin: 0; padding: 6px 12px 6px 10px;
  border-radius: 999px; font-size: 0.85em; font-weight: 600; }
.bell.on { background: var(--good-bg); color: var(--good); }
.bell.off { background: var(--grey-bg); color: var(--grey); }
.push-panel { margin-top: 0; }
.push-panel .steps { border: 0; padding: 0; margin: 8px 0 0; }

/* user data (reasons, WhatsApp text, names, items) may be Hebrew: each block picks its own direction */
.reason, .action-line, dd, .req-meta span { unicode-bidi: plaintext; overflow-wrap: anywhere; }
.pre { white-space: pre-wrap; }
.wa-to { font-weight: 600; font-size: 0.92em; margin-bottom: 2px; }
.wa-text { white-space: pre-wrap; }
.clamp { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }

.card { display: block; background: var(--card); border: 1px solid var(--line); border-radius: 16px; padding: 14px 16px; margin: 10px 0;
  color: inherit; text-decoration: none; }
a.card:active { background: var(--soft); }

/* the request card */
.card-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.card-right { display: inline-flex; align-items: center; gap: 8px; color: var(--muted); font-size: 0.85em; font-variant-numeric: tabular-nums; white-space: nowrap; }
.chip { display: inline-block; padding: 3px 10px; border-radius: 999px; font-size: 0.78em; font-weight: 700; letter-spacing: 0.01em; }
.chip.tone-login { color: var(--t-login); background: var(--t-login-bg); }
.chip.tone-wa { color: var(--t-wa); background: var(--t-wa-bg); }
.chip.tone-pay { color: var(--t-pay); background: var(--t-pay-bg); }
.chip.tone-danger { color: var(--t-danger); background: var(--t-danger-bg); }
.chip.tone-deploy { color: var(--t-deploy); background: var(--t-deploy-bg); }
.chip.tone-config { color: var(--t-config); background: var(--t-config-bg); }
.chip.tone-neutral { color: var(--t-neutral); background: var(--t-neutral-bg); }
.chip.tone-agent { color: var(--t-agent); background: var(--t-agent-bg); }
.chip.tone-update { color: var(--t-update); background: var(--t-update-bg); }
.reason { font-size: 1.22em; font-weight: 650; line-height: 1.3; margin: 10px 0 6px; }
.reason.none { color: var(--muted); font-weight: 500; font-size: 1em; font-style: italic; }
.history .reason { font-size: 1.05em; margin: 8px 0 4px; }
.action-line { background: var(--soft); border-radius: 10px; padding: 8px 10px; font-size: 0.92em; white-space: pre-wrap; margin: 6px 0 10px; }
.history .action-line { white-space: normal; }

.status-line { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 10px; margin: 8px 0 0; }
.status { font-weight: 650; font-size: 0.92em; }
.status.tone-waiting { color: var(--fg); }
.status.tone-approved { color: var(--good); }
.status.tone-ended { color: var(--grey); }
.status.tone-failed { color: var(--bad); }
.status.tone-late { color: var(--warn); }
.approver { color: var(--muted); font-size: 0.85em; }
.word-ok { color: var(--good); font-weight: 650; }
.word-bad { color: var(--bad); font-weight: 650; }
.countdown { font-variant-numeric: tabular-nums; }

/* label/value grids */
dl.grid { display: grid; grid-template-columns: max-content 1fr; gap: 6px 14px; margin: 0; font-size: 0.92em; }
dl.grid dt { color: var(--muted); }
dl.grid dd { margin: 0; }
dl.grid.nested { font-size: 1em; }
.history dl.grid { font-size: 0.85em; gap: 2px 12px; margin-top: 4px; }
.details { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line); }
.details .group { font-size: 0.75em; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); margin: 12px 0 6px; }
.details .group:first-child { margin-top: 0; }
.lines { margin: 0; padding-inline-start: 20px; }

/* buttons */
button, .btn { display: block; width: 100%; min-height: 50px; margin: 10px 0; padding: 12px 14px; border-radius: 14px; border: 0; font: inherit;
  font-weight: 600; text-align: center; text-decoration: none; cursor: pointer; -webkit-tap-highlight-color: transparent; }
button:disabled { opacity: 0.45; cursor: default; }
.approve { background: var(--approve); color: var(--approve-fg); }
.secondary, .reject { background: var(--soft); color: var(--fg); border: 1px solid var(--line); }
.danger-fill { background: var(--bad); color: #fff; }
/* The card (option A): Approve on its own row, then Reject / Reply / Details, each opening in place under them */
.card.req { container: card / inline-size; }
.approve-row { margin-top: 12px; }
.approve-row .approve { margin: 0; }
.row3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin-top: 8px; }
.row3 button { display: inline-flex; align-items: center; justify-content: center; gap: 6px; margin: 0; min-height: 48px; padding: 8px 10px;
  white-space: nowrap; }
.row3 .icon { width: 20px; height: 20px; flex: none; }
.row3 .reject { background: var(--bad-bg); color: var(--bad); border-color: color-mix(in srgb, var(--bad) 45%, transparent); }
.row3 .reply-open, .row3 .dt { color: var(--accent); }
.row3 .dt[aria-expanded="true"] .icon { transform: rotate(180deg); }
.card-more { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); }
/* Big text (AX5 and up): the labels no longer fit three in a row, so the buttons stack full width and Approve
   sticks to the bottom of the screen while the card is longer than it */
@container card (max-width: 18em) {
  .card-top { flex-wrap: wrap; }
  .card .brief { grid-template-columns: 1fr; row-gap: 2px; }
  .row3 { grid-template-columns: 1fr; }
  .row3 button { justify-content: flex-start; min-height: 56px; padding: 8px 16px; }
  .actions { display: contents; } /* so Approve's sticky range is the whole card, not its own small box */
  .approve-row { position: sticky; bottom: max(8px, env(safe-area-inset-bottom)); z-index: 1; }
}
.actions .note { margin-top: 10px; }
/* Hold Reject (500 ms) to reject with a note: the button fills while held, pops when the sheet opens */
button.holdable { position: relative; overflow: hidden; isolation: isolate; -webkit-touch-callout: none; -webkit-user-select: none;
  user-select: none; touch-action: manipulation; transition: transform 0.12s ease; }
button.holdable::after { content: ""; position: absolute; inset: 0; z-index: -1; background: var(--bad-bg); transform: scaleX(0);
  transform-origin: left center; }
button.holdable.holding { transform: scale(0.96); color: var(--bad); border-color: var(--bad); }
button.holdable.holding::after { transform: scaleX(1); transition: transform 0.5s linear; }
button.holdable.held { animation: held-pop 0.26s ease-out; }
@keyframes held-pop { 0% { transform: scale(0.96); } 45% { transform: scale(1.05); } 100% { transform: scale(1); } }
@media (prefers-reduced-motion: reduce) {
  button.holdable, button.holdable.holding::after { transition: none; }
  button.holdable.held { animation: none; }
}
.sheet-backdrop { position: fixed; inset: 0; z-index: 40; background: rgba(0, 0, 0, 0.35); animation: fade-in 0.18s ease-out; }
.sheet { position: fixed; z-index: 41; left: 0; right: 0; bottom: 0; max-width: 560px; margin: 0 auto; background: var(--card);
  border-radius: 18px 18px 0 0; box-shadow: 0 -6px 24px rgba(0, 0, 0, 0.18);
  padding: 8px calc(16px + env(safe-area-inset-right)) calc(12px + env(safe-area-inset-bottom)) calc(16px + env(safe-area-inset-left));
  animation: sheet-up 0.22s ease-out; }
.sheet-grab { width: 40px; height: 5px; border-radius: 3px; background: var(--line); margin: 0 auto 10px; }
.sheet-title { margin: 0; font-size: 1.05em; }
.sheet-sub { margin: 2px 0 10px; unicode-bidi: plaintext; overflow-wrap: anywhere; display: -webkit-box; -webkit-line-clamp: 1;
  -webkit-box-orient: vertical; overflow: hidden; }
.sheet .reply-input { min-height: 72px; }
.sheet .note { margin: 8px 0 0; }
button.sheet-cancel { display: block; margin: 6px auto 0; padding: 8px 16px; }
body.sheet-on { overflow: hidden; }
@keyframes sheet-up { from { transform: translateY(100%); } to { transform: translateY(0); } }
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-color-scheme: dark) { button.sheet-send { background: #d0362b; } .sheet-backdrop { background: rgba(0, 0, 0, 0.6); } .sheet { box-shadow: 0 -6px 24px rgba(0, 0, 0, 0.7); } }
/* Reply: a note back to the requester; the request stays pending */
button.reply-open { min-height: 44px; font-weight: 600; }
.reply-form { margin-top: 10px; }
textarea.reply-input { display: block; width: 100%; min-height: 84px; padding: 10px 12px; border-radius: 12px; border: 1px solid var(--line);
  background: var(--soft); color: var(--fg); font: inherit; resize: vertical; unicode-bidi: plaintext; }
/* the mic in the box's bottom-right corner (also for Hebrew, so the text stops before it on the right either way) */
.reply-field { position: relative; }
.reply-field textarea.reply-input { min-height: 104px; padding-right: 64px; }
.reply-field button.mic { position: absolute; right: 8px; bottom: 8px; width: 48px; height: 48px; min-height: 0; margin: 0; border-radius: 50%; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12); }
textarea.reply-input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.reply-controls { display: grid; grid-template-columns: 2fr 3fr; gap: 10px; margin-top: 10px; }
.reply-controls button { margin: 0; }
button.send { background: var(--soft); color: var(--accent); border: 1px solid var(--accent); }
button.mic { display: grid; place-items: center; padding: 0; background: var(--soft); color: var(--fg); border: 1px solid var(--line); }
button.mic.live { background: var(--bad); color: #fff; border-color: var(--bad); }
/* The thread: his replies (inline end, iMessage blue, white text) and the agent's answers (inline start, soft).
   White on #007AFF is 4.0:1 and on #0A84FF 3.7:1, under the 4.5:1 body-text bar; iMessage uses the same. */
.thread { display: flex; flex-direction: column; gap: 6px; margin: 10px 0 0; }
/* Home: about the last 2 messages; scrolls inside, the page still scrolls past it (no overscroll-behavior: contain). */
.thread.last .msg-text { display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; }
.thread-earlier { margin: 0; }
.thread.capped { max-height: 240px; overflow-y: auto; -webkit-overflow-scrolling: touch; }
.thread.capped.more { -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 36px); mask-image: linear-gradient(to bottom, transparent 0, #000 36px); }
.msg { max-width: 86%; border-radius: 14px; padding: 6px 10px; }
.msg.mine { align-self: flex-end; padding: 0; text-align: end; }
.msg.mine .msg-text { background: var(--me); color: #fff; padding: 6px 10px; border-radius: 14px; border-end-end-radius: 4px; text-align: start; }
/* his bubble keeps its bottom padding as a border, so the clamp never shows a fifth line's top */
.thread.last .msg.mine .msg-text { padding-bottom: 0; border-bottom: 6px solid var(--me); }
.msg.agent { align-self: flex-start; background: var(--soft); border-end-start-radius: 4px; }
.msg-text { margin: 0; white-space: pre-wrap; unicode-bidi: plaintext; overflow-wrap: anywhere; font-size: 0.94em; }
.msg-meta { display: block; color: var(--muted); font-size: 0.74em; margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
/* the agent started on his reply: a small status line in the Hub's success green, not a button, not the bubble blue */
.msg-meta.working { color: var(--good); font-weight: 600; }
.msg-meta.warn { color: var(--warn); font-weight: 600; }
.withdrawn-why { margin: 4px 0 0; color: var(--muted); unicode-bidi: plaintext; }
.linklike { display: inline-block; width: auto; min-height: 40px; margin: 4px 0 0; padding: 8px 0; background: none; color: var(--accent);
  font-weight: 500; font-size: 0.9em; text-align: left; }
button.older { background: none; color: var(--accent); min-height: 44px; margin: 4px 0; font-size: 0.95em; }
.link { display: inline-block; margin: 10px 0; }

.strip { display: block; padding: 10px 14px; border-radius: 12px; font-weight: 600; text-decoration: none; margin: 0 0 8px; }
.strip.good { background: var(--good-bg); color: var(--good); }
.strip.bad { background: var(--bad-bg); color: var(--bad); }
.note { padding: 10px 12px; border-radius: 12px; background: var(--card); border: 1px solid var(--line); }
.note.bad { background: var(--bad-bg); color: var(--bad); border-color: transparent; }
.note.warn { background: var(--warn-bg); color: var(--warn); border-color: transparent; }
.note.good { background: var(--good-bg); color: var(--good); border-color: transparent; }

.device { margin-top: 26px; }
.steps ol { margin: 8px 0 0; padding-inline-start: 22px; }
.steps li { margin: 4px 0; }

/* the account button: round, floating at the bottom right over the page (iOS safe area respected) */
button.round { width: 64px; height: 64px; min-height: 64px; margin: 0; padding: 0; border-radius: 50%; display: grid; place-items: center;
  background: var(--card); color: var(--bad); border: 1px solid var(--line); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08); }
button.round .icon { width: 26px; height: 26px; }
button.round.account { color: var(--fg); }
.fab { position: fixed; z-index: 20; right: calc(24px + env(safe-area-inset-right)); bottom: max(12px, calc(env(safe-area-inset-bottom) - 8px));
  width: 46px; height: 46px; min-height: 46px; box-shadow: var(--fab-shadow); transition: opacity 0.15s, transform 0.15s; }
.fab.tucked { opacity: 0; transform: scale(0.8); pointer-events: none; }
.searchbar { transition: opacity 0.15s ease, transform 0.15s ease; }
.searchbar.tucked { opacity: 0; transform: translateY(12px); pointer-events: none; }
@media (prefers-reduced-motion: reduce) { .searchbar { transition: none; } }
.fab[aria-expanded="true"] { background: var(--soft); }
/* room under the last card, so it always scrolls clear of the button */
main.has-fab { padding-bottom: calc(96px + env(safe-area-inset-bottom)); }
/* the account menu: two items, just above the button */
.menu { display: flex; flex-direction: column; min-width: 200px; background: var(--card); border: 1px solid var(--line);
  border-radius: 14px; overflow: hidden; box-shadow: var(--fab-shadow); }
.fab-menu { position: fixed; z-index: 21; right: calc(16px + env(safe-area-inset-right)); bottom: calc(82px + env(safe-area-inset-bottom)); }
button.menu-item { margin: 0; border-radius: 0; background: none; color: var(--fg); min-height: 48px; text-align: center; }
button.menu-item + button.menu-item { border-top: 1px solid var(--line); }
button.menu-item.bad-text { color: var(--bad); }
/* Devices screen */
.device-title { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.device-row .muted { margin: 2px 0 8px; }
button.back.linklike { margin: 0; padding: 8px 0; font-weight: 600; font-size: 1em; }

/* the gate: the whole screen is the one tap that starts Face ID */
.gate { min-height: calc(100vh - 60px); min-height: calc(100dvh - 60px); display: flex; flex-direction: column; justify-content: center; }
button.gate-tap { align-items: center; gap: 18px; background: transparent; color: var(--fg); border-radius: 24px; margin: 0; }
button.gate-tap .icon { width: 84px; height: 84px; stroke-width: 1.3; color: var(--approve); }
button.gate-tap.busy .icon { opacity: 0.5; }
.gate-title { font-size: 1.75em; font-weight: 700; text-align: center; }
.gate-hint { color: var(--muted); font-weight: 500; }
.big { min-height: 60px; font-size: 1.1em; }

/* the request brief: title, then one compact line each (what happens, risk, recommendation, access?, exposure?) */
.req-title { font-size: 1.22em; line-height: 1.3; font-weight: 700; margin: 10px 0 2px; unicode-bidi: plaintext; overflow-wrap: anywhere; }
.brief { margin: 6px 0 10px; display: grid; grid-template-columns: max-content 1fr; column-gap: 10px; row-gap: 6px; align-items: baseline; }
.brief-line { display: contents; }
.brief-k { font-size: 0.78em; font-weight: 650; color: var(--muted); }
.brief-text { line-height: 1.35; overflow-wrap: anywhere; unicode-bidi: plaintext; }
.brief > .note { grid-column: 1 / -1; }
.brief-risk .brief-k, .brief-exposure .brief-k { color: var(--warn); }
.brief-h { font-size: 0.75em; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); margin: 0 0 3px; font-weight: 650; }
.docs { margin: 10px 0; }
.doc-list { margin: 0; padding-inline-start: 18px; }
.doc-link { overflow-wrap: anywhere; }
/* the in-app document reader */
.doc-title { font-size: 1.3em; overflow-wrap: anywhere; }
.doc-body { margin: 12px 0; overflow-wrap: anywhere; unicode-bidi: plaintext; }
.doc-body .doc-h { font-size: 1.05em; text-transform: none; letter-spacing: 0; color: var(--fg); margin: 18px 0 6px; display: block; }
.doc-body pre, .doc-body code { font: 0.86em/1.4 ui-monospace, SFMono-Regular, Menlo, monospace; background: var(--soft); border-radius: 6px; }
.doc-body code { padding: 1px 4px; }
.doc-body pre { padding: 8px 10px; white-space: pre-wrap; overflow-wrap: anywhere; }
.doc-body blockquote { margin: 8px 0; padding-inline-start: 10px; border-inline-start: 3px solid var(--line); color: var(--muted); }
.doc-table { overflow-x: auto; }
.doc-body table { border-collapse: collapse; font-size: 0.88em; }
.doc-body th, .doc-body td { border: 1px solid var(--line); padding: 4px 6px; text-align: start; vertical-align: top; }
.img-off, .dead-link { color: var(--muted); font-style: italic; }
.doc-meta dd { font-family: ui-monospace, Menlo, monospace; font-size: 0.8em; }
.reason.sub { font-size: 1em; font-weight: 500; color: var(--muted); margin: 4px 0 6px; }
/* Ask again, on a request that expired before he answered */
.asked-again { margin: 4px 0 0; font-size: 0.9em; font-weight: 600; color: var(--accent); }
.ask-again { margin-top: 10px; }
.ask-again button { margin: 0; }
.ask-again .muted { margin: 6px 2px 0; }
.ask-again.under { margin: -4px 0 14px; padding: 0 2px; }
.req-wrap > .card { margin-bottom: 8px; }
/* the sheet covers the floating Account button (defined above) while it is open */
body.sheet-on .fab { opacity: 0; pointer-events: none; }
/* Pull to refresh (Home and the open card): the spinner drops in from the top, the page follows the finger, then
   settles with a short bounce. Reduced motion: no movement, the spinner only fades in and does not turn. */
html { overscroll-behavior-y: none; }
.ptr { position: fixed; z-index: 30; left: 50%; top: env(safe-area-inset-top); width: 34px; height: 34px; margin-left: -17px;
  border-radius: 50%; background: var(--card); box-shadow: var(--fab-shadow); display: grid; place-items: center; opacity: 0;
  pointer-events: none; transform: translateY(-40px); transition: opacity 0.15s ease; }
.ptr-spin { width: 18px; height: 18px; border-radius: 50%; border: 2.5px solid var(--line); border-top-color: var(--accent);
  transform: rotate(var(--ptr-turn, 0deg)); }
.ptr.armed .ptr-spin { border-color: var(--accent); border-right-color: var(--line); }
.ptr.spinning { transition: transform 0.2s ease-out, opacity 0.15s ease; }
.ptr.spinning .ptr-spin { animation: ptr-turn 0.7s linear infinite; }
@keyframes ptr-turn { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
main.ptr-bounce { animation: ptr-bounce 0.42s cubic-bezier(0.2, 0.8, 0.3, 1.2); }
@keyframes ptr-bounce { 0% { transform: translateY(42px); } 55% { transform: translateY(-6px); } 80% { transform: translateY(2px); } 100% { transform: translateY(0); } }
@media (prefers-reduced-motion: reduce) {
  .ptr, .ptr.spinning { transform: none; transition: none; top: max(8px, env(safe-area-inset-top)); }
  .ptr.spinning .ptr-spin { animation: none; border-color: var(--accent); }
  main.ptr-bounce { animation: none; }
}

/* Relay cards (round 5, docs/plans/relay-card-r5-2026-11-05.md; mock card5/states5): the task's full text is the
   headline, never cut; one "Asked by" line; one risk line; after Approve, who it waits on and since when. */
.req-title.full { font-size: 1.12em; font-weight: 650; line-height: 1.32; margin: 10px 0 6px; }
.req-title code.commit { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.9em; background: var(--soft);
  border-radius: 5px; padding: 0 4px; }
.asked-by { font-size: 0.9em; color: var(--muted); margin: 0 0 10px; unicode-bidi: plaintext; }
.asked-by b { color: var(--fg); font-weight: 600; }
.risk-line { font-size: 0.92em; margin: 0 0 14px; line-height: 1.35; unicode-bidi: plaintext; overflow-wrap: anywhere; }
.relay-status { display: block; background: var(--soft); border-radius: 12px; padding: 10px 12px; margin: 8px 0 4px; }
.relay-status .status { margin: 0; color: var(--fg); font-weight: 400; font-size: 0.95em; line-height: 1.35; }
.relay-status .status b { font-weight: 650; }
.relay-status .status.tone-late { color: var(--warn); font-weight: 650; }
.relay-status:has(.tone-late) { background: var(--warn-bg); }
.relay-status .status.tone-ended { color: var(--grey); }
.status-sub { margin: 2px 0 0; color: var(--muted); font-size: 0.85em; }

/* receipts (docs/plans/receipt-kind-2026-11-05.md) */
.receipt-line { margin: 4px 0 0; color: var(--muted); font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.receipt.page .receipt-amount, .receipt.row .receipt-amount { font-size: 28px; font-weight: 700; margin: 8px 0 2px; font-variant-numeric: tabular-nums; }
.receipt.page .receipt-shop, .receipt.row .receipt-shop { margin: 0 0 8px; color: var(--muted); }
.receipt-items { margin: 0; padding-left: 20px; }
.receipt-items li { margin: 2px 0; }

/* revise in place (docs/plans/revise-2026-11-05.md) */
.revised { margin: 2px 0 0; color: var(--muted); font-size: 0.86em; font-weight: 600; }
.changes { margin: 0 0 8px; padding-left: 18px; font-size: 0.92em; }
.changes li { margin: 4px 0; overflow-wrap: anywhere; }
.changes del { color: var(--muted); }
.changes ins { text-decoration: none; font-weight: 600; }
.change-field { color: var(--muted); }
.withdrawn-why.replaced { font-weight: 600; }

/* card files (docs/plans/card-files-2026-11-05.md) */
.files { margin: 10px 0 0; }
.thumbs { display: flex; gap: 8px; overflow-x: auto; padding-bottom: 2px; -webkit-overflow-scrolling: touch; }
button.thumb { flex: 0 0 auto; width: 96px; height: 96px; min-height: 0; margin: 0; padding: 0; border-radius: 10px; overflow: hidden;
  border: 1px solid var(--line); background: var(--soft); }
button.thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.thumb.none { display: inline-flex; align-items: center; padding: 8px; font-size: 0.8em; color: var(--muted); border: 1px dashed var(--line);
  border-radius: 10px; max-width: 140px; overflow: hidden; }
.file-row { display: flex; align-items: center; gap: 8px; padding: 10px 12px; margin-top: 8px; border-radius: 10px; background: var(--soft);
  color: var(--fg); text-decoration: none; min-height: 44px; }
.file-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.file-size { color: var(--muted); font-size: 0.85em; }
.viewer { position: fixed; inset: 0; z-index: 50; background: rgba(0, 0, 0, 0.92); display: flex; flex-direction: column;
  align-items: center; justify-content: center; padding: env(safe-area-inset-top) 12px env(safe-area-inset-bottom); }
.viewer img { max-width: 100%; max-height: 85vh; object-fit: contain; }
.viewer-name { color: #fff; margin: 10px 0 0; font-size: 0.9em; }

/* one feed (docs/plans/hub-feed-2026-11-05.md) */
.tabs { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 4px; background: var(--soft); border: 1px solid var(--line); border-radius: 12px; padding: 4px; margin: 4px 0 6px; }
button.tab { min-height: 36px; margin: 0; padding: 6px 4px; border-radius: 9px; border: 0; font-weight: 650; font-size: 0.86em; color: var(--muted); background: none; }
button.tab.on { background: var(--card); color: var(--fg); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12); }
.tab .n { display: inline-block; min-width: 18px; margin-left: 4px; padding: 0 6px; border-radius: 999px; font-size: 0.85em; }
.tab .n.green { background: var(--approve); color: var(--approve-fg); }
.tab .n.grey { background: var(--line); color: var(--fg); }
.bar { display: flex; justify-content: space-between; align-items: center; margin: 2px 2px 6px; min-height: 32px; }
.bar .sub { color: var(--muted); font-size: 0.9em; }
button.sort { width: auto; min-height: 32px; margin: 0; padding: 4px 0; background: none; border: 0; color: var(--accent); font-weight: 650; font-size: 0.9em; }
.sortmenu { background: var(--card); border: 1px solid var(--line); border-radius: 16px; padding: 4px 0; margin: 0 0 10px; box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12); }
button.opt { display: flex; justify-content: space-between; width: 100%; min-height: 44px; margin: 0; padding: 10px 16px; background: none; border: 0;
  border-radius: 0; color: var(--fg); font-weight: 600; text-align: left; }
button.opt + button.opt { border-top: 1px solid var(--line); }
.opt .tick { color: var(--accent); }
.card.unread .chip::before { content: ""; display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: #0a84ff; margin-right: 6px; vertical-align: 1px; }
.viewer-stage { display: flex; align-items: center; justify-content: center; width: 100%; flex: 0 1 auto; }
.viewer-file { background: var(--card); color: var(--fg); border-radius: 16px; padding: 24px; text-align: center; min-width: 220px; }
.viewer-file .icon { width: 40px; height: 40px; }
.viewer-open { display: inline-block; margin-top: 12px; padding: 10px 22px; border-radius: 12px; background: var(--accent); color: #fff; text-decoration: none; font-weight: 650; }
/* the close button: a dark frosted circle inside the safe area, above the image, readable on a white screenshot */
button.viewer-close { position: absolute; z-index: 2; top: calc(env(safe-area-inset-top) + 10px); right: calc(14px + env(safe-area-inset-right));
  width: 44px; height: 44px; min-height: 0; margin: 0; padding: 0; border-radius: 50%; border: 1px solid rgba(255, 255, 255, 0.35);
  background: rgba(0, 0, 0, 0.6); -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px); color: #fff; font-size: 28px; line-height: 1;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.35); }
.viewer { padding-top: calc(env(safe-area-inset-top) + 64px); }
.viewer img { max-height: calc(100vh - env(safe-area-inset-top) - env(safe-area-inset-bottom) - 120px); }

/* the toast after a send (aria-live polite), above the safe area: a light translucent tint over a blurred backdrop,
   green with a check for done, red with an X for failed; the words stay in the text colour (4.5:1 in both modes) */
.toast { position: fixed; left: 16px; right: 16px; margin: 0 auto; width: fit-content; bottom: calc(env(safe-area-inset-bottom) + 20px);
  transform: translateY(20px); z-index: 60; display: flex; align-items: center; gap: 10px; max-width: calc(100% - 32px);
  padding: 10px 14px 10px 10px; border-radius: 16px; color: var(--fg); font-weight: 600; font-size: 0.95em;
  -webkit-backdrop-filter: blur(18px) saturate(1.4); backdrop-filter: blur(18px) saturate(1.4);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.14); opacity: 0; pointer-events: none; transition: opacity 0.2s, transform 0.2s; }
.toast.show { opacity: 1; transform: translateY(0); pointer-events: auto; }
.toast.good { background: linear-gradient(rgba(30, 142, 62, 0.16), rgba(30, 142, 62, 0.16)), rgba(255, 255, 255, 0.86); border: 1px solid rgba(30, 142, 62, 0.35); }
.toast.bad { background: linear-gradient(rgba(197, 34, 31, 0.14), rgba(197, 34, 31, 0.14)), rgba(255, 255, 255, 0.86); border: 1px solid rgba(197, 34, 31, 0.35); }
.toast-icon { flex: 0 0 auto; display: grid; place-items: center; width: 26px; height: 26px; border-radius: 50%; color: #fff; }
.toast.good .toast-icon { background: var(--good); }
.toast.bad .toast-icon { background: var(--bad); }
.toast-icon .icon { width: 18px; height: 18px; stroke-width: 2.6; }
button.toast-retry { width: auto; min-height: 32px; margin: 0 0 0 4px; padding: 4px 12px; border-radius: 9px; border: 1px solid rgba(197, 34, 31, 0.45);
  background: rgba(255, 255, 255, 0.6); color: var(--bad); font-weight: 700; }
@media (prefers-color-scheme: dark) {
  .toast.good { background: linear-gradient(rgba(46, 164, 79, 0.22), rgba(46, 164, 79, 0.22)), rgba(28, 28, 30, 0.86); }
  .toast.bad { background: linear-gradient(rgba(255, 99, 92, 0.2), rgba(255, 99, 92, 0.2)), rgba(28, 28, 30, 0.86); }
  button.toast-retry { background: rgba(0, 0, 0, 0.25); }
}

/* card template (docs/plans/card-template-2026-11-06.md) */
.row3.two { grid-template-columns: minmax(0, 1fr) 56px; }
button.more-btn { font-size: 1.3em; line-height: 1; letter-spacing: 0.05em; color: var(--fg); }
.card-menu { display: grid; gap: 8px; margin-top: 8px; }
.card-menu button { margin: 0; min-height: 48px; display: inline-flex; align-items: center; justify-content: center; gap: 6px; color: var(--accent); }
.card-menu .roll-back { color: var(--bad); }
.outcome { margin: 6px 0 0; font-weight: 650; font-size: 0.95em; }
.outcome.tone-approved { color: var(--good); } .outcome.tone-failed { color: var(--bad); } .outcome.tone-waiting { color: var(--fg); }
.outcome a { color: inherit; text-decoration: underline; }
.outcome-note { display: block; margin-top: 2px; color: var(--muted); font-weight: 500; font-size: 0.92em; }
figure.thumb-fig { position: relative; flex: 0 0 auto; margin: 0; width: 96px; text-align: center; }
figure.thumb-fig.changed button.thumb { box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.95), 0 0 0 3.5px rgba(10, 132, 255, 0.55), 0 0 18px rgba(10, 132, 255, 0.45); }
.thumb-mark { color: #0a84ff; font-weight: 700; margin-inline-end: 4px; }
.thumb-mark::before { content: ""; display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: #0a84ff; margin-inline-end: 3px; vertical-align: 1px; }
.thumb-cap { margin-top: 4px; font-size: 0.75em; font-weight: 600; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.file-row.changed { box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.95), 0 0 0 3.5px rgba(10, 132, 255, 0.5), 0 0 16px rgba(10, 132, 255, 0.4); }

/* Liquid Glass, for the floating controls only (Yonatan 2026-11-06): the search bar, the tab switcher, the toast and
   the ⋯ menu. A frosted blur with extra colour, a thin bright edge and a faint sheen across the top, pill shapes with a
   soft shadow. Cards stay solid. WebKit has no refraction for web pages, so there is none. */
.glass { -webkit-backdrop-filter: blur(22px) saturate(1.8); backdrop-filter: blur(22px) saturate(1.8);
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.6), rgba(255, 255, 255, 0.3)), rgba(242, 242, 247, 0.84);
  border: 1px solid rgba(255, 255, 255, 0.7);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9), inset 0 -1px 0 rgba(0, 0, 0, 0.05), 0 10px 28px rgba(0, 0, 0, 0.12); }
@media (prefers-color-scheme: dark) {
  .glass { background: linear-gradient(180deg, rgba(255, 255, 255, 0.14), rgba(255, 255, 255, 0.04)), rgba(44, 44, 46, 0.88);
    border-color: rgba(255, 255, 255, 0.16);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.28), inset 0 -1px 0 rgba(0, 0, 0, 0.3), 0 10px 28px rgba(0, 0, 0, 0.45); }
}
/* the switcher: a pill that floats over the feed as it scrolls */
.tabs.glass { position: sticky; top: calc(env(safe-area-inset-top) + 6px); z-index: 15; border-radius: 999px; padding: 4px; }
.tabs.glass button.tab { border-radius: 999px; }
.tabs.glass button.tab.on { background: rgba(255, 255, 255, 0.85); }
@media (prefers-color-scheme: dark) { .tabs.glass button.tab.on { background: rgba(255, 255, 255, 0.16); } }
/* the ⋯ menu */
.card-menu.glass { border-radius: 20px; padding: 6px; gap: 6px; }
.card-menu.glass button { background: transparent; border-color: transparent; }
/* the toast keeps its green or red tint, under the glass edge and sheen */
.toast.glass.good { background: linear-gradient(180deg, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0.2)), linear-gradient(rgba(30, 142, 62, 0.18), rgba(30, 142, 62, 0.18)), rgba(255, 255, 255, 0.92); }
.toast.glass.bad { background: linear-gradient(180deg, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0.2)), linear-gradient(rgba(197, 34, 31, 0.16), rgba(197, 34, 31, 0.16)), rgba(255, 255, 255, 0.92); }
@media (prefers-color-scheme: dark) {
  .toast.glass.good { background: linear-gradient(180deg, rgba(255, 255, 255, 0.12), rgba(255, 255, 255, 0.03)), linear-gradient(rgba(46, 164, 79, 0.26), rgba(46, 164, 79, 0.26)), rgba(28, 28, 30, 0.93); }
  .toast.glass.bad { background: linear-gradient(180deg, rgba(255, 255, 255, 0.12), rgba(255, 255, 255, 0.03)), linear-gradient(rgba(255, 99, 92, 0.24), rgba(255, 99, 92, 0.24)), rgba(28, 28, 30, 0.93); }
}
.toast { bottom: calc(env(safe-area-inset-bottom) + 88px); border-radius: 999px; } /* above the search bar */
/* the search bar: fixed at the bottom, left of the account button */
/* as low as iOS Settings puts its search field (Yonatan 2026-11-06 17:36): its bottom edge 8 px inside the home indicator
   area, about 26 pt from the screen edge, 46 px tall, 24 px gutters; 12 px up where there is no home indicator */
.searchbar { position: fixed; z-index: 19; left: calc(24px + env(safe-area-inset-left)); right: calc(80px + env(safe-area-inset-right));
  bottom: max(12px, calc(env(safe-area-inset-bottom) - 8px)); height: 46px; border-radius: 999px; display: flex; align-items: center; gap: 8px; padding: 0 16px; }
.searchbar[hidden] { display: none; }
.searchbar .icon { color: var(--muted); }
input.search-input { flex: 1; min-width: 0; border: 0; background: transparent; color: var(--fg); font: inherit; font-size: 17px; outline: none; padding: 0; margin: 0; }
input.search-input::placeholder { color: var(--muted); }
main { padding-bottom: calc(96px + env(safe-area-inset-bottom)); }

/* swipe and dismiss (Yonatan 2026-11-06) */
.card.swipe { transition: transform 0.18s ease-out; touch-action: pan-y; }
.ask-again-row { display: grid; grid-template-columns: 2fr 1fr; gap: 8px; }
.ask-again-row button { margin: 0; }

/* search: the glass and the placeholder at the left, like an iOS search field (Yonatan 2026-11-06 12:25); the
   matches only while it has text; ✕ and Clear to leave */
.searchbar { justify-content: flex-start; padding-inline-start: 16px; }
.searchbar input.search-input { flex: 1; text-align: start; }
input.search-input::-webkit-search-cancel-button { display: none; }
button.search-clear { display: none; width: 44px; height: 44px; min-height: 0; margin: 0 -10px 0 0; padding: 0; border: 0; border-radius: 50%;
  background: transparent; color: var(--muted); font-size: 24px; line-height: 1; }
.searchbar.has-text button.search-clear { display: grid; place-items: center; }
.search-on { display: flex; justify-content: space-between; align-items: center; margin: 2px 2px 8px; color: var(--muted); font-size: 0.9em; }
button.search-off { width: auto; min-height: 44px; margin: 0; padding: 0 4px; font-size: 1em; }

article.card.req.row, article.card.req.page { cursor: pointer; -webkit-tap-highlight-color: transparent; }

/* the notes gate: his note is a condition of this approval (SPEC.md, "His notes gate the approval") */
.notes-gate { margin: 4px 0 0; font-size: 0.875rem; color: var(--muted); }
.notes-gate.warn { color: var(--warn); font-weight: 600; }

/* Reply and Details in sight on an answered card, as plain text buttons (Yonatan 2026-11-06 12:29) */
.quiet-row { display: flex; gap: 8px; margin-top: 4px; }
.quiet-row button { flex: 1; margin: 0; min-height: 44px; display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  background: transparent; border-color: transparent; color: var(--accent); font-weight: 600; }
.quiet-row button.more-btn { flex: 0 0 56px; }
.quiet-row .icon { width: 20px; height: 20px; flex: none; }
.quiet-row .dt[aria-expanded="true"] .icon { transform: rotate(180deg); }

/* Home: a floating glass pill at the top left of a card page and Devices; the header keeps its height under it */
.home-float { position: fixed; z-index: 21; top: calc(10px + env(safe-area-inset-top)); left: calc(16px + env(safe-area-inset-left));
  display: inline-flex; align-items: center; min-height: 44px; padding: 0 18px; border-radius: 999px; color: var(--accent); font-weight: 650;
  font-size: 17px; text-decoration: none; touch-action: manipulation; }
button.back.home-float { margin: 0; border: 0; }
header.top:has(.home-float) { min-height: 56px; }

/* an update: its text in the feed up to 3 lines, and as the body on its page (Yonatan 2026-11-06) */
.update-text { margin: 6px 0 0; color: var(--fg); font-size: 15px; line-height: 1.4; overflow-wrap: anywhere; unicode-bidi: plaintext;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.update-body { margin: 8px 0 4px; color: var(--fg); font-size: 17px; line-height: 1.45; white-space: pre-wrap; overflow-wrap: anywhere; unicode-bidi: plaintext; }

/* a full swipe (Yonatan 2026-11-06): no lag while the finger drags, a spring back, a slide off; the edge grows once a
   release would act */
.card.swipe.dragging { transition: none; }
.card.swipe.swiped { transition: transform 0.22s ease-in, opacity 0.22s ease-in; opacity: 0; }
@media (prefers-reduced-motion: reduce) { .card.swipe, .card.swipe.swiped { transition: none; } }

/* the line between open and handled cards, in every tab (Yonatan 2026-11-06 14:03) */
.feed-sep { display: flex; align-items: center; gap: 10px; margin: 18px 4px 10px; color: var(--muted); font-size: 0.85em; font-weight: 650; }
.feed-sep::before, .feed-sep::after { content: ""; flex: 1; height: 1px; background: var(--line); }
/* text is not selectable, so a long press on a button never selects its label (Yonatan 2026-11-06 14:04); what he types
   still is */
body { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
input, textarea { -webkit-user-select: text; user-select: text; -webkit-touch-callout: default; }

/* option B (Yonatan 2026-11-06 17:30): each card is tinted by its kind, the chip keeps the full colour; approvals
   (agent actions) are green so they read apart from Deploy's purple */
.card.req.kind-login { background: color-mix(in srgb, var(--t-login-bg) 70%, var(--card)); border-color: color-mix(in srgb, var(--t-login) 30%, transparent); }
.card.req.kind-wa { background: color-mix(in srgb, var(--t-wa-bg) 70%, var(--card)); border-color: color-mix(in srgb, var(--t-wa) 30%, transparent); }
.card.req.kind-pay { background: color-mix(in srgb, var(--t-pay-bg) 70%, var(--card)); border-color: color-mix(in srgb, var(--t-pay) 30%, transparent); }
.card.req.kind-danger { background: color-mix(in srgb, var(--t-danger-bg) 70%, var(--card)); border-color: color-mix(in srgb, var(--t-danger) 30%, transparent); }
.card.req.kind-deploy { background: color-mix(in srgb, var(--t-deploy-bg) 70%, var(--card)); border-color: color-mix(in srgb, var(--t-deploy) 30%, transparent); }
.card.req.kind-config { background: color-mix(in srgb, var(--t-config-bg) 70%, var(--card)); border-color: color-mix(in srgb, var(--t-config) 30%, transparent); }
.card.req.kind-agent { background: color-mix(in srgb, var(--t-agent-bg) 70%, var(--card)); border-color: color-mix(in srgb, var(--t-agent) 30%, transparent); }
.card.req.kind-update { background: color-mix(in srgb, var(--t-update-bg) 70%, var(--card)); border-color: color-mix(in srgb, var(--t-update) 30%, transparent); }

/* swipe: a thin edge stripe on the side the card moves away from (Yonatan 2026-11-06 18:09), 6 px as before (18:18) */
.card.swipe { position: relative; }
.card.swipe[data-dir="right"] { --stripe: 6px; }
.card.swipe[data-dir="left"] { --stripe: -6px; }
.card.swipe[data-swipe="approve"] { box-shadow: var(--stripe) 0 0 var(--approve) inset; }
.card.swipe[data-swipe="reject"] { box-shadow: var(--stripe) 0 0 var(--bad) inset; }
.card.swipe[data-swipe="dismiss"] { box-shadow: var(--stripe) 0 0 var(--grey, #8e8e93) inset; }

/* handled cards in the feed are plain: no kind tint (Yonatan 2026-11-06 19:00) */
.card.req.handled { background: var(--card); border-color: var(--line); }
