/* ============================================================
   Edit — portal.css
   Mobile-first. Tokens + utilities + components.
   Phase 0.5: waitlist landing + admin pages.
   Phase 1A onward will extend this stylesheet — never inline
   styles, never duplicate patterns. Add classes here first.
   ============================================================ */

/* ---------- DESIGN TOKENS ---------- */
:root {
    /* Brand */
    --brand:            #0a0a0a;
    --brand-soft:       #1a1a1a;
    --brand-accent:     #ff6b35;

    /* Text */
    --text:             #0a0a0a;
    --text-med:         #4a4a4a;
    --text-light:       #777;
    --text-inverse:     #fff;

    /* Surfaces */
    --bg:               #fff;
    --bg-soft:          #fafafa;
    --bg-muted:         #f3f3f3;
    --bg-card:          #fff;
    --bg-dark:          #0a0a0a;

    /* Borders */
    --border:           #e5e5e5;
    --border-soft:      #f0f0f0;
    --border-strong:    #c8c8c8;

    /* Status */
    --success:          #15803d;
    --success-bg:       #f0fdf4;
    --success-border:   #bbf7d0;
    --warn:             #92400e;
    --warn-bg:          #fffaf0;
    --warn-border:      #fed7aa;
    --danger:           #991b1b;
    --danger-bg:        #fef2f2;
    --danger-border:    #fecaca;
    --info:             #1e40af;
    --info-bg:          #eff6ff;
    --info-border:      #bfdbfe;

    /* Typography */
    --font-sans:        "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
    --font-display:     "Inter", -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
    --font-mono:        ui-monospace, SFMono-Regular, "SF Mono", Menlo, Monaco, monospace;

    /* Spacing scale */
    --sp-1: .25rem;  --sp-2: .5rem;   --sp-3: .75rem;
    --sp-4: 1rem;    --sp-5: 1.25rem; --sp-6: 1.5rem;
    --sp-7: 2rem;    --sp-8: 2.5rem;  --sp-9: 3rem;
    --sp-10: 4rem;   --sp-11: 5rem;   --sp-12: 6rem;

    /* Radius */
    --radius-sm: 4px;
    --radius:    8px;
    --radius-lg: 12px;
    --radius-pill: 999px;

    /* Shadow */
    --shadow-sm: 0 1px 2px rgba(0,0,0,.04);
    --shadow:    0 2px 8px rgba(0,0,0,.06);
    --shadow-lg: 0 8px 24px rgba(0,0,0,.08);
}

/* ---------- RESET ---------- */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
    font-family: var(--font-sans);
    color: var(--text);
    background: var(--bg);
    line-height: 1.5;
    font-size: 16px; /* iOS: prevents auto-zoom on input focus */
    -webkit-text-size-adjust: 100%;
    -webkit-font-smoothing: antialiased;
}
a { color: inherit; }
img, svg { max-width: 100%; display: block; }

/* ---------- TYPE UTILITIES (port from TP CLAUDE) ---------- */
.t-xs   { font-size: .78rem; }
.t-sm   { font-size: .85rem; }
.t-md   { font-size: .92rem; }
.t-lg   { font-size: 1.05rem; }
.t-muted   { color: var(--text-light); }
.t-med     { color: var(--text-med); }
.t-success { color: var(--success); }
.t-danger  { color: var(--danger); }
.t-mono    { font-family: var(--font-mono); }
.t-wrap    { white-space: pre-wrap; word-break: break-word; }
.text-center { text-align: center; }
.text-right  { text-align: right; }

/* ---------- SPACING UTILITIES ---------- */
.mt-0 { margin-top: 0; }
.mt-2 { margin-top: var(--sp-2); }
.mt-3 { margin-top: var(--sp-3); }
.mt-4 { margin-top: var(--sp-4); }
.mt-5 { margin-top: var(--sp-5); }
.mt-6 { margin-top: var(--sp-6); }
.mt-7 { margin-top: var(--sp-7); }
.mb-0 { margin-bottom: 0; }
.mb-2 { margin-bottom: var(--sp-2); }
.mb-3 { margin-bottom: var(--sp-3); }
.mb-4 { margin-bottom: var(--sp-4); }
.mb-5 { margin-bottom: var(--sp-5); }
.mb-6 { margin-bottom: var(--sp-6); }
.mb-7 { margin-bottom: var(--sp-7); }

/* ---------- PADDING UTILITIES ---------- */
.p-0 { padding: 0; }
.p-3 { padding: var(--sp-3); }
.p-4 { padding: var(--sp-4); }
.p-5 { padding: var(--sp-5); }
.p-6 { padding: var(--sp-6); }
.pt-0 { padding-top: 0; }
.mb-1 { margin-bottom: var(--sp-1); }

/* ---------- LAYOUT UTILITIES ---------- */
.action-row {
    display: flex;
    gap: var(--sp-3);
    flex-wrap: wrap;
    align-items: center;
}
.action-row-end     { justify-content: flex-end; }
.action-row-between { justify-content: space-between; }
.action-row > form  { display: contents; } /* let nested <form> not break flex layout */
.stack-col {
    display: flex;
    flex-direction: column;
    gap: var(--sp-4);
}
.stack-col-tight { gap: var(--sp-2); }
.stack-col-loose { gap: var(--sp-6); }

/* ---------- BRAND ----------
   Mark and wordmark both use Inter weight 900. The mark is just the
   letter "E" in a dark rounded square so it pairs visually with the
   wordmark and works as a favicon. */

.brand {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-3);
    color: var(--brand);
    text-decoration: none;
}

/* Mark: letter "E" in a dark square, white-on-dark.
   Size variants scale font-size proportionally to the square. */
.brand-mark,
.brand-mark-lg,
.brand-mark-xl {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--brand);
    color: #fff;
    font-family: var(--font-display);
    font-weight: 900;
    line-height: 1;
    text-align: center;
    flex-shrink: 0;
    user-select: none;
    /* nudge the letter optically — sans-serif caps sit slightly low in their box */
    padding-bottom: .05em;
}
.brand-mark {
    width: 1.6rem;
    height: 1.6rem;
    font-size: 1.1rem;
    letter-spacing: -.04em;
    border-radius: 4px;
}
.brand-mark-lg {
    width: 3rem;
    height: 3rem;
    font-size: 2rem;
    letter-spacing: -.05em;
    border-radius: 8px;
    margin: 0 auto;
}
.brand-mark-xl {
    width: 4rem;
    height: 4rem;
    font-size: 2.75rem;
    letter-spacing: -.05em;
    border-radius: 10px;
}

/* Wordmark: "Edit" text in matching Inter 900. */
.brand-wordmark {
    font-family: var(--font-display);
    font-weight: 900;
    font-size: 1.4rem;
    letter-spacing: -.04em;
    color: var(--brand);
    line-height: 1;
}
.brand-wordmark-lg {
    font-family: var(--font-display);
    font-weight: 900;
    font-size: 2.25rem;
    letter-spacing: -.045em;
    color: var(--brand);
    line-height: 1;
    margin: 0;
}
.brand-wordmark-xl {
    font-family: var(--font-display);
    font-weight: 900;
    font-size: 3rem;
    letter-spacing: -.05em;
    color: var(--brand);
    line-height: .95;
    margin: 0;
}
.brand-lockup-xl {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-4);
    margin: 0 auto;
}

/* Brand toggle: E shown by default, "Edit" wordmark slides out from behind
   it on hover or keyboard focus. Used on marketing surfaces only. */
.brand-toggle {
    display: inline-flex;
    align-items: center;
    color: var(--brand);
    text-decoration: none;
}
.brand-toggle .brand-wordmark {
    max-width: 0;
    margin-left: 0;
    opacity: 0;
    overflow: hidden;
    white-space: nowrap;
    transition:
        max-width 280ms cubic-bezier(.4, 0, .2, 1),
        margin-left 280ms cubic-bezier(.4, 0, .2, 1),
        opacity 180ms ease;
}
.brand-toggle:hover .brand-wordmark,
.brand-toggle:focus-visible .brand-wordmark,
.brand-toggle:focus-within .brand-wordmark {
    max-width: 6rem;
    margin-left: var(--sp-2);
    opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
    .brand-toggle .brand-wordmark {
        max-width: 6rem;
        margin-left: var(--sp-2);
        opacity: 1;
        transition: none;
    }
}

.brand-sublabel {
    font-family: var(--font-mono);
    font-size: .72rem;
    text-transform: uppercase;
    letter-spacing: .12em;
    font-weight: 600;
    color: var(--text-med);
}

/* Logo export page — preview tile + action buttons */
.logo-export {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--sp-6);
}
.logo-preview {
    width: 192px;
    height: 192px;
    background: var(--brand);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-display);
    font-weight: 900;
    font-size: 134px;
    letter-spacing: -.05em;
    line-height: 1;
    user-select: none;
}
.logo-export-actions {
    display: flex;
    gap: var(--sp-3);
    flex-wrap: wrap;
    justify-content: center;
}

/* ---------- BUTTONS ---------- */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2);
    padding: .75rem 1.25rem;
    min-height: 44px; /* mobile tap target */
    border-radius: var(--radius);
    border: 1px solid transparent;
    font-family: inherit;
    font-size: 1rem;
    font-weight: 500;
    line-height: 1;
    text-decoration: none;
    cursor: pointer;
    transition: background .15s, border-color .15s, color .15s;
    -webkit-appearance: none;
    appearance: none;
}
.btn-primary {
    background: var(--brand);
    color: var(--text-inverse);
}
.btn-primary:hover { background: var(--brand-soft); }
/* Compact button. Used inline in table rows + cards where the default
   44px tap target overwhelms the surrounding density. Still meets a
   reasonable touch target on mobile (32px) while looking right on
   desktop. */
.btn-sm {
    padding: .375rem .75rem;
    min-height: 32px;
    font-size: .875rem;
    gap: .375rem;
}
/* Action buttons grouped inline at the end of a table row (e.g. View
   + Pay on client invoices). Right-aligned by default — sits inside a
   .text-right td. */
.invoice-row-actions {
    display: inline-flex;
    gap: var(--sp-2);
    justify-content: flex-end;
}
.btn-secondary {
    background: var(--bg);
    color: var(--text);
    border-color: var(--border-strong);
}
.btn-secondary:hover { background: var(--bg-muted); }
.btn-tertiary {
    color: var(--text);
    background: var(--bg-muted);
    border-color: var(--bg-muted);
}
.btn-tertiary:hover {
    background: #e8e8e8;
    border-color: #e8e8e8;
}
.btn-ghost {
    background: transparent;
    color: var(--text-med);
}
.btn-ghost:hover { color: var(--text); background: var(--bg-muted); }
.btn-ghost.t-danger { color: var(--danger); }
.btn-ghost.t-danger:hover { color: var(--danger); background: var(--danger-bg); }
.btn-full { width: 100%; }

/* ---------- FORM CONTROLS ---------- */
.form-control {
    width: 100%;
    padding: .75rem .875rem;
    min-height: 44px;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    background: var(--bg);
    font-family: inherit;
    font-size: 1rem;
    line-height: 1.4;
    color: var(--text);
    -webkit-appearance: none;
    appearance: none;
}
.form-control:focus {
    outline: 2px solid var(--brand);
    outline-offset: -1px;
    border-color: var(--brand);
}
/* Client-side validation invalid state — applied by form-validate.js
   after blur if the field fails its data-validate rules. Matches the
   server-side .form-control + .form-error pairing so the visual is the
   same whether the error came from JS or PHP. */
.form-control.is-invalid {
    border-color: var(--danger);
    background: #fef7f7;
}
.form-control.is-invalid:focus {
    outline-color: var(--danger);
    border-color: var(--danger);
}
.form-error {
    display: block;
    color: var(--danger);
    font-size: .8rem;
    margin-top: 6px;
    line-height: 1.4;
}
.form-label {
    display: block;
    font-size: .92rem;
    font-weight: 500;
    color: var(--text);
    margin-bottom: var(--sp-2);
}
.form-help {
    display: block;
    font-size: .85rem;
    color: var(--text-light);
    margin-top: var(--sp-2);
}
.form-field {
    margin-bottom: var(--sp-5);
}
.form-control-upper { text-transform: uppercase; }

/* Card-style form container */
.form-card {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: var(--sp-6) var(--sp-6);
}

/* Two-column form row that collapses on mobile */
.form-row-2 {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--sp-3) var(--sp-5);
}
@media (min-width: 600px) {
    .form-row-2 { grid-template-columns: 1fr 1fr; }
}

/* Fieldset block (used for grouped address fields) */
.form-fieldset {
    border: 0;
    padding: 0;
    margin: 0 0 var(--sp-5);
}
.form-legend {
    font-size: .92rem;
    font-weight: 500;
    color: var(--text);
    margin: 0 0 var(--sp-3);
    padding: 0;
}

/* Definition-list pattern for read-only detail panels */
.detail-list {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--sp-3);
    margin: 0;
}
.detail-list dt {
    font-size: .8rem;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--text-light);
    margin: 0;
}
.detail-list dd {
    margin: 2px 0 0;
    color: var(--text);
    font-size: .95rem;
}
@media (min-width: 700px) {
    .detail-list { grid-template-columns: 200px 1fr; align-items: baseline; }
    .detail-list dt { margin-top: 4px; }
    .detail-list dd { margin: 0; }
}

/* Detail grid: cards auto-fit. With one card it takes full width; with two
   or more they split into equal columns down to a 20rem minimum. */
.portal-detail-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--sp-5);
}
@media (min-width: 800px) {
    .portal-detail-grid {
        grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
    }
}

/* Inline search field in toolbars */
.portal-search {
    flex: 1;
    min-width: 12rem;
    margin-left: auto;
}
.portal-search .form-control {
    max-width: 24rem;
    margin-left: auto;
}

/* Whole-row click affordance on data tables */
.row-link { cursor: pointer; }
/* Plain links inside clickable rows pick up body text color (no neon
   blue), but exclude .btn-styled anchors so action buttons keep their
   own color rules (e.g. .btn-primary white-on-brand). Same pattern as
   .data-table tbody a:not(.btn) below. */
.row-link a:not(.btn) { color: var(--text); text-decoration: none; font-weight: 500; }
.row-link a:not(.btn):hover { color: var(--brand); }

/* ---------- STATUS BANNERS ---------- */
.status-banner {
    padding: var(--sp-4) var(--sp-5);
    border-left: 4px solid;
    border-radius: var(--radius);
    font-size: .95rem;
}
.status-banner-success { background: var(--success-bg); border-color: var(--success); color: var(--success); }
.status-banner-warn    { background: var(--warn-bg);    border-color: var(--warn);    color: var(--warn);    }
.status-banner-danger  { background: var(--danger-bg);  border-color: var(--danger);  color: var(--danger);  }
.status-banner-info    { background: var(--info-bg);    border-color: var(--info);    color: var(--info);    }

