* { box-sizing: border-box; }
html { min-width: 320px; background: var(--bg); }
body { margin: 0; color: var(--text); background: var(--bg); font-family: var(--font-sans); font-size: 14px; line-height: 1.5; }
button, input, select { font: inherit; }
button, a { -webkit-tap-highlight-color: transparent; }
/* B2 fix loop 2 (Mozart): the focus ring also covers text areas and the keyboard-reachable rows (customer and catalog
   list rows, Home attention rows: tabindex="0"); an element focused only by script (tabindex="-1") keeps its own rule. */
button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible, a:focus-visible, summary:focus-visible,
[tabindex]:not([tabindex="-1"]):focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
button { cursor: pointer; }
button:disabled { cursor: not-allowed; }
[hidden] { display: none !important; }
h1, h2, h3, p { margin-top: 0; }
h1 { margin-bottom: var(--space-2); font-size: 24px; line-height: 1.25; letter-spacing: -.02em; }
h2 { margin-bottom: var(--space-3); font-size: 17px; line-height: 1.35; }
h3 { margin-bottom: var(--space-2); font-size: 14px; line-height: 1.4; }
a { color: inherit; }
.muted { color: var(--text-secondary); }
.subtle { color: var(--text-tertiary); }
.eyebrow { margin-bottom: var(--space-2); color: var(--text-secondary); font-size: 11px; font-weight: 650; letter-spacing: .08em; text-transform: uppercase; }
.app-shell { min-height: 100vh; padding-left: var(--sidebar-width); }
.sidebar { position: fixed; inset: 0 auto 0 0; z-index: 20; display: flex; width: var(--sidebar-width); flex-direction: column; padding: var(--space-6) var(--space-3) var(--space-4); border-right: 1px solid var(--border); background: #f9f8f4; }
.wordmark { display: flex; align-items: center; gap: 10px; padding: 0 10px; font-size: 17px; font-weight: 720; letter-spacing: -.02em; }
a.wordmark { margin-bottom: var(--space-6); color: inherit; text-decoration: none; }
.wordmark-mark { display: grid; width: 27px; height: 27px; place-items: center; border-radius: var(--radius-sm); background: var(--accent); color: white; font-size: 13px; }
.nav-list { display: grid; gap: 2px; }
.nav-break { height: 1px; margin: var(--space-3) 10px; background: var(--border); }
.nav-item { display: flex; min-height: 38px; align-items: center; gap: 10px; width: 100%; padding: 8px 10px; border: 0; border-radius: var(--radius-sm); background: transparent; color: var(--text-secondary); text-align: left; text-decoration: none; }
.nav-item svg { width: 17px; height: 17px; flex: 0 0 auto; }
.nav-item:hover:not(:disabled) { background: var(--surface-muted); color: var(--text); }
.nav-item[aria-current="page"] { background: var(--accent-soft); color: var(--accent); font-weight: 640; }
.nav-item:disabled { color: var(--text-tertiary); opacity: .72; }
.nav-label { min-width: 0; flex: 1; }
.soon { font-size: 9px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; }
.account { margin-top: auto; padding: var(--space-4) 10px 0; border-top: 1px solid var(--border); }
.account-name { overflow: hidden; font-weight: 640; text-overflow: ellipsis; white-space: nowrap; }
.account-meta { color: var(--text-tertiary); font-size: 12px; text-transform: capitalize; }
.logout { margin-top: var(--space-3); padding: 0; border: 0; background: none; color: var(--text-secondary); font-size: 12px; }
.page { width: min(1500px, 100%); margin: 0 auto; padding: var(--space-8) var(--space-10) var(--space-10); }
.page-header { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--space-5); margin-bottom: var(--space-8); }
.page-header p { margin: 0; max-width: 650px; color: var(--text-secondary); }
.header-actions { display: flex; align-items: center; gap: var(--space-2); }
.btn { display: inline-flex; min-height: var(--control-height); align-items: center; justify-content: center; gap: 8px; padding: 0 14px; border: 1px solid var(--accent); border-radius: var(--radius-sm); background: var(--accent); color: white; font-weight: 630; text-decoration: none; }
.btn:hover { background: var(--accent-hover); }
.btn:disabled { border-color: var(--border); background: var(--surface-subtle); color: var(--text-tertiary); opacity: .65; }
.btn-secondary { border-color: var(--border-strong); background: var(--surface); color: var(--text); }
.btn-secondary:hover { background: var(--surface-subtle); }
.btn-quiet { min-height: 32px; padding: 0 8px; border-color: transparent; background: transparent; color: var(--accent); }
.btn-quiet:hover { background: var(--accent-soft); }
.btn svg { width: 16px; height: 16px; }
.home-metrics { margin-bottom: var(--space-8); padding-bottom: var(--space-6); border-bottom: 1px solid var(--border); }
.home-primary { display: flex; flex-direction: column; gap: var(--space-1); margin-bottom: var(--space-5); }
.metric-primary { font-size: var(--font-size-display); font-weight: 690; line-height: 1.05; letter-spacing: -.03em; font-variant-numeric: tabular-nums; }
.metric-primary-label { color: var(--text-secondary); font-size: 14px; }
.home-secondary { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-8); }
.metric-secondary { display: flex; align-items: baseline; gap: var(--space-2); min-width: 0; color: var(--text-secondary); font-size: 14px; font-weight: 400; }
.metric-secondary-value { font-variant-numeric: tabular-nums; }
.summary-strip { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); margin-bottom: var(--space-8); border-block: 1px solid var(--border); }
.summary-item { min-width: 0; padding: var(--space-4) var(--space-5); border-right: 1px solid var(--border); }
.summary-item:first-child { padding-left: 0; }
.summary-item:last-child { border-right: 0; }
.summary-value { display: block; margin-top: 2px; font-size: 22px; font-weight: 690; letter-spacing: -.02em; overflow-wrap: anywhere; }
/* B2 fix loop 2 (P7): the label always sits on its own line above its value, also when the value is a badge or plain
   text ("Conflict" above "None", never "ConflictNone"). */
.summary-label { display: block; color: var(--text-secondary); font-size: 12px; }
.section-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-4); margin-bottom: var(--space-3); }
.section-head h2, .section-head p { margin: 0; }
.data-surface { overflow: hidden; border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--surface); }
/* B2 fix loop 2 (P7): on a phone the customers table may be wider than the screen; it scrolls sideways inside its
   surface (like .catalog-surface) instead of clipping the Understanding badge. */
.customer-surface { overflow-x: auto; }
.cell-status-inline { display: none; }
.customer-list, .catalog-table { width: 100%; border-collapse: collapse; }
.customer-list th, .catalog-table th { padding: 10px 16px; border-bottom: 1px solid var(--border); background: var(--surface-subtle); color: var(--text-secondary); font-size: 11px; font-weight: 650; letter-spacing: .04em; text-align: left; text-transform: uppercase; }
.customer-list td, .catalog-table td { height: 64px; padding: 10px 16px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.customer-list tr:last-child td, .catalog-table tr:last-child td { border-bottom: 0; }
.customer-list tbody tr, .catalog-table tbody tr { cursor: pointer; }
.customer-list tbody tr:hover, .catalog-table tbody tr:hover { background: #fafaf7; }
.field-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-3) var(--space-4); }
.catalog-bedrooms-filter { max-width: 180px; }
.summary-value-compact { font-size: 14px; }
/* B2 review (Mozart): catalog/search fixes. A long Rupiah amount or range is smaller and may break anywhere; the
   catalog table scrolls sideways inside its surface instead of being clipped; the search result strip (five items)
   fits as many per row as the width allows (two classes, so it also wins over the 780px two-column rule); the
   "Understood:" chips wrap; two row buttons (Accept / Reject, Generate / Unlink) keep a gap. */
