* {
    box-sizing: border-box;
}

body {
    margin: 0;
    font-family: var(--zlowi-font);
    color: var(--zlowi-navy);
}

/* App shell (see components/sidebar.js, components/header.js): a fixed
   left rail plus a main column (shared page header + routed #view),
   replacing the old single top nav bar. */
#app-shell {
    display: flex;
    align-items: stretch;
    min-height: 100vh;
}

#sidebar {
    flex: none;
}

/* Onboarding (views/onboarding.js) is full-page, without the rail or the
   page header -- toggled by app.js on navigation. */
body.onboarding-mode #sidebar,
body.onboarding-mode #page-header {
    display: none;
}

#main-col {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    /* Matches the mockup's own content-area fill exactly (see sketch/Zlowi
       platform UI mockups/Zlowi Platform.dc.html's .z2 wrapper) -- a soft
       neutral tint behind the white cards (.home-card, .z2-tile, etc.),
       which .page-header paints over with its own solid white. */
    background: #f7f8fa;
    /* A full-width bar inside #view (e.g. the Record detail header, see
       .record-page-header) paints past #view's own edges; clip that to this
       column so it never reaches over the rail. clip, not hidden: it makes
       no scroll container, so sticky positioning inside still follows the
       page. */
    overflow-x: clip;
}

#view {
    max-width: 1100px;
    width: 100%;
    margin: 0 auto;
    padding: 24px 16px 48px;
    box-sizing: border-box;
}

/* Rail (see components/sidebar.js) -- dark, collapsible, Home/Records/
   Settings only (see sketch/Zlowi platform UI mockups/Zlowi Rail.dc.html's
   "mvp" prop). */
.rail {
    /* Sticky, not just tall: #app-shell isn't a scroll container of its own,
       so a page taller than the viewport (e.g. a long Record detail form)
       scrolls the whole document -- without this the rail would scroll away
       with it instead of staying put like the rest of the app chrome. */
    position: sticky;
    top: 0;
    height: 100vh;
    width: 220px;
    background: var(--zlowi-navy);
    display: flex;
    flex-direction: column;
    padding: 18px 0;
    box-sizing: border-box;
    transition: width 0.18s ease;
}

.rail-collapsed {
    width: 72px;
}

.rail-head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 0 16px 22px;
}

.rail-logo-link {
    display: flex;
    align-items: center;
    gap: 10px;
    text-decoration: none;
    flex: 1;
    min-width: 0;
}

.rail-logo-mark {
    height: 26px;
    width: 26px;
    flex: none;
    object-fit: contain;
}

.rail-logo-text {
    color: #fff;
    font-weight: 600;
    font-size: 16px;
    white-space: nowrap;
    overflow: hidden;
}

.rail-collapsed .rail-logo-text {
    display: none;
}

.rail-toggle {
    width: 26px;
    height: 26px;
    flex: none;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: rgba(255, 255, 255, 0.85);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    padding: 0;
}

.rail-toggle:hover {
    color: #fff;
}

.rail-nav {
    display: flex;
    flex-direction: column;
    gap: 3px;
    padding: 0 12px;
}

.rail-item {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 11px 14px;
    border-radius: 10px;
    font-size: 14px;
    color: #cbd5e1;
    text-decoration: none;
    transition:
        background 0.15s ease,
        color 0.15s ease;
}

.rail-collapsed .rail-item {
    justify-content: center;
    padding: 11px 0;
}

.rail-item:hover {
    background: rgba(255, 255, 255, 0.08);
    color: #fff;
}

.rail-item[aria-current="page"] {
    background: var(--zlowi-blue);
    color: #fff;
}

.rail-collapsed .rail-item-label {
    display: none;
}

/* Shared page header (see components/header.js): single row above #view --
   title (or Home's date + greeting), an optional search box and primary
   action, then Help and the profile menu -- mirrors sketch/Zlowi platform UI
   mockups/Zlowi Platform.dc.html turns 5a/2a. Replaces the old .topbar strip
   plus each view's own in-page header block (.home-header, the old
   .view-header + #new-extraction pairing in views/extractions.js). */
.page-header {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 18px 28px;
    border-bottom: 1px solid #eef1f5;
    background: #fff;
}

.page-header-title {
    flex: 1;
    min-width: 0;
}

.page-header-date {
    font-size: 12.5px;
    color: #8894a7;
}

.page-header-title h1 {
    margin: 0;
    font-size: 24px;
    font-weight: 700;
    letter-spacing: -0.02em;
}

.page-header-date + h1 {
    margin-top: 3px;
}

.page-header-search {
    position: relative;
    flex: none;
    width: 230px;
}

.page-header-search svg {
    position: absolute;
    left: 13px;
    top: 50%;
    transform: translateY(-50%);
    color: #8894a7;
    pointer-events: none;
}

.page-header-search input {
    width: 100%;
    padding: 10px 14px 10px 38px;
    border-radius: 10px;
    border: 1px solid #e2e8f0;
    font-family: inherit;
    font-size: 13.5px;
    color: var(--zlowi-navy);
    outline: none;
}

.page-header-search input:focus {
    border-color: var(--zlowi-blue);
    box-shadow: 0 0 0 3px rgba(33, 120, 201, 0.14);
}

/* #page-header-action is the header's primary action button (currently
   always "Upload Record" -- see components/header.js's primaryAction,
   which gives it class="button accent" for the mockup's blue -- see
   .button.accent above). Its shape (size/radius/shadow) is still scoped to
   this one id, not shared with .accent's other users (Start reviewing, a
   selected plan card), which don't want the same padding/shadow. */
#page-header-action {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 10px 16px;
    border-radius: 10px;
    font-weight: 600;
    box-shadow: 0 4px 14px rgba(26, 115, 255, 0.3);
}

/* Locked state (all free Records used -- see sketch/Zlowi platform UI
   mockups/Zlowi Platform.dc.html turn 5c): a dashed, muted button with the
   lock icon (see components/header.js's primaryAction.disabled branch) --
   aria-disabled, not the native disabled attribute, since this button stays
   clickable to toggle .page-header-action-popover below. */
#page-header-action[aria-disabled] {
    background: #f1f5f9;
    border-color: #c3cddb;
    border-style: dashed;
    color: #64748b;
    box-shadow: none;
    cursor: pointer;
}

/* .page-header-action-wrap is the positioning context for the popover below
   (see the mockup's own <div style="position:relative"> wrapper, turn 5c) --
   #page-header-action itself stays position:static. */
.page-header-action-wrap {
    position: relative;
    flex: none;
}

/* Matches the mockup's lockPop popover exactly (turn 5c) -- see
   components/header.js's lockPopoverHtml. */
.page-header-action-popover {
    position: absolute;
    top: calc(100% + 10px);
    right: 0;
    width: 306px;
    z-index: 20;
    background: #fff;
    border: 1px solid #e6ebf2;
    border-radius: 12px;
    box-shadow: 0 16px 34px rgba(15, 23, 42, 0.16);
}

.page-header-action-popover[hidden] {
    display: none;
}

.page-header-action-popover-arrow {
    position: absolute;
    top: -6px;
    right: 34px;
    width: 11px;
    height: 11px;
    background: #fff;
    border-left: 1px solid #e6ebf2;
    border-top: 1px solid #e6ebf2;
    transform: rotate(45deg);
}

.page-header-action-popover-inner {
    position: relative;
    padding: 15px 17px;
}

.page-header-action-popover-head {
    display: flex;
    align-items: flex-start;
    gap: 10px;
}

.page-header-action-popover-icon {
    width: 28px;
    height: 28px;
    flex: none;
    border-radius: 8px;
    background: #eef5ff;
    color: #1a73ff;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.page-header-action-popover-title {
    font-size: 13px;
    font-weight: 700;
    color: var(--zlowi-navy);
}

.page-header-action-popover-sub {
    font-size: 12.5px;
    color: #64748b;
    line-height: 1.5;
    margin-top: 3px;
}

.page-header-action-popover-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 13px;
}

.page-header-action-popover-actions .button {
    flex: 1;
    justify-content: center;
    padding: 8px 0;
    white-space: nowrap;
    text-decoration: none;
}

.page-header-action-popover-actions .button.primary {
    background: #1a73ff;
    border-color: #1a73ff;
}

.page-header-action-popover-actions .button.primary:hover {
    background: #0d5fe0;
    border-color: #0d5fe0;
}

.page-header-action-popover-actions #page-header-action-popover-dismiss {
    flex: none;
    padding: 8px 12px;
}

.page-header-profile {
    position: relative;
    flex: none;
}

.profile-toggle {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 3px;
    border: 1px solid #e2e8f0;
    border-radius: 999px;
    background: #fff;
    cursor: pointer;
    font-family: inherit;
}

.profile-toggle:hover {
    border-color: #c3cddb;
}

.profile-toggle svg {
    margin-right: 2px;
    color: #8894a7;
    flex: none;
}

.profile-avatar {
    width: 30px;
    height: 30px;
    flex: none;
    border-radius: 50%;
    background: var(--zlowi-navy);
    color: #fff;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 11.5px;
    font-weight: 700;
}

/* Matches the mockup's z2-icobtn exactly (see sketch/Zlowi platform UI
   mockups/Zlowi Platform.dc.html) -- same border/size/radius as
   .profile-toggle right next to it in the header, and reused by the Record
   detail page's own back arrow (see views/record-detail.js). */
.icon-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    flex: none;
    border-radius: 10px;
    border: 1px solid #e2e8f0;
    background: #fff;
    color: #475569;
    cursor: pointer;
    text-decoration: none;
}

.icon-button:hover {
    color: var(--zlowi-blue);
    border-color: #c3cddb;
}

.dropdown-menu[hidden] {
    display: none;
}

.dropdown-menu {
    position: absolute;
    top: calc(100% + 4px);
    right: 0;
    min-width: 160px;
    background: #fff;
    border: 1px solid #e0e0e0;
    border-radius: 6px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
    display: flex;
    flex-direction: column;
    padding: 4px;
    z-index: 10;
}

.dropdown-menu a {
    padding: 8px 12px;
    color: var(--zlowi-navy);
    text-decoration: none;
    border-radius: 4px;
    font-size: 14px;
}

.dropdown-menu a:hover {
    background: #f2f2f2;
}

/* .action-menu anchors a .dropdown-menu to its trigger (see
   components/action-menu.js) -- Record detail's "⋯" menu and its Approve
   split button. Items are buttons rather than links; groups are the
   per-PO-card slots, divided from Reject file by a rule. */
.action-menu {
    position: relative;
    flex: none;
}

.action-menu[hidden] {
    display: none;
}