/* ---------- MARKETING LANDING ---------- */
.marketing {
    min-height: 100vh;
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    background: var(--bg);
}
.marketing-header {
    padding: var(--sp-5) var(--sp-5);
    display: flex;
    align-items: center;
    justify-content: space-between;
}
.marketing-hero {
    flex: 1;
    padding: var(--sp-7) var(--sp-5) var(--sp-9);
    max-width: 40rem;
    width: 100%;
    margin: 0 auto;
    text-align: center;
}
.marketing-hero-headline {
    font-size: 2.25rem;
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -.02em;
    margin: 0 0 var(--sp-5);
    color: var(--text);
}
.marketing-hero-sub {
    font-size: 1.1rem;
    color: var(--text-med);
    margin: 0 0 var(--sp-8);
    line-height: 1.5;
}
.marketing-footer {
    padding: var(--sp-7) var(--sp-5) var(--sp-6);
    text-align: center;
    font-size: .85rem;
    color: var(--text-light);
    font-family: var(--font-mono);
}

/* Waitlist form */
.waitlist-form {
    text-align: left;
}

/* ---------- DESKTOP REFINEMENTS ---------- */
@media (min-width: 600px) {
    .marketing-hero-headline { font-size: 3rem; }
    .marketing-hero-sub      { font-size: 1.2rem; }
    .brand-wordmark-xl       { font-size: 3.75rem; }
    .brand-mark-xl           { width: 5rem; height: 5rem; font-size: 3.5rem; }
}
@media (min-width: 900px) {
    .marketing-hero {
        padding-top: var(--sp-12);
        padding-bottom: var(--sp-12);
        max-width: 44rem;
    }
    .marketing-hero-headline { font-size: 3.5rem; }
    .brand-wordmark-xl       { font-size: 4.5rem; }
    .brand-mark-xl           { width: 6rem; height: 6rem; font-size: 4.25rem; }
}

/* ---------- TENANT PORTAL ----------
   Sidebar nav on desktop (>=900px). On mobile, the sidebar collapses;
   a top bar with hamburger toggles a slide-in drawer. */

.portal-body {
    background: var(--bg-soft);
    min-height: 100vh;
    min-height: 100dvh;
}
.portal-shell {
    min-height: 100vh;
    min-height: 100dvh;
}

/* Approximate topbar height — used to position the drawer below it on mobile.
   Don't hand-tune this without also adjusting the topbar padding. */
:root { --portal-topbar-h: 3.75rem; }

/* Mobile-first defaults: top bar visible, sidebar acts as a full-width drawer
   that slides in BELOW the topbar (the topbar stays visible above it so the
   close button is always reachable). */
.portal-topbar {
    background: var(--bg);
    border-bottom: 1px solid var(--border);
    padding: var(--sp-3) var(--sp-5);
    height: var(--portal-topbar-h);
    display: flex;
    align-items: center;
    justify-content: space-between;
    position: sticky;
    top: 0;
    z-index: 50;
}
.portal-nav-toggle {
    background: transparent;
    border: 0;
    width: 44px;
    height: 44px;
    padding: 0;
    cursor: pointer;
    position: relative;
    display: inline-block;
}
/* CSS-drawn hamburger that animates into an X.
   Three absolute-positioned bars; outer two rotate ±45° and slide to center,
   middle one fades out. Driven by body.portal-nav-open from the toggle JS. */
.portal-nav-toggle-bar {
    display: block;
    position: absolute;
    left: 11px;
    width: 22px;
    height: 2px;
    background: var(--text);
    border-radius: 1px;
    transition: top .25s ease, transform .25s ease, opacity .15s ease;
}
.portal-nav-toggle-bar:nth-child(1) { top: 14px; }
.portal-nav-toggle-bar:nth-child(2) { top: 21px; }
.portal-nav-toggle-bar:nth-child(3) { top: 28px; }

body.portal-nav-open .portal-nav-toggle-bar:nth-child(1) {
    top: 21px;
    transform: rotate(45deg);
}
body.portal-nav-open .portal-nav-toggle-bar:nth-child(2) {
    opacity: 0;
}
body.portal-nav-open .portal-nav-toggle-bar:nth-child(3) {
    top: 21px;
    transform: rotate(-45deg);
}

@media (prefers-reduced-motion: reduce) {
    .portal-nav-toggle-bar { transition: none; }
}

/* Topbar brand: wordmark | sublabel inline, vertically centered around the
   visual midline of the 'E' in 'Edit'. The sublabel needs line-height: 1
   so its line box doesn't add extra whitespace that throws off alignment. */
.brand-topbar {
    align-items: center;
    gap: var(--sp-3);
    min-width: 0;
    flex: 1;
    overflow: hidden;
}
.brand-sublabel-inline {
    line-height: 1;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}
/* Thin separator between wordmark and sublabel. Drawn as a 1px line,
   slightly shorter than the wordmark's cap height for visual harmony. */
.brand-separator {
    display: inline-block;
    width: 1px;
    height: 1.1rem;
    background: var(--border-strong);
    flex-shrink: 0;
}

.portal-sidebar {
    background: var(--bg);
    display: flex;       /* always rendered; visibility + transform handle hiding */
    flex-direction: column;
    position: fixed;
    top: var(--portal-topbar-h);
    left: 0;
    right: 0;
    bottom: 0;
    width: 100%;
    max-width: none;
    z-index: 40;
    padding: var(--sp-5) var(--sp-4) var(--sp-5);
    overflow-y: auto;

    /* Closed state: slid up out of view behind the topbar, transparent,
       and non-interactive. Visibility hides interaction; transform handles
       the slide; opacity handles the fade. */
    transform: translateY(-8%);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition:
        transform 280ms cubic-bezier(.4, 0, .2, 1),
        opacity 220ms ease,
        visibility 0s linear 280ms;
}
.portal-sidebar.is-open {
    transform: translateY(0);
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transition:
        transform 280ms cubic-bezier(.4, 0, .2, 1),
        opacity 220ms ease,
        visibility 0s linear 0s;
}

/* Hide the drawer's own header on mobile — the topbar already shows the brand. */
@media (max-width: 899px) {
    .portal-sidebar-header { display: none; }
}

@media (prefers-reduced-motion: reduce) {
    .portal-sidebar { transition: none; }
}
.portal-sidebar-header { padding: var(--sp-2) var(--sp-3) var(--sp-5); }
.portal-sidebar-header .brand-sublabel { margin: var(--sp-2) 0 0; display: block; }

.portal-sidenav {
    display: flex;
    flex-direction: column;
    gap: var(--sp-1);
    flex: 1;
}
.portal-sidenav-link {
    display: flex;
    align-items: center;
    color: var(--text-med);
    text-decoration: none;
    font-size: .95rem;
    border-radius: var(--radius);
    overflow: hidden;
    transition: background .15s, color .15s;
}
.portal-sidenav-link:hover {
    background: var(--bg-muted);
    color: var(--text);
}
.portal-sidenav-link.is-active {
    background: var(--brand);
    color: var(--text-inverse);
}
/* Icon container — its width determines where the icon sits.
   Mobile default; overridden in the desktop media query so it matches the
   collapsed sidebar width and keeps the icon visually centered. */
.portal-sidenav-icon {
    display: inline-block;
    width: 2.5rem;
    text-align: center;
    font-size: 1.05rem;
    line-height: 2.5rem;
    flex-shrink: 0;
}
.portal-sidenav-label {
    padding: 0 var(--sp-3);
    line-height: 2.5rem;
}

.portal-sidebar-footer {
    padding-top: var(--sp-5);
    margin-top: var(--sp-4);
    border-top: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
}
.portal-user-card {
    padding: 0 var(--sp-3);
}
.portal-user-name {
    font-size: .95rem;
    font-weight: 500;
    color: var(--text);
}
.portal-user-role {
    margin-top: 2px;
}
.btn-full > i { margin-right: var(--sp-2); }

.portal-main {
    padding: var(--sp-6) var(--sp-5) var(--sp-9);
    max-width: 1100px;
    margin: 0 auto;
}

/* Lock body scroll when mobile drawer is open */
body.portal-nav-open { overflow: hidden; }

/* Desktop: static sidebar at 16rem, always expanded. Main content takes the
   remaining viewport width up to a 1280px max, centered. */
@media (min-width: 900px) {
    :root { --portal-sidebar-w: 16rem; }

    .portal-topbar { display: none; }

    .portal-shell {
        display: grid;
        grid-template-columns: var(--portal-sidebar-w) 1fr;
        min-height: 100vh;
    }

    .portal-sidebar {
        display: flex;
        position: sticky;
        top: 0;
        left: auto;
        right: auto;
        bottom: auto;
        width: var(--portal-sidebar-w);
        max-width: none;
        height: 100vh;
        border-right: 1px solid var(--border);
        padding: var(--sp-7) var(--sp-4) var(--sp-5);
        /* Reset the mobile drawer animation state. */
        transform: none;
        opacity: 1;
        visibility: visible;
        pointer-events: auto;
        transition: none;
    }

    .portal-sidebar-header {
        padding: 0 var(--sp-2) var(--sp-6);
    }
    /* Stack the brand vertically in the sidebar so long studio names fit:
       "Edit" wordmark on top, then a subtle divider, then the studio name
       in semibold caps as a sublabel. Each line gets full sidebar width. */
    .brand-sidebar {
        flex-direction: column;
        align-items: stretch;
        gap: 0;
        max-width: 100%;
        min-width: 0;
    }
    .brand-sidebar .brand-separator {
        display: none;
    }
    .brand-sidebar .brand-sublabel-inline {
        margin-top: var(--sp-3);
        padding-top: var(--sp-3);
        padding-bottom: var(--sp-3);
        border-top: 1px solid var(--border-soft);
        border-bottom: 1px solid var(--border-soft);
        font-size: .72rem;
        font-weight: 600;
        letter-spacing: .1em;
        text-transform: uppercase;
        color: var(--text);
        max-width: 100%;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        line-height: 1.2;
    }

    .portal-sidenav-link {
        padding: var(--sp-3);
        white-space: nowrap;
    }
    .portal-sidenav-icon {
        width: 1.5rem;
        font-size: 1.05rem;
        line-height: 1;
        margin: 0 var(--sp-3) 0 0;
    }
    .portal-sidenav-label {
        padding: 0;
        line-height: 1;
    }

    .portal-main {
        padding: var(--sp-8) var(--sp-8) var(--sp-9);
        width: 100%;
        max-width: 1280px;
        margin: 0 auto;
    }

    body.portal-nav-open { overflow: auto; }
}

/* Portal-section page header */
.portal-page-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--sp-3);
    margin-bottom: var(--sp-6);
}
.portal-page-title {
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: -.02em;
    margin: 0;
    color: var(--text);
}
.portal-page-sub {
    color: var(--text-med);
    font-size: .92rem;
    margin: var(--sp-1) 0 0;
}

/* Stat card grid (dashboard) */
.portal-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--sp-4);
}
.portal-stat-card {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: var(--sp-5) var(--sp-5);
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    text-decoration: none;
    color: var(--text);
    transition: border-color .15s, background .15s;
}
.portal-stat-card:hover {
    border-color: var(--border-strong);
    background: var(--bg-soft);
}
.portal-stat-label {
    font-size: .85rem;
    color: var(--text-light);
    text-transform: uppercase;
    letter-spacing: .04em;
}
.portal-stat-value {
    font-size: 2rem;
    font-weight: 700;
    letter-spacing: -.02em;
    color: var(--text);
    line-height: 1;
}
@media (min-width: 600px) {
    .portal-grid { grid-template-columns: repeat(3, 1fr); }
}

/* ---------- ADMIN ---------- */
.admin-page {
    min-height: 100vh;
    min-height: 100dvh; /* iOS Safari: avoid 100vh including the area behind browser chrome */
    display: flex;
    flex-direction: column;
    background: var(--bg-soft);
}
.admin-header {
    background: var(--bg);
    border-bottom: 1px solid var(--border);
    padding: var(--sp-4) var(--sp-5);
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--sp-3);
}
.admin-container {
    width: 100%;
    max-width: 1100px;
    margin: 0 auto;
    padding: var(--sp-6) var(--sp-5);
}
.admin-login-shell {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--sp-7) var(--sp-5);
}
.admin-login-card {
    width: 100%;
    max-width: 22rem;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: var(--sp-7);
    box-shadow: var(--shadow);
}

/* Data table (port from TP CLAUDE pattern) */
.data-table-wrap {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    overflow: hidden;
}
.data-table {
    width: 100%;
    border-collapse: collapse;
    font-size: .92rem;
}
.data-table th, .data-table td {
    text-align: left;
    padding: var(--sp-3) var(--sp-4);
    border-bottom: 1px solid var(--border-soft);
    vertical-align: top;
}
.data-table th {
    background: var(--bg-soft);
    font-weight: 600;
    color: var(--text-med);
    font-size: .82rem;
    text-transform: uppercase;
    letter-spacing: .02em;
}
.data-table tbody tr:last-child td { border-bottom: none; }
.data-table tbody tr:hover { background: var(--bg-soft); }
.data-table form { display: inline; margin: 0; }

/* Anchors inside table rows get an explicit hover underline so users can
   tell they're a separate clickable target from the whole-row .row-link.
   Without this, hovering a row that ALSO contains an anchor child gives
   no visual cue that the anchor will go somewhere different. */
/* Plain links inside table rows pick up the body text color (no neon-blue
   default), but exclude .btn-styled anchors so an inline action button
   keeps its own color (e.g. .btn-primary white-on-brand). Without the
   :not(.btn), the Pay button on the client invoices list renders as
   black text on black bg = invisible. */
.data-table tbody a:not(.btn) {
    color: var(--text);
    text-decoration: none;
    transition: color .12s ease;
}
.data-table tbody a:not(.btn):hover {
    text-decoration: underline;
    text-underline-offset: 3px;
    text-decoration-thickness: 1px;
}

/* Mobile-friendly card layout for narrow screens */
@media (max-width: 599px) {
    .data-table thead { display: none; }
    .data-table, .data-table tbody, .data-table tr, .data-table td {
        display: block;
        width: 100%;
    }
    .data-table tr {
        border-bottom: 1px solid var(--border);
        padding: var(--sp-3) 0;
    }
    .data-table td {
        border-bottom: none;
        padding: var(--sp-1) var(--sp-4);
    }
    .data-table td::before {
        content: attr(data-label);
        display: block;
        font-size: .72rem;
        text-transform: uppercase;
        color: var(--text-light);
        letter-spacing: .05em;
        margin-bottom: 2px;
    }
}