.summary-value-money { font-size: 18px; }
.catalog-surface { overflow-x: auto; }
/* B2 fix loop 2 (P7 M7): a select inside a two-column field grid never grows past its column (select.control has a
   160px minimum), so it cannot cover the value next to it at 320px. */
.field-grid .control { min-width: 0; max-width: 100%; }
/* B2 fix loop 2 (P7 M6): search result cards: padding, space between cards; the price takes the first row of the
   strip; the other items are a plain grid (label above value, no dividers) so nothing is squeezed. */
.search-card { margin-bottom: var(--space-4); padding: var(--space-5); }
.search-card .customer-header { margin-bottom: var(--space-4); padding-bottom: var(--space-4); }
.search-card .summary-strip.summary-strip-fit { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: var(--space-4) var(--space-5); margin-bottom: 0; padding: 0 0 var(--space-4); border-top: 0; }
.search-card .summary-strip-fit .summary-item { padding: 0; border: 0; }
.search-card .summary-strip-fit .summary-item-money { grid-column: 1 / -1; }
.search-card .understanding-section:last-child { padding-bottom: 0; }
/* B2 fix loop 2 (P7 L4): "Price · Manual edit" on one line; the dot is its own element with space on both sides. */
.cell-secondary.meta-after { display: inline; margin-left: 6px; }
.meta-sep { margin-right: 6px; }
.summary-strip.summary-strip-fit { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.chip-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin-bottom: var(--space-4); }
.row-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.proposal-line { display: grid; gap: 2px; margin-bottom: var(--space-3); }
.primary-cell { font-weight: 650; }
.cell-secondary { display: block; margin-top: 2px; color: var(--text-secondary); font-size: 12px; font-weight: 400; }
.status { display: inline-flex; min-height: 24px; align-items: center; gap: 6px; padding: 2px 8px; border: 1px solid currentColor; border-radius: 999px; font-size: 11px; font-weight: 650; white-space: nowrap; }
.status::before { width: 5px; height: 5px; border-radius: 50%; background: currentColor; content: ""; }
.status-success { color: var(--success); background: var(--success-soft); }
.status-warning { color: var(--warning); background: var(--warning-soft); }
.status-danger { color: var(--danger); background: var(--danger-soft); }
.status-info { color: var(--info); background: var(--info-soft); }
.status-neutral { color: var(--text-secondary); background: var(--surface-muted); }
.toolbar { display: flex; align-items: center; gap: var(--space-3); margin-bottom: var(--space-4); }
.search-wrap { position: relative; width: min(400px, 100%); }
.search-wrap svg { position: absolute; top: 11px; left: 12px; width: 16px; height: 16px; color: var(--text-tertiary); pointer-events: none; }
.control { min-height: var(--control-height); width: 100%; padding: 8px 12px; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); background: var(--surface); color: var(--text); }
.search-wrap .control { padding-left: 36px; }
select.control { width: auto; min-width: 160px; }
.pagination { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); margin-top: var(--space-4); }
/* B2 fix loop 2 (P7 L3): "Berikutnya" and "Halaman 1" never wrap or spill at 320px. */
.pagination > * { white-space: nowrap; }
.attention-list { border-top: 1px solid var(--border); }
.attention-row { display: grid; grid-template-columns: minmax(190px, 1.2fr) minmax(180px, 1fr) minmax(150px, .8fr) auto; align-items: center; gap: var(--space-4); min-height: 68px; padding: 10px 0; border-bottom: 1px solid var(--border); cursor: pointer; }
.attention-row:hover .attention-name { color: var(--accent); }
.attention-name { font-weight: 650; }
.attention-detail { color: var(--text-secondary); font-size: 12px; }
.queue-empty { padding: var(--space-10) 0; border-block: 1px solid var(--border); text-align: center; }
.empty, .error-state { padding: 56px var(--space-6); text-align: center; }
.empty h2, .error-state h2 { margin-bottom: var(--space-2); }
.empty p, .error-state p { margin: 0 auto var(--space-4); max-width: 440px; color: var(--text-secondary); }
.skeleton { position: relative; overflow: hidden; border-radius: 4px; background: #e8e7e1; }
.skeleton::after { position: absolute; inset: 0; background: linear-gradient(90deg, transparent, rgb(255 255 255 / 65%), transparent); content: ""; transform: translateX(-100%); animation: shimmer 1.25s infinite; }
.skeleton-line { width: 70%; height: 12px; }
/* Reserves the rendered .home-metrics height (measured in Chromium: 137px desktop, 162px at 320-442px; the secondary metrics wrap to a second row at 442px and below) so content below does not jump. */
.skeleton-metric { width: 40%; height: 137px; margin-bottom: var(--space-8); }
@media (max-width: 442px) { .skeleton-metric { height: 162px; } }
.skeleton-row { height: 64px; border-bottom: 1px solid var(--border); }
@keyframes shimmer { to { transform: translateX(100%); } }
.detail-page { width: min(1680px, 100%); }
.back-link { display: inline-flex; align-items: center; gap: 6px; margin-bottom: var(--space-5); border: 0; background: none; color: var(--text-secondary); padding: 0; }
/* B2 fix loop 2 (P7): the arrow has a fixed size, so it never takes the label's room (the label wrapped at 1000px). */
.back-link svg { width: 16px; height: 16px; flex: 0 0 auto; }
.back-link:hover { color: var(--text); }
.customer-header { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-5); margin-bottom: var(--space-6); padding-bottom: var(--space-5); border-bottom: 1px solid var(--border); }
.customer-header h1 { margin-bottom: var(--space-2); }
.customer-meta { display: flex; flex-wrap: wrap; gap: 6px 16px; color: var(--text-secondary); font-size: 12px; }
.header-status { display: flex; flex-direction: column; align-items: flex-end; gap: var(--space-2); }
/* B2 fix loop 2 (P7 L5): the catalog entry's action buttons; on a phone they wrap in a row from the left. */
.header-actions-wrap { flex-wrap: wrap; }
.refresh-control { display: flex; align-items: center; gap: var(--space-2); }
.refresh-control .inline-error, .refresh-control .inline-notice { margin: 0; max-width: 260px; padding: 6px 10px; font-size: 12px; }
.refresh-status { font-size: 12px; }
.detail-grid { display: grid; grid-template-columns: minmax(0, 1.08fr) minmax(360px, .92fr); gap: var(--space-6); align-items: start; }
.understanding { min-width: 0; }
.understanding-section { padding: var(--space-6) 0; border-bottom: 1px solid var(--border); }
.understanding-section:first-child { padding-top: 0; }
.understanding-section:last-child { border-bottom: 0; }
.understanding-section h2 { margin-bottom: var(--space-3); }
.situation { max-width: 760px; font-size: 18px; line-height: 1.55; letter-spacing: -.01em; }
.action-panel { padding: var(--space-5); border-left: 3px solid var(--accent); background: var(--accent-soft); }
.action-title { margin-bottom: 4px; font-size: 17px; font-weight: 680; }
.action-reason { margin: 0; color: var(--text-secondary); }
.attribute-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-4) var(--space-6); }
.attribute { min-width: 0; }
.attribute-label { margin-bottom: 3px; color: var(--text-secondary); font-size: 12px; }
.attribute-value { word-break: break-word; }
.provenance { margin-left: 6px; color: var(--text-tertiary); font-size: 11px; white-space: nowrap; }
.evidence-link { display: inline-flex; margin-top: 5px; padding: 0; border: 0; background: none; color: var(--accent); font-size: 12px; }
.evidence-group { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-3); }
.context-list { display: grid; gap: var(--space-3); margin: 0; padding: 0; list-style: none; }
.context-item { padding-left: var(--space-3); border-left: 2px solid var(--border-strong); }
.override-item { padding: var(--space-3) 0; border-top: 1px solid var(--border); }
.override-item:first-child { border-top: 0; }
.conversation-pane { position: sticky; top: var(--space-6); overflow: hidden; max-height: calc(100vh - 48px); border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--surface); }
.conversation-head { display: flex; align-items: center; justify-content: space-between; padding: var(--space-4) var(--space-5); border-bottom: 1px solid var(--border); }
.conversation-head h2 { margin: 0; }
.conversation-scroll { display: flex; min-height: 360px; max-height: calc(100vh - 145px); flex-direction: column; gap: var(--space-3); overflow-y: auto; padding: var(--space-5); }
.message { max-width: 84%; padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--surface-subtle); }
.message-out { align-self: flex-end; border-color: #cddbd6; background: var(--accent-soft); }
.message-body { margin: 0; white-space: pre-wrap; word-break: break-word; }
.message-meta { display: flex; gap: 8px; margin-top: 5px; color: var(--text-tertiary); font-size: 10px; }
.load-older { align-self: center; }
details.context-details summary { cursor: pointer; color: var(--text-secondary); font-weight: 630; }
details.context-details[open] summary { margin-bottom: var(--space-4); }
.drawer-backdrop { position: fixed; inset: 0; z-index: 40; background: rgb(22 26 23 / 28%); }
.drawer { position: fixed; inset: 0 0 0 auto; z-index: 41; width: min(460px, 94vw); padding: var(--space-6); overflow-y: auto; border-left: 1px solid var(--border); background: var(--surface); box-shadow: var(--shadow-float); }
.drawer-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-4); padding-bottom: var(--space-5); border-bottom: 1px solid var(--border); }
.drawer-head h2 { margin: 0; }
.icon-button { display: grid; width: 34px; height: 34px; place-items: center; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface); color: var(--text-secondary); }
.drawer-message { margin-top: var(--space-6); padding: var(--space-4); border-left: 3px solid var(--accent); background: var(--surface-subtle); white-space: pre-wrap; }
.drawer-loading { margin-top: var(--space-6); }
.drawer-dl { display: grid; grid-template-columns: 110px 1fr; gap: 10px; margin-top: var(--space-5); font-size: 12px; }
.drawer-dl dt { color: var(--text-secondary); }
.drawer-dl dd { margin: 0; }
/* Fix loop 1 (Mozart): top-anchored (not vertically centred), so a message appearing below the button never moves
   the heading or the fields. */