.action-menu .dropdown-menu {
    min-width: 220px;
    z-index: 30;
}

.dropdown-menu-group {
    display: flex;
    flex-direction: column;
}

.dropdown-menu-group:empty,
.dropdown-menu-divider[hidden] {
    display: none;
}

.dropdown-menu-divider {
    height: 1px;
    margin: 4px 0;
    background: #eef1f5;
}

.dropdown-item {
    padding: 8px 12px;
    border: none;
    border-radius: 4px;
    background: none;
    color: var(--zlowi-navy);
    font: inherit;
    font-size: 14px;
    text-align: left;
    white-space: nowrap;
    cursor: pointer;
}

.dropdown-item:hover:not(:disabled) {
    background: #f2f2f2;
}

.dropdown-item:disabled {
    opacity: 0.45;
    cursor: not-allowed;
}

.dropdown-item--danger {
    color: #b00020;
}

.dropdown-item--danger:hover:not(:disabled) {
    background: #fef2f2;
}

/* A button with its alternatives behind a caret: the two halves read as
   one control. */
.split-button {
    display: inline-flex;
}

/* The two halves read as one button: square inner corners, no border
   between them (the main half drops its right border, the toggle its
   left), just a faint inset hairline. Selectors are .split-button-scoped so
   they outrank .button/.button.success's own radius and border-color. */
.split-button > .button:first-child {
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
    border-right-width: 0;
}

.split-button > .split-button-toggle {
    display: inline-flex;
    align-items: center;
    padding: 8px 9px;
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
    border-left-width: 0;
    box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.22);
}

.view-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 16px;
}

.button {
    font-size: 14px;
    padding: 8px 14px;
    border-radius: 6px;
    border: 1px solid #ccc;
    background: #fff;
    cursor: pointer;
}

.button.primary {
    background: var(--zlowi-navy);
    color: #fff;
    border-color: var(--zlowi-navy);
}

/* .accent is a second "primary" look, the mockup's own blue (see sketch/
   Zlowi platform UI mockups/Zlowi Platform.dc.html's z2-primary) rather
   than this app's default navy -- used wherever a button needs to match
   that specific blue: the header's Upload Record (#page-header-action),
   the review banner's Start reviewing, a selected plan card's Select
   button. Everywhere else, .primary's navy stays the default. */
.button.accent {
    background: #1a73ff;
    color: #fff;
    border-color: #1a73ff;
}

.button.accent:hover:not(:disabled) {
    background: #0d5fe0;
    border-color: #0d5fe0;
}

/* .tinted takes its color from --button-color (set inline from data, e.g.
   Record detail's Post button uses the Posted status's badge_color), so
   a data-driven color doesn't need a class per value. Hover darkens it. */
.button.tinted {
    background: var(--button-color);
    border-color: var(--button-color);
    color: #fff;
}