.empty-state {
    padding: var(--sp-10) var(--sp-5);
    text-align: center;
    color: var(--text-light);
}

/* ---------- STATUS CHIPS ----------
   Reusable pills for status badges in tables AND status filter chips.
   The same class hierarchy works for both — link variants add hover/active
   states on top of the colored backgrounds. */
.status-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-1);
    padding: .3rem .7rem;
    font-size: .78rem;
    font-weight: 500;
    border-radius: var(--radius-pill);
    text-decoration: none;
    white-space: nowrap;
    line-height: 1;
    background: var(--bg-muted);
    color: var(--text-med);
    border: 1px solid transparent;
}
a.status-chip { transition: opacity .15s, box-shadow .15s; }
a.status-chip:hover { opacity: .85; }
a.status-chip.is-active {
    box-shadow: 0 0 0 2px var(--text);
}

/* Per-status colors (used both as table badges and as colored filter chips) */
.status-chip-tentative       { background: #fef3c7;           color: #92400e; } /* amber-100 / amber-800 — pre-booked / scheduling */
.status-chip-booked          { background: var(--info-bg);    color: var(--info); }
.status-chip-proofing        { background: var(--bg-muted);   color: var(--text-light); } /* gray — proofing is a passive "waiting on client" state */
.status-chip-post_processing { background: #f3e8ff;           color: #6b21a8; }
.status-chip-delivered       { background: var(--success-bg); color: var(--success); }
.status-chip-cancelled,
.status-chip-archived        { background: var(--bg-muted);   color: var(--text-light); }

.status-chips {
    flex-wrap: wrap;
    gap: var(--sp-2);
}

/* ---------- ACTIVITY TIMELINE ----------
   Dot + content layout used on project view pages. */
.activity-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--sp-4);
}
.activity-list > li {
    display: flex;
    gap: var(--sp-3);
    align-items: flex-start;
}
.activity-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--brand);
    margin-top: 7px;
    flex-shrink: 0;
}

/* ---------- FLATPICKR OVERRIDES ----------
   Brand-matched theme on top of the vendor base. Selectors use the
   .flatpickr-* class names from the library. */
.flatpickr-calendar {
    font-family: var(--font-sans);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    border: 1px solid var(--border);
    background: var(--bg);
}
.flatpickr-calendar.arrowTop:before,
.flatpickr-calendar.arrowBottom:before {
    border-bottom-color: var(--border);
    border-top-color: var(--border);
}
.flatpickr-calendar.arrowTop:after,
.flatpickr-calendar.arrowBottom:after {
    border-bottom-color: var(--bg);
    border-top-color: var(--bg);
}
.flatpickr-months,
.flatpickr-current-month,
.flatpickr-monthDropdown-months,
.flatpickr-current-month input.cur-year {
    font-family: var(--font-sans);
    color: var(--text);
}
.flatpickr-current-month {
    font-weight: 600;
    font-size: .95rem;
}
.flatpickr-weekday {
    font-family: var(--font-sans);
    font-weight: 500;
    color: var(--text-light);
    font-size: .78rem;
    text-transform: uppercase;
    letter-spacing: .03em;
}
.flatpickr-day {
    border-radius: var(--radius);
    color: var(--text);
    font-weight: 400;
}
.flatpickr-day:hover,
.flatpickr-day:focus {
    background: var(--bg-muted);
    border-color: transparent;
    color: var(--text);
}
.flatpickr-day.today {
    border-color: var(--border-strong);
}
.flatpickr-day.today:hover {
    background: var(--bg-muted);
    color: var(--text);
}
.flatpickr-day.selected,
.flatpickr-day.selected:hover,
.flatpickr-day.selected:focus,
.flatpickr-day.startRange,
.flatpickr-day.endRange {
    background: var(--brand);
    border-color: var(--brand);
    color: var(--text-inverse);
}
.flatpickr-day.prevMonthDay,
.flatpickr-day.nextMonthDay {
    color: var(--text-light);
}
.flatpickr-day.flatpickr-disabled,
.flatpickr-day.flatpickr-disabled:hover {
    color: var(--border-strong);
    background: transparent;
}
.flatpickr-prev-month,
.flatpickr-next-month {
    color: var(--text-med);
    fill: var(--text-med);
}
.flatpickr-prev-month:hover,
.flatpickr-next-month:hover {
    color: var(--text);
    fill: var(--text);
}
.flatpickr-prev-month:hover svg,
.flatpickr-next-month:hover svg {
    fill: var(--text);
}
.empty-state-title {
    font-size: 1.1rem;
    font-weight: 500;
    color: var(--text);
    margin: 0 0 var(--sp-2);
}
.empty-state-desc {
    font-size: .95rem;
    margin: 0;
}

/* ── Invoice status chips ─────────────────────────────────────────────────── */
.status-chip-draft       { background: var(--bg-muted);    color: var(--text-light); }
.status-chip-sent        { background: var(--info-bg);     color: var(--info);       }
.status-chip-viewed      { background: #ede9fe;            color: #5b21b6;           }
.status-chip-paid        { background: var(--success-bg);  color: var(--success);    }
.status-chip-overdue     { background: #fee2e2;            color: #991b1b;           }
.status-chip-void        { background: var(--bg-muted);    color: var(--text-light); text-decoration: line-through; }
.status-chip-refunded    { background: var(--warn-bg);     color: var(--warn);       }
/* Bucket-only (filter chips on the list page; not a real invoice status). */
.status-chip-outstanding { background: #fef3c7;            color: #92400e;           }

/* ── Agreement status chips ───────────────────────────────────────────────── */
/* draft, sent, viewed, void reuse the invoice palette above — same intent. */
.status-chip-signed        { background: var(--success-bg); color: var(--success); }
.status-chip-countersigned { background: #d1fae5;           color: #065f46;        }

/* ── Invoice line items (form) ────────────────────────────────────────────── */
.invoice-line-items {
    border: 1px solid var(--border);
    border-radius: 10px;
    overflow: hidden;
    background: var(--bg-soft);
}
.invoice-line-head,
.invoice-line-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 90px 130px 110px 38px;
    gap: var(--sp-3);
    align-items: center;
    padding: var(--sp-3) var(--sp-4);
    border-bottom: 1px solid var(--border-soft);
}
.invoice-line-head {
    background: #fff;
    padding-top: var(--sp-2);
    padding-bottom: var(--sp-2);
    font-weight: 500;
}
.invoice-line-row:last-of-type { border-bottom: 1px solid var(--border-soft); }
.invoice-line-row .form-control { margin: 0; }
.invoice-line-amount {
    text-align: right;
    font-size: .95rem;
    color: var(--text);
}
.invoice-line-foot {
    padding: var(--sp-3) var(--sp-4);
    background: #fff;
}

/* Mobile: collapse the grid into a single-column stack per row */
@media (max-width: 700px) {
    .invoice-line-head { display: none; }
    .invoice-line-row {
        grid-template-columns: 1fr 38px;
        grid-template-areas:
            "desc    remove"
            "qty     remove"
            "unit    remove"
            "amount  remove";
        align-items: center;
    }
    .invoice-line-row > input:nth-child(1)         { grid-area: desc;   }
    .invoice-line-row > input[data-line-qty]       { grid-area: qty;    }
    .invoice-line-row > input[data-line-unit]      { grid-area: unit;   }
    .invoice-line-row > [data-line-amount]         { grid-area: amount; }
    .invoice-line-row > [data-line-remove]         { grid-area: remove; align-self: start; }
}

.btn-icon {
    padding: 6px 8px;
    line-height: 1;
}

/* ── Invoice summary card (totals: subtotal / tax / discount / total) ─────── */
.invoice-summary {
    margin-top: var(--sp-5);
    width: 100%;
    padding: var(--sp-5);
    border: 1px solid var(--border);
    border-radius: 12px;
    background: #fff;
}
.invoice-summary-title {
    margin: 0 0 var(--sp-3);
    font-size: 1rem;
    font-weight: 600;
    color: var(--text);
    text-transform: uppercase;
    letter-spacing: .04em;
    padding-bottom: var(--sp-3);
    border-bottom: 1px solid var(--border-soft);
}
.invoice-summary-row {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: center;
    gap: var(--sp-4);
    padding: var(--sp-3) 0;
}
.invoice-summary-row + .invoice-summary-row {
    border-top: 1px solid var(--border-soft);
}
.invoice-summary-label {
    font-size: .95rem;
    font-weight: 500;
    color: var(--text);
    margin: 0;
}
.invoice-summary-value {
    font-size: 1rem;
    font-weight: 500;
    color: var(--text);
}
.invoice-summary-row-grand {
    border-top: 2px solid var(--text) !important;
    margin-top: var(--sp-2);
    padding-top: var(--sp-4);
    padding-bottom: var(--sp-2);
}
.invoice-summary-row-grand .invoice-summary-label {
    font-size: 1.05rem;
    font-weight: 600;
}
.invoice-summary-row-grand .invoice-summary-value {
    font-size: 1.25rem;
    font-weight: 700;
}

/* Input cluster: symbol + (optional toggle) + number input */
.invoice-summary-input-wrap {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    justify-self: end;
}
.invoice-summary-symbol {
    font-size: .95rem;
    color: var(--text-light);
    font-weight: 500;
    min-width: 14px;
    text-align: right;
}
.invoice-summary-input {
    margin: 0;
    width: 110px;
    text-align: right;
}

/* $/% segmented toggle */
.discount-type-toggle {
    display: inline-flex;
    border: 1px solid var(--border-strong);
    border-radius: 8px;
    overflow: hidden;
    background: var(--bg-muted);
}
.discount-type-btn {
    appearance: none;
    background: transparent;
    border: 0;
    padding: 4px 10px;
    font-size: .9rem;
    font-weight: 600;
    color: var(--text-light);
    cursor: pointer;
    line-height: 1.4;
    transition: background .15s, color .15s;
}
.discount-type-btn + .discount-type-btn {
    border-left: 1px solid var(--border-strong);
}
.discount-type-btn:hover { color: var(--text); }
.discount-type-btn.is-active {
    background: var(--text);
    color: #fff;
}

/* Read-only variant used on the view page */
.invoice-summary-readonly {
    background: var(--bg-soft);
}

/* ── Invoice number display (read-only, replaces the old Title input) ─────── */
.invoice-number-display {
    display: flex;
    align-items: center;
    min-height: 42px;
    padding: 0 var(--sp-4);
    border: 1px dashed var(--border-strong);
    border-radius: 8px;
    background: var(--bg-soft);
    font-size: 1rem;
    font-weight: 600;
    letter-spacing: .03em;
    color: var(--text);
}

/* ─────────────────────────────────────────────────────────────────────────
   Client portal layout
   Mirrors the studio admin layout — uses the same .portal-* classes. The
   client-specific styles below are limited to dashboard cards, page
   headers, and the coming-soon interstitial.
   ───────────────────────────────────────────────────────────────────────── */
.client-page-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--sp-5);
    margin-bottom: var(--sp-6);
    flex-wrap: wrap;
}
.client-page-title {
    font-size: 1.6rem;
    font-weight: 700;
    margin: 0 0 var(--sp-2);
    color: var(--text);
    letter-spacing: -0.01em;
}
.client-page-sub {
    margin: 0;
    color: var(--text-light);
    font-size: .95rem;
}

/* Outstanding-balance callout above the dashboard */
.client-callout {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-4);
    padding: var(--sp-5);
    border-radius: 12px;
    background: #fff;
    border: 1px solid var(--border);
    margin-bottom: var(--sp-6);
    flex-wrap: wrap;
}
.client-callout-warn {
    border-color: #fed7aa;
    background: #fffbeb;
}
.client-callout-figure {
    font-family: var(--font-mono, ui-monospace, SFMono-Regular, monospace);
    font-size: 1.75rem;
    font-weight: 700;
    margin: 0;
    color: var(--text);
}

/* Two-column grid (projects | invoices) on the dashboard */
.client-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--sp-5);
}
@media (min-width: 900px) {
    .client-grid { grid-template-columns: 1fr 1fr; }
}
.client-card {
    background: #fff;
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: var(--sp-5);
}
.client-card-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--sp-3);
    margin-bottom: var(--sp-4);
    padding-bottom: var(--sp-3);
    border-bottom: 1px solid var(--border-soft);
}
.client-card-title {
    margin: 0;
    font-size: 1rem;
    font-weight: 600;
    color: var(--text);
}

/* Compact list inside dashboard cards */
.client-list {
    list-style: none;
    margin: 0;
    padding: 0;
}
.client-list li + li {
    border-top: 1px solid var(--border-soft);
}
.client-list-item {
    display: block;
    padding: var(--sp-3) 0;
    color: inherit;
    text-decoration: none;
}
.client-list-item:hover { background: var(--bg-soft); }
.client-list-main {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    margin-bottom: 2px;
}

/* ─────────────────────────────────────────────────────────────────────────
   Project detail two-column layout
   Main content on the left, sticky-ish right rail with client info +
   comments + internal notes. Stacks to one column on tablet/mobile.
   ───────────────────────────────────────────────────────────────────────── */
.project-layout {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--sp-5);
}
@media (min-width: 1000px) {
    .project-layout { grid-template-columns: 1fr 360px; align-items: start; }
}
.project-main {
    display: flex;
    flex-direction: column;
    gap: var(--sp-5);
    min-width: 0;
}
.project-aside {
    display: flex;
    flex-direction: column;
    gap: var(--sp-5);
    min-width: 0;
}

/* ─────────────────────────────────────────────────────────────────────────
   Card section — native <details>/<summary> accordion. JS animates the
   body's height (inline style) to/from scrollHeight on toggle. Native
   browser handles state (the [open] attribute), JS only does the
   animation. Bulletproof: works with or without JS (snaps without).
   ───────────────────────────────────────────────────────────────────────── */