.auth-page { position: relative; display: grid; min-height: 100vh; place-items: start center; padding: clamp(var(--space-10), 16vh, 160px) var(--space-6) var(--space-6); }
/* Track Language L1b: the top-right cluster of the sign-in/setup page, outside the form: the language picker (a real
   <select> with a visually hidden label) and the sound toggle. Both quiet (no box), 44px tall targets. */
.auth-tools { position: absolute; top: var(--space-3); right: var(--space-3); display: flex; align-items: center; gap: var(--space-1); }
.auth-language { height: 44px; padding: 0 var(--space-2); border: 1px solid transparent; border-radius: var(--radius-sm); background: transparent; color: var(--text-secondary); font-size: 13px; cursor: pointer; }
.auth-language:hover:not(:disabled) { background: var(--surface-muted); color: var(--text); }
.auth-language:disabled { color: var(--text-tertiary); cursor: not-allowed; }
/* Track UI U3 v2: sound on/off toggle, top right of the sign-in/setup page, outside the form. 44x44 target. */
.sound-toggle { display: grid; width: 44px; height: 44px; place-items: center; padding: 0; border: 0; border-radius: var(--radius-sm); background: transparent; color: var(--text-secondary); }
.sound-toggle:hover { background: var(--surface-muted); color: var(--text); }
.sound-toggle svg { width: 18px; height: 18px; }
/* Track UI U3 v2: narrower sign-in/setup form (the pointer tilt of U2 was withdrawn by the owner on 2026-10-03). */
.auth-panel { width: min(360px, 100%); }
.auth-brand { margin-bottom: var(--space-8); }
.auth-brand .wordmark { padding-left: 0; }
.auth-panel h1 { font-size: 28px; }
.field { display: grid; gap: 6px; margin-bottom: var(--space-4); }
.field label { color: var(--text-secondary); font-size: 12px; font-weight: 620; }
.field-inline { display: flex; align-items: center; gap: var(--space-3); }
.field-inline select { flex: 1; }
.password-row { display: flex; align-items: center; gap: var(--space-2); }
.password-row .control { flex: 1; min-width: 0; }
.password-toggle { min-height: 44px; min-width: 56px; flex: none; }
/* Track Language L2: in Indonesian the word flips between "Tampilkan" (87px) and "Sembunyikan" (110px, measured in
   Chrome); a fixed width for both keeps the password box from changing width on every click. English is unchanged. */
.password-toggle:lang(id) { min-width: 112px; }
.btn-link { display: inline-flex; padding: 0; border: 0; background: none; color: var(--text-secondary); font-size: 12px; white-space: nowrap; cursor: pointer; }
.btn-link:hover { color: var(--accent); }
.auth-panel .btn { width: 100%; min-height: 52px; margin-top: var(--space-2); border-radius: var(--radius-md); }
.auth-panel .password-toggle { width: auto; margin-top: 0; }
/* Track UI U3 v2: floating-label auth fields (ui.js formField `floating`, login and setup only). The label sits inside
   the empty 54px field and floats up (transform only) when the field is focused, filled or autofilled; :placeholder-shown
   works because the input has a one-space placeholder and the label follows it in the DOM. The label never takes clicks
   (pointer-events: none), so a click lands in the input; it stays a real <label for>. Field messages stay below the box. */