.button.tinted:hover:not(:disabled) {
    background: color-mix(in srgb, var(--button-color) 85%, #000);
    border-color: color-mix(in srgb, var(--button-color) 85%, #000);
}

/* Color-coded action variants (see views/record-detail.js's Save/Approve/
   Push to ERP buttons) -- plain .button stays the neutral default above. */

.button:disabled {
    opacity: 0.55;
    cursor: not-allowed;
}

/* The shared instant tooltip (tooltip.js) -- dark by default, the issue
   banner's red for data-tooltip-tone="danger". Its arrow points at the
   element's center (--tooltip-arrow-x, set per show). */
@keyframes tooltip-in {
    from {
        opacity: 0;
        transform: translateY(-2px);
    }
    to {
        opacity: 1;
        transform: none;
    }
}

.tooltip {
    --tooltip-bg: #0f172a;
    --tooltip-border: #0f172a;
    position: fixed;
    z-index: 1000;
    max-width: 300px;
    padding: 7px 10px;
    border: 1px solid var(--tooltip-border);
    border-radius: 8px;
    background: var(--tooltip-bg);
    color: #fff;
    font-size: 12.5px;
    font-weight: 500;
    line-height: 1.45;
    box-shadow: 0 6px 20px rgba(15, 23, 42, 0.14);
    pointer-events: none;
    animation: tooltip-in 0.12s ease-out;
}

.tooltip[data-tone="danger"] {
    --tooltip-bg: #fffafa;
    --tooltip-border: #f6d6d6;
    color: #7f1d1d;
}

.tooltip::before {
    content: "";
    position: absolute;
    left: calc(var(--tooltip-arrow-x, 50%) - 5px);
    width: 8px;
    height: 8px;
    background: var(--tooltip-bg);
    border: 1px solid var(--tooltip-border);
    transform: rotate(45deg);
}

.tooltip[data-placement="below"]::before {
    top: -5px;
    border-right: none;
    border-bottom: none;
}

.tooltip[data-placement="above"]::before {
    bottom: -5px;
    border-left: none;
    border-top: none;
}

/* A disabled control inside a [data-tooltip] wrapper passes hovers through
   to it (see tooltip.js) -- it isn't clickable anyway. */
[data-tooltip] :disabled {
    pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
    .tooltip {
        animation: none;
    }
}

/* .button--busy is a button disabled because its own action is running
   (busy-button.js's setButtonBusy) -- kept at full strength so its spinner
   reads as progress, not as unavailable. */
.button.button--busy:disabled {
    opacity: 1;
    cursor: progress;
}

.button.secondary {
    background: #fff;
    color: var(--zlowi-blue);
    border-color: var(--zlowi-blue);
}

.button.secondary:hover:not(:disabled) {
    background: #eef5ff;
}

.button.success {
    background: #17803d;
    color: #fff;
    border-color: #17803d;
}

.button.success:hover:not(:disabled) {
    background: #146633;
}

.button.danger {
    background: #fff;
    color: #b00020;
    border-color: #f0a3a3;
}

.button.danger:hover:not(:disabled) {
    background: #fef2f2;
    border-color: #dc2626;
}

.link-button {
    background: none;
    border: none;
    color: var(--zlowi-blue);
    cursor: pointer;
    font-size: 13px;
    padding: 0;
    margin-right: 8px;
}

.link-button:disabled {
    color: #b7bfca;
    cursor: not-allowed;
}

.data-table {
    width: 100%;
    border-collapse: collapse;
    background: #fff;
    border: 1px solid #e0e0e0;
    border-radius: 8px;
    overflow: hidden;
}

.data-table th,
.data-table td {
    text-align: left;
    padding: 10px 12px;
    border-bottom: 1px solid #eee;
    font-size: 14px;
}

.data-table th {
    color: #555;
    font-weight: 600;
    background: #fafafa;
}

.empty-state {
    color: #888;
    text-align: center;
}

.clickable-row {
    cursor: pointer;
}

.clickable-row:hover {
    background: #fafafa;
}

/* Every modal in the app shares the mockup's modal look (sketch/Zlowi
   platform UI mockups/Zlowi Platform.dc.html turn 5b): no border, a large
   radius and soft shadow over a dimmed navy backdrop, easing in. */
.add-connector-dialog,
.account-dialog,
.extraction-dialog,
.app-dialog {
    max-width: calc(100vw - 32px);
    border: none;
    border-radius: 18px;
    padding: 24px 26px;
    background: #fff;
    color: #0f172a;
    box-shadow: 0 24px 60px rgba(15, 23, 42, 0.28);
}

.add-connector-dialog,
.account-dialog {
    width: 380px;
}

.add-connector-dialog::backdrop,
.account-dialog::backdrop,
.extraction-dialog::backdrop,
.app-dialog::backdrop {
    background: rgba(15, 23, 42, 0.55);
}

@keyframes dialog-in {
    from {
        opacity: 0;
        transform: translateY(8px) scale(0.98);
    }
}

.add-connector-dialog[open],
.account-dialog[open],
.extraction-dialog[open],
.app-dialog[open] {
    animation: dialog-in 0.16s ease-out;
}

.add-connector-dialog h2,
.account-dialog h2,
.extraction-dialog h2,
.app-dialog h2 {
    margin: 0 0 4px;
    font-size: 19px;
    font-weight: 700;
    letter-spacing: -0.02em;
}

/* The message/confirm dialog (web/js/dialog.js's showMessage/
   openConfirmDialog -- the app's alert() and confirm()): a tinted icon
   beside the title and text, then its actions. */
.app-dialog {
    width: 420px;
}

.app-dialog-head {
    display: flex;
    align-items: flex-start;
    gap: 14px;
}

.app-dialog-icon {
    width: 34px;
    height: 34px;
    flex: none;
    border-radius: 10px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: #eef5ff;
    color: #1a73ff;
}

.app-dialog--error .app-dialog-icon {
    background: #fef2f2;
    color: #dc2626;
}

.app-dialog--confirm .app-dialog-icon {
    background: #fffaf2;
    color: #b45309;
}

.app-dialog-heading {
    flex: 1;
    min-width: 0;
    padding-top: 4px;
}

.app-dialog-body {
    margin-top: 6px;
    font-size: 13.5px;
    line-height: 1.5;
    color: #475569;
    overflow-wrap: break-word;
}

.app-dialog-form {
    margin-top: 16px;
}

.app-dialog .dialog-actions {
    margin-top: 20px;
}

.app-dialog-form .dialog-actions {
    margin-top: 4px;
}

.account-dialog h3 {
    margin: 0 0 4px;
    font-size: 14px;
}

.account-dialog hr,
.add-connector-dialog hr {
    border: none;
    border-top: 1px solid #eef1f5;
    margin: 18px 0;
}

.row-inactive {
    color: #999;
}

.copy-field {
    display: flex;
    align-items: center;
    gap: 8px;
}

.copy-field input {
    flex: 1;
    font-size: 13px;
    padding: 8px 11px;
    border: 1px solid #e2e8f0;
    border-radius: 9px;
    color: #475569;
    background: #f8fafc;
}

.dialog-subtitle {
    margin: 0 0 18px;
    color: #64748b;
    font-size: 13px;
    line-height: 1.5;
}

.connector-choices {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.connector-choice {
    display: flex;
    align-items: center;
    gap: 12px;
    text-align: left;
    padding: 12px 14px;
    border: 1px solid #e2e8f0;
    border-radius: 12px;
    background: #fff;
    cursor: pointer;
    font-family: inherit;
    font-size: 14px;
    color: #0f172a;
}

.connector-choice:hover {
    border-color: #1a73ff;
    background: #f7fbff;
}

.connector-choice-name {
    display: block;
    font-weight: 600;
}

.connector-choice-desc {
    display: block;
    margin-top: 2px;
    font-size: 12px;
    color: #8894a7;
}

/* A connector type's logo (connectors.logo_url) or initials badge -- see
   add-connector-dialog.js's connectorLogoHtml. */
.connector-logo {
    width: 38px;
    height: 38px;
    flex: none;
    border-radius: 10px;
    background: #eef5ff;
    color: #1454c0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    font-weight: 700;
    overflow: hidden;
}

.connector-logo img {
    width: 100%;
    height: 100%;
    object-fit: contain;
}

.connector-logo--muted {
    background: #f1f5f9;
    color: #64748b;
}

.form-field {
    display: flex;
    flex-direction: column;
    gap: 5px;
    margin-bottom: 14px;
    font-size: 13px;
    color: #334155;
}

/* A field's own label text (its leading <span>). */
.form-field > span:first-child {
    font-weight: 600;
}

/* Dialog form controls -- the same look as the review grid's inputs (see
   .mapping-select), blue focus ring included. */
.form-field input {
    font-family: inherit;
    font-size: 14px;
    padding: 9px 12px;
    border: 1px solid #e2e8f0;
    border-radius: 9px;
    color: #0f172a;
    outline: none;
}

.form-field input:focus,
.form-field select:focus {
    border-color: #1a73ff;
    box-shadow: 0 0 0 3px rgba(26, 115, 255, 0.14);
}

.form-field input:disabled {
    background: #f8fafc;
    color: #94a3b8;
}

/* Selects had no styling of their own before -- bare browser-default
   appearance, noticeably shorter than the text inputs above. A bit taller
   than .form-field input's own padding (not just matching it) since a
   select's chevron/label needs a little more breathing room to read well. */
.form-field select {
    width: 100%;
    font-size: 14px;
    font-family: inherit;
    padding: 10px 12px;
    border: 1px solid #e2e8f0;
    border-radius: 9px;
    background: #fff;
    color: #0f172a;
    outline: none;
}

/* Upload dialog's Type/Connector/Transaction Type pickers (see
   new-extraction-dialog.js) -- side by side instead of stacked, since most
   accounts only ever have one or two of these actually visible (the rest
   auto-hide when there's just a single option -- see pickerHtml). */
.upload-picker-row {
    display: flex;
    gap: 12px;
    margin-bottom: 4px;
}

.upload-picker-row > * {
    flex: 1;
    min-width: 0;
}

.upload-picker-row .form-field {
    margin-bottom: 8px;
}

.form-field-checkbox {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 14px;
    font-size: 13px;
    color: #334155;
}

.form-field-checkbox input {
    width: auto;
}

.form-error {
    color: #b00020;
    font-size: 13px;
    margin: 0 0 12px;
}

.form-hint {
    color: #64748b;
    font-size: 12.5px;
    line-height: 1.5;
    margin: 0 0 12px;
}

.dialog-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    margin-top: 12px;
}

/* Extraction pipeline (see sketch/app/apphome2.wire, apphome3.wire).
   .extraction-dialog itself is just the "New Extraction" file-picker dialog
   now; the progress checklist / mapping review / summary classes further
   down (.checklist, .review-object, .mapping-row, ...) are shared with the
   Record detail page (views/record-detail.js), which used to be this same
   dialog before it became a full page (see .record-page below). */

.extraction-dialog {
    width: 480px;
    max-height: calc(100vh - 64px);
    overflow-y: auto;
}

/* Wider than the base .extraction-dialog -- the dropzone and (on a first
   upload) the "How it works" 3-tile row both want more breathing room than
   the plain-form dialog ever needed. See new-extraction-dialog.js. */
.extraction-dialog--upload {
    width: 560px;
}

.upload-dropzone {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    padding: 28px 20px;
    margin-bottom: 14px;
    border: 1.5px dashed #c3d4ef;
    border-radius: 12px;
    background: linear-gradient(180deg, #f7fbff, #fff);
    cursor: pointer;
    text-align: center;
}

.upload-dropzone:hover,
.upload-dropzone--dragover {
    border-color: var(--zlowi-blue);
    background: #f2f8ff;
}

.upload-dropzone--filled {
    border-style: solid;
    border-color: #22c55e;
}

.upload-dropzone-icon {
    width: 40px;
    height: 40px;
    border-radius: 11px;
    background: #eef5ff;
    color: var(--zlowi-blue);
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

/* While uploading (new-extraction-dialog.js's setUploading) the dropzone
   stops taking clicks/drops and shows a bar of the bytes sent; at 100% the
   bar shimmers while the server stores and scans the file. */
.upload-dropzone--uploading {
    pointer-events: none;
}

.upload-dropzone--uploading #browse-cta {
    display: none;
}

.upload-progress {
    width: 100%;
    max-width: 320px;
    height: 6px;
    border-radius: 999px;
    background: #e3ecf9;
    overflow: hidden;
}

.upload-progress-bar {
    display: block;
    height: 100%;
    width: 0;
    border-radius: inherit;
    background: #1a73ff;
    transition: width 0.2s ease-out;
}

.upload-progress--done .upload-progress-bar {
    background: linear-gradient(90deg, #1a73ff 0%, #6aa6ff 50%, #1a73ff 100%);
    background-size: 200% 100%;
    animation: progress-shimmer 1.6s linear infinite;
}

.upload-dropzone-text {
    font-size: 14px;
    font-weight: 600;
    color: var(--zlowi-navy);
}

.upload-dropzone-hint {
    font-size: 12px;
    color: #8894a7;
}

.upload-howitworks {
    margin: 4px 0 16px;
}

.upload-howitworks-title {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #8894a7;
    margin-bottom: 10px;
}

.upload-howitworks-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: 10px;
}

.upload-tile {
    display: flex;
    gap: 8px;
    padding: 12px;
    border-radius: 10px;
    background: #fafbfc;
    border: 1px solid #eef1f5;
    font-size: 12px;
}

.upload-tile-num {
    flex: none;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: #eef5ff;
    color: #1454c0;
    font-size: 11px;
    font-weight: 700;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.upload-tile strong {
    display: block;
    font-size: 12.5px;
    margin-bottom: 3px;
}

.upload-tile p {
    margin: 0;
    color: #667;
    line-height: 1.4;
}

/* Shape only -- color is always inline now (see views/extractions.js's
   statusBadge and views/record-detail.js's statusPill), computed from the
   server's status_color (statuses.badge_color, migration 0036) rather than
   a modifier class hand-picked per status_id/is_critical. */
.status-badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 2px 8px;
    border-radius: 10px;
    font-size: 12px;
    font-weight: 600;
}

.status-badge-dot {
    width: 6px;
    height: 6px;
    flex: none;
    border-radius: 50%;
}

/* The round marker Home's setup checklist uses (views/home.js). */
.checklist-marker {
    width: 18px;
    height: 18px;
    border-radius: 50%;
    border: 2px solid #ccc;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
}

/* Record detail's state cards (record-detail.js's stateCardHtml): what the
   page shows while a Record is processing, or once it failed, was
   cancelled, approved or sent -- the review cards' white card with a
   tinted icon per tone. */
.state-card {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    padding: 18px 20px;
    background: #fff;
    border: 1px solid #eef1f5;
    border-radius: 14px;
}

.state-card-icon {
    width: 36px;
    height: 36px;
    flex: none;
    border-radius: 11px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: #eef5ff;
    color: #1a73ff;
}

.state-card--error .state-card-icon {
    background: #fef2f2;
    color: #dc2626;
}

.state-card--muted .state-card-icon {
    background: #f1f5f9;
    color: #64748b;
}

.state-card--ok .state-card-icon {
    background: #effaf4;
    color: #059669;
}

.state-card--ready .state-card-icon {
    background: #f3efff;
    color: #7c3aed;
}

.state-card-text {
    flex: 1;
    min-width: 0;
    padding-top: 2px;
}

.state-card-title {
    font-size: 15px;
    font-weight: 700;
    color: #0f172a;
}

.state-card-body {
    margin-top: 4px;
    font-size: 13px;
    line-height: 1.5;
    color: #64748b;
    overflow-wrap: break-word;
}

.state-card--error .state-card-body {
    color: #7f1d1d;
}

/* .spinner is the app's one loading ring -- inside a button it takes the
   button's own text color, so it works on navy, green and white alike. */
@keyframes spin {
    to {
        transform: rotate(360deg);
    }
}

.spinner {
    display: inline-block;
    width: 14px;
    height: 14px;
    margin-right: 8px;
    vertical-align: -2px;
    border-radius: 50%;
    border: 2px solid #c7dcff;
    border-top-color: #1a73ff;
    animation: spin 0.8s linear infinite;
    box-sizing: border-box;
}

.button .spinner {
    border-color: color-mix(in srgb, currentColor 30%, transparent);
    border-top-color: currentColor;
}

/* The progress card (record-detail.js's renderProgress): the file's type
   as its icon with a scan-line sweeping down it, an overall bar, then a
   connected stepper -- done (green check), current (pulsing dot), still to
   come (dashed ring). updateProgressInPlace only swaps classes and widths,
   so the transitions below actually get to run between polls. */
.progress-file-icon {
    position: relative;
    width: 100%;
    height: 100%;
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    border-radius: inherit;
}

.progress-file-icon svg {
    margin-top: -4px;
}

.progress-file-ext {
    position: absolute;
    bottom: 3px;
    font-size: 8px;
    font-weight: 800;
    letter-spacing: 0.04em;
}

@keyframes progress-scan {
    from {
        transform: translateY(-4px);
    }
    to {
        transform: translateY(38px);
    }
}

.progress-file-icon::after {
    content: "";
    position: absolute;
    left: 4px;
    right: 4px;
    top: 0;
    height: 2px;
    border-radius: 2px;
    background: #1a73ff;
    box-shadow: 0 0 8px 1px rgba(26, 115, 255, 0.55);
    animation: progress-scan 1.6s ease-in-out infinite alternate;
}

@keyframes progress-shimmer {
    from {
        background-position: 200% 0;
    }
    to {
        background-position: -200% 0;
    }
}

.progress-bar {
    height: 6px;
    margin-top: 14px;
    border-radius: 999px;
    background: #eef1f5;
    overflow: hidden;
}

.progress-bar span {
    display: block;
    height: 100%;
    width: 0;
    border-radius: inherit;
    background: linear-gradient(90deg, #1a73ff 0%, #6aa6ff 50%, #1a73ff 100%);
    background-size: 200% 100%;
    animation: progress-shimmer 2.4s linear infinite;
    transition: width 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}

.progress-steps {
    list-style: none;
    margin: 16px 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.progress-step {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: 12px;
    font-size: 13.5px;
    line-height: 20px;
    color: #94a3b8;
    transition: color 0.3s;
}

.progress-step-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

@keyframes progress-detail-in {
    from {
        opacity: 0;
        transform: translateY(-3px);
    }
    to {
        opacity: 1;
        transform: none;
    }
}

/* The current stage's description (statuses.description, migration 0039)
   -- only shown under the step that's running. */
.progress-step-detail {
    display: none;
    font-size: 12.5px;
    line-height: 1.45;
    font-weight: 400;
    color: #64748b;
}

.progress-step--current .progress-step-detail:not(:empty) {
    display: block;
    animation: progress-detail-in 0.3s ease-out;
}

/* The connector from each marker down to the next one: from under this
   marker to the next step's top (the list's 12px gap, minus 2px so it
   doesn't touch the next marker), however tall this step's text is --
   green once the step above it is done. */
.progress-step:not(:last-child)::before {
    content: "";
    position: absolute;
    left: 9px;
    top: 22px;
    bottom: -10px;
    width: 2px;
    border-radius: 1px;
    background: #e2e8f0;
    transition: background 0.4s;
}

.progress-step--done:not(:last-child)::before {
    background: #34d399;
}

.progress-step--done {
    color: #334155;
}

.progress-step--current {
    color: #0f172a;
    font-weight: 600;
}

.progress-step-marker {
    position: relative;
    width: 20px;
    height: 20px;
    flex: none;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    transition: background 0.3s, color 0.3s;
}

.progress-step--pending .progress-step-marker {
    border: 1.5px dashed #b6c0cd;
}

@keyframes progress-pop {
    from {
        transform: scale(0.4);
        opacity: 0;
    }
    to {
        transform: scale(1);
        opacity: 1;
    }
}

.progress-step--done .progress-step-marker {
    background: #effaf4;
    color: #059669;
}

.progress-step--done .progress-step-marker svg {
    width: 12px;
    height: 12px;
    animation: progress-pop 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}

@keyframes progress-pulse {
    0% {
        box-shadow: 0 0 0 0 rgba(26, 115, 255, 0.45);
    }
    100% {
        box-shadow: 0 0 0 9px rgba(26, 115, 255, 0);
    }
}

.progress-step--current .progress-step-marker {
    background: #eef5ff;
}

.progress-step--current .progress-step-marker::after {
    content: "";
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #1a73ff;
    animation: progress-pulse 1.4s ease-out infinite;
}

/* A failed stage (applyProgress's failed state): a red ✕ on the step that
   failed, and the card's scan-line and shimmer stop -- nothing's running. */
.progress-step--failed {
    color: #b91c1c;
    font-weight: 600;
}

.progress-step--failed .progress-step-marker {
    background: #fef2f2;
    color: #dc2626;
}

.progress-step--failed .progress-step-marker svg {
    animation: progress-pop 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.state-card--error .progress-file-icon::after {
    display: none;
}

.state-card--error .progress-bar span {
    background: #f87171;
    animation: none;
}

.progress-card[data-progress="finished"] .progress-bar span {
    background: #34d399;
    animation: none;
}

.progress-slow {
    margin: 14px 0 0;
    padding: 8px 12px;
    border-radius: 8px;
    background: #fffbeb;
    color: #92400e;
    font-size: 12.5px;
    line-height: 1.5;
}

.progress-slow a {
    color: inherit;
    font-weight: 600;
}

/* The review cards fading in once the progress card has finished (see
   record-detail.js's load, PROGRESS_FINISH_MS). */
@keyframes detail-body-enter {
    from {
        opacity: 0;
        transform: translateY(6px);
    }
    to {
        opacity: 1;
        transform: none;
    }
}

.detail-body--enter {
    animation: detail-body-enter 0.35s ease-out;
}

@media (prefers-reduced-motion: reduce) {
    .spinner,
    .progress-step-detail,
    .progress-step--failed .progress-step-marker svg,
    .detail-body--enter,
    .progress-file-icon::after,
    .progress-bar span,
    .progress-step--done .progress-step-marker svg,
    .progress-step--current .progress-step-marker::after {
        animation: none;
    }

    .progress-bar span,
    .progress-step,
    .progress-step:not(:last-child)::before,
    .progress-step-marker,
    .upload-progress-bar {
        transition: none;
    }
}

/* Record detail while a request is in flight (record-detail.js's
   setPageBusy): the inert parts dim a little, so it's visible that they're
   locked, not just unresponsive. */
.record-page--busy #detail-body,
.record-page--busy #record-more,
.record-page--busy .queue-nav,
.record-page--busy #record-banners {
    opacity: 0.6;
    transition: opacity 0.2s;
}

.record-page--busy {
    cursor: progress;
}

/* A PO's review card (see views/record-detail.js's renderObject) has no
   frame of its own: its toolbar and sections are separate white cards on
   the page's tinted background, as in the mockup (sketch/Zlowi platform UI
   mockups/Zlowi Platform.dc.html turn 3b). */
.review-object {
    margin-bottom: 24px;
}

/* .review-card is the card's own content (renderReviewCard/
   renderApprovedCard/renderCompletedCard's wrap); a failed PO's card
   (renderObject) holds its toolbar and error box directly. */
.review-object,
.review-card {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.review-card > .form-error,
.review-card > .form-hint {
    margin: 0;
}

/* The strip atop each card (cardToolbarHtml): destination (connector
   activation + transaction type), a pill, and on a review card the
   collapse/expand-all toggle. */
.review-toolbar {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    padding: 12px 18px;
    background: #fff;
    border: 1px solid #eef1f5;
    border-radius: 14px;
}

.review-toolbar-title {
    font-size: 12.5px;
    font-weight: 600;
    color: #334155;
}

/* Collapse all / Expand all (see record-detail.js's wireSectionsToggle),
   pushed to the toolbar's right edge. */
.sections-toggle {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 11px;
    border-radius: 999px;
    border: 1px solid #e2e8f0;
    background: #fff;
    font-family: inherit;
    font-size: 12px;
    color: #475569;
    cursor: pointer;
}

.sections-toggle:hover {
    border-color: #c3cddb;
    color: #0f172a;
}

/* Review sections (Order details / Letterhead / Bill to / Ship to / Line
   items), each a native <details> so expand/collapse needs no JS. */
.review-section {
    background: #fff;
    border: 1px solid #eef1f5;
    border-radius: 14px;
    overflow: hidden;
}

.review-section-header {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 14px 18px;
    font-size: 14px;
    font-weight: 700;
    cursor: pointer;
    list-style: none;
}

.review-section-header::-webkit-details-marker {
    display: none;
}

/* Collapse chevron, pushed to the right edge. */
.review-section-header::after {
    content: "";
    margin-left: auto;
    width: 7px;
    height: 7px;
    border-right: 1.8px solid #8894a7;
    border-bottom: 1.8px solid #8894a7;
    transform: rotate(-45deg);
    transition: transform 0.15s ease;
}

/* Right-aligned summary in a section header, e.g. Line items' "3 lines ·
   total 1,443.50" -- it takes the push to the right edge from the chevron. */
.review-section-meta {
    margin-left: auto;
    font-size: 12px;
    font-weight: 400;
    color: #8894a7;
}

.review-section-meta:empty {
    display: none;
}

.review-section-header:has(.review-section-meta:not(:empty))::after {
    margin-left: 12px;
}

.review-section[open] > .review-section-header::after {
    transform: rotate(45deg);
}

.review-section[open] > .review-section-header {
    border-bottom: 1px solid #f2f5f8;
}

/* Field-mapping grid: status / file field / mapped to / file value /
   destination value. */
.mapping-header-row,
.mapping-row {
    display: grid;
    grid-template-columns: 26px 1.15fr 1.15fr 1.1fr 1.25fr;
    gap: 14px;
    align-items: center;
    padding: 12px 18px;
    font-size: 13px;
    border-bottom: 1px solid #f6f8fa;
}

.mapping-row:last-child {
    border-bottom: none;
}

/* Column headers -- here and for the line items' summary grid. */
.mapping-header-row,
.review-line-header {
    padding: 9px 18px;
    background: #fbfcfd;
    border-bottom: 1px solid #f2f5f8;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #8894a7;
}

.mapping-label {
    min-width: 0;
    overflow-wrap: break-word;
    font-weight: 600;
    color: #0f172a;
}

.mapping-file-value {
    color: #64748b;
    min-width: 0;
    overflow-wrap: break-word;
}

.mapping-destination-value {
    position: relative;
    min-width: 0;
}

/* Inputs in the grid (and the lookup search's own, see
   components/lookup-search.js) -- the mockup's z2-inp/z2-sel. */
.mapping-select,
.mapping-value-input,
.lookup-search-input {
    width: 100%;
    font-family: inherit;
    font-size: 13px;
    padding: 8px 11px;
    border: 1px solid #e2e8f0;
    border-radius: 9px;
    background-color: #fff;
    color: #0f172a;
    outline: none;
}

.mapping-select:focus,
.mapping-value-input:focus,
.lookup-search-input:focus {
    border-color: #1a73ff;
    box-shadow: 0 0 0 3px rgba(26, 115, 255, 0.14);
}

/* Mapped To is a native <select> drawn like the mockup's z2-sel: no
   platform arrow, a thin chevron instead. */
.mapping-select {
    appearance: none;
    -webkit-appearance: none;
    padding-right: 32px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238894a7' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 11px center;
    background-size: 13px 13px;
    color: #334155;
    cursor: pointer;
}

.mapping-select:hover:not(:disabled) {
    border-color: #c3cddb;
}

.mapping-select:disabled,
.mapping-value-input:disabled {
    background-color: #f8fafc;
    color: #94a3b8;
    cursor: default;
}

/* A flagged row colors only the control that holds the problem (see
   paintRowStatus): Mapped To for a mapping issue (unmapped, or a required
   field left without one), the value box for a value issue (invalid,
   unresolved, or waiting to be confirmed) -- red for a blocker, amber for
   informational, like the mockup's bad/warn controls. */
.mapping-row--blocker.mapping-row--mapping-issue .mapping-select:not(:disabled),
.mapping-row--blocker.mapping-row--value-issue .mapping-destination-value input:not(:disabled) {
    border-color: #f0a3a3;
    background-color: #fffafa;
    color: #b91c1c;
}

.mapping-row--info.mapping-row--mapping-issue .mapping-select:not(:disabled),
.mapping-row--info.mapping-row--value-issue .mapping-destination-value input:not(:disabled) {
    border-color: #e8b667;
    background-color: #fffaf2;
    color: #7c4a06;
}

.mapping-row--blocker.mapping-row--mapping-issue .mapping-select:not(:disabled) {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23dc2626' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
}

.mapping-row--info.mapping-row--mapping-issue .mapping-select:not(:disabled) {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23b45309' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
}

.mapping-row-removed {
    opacity: 0.5;
}

/* Briefly marks the row the issue banner just jumped to. */
@keyframes mapping-row-flash {
    from {
        box-shadow: inset 3px 0 0 #1a73ff;
        background-color: #eef5ff;
    }
    to {
        box-shadow: inset 3px 0 0 transparent;
    }
}

.mapping-row--flash {
    animation: mapping-row-flash 1.6s ease-out;
}

/* The Line items section is the mockup's table (turn 3b): one
   .review-line-item per PO line -- a summary row (Item with its status /
   Description with the flagged field's note / Extras columns / Qty / Unit
   price / Amount / expand chevron) over that line's field-mapping grid
   (.review-line-detail, hidden until expanded). grid-template-columns is
   set inline, since the Extras columns vary per PO. */
.review-line-header,
.review-line-summary {
    display: grid;
    gap: 14px;
    align-items: center;
}

.review-line-item {
    border-bottom: 1px solid #f6f8fa;
}

.review-line-item:last-child {
    border-bottom: none;
}

.review-line-summary {
    padding: 12px 18px;
    font-size: 13px;
    color: #334155;
    cursor: pointer;
}

.review-line-summary:hover {
    background: #fbfcfd;
}

.review-line-item-cell {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    color: #0f172a;
}

.review-line-description {
    min-width: 0;
    overflow-wrap: break-word;
}

.review-line-description .mapping-note {
    display: block;
}

.review-line-description .mapping-note:empty {
    display: none;
}

.review-line-num {
    text-align: right;
}

.review-line-amount {
    font-weight: 700;
    color: #0f172a;
}

/* Qty/Unit price typed in the row itself -- same input as the grid's,
   right-aligned, colored by its field's status like the grid's value box. */
.review-line-input {
    text-align: right;
    padding: 6px 9px;
}

.review-line-num--blocker .review-line-input {
    border-color: #f0a3a3;
    background-color: #fffafa;
    color: #b91c1c;
}

.review-line-num--info .review-line-input {
    border-color: #e8b667;
    background-color: #fffaf2;
    color: #7c4a06;
}

.review-line-expand {
    width: 28px;
    height: 28px;
    padding: 0;
    border: none;
    border-radius: 8px;
    background: transparent;
    color: #8894a7;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}

.review-line-expand:hover {
    background: #eef1f5;
    color: #0f172a;
}

.review-line-expand svg {
    transition: transform 0.15s ease;
}

.review-line-item.is-open .review-line-expand svg {
    transform: rotate(180deg);
}

/* The line summary's status is a size down from a field row's, as in the
   mockup's line items. */
.review-line-summary .status-icon {
    width: 16px;
    height: 16px;
    flex: none;
}

.review-line-summary .status-icon svg {
    width: 10px;
    height: 10px;
}

.review-line-detail {
    margin: 0 18px 12px 42px;
    border: 1px solid #f2f5f8;
    border-radius: 10px;
    overflow: hidden;
}

/* Row validation status (see record-detail.js's classifyRow/refresh): a
   blocker prevents Approve, info doesn't. Colors match the mockup (see
   sketch/Zlowi platform UI mockups/Zlowi Platform.dc.html turn 3b). */
.status-icon {
    width: 20px;
    height: 20px;
    padding: 0;
    border: none;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
}

.status-icon--ok {
    background: #effaf4;
    color: #059669;
}

.status-icon--info {
    background: #fdefd8;
    color: #b45309;
}

.status-icon--blocker {
    background: #fee2e2;
    color: #dc2626;
}

.status-icon--removed {
    background: #f1f5f9;
    color: #94a3b8;
}

/* Only an actionable icon (delete/confirm/unmap) is clickable. */
button.status-icon:not(:disabled) {
    cursor: pointer;
}

button.status-icon:not(:disabled):hover {
    box-shadow: 0 0 0 3px rgba(180, 83, 9, 0.18);
}

button.status-icon--ok:not(:disabled):hover {
    box-shadow: 0 0 0 3px rgba(5, 150, 105, 0.18);
}

button.status-icon--blocker:not(:disabled):hover {
    box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.18);
}

.mapping-row--info {
    background: #fffdf8;
}

.mapping-row--blocker {
    background: #fffafa;
}

.mapping-note {
    font-size: 12px;
    font-weight: 400;
    margin-top: 2px;
}

.mapping-note:empty {
    display: none;
}

.mapping-note--ok {
    color: #8894a7;
}

.mapping-note--info {
    color: #b45309;
}

.mapping-note--blocker {
    color: #b91c1c;
}

.mapping-note--removed {
    color: #888;
    font-style: italic;
}

.mapping-empty {
    color: #b6c0cd;
}

.issue-pills {
    display: inline-flex;
    gap: 6px;
}

.issue-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 10px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 600;
    white-space: nowrap;
}

.issue-pill-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
}

.issue-pill--blocker {
    background: #fef2f2;
    color: #b91c1c;
}

.issue-pill--info {
    background: #fffaf2;
    color: #b45309;
}

.issue-pill--ok {
    background: #effaf4;
    color: #047857;
}

/* Type-ahead lookup search (web/js/components/lookup-search.js) -- the
   mapping-review screen's magnifying-glass search box for a lookup
   destination field, scoped to the matched customer for a field like Ship
   To (see domain.ScopedLookupSearcher). */

.lookup-search {
    position: relative;
}

/* Base look shared with the review grid's inputs (see .mapping-select);
   this adds the magnifying glass. */
.lookup-search-input {
    padding-left: 30px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23999' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: 10px center;
    background-size: 13px 13px;
}

.lookup-search-input:disabled {
    background-color: #f8fafc;
    color: #94a3b8;
}

/* The open results list -- a floating card in the review grid's style
   (see .mapping-select), with a hover/arrow-key highlight (.is-active). */
.lookup-search-results {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 20;
    margin-top: 4px;
    padding: 4px;
    max-height: 220px;
    overflow-y: auto;
    background: #fff;
    border: 1px solid #e2e8f0;
    border-radius: 10px;
    box-shadow: 0 12px 28px rgba(15, 23, 42, 0.12);
}

.lookup-search-results[hidden] {
    display: none;
}

.lookup-search-result {
    padding: 8px 10px;
    border-radius: 7px;
    font-size: 13px;
    color: #0f172a;
    cursor: pointer;
}

.lookup-search-result.is-active {
    background: #eef5ff;
    color: #1454c0;
}

.lookup-search-empty {
    padding: 8px 10px;
    font-size: 12.5px;
    color: #8894a7;
}

/* Shared stat tile (see views/extractions.js's Records stats row and
   views/home.js's KPI row -- same tile look in both places). */

.stat-tile {
    background: #fff;
    border: 1px solid #eee;
    border-radius: 10px;
    padding: 14px 16px;
}

.stat-tile-label {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    font-weight: 600;
    color: #667;
}

.stat-tile-label-dot {
    width: 6px;
    height: 6px;
    flex: none;
    border-radius: 50%;
}

.stat-tile-value {
    font-size: 24px;
    font-weight: 700;
    margin-top: 6px;
    color: var(--zlowi-navy);
}

.stat-tile-unit {
    font-size: 14px;
    color: #8894a7;
    font-weight: 500;
}

.stat-tile-sub {
    font-size: 11.5px;
    color: #8894a7;
    margin-top: 2px;
}

.stat-tile-bar {
    height: 5px;
    border-radius: 999px;
    background: #eef1f5;
    margin-top: 8px;
    overflow: hidden;
}

.stat-tile-bar span {
    display: block;
    height: 100%;
    background: var(--zlowi-blue);
    border-radius: 999px;
}

.pill {
    display: inline-flex;
    align-items: center;
    padding: 3px 10px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 600;
}

.pill--info {
    background: #eef5ff;
    color: var(--zlowi-blue);
}

.pill--neutral {
    background: #f1f5f9;
    color: #475569;
}

.pill--success {
    background: #effaf4;
    color: #047857;
}

/* A finished state that isn't a success -- e.g. a task closed as not
   required: outlined, not filled, so it never reads as Open. */
.pill--closed {
    background: none;
    box-shadow: inset 0 0 0 1px #e2e8f0;
    color: #94a3b8;
}

/* A dropdown dressed as a pill -- e.g. the activity filters (see
   components/activity-feed.js). */
.pill-select {
    appearance: none;
    -webkit-appearance: none;
    border: none;
    border-radius: 999px;
    background: #f1f5f9 url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='%23475569' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E") no-repeat right 9px center;
    color: #475569;
    font: inherit;
    font-size: 12px;
    font-weight: 600;
    padding: 3px 24px 3px 10px;
    cursor: pointer;
}

.pill-select:hover {
    background-color: #e8edf3;
}

/* Records list (see views/extractions.js) */

.records-stats {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 14px;
    margin-bottom: 16px;
}

.records-toolbar {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 14px;
}

.seg {
    display: inline-flex;
    padding: 3px;
    gap: 2px;
    background: #eef1f5;
    border-radius: 999px;
}

.seg-opt {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 7px 13px;
    border-radius: 999px;
    font-size: 13px;
    color: #64748b;
    cursor: pointer;
    border: none;
    background: transparent;
    font-family: inherit;
}

.seg-opt:hover {
    color: var(--zlowi-navy);
}

.seg-opt[aria-selected="true"] {
    background: #fff;
    color: var(--zlowi-navy);
    font-weight: 600;
    box-shadow: 0 1px 3px rgba(15, 23, 42, 0.1);
}

/* Count badge on the All/Needs review/Posted segmented options (see
   views/extractions.js's updateFilterCounts) -- color is set inline per
   badge (the status's own badge_color, or neutral gray for All), matching
   the mockup's own per-option color (sketch/Zlowi platform UI mockups/Zlowi
   Platform.dc.html turn 2a). */
.seg-opt-count {
    font-size: 11.5px;
    font-weight: 700;
}

/* Customer/Source/Date range dropdown chips (see views/extractions.js's
   filterChipHtml/wireFilterChip -- matches sketch/Zlowi platform UI
   mockups/Zlowi Platform.dc.html turn 2a's z2-chip). */
.filter-chip-wrap {
    position: relative;
}

.filter-chip {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 7px 13px;
    border-radius: 999px;
    border: 1px solid #e2e8f0;
    background: #fff;
    font-family: inherit;
    font-size: 12.5px;
    color: #475569;
    cursor: pointer;
}

.filter-chip:hover {
    border-color: #c3cddb;
    color: var(--zlowi-navy);
}

.filter-dropdown {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    min-width: 180px;
    max-height: 260px;
    overflow-y: auto;
    background: #fff;
    border: 1px solid #e0e0e0;
    border-radius: 8px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
    display: flex;
    flex-direction: column;
    padding: 4px;
    z-index: 10;
}

.filter-dropdown[hidden] {
    display: none;
}

.filter-dropdown button {
    display: block;
    width: 100%;
    text-align: left;
    padding: 8px 12px;
    border: none;
    background: none;
    border-radius: 4px;
    font-family: inherit;
    font-size: 13px;
    color: var(--zlowi-navy);
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.filter-dropdown button:hover {
    background: #f2f2f2;
}

.sort-toggle {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    border: none;
    background: none;
    font-family: inherit;
    font-size: 12.5px;
    color: #8894a7;
    cursor: pointer;
}

.sort-toggle:hover {
    color: var(--zlowi-navy);
}

.record-cell {
    display: flex;
    align-items: center;
    gap: 11px;
}

.record-cell-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.record-file {
    font-weight: 600;
    color: var(--zlowi-navy);
}

.record-type {
    font-size: 11.5px;
    color: #8894a7;
}

/* File-type badge (see views/extractions.js's fileTypeBadge) -- colors set
   inline per file type since they're data-driven, not a fixed set of CSS
   modifier classes. */
.file-type-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 32px;
    height: 32px;
    border-radius: 9px;
    font-size: 9.5px;
    font-weight: 700;
}

/* Source column (see views/extractions.js's sourceCell) -- an icon plus a
   two-line category/detail, replacing the single pill this used to be. */
.source-cell {
    display: flex;
    align-items: center;
    gap: 8px;
}

.source-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 24px;
    height: 24px;
    border-radius: 7px;
}

.source-icon--agent {
    background: #eef5ff;
    color: var(--zlowi-blue);
}

.source-icon--manual {
    background: #f1f5f9;
    color: #475569;
}

.source-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.source-label {
    font-size: 12.5px;
    font-weight: 600;
    color: #334155;
}

.source-detail {
    font-size: 11px;
    color: #8894a7;
    max-width: 150px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Records pagination footer (see views/extractions.js's renderPagination --
   sketch/Zlowi platform UI mockups/Zlowi Platform.dc.html, turn 2/2a's
   "Showing 8 of 104" / Previous / Next). Empty (zero height) when
   everything fits on one page. */
.records-pagination {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 14px 4px 0;
}

.records-pagination:empty {
    display: none;
}

.records-pagination-left {
    display: flex;
    align-items: center;
    gap: 10px;
}

.records-pagination-summary {
    font-size: 12.5px;
    color: #8894a7;
}

.records-page-size {
    padding: 4px 8px;
    border-radius: 6px;
    border: 1px solid #e2e8f0;
    background: #fff;
    font-family: inherit;
    font-size: 12px;
    color: #475569;
    cursor: pointer;
}

.records-pagination-buttons {
    display: flex;
    gap: 8px;
}

/* Record detail page (see views/record-detail.js) -- was a modal, now a
   full page reached at /web/records/:id. The header is one line, as in the
   mockup (turn 3b) -- back arrow, file name + status, a one-line summary,
   then Save/Approve (or Push to ERP) and the "⋯" menu -- with the
   issue banner under it, and stays sticky so a reviewer working through a
   long mapping form never has to scroll back up to act on it. */
/* Full width, like the mockup's header bar: the box itself stays in
   #view's column (so its content lines up with the cards below), and a
   spread shadow on its ::before layer (below) paints the white out to the
   main column's edges. The -24px top margin cancels #view's top
   padding, so the bar sits directly under the shared page header. */
.record-page-header {
    position: sticky;
    top: 0;
    z-index: 4;
    background: #fff;
    margin: -24px 0 20px;
    padding-top: 16px;
    display: flex;
    flex-direction: column;
}

/* Its bottom rule, full width the same way. */
.record-page-header::after {
    content: "";
    position: absolute;
    left: -100vmax;
    right: -100vmax;
    bottom: 0;
    height: 1px;
    background: #eef1f5;
}

/* The header's white band runs edge to edge (a shadow, which never adds
   scroll overflow, clipped to the header's height). It's on this layer, not
   the header itself, so the header doesn't clip its own dropdowns (the "⋯"
   menu, Approve's split button) where they hang below it. */
.record-page-header::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background: #fff;
    box-shadow: 0 0 0 100vmax #fff;
    clip-path: inset(0 -100vmax);
}

.record-page-header-top {
    display: flex;
    align-items: center;
    gap: 14px;
    padding-bottom: 16px;
}

.record-page-title {
    flex: 1;
    min-width: 0;
}

.record-page-title-row {
    display: flex;
    align-items: center;
    gap: 9px;
    flex-wrap: wrap;
}

.record-page-title-row h1 {
    margin: 0;
    font-size: 19px;
    letter-spacing: -0.01em;
}

.record-page-subtitle {
    display: flex;
    align-items: baseline;
    gap: 10px;
    margin-top: 3px;
    font-size: 12.5px;
    color: #8894a7;
}

/* One line, ellipsized -- see recordSubtitleHtml. */
.record-page-subtitle-text {
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.record-page-subtitle .link-button {
    flex: none;
    font-size: 12.5px;
    margin: 0;
}

.record-page-subtitle-dot {
    margin: 0 8px;
    opacity: 0.5;
}

/* Source panel (see components/source-panel.js): the Record's files beside
   the review form. Open, the page widens past #view's usual 1100px column
   and splits in two; the panel sticks under the sticky header (whose height
   wireSourcePanel keeps in --record-header-h) while the form scrolls. */
#view:has(.record-page--split) {
    max-width: 1680px;
}

.record-page--split .record-page-body {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(380px, 44%);
    gap: 20px;
    align-items: start;
}

.source-panel {
    position: sticky;
    top: calc(var(--record-header-h, 96px) + 16px);
    height: calc(100vh - var(--record-header-h, 96px) - 32px);
    display: flex;
    flex-direction: column;
    background: #fff;
    border: 1px solid #eef1f5;
    border-radius: 12px;
    overflow: hidden;
}

.source-panel[hidden] {
    display: none;
}

.source-tabs {
    display: flex;
    gap: 2px;
    padding: 6px 8px 0;
    border-bottom: 1px solid #eef1f5;
    overflow-x: auto;
    flex: none;
}

.source-tab {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    max-width: 220px;
    padding: 8px 10px;
    border: none;
    border-bottom: 2px solid transparent;
    background: none;
    font: inherit;
    font-size: 13px;
    color: #667;
    cursor: pointer;
    white-space: nowrap;
}

.source-tab:hover {
    color: var(--zlowi-navy);
}

.source-tab[aria-selected="true"] {
    color: var(--zlowi-navy);
    font-weight: 600;
    border-bottom-color: var(--zlowi-blue);
}

.source-tab-kind {
    flex: none;
    padding: 1px 5px;
    border-radius: 4px;
    background: #f1f4f8;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.02em;
    color: #5b6b82;
}

.source-tab-name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

.source-view {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

.source-view-toolbar {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 8px 12px;
    border-bottom: 1px solid #eef1f5;
    font-size: 12.5px;
    color: #8894a7;
    flex: none;
}

.source-view-name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--zlowi-navy);
}

.source-view-links {
    margin-left: auto;
    flex: none;
    white-space: nowrap;
}

.source-view-links .link-button {
    font-size: 12.5px;
    text-decoration: none;
}

.source-view-body {
    flex: 1;
    min-height: 0;
    overflow: auto;
}

.source-frame {
    display: block;
    width: 100%;
    height: 100%;
    border: 0;
}

/* An email's HTML sets its own colors, or assumes a white page. */
.source-frame--email {
    background: #fff;
}

.source-image {
    padding: 12px;
    text-align: center;
}

.source-image img {
    max-width: 100%;
    height: auto;
}

.source-text {
    margin: 0;
    padding: 12px 14px;
    font-size: 12px;
    line-height: 1.5;
    white-space: pre-wrap;
    word-break: break-word;
}

.source-table-wrap {
    padding: 0 0 12px;
}

.source-table {
    border-collapse: collapse;
    font-size: 12px;
    width: max-content;
    min-width: 100%;
}

.source-table th,
.source-table td {
    padding: 5px 10px;
    border-bottom: 1px solid #eef1f5;
    text-align: left;
    white-space: nowrap;
}

.source-table th {
    position: sticky;
    top: 0;
    background: #f7f8fa;
    font-weight: 600;
}

.source-panel-empty {
    padding: 24px 16px;
    font-size: 13px;
    color: #8894a7;
    text-align: center;
}

/* Too narrow to split: the panel sits above the form instead. */
@media (max-width: 1000px) {
    .record-page--split .record-page-body {
        grid-template-columns: minmax(0, 1fr);
    }

    .source-panel {
        position: static;
        height: 65vh;
        order: -1;
    }
}

/* .record-page-actions is the slot Save/Approve (or Push to ERP)
   render into -- see renderReviewCard/renderApprovedCard's actionsEl --
   one row per PO still being acted on. Empty (no visible gap) while
   nothing has buttons to show yet (the progress checklist, a cancelled
   Record). */
.record-page-actions {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 8px;
    flex: none;
}

.record-page-actions:empty {
    display: none;
}

.record-page-actions-row {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* Record detail's PO switcher (see poSwitcherHtml): a file holding several
   POs lists them under the subtitle, each with its status dot; the page
   below shows the selected one. */
.po-switcher {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 10px;
}

.po-switcher-option {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 5px 11px;
    border: 1px solid #e3e8ef;
    border-radius: 999px;
    background: #fff;
    font: inherit;
    font-size: 12.5px;
    color: #5b6b82;
    cursor: pointer;
}

.po-switcher-option:hover {
    border-color: #c9d2de;
    color: var(--zlowi-navy);
}

.po-switcher-option[aria-selected="true"] {
    border-color: var(--zlowi-blue);
    background: #f2f6fe;
    color: var(--zlowi-navy);
    font-weight: 600;
    cursor: default;
}

.po-switcher-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex: none;
}

/* Record detail's "‹ 2 of 4 in Needs review ›" (see queueNavHtml) --
   navigation, so it reads quieter than the action buttons beside it. */
.queue-nav {
    display: flex;
    align-items: center;
    gap: 6px;
    flex: none;
}

.queue-nav-step {
    width: 30px;
    height: 30px;
    border-radius: 8px;
}

.queue-nav-step:disabled {
    opacity: 0.4;
    cursor: default;
}

.queue-nav-text {
    font-size: 12.5px;
    color: #64748b;
    white-space: nowrap;
}

.record-page-banners {
    display: flex;
    flex-direction: column;
}

/* Nothing to show until a review card has an issue to report. */
.record-page-banners:not(:has(.issue-banner:not([hidden]))) {
    display: none;
}

/* The issue banner (renderReviewCard's renderIssueBanner): a full-width
   strip across the bottom of the header, as in the mockup -- amber while
   only informational issues remain, red once there's a blocker. Its fill
   and top rule reach the column's edges the same way the header's do. */
.issue-banner {
    --issue-banner-bg: #fffaf2;
    --issue-banner-rule: #f6ead6;
    position: relative;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 0;
    background: var(--issue-banner-bg);
    box-shadow: 0 0 0 100vmax var(--issue-banner-bg);
    clip-path: inset(0 -100vmax);
    color: #7c4a06;
}

.issue-banner::before {
    content: "";
    position: absolute;
    left: -100vmax;
    right: -100vmax;
    top: 0;
    height: 1px;
    background: var(--issue-banner-rule);
}

.issue-banner[hidden] {
    display: none;
}

.issue-banner-icon {
    width: 26px;
    height: 26px;
    flex: none;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: #fdefd8;
    color: #b45309;
}

.issue-banner-text {
    font-size: 13.5px;
}

.issue-banner-text strong {
    font-weight: 700;
}

.issue-banner-nav {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 8px;
    flex: none;
}

.issue-banner-jump {
    padding: 6px 12px;
    border-radius: 999px;
    border: 1px solid #e2e8f0;
    background: #fff;
    font-family: inherit;
    font-size: 12.5px;
    color: #475569;
    white-space: nowrap;
    cursor: pointer;
}

.issue-banner-jump:hover {
    border-color: #c3cddb;
    color: #0f172a;
}

.issue-banner .icon-button {
    width: 32px;
    height: 32px;
}

.issue-banner--blocker {
    --issue-banner-bg: #fffafa;
    --issue-banner-rule: #f6d6d6;
    color: #7f1d1d;
}

.issue-banner--blocker .issue-banner-icon {
    background: #fee2e2;
    color: #dc2626;
}

/* Home dashboard (see views/home.js) -- its own date/greeting/Upload Record
   header now renders into the shared .page-header (see components/
   header.js), so only the grid below it lives here. */

/* Locked banner (see views/home.js's renderBillingLockedBanner, shown once
   all 5 free Records are used) -- matches the mockup's own gradient exactly
   (see sketch/Zlowi platform UI mockups/Zlowi Platform.dc.html turn 5c). */
.billing-locked-banner {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 14px 20px;
    margin-bottom: 18px;
    border-radius: 12px;
    background: linear-gradient(90deg, #1a73ff, #4f46e5 58%, #7c3aed);
    color: #fff;
    text-decoration: none;
}

.billing-locked-banner-icon {
    width: 28px;
    height: 28px;
    flex: none;
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.18);
    color: #fff;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.billing-locked-banner-text {
    flex: 1;
    min-width: 0;
}

.billing-locked-banner-title {
    font-size: 13.5px;
    font-weight: 700;
}

.billing-locked-banner-sub {
    font-size: 12.5px;
    color: rgba(255, 255, 255, 0.82);
    margin-top: 2px;
}

.billing-locked-banner-cta {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    flex: none;
    white-space: nowrap;
    padding: 8px 14px;
    border-radius: 6px;
    background: #fff;
    color: #1454c0;
    font-weight: 700;
    font-size: 13.5px;
}

.home-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 320px;
    gap: 18px;
    align-items: start;
}

.home-main,
.home-side {
    display: flex;
    flex-direction: column;
    gap: 18px;
    min-width: 0;
}

.home-kpis {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 14px;
}

.home-card {
    background: #fff;
    border: 1px solid #eef1f5;
    border-radius: 12px;
    padding: 16px 18px;
}

.home-card-header {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    font-size: 14.5px;
    font-weight: 700;
    margin-bottom: 10px;
}

.review-banner {
    display: flex;
    align-items: center;
    gap: 20px;
    border-radius: 14px;
    padding: 20px 22px;
    /* Matches the mockup's own gradient exactly (see sketch/Zlowi platform UI
       mockups/Zlowi Platform.dc.html turn 5a) -- a subtler dark navy-to-blue
       than var(--zlowi-blue) would give, deliberately not the app's bright
       accent blue. */
    background: linear-gradient(120deg, #0f172a, #1b3a6b);
    color: #fff;
}

.review-banner--clear {
    background: #f1f5f9;
    color: var(--zlowi-navy);
}

.review-banner-kicker {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 12px;
    font-weight: 600;
    color: #8fbaff;
}

.review-banner--clear .review-banner-kicker {
    color: #64748b;
}

.review-banner-kicker-dot {
    width: 6px;
    height: 6px;
    flex: none;
    border-radius: 50%;
    background: #5b9bff;
}

.review-banner-title {
    font-size: 22px;
    font-weight: 700;
    letter-spacing: -0.02em;
    margin-top: 7px;
}

.review-banner-sub {
    font-size: 13px;
    color: rgba(226, 232, 240, 0.72);
    margin-top: 4px;
}

.review-banner--clear .review-banner-sub {
    color: #64748b;
}

/* Layout only -- color comes from .button.accent now (see home.js's
   renderReviewBanner and .button.accent above). */
.review-banner .button {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    flex: none;
    white-space: nowrap;
}

.activity-list {
    display: flex;
    flex-direction: column;
}

.activity-row {
    display: grid;
    grid-template-columns: 30px minmax(0, 1fr) auto;
    gap: 12px;
    align-items: center;
    padding: 10px 0;
    border-top: 1px solid #f6f8fa;
    font-size: 13.5px;
}

/* Tasks (see components/activity-feed.js) add a status pill and an
   assignee dropdown before the time. */
.activity-row--task {
    grid-template-columns: 30px minmax(0, 1fr) auto auto auto;
}

/* The Activity page's table layout (views/activity.js): icon, Type,
   Activity, Status, Assigned / closed by, Date -- logs leave the two task
   columns empty. */
.activity-row--table {
    grid-template-columns: 30px 56px minmax(0, 1fr) 104px 160px 128px;
}

.activity-row--head {
    padding: 4px 0 8px;
    font-size: 11.5px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: #8894a7;
    cursor: default;
}

.activity-row--table .pill,
.activity-row--table .activity-assignee {
    justify-self: start;
}

.activity-row--closed .activity-message strong {
    font-weight: 500;
    color: #64748b;
}

.activity-row--closed .activity-icon {
    opacity: 0.55;
}

.activity-kind {
    justify-self: start;
    padding: 2px 8px;
    border-radius: 6px;
    font-size: 11.5px;
    font-weight: 600;
}

.activity-kind--log {
    background: #f1f5f9;
    color: #64748b;
}

.activity-kind--task {
    background: #eef5ff;
    color: #1454c0;
}

/* The type icon (see activity-feed.js's ACTIVITY_ICONS) -- a tinted circle,
   as in the mockup's activity rows. */
.activity-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border-radius: 50%;
}

.activity-icon--info {
    background: #eef5ff;
    color: #1a73ff;
}

.activity-icon--success {
    background: #effaf4;
    color: #059669;
}

.activity-icon--warning {
    background: #fffbeb;
    color: #d97706;
}

.activity-icon--danger {
    background: #fef2f2;
    color: #dc2626;
}

.activity-icon--neutral {
    background: #f1f5f9;
    color: #475569;
}

.activity-row:first-child {
    border-top: none;
}

.activity-row[data-href] {
    cursor: pointer;
}

.activity-row[data-href]:hover {
    background: #fafbfc;
}

.activity-message {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.activity-message strong,
.activity-detail {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.activity-message strong {
    font-weight: 600;
}

.activity-detail {
    font-size: 12px;
    color: #8894a7;
}

.activity-time {
    font-size: 12px;
    color: #8894a7;
    white-space: nowrap;
}

.activity-assignee {
    max-width: 150px;
    font-size: 12.5px;
    padding: 3px 6px;
}

.activity-section-label {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 6px 0 2px;
    font-size: 12px;
    font-weight: 600;
    color: #64748b;
}

.activity-section-label:not(:first-child) {
    margin-top: 14px;
}

.activity-more {
    display: inline-block;
    padding-top: 6px;
    font-size: 12px;
    color: var(--zlowi-blue);
}

.activity-total {
    margin-left: auto;
    font-size: 12px;
    font-weight: 500;
    color: #8894a7;
}

/* Narrow screens: the assignee and time drop under the message. */
@media (max-width: 640px) {
    .activity-row--task {
        grid-template-columns: 30px minmax(0, 1fr) auto auto;
    }
    .activity-row--task .activity-message {
        grid-column: 2 / -1;
    }
    .activity-row--task .pill {
        grid-column: 2;
        justify-self: start;
    }
    /* The Activity table: the message takes the first line, Type / Status /
       assignee / date flow onto the next. */
    .activity-row--table {
        grid-template-columns: 30px auto auto minmax(0, 1fr) auto;
    }
    .activity-row--table .activity-message {
        grid-column: 2 / -1;
        grid-row: 1;
    }
    .activity-row--table .activity-kind {
        grid-column: 2;
    }
    .activity-row--head {
        display: none;
    }
}

.checklist-compact {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.checklist-compact-item {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 8px 0;
    font-size: 13px;
}

.checklist-compact-item .checklist-marker {
    width: 18px;
    height: 18px;
    font-size: 11px;
}

.checklist-compact-item.done .checklist-marker {
    background: #22c55e;
    border-color: #22c55e;
    color: #fff;
}

.done-label {
    color: #94a3b8;
    text-decoration: line-through;
}

.checklist-action {
    padding: 0;
}

/* Why a setup step's action isn't offered yet (e.g. "Connect your ERP
   first"). */
.checklist-locked {
    margin-top: 2px;
    font-size: 12px;
    color: #94a3b8;
}

/* Home's "Set up the Zlowi Agent" dialog (components/agent-address.js),
   after mockup 4b: a dark hero over the address box and how-to steps,
   whose own styles come from shared/css/onboarding.css. */
.agent-dialog {
    width: min(560px, calc(100vw - 32px));
    padding: 0;
    border: 1px solid #dbe7ff;
    border-radius: 16px;
    overflow: hidden;
}

.agent-dialog::backdrop {
    background: rgba(15, 23, 42, 0.45);
}

.agent-dialog-hero {
    padding: 22px;
    background: linear-gradient(120deg, #0f172a, #1b3a6b);
    color: #fff;
}

.agent-dialog-kicker {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 12px;
    font-weight: 600;
    color: #8fbaff;
}

.agent-dialog-kicker-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: #5b9bff;
}

.agent-dialog-title {
    margin: 8px 0 0;
    font-size: 20px;
    font-weight: 700;
    letter-spacing: -0.02em;
}

.agent-dialog-text {
    margin: 6px 0 0;
    font-size: 13px;
    line-height: 1.5;
    color: rgba(226, 232, 240, 0.78);
}

.agent-dialog-body {
    padding: 18px 20px 20px;
}

.agent-dialog-note {
    margin: 14px 0 0;
    font-size: 12px;
    color: #8894a7;
}

.connection-list {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.connection-row {
    display: flex;
    align-items: center;
    gap: 10px;
}

.connection-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #cbd5e1;
    flex: none;
}

.connection-dot--active {
    background: #22c55e;
}

.connection-name {
    font-size: 13px;
    font-weight: 600;
}

.connection-sub {
    font-size: 11.5px;
    color: #8894a7;
}

.connection-status {
    margin-left: auto;
    font-size: 12px;
    color: #8894a7;
    flex: none;
}

/* Settings (see views/settings.js) */

.settings-tabs {
    display: flex;
    gap: 4px;
    border-bottom: 1px solid #eee;
    margin-bottom: 20px;
}

.settings-tab {
    padding: 10px 16px;
    font-size: 14px;
    color: #667;
    text-decoration: none;
    border-bottom: 2px solid transparent;
}

.settings-tab:hover {
    color: var(--zlowi-navy);
}

.settings-tab[aria-current="page"] {
    color: var(--zlowi-navy);
    font-weight: 600;
    border-bottom-color: var(--zlowi-blue);
}

.account-summary {
    font-size: 13px;
    color: #444;
    line-height: 1.6;
}

.billing-cancel-notice {
    color: #b5650a;
    font-weight: 600;
}

.settings-plan-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 16px;
    max-width: 900px;
}

/* Billing / plan picker (see views/billing.js's renderFreeTier -- matches
   sketch/Zlowi platform UI mockups/Zlowi Platform.dc.html turn 6a). */

.usage-banner {
    display: flex;
    align-items: center;
    gap: 16px;
    max-width: 900px;
    padding: 16px 20px;
    background: #fff;
    border: 1px solid #dbe7ff;
    border-radius: 14px;
}

.usage-banner-icon {
    width: 34px;
    height: 34px;
    flex: none;
    border-radius: 10px;
    background: #eef5ff;
    color: var(--zlowi-blue);
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.usage-banner-text {
    flex: 1;
    min-width: 0;
}

.usage-banner-title {
    font-size: 13.5px;
    font-weight: 700;
    color: var(--zlowi-navy);
}

.usage-banner-sub {
    font-size: 11.5px;
    color: #8894a7;
    margin-top: 2px;
}

.usage-banner-progress {
    width: 190px;
    flex: none;
}

.usage-banner-progress-bar {
    height: 6px;
    border-radius: 999px;
    background: #eef1f5;
    overflow: hidden;
}

.usage-banner-progress-bar span {
    display: block;
    height: 100%;
    border-radius: 999px;
    background: var(--zlowi-blue);
}

.usage-banner-progress-label {
    font-size: 11.5px;
    color: #8894a7;
    margin-top: 6px;
    text-align: right;
}

.seg-save-pill {
    margin-left: 6px;
    padding: 1px 6px;
    border-radius: 999px;
    background: #dcfce7;
    color: #15803d;
    font-size: 10.5px;
    font-weight: 700;
}

.plan-card {
    display: block;
    padding: 18px 20px;
    background: #fff;
    border: 1.5px solid #eef1f5;
    border-radius: 14px;
    cursor: pointer;
}

.plan-card--selected {
    border-color: var(--zlowi-blue);
    box-shadow: 0 4px 14px rgba(33, 120, 201, 0.12);
}

.plan-card-head {
    display: flex;
    align-items: flex-start;
    gap: 12px;
}

.plan-card-radio {
    width: 18px;
    height: 18px;
    flex: none;
    margin-top: 2px;
    border-radius: 50%;
    border: 1.5px solid #c3cddb;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.plan-card--selected .plan-card-radio {
    border-color: var(--zlowi-blue);
}

.plan-card-radio-dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: transparent;
}

.plan-card--selected .plan-card-radio-dot {
    background: var(--zlowi-blue);
}

.plan-card-badge {
    display: inline-flex;
    margin-bottom: 5px;
    background: var(--zlowi-navy);
    color: #fff;
    font-weight: 700;
}

.plan-card-name {
    font-size: 15px;
    font-weight: 700;
    color: var(--zlowi-navy);
    white-space: nowrap;
}

.plan-card-price {
    display: flex;
    align-items: baseline;
    gap: 6px;
    margin-top: 18px;
}

.plan-card-price-amount {
    font-size: 34px;
    font-weight: 700;
    letter-spacing: -0.03em;
    color: var(--zlowi-navy);
}

.plan-card-price-unit {
    font-size: 13.5px;
    color: #64748b;
}

.plan-card-divider {
    height: 1px;
    background: #f2f5f8;
    margin: 16px 0 13px;
}

.plan-card-features {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.plan-card-feature {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    font-size: 12.5px;
    color: #334155;
}

.plan-card-feature svg {
    flex: none;
    margin-top: 2px;
}

.record-explainer-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 18px;
}

.record-explainer-title {
    font-size: 13px;
    font-weight: 600;
    color: var(--zlowi-navy);
    margin-bottom: 5px;
}

.billing-footnote {
    display: flex;
    align-items: center;
    gap: 8px;
    max-width: 900px;
    margin-top: 18px;
    color: #8894a7;
}

.billing-footnote svg {
    flex: none;
}

.billing-footnote span {
    font-size: 12px;
}

@media (max-width: 860px) {
    .home-grid {
        grid-template-columns: 1fr;
    }
    .settings-plan-grid {
        grid-template-columns: 1fr;
    }
    .record-explainer-grid {
        grid-template-columns: 1fr;
    }
    .usage-banner {
        flex-wrap: wrap;
    }
    .page-header {
        padding: 14px 16px;
        flex-wrap: wrap;
    }
    .page-header-search {
        display: none;
    }
}

/* Email headers (see components/source-panel.js's emailHeadersHtml): above a
   Record's Email tab, and at the top of the Inbox's reading pane. */

.email-headers {
    flex: none;
    padding: 12px 14px;
    border-bottom: 1px solid #eef1f5;
    font-size: 13px;
    color: #334155;
}

.email-headers-subject {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 6px;
    font-size: 15px;
    font-weight: 600;
    color: var(--zlowi-navy);
}

.email-headers-subject > span:first-child {
    min-width: 0;
    overflow-wrap: anywhere;
}

.email-headers-subject > :last-child:not(:first-child) {
    margin-left: auto;
    flex: none;
    font-size: 13px;
    font-weight: 400;
}

.email-header-row {
    display: flex;
    gap: 8px;
    line-height: 1.6;
}

.email-header-label {
    flex: none;
    width: 42px;
    color: #8894a7;
}

.email-header-value {
    min-width: 0;
    overflow-wrap: anywhere;
}

/* Inbox (see views/inbox.js): message list beside the reading pane. */

.inbox {
    display: grid;
    grid-template-columns: minmax(260px, 340px) minmax(0, 1fr);
    gap: 14px;
    align-items: start;
}

.inbox-list,
.inbox-reader {
    background: #fff;
    border: 1px solid #eef1f5;
    border-radius: 12px;
}

.inbox-list {
    max-height: calc(100vh - 190px);
    overflow-y: auto;
}

.inbox-reader {
    position: sticky;
    top: 16px;
    min-height: 240px;
}

.inbox-item {
    display: flex;
    flex-direction: column;
    gap: 3px;
    width: 100%;
    padding: 11px 14px;
    border: none;
    border-bottom: 1px solid #f1f4f8;
    border-left: 3px solid transparent;
    background: none;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.inbox-item:hover {
    background: #f8fafc;
}

.inbox-item[aria-current="true"] {
    background: #eef5ff;
    border-left-color: var(--zlowi-blue);
}

.inbox-item-top {
    display: flex;
    gap: 8px;
    font-size: 12.5px;
}

.inbox-item-from {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 600;
    color: var(--zlowi-navy);
}

.inbox-item-date {
    margin-left: auto;
    flex: none;
    color: #8894a7;
}

.inbox-item-subject {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 13.5px;
    color: #1e293b;
}

.inbox-item-clip {
    font-size: 11.5px;
    color: #8894a7;
}

.inbox-item-snippet {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 12.5px;
    color: #64748b;
}

.inbox-item-meta {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 3px;
}

.inbox-item-mailbox {
    font-size: 12px;
    color: #8894a7;
}

.inbox-more {
    display: block;
    width: 100%;
    padding: 10px;
}

.inbox-status {
    display: inline-flex;
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 11.5px;
    font-weight: 600;
    white-space: nowrap;
}

.inbox-status--neutral {
    background: #f1f5f9;
    color: #475569;
}

.inbox-status--info {
    background: #eef5ff;
    color: var(--zlowi-blue);
}

.inbox-status--ok {
    background: #effaf4;
    color: #047857;
}

.inbox-status--warn {
    background: #fff7ea;
    color: #b45309;
}

.inbox-status--error {
    background: #fef2f2;
    color: #b91c1c;
}

.inbox-reader-actions {
    display: inline-flex;
    gap: 8px;
}

.inbox-verdict {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 10px 14px;
    background: #fafbfc;
    border-bottom: 1px solid #eef1f5;
    font-size: 13px;
    color: #334155;
}

.inbox-mailbox {
    padding: 8px 14px 0;
    font-size: 12.5px;
    color: #8894a7;
}

.inbox-body {
    padding: 12px 14px 16px;
    font-size: 13.5px;
    line-height: 1.55;
    color: #1e293b;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.inbox-attachments {
    padding: 10px 14px 14px;
    border-top: 1px solid #eef1f5;
}

.inbox-attachments-head {
    margin-bottom: 6px;
    font-size: 12px;
    font-weight: 600;
    color: #64748b;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.inbox-attachment {
    display: flex;
    gap: 10px;
    padding: 4px 0;
    font-size: 13px;
}

.inbox-attachment-size {
    color: #8894a7;
}

.inbox-mailbox-row {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 10px 0;
    border-bottom: 1px solid #eef1f5;
}

.inbox-mailbox-name {
    font-weight: 600;
    font-size: 13.5px;
}

@media (max-width: 760px) {
    .inbox {
        grid-template-columns: minmax(0, 1fr);
    }

    .inbox-reader {
        position: static;
    }
}