.card-section {
    background: #fff;
    border: 1px solid var(--border);
    border-radius: 12px;
    overflow: hidden;
    /* Avoid the default details margin-bottom in some browsers */
}
.card-section-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-3);
    padding: var(--sp-4) var(--sp-5);
    color: var(--text);
    cursor: pointer;
    /* Remove the native disclosure triangle */
    list-style: none;
    user-select: none;
}
.card-section-head::-webkit-details-marker { display: none; }
.card-section-head::marker { display: none; }
.card-section[open] .card-section-head { border-bottom: 1px solid var(--border-soft); }
.card-section-head:hover { background: var(--bg-soft); }
.card-section-title {
    margin: 0;
    font-size: .98rem;
    font-weight: 600;
    color: var(--text);
    display: inline-flex;
    align-items: center;
    gap: 10px;
}
.card-section-title i { color: var(--text-light); font-size: .9rem; }
.card-section-chevron {
    color: var(--text-light);
    font-size: .8rem;
    transition: transform .22s ease;
}
.card-section[open] .card-section-chevron { transform: rotate(0deg); }
.card-section:not([open]) .card-section-chevron { transform: rotate(180deg); }

/* Body — JS sets inline height during the animation. Padding intentionally
   lives on the INNER wrapper, NOT here. If padding were on the body itself,
   it would fight for space as the body shrinks toward 0 (padding has nowhere
   to "go") which produces the jitter at the end of a close animation.
   With padding on inner, the body cleanly shrinks via overflow:hidden and
   the inner gets clipped naturally without any padding gymnastics. */
.card-section-body {
    overflow: hidden;
    transition: height .22s cubic-bezier(.4, 0, .2, 1);
}
.card-section-body-inner {
    padding: var(--sp-5);
}
.card-section-body-inner.p-0 { padding: 0; }

/* Tinted variant for "team-only" sections — distinguishes internal
   stuff from client-facing visually. */
.card-section-internal {
    background: #fefce8;
    border-color: #fde68a;
}
.card-section-internal .card-section-head:hover { background: #fef3c7; }
.card-section-internal .card-section-title i { color: var(--warn); }

/* Module slot grid (placeholder cards inside Modules section) */
.module-slot-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: var(--sp-3);
}
.module-slot {
    padding: var(--sp-4);
    background: var(--bg-soft);
    border: 1px dashed var(--border-strong);
    border-radius: 10px;
}
.module-slot-title {
    margin: 0 0 var(--sp-2);
    font-size: .95rem;
    font-weight: 600;
    color: var(--text);
}

/* ─────────────────────────────────────────────────────────────────────────
   Messages thread (project comments + reactions)
   Used on both /portal/projects/<id> and /client/projects/<id>.
   ───────────────────────────────────────────────────────────────────────── */
.messages-section { display: flex; flex-direction: column; gap: var(--sp-4); }
/* Used to be a section header above each thread; now the card-section
   header handles the title. Keep the rule in case it's referenced elsewhere. */
.messages-section-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--sp-3);
    flex-wrap: wrap;
}
/* In the right-rail context, messages are tighter — even smaller avatars,
   compact compose footer. */
.project-aside .messages-list { gap: var(--sp-4); }
.project-aside .message-avatar { --avatar-size: 24px; }
.project-aside .messages-compose-foot {
    flex-direction: column;
    align-items: stretch;
    gap: var(--sp-2);
}
.project-aside .messages-compose-foot button { align-self: flex-end; }

.messages-empty {
    text-align: center;
    padding: var(--sp-6) var(--sp-4);
    color: var(--text-light);
    border: 1px dashed var(--border);
    border-radius: 10px;
}
.messages-empty i {
    display: block;
    font-size: 1.5rem;
    margin-bottom: var(--sp-2);
    opacity: .6;
}

/* Text-message style: each row aligns to the sender's side. The viewer's
   own messages push to the right edge; everyone else's stay left. Avatar
   tucks right next to the bubble on the appropriate side.

   The list itself is capped so the thread never grows the card past a
   sane height — overflow scrolls within the card. Subtle scrollbar
   styling keeps it from feeling like a textarea. */
.messages-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-start;   /* default; .message-own overrides via align-self */
    gap: var(--sp-5);
    max-height: 520px;
    overflow-y: auto;
    /* Small inset padding so right-aligned bubbles don't kiss the
       scrollbar / card edge. Avatars get a little air too. */
    padding-right: var(--sp-2);
    /* Firefox */
    scrollbar-width: thin;
    scrollbar-color: var(--border-strong) transparent;
}
.messages-list::-webkit-scrollbar { width: 8px; }
.messages-list::-webkit-scrollbar-track { background: transparent; }
.messages-list::-webkit-scrollbar-thumb {
    background: var(--border-strong);
    border-radius: 8px;
}
.messages-list::-webkit-scrollbar-thumb:hover { background: var(--text-light); }

.message {
    display: flex;
    align-items: flex-end;     /* avatar sits flush with bottom of bubble */
    gap: var(--sp-2);
    max-width: 88%;            /* keep bubbles from spanning full width */
    min-width: 0;
}
.message-avatar { flex-shrink: 0; --avatar-size: 28px; }

.message-body-wrap {
    min-width: 0;
    background: var(--bg-soft);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: var(--sp-3) var(--sp-4);
}

/* Viewer's own messages — flip side + subtle accent. Premium-SaaS feel:
   barely-there background tint, but a clearly-blue border carries the
   "this is you" cue. Anything louder feels like a chat toy, not a tool. */
.message-own {
    align-self: flex-end;
    flex-direction: row-reverse;
}
.message-own .message-body-wrap {
    background: #f5f9ff;       /* near-white, faintest blue wash */
    border-color: #60a5fa;     /* clearly blue but not loud */
}
.message-own .message-meta { justify-content: flex-end; }
.message-own .message-reactions { justify-content: flex-end; }

/* Internal notes always look like internal notes regardless of side. */
.message-internal .message-body-wrap {
    background: #fffbeb;       /* faint warm wash */
    border-color: #fde68a;
}
.message-own.message-internal .message-body-wrap {
    /* Internal-and-mine: keep the warm wash, bump the border so "mine"
       still reads from across the thread. */
    background: #fffbeb;
    border-color: #f59e0b;
}

.message-meta {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    flex-wrap: wrap;
    margin-bottom: var(--sp-2);
    font-size: .85rem;
}
.message-author { font-weight: 600; color: var(--text); }
.message-time { color: var(--text-light); font-family: var(--font-mono); font-size: .78rem; }
.message-internal-badge {
    font-size: .7rem;
    font-weight: 600;
    color: var(--warn);
    background: var(--warn-bg);
    padding: 2px 8px;
    border-radius: 4px;
    text-transform: uppercase;
    letter-spacing: .06em;
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

.message-text {
    color: var(--text);
    line-height: 1.55;
    white-space: pre-wrap;
    word-wrap: break-word;
}

/* Reactions */
.message-reactions {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: var(--sp-3);
    flex-wrap: wrap;
    position: relative;
}
.reaction-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    background: var(--bg-muted);
    border: 1px solid var(--border);
    border-radius: 14px;
    cursor: pointer;
    font-family: inherit;
    font-size: .8rem;
    color: var(--text);
    transition: background .12s, border-color .12s;
}
.reaction-chip:hover {
    background: #fff;
    border-color: var(--border-strong);
}
.reaction-chip.is-mine {
    background: var(--info-bg);
    border-color: var(--info);
    color: var(--info);
}
.reaction-chip.is-mine:hover { background: #dbeafe; }
.reaction-chip:disabled { opacity: .6; cursor: wait; }
.reaction-emoji { font-size: .95rem; line-height: 1; }
.reaction-count { font-weight: 600; }

.reaction-add {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: transparent;
    border: 1px dashed var(--border-strong);
    color: var(--text-light);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background .12s, color .12s;
}
.reaction-add:hover {
    background: var(--bg-muted);
    color: var(--text);
}
.reaction-picker {
    position: absolute;
    top: 100%;
    left: 0;
    margin-top: 4px;
    background: #fff;
    border: 1px solid var(--border);
    border-radius: 10px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, .12);
    padding: 4px;
    display: flex;
    gap: 2px;
    z-index: 10;
}
/* Position is computed by JS as position:fixed relative to the viewport
   (see messages.js positionPickerNear), so no per-side CSS override is
   needed. The CSS values above act as a fallback if JS ever fails. */
.reaction-picker[hidden] { display: none; }
.reaction-picker-emoji {
    width: 32px;
    height: 32px;
    border-radius: 6px;
    background: transparent;
    border: 0;
    cursor: pointer;
    font-size: 1.15rem;
    line-height: 1;
    transition: background .12s, transform .12s;
}
.reaction-picker-emoji:hover {
    background: var(--bg-soft);
    transform: scale(1.15);
}

/* Compose form */
.messages-compose {
    margin-top: var(--sp-4);
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
}
.messages-compose textarea {
    resize: vertical;
    min-height: 80px;
}
.messages-compose-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-4);
    flex-wrap: wrap;
}
.messages-internal-toggle {
    margin: 0;
    flex: 1;
    min-width: 240px;
}

/* "Coming soon" interstitial for unshipped client modules */
.coming-soon-splash {
    text-align: center;
    padding: var(--sp-7) var(--sp-5);
}
.coming-soon-icon {
    width: 72px;
    height: 72px;
    margin: 0 auto var(--sp-4);
    border-radius: 16px;
    background: var(--bg-soft);
    color: var(--text-light);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.8rem;
}
.coming-soon-title {
    margin: 0 0 var(--sp-3);
    font-size: 1.15rem;
    font-weight: 700;
    color: var(--text);
}
.coming-soon-desc {
    max-width: 520px;
    margin: 0 auto var(--sp-4);
    color: var(--text);
    line-height: 1.5;
}

/* Layout polish on invoice view (meta row across the top) */
.invoice-meta-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: var(--sp-4);
    padding-bottom: var(--sp-5);
    border-bottom: 1px solid var(--border-soft);
    margin-bottom: var(--sp-5);
}

/* ─────────────────────────────────────────────────────────────────────────
   Studio dashboard
   Five stat tiles → action items → recent projects + quick actions sidebar
   ───────────────────────────────────────────────────────────────────────── */
.dashboard-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: var(--sp-4);
    margin-bottom: var(--sp-6);
}
.dashboard-stat {
    display: flex;
    align-items: center;
    gap: var(--sp-4);
    padding: var(--sp-5);
    background: #fff;
    border: 1px solid var(--border);
    border-radius: 12px;
    text-decoration: none;
    color: inherit;
    cursor: pointer;
    transition: background .15s, border-color .15s, box-shadow .15s, transform .15s;
}
.dashboard-stat:hover {
    background: var(--bg-soft);
    border-color: var(--text-light);
    box-shadow: 0 4px 16px rgba(0, 0, 0, .06);
    transform: translateY(-1px);
}
.dashboard-stat:active {
    transform: translateY(0);
    box-shadow: 0 2px 8px rgba(0, 0, 0, .04);
}
.dashboard-stat-icon {
    flex-shrink: 0;
    width: 44px;
    height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--bg-muted);
    border-radius: 10px;
    color: var(--text-light);
    font-size: 1.15rem;
}
.dashboard-stat-icon-money {
    background: var(--success-bg);
    color: var(--success);
}
.dashboard-stat-body { min-width: 0; }
.dashboard-stat-value {
    font-size: 1.6rem;
    font-weight: 700;
    line-height: 1.1;
    color: var(--text);
    letter-spacing: -0.01em;
}
.dashboard-stat-label {
    font-size: .72rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-light);
    margin-top: 4px;
    font-weight: 500;
}

/* "You're clear" green banner when there are no action items */
.action-clear {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-3);
    padding: var(--sp-4) var(--sp-5);
    background: var(--success-bg);
    border: 1px solid var(--success-border);
    border-radius: 10px;
    color: var(--success);
    font-weight: 500;
    margin-bottom: var(--sp-6);
}
.action-clear i { font-size: 1.05rem; }

/* Action-items card when there ARE items */
.action-items {
    background: #fff;
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: var(--sp-5);
    margin-bottom: var(--sp-6);
}
.action-items-list { list-style: none; margin: 0; padding: 0; }
.action-item {
    display: flex;
    align-items: center;
    gap: var(--sp-4);
    padding: var(--sp-3) 0;
    border-top: 1px solid var(--border-soft);
}
.action-item:first-child { border-top: 0; padding-top: 0; }
.action-item:last-child { padding-bottom: 0; }
.action-item-icon {
    width: 38px;
    height: 38px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--bg-muted);
    color: var(--text-light);
    border-radius: 8px;
    flex-shrink: 0;
}
.action-item-warn .action-item-icon {
    background: #fef3c7;
    color: #92400e;
}
.action-item-body { flex: 1; min-width: 0; }
.action-item-text { font-weight: 500; color: var(--text); }
.action-item-sub { margin-top: 2px; }

/* Recent-projects + Quick-actions two-column layout */
.dashboard-main {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--sp-5);
}
@media (min-width: 1000px) {
    .dashboard-main { grid-template-columns: 1fr 300px; }
}
.dashboard-section-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-3);
    padding: var(--sp-4) var(--sp-5);
    border-bottom: 1px solid var(--border-soft);
    flex-wrap: wrap;
}
.dashboard-section-title {
    margin: 0 0 var(--sp-3);
    font-size: 1rem;
    font-weight: 600;
    color: var(--text);
}

/* Quick-actions sidebar */
.dashboard-quick-actions {
    background: #fff;
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: var(--sp-5);
    height: fit-content;
}
.dashboard-quick-actions .dashboard-section-title {
    padding-bottom: var(--sp-3);
    border-bottom: 1px solid var(--border-soft);
    margin-bottom: var(--sp-4);
}
.quick-action {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    padding: 10px var(--sp-3);
    background: #fff;
    border: 1px solid var(--border);
    border-radius: 8px;
    color: var(--text);
    text-decoration: none;
    font-weight: 500;
    font-size: .92rem;
    margin-bottom: var(--sp-2);
    transition: background .15s, border-color .15s, transform .1s;
}
.quick-action:last-child { margin-bottom: 0; }
.quick-action:hover {
    background: var(--bg-soft);
    border-color: var(--border-strong);
}
.quick-action i {
    color: var(--text-light);
    width: 16px;
    text-align: center;
}
.quick-action-primary {
    background: var(--text);
    color: #fff;
    border-color: var(--text);
}
.quick-action-primary i { color: rgba(255, 255, 255, .8); }
.quick-action-primary:hover {
    background: #1a1a1a;
    border-color: #1a1a1a;
    color: #fff;
}

/* ── Password input with eye-icon reveal toggle ───────────────────────────── */
.password-input-wrap {
    position: relative;
    display: block;
}
.password-input-wrap .form-control {
    padding-right: 44px; /* leave room for the toggle button */
}
.password-toggle-btn {
    position: absolute;
    right: 6px;
    top: 50%;
    transform: translateY(-50%);
    background: transparent;
    border: 0;
    color: var(--text-light);
    cursor: pointer;
    padding: 8px 10px;
    border-radius: 6px;
    line-height: 1;
    font-size: .95rem;
    transition: background .15s, color .15s;
}
.password-toggle-btn:hover {
    color: var(--text);
    background: var(--bg-muted);
}
.password-toggle-btn:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 1px;
}