.field-float { gap: var(--space-1); }
.float-box { position: relative; }
.float-box .control-float { height: 54px; padding: 24px 14px 6px; border-radius: var(--radius-md); }
.float-box.has-toggle .control-float { padding-right: 52px; }
.float-box .control-float:focus { border-color: var(--accent); }
.float-box .float-label { position: absolute; top: 0; left: 15px; max-width: calc(100% - 30px); overflow: hidden; color: var(--text-secondary); font-size: 15px; font-weight: 500; line-height: 20px; white-space: nowrap; text-overflow: ellipsis; pointer-events: none; transform: translateY(17px); transform-origin: left top; transition: transform var(--motion-base) var(--motion-ease); }
.float-box.has-toggle .float-label { max-width: calc(100% - 67px); }
/* Floated: 15px x .8 = 12px exactly, at the top of the box (6-22px), above the value (from 25px). The width limit is
   divided by the scale so a floated label uses the same visual width as the box allows. */
.float-box .control-float:focus + .float-label, .float-box .control-float:not(:placeholder-shown) + .float-label { max-width: calc((100% - 30px) / .8); transform: translateY(6px) scale(.8); }
.float-box.has-toggle .control-float:focus + .float-label, .float-box.has-toggle .control-float:not(:placeholder-shown) + .float-label { max-width: calc((100% - 67px) / .8); }
/* Autofilled fields count as filled. Separate rules: one unknown pseudo-class would drop a whole selector list.
   The max-width here is the narrower has-toggle width for every field (also those without the eye): harmless, an
   autofilled label is short, and one rule per pseudo-class keeps the list small (Jane, U3 v2 review). */
.float-box .control-float:-webkit-autofill + .float-label { max-width: calc((100% - 67px) / .8); transform: translateY(6px) scale(.8); }
.float-box .control-float:autofill + .float-label { max-width: calc((100% - 67px) / .8); transform: translateY(6px) scale(.8); }
/* Fix loop 1 (Mozart): keep the field white under autofill. The browser's tinted autofill background is held back by
   an effectively endless transition delay (no box-shadow inset trick, so the shadow count stays at the one pattern). */
.float-box .control-float:-webkit-autofill { transition: background-color 0s 86400s, color 0s 86400s; }
.float-box .control-float:autofill { transition: background-color 0s 86400s, color 0s 86400s; }
/* The password Show/Hide inside the field: an eye / eye-off icon button with a 44x44 hit area inside the 54px box. */
.password-eye { position: absolute; top: 5px; right: 5px; display: grid; width: 44px; height: 44px; place-items: center; padding: 0; border: 0; border-radius: var(--radius-sm); background: transparent; color: var(--text-secondary); }
.password-eye:hover { color: var(--text); }
.password-eye svg { width: 18px; height: 18px; }
.password-eye:focus-visible { outline-offset: -4px; }
/* Track UI U3 v2: the Sign in button. Label on the left, the door drawing (stick figure + door, currentColor) on the
   right, always shown; the check mark is centred and shown only on success. Nothing in it changes size, so the button
   keeps its width and height in every state. The status line below it has its height reserved permanently. */
.auth-panel .auth-submit { position: relative; justify-content: space-between; padding: 0 var(--space-3) 0 var(--space-4); font-size: 15px; }
.auth-submit-label, .auth-submit .door-art, .auth-submit .auth-submit-check { transition: opacity var(--motion-fast) var(--motion-ease), transform var(--motion-fast) var(--motion-ease); }
.auth-submit .door-art { width: 52px; height: 28px; flex: none; }
.auth-submit .auth-submit-check { position: absolute; top: 50%; left: 50%; width: 22px; height: 22px; opacity: 0; transform: translate(-50%, -50%) scale(.6); }
/* Busy (aria-disabled="true", not the disabled attribute, so focus stays; the JS guard drops a second submit): normal
   accent look at full opacity with the label dimmed, progress cursor. Also under reduced motion. */
.btn.auth-submit.is-signing-in[aria-disabled="true"], .btn.auth-submit.is-signing-in[aria-disabled="true"]:hover { border-color: var(--accent); background: var(--accent); color: white; opacity: 1; cursor: progress; }
.auth-submit.is-signing-in .auth-submit-label { opacity: .7; }
/* Success: success token, label and drawing fade out, the white check mark replaces them. */
.btn.auth-submit.is-signed-in[aria-disabled="true"], .btn.auth-submit.is-signed-in[aria-disabled="true"]:hover { border-color: var(--success); background: var(--success); color: white; opacity: 1; cursor: default; }
.auth-submit.is-signed-in .auth-submit-label, .auth-submit.is-signed-in .door-art { opacity: 0; }
.auth-submit.is-signed-in .auth-submit-check { opacity: 1; transform: translate(-50%, -50%) scale(1); }
/* Fix loop 1 (Mozart): one outcome slot under the button for the status line OR the form-level error, its height
   reserved, so neither appearing moves anything. Track Language L1b: measured in headless Chrome, the longest
   sign-in/setup error is a 3-line box (83px) at 320px in Indonesian and 2 lines (62px) in English at every width, so
   84px is reserved (was 48px, one line). The "app could not open" state adds a Reload button below (terminal state). */
.auth-outcome { min-height: 84px; margin-top: var(--space-2); }
.auth-submit-status { min-height: 20px; margin: 0; color: var(--text-secondary); font-size: 13px; line-height: 20px; text-align: center; }
.auth-submit-status:empty { display: none; }
.auth-outcome .inline-error { margin: 0; overflow-wrap: anywhere; }
/* Setup busy (fix loop 1): same pattern as sign-in, accent look kept, progress cursor. */
.btn.is-creating[aria-disabled="true"], .btn.is-creating[aria-disabled="true"]:hover { border-color: var(--accent); background: var(--accent); color: white; opacity: 1; cursor: progress; }
/* Track Language L1b: signed in but the app could not open. The button stays aria-disabled with the disabled look
   (a resubmit would mint another session); a "Reload page" button sits in the outcome slot. */
.btn.auth-submit.is-open-failed[aria-disabled="true"], .btn.auth-submit.is-open-failed[aria-disabled="true"]:hover { border-color: var(--border); background: var(--surface-subtle); color: var(--text-tertiary); opacity: .65; cursor: not-allowed; }
/* Track Language L1b: "Remember my email" row between the password field and the button. The label fills the 44px
   row, so the whole row is the click target. */
.auth-remember { display: flex; align-items: center; gap: var(--space-2); min-height: 44px; margin-top: calc(var(--space-2) * -1); color: var(--text-secondary); font-size: 13px; }
.auth-remember input { width: 16px; height: 16px; flex: none; margin: 0; accent-color: var(--accent); }
.auth-remember label { display: flex; min-height: 44px; flex: 1; align-items: center; cursor: pointer; }
/* Reserved, owner decision pending: a "Forgot password?" link and a "Create account" line. Not built. */
/* The door: a translucent leaf with a knob in an outlined frame. While signing in with motion allowed
   (is-door-moving), the leaf swings out on its right-hand hinge (it ends as a narrow panel outside the frame) and the
   doorway fills with warm light (--bg), the figure walks into the light and fades, then the door swings shut. Fix
   loop 1 (Mozart): the cycle repeats while the server is slow (a calm closed pause, then the figure fades back in at
   its start), so the button never looks stalled; removing the class stops it at once. Transform and opacity only. */
.door-panel { fill-opacity: .3; }
.door-light { fill: var(--bg); opacity: 0; }
.door-leaf { transform-box: fill-box; transform-origin: right center; }
.auth-submit.is-door-moving .door-leaf { animation: door-leaf calc(var(--motion-slow) * 6) var(--motion-ease) infinite; }
.auth-submit.is-door-moving .door-light { animation: door-light calc(var(--motion-slow) * 6) linear infinite; }
.auth-submit.is-door-moving .door-walker { animation: door-walk calc(var(--motion-slow) * 6) linear infinite; }
/* One cycle = calc(var(--motion-slow) * 6) = 2160 ms: the door sequence takes the first 46% (about 1 s, done before
   AUTH_MIN_BUSY_MS), the door then rests closed, and the figure fades back in at its start (88-100%). */
@keyframes door-leaf {
  0% { transform: scaleX(1); }
  11%, 35% { transform: scaleX(-.45); }
  46%, 100% { transform: scaleX(1); }
}
@keyframes door-light {
  0% { opacity: 0; }
  11%, 35% { opacity: .6; }
  46%, 100% { opacity: 0; }
}
@keyframes door-walk {
  0%, 8% { opacity: 1; transform: translateX(0); }
  28% { opacity: 1; transform: translateX(16px); }
  34%, 87% { opacity: 0; transform: translateX(20px); }
  88% { opacity: 0; transform: translateX(0); }
  100% { opacity: 1; transform: translateX(0); }
}
/* Track UI U4: OTP design preview (its own URL, signed out only). Auth-screen motion exception: transform and
   opacity only, --motion-* tokens, existing colour tokens, no shadow, gradient or glass. Four 56x64 boxes 12px apart
   (centres at -102/-34/34/102px); each typed digit gets the accent ring. After the fourth digit the boxes fan out like a
   hand of cards and collapse into one stack (calc(var(--motion-slow) * 2) = OTP_FAN_MS in otp-preview.js), then the top
   card shows a spinning arc (a bordered ring rotated with transform, not a dash offset), then turns --success with a
   check mark and a short particle burst. Reduced motion: no fan, spin or burst (see the media query below). */
.otp-banner { margin-bottom: var(--space-6); }
.otp-stage { position: relative; display: flex; height: 64px; justify-content: center; margin: var(--space-6) 0 var(--space-4); }
.otp-boxes { display: flex; gap: 12px; }
.otp-box { width: 56px; height: 64px; padding: 0; border: 1px solid var(--border-strong); border-radius: var(--radius-md); background: var(--surface); color: var(--text); font-size: 24px; font-weight: 650; text-align: center; transform-origin: center bottom; }
.otp-box:focus { border-color: var(--accent); }
.otp-box.is-filled { border-color: var(--accent); outline: 2px solid var(--accent); outline-offset: 0; }
/* B1 fix loop 1 (Mozart): keyboard focus on a filled box must differ from the "filled" ring: the global focus ring
   (2px accent, offset 2px) sits outside the box, so a focused filled box shows a gap between the two. */
.otp-box.is-filled:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.otp-panel h1:focus { outline: none; }
.otp-box[readonly] { cursor: default; }
.otp-stage.is-fanning .otp-box:nth-child(1) { animation: otp-fan-1 calc(var(--motion-slow) * 2) var(--motion-ease) forwards; }
.otp-stage.is-fanning .otp-box:nth-child(2) { animation: otp-fan-2 calc(var(--motion-slow) * 2) var(--motion-ease) forwards; }
.otp-stage.is-fanning .otp-box:nth-child(3) { animation: otp-fan-3 calc(var(--motion-slow) * 2) var(--motion-ease) forwards; }
.otp-stage.is-fanning .otp-box:nth-child(4) { animation: otp-fan-4 calc(var(--motion-slow) * 2) var(--motion-ease) forwards; }
.otp-stage.is-static .otp-boxes { opacity: 0; }
.otp-card { position: absolute; top: 0; left: calc(50% - 28px); z-index: 1; display: grid; width: 56px; height: 64px; place-items: center; border: 1px solid var(--accent); border-radius: var(--radius-md); background: var(--surface); color: white; opacity: 0; transform: scale(.92); pointer-events: none; transition: opacity var(--motion-base) var(--motion-ease), transform var(--motion-base) var(--motion-ease); }
.otp-stage.is-checking .otp-card, .otp-stage.is-verified .otp-card { opacity: 1; transform: scale(1); }
.otp-stage.is-verified .otp-card { border-color: var(--success); background: var(--success); }
.otp-spinner { grid-area: 1 / 1; width: 24px; height: 24px; border: 2px solid var(--accent-soft); border-top-color: var(--accent); border-radius: 50%; opacity: 0; }
.otp-stage.is-checking .otp-spinner { opacity: 1; animation: otp-spin calc(var(--motion-slow) * 2) linear infinite; }
.otp-check { grid-area: 1 / 1; opacity: 0; transform: scale(.6); transition: opacity var(--motion-base) var(--motion-ease), transform var(--motion-base) var(--motion-ease); }
.otp-stage.is-verified .otp-check { opacity: 1; transform: scale(1); }
.otp-particle { position: absolute; top: calc(50% - 3px); left: calc(50% - 3px); width: 6px; height: 6px; border-radius: 50%; background: var(--success); opacity: 0; }
.otp-particle:nth-child(3) { --otp-dx: 0px; --otp-dy: -46px; }
.otp-particle:nth-child(4) { --otp-dx: 40px; --otp-dy: -24px; }
.otp-particle:nth-child(5) { --otp-dx: 40px; --otp-dy: 24px; }
.otp-particle:nth-child(6) { --otp-dx: 0px; --otp-dy: 46px; }
.otp-particle:nth-child(7) { --otp-dx: -40px; --otp-dy: 24px; }
.otp-particle:nth-child(8) { --otp-dx: -40px; --otp-dy: -24px; }
.otp-stage.is-fanning.is-verified .otp-particle { animation: otp-burst calc(var(--motion-slow) * 2) var(--motion-ease) forwards; }
.otp-actions { display: grid; gap: var(--space-2); }
@keyframes otp-fan-1 {
  0% { transform: none; }
  45% { transform: translate(-10px, -8px) rotate(-16deg); }
  100% { transform: translateX(102px) rotate(-6deg); }
}
@keyframes otp-fan-2 {
  0% { transform: none; }
  45% { transform: translate(-4px, -12px) rotate(-6deg); }
  100% { transform: translateX(34px) rotate(-2deg); }
}
@keyframes otp-fan-3 {
  0% { transform: none; }
  45% { transform: translate(4px, -12px) rotate(6deg); }
  100% { transform: translateX(-34px) rotate(2deg); }
}
@keyframes otp-fan-4 {
  0% { transform: none; }
  45% { transform: translate(10px, -8px) rotate(16deg); }
  100% { transform: translateX(-102px) rotate(0deg); }
}
@keyframes otp-spin {
  to { transform: rotate(360deg); }
}
@keyframes otp-burst {
  0% { opacity: 1; transform: translate(0, 0) scale(1); }
  100% { opacity: 0; transform: translate(var(--otp-dx), var(--otp-dy)) scale(.4); }
}
.inline-error { margin-bottom: var(--space-4); padding: 10px 12px; border-left: 3px solid var(--danger); background: var(--danger-soft); color: var(--danger); }
.auth-notice { margin-bottom: var(--space-4); padding: 10px 12px; border-left: 3px solid var(--info); background: var(--info-soft); color: var(--info); }
.inline-notice { margin-bottom: var(--space-4); padding: 10px 12px; border-left: 3px solid var(--info); background: var(--info-soft); color: var(--info); }
.field > .inline-error, .field > .inline-notice, .field > .inline-success { margin-bottom: 0; overflow-wrap: anywhere; }
.inline-success { margin-bottom: var(--space-4); padding: 10px 12px; border-left: 3px solid var(--success); background: var(--success-soft); color: var(--success); }
.toast-root { position: fixed; right: var(--space-5); bottom: var(--space-5); z-index: 60; }
.toast { display: flex; max-width: min(420px, calc(100vw - 2 * var(--space-5))); align-items: center; gap: var(--space-2); padding: 10px 14px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--text); color: white; box-shadow: var(--shadow-float); }
/* B2 review (Mozart): an error toast stays until closed; its Close button is a 44x44 target inside the toast padding. */
.toast-dismiss { display: grid; width: 44px; height: 44px; flex: none; place-items: center; margin: -10px -10px -10px 0; padding: 0; border: 0; border-radius: var(--radius-sm); background: transparent; color: inherit; }
.toast-dismiss svg { width: 16px; height: 16px; }
.settings-block { max-width: 620px; padding: var(--space-5) 0; border-bottom: 1px solid var(--border); }
.settings-form { max-width: 400px; }
.visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0; }
.attribute { position: relative; }
.attribute-override { padding-left: var(--space-3); border-left: 2px solid var(--accent); }
.attribute-edit { display: inline-flex; margin-top: 5px; margin-left: var(--space-3); padding: 0; border: 0; background: none; color: var(--text-secondary); font-size: 12px; }
.attribute-edit:hover { color: var(--accent); }
.override-item { position: relative; }
textarea.control { min-height: 72px; padding: 8px 12px; resize: vertical; font: inherit; }
.range-fields { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-2); }
/* B2 review (Mozart): the read-only "Currency: Rp" text takes its own row under the two amounts. */
.range-fields .range-note { grid-column: 1 / -1; }
/* B2 fix loop 2 (P7): two amounts (with or without the "Currency: Rp" note) share a row of two; one column on a phone
   (app.css 780px rule), so each amount field is wide enough. */