/* ─────────────────────────────────────────────────────────────────────────
   Admin top bar
   Sits at the top of .portal-main with global search, notification bell,
   and account dropdown. Sticky so it stays visible while scrolling.
   ───────────────────────────────────────────────────────────────────────── */
.admin-topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-4);
    padding: var(--sp-3) var(--sp-6);
    background: #fff;
    border-bottom: 1px solid var(--border);
    position: sticky;
    top: 0;
    z-index: 20;
}
.topbar-page-title {
    margin: 0;
    font-size: 1rem;
    font-weight: 600;
    color: var(--text);
    letter-spacing: -0.01em;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* Admin pages opt into the topbar layout via portal-main-with-topbar.
   The class strips the default padding + max-width from .portal-main so
   the topbar can span edge-to-edge of the main column. Content centering
   moves to .portal-content. Client portal pages keep the original
   .portal-main behavior (no topbar, content centered inside .portal-main). */
.portal-main-with-topbar {
    padding: 0;
    max-width: none;
    display: flex;
    flex-direction: column;
}
.portal-main-with-topbar .portal-content {
    padding: var(--sp-6) var(--sp-6) var(--sp-7);
    max-width: 1100px;
    margin: 0 auto;
    width: 100%;
}
@media (min-width: 900px) {
    .portal-main-with-topbar .portal-content {
        padding: var(--sp-7) var(--sp-7) var(--sp-9);
        max-width: 1280px;
    }
}

/* Right-aligned cluster: search trigger + bell + account dropdown.
   All three share the same light-gray-pill resting state for visual
   consistency, with a slightly darker hover state. */
.topbar-right {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
}
.topbar-popover { position: relative; }

/* Shared baseline for all three top-bar buttons */
.topbar-search-trigger,
.topbar-icon-btn,
.topbar-account-btn {
    display: inline-flex;
    align-items: center;
    height: 38px;
    background: var(--bg-soft);
    border: 1px solid var(--border);
    color: var(--text);
    cursor: pointer;
    font-family: inherit;
    transition: background .12s, border-color .12s, color .12s;
}
.topbar-search-trigger:hover,
.topbar-icon-btn:hover,
.topbar-account-btn:hover {
    background: var(--bg-muted);
    border-color: var(--border-strong);
}
.topbar-popover.is-open .topbar-icon-btn,
.topbar-popover.is-open .topbar-account-btn {
    background: var(--bg-muted);
    border-color: var(--border-strong);
}

/* Search trigger */
.topbar-search-trigger {
    gap: var(--sp-3);
    padding: 0 14px;
    border-radius: 10px;
    color: var(--text-light);
    font-size: .9rem;
    min-width: 220px;
}
.topbar-search-trigger:hover { color: var(--text); }
.topbar-search-trigger i { font-size: .85rem; }
.topbar-search-trigger span { flex: 1; text-align: left; }
.topbar-kbd {
    font-family: var(--font-mono);
    font-size: .72rem;
    padding: 2px 6px;
    background: #fff;
    border: 1px solid var(--border);
    border-radius: 4px;
    color: var(--text-light);
    flex-shrink: 0;
}
@media (max-width: 700px) {
    .topbar-search-trigger {
        min-width: 0;
        padding: 0 12px;
        width: 38px;
        justify-content: center;
    }
    .topbar-search-trigger span,
    .topbar-search-trigger .topbar-kbd { display: none; }
}

/* Bell button — same rounded-rect shape as the search trigger for
   visual cohesion across the topbar cluster. */
.topbar-icon-btn {
    width: 38px;
    justify-content: center;
    border-radius: 10px;
    position: relative;
    color: var(--text-light);
}
.topbar-icon-btn:hover { color: var(--text); }
.topbar-icon-btn i { font-size: .95rem; }
.topbar-badge {
    position: absolute;
    top: -3px;
    right: -3px;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    border-radius: 9px;
    background: var(--danger);
    color: #fff;
    font-size: .65rem;
    font-weight: 700;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
    box-shadow: 0 0 0 2px #fff;
    pointer-events: none;
}
/* Explicit hide-when-[hidden] — overrides the display:inline-flex above
   so the JS-controlled "hide when count=0" actually works. */
.topbar-badge[hidden] { display: none !important; }

/* Account button — same 10px rounded-rect as the search trigger and bell */
.topbar-account-btn {
    gap: var(--sp-2);
    padding: 4px 10px 4px 4px;
    border-radius: 10px;
}
.topbar-account-name {
    font-size: .9rem;
    font-weight: 500;
    color: var(--text);
}
.topbar-chevron {
    font-size: .7rem;
    color: var(--text-light);
}
@media (max-width: 700px) {
    .topbar-account-name { display: none; }
}

/* Dropdown panels (notification + account) */
.topbar-dropdown {
    position: absolute;
    top: calc(100% + var(--sp-2));
    right: 0;
    min-width: 280px;
    max-width: 380px;
    background: #fff;
    border: 1px solid var(--border);
    border-radius: 12px;
    box-shadow: 0 10px 40px rgba(0, 0, 0, .12);
    z-index: 30;
    overflow: hidden;
}
.topbar-dropdown[hidden] { display: none; }
.topbar-dropdown-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-3);
    padding: var(--sp-4);
    border-bottom: 1px solid var(--border-soft);
}
.topbar-dropdown-title {
    margin: 0;
    font-size: .92rem;
    font-weight: 600;
}
.topbar-link-btn {
    background: transparent;
    border: 0;
    color: var(--text-light);
    font-size: .8rem;
    cursor: pointer;
    padding: 4px 8px;
    border-radius: 6px;
    font-family: inherit;
}
.topbar-link-btn:hover { color: var(--text); background: var(--bg-soft); }