.range-fields.range-fields-pair { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.drawer-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--space-2); margin-top: var(--space-2); }
.conflict-banner { margin: var(--space-5) 0; padding: 10px 12px; border-left: 3px solid var(--warning); background: var(--warning-soft); color: var(--warning); }
.conflict-banner p { margin: 0 0 6px; }
.conflict-banner .btn-secondary { color: var(--text); }
.override-active-block { margin: var(--space-5) 0; padding: var(--space-4); border-left: 3px solid var(--accent); background: var(--accent-soft); }
.override-active-block .field { margin-bottom: var(--space-3); }
.review-actions { display: grid; gap: var(--space-3); max-width: 480px; }
.review-actions .drawer-actions { justify-content: flex-start; }
/* B2 review (Mozart): the consequence sentence and the reason field take a whole row; the buttons wrap below. */
.review-actions .drawer-actions > p, .review-actions .drawer-actions > textarea { flex: 1 1 100%; margin: 0; }
/* Batch B3 P4: a visible warning block (same geometry as .inline-error / .inline-notice, warning tokens): the
   one-time link warning and the "customers stay with this agent" block above the deactivate button. */
.inline-warning { margin-bottom: var(--space-4); padding: 10px 12px; border-left: 3px solid var(--warning); background: var(--warning-soft); color: var(--warning); }
/* Batch B3 P4: Team page. Two plain tables (members, invites) captioned by their h2 (aria-labelledby); the actions
   column header is visually hidden; every row button is a 44px target. Not clickable rows (no hover/pointer). */
.team-section { margin-bottom: var(--space-8); }
.team-section h2:focus, .page-header h1:focus, .link-heading:focus, #link-once-title:focus { outline: none; }
.team-surface { overflow-x: auto; } /* a safety net only: the table itself fits (fix loop 1, MED-1) */
/* B3 fix loop 2 (Lynelle MED-A): a fixed layout at every width, so the column widths no longer depend on the text
   (an auto layout let "overflow-wrap: anywhere" shrink Role/Status to one letter). Role and Status are as wide as
   their longest word and never wrap; the actions column is as wide as its widest button; Name and Email share the
   rest. Only an email wraps anywhere; a name wraps at spaces and breaks a word only when that word alone is wider
   than its column (a long unbroken name, or the email shown when the name is empty). */
.team-table { width: 100%; border-collapse: collapse; table-layout: fixed; }
.team-table th, .team-table td { overflow-wrap: break-word; }
.team-table .team-col-email, .team-invites .primary-cell, .team-inline { overflow-wrap: anywhere; }
.team-table .team-col-role, .team-table .team-col-status { white-space: nowrap; }
/* Widths measured in Chrome on macOS (EN and ID) plus 32px padding and a margin: the longest Role word ("Leader"
   44px), the widest status badge ("Deactivated" 96px; invites "Waiting to be used" 132px), the "Valid until" /
   "Berlaku sampai" date, and the widest row button ("Buat tautan atur ulang" 181px). */
.team-members .team-col-role { width: 88px; }
.team-members .team-col-status { width: 136px; }
.team-invites .team-col-status { width: 176px; }
.team-table .team-col-expires { width: 160px; }
.team-table .team-actions-cell { width: 216px; }
.team-table th { padding: 10px 16px; border-bottom: 1px solid var(--border); background: var(--surface-subtle); color: var(--text-secondary); font-size: 11px; font-weight: 650; letter-spacing: .04em; text-align: left; text-transform: uppercase; }
.team-table td { height: 64px; padding: 10px 16px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.team-table tr:last-child td { border-bottom: 0; }
/* Fix loop 2: an inline block, so "(you)" can move to the next line as a whole instead of being split from or
   glued to the last word of the name (there is no space between them in the markup). */
.team-you { display: inline-block; margin-left: 6px; color: var(--text-secondary); font-weight: 400; white-space: nowrap; }
.team-inline { display: none; }
.team-actions-cell { text-align: right; }
/* Fix loop 2: the row buttons stack at every width (the actions column is fixed); a label that does not fit (a
   wider fallback font) wraps at a space inside its button instead of leaving it. */
.team-actions { display: flex; flex-direction: column; align-items: stretch; gap: var(--space-2); }
.team-action { min-height: 44px; white-space: normal; }
.team-leader-row { font-size: 12px; }
.team-empty { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); margin-top: var(--space-4); color: var(--text-secondary); }
.team-empty p { margin: 0; }
.team-invite, .team-invite-drawer .btn, .team-invite-drawer .control, .link-once .btn, .team-confirm .btn { min-height: 44px; }
.team-invite-drawer .icon-button { width: 44px; height: 44px; }
.team-hint { max-width: 620px; }
/* The one-time link panel (Style Guide 11 exception: Escape and the backdrop do not close it). Tab order: heading,
   Copy, Done, then the close button, which CSS places at the top right. The close confirm sits on top of the panel
   at its bottom edge (sticky), the panel content inert behind it. */
.link-once { padding-top: var(--space-6); }
.link-once .drawer-head { padding-right: 52px; }
.link-once-close { position: absolute; top: var(--space-6); right: var(--space-6); width: 44px; height: 44px; }
.link-once-content { padding-top: var(--space-5); }
.link-once-note { margin-bottom: var(--space-3); }
.link-once-field { margin-top: var(--space-4); }
.link-once-value { min-height: 44px; font-size: 13px; } /* after .control, so the 44px target wins */
.link-once-hint { margin: 0; font-size: 12px; }
.link-once-status { min-height: 20px; margin: 0 0 var(--space-2); color: var(--text-secondary); font-size: 13px; }
.link-once-actions { justify-content: flex-start; }
.link-once-confirm { position: sticky; bottom: 0; margin: var(--space-5) calc(var(--space-6) * -1) 0; padding: var(--space-5) var(--space-6); border-top: 1px solid var(--border-strong); background: var(--surface); }
.link-once-confirm p { margin-bottom: var(--space-3); font-weight: 630; }
/* B3 fix loop 3: a Team overlay's heading, confirm text and link notes may carry a long email (or the email shown as
   the name), one unbroken token: it wraps anywhere so the drawer never scrolls sideways. Scoped to these overlays
   (global headings keep their wrapping); min-width: 0 lets the heading block shrink inside the flex drawer head. */
.team-invite-drawer .drawer-head > div, .team-confirm .drawer-head > div, .link-once .drawer-head > div { min-width: 0; }
.team-invite-drawer .drawer-head h2, .team-confirm .drawer-head h2, .link-once .drawer-head h2, .team-confirm-content, .link-once-note { overflow-wrap: anywhere; }
/* Batch B3 P4: join / reset screens (auth-screen language) and the signed-in notice. */
.link-panel .link-back.btn-link { min-height: 44px; margin-top: var(--space-2); }
.link-panel .inline-error, .link-panel .inline-notice { overflow-wrap: anywhere; }
.link-status { text-align: left; }
.setup-token-help { margin: calc(var(--space-3) * -1) 0 var(--space-4); font-size: 12px; }
.link-signed-in { max-width: 520px; }
.link-signed-in .btn { min-height: 44px; margin-top: var(--space-4); }
/* Batch F5-2: Team Intelligence (only while /api/me says team_intelligence). The Team page tabs (ARIA tabs): the
   selected tab looks like the selected nav item (accent tint and text, never colour alone: aria-selected and the
   weight change too); 44px targets. No new colour, shadow or motion. */
.team-tabs { display: flex; flex-wrap: wrap; gap: var(--space-1); margin-bottom: var(--space-6); padding-bottom: var(--space-2); border-bottom: 1px solid var(--border); }
.team-tab { min-height: 44px; padding: 0 var(--space-4); border: 0; border-radius: var(--radius-sm); background: transparent; color: var(--text-secondary); font-weight: 600; }
.team-tab:hover { background: var(--surface-muted); color: var(--text); }
.team-tab[aria-selected="true"] { background: var(--accent-soft); color: var(--accent); font-weight: 680; }
.team-member-link { display: inline-flex; min-height: 44px; align-items: center; color: var(--accent); text-underline-offset: 2px; }
/* The sales database: one .customer-list table (Name with the summary under it, Held by, Last activity). Rows are
   not links (read-only Team Intelligence), so no pointer and no hover tint. */
.salesdb-intro, .member-counts, .member-personal-intro { max-width: 650px; }
.salesdb-toolbar { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--space-3) var(--space-4); margin-bottom: var(--space-4); }
.salesdb-toolbar .field { margin-bottom: 0; }
.salesdb-toolbar .control, .salesdb-toolbar .btn { min-height: 44px; }
.salesdb-search { flex: 1 1 280px; min-width: 0; max-width: 520px; }
.salesdb-search-row { display: flex; gap: var(--space-2); }
.salesdb-search-row .search-wrap { flex: 1; width: auto; min-width: 0; }
.salesdb-search-row .search-wrap svg { top: 14px; }
.salesdb-table tbody tr { cursor: default; }
.salesdb-table tbody tr:hover { background: transparent; }
.salesdb-table .primary-cell, .member-company .primary-cell, .member-personal-list li { overflow-wrap: break-word; }
.salesdb-table .salesdb-col-holder { width: 28%; }
.salesdb-table .salesdb-col-activity { width: 20%; }
.salesdb-col-holder .status { margin-left: 6px; }
.salesdb-inline { display: none; }
.salesdb-inline-label { font-weight: 620; }
.salesdb-inline-badge { display: inline-block; margin-left: 6px; }
.team-more-slot { margin-top: var(--space-4); }
.team-more { min-height: 44px; }
.team-ti-notice { padding: var(--space-6) 0; }
.team-ti-notice .inline-notice { max-width: 620px; }
.team-ti-notice .btn { min-height: 44px; }
/* The member page: the counts are one plain sentence line (not metrics); the "not movable yet" line is plain text
   in --text-secondary (never a tooltip, never a disabled button). */
.member-title { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); margin-bottom: var(--space-2); }
.member-title h1 { margin-bottom: 0; overflow-wrap: anywhere; }
.member-title-badge:empty { display: none; }
.member-counts { margin-bottom: var(--space-6); }
.member-company .team-col-stage { width: 120px; }
.member-company .team-col-followup { width: 180px; }
.member-not-yet { margin: 0; color: var(--text-secondary); font-size: 12px; text-align: left; }
.member-personal-list { margin: 0; padding-left: var(--space-5); }
.member-personal-list li { padding: var(--space-1) 0; }
.member-detail .btn, .salesdb .btn, .member-back { min-height: 44px; }
.transfer-field { margin: var(--space-4) 0 0; }
.transfer-field .control { width: 100%; min-height: 44px; }
/* Batch F5-3: the Share drawer (Customers page, Leader, Team Intelligence on). One drawer, two steps; every row,
   the acknowledgement and every button is a 44px target; names wrap (no sideways scroll at 320px). No new colour,
   shadow or motion. */
.share-bar { margin: calc(var(--space-2) * -1) 0 var(--space-4); }
.share-bar .btn { min-height: 44px; }
.share-none { margin: 0; }
.share-drawer .drawer-head > div { min-width: 0; }
.share-drawer .drawer-head h2, .share-step { overflow-wrap: anywhere; }
.share-drawer .icon-button, .share-drawer .btn, .share-drawer .control { min-height: 44px; }
/* F5 fix loop 1 (Lynelle D6): never shrunk by a long title in the flex head (it measured 36-42px at 320/375). */
.share-drawer .icon-button { width: 44px; height: 44px; min-width: 44px; flex: none; }
.share-agents-status:not(:empty) { margin-top: var(--space-2); }
.share-agents-status .btn { margin-top: var(--space-2); }
.share-step { padding-top: var(--space-5); }
.share-drawer h2:focus { outline: none; } /* focused by script (step headings, tabindex -1), like the Team headings */
.share-fieldset { margin: var(--space-4) 0 0; padding: 0; border: 0; }
.share-fieldset legend { margin-bottom: var(--space-2); padding: 0; color: var(--text-secondary); font-size: 12px; font-weight: 620; }
.share-list { margin: 0; padding: 0; border-top: 1px solid var(--border); list-style: none; }
.share-list li { border-bottom: 1px solid var(--border); }
.share-option, .share-ack { display: flex; min-height: 44px; align-items: center; gap: var(--space-3); cursor: pointer; }
.share-option input, .share-ack input { width: 16px; height: 16px; flex: none; margin: 0; accent-color: var(--accent); }
.share-ack { margin: var(--space-4) 0; font-weight: 600; }
.share-more-slot { margin-top: var(--space-3); }
.share-count { margin: var(--space-4) 0 var(--space-2); font-weight: 600; }
.share-field { margin: var(--space-4) 0 var(--space-2); }
.share-field .control { width: 100%; }
.share-reason { margin: 0 0 var(--space-2); font-size: 13px; }
/* F5-3: the sign-in screen's "Forgot password?" link (44px target) and the join / reset screens' address shown as
   text with the own-address warning. */