/* Account dropdown */
.topbar-account-dropdown { min-width: 260px; }
.topbar-account-head {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    padding: var(--sp-4);
    border-bottom: 1px solid var(--border-soft);
}
.topbar-account-meta { min-width: 0; }
.topbar-account-fullname {
    font-weight: 600;
    color: var(--text);
    font-size: .92rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.topbar-account-email {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.topbar-menu-item {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    padding: 10px var(--sp-4);
    color: var(--text);
    text-decoration: none;
    font-size: .9rem;
    background: transparent;
    border: 0;
    cursor: pointer;
    width: 100%;
    text-align: left;
    font-family: inherit;
}
.topbar-menu-item:hover { background: var(--bg-soft); }
.topbar-menu-item i { width: 16px; color: var(--text-light); text-align: center; }
.topbar-menu-item-danger { color: var(--danger, #b91c1c); }
.topbar-menu-item-danger i { color: var(--danger, #b91c1c); }
.topbar-menu-item-danger:hover { background: var(--danger-bg, #fef2f2); }
.topbar-menu-form { margin: 0; }

/* Notification panel */
.topbar-notif-dropdown {
    min-width: 360px;
    max-height: 70vh;
    display: flex;
    flex-direction: column;
}
.topbar-notif-list {
    overflow-y: auto;
    flex: 1;
    max-height: 60vh;
}
.topbar-notif-empty {
    padding: var(--sp-6) var(--sp-4);
    text-align: center;
    color: var(--text-light);
}
.topbar-notif-empty i {
    display: block;
    font-size: 1.5rem;
    margin-bottom: var(--sp-2);
    opacity: .5;
}
/* ── Notification filter tabs (Unread / All) ──────────────────────── */
.topbar-notif-tabs {
    display: flex;
    gap: 0;
    padding: 4px var(--sp-4);
    border-bottom: 1px solid var(--border-soft);
    background: #fff;
}
.topbar-notif-tab {
    appearance: none;
    background: transparent;
    border: 0;
    padding: 8px 12px;
    font: inherit;
    font-size: .85rem;
    font-weight: 500;
    color: var(--text-muted);
    cursor: pointer;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    transition: color .12s, border-color .12s;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.topbar-notif-tab:hover { color: var(--text); }
.topbar-notif-tab.is-active {
    color: var(--text);
    border-bottom-color: var(--brand);
}
.topbar-notif-tab-count {
    background: var(--danger);
    color: #fff;
    font-size: .65rem;
    font-weight: 700;
    line-height: 1;
    padding: 2px 6px;
    border-radius: 9px;
    min-width: 18px;
    text-align: center;
}

/* ── Date-bucket group headers (Today / Yesterday / Earlier) ─────── */
.topbar-notif-group-label {
    padding: var(--sp-3) var(--sp-4) 4px;
    font-size: .65rem;
    font-weight: 700;
    color: var(--text-light);
    text-transform: uppercase;
    letter-spacing: .08em;
}

/* ── Notification item — refined visual hierarchy ─────────────────── */
.topbar-notif-item {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-4);
    color: inherit;
    text-decoration: none;
    border-bottom: 1px solid var(--border-soft);
    background: #fff;
    transition: background .12s;
}
.topbar-notif-item:last-child { border-bottom: 0; }
.topbar-notif-item:hover { background: var(--bg-soft); }

/* Unread state — light background tint + colored left bar.
   Together with the bold title + the right-side dot, three visual
   cues a glance can pick up. */
.topbar-notif-item.is-unread {
    background: #fafafa;
    box-shadow: inset 3px 0 0 var(--brand-accent, #ff6b35);
}
.topbar-notif-item.is-unread:hover { background: #f4f4f4; }

/* Round colored icon badge on the left — replaces the bare dot.
   Tone classes drive the bg color so payment/agreement/etc each get
   their own visual identity. */
.topbar-notif-icon {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: .85rem;
    margin-top: 2px;
}
.topbar-notif-icon-success { background: #d1fae5; color: #065f46; }
.topbar-notif-icon-danger  { background: #fee2e2; color: #991b1b; }
.topbar-notif-icon-info    { background: #dbeafe; color: #1e40af; }
.topbar-notif-icon-neutral { background: var(--bg-soft); color: var(--text-muted); }

/* Unread dot — small accent on the right side of the row */
.topbar-notif-dot {
    position: absolute;
    top: 50%;
    right: 14px;
    transform: translateY(-50%);
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--brand-accent, #ff6b35);
    flex-shrink: 0;
}

.topbar-notif-body-wrap { min-width: 0; flex: 1; padding-right: 18px; }
.topbar-notif-title {
    font-size: .9rem;
    font-weight: 500;
    color: var(--text);
    margin-bottom: 2px;
    line-height: 1.35;
}
.topbar-notif-item.is-unread .topbar-notif-title { font-weight: 600; }
.topbar-notif-body {
    font-size: .8rem;
    color: var(--text-muted);
    line-height: 1.4;
    margin-bottom: 4px;
}
.topbar-notif-time {
    font-size: .7rem;
    color: var(--text-light);
    font-weight: 500;
}

/* Search modal */
.topbar-search-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, .45);
    z-index: 1000;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: 10vh var(--sp-4) var(--sp-4);
}
.topbar-search-backdrop[hidden] { display: none; }
body.topbar-search-open { overflow: hidden; }
.topbar-search-modal {
    background: #fff;
    border-radius: 14px;
    width: 100%;
    max-width: 640px;
    box-shadow: 0 20px 60px rgba(0, 0, 0, .25);
    overflow: hidden;
    display: flex;
    flex-direction: column;
    max-height: 70vh;
}
.topbar-search-input-wrap {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    padding: var(--sp-4) var(--sp-5);
    border-bottom: 1px solid var(--border-soft);
}
.topbar-search-input-wrap > i {
    color: var(--text-light);
    font-size: 1rem;
}
.topbar-search-input {
    flex: 1;
    border: 0;
    outline: none;
    background: transparent;
    font-size: 1rem;
    font-family: inherit;
    color: var(--text);
    min-width: 0;
}
.topbar-search-results {
    overflow-y: auto;
    flex: 1;
    padding: var(--sp-2) 0;
}
.topbar-search-hint {
    padding: var(--sp-5) var(--sp-5);
    margin: 0;
    color: var(--text-light);
    text-align: center;
    font-size: .9rem;
}
.topbar-search-group { padding-bottom: var(--sp-2); }
.topbar-search-group-label {
    padding: var(--sp-2) var(--sp-5);
    font-size: .72rem;
    color: var(--text-light);
    letter-spacing: .06em;
    font-weight: 600;
    text-transform: uppercase;
}
.topbar-search-result {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    padding: 10px var(--sp-5);
    color: inherit;
    text-decoration: none;
}
.topbar-search-result:hover,
.topbar-search-result.is-active {
    background: var(--bg-soft);
}
.topbar-search-result > i {
    width: 20px;
    text-align: center;
    color: var(--text-light);
}
.topbar-search-result-body { min-width: 0; flex: 1; }
.topbar-search-result-label {
    font-size: .92rem;
    font-weight: 500;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.topbar-search-result-sub {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ── Section divider inside a form-card ───────────────────────────────────── */
.form-divider {
    height: 1px;
    background: var(--border-soft);
    margin: var(--sp-6) calc(var(--sp-6) * -1);
}

/* ─────────────────────────────────────────────────────────────────────────
   Avatars — used in:
     * Sidebar user cards (admin + client)
     * Settings page upload preview
     * Future: activity log, client list, messages
   ───────────────────────────────────────────────────────────────────────── */

/* Base avatar — flexible size via the --avatar-size custom property
   (default 40px; override per usage site). */
.avatar {
    --avatar-size: 40px;
    width: var(--avatar-size);
    height: var(--avatar-size);
    border-radius: 50%;
    background: var(--bg-muted);
    color: var(--text);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-weight: 600;
    font-size: calc(var(--avatar-size) * 0.4);
    overflow: hidden;
    flex-shrink: 0;
    text-transform: uppercase;
    line-height: 1;
}
.avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.avatar-sm  { --avatar-size: 28px; }
.avatar-md  { --avatar-size: 40px; }
.avatar-lg  { --avatar-size: 56px; }
.avatar-xl  { --avatar-size: 80px; }

/* Settings page upload widget */
.avatar-upload-field { margin-bottom: var(--sp-5); }
.avatar-upload-row {
    display: flex;
    align-items: center;
    gap: var(--sp-5);
    flex-wrap: wrap;
}
.avatar-preview {
    width: 80px;
    height: 80px;
    border-radius: 50%;
    background: var(--bg-muted);
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
.avatar-preview img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}
.avatar-preview .avatar-initial {
    font-size: 1.8rem;
    font-weight: 600;
    color: var(--text);
}
.avatar-upload-controls {
    flex: 1;
    min-width: 240px;
}
.avatar-upload-btn { cursor: pointer; }

/* Avatar inside the sidebar user card */
.portal-user-card .avatar {
    --avatar-size: 36px;
    margin-bottom: var(--sp-2);
}

/* ── Avatar crop modal (Cropper.js wrapper) ───────────────────────────────── */
.avatar-cropper-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, .55);
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--sp-4);
}
.avatar-cropper-backdrop[hidden] { display: none !important; }
body.avatar-cropper-open { overflow: hidden; }

.avatar-cropper-modal {
    background: #fff;
    border-radius: 14px;
    overflow: hidden;
    width: 100%;
    max-width: 640px;
    max-height: 90vh;
    display: flex;
    flex-direction: column;
    box-shadow: 0 20px 60px rgba(0, 0, 0, .25);
}
.avatar-cropper-head {
    padding: var(--sp-5) var(--sp-5) var(--sp-4);
    border-bottom: 1px solid var(--border-soft);
}
.avatar-cropper-body {
    padding: var(--sp-5);
    background: var(--bg-soft);
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
    min-height: 0;
}
.avatar-cropper-stage {
    width: 100%;
    aspect-ratio: 1 / 1;
    max-height: 60vh;
    overflow: hidden;
    background: #000;
    border-radius: 10px;
}
.avatar-cropper-stage img {
    display: block;
    max-width: 100%;
}
.avatar-cropper-hint {
    text-align: center;
    margin: 0;
}
.avatar-cropper-foot {
    padding: var(--sp-4) var(--sp-5);
    border-top: 1px solid var(--border-soft);
    display: flex;
    justify-content: space-between;
    gap: var(--sp-3);
}

/* Make the Cropper.js viewbox render as a circle so the user sees the
   actual avatar shape while positioning. */
.avatar-cropper-stage .cropper-view-box,
.avatar-cropper-stage .cropper-face {
    border-radius: 50%;
}
.avatar-cropper-stage .cropper-view-box {
    outline: 2px solid #fff;
    outline-offset: -1px;
}

/* ── Form checkbox row ────────────────────────────────────────────────────── */
.form-check {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-3);
    padding: var(--sp-3) 0;
    cursor: pointer;
}
.form-check input[type="checkbox"] {
    width: 18px;
    height: 18px;
    margin: 2px 0 0;
    accent-color: var(--text);
    cursor: pointer;
    flex-shrink: 0;
}
.form-check-label {
    display: block;
    font-size: .95rem;
    font-weight: 500;
    color: var(--text);
    margin-bottom: 2px;
}
.form-check .form-help {
    margin-top: 2px;
}

/* ── NET preset buttons (under Due date) ──────────────────────────────────── */
.due-date-presets {
    display: flex;
    gap: var(--sp-2);
    margin-top: var(--sp-2);
    flex-wrap: wrap;
}
.due-preset-btn {
    appearance: none;
    background: var(--bg-soft);
    border: 1px solid var(--border-strong);
    border-radius: 999px;
    padding: 4px 12px;
    font-size: .8rem;
    font-weight: 600;
    color: var(--text-light);
    cursor: pointer;
    letter-spacing: .03em;
    transition: background .15s, color .15s, border-color .15s;
}
.due-preset-btn:hover {
    color: var(--text);
    border-color: var(--text-light);
}
.due-preset-btn.is-active {
    background: var(--text);
    color: #fff;
    border-color: var(--text);
}

/* ── Flush data-table variant (no outer wrap border) ──────────────────────── */
.data-table-flush { border: 0; box-shadow: none; }
.data-table-flush th,
.data-table-flush td { padding-left: 0; padding-right: 0; }


/* ─────────────────────────────────────────────────────────────────────────
   Agreements module
   ───────────────────────────────────────────────────────────────────────── */

/* Status badge variants used in the agreement list. Most of these reuse
   existing palette tokens. */
.badge-purple        { background: #ede9fe; color: #6d28d9; }
.badge-success-strong{ background: #d1fae5; color: #065f46; }
.badge-warn          { background: var(--warn-bg, #fef3c7); color: var(--warn, #92400e); }

/* "Strike-through everywhere" treatment for superseded rows in the list */
.data-table tr.is-superseded td {
    color: var(--text-light);
    text-decoration: line-through;
    text-decoration-color: rgba(0,0,0,.3);
}
/* …and for the rendered doc card */
.is-superseded-doc {
    opacity: .55;
    position: relative;
}
.is-superseded-doc::after {
    content: "SUPERSEDED";
    position: absolute;
    top: 20px;
    right: 20px;
    font-size: .7rem;
    letter-spacing: .15em;
    color: #b91c1c;
    border: 2px solid #b91c1c;
    padding: 4px 10px;
    border-radius: 4px;
    transform: rotate(8deg);
    pointer-events: none;
    font-weight: 700;
}
/* Strike through every line of the actual document body when superseded
   so it's unmistakable visually — opacity-dim alone left the doc still
   reading as authoritative. Apply to paragraphs / headings / list items
   / table cells inside the body so each line gets its own strike rather
   than one long line across blocks. The signer block (signatures, IP,
   timestamps) and the agreement-signers grid below it stay un-struck
   — those record what actually happened and should remain legible. */
.is-superseded-doc .agreement-body p,
.is-superseded-doc .agreement-body h1,
.is-superseded-doc .agreement-body h2,
.is-superseded-doc .agreement-body h3,
.is-superseded-doc .agreement-body h4,
.is-superseded-doc .agreement-body h5,
.is-superseded-doc .agreement-body h6,
.is-superseded-doc .agreement-body li,
.is-superseded-doc .agreement-body td,
.is-superseded-doc .agreement-body th,
.is-superseded-doc .agreement-body blockquote {
    text-decoration: line-through;
    text-decoration-color: rgba(0,0,0,.4);
}

/* Highlight rows in the client list that need action */
.data-table tr.is-needs-action td:first-child {
    box-shadow: inset 3px 0 0 var(--info, #2563eb);
}

/* Two-column signer block under the agreement body */
.agreement-signers {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--sp-5);
    padding-top: var(--sp-4);
    border-top: 1px solid var(--border);
}
.agreement-signer {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.agreement-signer-label {
    font-size: .7rem;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--text-light);
}
.agreement-signer-name { font-weight: 600; }
.agreement-signature-img {
    display: block;
    margin-top: 6px;
    max-width: 240px;
    max-height: 90px;
    border-bottom: 1px solid var(--border);
    padding-bottom: 4px;
}

/* Signature pad */
.sig-pad {
    position: relative;
    border: 1px solid var(--border-strong);
    border-radius: 8px;
    background: #fff;
    overflow: hidden;
    height: 160px;
}
.sig-pad canvas {
    display: block;
    width: 100%;
    height: 100%;
    cursor: crosshair;
    touch-action: none;
}
.sig-pad.is-empty::before {
    content: "Draw your signature here";
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--text-light);
    font-size: .9rem;
    pointer-events: none;
    font-style: italic;
}
.sig-clear {
    position: absolute;
    bottom: 6px;
    right: 8px;
    font-size: .75rem;
    color: var(--text-light);
    background: rgba(255,255,255,.85);
    border: 1px solid var(--border);
    padding: 2px 8px;
    border-radius: 4px;
    cursor: pointer;
}
.sig-clear:hover { color: var(--text); }

/* Countersign modal */
.countersign-modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,.45);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1000;
    padding: var(--sp-4);
}
.countersign-modal-backdrop[hidden] { display: none; }
.countersign-modal {
    background: #fff;
    border-radius: 12px;
    box-shadow: 0 20px 60px rgba(0,0,0,.25);
    padding: var(--sp-5);
    max-width: 520px;
    width: 100%;
    max-height: 92vh;
    overflow-y: auto;
}
.countersign-modal h2 { margin: 0 0 var(--sp-2); }

/* ── Rendered agreement body (in-app view) ──────────────────────────────────
   Used inside the admin/client agreement detail card. Mirrors the snapshot
   stylesheet at the typography level so an agreement looks identical
   in-app and when printed/downloaded. */
.agreement-body { color: var(--text); line-height: 1.6; }
.agreement-body h2 {
    margin: 0 0 var(--sp-5);
    font-size: 1.05rem;
    text-align: center;
    letter-spacing: .04em;
    font-weight: 700;
}
.agreement-body h3 {
    margin: var(--sp-6) 0 var(--sp-2);
    font-size: .8rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--text);
}
.agreement-body p  { margin: var(--sp-2) 0; }
.agreement-body ul { margin: var(--sp-2) 0 var(--sp-2) var(--sp-5); }
.agreement-body strong { font-weight: 600; }

/* Rates table — in-app variant (the snapshot file uses the same class with
   its own literal-value styles so it works standalone). */
.agreement-rates {
    width: 100%;
    border-collapse: collapse;
    margin-top: var(--sp-3);
    border: 1px solid var(--border);
}
.agreement-rates th,
.agreement-rates td {
    padding: var(--sp-3) var(--sp-4);
    border-top: 1px solid var(--border-soft);
    text-align: left;
    font-size: .9rem;
}
.agreement-rates thead th {
    background: var(--bg-soft);
    border-top: 0;
    font-size: .72rem;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--text-light);
    font-weight: 600;
}
.agreement-rates .price {
    text-align: right;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

/* ─────────────────────────────────────────────────────────────────────────
   Agreement WYSIWYG editor (templates + new-agreement page)
   ───────────────────────────────────────────────────────────────────────── */
.ag-editor {
    border: 1px solid var(--border-strong);
    border-radius: 10px;
    background: #fff;
    overflow: hidden;
}

.ag-toolbar {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    padding: var(--sp-2);
    background: var(--bg-soft);
    border-bottom: 1px solid var(--border);
    flex-wrap: wrap;
}
.ag-tb-group {
    display: inline-flex;
    border: 1px solid var(--border);
    border-radius: 6px;
    overflow: hidden;
    background: #fff;
}
button.ag-tb {
    appearance: none;
    border: 0;
    background: #fff;
    color: var(--text);
    font-family: inherit;
    font-size: .85rem;
    padding: .35rem .55rem;
    min-width: 32px;
    cursor: pointer;
    line-height: 1.2;
    border-right: 1px solid var(--border);
    transition: background .12s;
}
.ag-tb-group button.ag-tb:last-child { border-right: 0; }
button.ag-tb:hover { background: var(--bg-soft); }
button.ag-tb.is-active {
    background: var(--text);
    color: var(--text-inverse);
}
button.ag-tb.is-active i { color: var(--text-inverse); }

/* Edit/Preview/HTML tabs — pushed to the right side of the toolbar */
.ag-toolbar-tabs {
    margin-left: auto;
    display: inline-flex;
    border: 1px solid var(--border);
    border-radius: 6px;
    overflow: hidden;
    background: #fff;
}
.ag-tab {
    appearance: none;
    border: 0;
    background: #fff;
    color: var(--text-light);
    font-family: inherit;
    font-size: .8rem;
    font-weight: 600;
    padding: .35rem .7rem;
    cursor: pointer;
    border-right: 1px solid var(--border);
    transition: background .12s, color .12s;
}
.ag-tab:last-child { border-right: 0; }
.ag-tab:hover { color: var(--text); }
.ag-tab.is-active {
    background: var(--text);
    color: var(--text-inverse);
}

/* When NOT in rich mode, dim/disable the formatting buttons. They wake up
   the editor automatically if clicked. */
.ag-editor:not(.ag-mode-rich) .ag-tb-group {
    opacity: .45;
}

/* The editing surface. The wrapper has a fixed initial height and can be
   resized vertically only — never horizontally — so the page layout stays
   intact when the user drags the resize handle. */
.ag-stage {
    min-height: 360px;
    height: 480px;
    resize: vertical;
    overflow: hidden;             /* let the child handle its own scrolling */
    position: relative;
}
.ag-rich,
.ag-raw,
.ag-preview {
    width: 100%;
    height: 100%;
    padding: var(--sp-5);
    overflow-y: auto;
    box-sizing: border-box;
    outline: none;
    background: #fff;
    color: var(--text);
}
.ag-rich {
    line-height: 1.6;
    font-size: 15px;
}
.ag-rich:focus { outline: none; }   /* card border carries the focus cue */
.ag-rich h2 {
    margin: 0 0 var(--sp-5);
    font-size: 1.05rem;
    text-align: center;
    letter-spacing: .04em;
    font-weight: 700;
}
.ag-rich h3 {
    margin: var(--sp-6) 0 var(--sp-2);
    font-size: .8rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
}
.ag-rich p  { margin: var(--sp-2) 0; }
.ag-rich ul { margin: var(--sp-2) 0 var(--sp-2) var(--sp-5); }
.ag-rich ol { margin: var(--sp-2) 0 var(--sp-2) var(--sp-5); }
.ag-rich strong { font-weight: 600; }
.ag-rich a { color: var(--info); text-decoration: underline; }

.ag-raw {
    font-family: var(--font-mono);
    font-size: .85rem;
    line-height: 1.55;
    resize: none;
    border: 0;
    background: var(--bg-soft);
}

/* Focused state for the whole editor */
.ag-editor:focus-within {
    border-color: var(--text);
    box-shadow: 0 0 0 3px rgba(0, 0, 0, .06);
}

/* Rates Schedule legend — give it real heading weight, not the default
   tiny fieldset legend look. */
.ag-rates-fieldset {
    border: 0;
    padding: 0;
    margin: var(--sp-6) 0 0;
}
.ag-rates-legend {
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--text);
    padding: 0;
    margin-bottom: var(--sp-2);
}

/* ─────────────────────────────────────────────────────────────────────────
   New-agreement compose: 2-column layout
   ───────────────────────────────────────────────────────────────────────── */
.ag-compose-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 340px;
    gap: var(--sp-5);
    align-items: start;
}
@media (max-width: 1100px) {
    .ag-compose-layout {
        grid-template-columns: 1fr;
    }
}
.ag-compose-main { min-width: 0; }
.ag-compose-aside {
    display: flex;
    flex-direction: column;
    /* Each card is .card; mt-3 between them keeps consistent spacing */
}

.ag-meta-box {
    background: var(--bg-soft);
    border: 1px solid var(--border-soft);
    border-radius: 6px;
    padding: var(--sp-2) var(--sp-3);
    font-size: .82rem;
    margin-bottom: var(--sp-3);
}
.ag-meta-box div { margin: 2px 0; }

/* Settings card checkbox row */
.checkbox-row {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-2);
    font-size: .85rem;
    cursor: pointer;
    margin: var(--sp-2) 0 0;
}
.checkbox-row input { margin-top: .2rem; }

/* Supersedes card — give it a subtle left accent so it reads as a distinct
   "this is the supersession control" without being loud. */
.ag-supersedes-card {
    border-left: 3px solid var(--warn-border, #fed7aa);
}
.ag-supersedes-card .card-title i {
    color: var(--warn, #92400e);
    margin-right: .25rem;
}

/* ─────────────────────────────────────────────────────────────────────────
   Rates Schedule editor (grid layout — no table-cell padding squeezing
   the inputs). Used on both the template editor and the new-agreement
   composer. Function matches TP's compose page; styling is all Edit.
   ───────────────────────────────────────────────────────────────────────── */
.ag-rates-grid {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
}
.ag-rates-head {
    display: grid;
    grid-template-columns: 1fr 180px 40px;
    gap: var(--sp-3);
    padding: 0 var(--sp-2);
    font-size: .7rem;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--text-light);
    font-weight: 600;
}
.ag-rates-row {
    display: grid;
    grid-template-columns: 1fr 180px 40px;
    gap: var(--sp-3);
    align-items: center;
}
.ag-rates-row .form-control { margin: 0; }
.ag-rates-remove {
    appearance: none;
    border: 1px solid var(--border);
    background: #fff;
    color: var(--text-light);
    width: 40px;
    height: 40px;
    border-radius: 6px;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background .12s, color .12s, border-color .12s;
}
.ag-rates-remove:hover {
    background: #fff5f5;
    color: #b91c1c;
    border-color: #fecaca;
}

/* Supersedes panel — tighten internal spacing so it doesn't feel
   unfinished. The orange left accent stays. */
.ag-supersedes-card .card-title {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    margin: 0 0 var(--sp-2);
}
.ag-supersedes-card p {
    line-height: 1.5;
}
.ag-supersedes-card select { margin-top: var(--sp-1); }

/* ─────────────────────────────────────────────────────────────────────────
   Generic .card / .card-padded / .card-title — used throughout the
   agreements module's right-rail panels and elsewhere. Mirrors the
   .client-card visual so admin and client portal cards feel identical.
   ───────────────────────────────────────────────────────────────────────── */
.card {
    background: #fff;
    border: 1px solid var(--border);
    border-radius: 12px;
}
.card-padded { padding: var(--sp-5); }
.card-title {
    margin: 0 0 var(--sp-3);
    font-size: 1rem;
    font-weight: 600;
    color: var(--text);
}

/* Breadcrumb-style nav row above a page header: back-link on the left,
   secondary action(s) on the right. Used on the New Agreement page (and
   reusable wherever a sub-page wants a Back ← / → Action header pair).
   Edge ghost buttons have their horizontal padding stripped so their
   text aligns flush with the page-title heading below. */
.page-subnav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-3);
    margin-bottom: var(--sp-3);
}
.page-subnav > .btn-ghost:first-child { padding-left: 0; }
.page-subnav > .btn-ghost:last-child  { padding-right: 0; }

/* ─────────────────────────────────────────────────────────────────────────
   Project view: live "module" lists (agreements + invoices linked to a
   project). Used instead of placeholder "shipping in the X sprint" cards
   once those modules ship.
   ───────────────────────────────────────────────────────────────────────── */
.project-module-list {
    list-style: none;
    margin: 0 0 var(--sp-3);
    padding: 0;
    display: flex;
    flex-direction: column;
    border-top: 1px solid var(--border-soft);
}
.project-module-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-3);
    padding: var(--sp-3) 0;
    border-bottom: 1px solid var(--border-soft);
}
.project-module-row-main {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    text-decoration: none;
    color: var(--text);
    flex: 1;
    min-width: 0;
}
.project-module-row-main:hover .project-module-row-title { text-decoration: underline; }
.project-module-row-title { font-weight: 500; }
.project-module-row-meta { flex-shrink: 0; }
.project-module-row.is-superseded .project-module-row-title {
    color: var(--text-light);
    text-decoration: line-through;
}

/* ─────────────────────────────────────────────────────────────────────────
   Public agreement sign page (/sign?t=...)
   Standalone — no admin/client chrome. Lives at the root so non-portal
   signers can use it.
   ───────────────────────────────────────────────────────────────────────── */
.public-sign-body {
    background: var(--bg-soft);
    margin: 0;
    min-height: 100vh;
}
.public-sign-bar {
    background: #fff;
    border-bottom: 1px solid var(--border);
    padding: var(--sp-4) var(--sp-5);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-4);
}
.public-sign-bar-brand {
    font-weight: 700;
    font-size: 1.1rem;
    color: var(--text);
}
.public-sign-shell {
    max-width: 780px;
    margin: 0 auto;
    padding: var(--sp-7) var(--sp-5) var(--sp-9);
}
.public-sign-title {
    margin: 0 0 var(--sp-5);
    font-size: 1.5rem;
    font-weight: 700;
}
.public-sign-form .card-title { margin-top: 0; }
.public-sign-success {
    background: #fff;
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: var(--sp-7);
    text-align: center;
}
.public-sign-success h1 {
    color: var(--success, #15803d);
    margin: 0 0 var(--sp-3);
    font-size: 1.5rem;
}
.public-sign-success h1 i { margin-right: .5rem; }
.public-sign-success p { margin: var(--sp-2) 0; color: var(--text-med); }
.public-sign-error h1 {
    color: var(--warn, #92400e);
    margin: 0 0 var(--sp-3);
    font-size: 1.25rem;
}
.public-sign-footer {
    margin-top: var(--sp-7);
    text-align: center;
    font-size: .8rem;
    color: var(--text-light);
}
.public-sign-footer a {
    color: var(--text-light);
    text-decoration: underline;
}

/* ── Rates Schedule visual anchor (in the WYSIWYG editor) ─────────────────
   Stands in for the literal {{rates_schedule}} token so the user never
   sees implementation detail. contenteditable=false on the JS side
   prevents accidental cursor-inside-the-block edits. */
.ag-rates-anchor {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2);
    margin: var(--sp-4) 0;
    padding: var(--sp-3) var(--sp-4);
    border: 2px dashed var(--border-strong);
    border-radius: 8px;
    background: var(--bg-soft);
    color: var(--text-light);
    font-size: .85rem;
    user-select: none;
    cursor: default;
}
.ag-rates-anchor i { color: var(--text-light); font-size: 1rem; }

/* Button busy / submit-in-flight state (set by wireSubmitGuards in portal.js).
   Disabled + dimmed + cursor:wait. */
button.is-busy,
input[type="submit"].is-busy {
    opacity: .7;
    cursor: wait;
}

/* Messages inbox: unread thread treatment. Bold text + a small blue dot
   before the project title. Sorts to the top of the list (server-side). */
.data-table tr.is-thread-unread td { font-weight: 600; }
.thread-unread-dot {
    display: inline-block;
    width: 8px; height: 8px;
    background: var(--info, #2563eb);
    border-radius: 50%;
    margin-right: var(--sp-2);
    vertical-align: middle;
}

/* Rectangular variant of the avatar preview (used for studio-logo upload —
   logos aren't necessarily square). */
.avatar-preview-rect {
    width: 120px;
    height: 80px;
    border-radius: 6px;
    background: var(--bg-soft);
    border: 1px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}
.avatar-preview-rect img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

/* Studio logo image inside the brand block (sidebar / topbar) — falls back
   to the wordmark text when no logo_path is set on the tenant. */
.brand-logo {
    max-width: 100%;
    max-height: 48px;
    height: auto;
    width: auto;
    display: block;
    margin-bottom: var(--sp-2);
    object-fit: contain;
}

/* ─────────────────────────────────────────────────────────────────────────
   Settings → Payments → Processor cards
   ───────────────────────────────────────────────────────────────────────── */
.processor-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--sp-4);
}
@media (max-width: 700px) {
    .processor-grid { grid-template-columns: 1fr; }
}
.processor-card {
    background: var(--bg-soft);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: var(--sp-4);
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
    transition: border-color .15s;
}
.processor-card.is-connected {
    background: #fff;
    border-color: var(--success, #15803d);
    box-shadow: inset 3px 0 0 var(--success, #15803d);
}
.processor-card-head {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
}
.processor-card-icon {
    font-size: 1.75rem;
    width: 40px;
    height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 8px;
    background: #fff;
    border: 1px solid var(--border);
    color: var(--text);
}
.processor-card-name {
    font-weight: 600;
    font-size: 1rem;
}
.processor-card-sub { margin-top: 1px; }
.processor-card-head .badge { margin-left: auto; }

/* ─────────────────────────────────────────────────────────────────────────
   Client notification preferences — two-column toggle grid
   ───────────────────────────────────────────────────────────────────────── */
.notif-prefs-group { margin-bottom: var(--sp-6); }
.notif-prefs-group:last-of-type { margin-bottom: 0; }
.notif-prefs-table {
    width: 100%;
    border-collapse: collapse;
    border: 1px solid var(--border);
    border-radius: 10px;
    overflow: hidden;
    background: #fff;
}
.notif-prefs-table thead th {
    background: var(--bg-soft);
    color: var(--text-muted);
    font-weight: 600;
    font-size: .75rem;
    text-transform: uppercase;
    letter-spacing: .06em;
    padding: var(--sp-3);
    text-align: left;
}
.notif-prefs-table thead th.notif-prefs-col-toggle { text-align: center; width: 90px; }
.notif-prefs-table tbody td {
    border-top: 1px solid var(--border);
    padding: var(--sp-3);
    vertical-align: middle;
}
.notif-prefs-table tbody td.notif-prefs-col-toggle { text-align: center; }
.notif-prefs-label { font-weight: 600; display: inline-flex; align-items: center; gap: var(--sp-2); }
.notif-prefs-desc  { margin-top: 4px; }
.notif-prefs-locked { font-size: .65rem; letter-spacing: .04em; text-transform: uppercase; }
.notif-prefs-checkbox input[type="checkbox"] {
    width: 18px; height: 18px;
    accent-color: var(--brand);
    cursor: pointer;
}
.notif-prefs-checkbox input[type="checkbox"]:disabled { cursor: not-allowed; opacity: .5; }

/* Sidebar nav unread count badge + per-row "New" pill. The badge color
   matches the topbar notification bell (--danger) for visual
   consistency — same signal across the chrome. */
.nav-unread-badge {
    margin-left: auto;          /* push to the far right of the .portal-sidenav-link flex row */
    background: var(--danger);
    color: #fff;
    font-size: .7rem;
    font-weight: 700;
    line-height: 1;
    padding: 3px 7px;
    border-radius: 10px;
    min-width: 18px;
    text-align: center;
}
.pill-new {
    display: inline-block;
    background: var(--brand-accent, #ff6b35);
    color: #fff;
    font-size: .6rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    padding: 2px 6px;
    border-radius: 8px;
    vertical-align: 2px;
    margin-left: 6px;
}

/* Receipt print mode — hide sidebar/topbar chrome and the .no-print
   inline header so what prints is just the white receipt card. */
@media print {
    .portal-shell { display: block; }
    .portal-sidebar, .portal-topbar, .topbar, .client-sidebar { display: none !important; }
    .no-print { display: none !important; }
    .printable-receipt { box-shadow: none !important; border: 0 !important; }
    body { background: #fff !important; }
}

/* ─────────────────────────────────────────────────────────────────────────
   Breadcrumb trail — used at the top of deep detail pages
   (agreement detail, client detail, template edit, etc.)
   ───────────────────────────────────────────────────────────────────────── */
.breadcrumbs {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    font-size: .85rem;
    color: var(--text-muted);
    margin-bottom: var(--sp-2);
}
.breadcrumb-link {
    color: var(--text-muted);
    text-decoration: none;
    transition: color .15s;
}
.breadcrumb-link:hover { color: var(--text); text-decoration: underline; text-underline-offset: 2px; }
.breadcrumb-sep { color: var(--text-light); user-select: none; }
.breadcrumb-current { color: var(--text); font-weight: 500; }

/* Inline ?-icon field help — emits a tooltip on hover + a native
   title attribute as fallback for keyboard-only users. */
.field-help {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    margin-left: 4px;
    padding: 0;
    background: transparent;
    border: 0;
    color: var(--text-light);
    cursor: help;
    font-size: .8rem;
    vertical-align: middle;
    border-radius: 50%;
    position: relative;
}
.field-help:hover, .field-help:focus { color: var(--brand); outline: none; }
.field-help[data-tooltip]:hover::after,
.field-help[data-tooltip]:focus::after {
    content: attr(data-tooltip);
    position: absolute;
    bottom: calc(100% + 8px);
    left: 50%;
    transform: translateX(-50%);
    background: var(--brand);
    color: #fff;
    padding: 6px 10px;
    border-radius: 6px;
    font-size: .75rem;
    font-weight: 400;
    line-height: 1.4;
    white-space: nowrap;
    max-width: 280px;
    white-space: normal;
    width: max-content;
    text-align: left;
    z-index: 100;
    pointer-events: none;
}
.field-help[data-tooltip]:hover::before,
.field-help[data-tooltip]:focus::before {
    content: '';
    position: absolute;
    bottom: calc(100% + 2px);
    left: 50%;
    transform: translateX(-50%);
    border: 4px solid transparent;
    border-top-color: var(--brand);
    z-index: 100;
    pointer-events: none;
}

/* ─────────────────────────────────────────────────────────────────────────
   Shortcuts cheatsheet modal — opened by `?`
   ───────────────────────────────────────────────────────────────────────── */
dialog.shortcuts-modal {
    border: 0;
    padding: 0;
    border-radius: 14px;
    background: #fff;
    max-width: 600px;
    width: calc(100% - 32px);
    max-height: 80vh;
    box-shadow: 0 24px 60px rgba(10, 10, 10, 0.22), 0 4px 12px rgba(10, 10, 10, 0.08);
    color: var(--text);
    font-family: inherit;
}
dialog.shortcuts-modal::backdrop {
    background: rgba(10, 10, 10, 0.45);
    backdrop-filter: blur(2px);
}
.shortcuts-modal-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: var(--sp-4) var(--sp-5);
    border-bottom: 1px solid var(--border);
}
.shortcuts-modal-head h2 {
    font-size: 1.05rem;
    font-weight: 600;
    margin: 0;
}
.shortcuts-modal-close {
    appearance: none;
    background: transparent;
    border: 0;
    color: var(--text-muted);
    font-size: 1rem;
    cursor: pointer;
    width: 32px;
    height: 32px;
    border-radius: 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.shortcuts-modal-close:hover { background: var(--bg-soft); color: var(--text); }
.shortcuts-modal-body {
    padding: var(--sp-5);
    overflow-y: auto;
    max-height: calc(80vh - 64px);
}
.shortcuts-group { margin-bottom: var(--sp-5); }
.shortcuts-group:last-child { margin-bottom: 0; }
.shortcuts-group-title {
    font-size: .7rem;
    font-weight: 700;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: .08em;
    margin: 0 0 var(--sp-3);
}
.shortcuts-list { margin: 0; }
.shortcuts-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 8px 0;
    border-bottom: 1px solid var(--border);
}
.shortcuts-row:last-child { border-bottom: 0; }
.shortcuts-label {
    margin: 0;
    font-size: .9rem;
    color: var(--text);
}
.shortcuts-keys {
    margin: 0;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: .8rem;
}
.shortcuts-keys kbd {
    display: inline-block;
    background: var(--bg-soft);
    border: 1px solid var(--border);
    border-bottom-width: 2px;
    border-radius: 5px;
    padding: 2px 8px;
    font-family: 'SF Mono', Menlo, monospace;
    font-size: .75rem;
    font-weight: 500;
    color: var(--text);
    min-width: 22px;
    text-align: center;
}
.shortcuts-keys-sep { color: var(--text-light); font-size: .7rem; }

/* ─────────────────────────────────────────────────────────────────────────
   Kebab menus — secondary actions on table rows
   ───────────────────────────────────────────────────────────────────────── */
.kebab {
    position: relative;
    display: inline-block;
}
.kebab-btn {
    appearance: none;
    background: transparent;
    border: 0;
    cursor: pointer;
    width: 32px;
    height: 32px;
    border-radius: 6px;
    color: var(--text-muted);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: .95rem;
    transition: background .12s, color .12s;
}
.kebab-btn:hover { background: var(--bg-soft); color: var(--text); }
.kebab-btn[aria-expanded="true"] { background: var(--bg-soft); color: var(--text); }
.kebab-menu {
    /* Default rendering — only ever visible briefly before kebab-menu.js
       portals it to <body>. JS sets explicit position/top/left there. */
    position: absolute;
    top: calc(100% + 4px);
    right: 0;
    min-width: 180px;
    background: #fff;
    border: 1px solid var(--border);
    border-radius: 10px;
    box-shadow: 0 12px 28px rgba(10,10,10,.12), 0 2px 6px rgba(10,10,10,.06);
    padding: 6px;
    z-index: 1200;
    text-align: left;
}
/* When portaled to <body>, the menu loses its parent context for
   width (was naturally constrained inside the .kebab inline-block).
   width:max-content makes it shrink-wrap to the widest menu item +
   max-width caps it at a sensible 240px so a long action label
   doesn't blow out the layout. z-index needs to beat the topbar
   (1100) and any drawer backdrops (1000). */
.kebab-menu-portaled {
    width: max-content;
    max-width: 240px;
    z-index: 1200;
}
.kebab-menu a,
.kebab-menu button {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 8px 10px;
    border-radius: 6px;
    background: transparent;
    border: 0;
    color: var(--text);
    font-size: .88rem;
    font-weight: 400;
    text-align: left;
    text-decoration: none;
    cursor: pointer;
    font-family: inherit;
}
.kebab-menu a:hover,
.kebab-menu button:hover { background: var(--bg-soft); }
.kebab-menu a i,
.kebab-menu button i { color: var(--text-muted); font-size: .85rem; width: 14px; }
.kebab-menu .kebab-item-danger { color: var(--danger); }
.kebab-menu .kebab-item-danger i { color: var(--danger); }
.kebab-menu .kebab-item-danger:hover { background: #fef2f2; }
.kebab-divider {
    border: 0;
    border-top: 1px solid var(--border);
    margin: 4px 0;
}
.kebab-menu form { margin: 0; }

/* Tiny inline kbd chip for the account-dropdown shortcuts hint. */
.topbar-menu-kbd {
    margin-left: auto;
    background: var(--bg-soft);
    border: 1px solid var(--border);
    border-radius: 4px;
    padding: 1px 6px;
    font-family: 'SF Mono', Menlo, monospace;
    font-size: .7rem;
    color: var(--text-muted);
}

/* ─────────────────────────────────────────────────────────────────────────
   Settings sub-nav — horizontal tab bar at the top of every /portal/
   settings/ page. Same pattern as Stripe / Linear settings.
   ───────────────────────────────────────────────────────────────────────── */
.settings-subnav {
    display: flex;
    gap: 4px;
    padding-bottom: var(--sp-3);
    margin-bottom: var(--sp-5);
    border-bottom: 1px solid var(--border);
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}
.settings-subnav-item {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 14px;
    border-radius: 8px 8px 0 0;
    font-size: .9rem;
    font-weight: 500;
    color: var(--text-muted);
    text-decoration: none;
    white-space: nowrap;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;  /* sit on top of the parent border so active overlays it */
    transition: color .15s, background .15s;
}
.settings-subnav-item:hover { color: var(--text); background: var(--bg-soft); }
.settings-subnav-item.is-active {
    color: var(--brand);
    border-bottom-color: var(--brand);
    background: transparent;
}
.settings-subnav-item.is-soon {
    color: var(--text-light);
    cursor: not-allowed;
    opacity: .65;
}
.settings-subnav-item.is-soon:hover { background: transparent; color: var(--text-light); }
.settings-subnav-soon {
    font-size: .65rem;
    font-style: normal;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--text-light);
    background: var(--bg-soft);
    padding: 2px 6px;
    border-radius: 4px;
    margin-left: 4px;
}

/* ─────────────────────────────────────────────────────────────────────────
   Custom confirm modal — replaces native window.confirm()
   ───────────────────────────────────────────────────────────────────────── */
dialog.confirm-modal {
    border: 0;
    padding: 0;
    border-radius: 12px;
    background: #fff;
    max-width: 440px;
    width: calc(100% - 32px);
    box-shadow: 0 20px 50px rgba(10,10,10,.22), 0 4px 12px rgba(10,10,10,.08);
    color: var(--text);
    font-family: inherit;
}
dialog.confirm-modal::backdrop {
    background: rgba(10, 10, 10, 0.45);
    backdrop-filter: blur(2px);
}
.confirm-modal-body { padding: var(--sp-5) var(--sp-5) var(--sp-3); }
.confirm-modal-title {
    font-size: 1.1rem;
    font-weight: 600;
    margin: 0 0 var(--sp-2);
    letter-spacing: -.01em;
}
.confirm-modal-text {
    margin: 0;
    color: var(--text-muted);
    font-size: .92rem;
    line-height: 1.5;
}
.confirm-modal-text:empty { display: none; }
.confirm-modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--sp-2);
    padding: var(--sp-3) var(--sp-5) var(--sp-5);
}

/* Danger-tier CTA button — red bg, white text, hover deepens.
   Distinct from .btn-danger (ghost variant) used elsewhere. */
.btn-danger-strong {
    background: var(--danger);
    color: #fff;
    border-color: var(--danger);
}
.btn-danger-strong:hover { background: #7f1d1d; border-color: #7f1d1d; }

/* ─────────────────────────────────────────────────────────────────────────
   Toast notifications — slide-in from bottom-right
   ───────────────────────────────────────────────────────────────────────── */
.toast-host {
    position: fixed;
    bottom: 24px;
    right: 24px;
    z-index: 1100;
    display: flex;
    flex-direction: column;
    gap: 12px;
    pointer-events: none;
    max-width: calc(100vw - 48px);
}
.toast {
    pointer-events: auto;
    display: flex;
    align-items: flex-start;
    gap: 10px;
    background: #fff;
    color: var(--text);
    border: 1px solid var(--border);
    border-left: 4px solid var(--success);
    border-radius: 10px;
    box-shadow: 0 10px 28px rgba(10, 10, 10, 0.12), 0 2px 6px rgba(10, 10, 10, 0.05);
    padding: 12px 14px;
    min-width: 280px;
    max-width: 380px;
    transform: translateX(120%);
    opacity: 0;
    transition: transform .22s cubic-bezier(.21,1.02,.73,1), opacity .22s ease;
}
.toast.is-shown { transform: translateX(0); opacity: 1; }
.toast.toast-error   { border-left-color: var(--danger); }
.toast.toast-info    { border-left-color: var(--info, #2563eb); }
.toast-icon {
    font-size: 1rem;
    color: var(--success);
    margin-top: 2px;
    flex-shrink: 0;
}
.toast-error .toast-icon { color: var(--danger); }
.toast-info  .toast-icon { color: var(--info, #2563eb); }
.toast-message { flex: 1; font-size: .9rem; line-height: 1.4; }
.toast-close {
    appearance: none;
    background: transparent;
    border: 0;
    color: var(--text-muted);
    cursor: pointer;
    padding: 2px 4px;
    border-radius: 4px;
    font-size: .85rem;
    flex-shrink: 0;
}
.toast-close:hover { color: var(--text); background: var(--bg-soft); }
@media (max-width: 600px) {
    .toast-host { left: 16px; right: 16px; bottom: 16px; }
    .toast { max-width: none; min-width: 0; }
}

/* Auto-dismiss + manual-close on status banners (success only). */
.status-banner.is-fading {
    opacity: 0;
    transform: translateY(-4px);
    transition: opacity .25s ease, transform .25s ease;
}
.status-banner .banner-close {
    appearance: none;
    background: transparent;
    border: 0;
    color: inherit;
    opacity: .55;
    cursor: pointer;
    margin-left: auto;
    padding: 2px 6px;
    font-size: .9rem;
    border-radius: 4px;
    align-self: flex-start;
}
.status-banner .banner-close:hover { opacity: 1; }
.status-banner-success { display: flex; align-items: flex-start; gap: 12px; }

/* ─────────────────────────────────────────────────────────────────────────
   Empty states — used inside .data-table-wrap when there are no rows.
   Richer than plain text — icon + title + sub + optional CTA.
   ───────────────────────────────────────────────────────────────────────── */
.empty-state {
    padding: 56px 24px;
    text-align: center;
    color: var(--text-muted);
}
.empty-state-icon {
    width: 56px;
    height: 56px;
    border-radius: 14px;
    background: var(--bg-soft);
    color: var(--text-muted);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 1.5rem;
    margin: 0 auto var(--sp-3);
}
.empty-state-title {
    font-size: 1rem;
    font-weight: 600;
    color: var(--text);
    margin: 0 0 6px;
}
.empty-state-desc {
    font-size: .9rem;
    max-width: 420px;
    margin: 0 auto var(--sp-4);
    line-height: 1.5;
}
.empty-state-cta { margin-top: 0; }

/* ─────────────────────────────────────────────────────────────────────────
   Invoice payment drawer — right-side slide-out
   Premium-SaaS pattern (HoneyBook, Linear billing, Stripe Dashboard).
   Slides in from the right with a dimmed backdrop over the invoice.
   ───────────────────────────────────────────────────────────────────────── */
.pay-drawer-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(10, 10, 10, 0.45);
    z-index: 1000;
    opacity: 0;
    transition: opacity .22s ease;
    pointer-events: none;
}
body.has-pay-drawer-open .pay-drawer-backdrop {
    opacity: 1;
    pointer-events: auto;
}
.pay-drawer {
    position: fixed;
    top: 0;
    right: 0;
    height: 100vh;
    width: 480px;
    max-width: 100vw;
    background: #fff;
    box-shadow: -16px 0 48px rgba(10, 10, 10, 0.16);
    z-index: 1001;
    display: flex;
    flex-direction: column;
    transform: translateX(100%);
    transition: transform .22s ease;
}
body.has-pay-drawer-open .pay-drawer {
    transform: translateX(0);
}
body.has-pay-drawer-open {
    /* Lock body scroll so only the drawer scrolls. */
    overflow: hidden;
}
.pay-drawer-head {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: var(--sp-3);
    padding: var(--sp-5);
    border-bottom: 1px solid var(--border);
}
.pay-drawer-title {
    font-size: 1.15rem;
    font-weight: 600;
    margin: 0 0 4px;
    letter-spacing: -0.01em;
}
.pay-drawer-close {
    appearance: none;
    background: transparent;
    border: 0;
    color: var(--text-muted);
    font-size: 1.25rem;
    cursor: pointer;
    width: 32px;
    height: 32px;
    border-radius: 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
.pay-drawer-close:hover { background: var(--bg-soft); color: var(--text); }
.pay-drawer-body {
    padding: var(--sp-5);
    overflow-y: auto;
    flex: 1;
}
.pay-summary-note {
    padding: var(--sp-3);
    background: var(--bg-soft);
    border-radius: 8px;
}

@media (max-width: 600px) {
    .pay-drawer { width: 100vw; }
}

/* ─────────────────────────────────────────────────────────────────────────
   Client invoice → Square embedded payment form
   The Web Payments SDK iframes the card field into #sq-card; we style
   the surrounding shell, not the iframe itself (Square owns those styles).
   ───────────────────────────────────────────────────────────────────────── */
.sq-pay-shell {
    max-width: 480px;
    margin: 0 auto;
}
.sq-tabs {
    display: flex;
    gap: var(--sp-2);
    margin-bottom: var(--sp-4);
    border-bottom: 1px solid var(--border);
}
.sq-tab {
    appearance: none;
    background: transparent;
    border: 0;
    padding: var(--sp-2) var(--sp-3);
    font: inherit;
    color: var(--text-muted);
    cursor: pointer;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    transition: color .15s, border-color .15s;
}
.sq-tab:hover { color: var(--text); }
.sq-tab.is-active {
    color: var(--text);
    border-bottom-color: var(--primary, #111);
    font-weight: 600;
}
.sq-tab i { margin-right: 6px; }
.sq-mount {
    min-height: 90px;
    padding: var(--sp-2) 0;
}
.sq-breakdown {
    border-top: 1px solid var(--border);
    margin-top: var(--sp-4);
    padding-top: var(--sp-3);
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.sq-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    font-size: .9rem;
}
.sq-row-total {
    padding-top: var(--sp-2);
    border-top: 1px dashed var(--border);
    margin-top: 4px;
    font-weight: 600;
    font-size: 1.05rem;
}
.sq-status {
    margin-top: var(--sp-3);
    padding: var(--sp-3);
    border-radius: 8px;
    font-size: .9rem;
    background: var(--bg-soft);
    border: 1px solid var(--border);
}
.sq-status[data-kind="error"] {
    background: #fef2f2;
    border-color: #fecaca;
    color: #991b1b;
}
.sq-status[data-kind="success"] {
    background: #f0fdf4;
    border-color: #bbf7d0;
    color: #166534;
}