.auth-forgot { display: inline-flex; min-height: 44px; align-items: center; margin-top: var(--space-2); padding: 0; text-decoration: none; }
.auth-forgot:hover { background: transparent; text-decoration: underline; }
.link-email { margin-bottom: var(--space-4); }
.link-email-label { margin: 0 0 4px; color: var(--text-secondary); font-size: 12px; font-weight: 620; }
.link-email-value { margin: 0 0 var(--space-3); font-weight: 600; overflow-wrap: anywhere; }
.link-email-own { margin-bottom: 0; }
.forgot-done { overflow-wrap: anywhere; }
.forgot-panel .btn-secondary.link-back { min-height: 44px; }
@media (max-width: 1050px) {
  .detail-grid { grid-template-columns: 1fr; }
  /* B3 fix loop 2 (Lynelle MED-A): from tablet width down (iPad portrait 820px included) the Team tables keep only
     Name/Email plus the actions: email and status move under the name (the hidden columns are display:none, so
     nothing is read twice). Between 781 and 1050px the five columns did not fit beside the 232px sidebar. */
  .team-table .team-col-email, .team-table .team-col-role, .team-table .team-col-status, .team-table .team-col-expires { display: none; }
  .team-inline { display: block; margin-top: 4px; }
  /* F5-2: the member page's company table drops Stage and Last follow-up from tablet width down (shown under the name). */
  .member-company .team-col-stage, .member-company .team-col-followup { display: none; }
  .conversation-pane { position: static; max-height: none; }
  .conversation-scroll { max-height: 620px; }
}
@media (max-width: 780px) {
  :root { --sidebar-width: 0px; }
  .app-shell { padding: 0; }
  .sidebar { position: static; width: 100%; padding: var(--space-3); border-right: 0; border-bottom: 1px solid var(--border); }
  .wordmark { min-height: 44px; padding: 4px 6px; }
  a.wordmark { margin-bottom: var(--space-3); }
  .home-secondary { gap: var(--space-1) var(--space-5); }
  .nav-list { display: flex; overflow-x: auto; }
  .nav-item { width: auto; white-space: nowrap; }
  .nav-break, .account, .nav-item:disabled { display: none; }
  .page { padding: var(--space-6) var(--space-4); }
  .page-header, .customer-header { align-items: flex-start; flex-direction: column; }
  .summary-strip { grid-template-columns: repeat(2, 1fr); }
  .summary-item:nth-child(2) { border-right: 0; }
  .summary-item:nth-child(-n+2) { border-bottom: 1px solid var(--border); }
  .summary-item:nth-child(3) { padding-left: 0; }
  .toolbar { align-items: stretch; flex-direction: column; }
  select.control { width: 100%; }
  .customer-list th:nth-child(3), .customer-list td:nth-child(3), .customer-list th:nth-child(4), .customer-list td:nth-child(4) { display: none; }
  /* B2 fix loop 2 (P7): the Understanding badge moves under the customer's name (the column is hidden), so the
     list fits a 320px screen; narrower cells; the surface still scrolls if a long word does not fit. */
  .customer-list th:nth-child(5), .customer-list td:nth-child(5) { display: none; }
  .cell-status-inline { display: block; margin-top: 6px; }
  .customer-list th, .customer-list td { padding-right: 12px; padding-left: 12px; }
  .range-fields.range-fields-pair { grid-template-columns: 1fr; }
  .search-card { padding: var(--space-4); }
  .header-actions-wrap { flex-direction: row; align-items: center; justify-content: flex-start; }
  .pagination { gap: var(--space-2); }
  .pagination .btn { padding: 0 10px; }
  /* B2 review (Mozart): Category and Freshness are left out of the catalog list on a phone (the entry page has both).
     Fix loop 2: checked in Chrome; the table is already wider than a 375px screen without Freshness (458-468px in a
     341px surface), and Freshness would add 103-129px more sideways scroll, so it stays hidden. */
  .catalog-table th:nth-child(2), .catalog-table td:nth-child(2), .catalog-table th:nth-child(6), .catalog-table td:nth-child(6) { display: none; }
  /* B2 review (Mozart): 44px touch targets for the small text buttons and the icon buttons. */
  .evidence-link, .attribute-edit, .btn-link { min-height: 44px; align-items: center; }
  .btn-quiet { min-height: 44px; }
  .icon-button { width: 44px; height: 44px; }
  .attention-row { grid-template-columns: 1fr auto; }
  .attention-row > :nth-child(2), .attention-row > :nth-child(3) { display: none; }
  .attribute-grid { grid-template-columns: 1fr; }
  /* Batch B3 P4 (5.14 item 6): on a phone the Team tables show Name/Email plus the actions (columns hidden from
     1050px, above). Fix loop 1 (MED-1): a 128px actions column, so a long email can never push the buttons out;
     a long button label wraps inside its button. */
  .team-table th:last-child, .team-table td:last-child { width: 128px; }
  .team-table th, .team-table td { padding-right: 12px; padding-left: 12px; }
  .team-action { width: 100%; padding: 0 8px; white-space: normal; overflow-wrap: anywhere; }
  /* F5-2: on a phone the sales database keeps only Name; Held by and Last activity move under the name. */
  .salesdb-table .salesdb-col-holder, .salesdb-table .salesdb-col-activity { display: none; }
  .salesdb-inline { display: block; }
  .salesdb-search { flex-basis: 100%; max-width: none; }
  .salesdb-toolbar .salesdb-field { flex: 1 1 100%; }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { scroll-behavior: auto !important; animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
  .auth-submit.is-door-moving .door-leaf, .auth-submit.is-door-moving .door-light, .auth-submit.is-door-moving .door-walker { animation: none; }
  .float-box .float-label, .auth-submit-label, .auth-submit .door-art, .auth-submit .auth-submit-check { transition: none; }
  /* B1 fix loop 1: same specificity as the rules that start each animation (later wins), so they really stop. */
  .otp-stage.is-fanning .otp-box:nth-child(n), .otp-stage.is-checking .otp-spinner, .otp-stage.is-fanning.is-verified .otp-particle { animation: none; }
  .otp-particle { display: none; }
  .otp-card, .otp-check { transition: none; }
}
