/* GENERATED by scripts/build-admin-css.mjs — do not edit; edit the inputs and rebuild.
 * One stylesheet for the admin console. Inputs, in cascade order (@imports inlined
 * where they stood); sha256 of each source file:
 *   34c0c24b85c7c893dd1c196c889cabc18df4accf4ba9cb7d078746882db595dd  public/assets/brand/zds-1.6.0/styles.css
 *   405ee371f4d7e11666ce19aa89b1483d8e88c20c4549df32e189631e4a9bc05a  public/assets/brand/zds-1.6.0/tokens/fonts.css
 *   c97d25b6d407061e15acf23e85f78e91d10434e5fc9faddbdba24af90d26ed31  public/assets/brand/zds-1.6.0/tokens/brand.css
 *   602b50f34ac1524f3203c2b2c73d87ae5f04576f2cf6cfcfa641ca9a7cb5cb8e  public/assets/brand/zds-1.6.0/tokens/colors.css
 *   8b67a51f7438764982c5ac86e79d830502bf62cf9f5c18aaa8f735689dd0ecf8  public/assets/brand/zds-1.6.0/tokens/typography.css
 *   8beaeaac21c7f23b8a9b1aca64bb9113af1d42e751121424ff76536130f405cc  public/assets/brand/zds-1.6.0/tokens/spacing.css
 *   455fcf0c3424c2b47504f8ce799aab5aff9f2ee3bee4b2f6145b02181972c92f  public/assets/brand/zds-1.6.0/tokens/effects.css
 *   f3f76ca8e74c5888eba65e3ee6609636dbfa1dfa63434746e7b7d0967ddb2003  public/assets/brand/zds-1.6.0/tokens/motion.css
 *   50afc0105546de82fd24914d8fc1e21566a24b85d493439e9b7c9e31b98487bf  public/assets/brand/zds-1.6.0/tokens/charts.css
 *   3757900cffdfbe7626531583d52169b2256d5221af5574b8cacf605fc7be33b2  public/assets/brand/zds-1.6.0/tokens/base.css
 *   a2726d833b7da7aa988689ee39211d374bf2e0d59f08c0b2c929716640a03298  public/assets/brand/zds-1.6.0/components/foundation/Icon.css
 *   2454199e2ae748e2e9d98686c17333ed3340731e0dfcafc7f6c2e87a8ecbc60a  public/assets/brand/zds-1.6.0/components/foundation/Logo.css
 *   4cf1730f5e1afdb858d97f490b8272a7804c139b4f7c24bbf60581ec8e80fecd  public/assets/brand/zds-1.6.0/components/foundation/Kbd.css
 *   02e7ea898063b1cf7afb9a1ef94340966f76a8e7a4a13795fcb6ac77b5593e89  public/assets/brand/zds-1.6.0/components/feedback/Spinner.css
 *   9277a459bdb3c9fcb9ec9a65b99750da17d5628f9444cff54a6aa646e8b81637  public/assets/brand/zds-1.6.0/components/feedback/Skeleton.css
 *   e634a76d3e63c68632a138c6e4a5e68fd424c80709b484278127fe5039d17958  public/assets/brand/zds-1.6.0/components/overlays/Tooltip.css
 *   f7be992babf606e2c5283167c4734eb396a4c77141fedee596f94039559a2840  public/assets/brand/zds-1.6.0/components/actions/Button.css
 *   803dd740309f47a691a985cb89bef45bac4df7425a12a07087f2ed80d4990ef5  public/assets/brand/zds-1.6.0/components/actions/IconButton.css
 *   df1d34a5a1f911d95b64645c7c2fd238cd577503f1b4fea681b44e652d99c70d  public/assets/brand/zds-1.6.0/components/forms/Input.css
 *   1fb0c82092a428804a3ead5a613bc16f4c133c293532abb6a0b910601fea312f  public/assets/brand/zds-1.6.0/components/forms/Textarea.css
 *   00a9b0f21aa13d46659f805669727a7b61e45d001a4115472c26757397746274  public/assets/brand/zds-1.6.0/components/forms/FormGroup.css
 *   ff1fba4ecc9a1996b66456c8da60167f45126395a874d8e626b12f0f84eacc13  public/assets/brand/zds-1.6.0/components/forms/Toggle.css
 *   a25e626e0f8e444ecf86341d477e5164570b0ed0b3c1b109ac2b4b0cf5459ce5  public/assets/brand/zds-1.6.0/components/forms/ToggleGroup.css
 *   e1f9d878d0be280dad5f86e5506d4479866f9af8397b795ea898f2363d5c99e1  public/assets/brand/zds-1.6.0/components/forms/SearchField.css
 *   d41d33f550ce564c0011f6077bdd75a1194d9fb631c5d4bfdb074d99413d8cc2  public/assets/brand/zds-1.6.0/components/forms/FilterDropdown.css
 *   60e436352286af38900890852e0430f6af5704119445bff60d69f11e8a39d49b  public/assets/brand/zds-1.6.0/components/layout/Card.css
 *   65f67844b90b5ad913c9fbe60575b2c01dc13b5c346dad6df68e0a03c61ab8d3  public/assets/brand/zds-1.6.0/components/data/StatusBadge.css
 *   6f445d5297a92279dd167debdb7a7e9138646187b224020ec978859251cafd28  public/assets/brand/zds-1.6.0/components/data/EmptyState.css
 *   054aef80acb3e0d8aa1c94f06b0330bcd25349217ddce659dc453164c9a1e431  public/assets/brand/zds-1.6.0/components/data/DataControls.css
 *   4d9fd95db7df0974611cebde5a62674d61386b88ea5d7c9960efd0d6b2766156  public/assets/brand/zds-1.6.0/components/data/DataTable.css
 *   b6395083df31e4fd2913c9cdf8f129397a1814b6f0ac1796d82d62ef9bc7f74f  public/assets/brand/zds-1.6.0/components/data/DescriptionList.css
 *   18c1079927377cbcf8b3b2087d980e4d20b6bd227863992fdaddefa4550a964f  public/assets/brand/zds-1.6.0/components/data/Avatar.css
 *   713816f1017f28cc9a5d8dcc8bf4b5a4e17f6afbf82bbb7cfaa9119f51c6c3c5  public/assets/brand/zds-1.6.0/components/layout/DetailHeader.css
 *   fe4f72600ea069337eaeb3c10f69f71b468d64c57a94cfa78eb045148c1296a2  public/assets/brand/zds-1.6.0/components/navigation/SubNav.css
 *   c9db5e4102f65553a843abbe0fba65fbc3f10ae6a24d7f35f53dd2a0a58ad3de  public/assets/brand/zds-1.6.0/components/overlays/Tray.css
 *   8ccc5e073abdd76286684490337007f885adb76fb43698d4663f3bd3c8e3df9c  public/assets/brand/zds-1.6.0/components/overlays/Sheet.css
 *   8c72a2cd22e4f525101b2ca8f534e8b2f7c2b24764a58de4f8615290647ff937  public/assets/brand/zds-1.6.0/components/overlays/Toast.css
 *   71dd21089559a8fe04227d7ddef88a196efc6b676611d60de280de6675fc30b5  admin/css/zds-overrides.css
 *   a0af3a29e94d0666791b8572fdd0f202e8e5f32578abfac9887ce0599f06bf53  admin/css/compat.css
 *   965421f9332e9c4da52f1caf0f999eb326bb92e6d44bca85c9aa4d4575a6b007  admin/css/admin.css
 *   d39bc17fa4cb0582cef187f398a312be63c6d171c4a83a5637d4354aa65fd210  admin/css/app-chrome.css
 *   41a41ec85367b1a1e49b1d59f30c8aa00ef81637fdd583e93a843476e4ebbfdc  admin/css/build-requests.css
 *   034de121c0b51dff63d468b6336675178f125bba728657a00938f2a0c56eb6d5  admin/css/integrations.css
 *   ddc1213ed33f07e919f6cbd974ace51cd7af8082e239a74e37eb51096c455af9  admin/css/analytics.css
 *   7928f622aa730fcb955ba3463e26cf529c6f8fe220773311a4576916d6611ef1  admin/css/agent-work.css
 */
/* ======== /assets/zds-1.6.0/styles.css ======== */
/* @version 1.3.0 @status stable @since 2026-09-26 @updated 2026-09-28 (ZDS tokens: all files in tokens/ version as one set. Changelog: tokens/CHANGELOG.md) */
/* ---- @import /assets/zds-1.6.0/tokens/fonts.css (inlined) ---- */
/* zivvy.ai deviation (2026-09-27, carried from zds-1.0.0; ZDS 1.1.0 admin port; carried unchanged into the 1.6.0 port — tokens 1.3.0 fonts.css is identical to 1.1.0): the src:url(...otf) declarations
   were stripped from every @font-face of the export. SF Pro's licence does not permit web
   embedding, so the .otf binaries are NOT shipped on zivvy.ai. The --zivvy-font-*
   stacks (tokens/typography.css) fall back to the system face (-apple-system /
   BlinkMacSystemFont / Segoe UI / Roboto).
   Admin fix round (2026-09-27): the ten @font-face blocks left empty by the strip
   (no src, so the browser ignored them) and the export's comment about the .otf
   binaries ("Binaries supplied by Zivvy (uploads/)") were removed from this
   published copy too: they described files that are not shipped. This file now
   declares no faces on purpose. The export's original is
   docs/design-handoffs/zds-1.6.0/tokens/fonts.css. */

/* ---- end /assets/zds-1.6.0/tokens/fonts.css ---- */
/* ---- @import /assets/zds-1.6.0/tokens/brand.css (inlined) ---- */
/* Zivvy BRAND palette — the identity layer (logo lockups, motion, marketing, print).
   Source: zivvy-motion-spec.html v1.0 + lockup SVGs. Full Color = purple/gold on light;
   Reverse = cream/deep-gold on dark. NOTE: the web-app UI runs on a separate blue product
   palette (tokens/colors.css) — see readme.md "Two palettes". */
:root{
  --zivvy-brand-purple:#4D2C7E;        /* logomark body + wordmark (full color) */
  --zivvy-brand-gold:#D3B87E;          /* the bolt (full color) — "gold = found" */
  --zivvy-brand-gold-deep:#A1874F;     /* the bolt on Reverse lockups */
  --zivvy-brand-cream:#F2F1E7;         /* logomark + wordmark on Reverse */
  --zivvy-brand-ink:#17131F;           /* dark brand stage (motion concepts) */
  --zivvy-brand-ink-2:#201A2E;         /* raised panel on ink */
  --zivvy-brand-ink-border:#322A47;    /* hairline on ink */
  --zivvy-brand-lavender:#9A8FB8;      /* muted copy on ink */
  --zivvy-brand-paper:#FAF9F4;         /* light brand stage (gradient start) */
  --zivvy-brand-paper-2:#EFEDE2;       /* light brand stage (gradient end) */
  --zivvy-brand-stage-light:linear-gradient(160deg,#FAF9F4,#EFEDE2); /* @kind other */
  --zivvy-brand-stage-dark:radial-gradient(120% 120% at 30% 20%,#2A2140,#17131F); /* @kind other */
  /* Logo clear space (from clearspace proof sheet) */
  --zivvy-logo-clearspace-lockup:1em; /* @kind other */    /* = x-height of the "zivvy" wordmark */
  --zivvy-logo-clearspace-mark:25%; /* @kind other */      /* = ¼ of logomark height */
  --zivvy-logo-min-width-horizontal:120px;
  --zivvy-logo-min-width-mark:24px;
}

/* ---- end /assets/zds-1.6.0/tokens/brand.css ---- */
/* ---- @import /assets/zds-1.6.0/tokens/colors.css (inlined) ---- */
/* Zivvy PRODUCT UI palette — the web-app layer.
   Source: zivvy-platform tokens/theme-foundation.css, tokens/theme.css, tokens/psychology.css,
   themes/theme-system.css, components/*.css. Values copied verbatim, never rounded. */
:root{
  /* ---- Primary (brand blue used by the app) ---- */
  --zivvy-primary:#256EFF;
  --zivvy-primary-hover:#1A4FCC;        /* theme-foundation.css; buttons.css falls back to #4285FF */
  --zivvy-primary-light:#4285FF;
  --zivvy-primary-subtle:#EBF2FF;       /* tinted fills, active chips */
  --zivvy-primary-tint-03:rgba(37,110,255,0.03); /* card header wash */
  --zivvy-primary-tint-05:rgba(37,110,255,0.05); /* nav item hover */
  --zivvy-primary-tint-10:rgba(37,110,255,0.10); /* dropdown item hover */
  --zivvy-primary-tint-20:rgba(37,110,255,0.20); /* focus halo on dark nav */
  --zivvy-primary-tint-30:rgba(37,110,255,0.30); /* primary button hover shadow */
  --zivvy-dark:#0A0E27;                 /* top navigation, dark canvas */
  --zivvy-white:#FFFFFF;
  --zivvy-background:#F5F7FA;           /* legacy app canvas */

  /* ---- Psychology colors (behavioral triggers) ---- */
  --zivvy-calm-blue:#3B82F6;            /* interactive default: inputs, tabs, links, focus */
  --zivvy-success-green:#10B981;
  --zivvy-warning-amber:#F59E0B;
  --zivvy-urgency-red:#EF4444;
  --zivvy-neutral-gray:#6B7280;

  /* ---- Semantic status (with tints + borders) ---- */
  --zivvy-success:#10B981; --zivvy-success-hover:#059669; --zivvy-success-bg:#ECFDF5; --zivvy-success-light:#D1FAE5; --zivvy-success-border:#86EFAC; --zivvy-success-text:#065F46;
  --zivvy-warning:#F59E0B; --zivvy-warning-hover:#D97706; --zivvy-warning-bg:#FFFBEB; --zivvy-warning-light:#FEF3C7; --zivvy-warning-border:#FCD34D; --zivvy-warning-text:#92400E;
  --zivvy-danger:#EF4444;  --zivvy-danger-hover:#DC2626;  --zivvy-danger-bg:#FEF2F2;  --zivvy-danger-light:#FEE2E2;  --zivvy-danger-border:#FCA5A5;  --zivvy-danger-text:#991B1B;
  --zivvy-error:var(--zivvy-danger);
  --zivvy-info:#3B82F6;    --zivvy-info-hover:#2563EB;    --zivvy-info-bg:#EFF6FF;    --zivvy-info-light:#DBEAFE;    --zivvy-info-border:#93C5FD;    --zivvy-info-text:#1E40AF;
  /* Opportunity / money — "always golden" */
  --zivvy-opportunity:#F59E0B; --zivvy-opportunity-bg:#FEF3C7; --zivvy-opportunity-border:#FCD34D; --zivvy-opportunity-text:#92400E;
  /* Priority (tasks) */
  --zivvy-priority-low:#94A3B8;    --zivvy-priority-low-bg:#F1F5F9;    --zivvy-priority-low-text:#475569;    --zivvy-priority-low-border:#CBD5E1;
  --zivvy-priority-medium:#3B82F6; --zivvy-priority-medium-bg:#DBEAFE; --zivvy-priority-medium-text:#1E40AF; --zivvy-priority-medium-border:#3B82F6;
  --zivvy-priority-high:#F97316;   --zivvy-priority-high-bg:#FED7AA;   --zivvy-priority-high-text:#9A3412;   --zivvy-priority-high-border:#F97316;
  --zivvy-priority-urgent:#EF4444; --zivvy-priority-urgent-bg:#FEE2E2; --zivvy-priority-urgent-text:#991B1B; --zivvy-priority-urgent-border:#EF4444;
  /* Contact types (avatar/contact-cell badges) */
  --zivvy-contact-lead:#9B7EDE; --zivvy-contact-instructor:#14B8A6;
  /* Vertical accents (school type) */
  --vertical-martial-arts:#D97706; --vertical-crossfit:#DC2626; --vertical-yoga:#059669; --vertical-dance:#7C3AED; --vertical-boxing:#991B1B;

  /* ---- Neutrals: Slate (current system) ---- */
  --zivvy-slate-50:#F8FAFC; --zivvy-slate-100:#F1F5F9; --zivvy-slate-200:#E2E8F0; --zivvy-slate-300:#CBD5E1; --zivvy-slate-400:#94A3B8;
  --zivvy-slate-500:#64748B; --zivvy-slate-600:#475569; --zivvy-slate-700:#334155; --zivvy-slate-800:#1E293B; --zivvy-slate-900:#0F172A;
  /* ---- Neutrals: Gray (legacy, still in many components) ---- */
  --zivvy-gray-50:#F9FAFB; --zivvy-gray-100:#F3F4F6; --zivvy-gray-200:#E5E7EB; --zivvy-gray-300:#D1D5DB; --zivvy-gray-400:#9CA3AF;
  --zivvy-gray-500:#6B7280; --zivvy-gray-600:#4B5563; --zivvy-gray-700:#374151; --zivvy-gray-800:#1F2937; --zivvy-gray-900:#111827;

  /* ---- Top navigation (constant across themes) ---- */
  --zivvy-nav-bg:#0A0E27; --zivvy-nav-text:#FFFFFF; --zivvy-nav-text-muted:rgba(255,255,255,0.7);
  --zivvy-nav-hover:rgba(255,255,255,0.1); --zivvy-nav-hover-strong:rgba(255,255,255,0.15); --zivvy-nav-border:rgba(255,255,255,0.1); --zivvy-nav-field-border:rgba(255,255,255,0.4);
}

/* ---- Semantic theme aliases (LIGHT, default) — use these in components ---- */
:root,[data-theme="light"]{
  --theme-bg-base:#FFFFFF; --theme-bg-primary:#FFFFFF; --theme-bg-secondary:#F8FAFC; --theme-bg-tertiary:#F1F5F9;
  --theme-bg-hover:#F8FAFC; --theme-bg-selected:#EFF6FF; --theme-bg-overlay:rgba(15,23,42,0.5); --theme-bg-canvas:#F5F7FA;
  --theme-text-primary:#0F172A; --theme-text-secondary:#475569; --theme-text-tertiary:#475569; --theme-text-muted:#CBD5E1; --theme-text-inverse:#FFFFFF;
  --theme-border-primary:#E2E8F0; --theme-border-secondary:#CBD5E1; --theme-border-hover:#94A3B8; --theme-border-focus:var(--zivvy-calm-blue);
  --theme-interactive-default:var(--zivvy-calm-blue); --theme-interactive-hover:#3A7BC8; --theme-interactive-active:#2563EB; --theme-interactive-disabled:#CBD5E1;
  /* 1.2.0 AA tokens: action grounds carry white text ≥4.5:1; border-control is the resting boundary of inputs and outlined controls (≥3:1) */
  --theme-action-primary:#2563EB; --theme-action-success-hover:#065F46; --theme-border-control:var(--zivvy-slate-500);
  --theme-success:var(--zivvy-success-green); --theme-warning:var(--zivvy-warning-amber); --theme-danger:var(--zivvy-urgency-red); --theme-info:var(--zivvy-calm-blue); --theme-neutral:var(--zivvy-neutral-gray);
  --theme-status-pending:#F59E0B; --theme-status-inprogress:#3B82F6; --theme-status-completed:#10B981; --theme-status-blocked:#EF4444; --theme-status-overdue:#DC2626;
  --theme-primary:#256EFF; --theme-primary-hover:#1A4FCC; --theme-nav-bg:#0A0E27; --theme-subnav-bg:#FFFFFF;
}

/* ---- DARK theme ---- */
[data-theme="dark"]{
  --theme-bg-base:#1E293B; --theme-bg-primary:#1E293B; --theme-bg-secondary:#0F172A; --theme-bg-tertiary:#334155;
  --theme-bg-hover:#334155; --theme-bg-selected:#1E3A8A; --theme-bg-overlay:rgba(0,0,0,0.7); --theme-bg-canvas:#0F172A;
  --theme-text-primary:#F1F5F9; --theme-text-secondary:#CBD5E1; --theme-text-tertiary:#CBD5E1; --theme-text-muted:#475569; --theme-text-inverse:#0F172A;
  --theme-border-primary:#334155; --theme-border-secondary:#475569; --theme-border-hover:#64748B; --theme-border-focus:#60A5FA;
  --theme-interactive-default:#60A5FA; --theme-interactive-hover:#93C5FD; --theme-interactive-active:#BFDBFE; --theme-interactive-disabled:#475569;
  --theme-action-primary:#2563EB; --theme-action-success-hover:#065F46; --theme-border-control:var(--zivvy-slate-400);
  --theme-success:#34D399; --theme-warning:#FBBF24; --theme-danger:#F87171; --theme-info:#60A5FA; --theme-neutral:#9CA3AF;
  --theme-status-pending:#FBBF24; --theme-status-inprogress:#60A5FA; --theme-status-completed:#34D399; --theme-status-blocked:#F87171; --theme-status-overdue:#EF4444;
  --zivvy-nav-bg:#1E293B; --zivvy-nav-text:#F1F5F9; --zivvy-nav-border:#334155; --theme-subnav-bg:#1E293B;
  /* Status + money text and tints on dark surfaces (ZDS 1.1.0) */
  --zivvy-success-text:#34D399; --zivvy-danger-text:#F87171; --zivvy-warning-text:#FBBF24; --zivvy-info-text:#93C5FD; --zivvy-opportunity-text:#FBBF24;
  --zivvy-success-bg:rgba(16,185,129,0.12); --zivvy-success-light:rgba(16,185,129,0.18);
  --zivvy-danger-bg:rgba(239,68,68,0.12); --zivvy-danger-light:rgba(239,68,68,0.18);
  --zivvy-warning-bg:rgba(245,158,11,0.12); --zivvy-warning-light:rgba(245,158,11,0.18); --zivvy-warning-border:rgba(245,158,11,0.4);
  --zivvy-info-bg:rgba(59,130,246,0.12); --zivvy-info-light:rgba(59,130,246,0.2);
  --zivvy-opportunity-bg:rgba(245,158,11,0.18);
  /* Visa's navy mark is invisible on dark; CardBrand reads this */
  --zivvy-card-visa:#FFFFFF;
}

/* 1.3.0: text colours for the violet (prospect/lead) and teal (instructor) contact badges. The old #9B7EDE / #14B8A6 were 2.95 and 2.5:1. */
:root{--zivvy-violet-text:#6D28D9; --zivvy-teal-text:#0F766E;}
[data-theme="dark"]{--zivvy-violet-text:#C4B5FD; --zivvy-teal-text:#5EEAD4;}

/* ---- end /assets/zds-1.6.0/tokens/colors.css ---- */
/* ---- @import /assets/zds-1.6.0/tokens/typography.css (inlined) ---- */
/* Zivvy typography tokens — SF Pro Display for headlines, SF Pro Text for body/UI.
   RHYTHM24: 24px baseline. Source: tokens/typography.css + tokens/theme-foundation.css. */
:root{
  --zivvy-font-display:'SF Pro Display',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;
  --zivvy-font-text:'SF Pro Text',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;
  --zivvy-font-system:var(--zivvy-font-text);
  --zivvy-font-mono:'SF Mono',Menlo,Monaco,Consolas,'Courier New',monospace; /* kbd hints only; system mono, no webfont */
  --font-display:var(--zivvy-font-display); --font-text:var(--zivvy-font-text);
  /* Scale */
  --zivvy-text-xs:12px; --zivvy-text-sm:14px; --zivvy-text-base:16px; --zivvy-text-lg:18px; --zivvy-text-xl:20px;
  --zivvy-text-2xl:24px; --zivvy-text-3xl:30px; --zivvy-text-4xl:36px; --zivvy-text-5xl:48px; --zivvy-text-6xl:64px;
  /* Off-grid sizes the product actually uses (badges, helper text, contact names, page titles) */
  --zivvy-text-2xs:11px; --zivvy-text-sm-minus:13px; --zivvy-text-md:15px; --zivvy-text-page-title:28px; --zivvy-text-settings-title:32px;
  /* Legacy role aliases */
  --zivvy-font-hero:var(--zivvy-text-5xl); --zivvy-font-h1:var(--zivvy-text-4xl); --zivvy-font-h2:var(--zivvy-text-2xl); --zivvy-font-h3:var(--zivvy-text-xl); --zivvy-font-body:var(--zivvy-text-base); --zivvy-font-small:var(--zivvy-text-sm);
  /* Line heights (px, rhythm-based) */
  --zivvy-leading-tight:20px; --zivvy-leading-snug:22px; --zivvy-leading-normal:24px; --zivvy-leading-relaxed:28px; --zivvy-leading-loose:32px;
  --zivvy-leading-rhythm-1:24px; --zivvy-leading-rhythm-2:48px; --zivvy-leading-rhythm-3:72px;
  --zivvy-line-heading:1.1; /* @kind other */
  --zivvy-line-tight:1.25; /* @kind other */
  --zivvy-line-body:1.5; /* @kind other */
  /* Weights */
  --zivvy-weight-light:300; --zivvy-weight-normal:400; --zivvy-weight-medium:500; --zivvy-weight-semibold:600; --zivvy-weight-bold:700; --zivvy-weight-extrabold:800;
  /* Tracking — tighter for large Display, wider for small Text */
  --zivvy-tracking-tighter:-0.02em; --zivvy-tracking-tight:-0.01em; --zivvy-tracking-normal:0em; --zivvy-tracking-wide:0.01em; --zivvy-tracking-wider:0.02em; --zivvy-tracking-widest:0.05em;
  --zivvy-tracking-caps:0.5px; /* uppercase table headers, priority badges, step labels */
}

/* ---- end /assets/zds-1.6.0/tokens/typography.css ---- */
/* ---- @import /assets/zds-1.6.0/tokens/spacing.css (inlined) ---- */
/* Zivvy spacing — GRID4_RHYTHM24_TOUCH44_TIMING300 foundation.
   Source: tokens/spacing.css, tokens/psychology.css, themes/theme-system.css, layouts/*. */
:root{
  /* GRID4 scale */
  --zivvy-space-half:2px; --zivvy-space-1:4px; --zivvy-space-1-half:6px; --zivvy-space-2:8px; --zivvy-space-2-half:10px; --zivvy-space-3:12px; --zivvy-space-3-half:14px;
  --zivvy-space-4:16px; --zivvy-space-5:20px; --zivvy-space-6:24px; --zivvy-space-7:28px; --zivvy-space-8:32px; --zivvy-space-9:36px; --zivvy-space-10:40px;
  --zivvy-space-11:44px; --zivvy-space-12:48px; --zivvy-space-14:56px; --zivvy-space-16:64px; --zivvy-space-20:80px; --zivvy-space-24:96px; --zivvy-space-25:100px;
  --zivvy-space-50:200px; --zivvy-space-100:400px; --zivvy-space-150:600px; --zivvy-space-200:800px;
  --zivvy-space-xs:4px; --zivvy-space-sm:8px; --zivvy-space-md:16px; --zivvy-space-lg:24px; --zivvy-space-xl:32px;
  /* RHYTHM24 */
  --zivvy-baseline:24px; --zivvy-rhythm-half:12px; --zivvy-rhythm-1:24px; --zivvy-rhythm-2:48px; --zivvy-rhythm-3:72px; --zivvy-rhythm-4:96px;
  /* Psychological spacing */
  --zivvy-spacing-urgent:8px; --zivvy-spacing-comfortable:24px; --zivvy-spacing-contemplation:32px; --zivvy-spacing-separation:48px;
  /* TOUCH44 */
  --zivvy-touch-minimum:44px; --zivvy-touch-min:44px; --zivvy-touch-comfortable:48px; --zivvy-touch-premium:56px; --zivvy-touch-mobile:56px; --zivvy-touch-hero:64px;
  /* Radii */
  --zivvy-radius-sm:4px; --zivvy-radius-md:8px; --zivvy-radius-lg:12px; --zivvy-radius-xl:16px; --zivvy-radius-2xl:20px; --zivvy-radius-full:9999px;
  --zivvy-radius-button:8px; --zivvy-radius-input:8px; --zivvy-radius-card:12px; --zivvy-radius-modal:12px; --zivvy-radius-pill:16px; --zivvy-radius-badge:4px;
  /* Layout constants */
  --zivvy-nav-height:56px; --zivvy-subnav-height:48px; --zivvy-chrome-height:104px; --zivvy-sidebar-width:240px;
  --zivvy-container-max:1400px; --zivvy-container-max-wide:1536px; --zivvy-container-max-narrow:1200px; --zivvy-content-padding:24px; --container-padding:24px;
  --zivvy-card-padding:24px; --zivvy-card-header-height:56px; --zivvy-tray-width:600px; --zivvy-sheet-sm:320px; --zivvy-sheet-md:480px; --zivvy-sheet-lg:640px; --zivvy-sheet-xl:800px;
  --zivvy-modal-sm:400px; --zivvy-modal-md:600px; --zivvy-modal-lg:800px;
  --zivvy-profile-grid:320px 1fr 380px; /* @kind other */
  /* Z-index */
  --zivvy-z-dropdown:100; /* @kind other */
  --zivvy-z-sticky:200; /* @kind other */
  --zivvy-z-overlay:300; /* @kind other */
  --zivvy-z-modal:400; /* @kind other */
  --zivvy-z-subnav:999; /* @kind other */
  --zivvy-z-nav:1000; /* @kind other */
  --zivvy-z-sheet:9999; /* @kind other */
  --zivvy-z-toast:99999; /* @kind other */
}

/* ---- end /assets/zds-1.6.0/tokens/spacing.css ---- */
/* ---- @import /assets/zds-1.6.0/tokens/effects.css (inlined) ---- */
/* Zivvy shadows, focus rings, overlays, blur. Source: tokens/theme.css, theme-foundation.css, components/*. */
:root{
  --theme-shadow-xs:0 1px 2px 0 rgba(0,0,0,0.05);
  --theme-shadow-sm:0 1px 3px 0 rgba(0,0,0,0.1),0 1px 2px 0 rgba(0,0,0,0.06);
  --theme-shadow-md:0 4px 6px -1px rgba(0,0,0,0.1),0 2px 4px -1px rgba(0,0,0,0.06);
  --theme-shadow-lg:0 10px 15px -3px rgba(0,0,0,0.1),0 4px 6px -2px rgba(0,0,0,0.05);
  --theme-shadow-xl:0 20px 25px -5px rgba(0,0,0,0.1),0 10px 10px -5px rgba(0,0,0,0.04);
  --theme-shadow-focus:0 0 0 3px rgba(59,130,246,0.1);
  --zivvy-shadow-sm:0 1px 2px rgba(0,0,0,0.05); --zivvy-shadow-md:0 4px 6px rgba(0,0,0,0.1); --zivvy-shadow-lg:0 10px 15px rgba(0,0,0,0.1); --zivvy-shadow-xl:0 20px 25px rgba(0,0,0,0.1);
  /* Component-specific */
  --zivvy-shadow-primary-hover:0 4px 12px rgba(37,110,255,0.3);   /* primary button hover */
  --zivvy-shadow-fab:0 4px 12px rgba(37,110,255,0.4),0 2px 4px rgba(0,0,0,0.1);
  --zivvy-shadow-toast:0 8px 24px rgba(0,0,0,0.3),0 0 0 1px rgba(0,0,0,0.1);
  --zivvy-shadow-tray:-4px 0 24px rgba(0,0,0,0.15);
  --zivvy-shadow-sticky-bar:0 -4px 12px rgba(0,0,0,0.08);
  --zivvy-shadow-modal-legacy:0 20px 60px rgba(0,0,0,0.3);
  --zivvy-shadow-glass:0 12px 32px rgba(0,0,0,0.15),0 4px 12px rgba(0,0,0,0.1),inset 0 1px 0 rgba(255,255,255,0.5);
  --zivvy-shadow-step-active:0 0 0 4px rgba(37,110,255,0.1);
  --zivvy-shadow-toggle-knob:0 2px 4px rgba(0,0,0,0.2);
  --zivvy-shadow-segment-inset:inset 0 1px 3px rgba(0,0,0,0.1);
  /* Focus */
  --zivvy-focus-ring:0 0 0 3px rgba(59,130,246,0.1); --zivvy-focus-ring-nav:0 0 0 3px rgba(37,110,255,0.2); --zivvy-focus-outline:2px solid var(--theme-interactive-default);
  /* Overlays + blur */
  --zivvy-overlay:rgba(15,23,42,0.5); --zivvy-overlay-legacy:rgba(0,0,0,0.5);
  --zivvy-blur-backdrop:4px; /* @kind other */
  --zivvy-blur-toolbar:8px; /* @kind other */
  --zivvy-blur-glass:20px; /* @kind other */
  --zivvy-glass-bg:rgba(255,255,255,0.95); --zivvy-glass-border:rgba(255,255,255,0.3);
  /* Gradients actually used in the product */
  --zivvy-gradient-bulk:linear-gradient(135deg,rgba(59,130,246,0.95) 0%,rgba(37,99,235,0.95) 100%); /* @kind other */
  --zivvy-gradient-progress:linear-gradient(90deg,#3B82F6 0%,#10B981 100%); /* @kind other */
  --zivvy-gradient-card-header:linear-gradient(to right,rgba(37,110,255,0.03),transparent); /* @kind other */
  --zivvy-gradient-live-stats:linear-gradient(90deg,#F0F9FF 0%,#E0F2FE 100%); /* @kind other */
  --zivvy-gradient-shine:linear-gradient(90deg,transparent 0%,rgba(255,255,255,0.3) 50%,transparent 100%); /* @kind other */
  --zivvy-border-width:1px; /* @kind other */
  --zivvy-border-width-strong:2px; /* @kind other */
  --zivvy-border-width-active-tab:3px; /* @kind other */
  --zivvy-border-width-alert-stripe:4px; /* @kind other */
}
[data-theme="dark"]{
  --theme-shadow-xs:0 1px 2px 0 rgba(0,0,0,0.3);
  --theme-shadow-sm:0 1px 3px 0 rgba(0,0,0,0.4),0 1px 2px 0 rgba(0,0,0,0.3);
  --theme-shadow-md:0 4px 6px -1px rgba(0,0,0,0.4),0 2px 4px -1px rgba(0,0,0,0.3);
  --theme-shadow-lg:0 10px 15px -3px rgba(0,0,0,0.5),0 4px 6px -2px rgba(0,0,0,0.4);
  --theme-shadow-xl:0 20px 25px -5px rgba(0,0,0,0.6),0 10px 10px -5px rgba(0,0,0,0.5);
  --theme-shadow-focus:0 0 0 3px rgba(96,165,250,0.2);
}

/* ---- end /assets/zds-1.6.0/tokens/effects.css ---- */
/* ---- @import /assets/zds-1.6.0/tokens/motion.css (inlined) ---- */
/* Zivvy motion — TIMING300 "dopamine" durations + brand logo-animation curves.
   Source: tokens/psychology.css, themes/theme-system.css, zivvy-motion-spec.html v1.0. */
:root{
  /* Product UI durations */
  --zivvy-dopamine-instant:150ms; /* @kind other */
  --zivvy-dopamine-quick:300ms; /* @kind other */
  --zivvy-dopamine-anticipation:600ms; /* @kind other */
  --zivvy-dopamine-reward:1200ms; /* @kind other */
  --zivvy-timing-fast:150ms; /* @kind other */
  --zivvy-timing-base:250ms; /* @kind other */
  --zivvy-timing-smooth:300ms; /* @kind other */
  --zivvy-timing-slow:350ms; /* @kind other */
  --zivvy-dopamine-timing:300ms; /* @kind other */
  --zivvy-dopamine-timing-calm:300ms; /* @kind other */
  --zivvy-transition-fast:150ms ease; /* @kind other */
  --zivvy-transition-base:250ms ease; /* @kind other */
  --zivvy-transition-slow:350ms ease; /* @kind other */
  --zivvy-transition:all 0.2s ease; /* @kind other */
  /* Product UI easings */
  --zivvy-easing:cubic-bezier(0.4,0,0.2,1); /* @kind other */ /* standard */
  --zivvy-easing-standard:cubic-bezier(0.4,0,0.2,1); /* @kind other */
  --zivvy-easing-bounce:cubic-bezier(0.68,-0.55,0.265,1.55); /* @kind other */ /* celebrations: toast, check pop */
  --zivvy-easing-snap:cubic-bezier(0.25,0.46,0.45,0.94); /* @kind other */
  --zivvy-easing-spring:cubic-bezier(0.34,1.56,0.64,1); /* @kind other */ /* FAB radial menu */
  /* Micro-interaction constants */
  --zivvy-press-scale:0.98; /* @kind other */
  --zivvy-press-scale-icon:0.95; /* @kind other */
  --zivvy-hover-lift:-1px; /* @kind other */
  --zivvy-hover-lift-card:-4px; /* @kind other */
  --zivvy-hover-scale-card:1.02; /* @kind other */
  --zivvy-loop-pulse:2s; /* @kind other */
  --zivvy-loop-shimmer:2s; /* @kind other */
  /* Brand logo animations (motion spec v1.0) */
  --zivvy-logo-ceiling:1.6s; /* @kind other */ /* no intro may delay legibility beyond this */
  --zivvy-logo-strike-total:1.5s; /* @kind other */
  --zivvy-logo-interlock-total:1.45s; /* @kind other */
  --zivvy-logo-sweep-total:1.75s; /* @kind other */
  --zivvy-logo-pulse-loop:2.4s; /* @kind other */
  --zivvy-logo-pulse-float:4.8s; /* @kind other */
  --zivvy-ease-bolt:cubic-bezier(.16,.9,.28,1); /* @kind other */
  --zivvy-ease-overshoot:cubic-bezier(.2,1.4,.4,1); /* @kind other */
  --zivvy-ease-overshoot-soft:cubic-bezier(.2,1.3,.4,1); /* @kind other */
  --zivvy-ease-settle:cubic-bezier(.2,.9,.25,1); /* @kind other */
  --zivvy-ease-rise:cubic-bezier(.2,.9,.3,1); /* @kind other */
  --zivvy-ease-sweep:cubic-bezier(.55,0,.3,1); /* @kind other */
  --zivvy-reduced-motion-fade:300ms; /* @kind other */ /* prefers-reduced-motion: swap any animation for this fade */
}

/* 1.2.2: every component animation lives here, once. Components reference these names inline and never inject their own <style>. */
@keyframes zivvy-spin{to{transform:rotate(360deg)}}
@keyframes zivvy-fade{0%,100%{opacity:1}50%{opacity:.55}}
@keyframes zivvy-sweep{from{transform:translateX(-100%)}to{transform:translateX(100%)}}
@keyframes zivvy-pop{0%{transform:scale(0)}100%{transform:scale(1)}}
@keyframes zivvy-expand{from{opacity:0}to{opacity:1}}
@keyframes zivvy-hc-in{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}
@keyframes zivvy-dd-in{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:none}}
@keyframes zivvy-abs-in{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:none}}
@keyframes zivvy-banner-in{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}
@keyframes zivvy-toolbar-in{from{opacity:0;transform:translateY(-16px)}to{opacity:1;transform:none}}
@keyframes zivvy-toast-in{from{opacity:0;transform:translateY(20px) scale(.95)}to{opacity:1;transform:none}}
@keyframes zivvy-toast-celebrate{0%{opacity:0;transform:translateY(20px) scale(.8) rotate(-5deg)}50%{transform:translateY(-5px) scale(1.05) rotate(2deg)}100%{opacity:1;transform:none}}
@keyframes zivvy-progress-shine{0%{transform:translateX(-100%)}100%{transform:translateX(100%)}}
@keyframes zivvy-belt-shimmer{0%,100%{background-position:0% 50%}50%{background-position:100% 50%}}
@keyframes zivvy-ar-shimmer{0%{background-position:-200% 0}100%{background-position:200% 0}}
@keyframes zivvy-priority-pulse{0%,100%{opacity:1}50%{opacity:.8}}
@keyframes zivvy-priority-ping{0%,100%{transform:scale(1);opacity:1}50%{transform:scale(1.3);opacity:.7}}
/* Reduced motion, one block for every component: movement becomes a plain fade, loops hold still, spinners pulse. */
@media (prefers-reduced-motion:reduce){
@keyframes zivvy-pop{from{opacity:0}to{opacity:1}}
@keyframes zivvy-hc-in{from{opacity:0}to{opacity:1}}
@keyframes zivvy-dd-in{from{opacity:0}to{opacity:1}}
@keyframes zivvy-abs-in{from{opacity:0}to{opacity:1}}
@keyframes zivvy-banner-in{from{opacity:0}to{opacity:1}}
@keyframes zivvy-toolbar-in{from{opacity:0}to{opacity:1}}
@keyframes zivvy-toast-in{from{opacity:0}to{opacity:1}}
@keyframes zivvy-toast-celebrate{from{opacity:0}to{opacity:1}}
@keyframes zivvy-spin{0%,100%{opacity:1}50%{opacity:.55}}
@keyframes zivvy-sweep{from,to{opacity:0}}
@keyframes zivvy-progress-shine{from,to{opacity:0}}
@keyframes zivvy-belt-shimmer{from,to{background-position:0% 50%}}
@keyframes zivvy-ar-shimmer{from,to{background-position:0 0}}
@keyframes zivvy-priority-ping{from,to{transform:none;opacity:1}}
}

/* ---- end /assets/zds-1.6.0/tokens/motion.css ---- */
/* ---- @import /assets/zds-1.6.0/tokens/charts.css (inlined) ---- */
/* Zivvy data-visualization palette. Source: tokens/chart-colors.css v1.0 (WCAG AA, colorblind-safe). */
:root{
  /* Categorical core 8 (in order of importance) */
  --chart-cat-1:#256EFF; --chart-cat-2:#00C3AC; --chart-cat-3:#9958B3; --chart-cat-4:#F59E0B; --chart-cat-5:#10B981; --chart-cat-6:#EC9712; --chart-cat-7:#FF7A6B; --chart-cat-8:#64748B;
  --chart-cat-9:#06B6D4; --chart-cat-10:#8B5CF6; --chart-cat-11:#F97316; --chart-cat-12:#14B8A6;
  --chart-cat-1-light:#E0F2FE; --chart-cat-2-light:#CCFBF1; --chart-cat-3-light:#EDE9FE; --chart-cat-4-light:#FEF3C7; --chart-cat-5-light:#D1FAE5; --chart-cat-6-light:#FEF3C7; --chart-cat-7-light:#FEE2E2; --chart-cat-8-light:#F1F5F9;
  /* Sequential primary (7 steps) */
  --chart-seq-primary-1:#E0F2FE; --chart-seq-primary-2:#BAE6FD; --chart-seq-primary-3:#7DD3FC; --chart-seq-primary-4:#38BDF8; --chart-seq-primary-5:#0EA5E9; --chart-seq-primary-6:#0284C7; --chart-seq-primary-7:#0C4A6E;
  --chart-seq-success-1:#D1FAE5; --chart-seq-success-3:#6EE7B7; --chart-seq-success-5:#10B981; --chart-seq-success-7:#047857;
  /* Diverging */
  --chart-div-neg-strong:#DC2626; --chart-div-neg-moderate:#EF4444; --chart-div-neg-mild:#FCA5A5; --chart-div-neutral:#E5E7EB; --chart-div-pos-mild:#86EFAC; --chart-div-pos-moderate:#10B981; --chart-div-pos-strong:#059669;
  /* Financial */
  --chart-revenue:#10B981; --chart-expense:#EF4444; --chart-profit:#00C3AC; --chart-loss:#DC2626; --chart-forecast:#7DD3FC; --chart-target:#9958B3; --chart-actual:#256EFF; --chart-variance:#F59E0B;
  /* Canvas */
  --chart-bg-canvas:#FFFFFF; --chart-bg-panel:#F9FAFB; --chart-grid-line:#E5E7EB; --chart-grid-line-emphasis:#D1D5DB; --chart-axis-line:#9CA3AF; --chart-axis-text:#6B7280;
  --chart-tooltip-bg:rgba(10,14,39,0.95); --chart-tooltip-text:#FFFFFF; --chart-selection-overlay:rgba(37,110,255,0.15);
}
[data-theme="dark"]{
  /* Canvas (ZDS 1.1.0). Series colours stay the same — they already pass on #1E293B. */
  --chart-bg-canvas:#1E293B; --chart-bg-panel:#0F172A;
  --chart-grid-line:#334155; --chart-grid-line-emphasis:#475569; --chart-axis-line:#64748B; --chart-axis-text:#94A3B8;
  --chart-div-neutral:#475569; --chart-selection-overlay:rgba(37,110,255,0.25);
}

/* ---- end /assets/zds-1.6.0/tokens/charts.css ---- */
/* ---- @import /assets/zds-1.6.0/tokens/base.css (inlined) ---- */
/* Minimal base — mirrors zivvy-platform base/fonts.css + layouts/layout.css resets.
   Body text is SF Pro Text at 16/24; Material Symbols Rounded is the icon font. */
*,*::before,*::after{box-sizing:border-box}
html{font-size:16px;line-height:24px}
body{margin:0;font-family:var(--zivvy-font-text);font-size:var(--zivvy-text-base);line-height:var(--zivvy-leading-rhythm-1);color:var(--theme-text-primary);background:var(--theme-bg-secondary);text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-feature-settings:"kern" 1,"liga" 1,"calt" 1}
h1,h2,h3,h4{font-family:var(--zivvy-font-display);font-weight:var(--zivvy-weight-semibold);color:var(--theme-text-primary);font-feature-settings:"kern" 1,"liga" 1,"calt" 1,"case" 1,"cpsp" 1;text-wrap:balance}
/* Additive to the codebase (not in zivvy-platform yet): balance multi-line headlines, avoid orphans in prose. Never on table cells, pills or anything nowrap. */
p,.zivvy-prose,.zivvy-helper{text-wrap:pretty}
.tabular-nums,.metric-value,.currency-value{font-variant-numeric:tabular-nums lining-nums}
a{color:var(--theme-interactive-active);text-decoration:none}a:hover{color:var(--theme-interactive-active);text-decoration:underline}
/* 1.2.0: browser placeholder grey (#757575) fails on dark fields; nav fields keep the muted nav ink */
::placeholder{color:var(--theme-text-secondary);opacity:1}
[data-zds-nav-field]::placeholder{color:var(--zivvy-nav-text-muted)}
.material-symbols-rounded{font-family:'Material Symbols Rounded';font-weight:normal;font-style:normal;font-size:20px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;direction:ltr;vertical-align:middle;user-select:none;-webkit-font-smoothing:antialiased;font-feature-settings:'liga';font-variation-settings:'FILL' 1,'wght' 400,'GRAD' 0,'opsz' 24}
.material-symbols-rounded.outlined{font-variation-settings:'FILL' 0,'wght' 400,'GRAD' 0,'opsz' 24}
.material-symbols-rounded.filled{font-variation-settings:'FILL' 1,'wght' 400,'GRAD' 0,'opsz' 24}
/* 1.2.1: one keyboard focus ring for every control (SC 2.4.7 / 1.4.11). !important beats the inline outline:none many components set.
   Text fields keep their own border + ring. Components that draw their own ring (inset rows, menu items) opt out with data-zds-ring.
   [data-zds-focus] lets tools/contrast-gate.txt show the ring when it can only simulate focus. */
:where(a[href],button,summary,[role="button"],[role="switch"],[role="checkbox"],[role="radio"],[role="tab"],[role="option"],[role="menuitem"],[role="link"],[tabindex="0"]):not([data-zds-ring]):is(:focus-visible,[data-zds-focus]){outline:2px solid var(--theme-border-focus)!important;outline-offset:2px!important}
/* Fields with no focus style of their own opt in with data-zds-focus-ring (inset, so it isn't clipped by the field's box) */
[data-zds-focus-ring]:is(:focus-visible,[data-zds-focus]){outline:2px solid var(--theme-border-focus)!important;outline-offset:-2px!important}
/* 1.2.2: Fab + FabMenu items: ring 3px outside the round button (moved from an injected <style> in Fab.jsx) */
.zds-fab:focus-visible{outline:2px solid var(--theme-interactive-default);outline-offset:3px}
/* 1.3.0: RichTextEditor content. The editor is contentEditable, so its children can't take inline styles. */
[data-zds-rte]{font-family:var(--zivvy-font-text);font-size:16px;line-height:24px;color:var(--theme-text-primary);overflow-wrap:anywhere;-webkit-font-smoothing:antialiased}
[data-zds-rte] p{margin:0 0 12px}
[data-zds-rte] h2{font-family:var(--zivvy-font-display);font-size:20px;line-height:28px;font-weight:600;margin:16px 0 8px}
[data-zds-rte] h3{font-family:var(--zivvy-font-display);font-size:18px;line-height:24px;font-weight:600;margin:16px 0 8px}
[data-zds-rte] ul,[data-zds-rte] ol{margin:0 0 12px;padding-left:24px}
[data-zds-rte] li{margin-bottom:4px}
[data-zds-rte] blockquote{margin:12px 0;padding-left:16px;border-left:3px solid var(--theme-border-control);color:var(--theme-text-secondary)}
[data-zds-rte] code{font-family:var(--zivvy-font-mono);font-size:14px;background:var(--theme-bg-tertiary);padding:2px 6px;border-radius:4px}
[data-zds-rte] a{color:var(--theme-interactive-active);text-decoration:underline}
[data-zds-rte] > :first-child{margin-top:0}
[data-zds-rte] > :last-child{margin-bottom:0}

/* ---- end /assets/zds-1.6.0/tokens/base.css ---- */

/* ======== /assets/zds-1.6.0/components/foundation/Icon.css ======== */
/* ZDS Icon 1.0.4 — ported from docs/design-handoffs/zds-1.6.0/components/foundation/Icon.jsx (ZDS 1.6.0)
   1.6.0 (1.0.4): no visual change for known glyphs; an unknown one is an empty box
   of the same size (Icon.js).
   Start: the zds-1.0.0 components.css transcription. Diffed against the 1.1.0 JSX:
   unchanged (size, colour = currentColor, flex-shrink 0, vertical-align middle).
   Deviations (recorded):
   - Inline SVG (Material Symbols Rounded paths, FILL 1, wght 400 — Apache 2.0)
     instead of the font ligature; Icon.js builds the element. See Icon.js.
   - Sizes are modifiers: the JSX takes any number; the sizes ZDS components use
     are carried (12 is new here: StatusBadge sm). Any other size gets width/height
     attributes from Icon.js. */
.zds-icon{display:inline-block;flex-shrink:0;width:20px;height:20px;fill:currentColor;vertical-align:middle;user-select:none;-webkit-user-select:none}
.zds-icon--12{width:12px;height:12px}
.zds-icon--16{width:16px;height:16px}
.zds-icon--18{width:18px;height:18px}
.zds-icon--24{width:24px;height:24px}
.zds-icon--28{width:28px;height:28px}
.zds-icon--40{width:40px;height:40px}
.zds-icon--64{width:64px;height:64px}

/* ======== /assets/zds-1.6.0/components/foundation/Logo.css ======== */
/* ZDS Logo 1.0.0 — ported from docs/design-handoffs/zds-1.6.0/components/foundation/Logo.jsx (ZDS 1.6.0)
   1.6.0: the JSX is unchanged from 1.1.0; this file is carried as it was.
   Start: the zds-1.0.0 components.css transcription. Diffed against the 1.1.0 JSX:
   unchanged (<img>, height prop, width auto, display block).
   Deviations (recorded):
   - The JSX builds `assets/logo/<file>`. On zivvy.ai the mark is served only
     from /logos/ (root CLAUDE.md, Brand asset routing), so markup passes the
     /logos/ path: horizontal-fullcolor → /logos/primary/zivvy-horizontal-fullcolor.svg,
     horizontal-reverse → /logos/primary/zivvy-horizontal-reverse.svg,
     mark → /logos/icon/zivvy-logomark-fullcolor.svg on light grounds and
     /logos/icon/zivvy-logomark-reverse.png on navy (public/logos/CLAUDE.md:
     fullcolor never on dark; the reverse logomark ships as PNG only). The export's
     zivvy-logomark.svg (cream tile) is not a /logos/ file and is not used.
   - Height is a modifier (the JSX takes any number): 24, 28, 32 (default). */
.zds-logo{display:block;height:32px;width:auto}
.zds-logo--24{height:24px}
.zds-logo--28{height:28px}

/* ======== /assets/zds-1.6.0/components/foundation/Kbd.css ======== */
/* ZDS Kbd 0.1.0 — ported from docs/design-handoffs/zds-1.6.0/components/foundation/Kbd.jsx (ZDS 1.6.0)
   1.6.0: the JSX is unchanged from 1.1.0; this file is carried as it was.
   <kbd class="zds-kbd"> (md 24) · --sm (20) · --on-dark (navy nav).
   KbdCombo → <span class="zds-kbd-combo"> holding kbds and optional
   <span class="zds-kbd-combo__then">then</span> between keys of a sequence.
   Deviations: none. */
.zds-kbd{min-width:24px;height:24px;padding:0 6px;box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;border-radius:4px;border:1px solid var(--theme-border-primary);border-bottom-width:2px;background:var(--theme-bg-secondary);color:var(--theme-text-secondary);font-family:var(--zivvy-font-mono);font-size:12px;line-height:16px;font-weight:500}
.zds-kbd--sm{min-width:20px;height:20px;padding:0 5px;font-size:11px}
.zds-kbd--on-dark{border:none;border-bottom-width:0;background:rgba(255,255,255,.1);color:rgba(255,255,255,.7)}
.zds-kbd-combo{display:inline-flex;align-items:center;gap:4px}
.zds-kbd-combo__then{font-family:var(--zivvy-font-text);font-size:12px;line-height:16px;color:var(--theme-text-tertiary)}

/* ======== /assets/zds-1.6.0/components/feedback/Spinner.css ======== */
/* ZDS Spinner 0.1.1 — ported from docs/design-handoffs/zds-1.6.0/components/feedback/Spinner.jsx (ZDS 1.6.0)
   <span class="zds-spinner" role="status" aria-label="Loading">. Sizes: 20 (default,
   2px ring), --16 (2px), --24 / --32 (3px), --40 (4px) — the JSX's width rule
   (≤20 → 2, ≤32 → 3, else 4). --current: arc in currentColor (Button loading).
   --on-filled: track rgba(255,255,255,.35) (Button filled). Colour/track are
   custom properties (--zds-spinner-color, --zds-spinner-track) so the JSX's
   color/track props stay available.
   0.1.1: the zivvy-spin / zivvy-fade keyframes come from tokens/motion.css (was
   local zds-spin / zds-fade); needs styles.css.
   Deviations (recorded): the JSX picks the animation in JS from matchMedia at
   render; here @media (prefers-reduced-motion) swaps the 800ms spin for the 2s
   opacity pulse, which also follows a live change of the setting. */
.zds-spinner{--zds-spinner-color:var(--zivvy-primary);--zds-spinner-track:var(--theme-border-primary);display:inline-block;flex:none;width:20px;height:20px;border-radius:50%;box-sizing:border-box;border:2px solid var(--zds-spinner-track);border-top-color:var(--zds-spinner-color);animation:zivvy-spin 800ms linear infinite}
.zds-spinner--16{width:16px;height:16px}
.zds-spinner--24{width:24px;height:24px;border-width:3px}
.zds-spinner--32{width:32px;height:32px;border-width:3px}
.zds-spinner--40{width:40px;height:40px;border-width:4px}
.zds-spinner--current{--zds-spinner-color:currentColor}
.zds-spinner--on-filled{--zds-spinner-track:rgba(255,255,255,.35)}
@media (prefers-reduced-motion:reduce){.zds-spinner{animation:zivvy-fade 2s ease-in-out infinite}}

/* ======== /assets/zds-1.6.0/components/feedback/Skeleton.css ======== */
/* ZDS Skeleton 0.1.1 — ported from docs/design-handoffs/zds-1.6.0/components/feedback/Skeleton.jsx (ZDS 1.6.0)
   1.6.0 (0.1.1): the sweep and pulse keyframes moved to tokens/motion.css (zivvy-sweep, zivvy-fade); the local zds-* keyframes are gone.
   Bone: <span class="zds-skeleton" aria-hidden="true"> — line (default, 14px, radius 4),
   --circle (radius 50%, height = width), --block (32px, radius 6). Width/height are
   set by the page (inline style or its own class), as the JSX takes them as props.
   Group: <div class="zds-skeleton-group" role="status" aria-busy="true" aria-label="Loading">
   … bones … <div class="zds-skeleton-group__sweep" aria-hidden="true"></div></div>
   Deviations (recorded): reduced motion is a CSS media query instead of a
   render-time matchMedia check (same result: 40% bg-primary veil, 2s pulse). */
.zds-skeleton{display:block;flex:none;width:100%;height:14px;border-radius:4px;background:var(--theme-bg-tertiary)}
.zds-skeleton--circle{border-radius:50%;aspect-ratio:1/1;height:auto}
.zds-skeleton--block{height:32px;border-radius:6px}
.zds-skeleton-group{position:relative;overflow:hidden}
.zds-skeleton-group__sweep{position:absolute;inset:0;pointer-events:none;background:linear-gradient(90deg,transparent 0%,color-mix(in srgb,var(--theme-bg-primary) 70%,transparent) 50%,transparent 100%);animation:zivvy-sweep 2s cubic-bezier(.4,0,.2,1) infinite}
@media (prefers-reduced-motion:reduce){.zds-skeleton-group__sweep{background:var(--theme-bg-primary);opacity:.4;animation:zivvy-fade 2s ease-in-out infinite}}

/* ======== /assets/zds-1.6.0/components/overlays/Tooltip.css ======== */
/* ZDS Tooltip 0.1.1 — ported from docs/design-handoffs/zds-1.6.0/components/overlays/Tooltip.jsx (ZDS 1.6.0)
   1.6.0 (0.1.1): no style change; behaviour changes are in Tooltip.js.
   <span class="zds-tooltip"> trigger <span class="zds-tooltip__bubble zds-tooltip__bubble--top"
   role="tooltip" id="…"><span>words</span><span class="zds-tooltip__kbd">⌘K</span></span></span>
   Shown state (React useState) = .is-shown on the wrapper, set by Tooltip.js.
   Placements: --top (default) · --bottom · --left · --right. max-width 280 via
   --zds-tooltip-max.
   Deviations (recorded): motion is removed under prefers-reduced-motion (ZDS
   readme rule; the JSX keeps its 150ms fade). */
.zds-tooltip{position:relative;display:inline-flex}
.zds-tooltip__bubble{position:absolute;z-index:50;pointer-events:none;opacity:0;display:flex;gap:8px;align-items:center;width:max-content;max-width:var(--zds-tooltip-max,280px);padding:6px 10px;border-radius:8px;background:var(--chart-tooltip-bg);border:1px solid rgba(255,255,255,.1);color:var(--chart-tooltip-text);font-family:var(--zivvy-font-text);font-size:12px;line-height:16px;font-weight:500;box-shadow:var(--theme-shadow-md);transition:opacity 150ms cubic-bezier(.4,0,.2,1),transform 150ms cubic-bezier(.4,0,.2,1)}
.zds-tooltip__bubble--top{bottom:calc(100% + 8px);left:50%;transform:translate(-50%,4px)}
.zds-tooltip__bubble--bottom{top:calc(100% + 8px);left:50%;transform:translate(-50%,-4px)}
.zds-tooltip__bubble--left{right:calc(100% + 8px);top:50%;transform:translate(4px,-50%)}
.zds-tooltip__bubble--right{left:calc(100% + 8px);top:50%;transform:translate(-4px,-50%)}
.zds-tooltip.is-shown > .zds-tooltip__bubble{opacity:1}
.zds-tooltip.is-shown > .zds-tooltip__bubble--top,.zds-tooltip.is-shown > .zds-tooltip__bubble--bottom{transform:translate(-50%,0)}
.zds-tooltip.is-shown > .zds-tooltip__bubble--left,.zds-tooltip.is-shown > .zds-tooltip__bubble--right{transform:translate(0,-50%)}
.zds-tooltip__kbd{font-family:var(--zivvy-font-mono);font-size:11px;line-height:16px;padding:0 6px;border-radius:4px;background:rgba(255,255,255,.15);color:rgba(255,255,255,.7)}
@media (prefers-reduced-motion:reduce){.zds-tooltip__bubble{transition:none}}

/* ======== /assets/zds-1.6.0/components/actions/Button.css ======== */
/* ZDS Button 1.1.1 — ported from docs/design-handoffs/zds-1.6.0/components/actions/Button.jsx (ZDS 1.6.0)
   Start: the zds-1.0.0 components.css transcription (Button 1.0.0), diffed against
   the 1.1.0 and then the 1.6.0 JSX and corrected:
   - 1.0.1: `loading` shows the ZDS Spinner (ring in currentColor, 800ms; track
     rgba(255,255,255,.35) on filled, border-primary otherwise) and opacity .85
     (was a rotating glyph at .7).
   - 1.1.0: filled grounds that carry white text at 4.5:1 (primary
     --theme-action-primary, danger --zivvy-danger-hover → hover
     --zivvy-priority-urgent-text, success --chart-seq-success-7 → hover
     --theme-action-success-hover); primary tint → --theme-interactive-active;
     outlined secondary border → --theme-border-control. New --nav variant and
     the count badge.
   - 1.1.1: outlined / ghost / text danger and success labels (and outlined
     borders) → --zivvy-danger-text / --zivvy-success-text.
   - Size md (40/16/14) added; ghost variant and the secondary / danger / success
     colours added for every variant (1.0.0 carried only what /build used).
   Markup: <button class="zds-button [variant] [color] [size]" type="button">
     [<svg class="zds-icon">] label [<svg class="zds-icon">]
     [<span class="zds-button__count">3</span>]</button>
   Variant: (filled) · --outlined · --ghost · --text · --nav.  Colour: (primary) ·
   --secondary · --danger · --success.  Size: --sm · --md · (default 44) · --lg ·
   --xl.  --full = fullWidth.  --icon-only = iconOnly (square, min-width = height).
   Count: the caller renders the number (JSX caps at "99+" and omits the badge
     when count ≤ 0); on --icon-only it sits absolute top-right.
   Loading: aria-busy="true" + disabled, first child
     <span class="zds-spinner zds-spinner--current [zds-spinner--on-filled]"
      role="status" aria-label="<label>"></span> (leading icon omitted).
   Porting rules: React hover/active → :hover/:active; motion removed under
   prefers-reduced-motion. The keyboard focus ring now comes from the global
   :focus-visible ring in tokens/base.css (upstream since tokens 1.2.1), so the
   port's own :focus-visible rule is dropped.
   Deviations (recorded): the JSX's literal hexes are read from the tokens that
   hold the same values (#64748B/#475569 = --zivvy-slate-500/600);
   rgba(37,110,255,.1) = --zivvy-primary-tint-10. */
.zds-button{margin:0;font:inherit;cursor:pointer;outline:none;text-decoration:none;display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:44px;padding:0 16px;font-family:var(--zivvy-font-text);font-size:14px;font-weight:500;line-height:1.5;letter-spacing:.01em;border-radius:8px;white-space:nowrap;user-select:none;-webkit-user-select:none;position:relative;flex-shrink:0;transition:all 300ms cubic-bezier(.4,0,.2,1);
  --zds-btn-bg:var(--theme-action-primary);--zds-btn-hover:var(--zivvy-primary-hover);--zds-btn-glow:var(--zivvy-shadow-primary-hover);--zds-btn-tint:var(--theme-interactive-active);--zds-btn-tint-bg:var(--zivvy-primary-tint-10);
  /* only filled·primary lifts on hover (JSX); every other combination sets --zds-btn-lift:none */
  background:var(--zds-btn-bg);color:#FFFFFF;border:1px solid transparent;box-shadow:var(--zivvy-shadow-sm)}
.zds-button .zds-icon{width:20px;height:20px}
.zds-button:hover{background:var(--zds-btn-hover);box-shadow:var(--zds-btn-glow);color:#FFFFFF;text-decoration:none;transform:var(--zds-btn-lift,translateY(-1px))}
.zds-button:active{transform:scale(.98)}
/* colour */
.zds-button--secondary{--zds-btn-lift:none;--zds-btn-bg:var(--zivvy-slate-500);--zds-btn-hover:var(--zivvy-slate-600);--zds-btn-glow:var(--theme-shadow-md);--zds-btn-tint:var(--theme-text-primary);--zds-btn-tint-bg:var(--theme-bg-hover)}
.zds-button--danger{--zds-btn-lift:none;--zds-btn-bg:var(--zivvy-danger-hover);--zds-btn-hover:var(--zivvy-priority-urgent-text);--zds-btn-glow:var(--theme-shadow-md);--zds-btn-tint:var(--zivvy-danger-text);--zds-btn-tint-bg:rgba(239,68,68,.1)}
.zds-button--success{--zds-btn-lift:none;--zds-btn-bg:var(--chart-seq-success-7);--zds-btn-hover:var(--theme-action-success-hover);--zds-btn-glow:var(--theme-shadow-md);--zds-btn-tint:var(--zivvy-success-text);--zds-btn-tint-bg:rgba(16,185,129,.1)}
/* variant */
.zds-button--outlined{--zds-btn-lift:none;background:transparent;color:var(--zds-btn-tint);border-color:var(--zds-btn-tint);box-shadow:none}
.zds-button--outlined:hover{background:var(--theme-bg-hover);color:var(--zds-btn-tint);box-shadow:none}
.zds-button--outlined.zds-button--secondary{border-color:var(--theme-border-control)}
.zds-button--outlined.zds-button--secondary:hover{border-color:var(--theme-border-hover)}
.zds-button--ghost,.zds-button--text{--zds-btn-lift:none;background:transparent;color:var(--zds-btn-tint);border-color:transparent;box-shadow:none}
.zds-button--ghost:hover,.zds-button--text:hover{background:var(--zds-btn-tint-bg);color:var(--zds-btn-tint);box-shadow:none}
.zds-button--ghost.zds-button--secondary{color:var(--theme-text-secondary)}
.zds-button--ghost.zds-button--secondary:hover{color:var(--theme-text-primary)}
.zds-button--text.zds-button--secondary,.zds-button--text.zds-button--secondary:hover{color:var(--theme-text-secondary)}
.zds-button--text{padding:0 8px}
.zds-button--nav,.zds-button--nav:hover{--zds-btn-lift:none;color:var(--zivvy-nav-text);border-color:transparent;box-shadow:none}
.zds-button--nav{background:transparent}
.zds-button--nav:hover{background:var(--zivvy-nav-hover)}
/* size */
.zds-button--sm{min-height:32px;padding:0 12px;font-size:12px}
.zds-button--sm .zds-icon{width:18px;height:18px}
.zds-button--md{min-height:40px}
.zds-button--lg{min-height:44px;padding:0 20px;font-size:16px}
.zds-button--lg .zds-icon{width:24px;height:24px}
.zds-button--xl{min-height:48px;padding:0 24px;font-size:16px}
.zds-button--xl .zds-icon{width:28px;height:28px}
.zds-button--text.zds-button--sm,.zds-button--text.zds-button--md,.zds-button--text.zds-button--lg,.zds-button--text.zds-button--xl{padding:0 8px}
.zds-button--full{display:flex;width:100%}
.zds-button--icon-only{gap:0;padding:0;min-width:44px}
.zds-button--icon-only.zds-button--sm{min-width:32px}
.zds-button--icon-only.zds-button--md{min-width:40px}
.zds-button--icon-only.zds-button--xl{min-width:48px}
/* state */
.zds-button:disabled{opacity:.4;cursor:not-allowed;pointer-events:none;transform:none}
.zds-button[aria-busy="true"]{opacity:.85;cursor:wait;pointer-events:none;transform:none}
.zds-button .zds-spinner{--zds-spinner-color:currentColor}
.zds-button--sm .zds-spinner{width:16px;height:16px}
/* count badge */
.zds-button__count{position:static;min-width:18px;height:18px;padding:0 5px;box-sizing:border-box;border-radius:9999px;background:var(--zivvy-danger-hover);color:#FFFFFF;font-size:11px;font-weight:700;line-height:18px;text-align:center;font-variant-numeric:tabular-nums;box-shadow:none}
.zds-button--icon-only .zds-button__count{position:absolute;top:2px;right:2px}
.zds-button--nav .zds-button__count{box-shadow:0 0 0 2px var(--zivvy-nav-bg)}
@media (prefers-reduced-motion:reduce){.zds-button{transition:none}.zds-button:hover,.zds-button:active{transform:none!important}}

/* ======== /assets/zds-1.6.0/components/actions/IconButton.css ======== */
/* ZDS IconButton 1.1.0 — ported from docs/design-handoffs/zds-1.6.0/components/actions/IconButton.jsx (ZDS 1.6.0)
   1.6.0: the JSX is unchanged from 1.1.0; this file is carried as it was.
   IconButton has no styles of its own in 1.1.0: it is a Button (iconOnly, variant
   ghost, colour secondary, size default = 44×44) wrapped in a Tooltip that shows
   `label`. Requires Button.css and Tooltip.css. Markup (or IconButton.js):
   <span class="zds-tooltip"><button class="zds-button zds-button--ghost
     zds-button--secondary zds-button--icon-only" type="button" aria-label="Back">
     <svg class="zds-icon">…</svg></button><span class="zds-tooltip__bubble
     zds-tooltip__bubble--top" role="tooltip"><span>Back</span></span></span>
   Disabled or tooltip=false: the bare button, no wrapper (as the JSX).
   Deviations: none beyond Button's and Tooltip's. This file exists so the port
   set is one file per component; the rule below only keeps the wrapper from
   adding a baseline gap under the button. */
.zds-tooltip > .zds-button--icon-only{vertical-align:top}

/* ======== /assets/zds-1.6.0/components/forms/Input.css ======== */
/* ZDS Input 1.0.3 — ported from docs/design-handoffs/zds-1.6.0/components/forms/Input.jsx (ZDS 1.6.0)
   1.6.0 (1.0.3): resting border is --theme-border-control (≥3:1); padding 9px 16px with border-box; focus = 1px ring + 4px 15% halo; leading glyph is text-secondary (tertiary when disabled).
   Start: the zds-1.0.0 components.css transcription; diffed against the 1.1.0 JSX
   (fieldStyle): unchanged. Re-diffed against 1.6.0 below.
   Markup: <input class="zds-input" placeholder="…"> ; with a leading icon:
   <div class="zds-input-wrap"><svg class="zds-icon">…</svg><input class="zds-input zds-input--icon"></div>
   State mapping (recorded): `hasValue` (React state) → :not(:placeholder-shown), so
   every field carries a placeholder; `focus` → :focus; `error` → [aria-invalid="true"];
   disabled → :disabled. */
.zds-input{width:100%;box-sizing:border-box;min-height:44px;margin:0;padding:9px 16px;font-size:16px;line-height:24px;font-family:var(--zivvy-font-text);color:var(--theme-text-primary);background:var(--theme-bg-primary);border:1px solid var(--theme-border-control);border-radius:8px;outline:none;box-shadow:none;transition:all 200ms ease}
.zds-input::placeholder{color:var(--theme-text-tertiary);opacity:1}
.zds-input:not(:placeholder-shown){border-color:var(--theme-interactive-default);background-color:rgba(59,130,246,.02)}
.zds-input:focus{border-color:var(--theme-interactive-default);box-shadow:0 0 0 1px var(--theme-border-focus),0 0 0 4px rgba(59,130,246,.15)}
.zds-input[aria-invalid="true"]{border-color:#EF4444;background-color:var(--theme-bg-primary)}
.zds-input[aria-invalid="true"]:focus{box-shadow:0 0 0 1px #EF4444,0 0 0 4px rgba(239,68,68,.15)}
.zds-input:disabled{color:var(--theme-text-tertiary);background-color:var(--theme-bg-tertiary);cursor:not-allowed}
.zds-input-wrap{position:relative}
.zds-input-wrap > .zds-icon{position:absolute;left:12px;top:12px;pointer-events:none;color:var(--theme-text-secondary)}
.zds-input-wrap:has(.zds-input:disabled) > .zds-icon{color:var(--theme-text-tertiary)}
.zds-input--icon{padding-left:40px}
@media (prefers-reduced-motion:reduce){.zds-input{transition:none}}

/* ======== /assets/zds-1.6.0/components/forms/Textarea.css ======== */
/* ZDS Textarea 1.0.1 — ported from docs/design-handoffs/zds-1.6.0/components/forms/Textarea.jsx (ZDS 1.6.0)
   1.6.0 (1.0.1): first port. Multi-line field styled like Input (the JSX shares
   Input's fieldStyle): border-box, so the 80px minimum includes padding and
   border; vertical resize only.
   Markup: <textarea class="zds-textarea" rows="3" placeholder="…"></textarea>
   rows="3" is the JSX default and is written in the markup: a <textarea> with no
   rows attribute is two lines tall, not three.
   State mapping (recorded), the same as Input.css: `hasValue` (React state) →
   :not(:placeholder-shown), so every field carries a placeholder; `focus` →
   :focus; `error` → [aria-invalid="true"]; disabled → :disabled.
   As the JSX: an error field keeps the plain surface and the error border
   whether or not it holds a value or has focus; a disabled field takes the
   tertiary surface in every state.
   Deviations (recorded):
   - The error border and ring colour is written through --zivvy-danger, the
     token that holds the JSX's literal value in both themes. The two 15% halo
     colours have no token and stay literal, as in Input.css.
   - prefers-reduced-motion drops the 200ms transition, as Input.css does. */
.zds-textarea{width:100%;box-sizing:border-box;min-height:80px;padding:9px 16px;font-size:16px;line-height:24px;font-family:var(--zivvy-font-text);color:var(--theme-text-primary);background:var(--theme-bg-primary);border:1px solid var(--theme-border-control);border-radius:8px;outline:none;box-shadow:none;transition:all 200ms ease;resize:vertical}
.zds-textarea:not(:placeholder-shown){border-color:var(--theme-interactive-default);background:rgba(59,130,246,.02)}
.zds-textarea:focus{border-color:var(--theme-interactive-default);box-shadow:0 0 0 1px var(--theme-border-focus),0 0 0 4px rgba(59,130,246,.15)}
.zds-textarea[aria-invalid="true"]{border-color:var(--zivvy-danger);background:var(--theme-bg-primary)}
.zds-textarea[aria-invalid="true"]:focus{box-shadow:0 0 0 1px var(--zivvy-danger),0 0 0 4px rgba(239,68,68,.15)}
.zds-textarea:disabled{color:var(--theme-text-tertiary);background:var(--theme-bg-tertiary);cursor:not-allowed}
@media (prefers-reduced-motion:reduce){.zds-textarea{transition:none}}

/* ======== /assets/zds-1.6.0/components/forms/FormGroup.css ======== */
/* ZDS FormGroup 1.0.2 — ported from docs/design-handoffs/zds-1.6.0/components/forms/FormGroup.jsx (ZDS 1.6.0)
   1.6.0 (1.0.2): first port. Label + field + helper wrapper. The required
   asterisk, the error label and the error text are --zivvy-danger-text (AA in
   both themes).
   Requires Icon>=1.0.1 for the valid check (check_circle, 16px).
   Markup:
   <div class="zds-form-group [zds-form-group--error]">
     <label class="zds-form-group__label" for="title">Title
       <span class="zds-form-group__required">*</span>
       <svg class="zds-icon zds-icon--16 zds-form-group__valid">…</svg></label>
     [the field: zds-input, zds-textarea, …]
     <div class="zds-form-group__helper">Helper text, or the error message</div>
   </div>
   As the JSX: label 14/20 medium, 8px between label, field and helper, helper
   12/16 pulled 4px towards the field. Every part is optional and is left out,
   not rendered empty. An error message replaces the helper text in the same
   element, and --error turns the label and that text red. The valid check sits at
   the right end of the label and never shows beside an error (the JSX renders it
   only when valid and not in error; here --error hides it).
   Stack groups 16px apart; a two-column row is a grid, 1fr 1fr, gap 16px.
   `for` on the label names the field's id (the JSX's htmlFor).
   Deviations (recorded):
   - The check's literal green is written through --zivvy-success, the token that
     holds that exact value in both themes.
   - The check is Icon.js's inline SVG, not the font ligature (Icon's deviation). */
.zds-form-group{display:flex;flex-direction:column;gap:8px;font-family:var(--zivvy-font-text)}
.zds-form-group__label{display:flex;align-items:center;gap:8px;font-size:14px;font-weight:500;line-height:20px;color:var(--theme-text-primary)}
.zds-form-group__required{color:var(--zivvy-danger-text);font-weight:600}
.zds-form-group__valid{margin-left:auto;color:var(--zivvy-success)}
.zds-form-group__helper{margin-top:-4px;font-size:12px;line-height:16px;color:var(--theme-text-secondary)}
.zds-form-group--error > .zds-form-group__label,.zds-form-group--error > .zds-form-group__helper{color:var(--zivvy-danger-text)}
.zds-form-group--error > .zds-form-group__label > .zds-form-group__valid{display:none}

/* ======== /assets/zds-1.6.0/components/forms/Toggle.css ======== */
/* ZDS Toggle 1.0.2 — ported from docs/design-handoffs/zds-1.6.0/components/forms/Toggle.jsx (ZDS 1.6.0)
   1.6.0 (1.0.2): off track is bg-tertiary with an inset 1px --theme-border-control ring, and the off knob gets the same 1px ring (≥3:1 boundary).
   Start: the zds-1.0.0 components.css transcription; diffed against the 1.1.0 JSX:
   unchanged (track 56×32, knob 24, 250ms, primary when on, label 14/500 +
   description 12/16).
   Markup: <label class="zds-toggle"><span class="zds-toggle__text"><span
   class="zds-toggle__label">Label</span>[<span class="zds-toggle__description">…</span>]
   </span><input class="zds-toggle__switch" type="checkbox" role="switch"></label>
   Deviations (recorded): the switch is a native checkbox (role="switch",
   appearance:none track, ::before knob) instead of <button role="switch">, so it
   submits and fires `change`; --switch-first puts the switch before the text (the JSX puts it
   last). A focus ring is added (the JSX sets outline:none with none). */
.zds-toggle{display:flex;align-items:center;justify-content:space-between;gap:16px;cursor:pointer;font-family:var(--zivvy-font-text)}
.zds-toggle--switch-first{flex-direction:row-reverse;justify-content:flex-end;gap:12px}
.zds-toggle__text{display:flex;flex-direction:column;gap:2px}
.zds-toggle__label{font-size:14px;font-weight:500;color:var(--theme-text-primary);line-height:20px}
.zds-toggle__description{font-size:12px;line-height:16px;color:var(--theme-text-secondary)}
.zds-toggle__switch{appearance:none;-webkit-appearance:none;position:relative;width:56px;height:32px;flex-shrink:0;margin:0;background:var(--theme-bg-tertiary);box-shadow:inset 0 0 0 1px var(--theme-border-control);border-radius:16px;border:none;padding:0;cursor:pointer;transition:background-color 250ms ease;outline:none}
.zds-toggle__switch::before{content:"";position:absolute;top:4px;left:4px;width:24px;height:24px;background:#FFFFFF;border-radius:50%;box-shadow:0 2px 4px rgba(0,0,0,.2),0 0 0 1px var(--theme-border-control);transform:translateX(0);transition:transform 250ms ease}
.zds-toggle__switch:checked{background:var(--zivvy-primary);box-shadow:none}
.zds-toggle__switch:checked::before{box-shadow:0 2px 4px rgba(0,0,0,.2);transform:translateX(24px)}
.zds-toggle__switch:focus-visible{outline:2px solid var(--theme-border-focus);outline-offset:2px}
.zds-toggle__switch:disabled{opacity:.5;cursor:not-allowed}
.zds-toggle:has(.zds-toggle__switch:disabled){cursor:not-allowed}
@media (prefers-reduced-motion:reduce){.zds-toggle__switch,.zds-toggle__switch::before{transition:none}}

/* ======== /assets/zds-1.6.0/components/forms/ToggleGroup.css ======== */
/* ZDS ToggleGroup 1.0.2 — ported from docs/design-handoffs/zds-1.6.0/components/forms/ToggleGroup.jsx (ZDS 1.6.0)
   1.6.0 (1.0.2): group border is --theme-border-control; the selected ground is --theme-interactive-active (white text ≥4.5:1).
   Start: the zds-1.0.0 components.css transcription; diffed against the 1.1.0 JSX:
   added the per-option disabled opacity (.5); removed the 1.0.0 port's hover
   colour on a SELECTED option (the JSX computes hover as `hover && !on`, so a
   selected option never changes on hover); the legend carries the 12px gap as a
   margin (a <legend> is not a flex item, so the fieldset's gap skips it).
   Markup: <fieldset class="zds-toggle-group [--vertical] [--full]"><legend
   class="zds-toggle-group__label">Label</legend><div class="zds-toggle-group__group"
   role="group"><label class="zds-toggle-group__item"><input class="zds-toggle-group__input"
   type="checkbox|radio" name value>Option</label>…</div></fieldset>
   Deviations (recorded): each option is a <label> wrapping a native checkbox
   (multiple) or radio (single) that covers the label and is transparent, instead
   of <button aria-pressed>: native inputs give named values, keyboard behaviour
   and a `change` event for free. Selected = :has(input:checked). A focus ring is
   added (the JSX sets none). ToggleGroup.js builds it and reads values. */
.zds-toggle-group{display:flex;flex-direction:column;gap:12px;font-family:var(--zivvy-font-text);margin:0;padding:0;border:0;min-width:0}
.zds-toggle-group__label{padding:0;margin:0 0 12px;font-size:16px;line-height:24px;font-weight:500;color:var(--theme-text-primary)}
.zds-toggle-group__required{color:var(--theme-danger);font-weight:600}
.zds-toggle-group__group{display:flex;flex-direction:row;gap:8px;background:var(--theme-bg-secondary);border:1px solid var(--theme-border-control);border-radius:8px;padding:4px;width:fit-content;max-width:100%}
.zds-toggle-group--vertical .zds-toggle-group__group{flex-direction:column}
.zds-toggle-group--full .zds-toggle-group__group{width:100%}
.zds-toggle-group__item{position:relative;display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:44px;padding:8px 16px;font-size:14px;line-height:24px;font-weight:500;text-align:center;white-space:nowrap;color:var(--theme-text-secondary);background:transparent;border-radius:4px;cursor:pointer;box-shadow:none;transition:all 300ms ease;user-select:none;-webkit-user-select:none}
.zds-toggle-group--full:not(.zds-toggle-group--vertical) .zds-toggle-group__item{flex:1}
.zds-toggle-group__item:hover{color:var(--theme-text-primary);background:var(--theme-bg-hover)}
.zds-toggle-group__item:has(input:checked){color:var(--theme-text-inverse);background:var(--theme-interactive-active);font-weight:600;box-shadow:var(--theme-shadow-sm)}
.zds-toggle-group__item:has(input:focus-visible){outline:2px solid var(--theme-border-focus);outline-offset:2px}
.zds-toggle-group__item:has(input:disabled){cursor:not-allowed;opacity:.5}
.zds-toggle-group__input{position:absolute;inset:0;width:100%;height:100%;margin:0;opacity:0;cursor:inherit;z-index:1}
@media (prefers-reduced-motion:reduce){.zds-toggle-group__item{transition:none}}

/* ======== /assets/zds-1.6.0/components/forms/SearchField.css ======== */
/* ZDS SearchField 0.1.2 — ported from docs/design-handoffs/zds-1.6.0/components/forms/SearchField.jsx (ZDS 1.6.0)
   The one search box. Whole component ported: simple mode (icon, ⌘K hint, clear,
   Esc) and advanced mode (debounced "Searching…", summary, facet chips with live
   counts, result rows, ↑/↓ + Enter, both empty states). SearchField.js builds it.
   Markup (simple, static-HTML use + ZDS.SearchField.init):
   <div class="zds-search-field [--sm|--md] [--nav]">
     <div class="zds-search-field__box">
       <span class="zds-search-field__lead"><svg class="zds-icon">search</svg>
         <span class="zds-spinner" role="status" aria-label="Searching contacts"></span></span>
       <input class="zds-search-field__input" type="search" aria-label placeholder>
       <button class="zds-search-field__clear" type="button" aria-label="Clear search"><svg class="zds-icon zds-icon--18">cancel</svg></button>
       <kbd class="zds-kbd zds-kbd--sm">⌘K</kbd>
     </div>
     <div class="zds-search-field__panel" role="listbox" hidden>…</div>
   </div>
   State mapping (recorded): focus (React state) → :focus-within on the box; the
   clear button shows when the input has a value and the ⌘K hint only when it is
   empty and unfocused (:has(input:placeholder-shown) — every field carries a
   placeholder, as in the JSX); busy → .is-busy (spinner replaces the glyph);
   active row → [aria-selected="true"]; chip on → [aria-pressed="true"];
   disabled → :has(input:disabled) (tertiary ground and ink, not-allowed cursor,
   no clear button or ⌘K hint; nav variant at 50% opacity).
   0.1.2 contrast: resting border → --theme-border-control; glyph and clear →
   --theme-text-secondary; chip-on and avatar grounds → --theme-action-primary;
   links and type badge → --theme-interactive-active; nav border fallback 40%.
   Placeholder ink comes from tokens/base.css (::placeholder → text-secondary,
   [data-zds-nav-field] → nav muted ink). Focus rings on the clear button, chips
   and links come from the global ring in tokens/base.css.
   Deviations (recorded):
   - The browser's own type="search" cancel glyph is hidden. The JSX leaves it,
     so Chromium draws two clear buttons side by side once there is a value.
   - Chip and row hover (React state) → :hover. */
.zds-search-field{position:relative;width:100%;max-width:100%;flex-shrink:1;font-family:var(--zivvy-font-text);--zds-sf-h:44px}
.zds-search-field--md{--zds-sf-h:40px}
.zds-search-field--sm{--zds-sf-h:32px}
.zds-search-field--nav{--zds-sf-h:40px;width:320px;min-width:180px}
.zds-search-field__box{display:flex;align-items:center;gap:8px;height:var(--zds-sf-h);padding:0 8px 0 12px;box-sizing:border-box;border-radius:8px;border:1px solid var(--theme-border-control);background:var(--theme-bg-primary);box-shadow:none;transition:all 250ms ease}
.zds-search-field__box:focus-within{border-color:var(--zivvy-calm-blue);box-shadow:0 0 0 3px rgba(59,130,246,.1)}
.zds-search-field__lead{display:flex;pointer-events:none;color:var(--theme-text-secondary)}
.zds-search-field__lead .zds-icon{width:20px;height:20px}
.zds-search-field--sm .zds-search-field__lead .zds-icon{width:18px;height:18px}
.zds-search-field__lead .zds-spinner{display:none}
.zds-search-field.is-busy .zds-search-field__lead .zds-spinner{display:inline-block}
.zds-search-field.is-busy .zds-search-field__lead .zds-icon{display:none}
.zds-search-field--sm .zds-search-field__lead .zds-spinner{width:16px;height:16px}
.zds-search-field__input{flex:1;min-width:0;height:100%;margin:0;padding:0;border:none;outline:none;background:transparent;font-family:inherit;font-size:16px;letter-spacing:.01em;color:var(--theme-text-primary);-webkit-appearance:none;appearance:none}
.zds-search-field--md .zds-search-field__input,.zds-search-field--sm .zds-search-field__input,.zds-search-field--nav .zds-search-field__input{font-size:14px}
.zds-search-field__input::-webkit-search-cancel-button,.zds-search-field__input::-webkit-search-decoration{-webkit-appearance:none;appearance:none;display:none}
.zds-search-field__clear{width:28px;height:28px;flex:none;display:flex;align-items:center;justify-content:center;margin:0;padding:0;border:none;border-radius:999px;background:transparent;cursor:pointer;color:var(--theme-text-secondary)}
.zds-search-field__clear .zds-icon{width:18px;height:18px}
.zds-search-field:has(.zds-search-field__input:placeholder-shown) .zds-search-field__clear{display:none}
.zds-search-field .zds-search-field__box > .zds-kbd{display:none}
.zds-search-field:has(.zds-search-field__input:placeholder-shown):not(:focus-within):not(:has(.zds-search-field__input:disabled)) .zds-search-field__box > .zds-kbd{display:inline-flex}
/* disabled (0.1.2) */
.zds-search-field:has(.zds-search-field__input:disabled) .zds-search-field__box{background:var(--theme-bg-tertiary);cursor:not-allowed}
.zds-search-field:has(.zds-search-field__input:disabled) .zds-search-field__lead,.zds-search-field__input:disabled{color:var(--theme-text-tertiary)}
.zds-search-field__input:disabled{cursor:not-allowed}
.zds-search-field:has(.zds-search-field__input:disabled) .zds-search-field__clear{display:none}
/* nav variant (navy AppNav/TopNav) */
.zds-search-field--nav .zds-search-field__box{border-radius:9999px;padding:0 12px 0 14px;border-color:var(--zivvy-nav-field-border,rgba(255,255,255,.4));background:var(--zivvy-nav-hover,rgba(255,255,255,.1))}
.zds-search-field--nav .zds-search-field__box:focus-within{border-color:var(--zivvy-primary);background:var(--zivvy-nav-hover-strong,rgba(255,255,255,.15));box-shadow:0 0 0 3px rgba(37,110,255,.2)}
.zds-search-field--nav .zds-search-field__lead,.zds-search-field--nav .zds-search-field__clear{color:var(--zivvy-nav-text-muted,rgba(255,255,255,.7))}
.zds-search-field--nav .zds-search-field__input{color:#FFFFFF}
.zds-search-field--nav:has(.zds-search-field__input:disabled) .zds-search-field__box{background:var(--zivvy-nav-hover,rgba(255,255,255,.1));opacity:.5}
.zds-search-field--nav:has(.zds-search-field__input:disabled) .zds-search-field__lead{color:var(--zivvy-nav-text-muted,rgba(255,255,255,.7))}
/* dropdown panel */
.zds-search-field__panel{position:absolute;top:calc(var(--zds-sf-h) + 8px);left:0;width:100%;max-width:calc(100vw - 16px);max-height:480px;overflow:auto;z-index:110;box-sizing:border-box;background:color-mix(in srgb,var(--theme-bg-primary) 95%,transparent);-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px);border:1px solid var(--theme-border-primary);border-radius:12px;box-shadow:var(--zivvy-shadow-lg);padding:8px}
.zds-search-field__panel[hidden]{display:none}
.zds-search-field--advanced .zds-search-field__panel{width:var(--zds-sf-dropdown,400px);padding:0}
.zds-search-field__summary{padding:10px 16px;font-size:12px;line-height:16px;letter-spacing:.02em;color:var(--theme-text-secondary);background:var(--theme-bg-secondary);border-bottom:1px solid var(--theme-border-primary)}
.zds-search-field__facets{padding:12px 16px;display:flex;flex-direction:column;gap:8px;border-bottom:1px solid var(--theme-border-primary);background:var(--theme-bg-primary)}
.zds-search-field__facets-head{display:flex;align-items:center;gap:8px}
.zds-search-field__eyebrow{font-size:12px;line-height:16px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--theme-text-tertiary)}
.zds-search-field__link{margin:0;padding:0;background:transparent;border:none;cursor:pointer;font-family:inherit;font-weight:500;color:var(--theme-interactive-active);font-size:13px}
.zds-search-field__facets-head .zds-search-field__link{margin-left:auto;font-size:12px}
.zds-search-field__chips{display:flex;flex-wrap:wrap;gap:6px}
.zds-search-field__chip{display:flex;align-items:center;gap:6px;height:28px;margin:0;padding:0 10px;border-radius:9999px;border:1px solid var(--theme-border-primary);background:var(--theme-bg-primary);color:var(--theme-text-secondary);cursor:pointer;font-family:inherit;font-size:12px;font-weight:500;white-space:nowrap;transition:all 150ms}
.zds-search-field__chip:hover{border-color:var(--zivvy-primary)}
.zds-search-field__chip[aria-pressed="true"]{border-color:var(--zivvy-primary);background:var(--theme-action-primary);color:#FFFFFF}
.zds-search-field__chip-count{font-size:11px;font-weight:600;color:var(--theme-text-tertiary);font-variant-numeric:tabular-nums lining-nums}
.zds-search-field__chip[aria-pressed="true"] .zds-search-field__chip-count{color:#FFFFFF}
.zds-search-field__row{display:flex;align-items:center;gap:12px;padding:12px 16px;border-bottom:1px solid var(--theme-border-primary);cursor:pointer;background:transparent;transition:background 150ms}
.zds-search-field__row[aria-selected="true"]{background:var(--theme-bg-selected)}
.zds-search-field__avatar{width:36px;height:36px;border-radius:50%;flex:none;background:var(--theme-action-primary);color:#FFFFFF;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:700;object-fit:cover}
.zds-search-field__text{display:flex;flex-direction:column;gap:4px;min-width:0;flex:1}
.zds-search-field__name{font-size:14px;font-weight:600;color:var(--theme-text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.zds-search-field__sub{display:flex;align-items:center;gap:8px;min-width:0}
.zds-search-field__type{flex:none;font-size:11px;font-weight:600;letter-spacing:.5px;text-transform:uppercase;padding:2px 8px;border-radius:4px;background:var(--zivvy-primary-subtle);color:var(--theme-interactive-active)}
.zds-search-field__meta{font-size:12px;color:var(--theme-text-tertiary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.zds-search-field__empty{padding:20px 16px;font-size:13px;line-height:20px;color:var(--theme-text-secondary);text-wrap:pretty}
.zds-search-field__hidden{padding:20px 16px;display:flex;flex-direction:column;align-items:flex-start;gap:8px}
.zds-search-field__hidden > span{font-size:13px;line-height:20px;color:var(--theme-text-secondary);text-wrap:pretty}
@media (prefers-reduced-motion:reduce){.zds-search-field__box,.zds-search-field__chip,.zds-search-field__row{transition:none}}

/* ======== /assets/zds-1.6.0/components/forms/FilterDropdown.css ======== */
/* ZDS FilterDropdown 1.0.3 — ported from docs/design-handoffs/zds-1.6.0/components/forms/FilterDropdown.jsx (ZDS 1.6.0)
   Compact bordered trigger + 200px menu of options. FilterDropdown.js builds it.
   <div class="zds-filter-dropdown [--sm|--lg] [--align-right] [has-value]">
     <button class="zds-filter-dropdown__trigger" type="button" aria-haspopup="listbox" aria-expanded="false">
       <svg class="zds-icon">filter_list</svg><span class="zds-filter-dropdown__text">Label</span>
       <svg class="zds-icon zds-filter-dropdown__chevron">expand_more</svg></button>
     <ul class="zds-filter-dropdown__menu" role="listbox" hidden>
       <li class="zds-filter-dropdown__option zds-filter-dropdown__option--clear" role="option" aria-selected="false">…Clear</li>
       <li class="zds-filter-dropdown__option" role="option" aria-selected="true|false">[icon]<span
         class="zds-filter-dropdown__label">Yes</span><span class="zds-filter-dropdown__count">6</span>[check]</li>
     </ul></div>
   Sizes: sm 32/12 · md 36/14 (default) · lg 44/16; icons are font-size + 4.
   State mapping (recorded): `has` (a value is chosen) → .has-value on the root;
   hover (React state) → :hover; open → aria-expanded="true"; option lit (hover or
   keyboard focus, hi/kf) → :hover and :focus-visible; trigger ring (fv) →
   :focus-visible.
   Rings (1.0.3): trigger and options carry data-zds-ring and keep their own rings
   instead of the global one in tokens/base.css — trigger: 2px bg-primary gap +
   2px --theme-border-focus box-shadow; options: inset 2px --theme-border-focus
   outline.
   Contrast (1.0.2): resting trigger border → --theme-border-control; option
   counts and the Clear option → --theme-text-secondary.
   Deviations (recorded): motion off under prefers-reduced-motion. */
.zds-filter-dropdown{position:relative;display:inline-block;font-family:var(--zivvy-font-text);--zds-fd-h:36px;--zds-fd-fs:14px;--zds-fd-ic:18px}
.zds-filter-dropdown--sm{--zds-fd-h:32px;--zds-fd-fs:12px;--zds-fd-ic:16px}
.zds-filter-dropdown--lg{--zds-fd-h:44px;--zds-fd-fs:16px;--zds-fd-ic:20px}
.zds-filter-dropdown__trigger{display:flex;align-items:center;gap:8px;height:var(--zds-fd-h);min-height:var(--zds-fd-h);margin:0;padding:0 12px;background:var(--theme-bg-primary);border:1px solid var(--theme-border-control);border-radius:8px;font-size:var(--zds-fd-fs);font-weight:500;font-family:inherit;color:var(--theme-text-secondary);cursor:pointer;white-space:nowrap;user-select:none;-webkit-user-select:none;transition:all 300ms ease;outline:none}
.zds-filter-dropdown__trigger .zds-icon{width:var(--zds-fd-ic);height:var(--zds-fd-ic)}
.zds-filter-dropdown__trigger:hover{background:var(--theme-bg-hover);border-color:var(--theme-interactive-default)}
.zds-filter-dropdown__trigger[aria-expanded="true"]{border-color:var(--theme-interactive-default)}
.zds-filter-dropdown__trigger:focus-visible{outline:none;box-shadow:0 0 0 2px var(--theme-bg-primary),0 0 0 4px var(--theme-border-focus)}
.zds-filter-dropdown.has-value .zds-filter-dropdown__trigger{background:rgba(59,130,246,.05);border-color:var(--theme-interactive-default);font-weight:600;color:var(--theme-text-primary)}
.zds-filter-dropdown__trigger:disabled{opacity:.5;cursor:not-allowed}
.zds-filter-dropdown__chevron{transition:transform 300ms}
.zds-filter-dropdown__trigger[aria-expanded="true"] .zds-filter-dropdown__chevron{transform:rotate(180deg)}
.zds-filter-dropdown__menu{position:absolute;top:calc(100% + 4px);left:0;right:auto;z-index:1000;min-width:200px;margin:0;padding:8px;list-style:none;background:var(--theme-bg-primary);border:1px solid var(--theme-border-primary);border-radius:8px;box-shadow:var(--theme-shadow-lg);max-height:300px;overflow-y:auto}
.zds-filter-dropdown__menu[hidden]{display:none}
.zds-filter-dropdown--align-right .zds-filter-dropdown__menu{left:auto;right:0}
.zds-filter-dropdown__option{display:flex;align-items:center;gap:8px;min-height:36px;padding:8px 12px;border-radius:4px;font-size:14px;font-weight:500;color:var(--theme-text-secondary);background:transparent;cursor:pointer;white-space:nowrap;transition:all 300ms ease;outline:none;box-sizing:border-box}
.zds-filter-dropdown__option .zds-icon{width:18px;height:18px}
.zds-filter-dropdown__option:hover,.zds-filter-dropdown__option:focus-visible{color:var(--theme-text-primary);background:var(--theme-bg-hover)}
.zds-filter-dropdown__option[aria-selected="true"]{color:var(--theme-text-primary);background:var(--theme-bg-selected)}
.zds-filter-dropdown__option:focus-visible{outline:2px solid var(--theme-border-focus);outline-offset:-2px}
.zds-filter-dropdown__label{flex:1}
.zds-filter-dropdown__count{font-size:12px;color:var(--theme-text-secondary)}
.zds-filter-dropdown__check{width:16px!important;height:16px!important;color:var(--theme-interactive-default)}
.zds-filter-dropdown__option--clear{color:var(--theme-text-secondary);border-bottom:1px solid var(--theme-border-primary);margin-bottom:4px}
.zds-filter-dropdown__option--clear .zds-icon{width:16px;height:16px}
@media (prefers-reduced-motion:reduce){.zds-filter-dropdown__trigger,.zds-filter-dropdown__chevron,.zds-filter-dropdown__option{transition:none}}

/* ======== /assets/zds-1.6.0/components/layout/Card.css ======== */
/* ZDS Card 1.0.1 — ported from docs/design-handoffs/zds-1.6.0/components/layout/Card.jsx (ZDS 1.6.0)
   1.6.0 (1.0.1): the header ground is plain --theme-bg-primary (the 3% blue wash is gone) and CardRow text is --theme-interactive-active.
   Start: the zds-1.0.0 components.css transcription (body only); diffed against
   the 1.1.0 JSX: added the 56px header (title + actions, 3% blue wash), the
   `hoverable` state and CardRow.
   Markup: <section class="zds-card [--hoverable] [--pad-N]">[<header class="zds-card__header">
   <h3 class="zds-card__title">…</h3><div class="zds-card__actions">…</div></header>]
   <div class="zds-card__body">…</div></section>
   Padding is a prop in the JSX (default 12): --pad-0/16/20/24/32 modifiers.
   CardRow: <div class="zds-card-row [--muted] [--clickable]">icon + text</div>.
   Porting rules: hover (React state) → :hover. Deviations: a hoverable card that is
   a link/button gets the 2px focus ring (the JSX has no focus state). */
.zds-card{background:var(--theme-bg-primary);border-radius:12px;border:1px solid var(--theme-border-primary);box-shadow:var(--theme-shadow-sm);transition:all 250ms ease;font-family:var(--zivvy-font-text);overflow:visible}
.zds-card__body{padding:12px}
.zds-card--pad-0 .zds-card__body{padding:0}
.zds-card--pad-16 .zds-card__body{padding:16px}
.zds-card--pad-20 .zds-card__body{padding:20px}
.zds-card--pad-24 .zds-card__body{padding:24px}
.zds-card--pad-32 .zds-card__body{padding:32px}
.zds-card--hoverable:hover{border-color:var(--theme-interactive-default);box-shadow:var(--theme-shadow-md);transform:translateY(-1px)}
.zds-card--hoverable:focus-visible{outline:2px solid var(--theme-border-focus);outline-offset:2px}
.zds-card__header{height:56px;padding:16px 20px;border-bottom:1px solid var(--theme-border-primary);display:flex;justify-content:space-between;align-items:center;background:var(--theme-bg-primary);border-radius:12px 12px 0 0;box-sizing:border-box}
.zds-card__title{margin:0;font-family:var(--zivvy-font-display);font-size:16px;font-weight:600;color:var(--theme-text-primary);display:flex;align-items:center;gap:8px}
.zds-card__actions{display:flex;align-items:center;gap:8px}
.zds-card-row{display:flex;align-items:center;gap:12px;padding:12px;border-radius:8px;min-height:44px;font-size:14px;font-weight:500;color:var(--theme-interactive-active);background:transparent;cursor:default;transition:all 150ms ease;font-family:var(--zivvy-font-text)}
.zds-card-row--muted{color:var(--theme-text-secondary)}
.zds-card-row--clickable{cursor:pointer}
.zds-card-row--clickable:hover{background:var(--theme-bg-hover)}
@media (prefers-reduced-motion:reduce){.zds-card,.zds-card-row{transition:none}.zds-card--hoverable:hover{transform:none}}

/* ======== /assets/zds-1.6.0/components/data/StatusBadge.css ======== */
/* ZDS StatusBadge 1.0.1 — ported from docs/design-handoffs/zds-1.6.0/components/data/StatusBadge.jsx (ZDS 1.6.0)
   1.6.0 (1.0.1): membership pill text darkened for AA — active #065F46 (--zivvy-success-text), expired #991B1B (--zivvy-danger-text), primary #1A4FCC (--zivvy-primary-hover).
   <span class="zds-status-badge zds-status-badge--<status> [--sm|--lg]">[icon]Label</span>
   Task statuses (bordered, capitalised, 12/16 at md): pending · inprogress ·
   completed · blocked · inactive. Membership pills (no border, 13px/600, no
   capitalisation at every size): active · warning · expired · primary.
   Sizes: sm (2px 8px, 11/12, icon 12) · md default (4px 12px, 12/16, icon 16) ·
   lg (8px 16px, 14/20, icon 20). The icon takes the border colour (task) or the
   text colour (membership), as the JSX.
   Deviations (recorded): the JSX's literal hexes are kept where no token holds
   that exact value in that role (e.g. #065F46 = --zivvy-success-text is used
   through its token; #ECFDF5 = --zivvy-success-bg; #FFFBEB = --zivvy-warning-bg;
   #B45309 has no token and stays literal). Default labels (Pending, In progress…)
   are the caller's text: this port renders whatever text the markup holds. */
.zds-status-badge{display:inline-flex;align-items:center;gap:4px;padding:4px 12px;border-radius:16px;font-size:12px;line-height:16px;font-weight:500;text-transform:capitalize;white-space:nowrap;font-family:var(--zivvy-font-text);border:1px solid transparent}
.zds-status-badge .zds-icon{width:16px;height:16px}
.zds-status-badge--sm{padding:2px 8px;font-size:11px;line-height:12px}
.zds-status-badge--sm .zds-icon{width:12px;height:12px}
.zds-status-badge--lg{padding:8px 16px;font-size:14px;line-height:20px}
.zds-status-badge--lg .zds-icon{width:20px;height:20px}
.zds-status-badge--pending{background:var(--zivvy-warning-light);color:var(--zivvy-warning-text);border-color:var(--zivvy-warning)}
.zds-status-badge--inprogress{background:var(--zivvy-info-light);color:var(--zivvy-info-text);border-color:var(--zivvy-info)}
.zds-status-badge--completed{background:var(--zivvy-success-light);color:var(--zivvy-success-text);border-color:var(--zivvy-success)}
.zds-status-badge--blocked{background:var(--zivvy-danger-light);color:var(--zivvy-danger-text);border-color:var(--zivvy-danger)}
.zds-status-badge--inactive{background:var(--zivvy-gray-100);color:var(--zivvy-gray-700);border-color:var(--zivvy-gray-400)}
.zds-status-badge--pending .zds-icon{color:var(--zivvy-warning)}
.zds-status-badge--inprogress .zds-icon{color:var(--zivvy-info)}
.zds-status-badge--completed .zds-icon{color:var(--zivvy-success)}
.zds-status-badge--blocked .zds-icon{color:var(--zivvy-danger)}
.zds-status-badge--inactive .zds-icon{color:var(--zivvy-gray-400)}
.zds-status-badge--active,.zds-status-badge--warning,.zds-status-badge--expired,.zds-status-badge--primary{font-size:13px;font-weight:600;text-transform:none;border-color:transparent}
.zds-status-badge--active{background:var(--zivvy-success-bg);color:var(--zivvy-success-text)}
.zds-status-badge--warning{background:var(--zivvy-warning-bg);color:#B45309}
.zds-status-badge--expired{background:var(--zivvy-danger-bg);color:var(--zivvy-danger-text)}
.zds-status-badge--primary{background:var(--zivvy-primary-subtle);color:var(--zivvy-primary-hover)}

/* ======== /assets/zds-1.6.0/components/data/EmptyState.css ======== */
/* ZDS EmptyState 1.0.0 — ported from docs/design-handoffs/zds-1.6.0/components/data/EmptyState.jsx (ZDS 1.6.0)
   1.6.0: the JSX is unchanged from 1.1.0; this file is carried as it was.
   Start: the zds-1.0.0 components.css transcription (default size); diffed against
   the 1.1.0 JSX: added `compact` (padding 48 24, icon 40, gap 16) and the action
   slot (margin-top 24).
   Markup: <div class="zds-empty-state [--compact]"><svg class="zds-icon zds-empty-state__icon">
   <div class="zds-empty-state__title">…</div><div class="zds-empty-state__message">…</div>
   <div class="zds-empty-state__action">…</div></div>
   Deviations: none (title/message may be <p>/<h*> elements; margins are reset). */
.zds-empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:100px;text-align:center;font-family:var(--zivvy-font-text)}
.zds-empty-state__icon,.zds-empty-state > .zds-icon{width:64px;height:64px;flex-shrink:0;fill:currentColor;color:var(--theme-text-tertiary);margin-bottom:24px}
.zds-empty-state__title{margin:0 0 8px;font-family:var(--zivvy-font-display);font-size:20px;line-height:28px;font-weight:600;color:var(--theme-text-primary);text-wrap:balance}
.zds-empty-state__message{margin:0;font-size:14px;line-height:20px;color:var(--theme-text-secondary);max-width:420px;text-wrap:pretty}
.zds-empty-state__action{margin-top:24px}
.zds-empty-state--compact{padding:48px 24px}
.zds-empty-state--compact .zds-empty-state__icon,.zds-empty-state--compact > .zds-icon{width:40px;height:40px;margin-bottom:16px}

/* ======== /assets/zds-1.6.0/components/data/DataControls.css ======== */
/* ZDS DataControls 1.2.0 — ported from docs/design-handoffs/zds-1.6.0/components/data/DataControls.jsx (ZDS 1.6.0)
   Search (a SearchField, size lg, label "Search") + filter slot + Clear filters +
   results counter on the left; `right` slot and page-size select on the right.
   DataControls.js builds it. Requires SearchField (1.1.0 change: the search box is
   SearchField, it was a plain Input in 1.0.0).
   <div class="zds-data-controls">
     <div class="zds-data-controls__main">
       <div class="zds-data-controls__search">[SearchField]</div>
       <div class="zds-data-controls__filters">[FilterDropdowns…]</div>
       <button class="zds-data-controls__clear" type="button">[filter_list_off 18]Clear filters</button>
       <span class="zds-data-controls__results"><strong>8</strong> results</span></div>
     <div class="zds-data-controls__side">[right]<label class="zds-data-controls__page-size">Show<select>…</select></label></div></div>
   Stacked (1.2.0, phone layout; .zds-data-controls--stacked):
   <div class="zds-data-controls zds-data-controls--stacked">
     <div class="zds-data-controls__search">[SearchField]</div>
     <div class="zds-data-controls__filter-row"><div class="zds-data-controls__filters">…</div>[Clear filters]</div>
     <div class="zds-data-controls__foot">[results]<div class="zds-data-controls__side">…</div></div></div>
   1.2.0 contrast: Clear filters and page-size select resting borders →
   --theme-border-control. Clear filters no longer shrinks.
   Porting rules: hover (React state) → :hover. The Clear filters focus ring is
   the global ring in tokens/base.css. Deviations: none. */
.zds-data-controls{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:16px;background:var(--theme-bg-primary);border:1px solid var(--theme-border-primary);border-radius:12px;margin-bottom:16px;flex-wrap:wrap;font-family:var(--zivvy-font-text)}
.zds-data-controls__main{display:flex;align-items:center;gap:12px;flex:1;flex-wrap:wrap;min-width:300px}
.zds-data-controls__search{flex:1;min-width:240px;max-width:400px}
.zds-data-controls__filters{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.zds-data-controls__clear{display:inline-flex;align-items:center;gap:8px;min-height:44px;margin:0;padding:0 16px;flex-shrink:0;border:1px solid var(--theme-border-control);border-radius:8px;background:var(--theme-bg-primary);color:var(--theme-text-secondary);font-size:14px;font-weight:600;font-family:inherit;cursor:pointer;white-space:nowrap;transition:all 300ms ease}
.zds-data-controls__clear[hidden]{display:none}
.zds-data-controls__clear .zds-icon{width:18px;height:18px}
.zds-data-controls__clear:hover{border-color:var(--theme-border-hover);background:var(--theme-bg-hover);color:var(--theme-text-primary)}
.zds-data-controls__results{font-size:14px;color:var(--theme-text-secondary);white-space:nowrap}
.zds-data-controls__results strong{color:var(--theme-text-primary);font-weight:600}
.zds-data-controls__side{display:flex;align-items:center;gap:12px}
.zds-data-controls__page-size{display:flex;align-items:center;gap:8px;font-size:14px;color:var(--theme-text-secondary);white-space:nowrap}
.zds-data-controls__page-size select{min-height:44px;padding:0 12px;border:1px solid var(--theme-border-control);border-radius:8px;background:var(--theme-bg-primary);color:var(--theme-text-primary);font-size:14px;font-weight:500;font-family:inherit;cursor:pointer}
/* stacked (phone) */
.zds-data-controls--stacked{flex-direction:column;align-items:stretch;justify-content:flex-start;gap:12px;padding:12px;flex-wrap:nowrap}
.zds-data-controls--stacked .zds-data-controls__search{flex:none;min-width:0;max-width:none}
.zds-data-controls__filter-row{display:flex;align-items:center;gap:8px;overflow-x:auto;margin:0 -12px;padding:0 12px}
.zds-data-controls__filter-row .zds-data-controls__filters{flex-wrap:nowrap;flex-shrink:0}
.zds-data-controls__foot{display:flex;align-items:center;justify-content:space-between;gap:12px}
.zds-data-controls__foot .zds-data-controls__side{margin-left:auto}
.zds-data-controls__filter-row[hidden],.zds-data-controls__foot[hidden],.zds-data-controls__results[hidden]{display:none}
@media (prefers-reduced-motion:reduce){.zds-data-controls__clear{transition:none}}

/* ======== /assets/zds-1.6.0/components/data/DataTable.css ======== */
/* ZDS DataTable 1.1.0 — ported from docs/design-handoffs/zds-1.6.0/components/data/DataTable.jsx (ZDS 1.6.0)
   White 12px container, sticky slate-50 header with uppercase 12px labels, 16/24
   cells (8/16 compact), sortable headers, clickable rows, keyboard grid, column
   resize, loading veil, empty slot, selection checkbox styles. DataTable.js builds
   it (columns/rows/sort/row click/loading/empty/density/keyboardNav/resizable/caption).
   <div class="zds-data-table [--compact] [--grid] [is-loading]">[<span class="zds-data-table__sr-only" id>hint</span>]
     <div class="zds-data-table__scroll"><table class="zds-data-table__table" [role="grid"]>[<caption class="zds-data-table__sr-only">]
     <thead><tr><th class="zds-data-table__th [--sortable] [--align-right] [--sized]" aria-sort [data-cell]>
       <button class="zds-data-table__sort" type="button" data-zds-ring>Label<svg class="zds-icon zds-data-table__sort-icon">arrow_upward</svg></button>
       [<span class="zds-data-table__resize" role="separator" data-zds-resize data-zds-ring><span class="zds-data-table__resize-bar"></span></span>]</th></tr></thead>
     <tbody><tr class="zds-data-table__row [--clickable] [is-selected]" data-zds-ring [tabindex="0"]><td class="zds-data-table__td [--nowrap] [--numeric] [--sized]" [data-cell]>…</td></tr></tbody>
   </table>[empty]</div>[footer]<div class="zds-data-table__loading"><span class="zds-data-table__spinner"></span></div></div>
   State mapping (recorded): row hover/focus (React state) → :hover / :focus-within;
   the sorted column → aria-sort on the <th>; the sort arrow points up for asc and
   rotates 180° for desc, opacity .7 when the column is not the sorted one;
   focus-visible React state (fk) → :focus-visible; resize-bar highlight (rz) →
   :hover / :focus-visible / .is-active; loading → .is-loading (veil shown).
   Upstream since 1.0.2 (no longer deviations): sortable header content is a
   full-cell <button> with an inset 2px --theme-border-focus ring, and clickable
   rows are tabindex 0, open on Enter/Space and show an inset 2px ring; both carry
   data-zds-ring to opt out of the global ring in tokens/base.css.
   The loading ring's zivvy-spin comes from tokens/motion.css, whose one
   reduced-motion block turns it into a pulse (upstream 1.0.5; needs styles.css).
   Deviations (recorded):
   - The last row's bottom border is dropped with :last-child (the JSX compares
     the index), same result.
   - An unsorted sortable <th> carries aria-sort="none" (the JSX omits it).
   - Keyboard-grid cell and resize-handle rings are :focus-visible outlines (the
     JSX tracks focus-visible in state and sets the same outline inline).
   - resizable: widths apply at once and are reported through
     onColumnWidthsChange; update({columnWidths}) replaces them (the JSX's
     controlled/uncontrolled split, in the port's update() shape).
   - Not ported in JS: selectable / selectMenu / banner / hoverActions /
     onRowAction (they need Checkbox, DropdownMenu and RowActions wiring the
     admin does not use), and with them keyboardNav's Space-to-select and
     Ctrl/Cmd+A. Their CSS (checkbox, 24px selection caret, selected row,
     actions cell) IS carried below.
   - columnPicker / hiddenColumns / onHiddenColumnsChange / column hideable and
     title: not carried (opt-in, unused by the console). */
.zds-data-table{position:relative;width:100%;background:var(--theme-bg-primary);border-radius:12px;border:1px solid var(--theme-border-primary);overflow:hidden;font-family:var(--zivvy-font-text)}
.zds-data-table__sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap}
.zds-data-table__scroll{overflow-x:auto}
.zds-data-table__table{width:100%;border-collapse:separate;border-spacing:0;font-size:14px;line-height:20px}
.zds-data-table__table thead{background:var(--theme-bg-secondary);position:sticky;top:0;z-index:10}
.zds-data-table__th{padding:16px 24px;text-align:left;font-weight:600;color:var(--theme-text-secondary);font-size:12px;text-transform:uppercase;letter-spacing:.05em;border-bottom:2px solid var(--theme-border-primary);white-space:nowrap;user-select:none;-webkit-user-select:none;line-height:16px;position:relative;cursor:default;text-overflow:ellipsis}
.zds-data-table__th--sortable{padding:0;cursor:pointer}
.zds-data-table__th--sized{overflow:hidden}
.zds-data-table__th[aria-sort="ascending"],.zds-data-table__th[aria-sort="descending"]{color:var(--theme-text-primary)}
.zds-data-table__th--align-right{text-align:right}
.zds-data-table__th--align-center{text-align:center}
.zds-data-table__th--select{width:48px;padding-left:24px;padding-right:8px}
.zds-data-table__th--select-menu{width:76px}
.zds-data-table__select-group{display:inline-flex;align-items:center;gap:8px}
.zds-data-table__select-caret{display:inline-flex;align-items:center;justify-content:center;width:24px;height:28px;padding:0;border:none;background:none;border-radius:6px;color:var(--theme-text-secondary);cursor:pointer}
.zds-data-table__th--actions{width:80px;text-align:right;padding-right:24px}
.zds-data-table__sort{display:block;width:100%;margin:0;padding:16px 28px 16px 24px;border:0;background:none;font:inherit;color:inherit;text-transform:inherit;letter-spacing:inherit;line-height:inherit;text-align:inherit;cursor:pointer;white-space:inherit;overflow:hidden;text-overflow:ellipsis;position:relative;outline:none;box-shadow:none}
.zds-data-table__sort:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--theme-border-focus)}
.zds-data-table__sort-icon{position:absolute;right:8px;top:50%;width:16px!important;height:16px!important;transform:translateY(-50%) rotate(0deg);opacity:.7;color:currentColor;transition:all 300ms ease}
.zds-data-table__th[aria-sort="ascending"] .zds-data-table__sort-icon,.zds-data-table__th[aria-sort="descending"] .zds-data-table__sort-icon{opacity:1;color:var(--theme-interactive-default)}
.zds-data-table__th[aria-sort="descending"] .zds-data-table__sort-icon{transform:translateY(-50%) rotate(180deg)}
.zds-data-table__resize{position:absolute;top:0;bottom:0;right:0;width:12px;cursor:col-resize;touch-action:none;z-index:1;display:flex;justify-content:flex-end;outline:none}
.zds-data-table__resize:focus-visible{outline:2px solid var(--theme-border-focus);outline-offset:-2px}
.zds-data-table__resize-bar{width:2px;margin:8px 0;border-radius:1px;background:var(--theme-border-primary);transition:background 150ms ease}
.zds-data-table__resize:hover .zds-data-table__resize-bar,.zds-data-table__resize:focus-visible .zds-data-table__resize-bar,.zds-data-table__resize.is-active .zds-data-table__resize-bar{background:var(--theme-interactive-default)}
.zds-data-table__row{background:transparent;transition:background 300ms ease;cursor:default;outline:none}
.zds-data-table__row:hover,.zds-data-table__row:focus-within{background:var(--theme-bg-hover)}
.zds-data-table__row--clickable{cursor:pointer}
.zds-data-table__row--clickable:focus-visible{outline:2px solid var(--theme-border-focus);outline-offset:-2px}
.zds-data-table__row.is-selected{background:rgba(59,130,246,.05)}
.zds-data-table__row.is-selected:hover{background:rgba(59,130,246,.1)}
.zds-data-table__td{padding:16px 24px;color:var(--theme-text-primary);vertical-align:middle;text-align:left;border-bottom:1px solid var(--theme-border-primary)}
.zds-data-table__row:last-child > .zds-data-table__td{border-bottom:none}
.zds-data-table__td--align-right{text-align:right}
.zds-data-table__td--align-center{text-align:center}
.zds-data-table__td--numeric{font-variant-numeric:tabular-nums lining-nums}
.zds-data-table__td--nowrap{white-space:nowrap}
.zds-data-table__td--sized{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.zds-data-table__td--select{padding:16px 8px 16px 24px}
.zds-data-table__td--actions{padding:8px 24px;text-align:right;white-space:nowrap}
/* keyboardNav: roving-tabindex cells, inset ring */
.zds-data-table--grid [data-cell]{outline:none}
.zds-data-table--grid [data-cell]:focus-visible{outline:2px solid var(--theme-border-focus);outline-offset:-2px}
/* density="compact": 8/16 cells, 10/16 header */
.zds-data-table--compact .zds-data-table__th{padding:10px 16px}
.zds-data-table--compact .zds-data-table__th--sortable{padding:0}
.zds-data-table--compact .zds-data-table__sort{padding:10px 28px 10px 16px}
.zds-data-table--compact .zds-data-table__th--select{padding-left:16px;padding-right:8px}
.zds-data-table--compact .zds-data-table__th--actions{padding-right:16px}
.zds-data-table--compact .zds-data-table__td{padding:8px 16px}
.zds-data-table--compact .zds-data-table__td--select{padding:8px 8px 8px 16px}
.zds-data-table--compact .zds-data-table__td--actions{padding:2px 16px}
.zds-data-table__checkbox{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border:2px solid var(--theme-border-control);border-radius:4px;background:var(--theme-bg-primary);cursor:pointer;transition:all 300ms ease;flex-shrink:0;color:#FFFFFF}
.zds-data-table__checkbox:hover{border-color:var(--theme-interactive-default);background:var(--theme-bg-hover)}
.zds-data-table__checkbox[aria-checked="true"],.zds-data-table__checkbox[aria-checked="mixed"]{border-color:var(--theme-interactive-default);background:var(--theme-action-primary)}
.zds-data-table__checkbox .zds-icon{width:16px;height:16px}
.zds-data-table__banner-cell{padding:0;border-bottom:1px solid var(--theme-border-primary)}
.zds-data-table__loading{display:none;position:absolute;inset:0;background:rgba(255,255,255,.9);-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);align-items:center;justify-content:center;z-index:20}
.zds-data-table.is-loading > .zds-data-table__loading{display:flex}
.zds-data-table__spinner{width:40px;height:40px;border:3px solid var(--theme-border-primary);border-top-color:var(--theme-interactive-default);border-radius:50%;animation:zivvy-spin .8s linear infinite;box-sizing:border-box}
@media (prefers-reduced-motion:reduce){.zds-data-table__row,.zds-data-table__sort-icon,.zds-data-table__checkbox,.zds-data-table__resize-bar{transition:none}}

/* ======== /assets/zds-1.6.0/components/data/DescriptionList.css ======== */
/* ZDS DescriptionList 0.1.0 — ported from docs/design-handoffs/zds-1.6.0/components/data/DescriptionList.jsx (ZDS 1.6.0)
   1.6.0 (0.1.0, beta): first port. Label / value pairs in a semantic <dl>.
   Markup (or DescriptionList.js):
   <dl class="zds-description-list [--inline] [--cols-1|--cols-3] [--dense]">
     <div class="zds-description-list__item [--full]">
       <dt class="zds-description-list__label">Phone</dt>
       <dd class="zds-description-list__value">(555) 014-2231</dd>
     </div>
   </dl>
   An empty value is <span class="zds-description-list__empty">—</span> inside the
   <dd>, so a row never collapses (DescriptionList.js writes it for null,
   undefined and '').
   Layouts, as the JSX: stacked (default) is label above value in an auto-fit
   grid, minimum column 200px (columns 2, the default) or 160px (--cols-3);
   --cols-1 forces one column; --full makes an item take the whole row. --inline
   is label left, value right, a divider under every row but the last (phone,
   sheets); --cols-* and --full do nothing there, as in the JSX. --dense tightens
   the row gap (stacked: 20 → 12px) or the row padding (inline: 12 → 8px).
   Deviations: none. */
.zds-description-list{margin:0;display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));column-gap:24px;row-gap:20px;font-family:var(--zivvy-font-text)}
.zds-description-list--cols-3{grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}
.zds-description-list--cols-1{grid-template-columns:1fr}
.zds-description-list--dense{row-gap:12px}
.zds-description-list__item{display:flex;flex-direction:column;gap:4px;min-width:0}
.zds-description-list__item--full{grid-column:1 / -1}
.zds-description-list__label{margin:0;font-size:13px;line-height:18px;font-weight:500;color:var(--theme-text-secondary)}
.zds-description-list__value{margin:0;font-size:14px;line-height:20px;color:var(--theme-text-primary);overflow-wrap:anywhere;font-variant-numeric:tabular-nums lining-nums}
.zds-description-list__empty{color:var(--theme-text-secondary)}
.zds-description-list--inline{display:flex;flex-direction:column;column-gap:normal;row-gap:normal}
.zds-description-list--inline > .zds-description-list__item{flex-direction:row;align-items:baseline;justify-content:space-between;gap:16px;min-width:auto;padding:12px 0;border-bottom:1px solid var(--theme-border-primary)}
.zds-description-list--inline.zds-description-list--dense > .zds-description-list__item{padding:8px 0}
.zds-description-list--inline > .zds-description-list__item:last-child{border-bottom:none}
.zds-description-list--inline .zds-description-list__label{flex:none;max-width:45%}
.zds-description-list--inline .zds-description-list__value{text-align:right;min-width:0}

/* ======== /assets/zds-1.6.0/components/data/Avatar.css ======== */
/* ZDS Avatar 1.0.2 — ported from docs/design-handoffs/zds-1.6.0/components/data/Avatar.jsx (ZDS 1.6.0)
   1.6.0 (1.0.2): first port. Default ground is --theme-action-primary (white
   initials 5.17:1); the status dot is role="img" named "Status: online" etc.
   Markup (or Avatar.js, which derives the initials and sets a custom ground):
   <span class="zds-avatar [--sm|--lg|--xl|--profile] [--placeholder]" title="Sarah Chen">SC
     <span class="zds-avatar__status zds-avatar__status--online" role="img" aria-label="Status: online"></span></span>
   With a photo, the initials are replaced by
   <img class="zds-avatar__image" src="…" alt="Sarah Chen">.
   Sizes (diameter / initials): sm 28/11 · md 32/12 (default, tables) · lg 40/16 ·
   xl 56/20 · profile 80/28 (the only size with a shadow). The status dot is 25%
   of the diameter, never under 8px, with a 2px --theme-bg-primary ring.
   Group: <span class="zds-avatar-group [--sm|--lg|--xl|--profile]"> holding the
   avatars and, past `max`, <span class="zds-avatar-group__more">+2</span>. Each
   member overlaps the one before by 8px and carries a 2px --theme-bg-primary ring.
   Deviations (recorded):
   - `color` (a custom ground) has no class: Avatar.js sets it as the element's
     background, as the JSX does. By hand, set `background` on the element.
   - The JSX's four literal status colours are written through the tokens that
     hold those exact values in both themes: online = --zivvy-success, away =
     --zivvy-warning, busy = --zivvy-danger, offline (and any unknown status) =
     --zivvy-slate-400. The white initials and the profile shadow have no token
     and stay literal. */
.zds-avatar{position:relative;display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:50%;flex-shrink:0;background:var(--theme-action-primary);color:#FFFFFF;font-family:var(--zivvy-font-text);font-size:12px;font-weight:700;line-height:1;text-transform:uppercase;user-select:none;-webkit-user-select:none;box-shadow:none}
.zds-avatar--sm{width:28px;height:28px;font-size:11px}
.zds-avatar--lg{width:40px;height:40px;font-size:16px}
.zds-avatar--xl{width:56px;height:56px;font-size:20px}
.zds-avatar--profile{width:80px;height:80px;font-size:28px;box-shadow:0 2px 8px rgba(0,0,0,.1),0 1px 3px rgba(0,0,0,.08)}
.zds-avatar--placeholder{background:var(--theme-bg-tertiary);color:var(--theme-text-tertiary)}
.zds-avatar__image{width:100%;height:100%;object-fit:cover;border-radius:50%}
.zds-avatar__status{position:absolute;bottom:0;right:0;width:25%;height:25%;min-width:8px;min-height:8px;border-radius:50%;background:var(--zivvy-slate-400);border:2px solid var(--theme-bg-primary)}
.zds-avatar__status--online{background:var(--zivvy-success)}
.zds-avatar__status--away{background:var(--zivvy-warning)}
.zds-avatar__status--busy{background:var(--zivvy-danger)}
.zds-avatar__status--offline{background:var(--zivvy-slate-400)}
.zds-avatar-group{display:inline-flex;align-items:center}
.zds-avatar-group > .zds-avatar{position:relative;z-index:1;border:2px solid var(--theme-bg-primary)}
.zds-avatar-group > .zds-avatar + .zds-avatar{margin-left:-8px}
.zds-avatar-group__more{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;margin-left:-8px;border-radius:50%;border:2px solid var(--theme-bg-primary);background:var(--theme-bg-tertiary);color:var(--theme-text-secondary);font-family:var(--zivvy-font-text);font-size:11px;font-weight:600}
.zds-avatar-group--sm > .zds-avatar-group__more{width:28px;height:28px;font-size:10px}
.zds-avatar-group--lg > .zds-avatar-group__more{width:40px;height:40px;font-size:15px}
.zds-avatar-group--xl > .zds-avatar-group__more{width:56px;height:56px;font-size:19px}
.zds-avatar-group--profile > .zds-avatar-group__more{width:80px;height:80px;font-size:27px}

/* ======== /assets/zds-1.6.0/components/layout/DetailHeader.css ======== */
/* ZDS DetailHeader 0.1.1 — ported from docs/design-handoffs/zds-1.6.0/components/layout/DetailHeader.jsx (ZDS 1.6.0)
   1.6.0 (0.1.1, beta): first port. The back button draws its own ring and opts
   out of the global one (data-zds-ring).
   Requires Avatar>=1.0.0 and Icon>=1.0.1 (Avatar.css, Icon.css). The status and
   the actions are whatever the caller puts there, usually a StatusBadge and
   Buttons.
   Markup (or DetailHeader.js):
   <header class="zds-detail-header [zds-detail-header--compact]">
     <div class="zds-detail-header__main">
       <button class="zds-detail-header__back" type="button" data-zds-ring="" aria-label="Back"><svg class="zds-icon zds-icon--24">…</svg></button>
       <span class="zds-avatar zds-avatar--xl">…</span>   (or, with no person:)
       <span class="zds-detail-header__tile" aria-hidden="true"><svg class="zds-icon zds-icon--28">…</svg></span>
       <div class="zds-detail-header__text">
         <div class="zds-detail-header__title-row"><h1 class="zds-detail-header__title">Maya Chen</h1>[status]</div>
         <div class="zds-detail-header__subtitle">Adults · Green belt</div>
         <div class="zds-detail-header__meta"><span class="zds-detail-header__meta-item">Member since 2023</span><span aria-hidden="true">·</span><span class="zds-detail-header__meta-item">Autopay on</span></div>
       </div>
     </div>
     <div class="zds-detail-header__actions">[buttons]</div>
   </header>
   Every part but the title is optional and is left out, not rendered empty.
   Default: one row, 24/32 title, 56px avatar (xl) or icon tile (28px glyph),
   actions at the right. --compact (phone): 20/24 title, 40px avatar (lg) or tile
   (22px glyph), the back button pulled 8px left and 4px into the gap, and the
   actions on their own row underneath, left-aligned. The title truncates on one
   line; subtitle too; the meta line wraps between items, never inside one.
   State mapping (recorded): the JSX's hover and focus-visible React state →
   :hover and :focus-visible on the back button.
   The back button's padding is left to the browser, as the JSX leaves it: it
   does not move the 24px glyph inside the fixed 44×44 box.
   Deviations (recorded):
   - The compact tile's glyph is 22px, a size Icon.css has no modifier for (and
     its 20px default outranks the width/height attributes Icon.js writes), so
     the size is set here on the tile's icon.
   - Glyphs are Icon.js's inline SVG, not the font ligature (Icon's deviation). */
.zds-detail-header{display:flex;flex-direction:row;align-items:center;gap:16px;padding:20px 24px;background:var(--theme-bg-primary);border-bottom:1px solid var(--theme-border-primary);font-family:var(--zivvy-font-text)}
.zds-detail-header--compact{flex-direction:column;align-items:stretch;gap:12px;padding:12px 16px}
.zds-detail-header__main{display:flex;align-items:center;gap:16px;flex:1;min-width:0}
.zds-detail-header--compact > .zds-detail-header__main{gap:12px}
.zds-detail-header__back{width:44px;height:44px;flex:none;margin:0;display:flex;align-items:center;justify-content:center;border:none;border-radius:8px;background:transparent;color:var(--theme-text-primary);cursor:pointer;outline:none;box-shadow:none}
.zds-detail-header--compact .zds-detail-header__back{margin:0 -4px 0 -8px}
.zds-detail-header__back:hover{background:var(--theme-bg-hover)}
.zds-detail-header__back:focus-visible{box-shadow:0 0 0 2px var(--theme-border-focus)}
.zds-detail-header__tile{width:56px;height:56px;flex:none;border-radius:12px;background:var(--theme-bg-tertiary);color:var(--theme-text-secondary);display:flex;align-items:center;justify-content:center}
.zds-detail-header--compact .zds-detail-header__tile{width:40px;height:40px}
.zds-detail-header--compact .zds-detail-header__tile > .zds-icon{width:22px;height:22px}
.zds-detail-header__text{display:flex;flex-direction:column;gap:4px;min-width:0;flex:1}
.zds-detail-header__title-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap;min-width:0}
.zds-detail-header__title{margin:0;font-family:var(--zivvy-font-display);font-size:24px;line-height:32px;font-weight:600;color:var(--theme-text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.zds-detail-header--compact .zds-detail-header__title{font-size:20px;line-height:24px}
.zds-detail-header__subtitle{font-size:14px;line-height:20px;color:var(--theme-text-secondary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.zds-detail-header__meta{display:flex;align-items:center;gap:8px;flex-wrap:wrap;font-size:13px;line-height:18px;color:var(--theme-text-secondary)}
.zds-detail-header__meta-item{white-space:nowrap}
.zds-detail-header__actions{display:flex;align-items:center;gap:8px;flex-wrap:wrap;flex:none;justify-content:flex-end}
.zds-detail-header--compact > .zds-detail-header__actions{justify-content:flex-start}

/* ======== /assets/zds-1.6.0/components/navigation/SubNav.css ======== */
/* ZDS SubNav 1.0.1 — ported from docs/design-handoffs/zds-1.6.0/components/navigation/SubNav.jsx (ZDS 1.6.0)
   1.6.0 (1.0.1): the default accent is --theme-interactive-active; the ground is --theme-subnav-bg, which tokens 1.3.0 now set dark in dark theme.
   48px white section bar with a 3px active underline; the row scrolls sideways
   when the items do not fit (overflow-x auto, as the JSX).
   <nav class="zds-sub-nav" aria-label="Section"><div class="zds-sub-nav__inner">
     <button class="zds-sub-nav__item" type="button" aria-current="page">[icon 18]Label
       [<span class="zds-sub-nav__count">3</span>]</button>…</div></nav>
   Active = aria-current="page" (the JSX's only active marker). Accent is
   --zds-sub-nav-accent (default --theme-interactive-active; the JSX `accent` prop); max width
   --zds-sub-nav-max (1536).
   Porting rules: hover (React state) → :hover on a non-active item; focus ring
   added (the JSX has none). SubNav.js scrolls the active item into view.
   Deviations: none in look. */
.zds-sub-nav{--zds-sub-nav-accent:var(--theme-interactive-active);height:48px;background:var(--theme-subnav-bg,#FFFFFF);border-bottom:1px solid var(--theme-border-primary);box-shadow:var(--zivvy-shadow-sm);font-family:var(--zivvy-font-text)}
.zds-sub-nav__inner{max-width:var(--zds-sub-nav-max,1536px);height:100%;margin:0 auto;padding:0 24px;display:flex;align-items:stretch;gap:32px;overflow-x:auto;box-sizing:border-box}
.zds-sub-nav__item{margin:0;padding:0 16px;min-height:44px;height:100%;display:flex;align-items:center;gap:8px;background:transparent;border:none;border-bottom:3px solid transparent;color:var(--theme-text-secondary);font-size:14px;font-weight:500;font-family:inherit;cursor:pointer;white-space:nowrap;transition:all 250ms ease;outline:none;flex-shrink:0}
.zds-sub-nav__item .zds-icon{width:18px;height:18px}
.zds-sub-nav__item:hover:not([aria-current="page"]){background:rgba(37,110,255,.05);color:var(--zds-sub-nav-accent)}
.zds-sub-nav__item[aria-current="page"]{border-bottom-color:var(--zds-sub-nav-accent);color:var(--zds-sub-nav-accent)}
.zds-sub-nav__item:focus-visible{outline:2px solid var(--theme-border-focus);outline-offset:-2px}
.zds-sub-nav__count{min-width:20px;height:20px;padding:0 6px;border-radius:10px;background:var(--theme-bg-tertiary);color:var(--theme-text-secondary);font-size:11px;font-weight:600;display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box}
.zds-sub-nav__item[aria-current="page"] .zds-sub-nav__count{background:var(--zds-sub-nav-accent);color:#fff}
@media (prefers-reduced-motion:reduce){.zds-sub-nav__item{transition:none}}

/* ======== /assets/zds-1.6.0/components/overlays/Tray.css ======== */
/* ZDS Tray 1.0.1 — ported from docs/design-handoffs/zds-1.6.0/components/overlays/Tray.jsx (ZDS 1.6.0)
   600px right slide-in over a 50% black overlay: title/subtitle header, close
   button, optional tabs, scrolling body of TraySections, optional footer.
   Tray.js builds and drives it.
   <div class="zds-tray-overlay [is-shown]"><aside class="zds-tray" role="dialog" aria-modal="true" aria-labelledby tabindex="-1">
     <header class="zds-tray__header"><div><h2 class="zds-tray__title">…</h2><p class="zds-tray__subtitle">…</p></div>
       <button class="zds-tray__close" type="button" aria-label="Close"><svg class="zds-icon zds-icon--24">close</svg></button></header>
     <div class="zds-tray__body">[<div class="zds-tray__tabs" role="tablist"><button class="zds-tray__tab" role="tab" aria-selected>…]
       <section class="zds-tray-section"><h3 class="zds-tray-section__title">…</h3><p class="zds-tray-section__description">…</p>…</section></div>
     [<footer class="zds-tray__footer">…</footer>]</aside></div>
   --inline: the `inline` prop (relative, full height, no overlay, no slide).
   Active tab: underline --zivvy-primary, label --theme-interactive-active (1.0.1 contrast fix).
   State mapping (recorded): `shown` (set on the frame after open) → .is-shown on
   the overlay; hover (React state) → :hover.
   Focus ring: from tokens/base.css (global :focus-visible ring), as upstream.
   Deviations (recorded): under prefers-reduced-motion the slide is replaced by
   the overlay's 300ms opacity fade (handoff: "swap slides for a 300ms opacity fade"). */
.zds-tray-overlay{position:fixed;inset:0;z-index:9999;background:rgba(0,0,0,.5);opacity:0;transition:opacity 300ms ease}
.zds-tray-overlay[hidden]{display:none}
.zds-tray-overlay.is-shown{opacity:1}
.zds-tray{position:fixed;top:0;right:0;bottom:0;z-index:10000;width:600px;max-width:100%;background:var(--theme-bg-primary);box-shadow:-4px 0 24px rgba(0,0,0,.15);display:flex;flex-direction:column;transform:translateX(100%);transition:transform 300ms ease;font-family:var(--zivvy-font-text);outline:none}
.zds-tray-overlay.is-shown > .zds-tray{transform:none}
.zds-tray--inline{position:relative;top:auto;right:auto;bottom:auto;z-index:auto;height:100%;transform:none}
.zds-tray__header{padding:24px;border-bottom:1px solid var(--theme-border-primary);display:flex;align-items:center;justify-content:space-between;flex-shrink:0}
.zds-tray__title{margin:0;font-family:var(--zivvy-font-display);font-size:20px;font-weight:600;color:var(--theme-text-primary);text-wrap:balance}
.zds-tray__subtitle{margin:4px 0 0;font-size:14px;color:var(--theme-text-secondary);text-wrap:pretty}
.zds-tray__close{width:40px;height:40px;min-width:40px;margin:0;padding:0;display:flex;align-items:center;justify-content:center;background:transparent;border:none;border-radius:8px;cursor:pointer;color:var(--theme-text-secondary);transition:all 200ms ease;outline:none}
.zds-tray__close:hover{background:var(--theme-bg-hover);color:var(--theme-text-primary)}
.zds-tray__body{flex:1;overflow-y:auto;overflow-x:hidden;padding:24px}
.zds-tray__tabs{display:flex;gap:8px;margin-bottom:24px;border-bottom:1px solid var(--theme-border-primary)}
.zds-tray__tab{margin:0 0 -1px;padding:12px 16px;background:none;border:none;border-bottom:2px solid transparent;cursor:pointer;font-size:14px;font-weight:500;font-family:inherit;color:var(--theme-text-secondary);transition:all 200ms;outline:none}
.zds-tray__tab:hover:not([aria-selected="true"]){background:rgba(0,0,0,.03);color:var(--theme-text-primary)}
.zds-tray__tab[aria-selected="true"]{border-bottom-color:var(--zivvy-primary);color:var(--theme-interactive-active)}
.zds-tray__footer{display:flex;align-items:center;justify-content:flex-end;gap:12px;padding:24px;border-top:1px solid var(--theme-border-primary);flex-shrink:0;background:var(--theme-bg-primary)}
.zds-tray-section{margin-bottom:32px}
.zds-tray-section__title{margin:0 0 16px;font-family:var(--zivvy-font-display);font-size:18px;font-weight:600;color:var(--theme-text-primary)}
.zds-tray-section__description{margin:0 0 16px;font-size:14px;line-height:1.5;color:var(--theme-text-secondary);text-wrap:pretty}
@media (prefers-reduced-motion:reduce){.zds-tray{transition:none;transform:none}.zds-tray__close,.zds-tray__tab{transition:none}}

/* ======== /assets/zds-1.6.0/components/overlays/Sheet.css ======== */
/* ZDS Sheet 1.1.0 — ported from docs/design-handoffs/zds-1.6.0/components/overlays/Sheet.jsx (ZDS 1.6.0)
   Slide-out panel from any edge over a blurred overlay. Sheet.js builds and drives it.
   <div class="zds-sheet-root [is-shown]">
     <div class="zds-sheet-overlay"></div>
     <aside class="zds-sheet zds-sheet--<right|left|top|bottom> zds-sheet--<sm|md|lg|xl|full> [zds-sheet--handle]" role="dialog" aria-modal="true" tabindex="-1">
       [<div class="zds-sheet__handle" aria-hidden="true"><span class="zds-sheet__handle-bar"></span></div>]
       <header class="zds-sheet__header"><h2 class="zds-sheet__title">…</h2>[extra]
         <button class="zds-sheet__close" type="button" aria-label="Close"><svg class="zds-icon zds-icon--24">close</svg></button></header>
       <div class="zds-sheet__body">…</div>[<footer class="zds-sheet__footer">…</footer>]</aside></div>
   Width (left/right): sm 320 · md 480 · lg 640 · xl 800 · full 100%.
   Height (top/bottom): sm 240 · md 360 · lg 480 · xl 600 · full 100%.
   --inline: the `inline` prop (relative, no overlay, no slide).
   --handle: bottom sheet with `handle` (grab bar, 16px top radius).
   .zds-sheet__swipe: handle/header of a `swipeToClose` bottom sheet (grab cursor,
   touch-action none); the drag offset is set inline by Sheet.js, as in the JSX.
   Safe area: a modal bottom sheet pads its last block (footer, else body) by
   24px + env(safe-area-inset-bottom).
   State mapping (recorded): `shown` (set on the frame after open) → .is-shown on
   the root; hover (React state) → :hover.
   Focus ring: from tokens/base.css (global :focus-visible ring), as upstream.
   Deviations (recorded): under prefers-reduced-motion the slide becomes a 300ms
   opacity fade (handoff rule). The panel keeps max-width/max-height 100% so an
   xl bottom sheet fits a phone. */
.zds-sheet-root[hidden]{display:none}
.zds-sheet-overlay{position:fixed;inset:0;z-index:9998;background:var(--theme-bg-overlay);-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);opacity:0;transition:opacity 300ms ease}
.zds-sheet-root.is-shown > .zds-sheet-overlay{opacity:1}
.zds-sheet{position:fixed;z-index:9999;max-width:100%;max-height:100%;background:var(--theme-bg-primary);box-shadow:var(--theme-shadow-xl);display:flex;flex-direction:column;overflow:hidden;font-family:var(--zivvy-font-text);transition:transform 300ms ease,opacity 300ms ease;box-sizing:border-box;outline:none}
.zds-sheet--right{top:0;bottom:0;right:0;border-left:1px solid var(--theme-border-primary);transform:translateX(100%)}
.zds-sheet--left{top:0;bottom:0;left:0;border-right:1px solid var(--theme-border-primary);transform:translateX(-100%)}
.zds-sheet--top{top:0;left:0;right:0;border-bottom:1px solid var(--theme-border-primary);transform:translateY(-100%)}
.zds-sheet--bottom{bottom:0;left:0;right:0;border-top:1px solid var(--theme-border-primary);transform:translateY(100%)}
.zds-sheet-root.is-shown > .zds-sheet{transform:none}
.zds-sheet--left.zds-sheet--sm,.zds-sheet--right.zds-sheet--sm{width:320px}
.zds-sheet--left.zds-sheet--md,.zds-sheet--right.zds-sheet--md{width:480px}
.zds-sheet--left.zds-sheet--lg,.zds-sheet--right.zds-sheet--lg{width:640px}
.zds-sheet--left.zds-sheet--xl,.zds-sheet--right.zds-sheet--xl{width:800px}
.zds-sheet--left.zds-sheet--full,.zds-sheet--right.zds-sheet--full{width:100%}
.zds-sheet--top.zds-sheet--sm,.zds-sheet--bottom.zds-sheet--sm{height:240px}
.zds-sheet--top.zds-sheet--md,.zds-sheet--bottom.zds-sheet--md{height:360px}
.zds-sheet--top.zds-sheet--lg,.zds-sheet--bottom.zds-sheet--lg{height:480px}
.zds-sheet--top.zds-sheet--xl,.zds-sheet--bottom.zds-sheet--xl{height:600px}
.zds-sheet--top.zds-sheet--full,.zds-sheet--bottom.zds-sheet--full{height:100%}
.zds-sheet--inline{position:relative;top:auto;bottom:auto;left:auto;right:auto;z-index:auto;transform:none}
.zds-sheet--inline.zds-sheet--left,.zds-sheet--inline.zds-sheet--right{height:100%}
.zds-sheet__header{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:24px;border-bottom:1px solid var(--theme-border-primary);flex-shrink:0;min-height:72px;box-sizing:border-box}
.zds-sheet__title{margin:0;flex:1;font-family:var(--zivvy-font-display);font-size:20px;font-weight:600;line-height:24px;color:var(--theme-text-primary);text-wrap:balance}
.zds-sheet__close{display:flex;align-items:center;justify-content:center;margin:0;padding:12px;border:none;border-radius:8px;background:transparent;color:var(--theme-text-secondary);cursor:pointer;transition:all 300ms ease;flex-shrink:0;outline:none}
.zds-sheet__close:hover{background:var(--theme-bg-hover);color:var(--theme-text-primary)}
.zds-sheet__body{flex:1;overflow-y:auto;padding:24px}
.zds-sheet__footer{display:flex;align-items:center;justify-content:flex-end;gap:12px;padding:24px;border-top:1px solid var(--theme-border-primary);flex-shrink:0}
.zds-sheet--bottom:not(.zds-sheet--inline) > .zds-sheet__body:last-child,
.zds-sheet--bottom:not(.zds-sheet--inline) > .zds-sheet__footer{padding-bottom:calc(24px + env(safe-area-inset-bottom, 0px))}
.zds-sheet--handle{border-radius:16px 16px 0 0}
.zds-sheet__handle{display:flex;justify-content:center;padding:8px 0 0;flex-shrink:0}
.zds-sheet__handle-bar{width:36px;height:4px;border-radius:2px;background:var(--theme-border-control)}
.zds-sheet__swipe{touch-action:none}
.zds-sheet__handle.zds-sheet__swipe{cursor:grab}
@media (prefers-reduced-motion:reduce){
  .zds-sheet,.zds-sheet--right,.zds-sheet--left,.zds-sheet--top,.zds-sheet--bottom{transform:none;opacity:0}
  .zds-sheet-root.is-shown > .zds-sheet{opacity:1}
  .zds-sheet--inline{opacity:1}
  .zds-sheet__close{transition:none}
}

/* ======== /assets/zds-1.6.0/components/overlays/Toast.css ======== */
/* ZDS Toast 1.1.2 — ported from docs/design-handoffs/zds-1.6.0/components/overlays/Toast.jsx (ZDS 1.6.0)
   Solid coloured notification: icon, title, message, optional Undo, optional
   close. ToastContainer = fixed stack, 12px gap. Toast.js builds, stacks and
   auto-dismisses it.
   <div class="zds-toast-container [zds-toast-container--bottom|--responsive]"><div class="zds-toast zds-toast--success" role="status">
     <svg class="zds-icon zds-icon--24">check_circle</svg><div class="zds-toast__text">
     <div class="zds-toast__title">…</div><div class="zds-toast__message">…</div></div>
     [<button class="zds-toast__undo">undo Undo</button>][<button class="zds-toast__close" aria-label="Dismiss">close</button>]</div></div>
   Types (grounds chosen so the text clears 4.5:1): success --chart-seq-success-7
   (entrance "celebrate") · error --zivvy-danger-hover · info --zivvy-info-hover ·
   warning --zivvy-warning-amber with --zivvy-slate-900 ink and black Undo/Dismiss
   tints (--zds-toast-ink carries the JSX `ink` rgb triple).
   Placement: top-right (default, 24px inset, right-aligned) · --bottom (16px
   inset + safe area, centred, newest at the bottom) · --responsive (bottom under
   768px, top-right above; the JSX uses matchMedia, the port a media query).
   Animations: zivvy-toast-in / zivvy-toast-celebrate from tokens/motion.css,
   which also swaps them for a fade under prefers-reduced-motion.
   Focus ring: tokens/base.css global ring; the toast sets --theme-border-focus
   to its ink, as the JSX does.
   Porting rules: hover (React state) → :hover (lift + deeper shadow); the hover
   lift is removed under prefers-reduced-motion.
   Deviations: none in look. */
.zds-toast-container{position:fixed;top:24px;right:24px;z-index:99999;display:flex;flex-direction:column;align-items:flex-end;gap:12px;pointer-events:none}
.zds-toast-container > *{pointer-events:auto}
.zds-toast-container--bottom{top:auto;right:16px;bottom:calc(16px + env(safe-area-inset-bottom, 0px));left:16px;align-items:center;flex-direction:column-reverse}
@media (max-width:767px){
  .zds-toast-container--responsive{top:auto;right:16px;bottom:calc(16px + env(safe-area-inset-bottom, 0px));left:16px;align-items:center;flex-direction:column-reverse}
}
.zds-toast{--zds-toast-ink:255,255,255;--theme-border-focus:var(--zivvy-white);display:flex;align-items:center;gap:12px;padding:16px;border-radius:12px;box-shadow:0 8px 24px rgba(0,0,0,.3),0 0 0 1px rgba(0,0,0,.1);min-width:300px;max-width:500px;color:var(--zivvy-white);font-family:var(--zivvy-font-text);cursor:pointer;transition:all 300ms cubic-bezier(.4,0,.2,1);animation:zivvy-toast-in 300ms cubic-bezier(.4,0,.2,1);box-sizing:border-box;background:var(--zivvy-info-hover)}
.zds-toast:hover{box-shadow:0 12px 32px rgba(0,0,0,.4),0 0 0 1px rgba(0,0,0,.1);transform:translateY(-2px) scale(1.02)}
.zds-toast--has-undo{min-width:350px}
.zds-toast--success{background:var(--chart-seq-success-7);animation:zivvy-toast-celebrate 600ms var(--zivvy-easing-bounce)}
.zds-toast--error{background:var(--zivvy-danger-hover)}
.zds-toast--warning{--zds-toast-ink:0,0,0;--theme-border-focus:var(--zivvy-slate-900);background:var(--zivvy-warning-amber);color:var(--zivvy-slate-900)}
.zds-toast--info{background:var(--zivvy-info-hover)}
.zds-toast__text{flex:1;min-width:0}
.zds-toast__title{font-weight:600;font-size:14px;margin-bottom:2px}
.zds-toast__message{font-size:13px;opacity:.95;word-wrap:break-word;text-wrap:pretty}
.zds-toast__undo{display:flex;align-items:center;gap:6px;margin:0;padding:6px 12px;background:rgba(var(--zds-toast-ink),.2);border:1px solid rgba(var(--zds-toast-ink),.3);border-radius:6px;color:currentColor;font-size:13px;font-weight:600;font-family:inherit;cursor:pointer;white-space:nowrap;transition:all 200ms}
.zds-toast__undo .zds-icon{width:16px;height:16px}
.zds-toast__undo:hover{background:rgba(var(--zds-toast-ink),.3);border-color:rgba(var(--zds-toast-ink),.5);transform:translateY(-1px)}
.zds-toast__close{margin:0;background:transparent;border:none;color:currentColor;cursor:pointer;padding:4px;display:flex;border-radius:4px;opacity:.8;transition:all 200ms}
.zds-toast__close .zds-icon{width:18px;height:18px}
.zds-toast__close:hover{background:rgba(var(--zds-toast-ink),.2);opacity:1}
@media (prefers-reduced-motion:reduce){.zds-toast{transition:none}.zds-toast:hover,.zds-toast__undo:hover{transform:none}.zds-toast__undo,.zds-toast__close{transition:none}}

/* ======== /css/zds-overrides.css ======== */
/* Admin overrides on ZDS 1.6.0 ports — admin only.

   ZDS 1.6.0 re-check (2026-09-29): every contrast override this file carried on
   1.1.0 is now the ports' own value, so each was deleted rather than repeated.
   scripts/check-admin-contrast.mjs still gates those pairings against the ports
   (its ZDS section), so a later ZDS bump cannot regress them unseen:

   pairing (1.1.0 override)          now in the 1.6.0 port as
   StatusBadge active / primary text  --zivvy-success-text / --zivvy-primary-hover (StatusBadge 1.0.1)
   Toast success ground               --chart-seq-success-7 (Toast 1.1.2)
   Button filled primary ground       --theme-action-primary; hover --zivvy-primary-hover (Button 1.1.1)
   Button text/ghost primary text     --theme-interactive-active (Button 1.1.1)
   Field / control boundary           --theme-border-control = slate-500 (Input 1.0.3, SearchField 0.1.2,
                                      FilterDropdown 1.0.3, outlined-secondary Button, DataControls
                                      Clear filters 1.2.0, ToggleGroup 1.0.2)
   Toggle off boundary                bg-tertiary track with a 1px border-control ring, ringed
                                      thumb (Toggle 1.0.2). On track is --zivvy-primary again
                                      (4.42:1 on white, passes the 3:1 UI line).
   FilterDropdown count / Clear       --theme-text-secondary (FilterDropdown 1.0.3)
   SearchField icons, Sheet close     --theme-text-secondary (SearchField 0.1.2, Sheet 1.1.0)
   .zds-select border                 dropped: the 1.6.0 port set carries no Select (the
                                      console never loaded it).

   KEPT, one rule, because 1.6.0 still does it:
   Sentence case. StatusBadge capitalises task-status text ("Not now" →
   "Not Now"; the 1.6.0 JSX still sets textTransform: 'capitalize'). Every badge
   label on this console is already sentence case (Zivvy Canon), so the
   transform is off here. */

.zds-status-badge{text-transform:none}

/* ======== /css/compat.css ======== */
/* Admin compatibility layer — ZDS 1.6.0, LIGHT.
   The legacy modules (Scoreboard, Experiments, Campaigns, Proof, Analyst,
   Transcripts) still emit the console's own classes (sb-*, cm-*, note, dim, link)
   and read a handful of CSS variables the marketing stylesheet and the old dark
   admin.css used to define. This file:
     1. maps every legacy variable to a ZDS 1.6.0 light token (list below is the
        whole of `node scripts/admin-style-inventory.mjs`, variables section);
     2. restyles every legacy class with ZDS tokens — no literal colour left;
     3. gives the element base styles the marketing stylesheet used to give
        (body, headings, links, code). ZDS base.css already sets body/headings/
        links; only what differs for the console is here.
   The two dark colour-scheme declarations the inventory found (admin.css and
   index.html) are gone. The whole console is light: bg-secondary canvas,
   white surfaces, navy top bar (app-chrome.css).
   Control boundaries (legacy inputs, buttons, tabs) use --zivvy-slate-500: the
   ZDS field border (#E2E8F0) is 1.2:1, under the 3:1 UI floor Scott ruled.
   Contrast: every text/UI pairing this file produces is checked by
   scripts/check-admin-contrast.mjs (WCAG 2.2 AA — 4.5:1 text, 3:1 large text and
   UI/status colours). Do not add a `color:` here without running it.
   Literal colours from the inventory and where each went:
     #0e0d0a page → --theme-bg-secondary · #16140f panel → (panel removed; ZDS Tray)
     #2a2724, #2a2a2a, rgba(255,255,255,.06) borders → --theme-border-primary
     #ffffff/#fff text → --theme-text-primary (the QR ground stays --theme-bg-primary)
     #a9a49a dim → --theme-text-secondary · #5c1d9e purple → --zivvy-primary
     #4ade80 ok → --zivvy-success-text · #fbbf24 warn → --zivvy-warning-text
     #f87171 bad → --zivvy-danger-text · rgba(0,0,0,.45) → (panel removed)
     rgba(255,255,255,.03) hover/banner → --theme-bg-hover / --theme-bg-tertiary
     rgba(255,255,255,.04) input ground → --theme-bg-primary
     rgba(92,29,158,.16|.22) selected → --zivvy-primary-subtle
     charts.js literals → ZDS chart tokens (charts.js reads them at load). */

:root{
  /* legacy variable → ZDS 1.6.0 light token */
  --black:var(--theme-bg-secondary);
  --white:var(--theme-text-primary);
  --dim:var(--theme-text-secondary);
  --purple:var(--zivvy-primary);
  --border-default:var(--theme-border-primary);
  --danger-400:var(--zivvy-danger-text);
  --text-primary:var(--theme-text-primary);
  --radius-full:var(--zivvy-radius-full);
  --radius-sm:var(--zivvy-radius-sm);
  --space-xxs:var(--zivvy-space-1);
  --space-xs:var(--zivvy-space-2);
  --space-2:var(--zivvy-space-2);
  --space-s:var(--zivvy-space-3);
  --space-m:var(--zivvy-space-4);
  --space-l:var(--zivvy-space-6);
  /* peers, not a scale — see the note that used to sit in index.html */
  --cm-control-size:.875rem;
  --cm-mono-size:.8125rem;
}

/* ---- element base ------------------------------------------------------ */
body{background:var(--theme-bg-secondary);color:var(--theme-text-primary)}
h1,h2,h3,h4{margin:0}
/* Links: --theme-interactive-active (5.2:1 on white). --zivvy-primary is 4.4:1,
   just under AA for body-size text. */
a{color:var(--theme-interactive-active)}
a:hover{color:var(--zivvy-primary-hover)}
code{font-family:var(--zivvy-font-mono);font-size:.85em;color:var(--theme-text-primary)}
:focus-visible{outline:2px solid var(--theme-border-focus);outline-offset:2px}

/* ---- shared legacy text ----------------------------------------------- */
.note{font-size:.875rem;line-height:1.45;color:var(--theme-text-secondary);margin:0 0 .75rem}
.note.dim{font-size:.8125rem}
.dim{color:var(--theme-text-secondary)}
.link{background:none;border:0;padding:0;color:var(--theme-interactive-active);font:inherit;font-size:.875rem;text-decoration:underline;cursor:pointer}
.link:hover{color:var(--zivvy-primary-hover)}

/* ---- Scoreboard family (sb-*) ----------------------------------------- */
.sb-nav{display:flex;flex-wrap:wrap;gap:var(--zivvy-space-2);margin:0 0 var(--zivvy-space-4)}
.sb-tab{background:var(--theme-bg-primary);color:var(--theme-text-secondary);cursor:pointer;border:1px solid var(--zivvy-slate-500);border-radius:var(--zivvy-radius-full);padding:.35rem .85rem;font:inherit;font-size:.875rem;transition:color .15s,border-color .15s}
.sb-part{margin-top:var(--zivvy-space-6)}
.sb-part .sb-title{margin-bottom:var(--zivvy-space-2)}
.sb-tab:hover{color:var(--theme-text-primary);border-color:var(--zivvy-slate-600)}
.sb-tab.is-on{color:var(--zivvy-primary-hover);border-color:var(--zivvy-primary);background:var(--zivvy-primary-subtle)}
.sb-view{margin:0}
/* Experiments stacks two panels (open form, then the log): give the log room. */
#mod-experiments > .sb-view + .sb-view{margin-top:var(--zivvy-space-8)}
.sb-head{display:flex;align-items:baseline;justify-content:space-between;gap:1rem;flex-wrap:wrap;margin-bottom:.75rem}
.sb-title{font-family:var(--zivvy-font-display);font-size:1.125rem;line-height:1.4;font-weight:600;margin:0;color:var(--theme-text-primary)}
.sb-fresh{font-size:.8125rem;color:var(--theme-text-secondary)}
/* State chips: the word carries the meaning, colour only reinforces it. */
.sb-chip{display:inline-block;padding:.1rem .5rem;border-radius:var(--zivvy-radius-full);font-size:.75rem;line-height:1.5;font-weight:500;white-space:nowrap;border:1px solid currentColor;background:var(--theme-bg-primary)}
.sb-ok{color:var(--zivvy-success-text)}
.sb-warn{color:var(--zivvy-warning-text)}
.sb-bad{color:var(--zivvy-danger-text)}
.sb-idle{color:var(--theme-text-secondary)}
.sb-chip.sb-ok{background:var(--zivvy-success-bg)}
.sb-chip.sb-warn{background:var(--zivvy-warning-bg)}
.sb-chip.sb-bad{background:var(--zivvy-danger-bg)}
.sb-banner{margin:0 0 .9rem;padding:.6rem .8rem;font-size:.875rem;line-height:1.5;border-left:3px solid currentColor;border-radius:var(--zivvy-radius-sm);background:var(--theme-bg-tertiary);color:var(--theme-text-primary)}
.sb-banner.sb-ok{color:var(--zivvy-success-text);background:var(--zivvy-success-bg)}
.sb-banner.sb-warn{color:var(--zivvy-warning-text);background:var(--zivvy-warning-bg)}
.sb-banner.sb-bad{color:var(--zivvy-danger-text);background:var(--zivvy-danger-bg)}
.sb-banner.sb-idle{color:var(--theme-text-secondary);background:var(--theme-bg-tertiary)}
.sb-scroll{margin-bottom:.75rem;overflow-x:auto;background:var(--theme-bg-primary);border:1px solid var(--theme-border-primary);border-radius:var(--zivvy-radius-lg)}
.sb-table{width:100%;border-collapse:collapse;font-size:.875rem;color:var(--theme-text-primary)}
.sb-table th{text-align:left;font-weight:600;color:var(--theme-text-secondary);font-size:.75rem;text-transform:uppercase;letter-spacing:.05em;padding:.6rem .75rem;border-bottom:2px solid var(--theme-border-primary);background:var(--theme-bg-secondary);white-space:nowrap}
.sb-table td{padding:.55rem .75rem;border-bottom:1px solid var(--theme-border-primary)}
.sb-table tbody tr:last-child td{border-bottom:0}
.sb-table tbody tr:hover{background:var(--theme-bg-hover)}
.sb-num{text-align:right;font-variant-numeric:tabular-nums}
.sb-null{color:var(--theme-text-secondary)}
.sb-blended td{border-top:1px solid var(--zivvy-primary);font-weight:600}
.sb-foot{margin-top:1.5rem}
.sb-chart{margin:0 0 1.1rem;padding:var(--zivvy-space-3);background:var(--theme-bg-primary);border:1px solid var(--theme-border-primary);border-radius:var(--zivvy-radius-lg)}
.sb-svg{width:100%;height:auto;display:block}
/* Phone: the period column (first) never breaks "2026-06" in two. */
@media (max-width:767px){
  .sb-table td:first-child{white-space:nowrap}
  /* A module table not wrapped in .sb-scroll (Transcripts) scrolls in place
     instead of pushing the whole page sideways. */
  :not(.sb-scroll) > .sb-table{display:block;overflow-x:auto}
}

/* ---- Campaign Registry family (cm-*) — was the inline block in index.html */
.cm-sub{font-family:var(--zivvy-font-display);font-size:1rem;font-weight:600;margin:1.5rem 0 .5rem;color:var(--theme-text-primary)}
.cm-rule{border:0;border-top:1px solid var(--theme-border-primary);margin:2rem 0 1.5rem}
.cm-form{max-width:34rem}
.cm-field{margin:0 0 var(--zivvy-space-4)}
.cm-label{display:block;font-size:var(--cm-control-size);font-weight:600;color:var(--theme-text-primary);margin-bottom:var(--zivvy-space-1)}
.cm-input{width:100%;min-height:40px;padding:.5rem .75rem;font:inherit;font-size:var(--cm-control-size);color:var(--theme-text-primary);background:var(--theme-bg-primary);border:1px solid var(--zivvy-slate-500);border-radius:var(--zivvy-radius-md)}
.cm-input::placeholder{color:var(--theme-text-secondary);opacity:1}
.cm-input:focus{outline:none;border-color:var(--theme-interactive-default);box-shadow:0 0 0 3px rgba(59,130,246,.1)}
.cm-frozen{font-family:var(--zivvy-font-mono);font-size:var(--cm-mono-size);padding:.35rem 0;color:var(--theme-text-primary)}
.cm-mono{font-family:var(--zivvy-font-mono);font-size:var(--cm-mono-size);word-break:break-all}
.cm-copy{display:flex;align-items:center;gap:var(--zivvy-space-3);flex-wrap:wrap}
.cm-help{font-size:.8125rem;line-height:1.45;color:var(--theme-text-secondary);margin:var(--zivvy-space-1) 0 0}
.cm-inline{margin:0}
.cm-actions{display:flex;gap:var(--zivvy-space-3);flex-wrap:wrap;margin:var(--zivvy-space-3) 0 0}
.cm-btn{display:inline-flex;align-items:center;min-height:36px;background:var(--theme-bg-primary);color:var(--theme-text-primary);cursor:pointer;border:1px solid var(--zivvy-slate-500);border-radius:var(--zivvy-radius-md);padding:.35rem .85rem;font:inherit;font-size:var(--cm-control-size);font-weight:500}
.cm-btn:hover:not(:disabled){border-color:var(--zivvy-slate-600);background:var(--theme-bg-hover)}
.cm-btn:disabled{color:var(--theme-text-secondary);background:var(--theme-bg-tertiary);cursor:not-allowed}
.cm-btn-primary{border-color:var(--theme-interactive-active);background:var(--theme-interactive-active);color:var(--theme-text-inverse)}
.cm-btn-primary:hover:not(:disabled){background:var(--zivvy-primary-hover);border-color:var(--zivvy-primary-hover)}
.cm-btn-sm{min-height:32px;font-size:.8125rem;padding:.2rem .6rem}
/* One-way acts are the only red on this page. */
.cm-btn-danger{color:var(--zivvy-danger-text);border-color:currentColor}
.cm-oneway{margin-top:var(--zivvy-space-6);border-top:1px solid var(--theme-border-primary);padding-top:var(--zivvy-space-3)}
.cm-detail{padding:var(--zivvy-space-4) 0;max-width:40rem}
.cm-msg:not(:empty){margin-top:var(--zivvy-space-3)}
/* A marker, never a gate. See field() in campaigns.js. */
.cm-req{font-size:.75rem;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--zivvy-danger-text);vertical-align:middle}
/* Server-rendered at ECC Q. A QR needs a light quiet zone to scan. */
.cm-qr{display:block;margin-top:var(--zivvy-space-2);background:var(--theme-bg-primary);padding:var(--zivvy-space-2);border:1px solid var(--theme-border-primary);border-radius:var(--zivvy-radius-sm);width:160px;height:160px}

@media (prefers-reduced-motion:reduce){.sb-tab{transition:none}}

/* ======== /css/admin.css ======== */
/* Admin shell layout — ZDS 1.6.0, light.
   The sign-in states (loading / sign in / not available) and the signed-in
   page frame. The navy bar and module tabs are app-chrome.css; legacy module
   classes are compat.css; Build requests is build-requests.css.
   Deliberately its own stylesheet, not the marketing site's: the admin target
   has a stricter CSP with no 'unsafe-inline' in script-src, so every script
   here is an external file (firebase.json, hosting target "admin"). */

/* Sign-in states: one centred card on the canvas. */
.shell{box-sizing:border-box;max-width:30rem;margin:12vh auto 0;padding:var(--zivvy-space-8);text-align:center;background:var(--theme-bg-primary);border:1px solid var(--theme-border-primary);border-radius:var(--zivvy-radius-lg);box-shadow:var(--theme-shadow-sm)}
.shell[hidden]{display:none}
.shell h1{font-family:var(--zivvy-font-display);font-size:1.5rem;line-height:2rem;font-weight:600;margin:0 0 1rem;color:var(--theme-text-primary)}
.mark{display:block;margin:0 auto var(--zivvy-space-6);height:auto}
#gsi-button{display:flex;justify-content:center;margin:1.5rem 0 1rem}
@media (max-width:40rem){.shell{margin:var(--zivvy-space-6) var(--zivvy-space-4) 0}}

/* Signed-in frame: bar + tabs (app-chrome.css), then the module area. */
.app[hidden]{display:none}
.app-main{box-sizing:border-box;max-width:1400px;margin:0 auto;padding:var(--zivvy-space-6)}
.app-main > .sb-foot{margin:var(--zivvy-space-6) 0 0}
@media (max-width:767px){.app-main{padding:var(--zivvy-space-6) var(--zivvy-space-4) var(--zivvy-space-8)}}

/* ======== /css/app-chrome.css ======== */
/* Admin app chrome — the 56px navy bar and the module tabs. ZDS 1.6.0.
   Composition, not a ZDS component: ZDS has no minimal top bar (TopNav always
   renders search + bell; AppNav is desktop-only with search, favourites,
   drawers, help and sound). This console has none of those controls, so none
   are drawn — no fake controls.
   Gap 1 (README-phone): minimal top bar — ZDS Logo port (variant mark, 28px,
   the reverse logomark because the ground is navy) + signed-in account +
   Sign out, on --zivvy-nav-* tokens. Used at every width.
   Gap 2 (README-phone): button on a dark ground — ZDS has no nav/inverse
   variant, so Sign out is Button filled · secondary (the nearest legal option,
   as the phone design does). White on --zivvy-slate-500 passes 4.5:1.
   Module tabs: the ZDS SubNav port (navigation/SubNav.*) at both widths. On a
   phone the seven tabs are one horizontally scrolling row and the active tab
   is scrolled into view (SubNav.js); the scrollbar is hidden as in the phone
   design (the row still scrolls by touch, trackpad and keyboard focus).
   The SubNav accent (its `accent` prop) is --theme-interactive-active: the
   default --zivvy-primary is 4.4:1 on white, under AA for 14px tab labels. */
.app-bar{position:relative;z-index:30;height:56px;box-sizing:border-box;display:flex;align-items:center;justify-content:space-between;gap:var(--zivvy-space-3);padding:0 var(--zivvy-space-6);background:var(--zivvy-nav-bg);color:var(--zivvy-nav-text);font-family:var(--zivvy-font-text)}
.app-bar__mark{flex:none;width:28px;height:28px}
.app-bar__account{display:flex;align-items:center;gap:var(--zivvy-space-3);min-width:0}
.app-bar__who{font-size:13px;line-height:20px;color:var(--zivvy-nav-text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:320px}
.app-bar .zds-button:focus-visible{outline-color:var(--zivvy-nav-text)}
.app-tabs{position:relative;z-index:20}
.app-tabs{--zds-sub-nav-max:1400px;--zds-sub-nav-accent:var(--theme-interactive-active)}
.app-tabs .zds-sub-nav__inner{scrollbar-width:none}
.app-tabs .zds-sub-nav__inner::-webkit-scrollbar{display:none}
@media (max-width:767px){
  .app-bar{padding:0 var(--zivvy-space-2) 0 var(--zivvy-space-4)}
  .app-bar__account{gap:var(--zivvy-space-1)}
  .app-bar__who{max-width:170px}
  .app-tabs .zds-sub-nav__inner{padding:0 var(--zivvy-space-4)}
}

/* ======== /css/build-requests.css ======== */
/* Build survey responses (admin/js/build-requests.js) — page compositions on
   ZDS 1.6.0. Every component here is a ZDS port (public/assets/brand/zds-1.6.0);
   this file only lays them out and composes what ZDS does not have. Each
   composition that fills a gap named in
   docs/design-handoffs/build-survey-2026-09-27/README-phone.md is headed
   "Gap N". Gap 6 (list loading) is NOT a composition: it uses the ZDS Skeleton
   port; only the bones' layout is here. Gaps 1 and 2 are in app-chrome.css.
   Layout switch (plan v1.4 W2: no horizontal scroll at any width). Both
   renderings are built by the script and kept in step; CSS picks:
     ≥1200px    desktop: DataControls + the table (.br-desk, whole).
     768–1199px DataControls (.br-desk minus its table) above the phone response
                cards (.br-phone-body) in a two-column grid; the phone search
                row and results row are hidden (DataControls has both). A card
                opens the desktop Tray here (build-requests.js, WIDE).
     <768px     phone (.br-phone, whole).
   Values are the handoffs' (desktop "Build Responses Admin", phone "… Phone"),
   on ZDS tokens. Where a comp colour fails WCAG 2.2 AA on its ground, the
   passing token is used and the line says so. */

#br-view{display:flex;flex-direction:column;gap:var(--zivvy-space-6);font-family:var(--zivvy-font-text);color:var(--theme-text-primary)}
.br-phone{display:none}
@media (max-width:767px){
  #br-view{gap:var(--zivvy-space-4)}
  .br-desk{display:none}
  .br-phone{display:flex;flex-direction:column;gap:var(--zivvy-space-4)}
}

/* ---- title row (both widths) ----------------------------------------- */
.br-head{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--zivvy-space-4);flex-wrap:wrap}
.br-titles{min-width:0;display:flex;flex-direction:column;gap:var(--zivvy-space-1)}
.br-title-line{display:flex;align-items:center;gap:var(--zivvy-space-3);flex-wrap:wrap}
.br-title{margin:0;font-family:var(--zivvy-font-display);font-size:28px;line-height:32px;font-weight:700;letter-spacing:-.01em;color:var(--theme-text-primary)}
.br-subtitle{margin:0;font-size:14px;line-height:20px;color:var(--theme-text-secondary);text-wrap:pretty}
@media (max-width:767px){
  .br-head{flex-direction:column;align-items:flex-start;gap:var(--zivvy-space-4)}
  .br-titles{gap:var(--zivvy-space-2)}
  .br-title-line{flex-direction:column;align-items:flex-start;gap:var(--zivvy-space-2)}
  .br-title{font-size:24px}
}
.br-notice:empty{display:none}
.br-notice .sb-banner{margin:0}
.br-notice .sb-banner + .sb-banner{margin-top:var(--zivvy-space-2)}
.br-foot{margin:0;font-size:12px;line-height:16px;color:var(--theme-text-secondary)}

/* ---- desktop: DataControls slot + table cells -------------------------- */
.br-test-toggle{display:flex;align-items:center;padding-left:var(--zivvy-space-3);border-left:1px solid var(--theme-border-primary)}
.br-test-toggle .zds-toggle__label{white-space:nowrap}
/* The divider separates the toggle from the filter to its left; when the row
   wraps and the toggle starts a line, nothing is to its left, so no divider
   (is-line-start is set by build-requests.js from the rendered positions). */
.br-test-toggle.is-line-start{padding-left:0;border-left:0}
.br-desk .zds-data-controls{margin-bottom:var(--zivvy-space-4)}
.br-owner{display:flex;flex-direction:column;min-width:0}
.br-name{display:flex;align-items:center;flex-wrap:wrap;gap:2px var(--zivvy-space-2);font-weight:600;color:var(--theme-text-primary)}
.br-school{font-size:13px;color:var(--theme-text-secondary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.br-clip{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.br-need{max-width:100%;font-weight:500}
.br-tools{max-width:100%;color:var(--theme-text-secondary)}
/* Review fix 1: fixed layout. The six fixed columns carry widths from
   build-requests.js (150+170+150+100+120+100 = 790px); "Still does by hand" and
   "Uses now" share what is left (≥180px each at 1200, 300px at 1440). Cells use
   16px side padding instead of the DataTable's 24. The table only shows at
   1200px and up (W2), where the frame is ≥1150px wide, so the 1090px floor
   (each answer column keeps ≥150px) never makes it scroll. A plain header that
   cannot fit wraps to a second line; a sort button header ends in an ellipsis. */
.br-desk .zds-data-table__table{table-layout:fixed;min-width:1090px}
.br-desk .zds-data-table__th,.br-desk .zds-data-table__sort{overflow:hidden;text-overflow:ellipsis}
.br-desk .zds-data-table__th:not(.zds-data-table__th--sortable){white-space:normal;text-overflow:clip}
.br-desk .zds-data-table__td{padding-left:16px;padding-right:16px}
.br-desk .zds-data-table__th:not(.zds-data-table__th--sortable){padding-left:16px;padding-right:16px}
.br-desk .zds-data-table__sort{padding-left:16px;padding-right:28px}
.br-desk .zds-data-table__td{overflow:hidden}
.br-none{color:var(--theme-text-secondary)}
/* Comp: #10B981 check / #94A3B8 dash — 2.5:1 and 2.6:1 on white, under the
   3:1 AA floor for a meaningful icon; the nearest passing tokens are used. */
.br-zoom{color:var(--theme-text-secondary)}
.br-zoom--yes{color:var(--zivvy-success-hover)}
.br-row.is-open,.br-card.is-open{background:var(--theme-bg-selected)}

/* ---- desktop: Tray content --------------------------------------------- */
.br-tray-content{display:flex;flex-direction:column;gap:var(--zivvy-space-6)}
/* Review fix 15: the tray's three answers use the phone detail's eyebrow +
   answer treatment (.br-detail__section below): one size, one colour. */

/* Gap 5: description list (facts grid). 2 columns of 12px uppercase labels and
   14px values. Labels are --theme-text-secondary at both widths (the desktop
   comp's #94A3B8 is 2.6:1 on white). */
.br-facts{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:var(--zivvy-space-4) var(--zivvy-space-6);margin:0}
.br-tray-content .br-facts{padding-top:var(--zivvy-space-4);border-top:1px solid var(--theme-border-primary)}
.br-fact{display:flex;flex-direction:column;gap:var(--zivvy-space-1);min-width:0;align-items:flex-start}
.br-fact--wide{grid-column:1 / -1}
.br-fact__value{margin:0;font-size:14px;line-height:20px;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.br-fact__zoom{display:inline-flex;align-items:center;gap:6px;color:var(--theme-text-primary)}
.br-fact__zoom .zds-icon{color:var(--theme-text-secondary)}
.br-fact__zoom--yes .zds-icon{color:var(--zivvy-success-hover)}
.br-fact__mail{overflow-wrap:anywhere;white-space:normal}
.br-eyebrow{margin:0;font-family:var(--zivvy-font-text);font-size:12px;line-height:16px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--theme-text-secondary)}

/* ---- phone: search row, results row ------------------------------------- */
.br-phone-bar{display:flex;gap:var(--zivvy-space-2);align-items:center}
.br-phone-bar .zds-search-field{flex:1;min-width:0}
/* Gap 10: results row — "N of M responses" + Clear filters, only while a
   search or filter is on (DataControls is desktop). */
.br-results{display:flex;align-items:center;justify-content:space-between;gap:var(--zivvy-space-2);min-height:44px}
.br-results[hidden]{display:none}
.br-results__text{font-size:14px;line-height:20px;color:var(--theme-text-secondary);font-variant-numeric:tabular-nums lining-nums}

/* ---- phone: response cards ---------------------------------------------- */
.br-cards{display:flex;flex-direction:column;gap:var(--zivvy-space-3)}
.br-card{cursor:pointer}
.br-card__body{display:flex;flex-direction:column;gap:var(--zivvy-space-3)}
.br-card__top{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--zivvy-space-3)}
.br-card__who{min-width:0;display:flex;flex-direction:column;gap:2px}
.br-card__name-line{display:flex;align-items:center;gap:var(--zivvy-space-2);min-width:0}
.br-card__name{font-size:16px;line-height:24px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.br-card__school{font-size:14px;line-height:20px;color:var(--theme-text-secondary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.br-card__date{font-size:13px;line-height:24px;color:var(--theme-text-secondary);white-space:nowrap;font-variant-numeric:tabular-nums lining-nums}
.br-card__hand{display:flex;flex-direction:column;gap:var(--zivvy-space-1)}
/* Gap 7: two-line clamp with the full text in `title` (TruncatedText is
   single-line in ZDS 1.1.0). */
.br-card__need{margin:0;font-size:14px;line-height:20px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;line-clamp:2;overflow:hidden;overflow-wrap:anywhere}
.br-card__foot{display:flex;flex-wrap:wrap;align-items:center;gap:var(--zivvy-space-1) var(--zivvy-space-2);padding-top:var(--zivvy-space-3);min-width:0;border-top:1px solid var(--theme-border-primary)}
.br-card__meta{font-size:13px;line-height:20px;color:var(--theme-text-secondary);white-space:nowrap}
.br-card__stage{white-space:normal}
.br-card__zoom{margin-left:auto;display:flex;color:var(--theme-text-secondary)}
.br-card__zoom--yes{color:var(--zivvy-success-hover)}

/* ---- loading bones (ZDS Skeleton port; gap 6) --------------------------- */
.br-skel{display:flex;flex-direction:column}
.br-skel--table{background:var(--theme-bg-primary);border:1px solid var(--theme-border-primary);border-radius:12px}
.br-skel--table .br-skel__item{display:flex;align-items:center;gap:var(--zivvy-space-6);padding:22px 24px;border-bottom:1px solid var(--theme-border-primary)}
.br-skel--table .br-skel__item:last-of-type{border-bottom:0}
.br-skel--table .br-skel__bone--a{width:120px}
.br-skel--table .br-skel__bone--b{width:160px}
.br-skel--table .br-skel__bone--c{width:auto;flex:1}
.br-skel--table .br-skel__bone--d{width:96px}
.br-skel--cards{gap:var(--zivvy-space-3)}
.br-skel--cards .br-skel__item{display:flex;flex-direction:column;gap:10px;padding:var(--zivvy-space-4);background:var(--theme-bg-primary);border:1px solid var(--theme-border-primary);border-radius:12px}
.br-skel--cards .br-skel__bone--a{width:50%;height:16px}
.br-skel--cards .br-skel__bone--b{width:35%}
.br-skel--cards .br-skel__bone--c{width:90%}
.br-skel--cards .br-skel__bone--d{width:70%}

/* Gap 4: full-screen detail (phone). Header = back IconButton + Display 20/600
   title + 13px subtitle; body = sections + the facts card. */
.br-detail{position:fixed;inset:0;z-index:1000;background:var(--theme-bg-secondary);display:flex;flex-direction:column}
.br-detail[hidden]{display:none}
.br-detail__head{flex-shrink:0;min-height:72px;box-sizing:border-box;background:var(--theme-bg-primary);border-bottom:1px solid var(--theme-border-primary);display:flex;align-items:center;gap:var(--zivvy-space-1);padding:12px 16px 12px 4px}
.br-detail__titles{min-width:0;display:flex;flex-direction:column}
.br-detail__title-line{display:flex;align-items:center;gap:var(--zivvy-space-2);min-width:0}
.br-detail__title{margin:0;font-family:var(--zivvy-font-display);font-size:20px;line-height:28px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.br-detail__subtitle{font-size:13px;line-height:20px;color:var(--theme-text-secondary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.br-detail__body{flex:1;overflow-y:auto;padding:24px 16px 32px;display:flex;flex-direction:column;gap:var(--zivvy-space-6)}
.br-detail__section{display:flex;flex-direction:column;gap:var(--zivvy-space-2)}
.br-detail__text{margin:0;font-size:16px;line-height:24px;overflow-wrap:anywhere}
.br-detail__facts .br-facts{gap:var(--zivvy-space-4)}

/* Gap 3: mobile bottom sheet. The ZDS Sheet (bottom, xl) is used as-is — no
   grab handle, top radius or swipe (ZDS has none); only the footer clears the
   home indicator and the three groups get the comp's 24px rhythm. */
.br-sheet-body{display:flex;flex-direction:column;gap:var(--zivvy-space-6)}
.br-sheet-foot{display:flex;align-items:center;justify-content:flex-end;gap:var(--zivvy-space-3)}
.br-sheet .zds-sheet__footer{padding-bottom:calc(24px + env(safe-area-inset-bottom,0px))}

/* Gap 8: toast placement. Desktop: bottom centre, 24px up (desktop comp).
   Phone: bottom, 16px inset, full width (ZDS ToastContainer is top-right,
   300px minimum). */
.br-toast-slot{position:fixed;left:50%;bottom:24px;transform:translateX(-50%);z-index:10001;display:flex;flex-direction:column;gap:var(--zivvy-space-3);pointer-events:none}
.br-toast-slot > *{pointer-events:auto}
@media (max-width:767px){
  .br-toast-slot{left:16px;right:16px;bottom:16px;transform:none}
  .br-toast-slot .zds-toast{width:100%;min-width:0;max-width:none}
}

/* Gap 4, cont.: the back button sits 4px from the left edge, so its Tooltip
   (shown instantly when focus lands on it as the detail opens) is anchored to
   the button's left edge instead of centred — centred, it runs off-screen. */
.br-detail__head .zds-tooltip > .zds-tooltip__bubble{left:4px;transform:translate(0,-4px)}
.br-detail__head .zds-tooltip.is-shown > .zds-tooltip__bubble{transform:none}

/* Review fix 9: phone touch targets ≥44px. The ports keep their default sizes;
   only this page's phone layout grows the three small controls. */
@media (max-width:767px){
  .br-results .zds-button--sm{min-height:44px}
  .br-phone .zds-search-field__clear{width:44px;height:44px}
  .br-phone .zds-search-field__box{padding-right:0}
  .br-toast-slot .zds-toast__close{min-width:44px;min-height:44px;justify-content:center;align-items:center}
}

/* ---- 768–1199px: DataControls over the cards in two columns (W2) -------
   Last in the file on purpose: it overrides the phone rules above at equal
   specificity (the search row and results row are DataControls' job here). */
@media (min-width:768px) and (max-width:1199px){
  .br-desk-body,.br-phone-bar,.br-results,.br-results[hidden]{display:none}
  .br-phone{display:block}
  .br-desk .zds-data-controls{margin-bottom:0}
  .br-cards,.br-skel--cards{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--zivvy-space-4)}
  .br-card{display:flex;flex-direction:column}
  .br-card__body{flex:1}
  .br-card__foot{margin-top:auto;position:relative;padding-right:32px}
  /* A half-width card can wrap its footer: the Zoom icon stays pinned to the
     right of the last line instead of dropping onto a line of its own. */
  .br-card__zoom{position:absolute;right:0;bottom:0;height:22px;align-items:center}
}

/* ======== /css/integrations.css ======== */
/* Integrations tab (admin/js/integrations.js) — compositions from the Gate 1
   comp v2 (Zivvy_Integrations_Comp_v2.html, frames 3a–3f) on ZDS 1.6.0 tokens.
   StatusBadge, Button, Skeleton, Spinner, Sheet and Toast are ZDS ports; this
   file lays them out and composes what the console's ZDS ports do not cover: the stat tile
   (comp StatTile), the website radio cards (RadioGroup variant=card), the
   confirmation dialog (ConfirmationModal) and the can't-load banner
   (AlertBanner). Layout: the comp's 1280 desktop (3a) and 390 phone (3b);
   below 768px the stat tiles stack and Coming soon becomes a list. */

#in-view{display:flex;flex-direction:column;gap:var(--zivvy-space-8);font-family:var(--zivvy-font-text);color:var(--theme-text-primary)}
.in-head{display:flex;flex-direction:column;gap:var(--zivvy-space-2)}
.in-title{margin:0;font-family:var(--zivvy-font-display);font-size:28px;line-height:36px;font-weight:700;letter-spacing:-.01em}
.in-intro{margin:0;max-width:680px;font-size:16px;line-height:24px;color:var(--theme-text-secondary);text-wrap:pretty}
.in-eyebrow{margin:0;font-size:12px;line-height:16px;letter-spacing:.05em;text-transform:uppercase;font-weight:600;color:var(--theme-text-secondary)}

/* ---- monogram stand-ins for vendor marks (comp: "Vendor marks are monogram stand-ins") */
.in-mono{flex:none;width:36px;height:36px;border-radius:9px;background:var(--zivvy-slate-100);border:1px solid var(--theme-border-primary);display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;color:var(--zivvy-slate-600)}
.in-mono--lg{width:44px;height:44px;border-radius:10px;font-size:13px;color:var(--zivvy-slate-700)}

/* ---- the Google Analytics tile (3a) ---------------------------------- */
.in-tile{background:var(--theme-bg-primary);border:1px solid var(--theme-border-primary);border-radius:12px;padding:var(--zivvy-space-6);display:flex;flex-direction:column;gap:var(--zivvy-space-6);box-shadow:0 1px 2px rgba(15,23,42,.06)}
.in-tile__head{display:flex;gap:var(--zivvy-space-4);align-items:center;flex-wrap:wrap}
.in-tile__id{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.in-tile__name-line{display:flex;gap:var(--zivvy-space-3);align-items:center;flex-wrap:wrap}
.in-tile__name{font-family:var(--zivvy-font-display);font-size:18px;line-height:24px;font-weight:600}
.in-tile__sub{font-size:13px;line-height:20px;color:var(--theme-text-secondary);overflow-wrap:anywhere}
.in-tile__actions{display:flex;gap:var(--zivvy-space-2);flex-wrap:wrap}
.in-tile__actions a.zds-button{text-decoration:none;display:inline-flex;align-items:center;gap:var(--zivvy-space-2)}
.in-tile__detail{margin:0;font-size:14px;line-height:20px;color:var(--zivvy-slate-700);text-wrap:pretty;max-width:680px}

/* ---- stat tiles (comp StatTile + the conversion card) ----------------- */
.in-stats{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--zivvy-space-4)}
.in-stat{border:1px solid var(--theme-border-primary);border-radius:12px;padding:var(--zivvy-space-5);display:flex;flex-direction:column;gap:var(--zivvy-space-2);min-width:0}
.in-stat--plain{justify-content:center}
.in-stat--span2{grid-column:span 2}
.in-stat__top{display:flex;justify-content:space-between;align-items:flex-end;gap:var(--zivvy-space-3)}
.in-stat__text{display:flex;flex-direction:column;gap:var(--zivvy-space-1);min-width:0}
.in-stat__label{display:flex;align-items:center;gap:var(--zivvy-space-1-half);font-size:14px;line-height:20px;font-weight:500;color:var(--theme-text-secondary)}
.in-stat__label .zds-icon{flex:none;color:var(--theme-text-secondary)}
.in-stat__value{font-family:var(--zivvy-font-display);font-size:30px;line-height:36px;font-weight:700;font-variant-numeric:tabular-nums lining-nums;color:var(--theme-text-primary)}
.in-stat__note{margin:0;font-size:13px;line-height:20px;color:var(--theme-text-secondary);text-wrap:pretty}
.in-stat__delta{display:flex;align-items:center;gap:var(--zivvy-space-1);flex-wrap:wrap;font-size:13px;line-height:20px;color:var(--theme-text-secondary)}
/* The delta's text stays in text tokens; the arrow and the words carry direction. */
.in-stat__delta-num{font-weight:600;color:var(--theme-text-primary)}
.in-stat__delta.is-up .zds-icon{color:var(--zivvy-success-text)}
.in-stat__delta.is-down .zds-icon{color:var(--zivvy-danger-text)}
.in-spark{flex:none;width:120px;height:36px;overflow:visible}
.in-spark__line{fill:none;stroke:var(--theme-action-primary,#2563EB);stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.in-spark__dot{fill:var(--theme-action-primary,#2563EB);stroke:var(--theme-bg-primary);stroke-width:2}

/* ---- Coming soon (3a grid of 4; 3b list) ------------------------------ */
.in-soon{display:flex;flex-direction:column;gap:var(--zivvy-space-4)}
.in-soon__grid{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--zivvy-space-4)}
.in-soon__item{background:var(--theme-bg-primary);border:1px solid var(--theme-border-primary);border-radius:12px;padding:var(--zivvy-space-5);display:flex;flex-direction:column;gap:var(--zivvy-space-3)}
.in-soon__head{display:flex;gap:var(--zivvy-space-3);align-items:center}
.in-soon__name{flex:1;min-width:0;font-family:var(--zivvy-font-display);font-size:15px;line-height:22px;font-weight:600}
.in-soon__desc{font-size:13px;line-height:20px;color:var(--theme-text-secondary);text-wrap:pretty}
.in-soon__badge{margin-top:auto}
.in-badge-icon{display:inline-flex;align-items:center;gap:4px}
.in-badge-icon .zds-icon{flex:none}

/* ---- loading (3e) and can't-load banner ------------------------------- */
.in-skel{display:grid;grid-template-columns:1fr 1fr;gap:var(--zivvy-space-4)}
.in-skel__card{background:var(--theme-bg-primary);border:1px solid var(--theme-border-primary);border-radius:12px;padding:var(--zivvy-space-5);display:flex;flex-direction:column;gap:var(--zivvy-space-3)}
.in-banner{display:flex;align-items:center;gap:var(--zivvy-space-3);padding:var(--zivvy-space-4);border:1px solid var(--theme-border-primary);border-left:4px solid var(--theme-border-control,#64748B);border-radius:8px;background:var(--theme-bg-primary)}
.in-banner > .zds-icon{flex:none;color:var(--theme-text-secondary)}
.in-banner__text{flex:1;min-width:0}
.in-banner__title{font-weight:600;font-size:15px;line-height:22px}
.in-banner__desc{font-size:14px;line-height:20px;color:var(--theme-text-secondary)}

/* ---- sheets (3d) ------------------------------------------------------ */
.in-sheet{display:flex;flex-direction:column;gap:var(--zivvy-space-5)}
.in-lede{margin:0;font-size:16px;line-height:24px;color:var(--zivvy-slate-700);text-wrap:pretty}
.in-small{margin:0;font-size:14px;line-height:20px;color:var(--zivvy-slate-700);text-wrap:pretty}
.in-small a,.in-stat a{font-weight:500}
.in-list{display:flex;flex-direction:column;gap:var(--zivvy-space-3)}
.in-list__row{display:flex;gap:var(--zivvy-space-3);align-items:flex-start;font-size:14px;line-height:20px}
.in-list__row .zds-icon{flex:none}
.in-list__row.is-yes .zds-icon{color:var(--zivvy-success-text)}
.in-list__row.is-no .zds-icon{color:var(--theme-text-secondary)}
.in-checking{align-items:center;text-align:center;padding:var(--zivvy-space-12) 0;gap:var(--zivvy-space-4)}
.in-checking__title{font-family:var(--zivvy-font-display);font-size:18px;line-height:24px;font-weight:600}
.in-sheet-foot{display:flex;gap:var(--zivvy-space-2);justify-content:flex-end;flex-wrap:wrap;width:100%}
.in-radios{display:flex;flex-direction:column;gap:var(--zivvy-space-3)}
.in-radio{display:flex;gap:var(--zivvy-space-3);align-items:flex-start;padding:var(--zivvy-space-4);border:1px solid var(--theme-border-primary);border-radius:12px;cursor:pointer;min-height:44px;box-sizing:border-box}
.in-radio:has(input:checked){border-color:var(--theme-action-primary,#2563EB);background:var(--theme-bg-selected)}
.in-radio input{margin:2px 0 0;width:18px;height:18px;accent-color:var(--theme-action-primary,#2563EB)}
.in-radio input:focus-visible{outline:2px solid var(--theme-border-focus);outline-offset:2px}
.in-radio__text{display:flex;flex-direction:column;gap:2px;min-width:0}
.in-radio__label{font-weight:600;font-size:15px;line-height:22px;overflow-wrap:anywhere}
.in-radio__helper{font-size:13px;line-height:20px;color:var(--theme-text-secondary)}
.in-verify{border:1px solid var(--theme-border-primary);border-radius:12px;padding:var(--zivvy-space-6);display:flex;flex-direction:column;gap:var(--zivvy-space-2)}
.in-verify__site{font-family:var(--zivvy-font-display);font-size:30px;line-height:36px;font-weight:700;letter-spacing:-.01em;overflow-wrap:anywhere}
.in-send{border:1px solid var(--theme-border-primary);border-radius:8px;padding:var(--zivvy-space-4);background:var(--theme-bg-secondary);display:flex;flex-direction:column;gap:var(--zivvy-space-2)}
.in-send[hidden]{display:none}
.in-send__msg{margin:0;font-size:14px;line-height:20px;user-select:all}

/* ---- disconnect confirmation (3f) ------------------------------------- */
.in-confirm{max-width:400px;width:calc(100% - 32px);border:0;border-radius:12px;padding:var(--zivvy-space-6);box-shadow:0 12px 32px rgba(15,23,42,.14);color:var(--theme-text-primary);background:var(--theme-bg-primary);font-family:var(--zivvy-font-text)}
.in-confirm::backdrop{background:var(--theme-bg-overlay)}
.in-confirm__head{display:flex;gap:var(--zivvy-space-3);align-items:center;margin-bottom:var(--zivvy-space-3)}
.in-confirm__head .zds-icon{flex:none;color:var(--zivvy-danger-text)}
.in-confirm__title{margin:0;font-family:var(--zivvy-font-display);font-size:18px;line-height:24px;font-weight:600}
.in-confirm__msg{margin:0 0 var(--zivvy-space-6);font-size:14px;line-height:20px;color:var(--zivvy-slate-700)}
.in-confirm__foot{display:flex;gap:var(--zivvy-space-2);justify-content:flex-end;flex-wrap:wrap}

/* ---- phone (3b) ------------------------------------------------------- */
@media (max-width:1099px){
  .in-soon__grid{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media (max-width:767px){
  #in-view{gap:var(--zivvy-space-5)}
  .in-title{font-size:24px;line-height:32px}
  .in-intro{font-size:14px;line-height:20px}
  .in-tile{padding:var(--zivvy-space-4);gap:var(--zivvy-space-4)}
  .in-tile__actions{width:100%;display:grid;grid-template-columns:1fr 1fr}
  .in-tile__actions .zds-button{justify-content:center;min-height:44px}
  .in-stats{grid-template-columns:1fr;gap:var(--zivvy-space-2)}
  .in-stat--span2{grid-column:auto}
  .in-stat__value{font-size:24px;line-height:32px}
  .in-skel{grid-template-columns:1fr}
  .in-soon__grid{grid-template-columns:1fr;gap:0;background:var(--theme-bg-primary);border:1px solid var(--theme-border-primary);border-radius:12px;overflow:hidden}
  .in-soon__item{flex-direction:row;flex-wrap:wrap;align-items:center;border:0;border-bottom:1px solid var(--theme-border-primary);border-radius:0;padding:var(--zivvy-space-3) var(--zivvy-space-4);gap:var(--zivvy-space-1) var(--zivvy-space-3)}
  .in-soon__item:last-child{border-bottom:0}
  .in-soon__head{flex:1 1 100%}
  .in-soon__desc{flex:1 1 100%;padding-left:48px}
  .in-soon__badge{display:none}
  .in-sheet-foot .zds-button{flex:1 1 auto;justify-content:center;min-height:44px}
  /* ZDS bottom sheets are a fixed 360px; these steps size to their content
     (up to 90% of the screen) so the second website option is never hidden. */
  .zds-sheet--bottom.in-sheet-panel{height:auto;max-height:90vh;border-radius:16px 16px 0 0}
  .in-sheet-panel .zds-sheet__footer{padding-bottom:calc(24px + env(safe-area-inset-bottom,0px))}
}

/* ======== /css/analytics.css ======== */
/* Analytics tab, Overview (admin/js/analytics.js) — "Analytics Tracking -
   Gate 1 comp" frames 1a (desktop) and 1b (phone), on ZDS 1.6.0 tokens only.
   Class prefix at- (an- is the Analyst tab). StatusBadge, Button, Skeleton and
   the charts are shared; this file lays them out. Below 768px the cards stack
   and every control is a 56px target (frame 1b). */

#at-view{display:flex;flex-direction:column;gap:var(--zivvy-space-8);font-family:var(--zivvy-font-text);color:var(--theme-text-primary)}
.at-head{display:flex;flex-direction:column;gap:var(--zivvy-space-2)}
.at-title{margin:0;font-family:var(--zivvy-font-display);font-size:28px;line-height:36px;font-weight:700;letter-spacing:-.01em}
.at-intro{margin:0;max-width:680px;font-size:16px;line-height:24px;color:var(--theme-text-secondary);text-wrap:pretty}
.at-site{margin:0;display:flex;align-items:center;gap:var(--zivvy-space-1-half);font-size:14px;line-height:20px;color:var(--theme-text-secondary);overflow-wrap:anywhere}
.at-site .zds-icon{flex:none}

/* ---- filter bar --------------------------------------------------------- */
.at-filters{display:flex;flex-wrap:wrap;align-items:flex-end;gap:var(--zivvy-space-4) var(--zivvy-space-6);padding:var(--zivvy-space-4) var(--zivvy-space-5);border:1px solid var(--theme-border-primary);border-radius:12px;background:var(--theme-bg-primary)}
.at-field{display:flex;flex-direction:column;gap:var(--zivvy-space-1)}
.at-field__label{font-size:13px;line-height:18px;font-weight:600;color:var(--theme-text-secondary)}
.at-select{min-height:40px;min-width:180px;padding:0 var(--zivvy-space-3);border:1px solid var(--theme-border-control,var(--theme-border-primary));border-radius:8px;background:var(--theme-bg-primary);color:var(--theme-text-primary);font:inherit;font-size:15px}
.at-facts{display:flex;flex-wrap:wrap;gap:var(--zivvy-space-2) var(--zivvy-space-6);margin:0;flex:1;min-width:0}
.at-fact{display:flex;flex-direction:column;gap:2px;min-width:0}
.at-fact dt{font-size:13px;line-height:18px;font-weight:600;color:var(--theme-text-secondary)}
.at-fact dd{margin:0;font-size:14px;line-height:20px;font-variant-numeric:tabular-nums}
.at-fresh{margin:0;font-size:13px;line-height:18px;color:var(--theme-text-secondary)}

/* ---- sections and cards ------------------------------------------------- */
.at-section{display:flex;flex-direction:column;gap:var(--zivvy-space-4)}
.at-h3{margin:0;font-family:var(--zivvy-font-display);font-size:18px;line-height:24px;font-weight:600}
.at-cards{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--zivvy-space-4)}
.at-cards--four{grid-template-columns:repeat(4,minmax(0,1fr))}
.at-card{background:var(--theme-bg-primary);border:1px solid var(--theme-border-primary);border-radius:12px;padding:var(--zivvy-space-5);display:flex;flex-direction:column;gap:var(--zivvy-space-2);min-width:0}
.at-card__top{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--zivvy-space-3)}
.at-card__label{font-size:14px;line-height:20px;font-weight:500;color:var(--theme-text-secondary)}
.at-card__value{font-family:var(--zivvy-font-display);font-size:30px;line-height:36px;font-weight:700;font-variant-numeric:tabular-nums lining-nums}
.at-card__delta{display:flex;align-items:center;gap:var(--zivvy-space-1);flex-wrap:wrap;font-size:13px;line-height:20px;color:var(--theme-text-secondary)}
.at-card__delta-num{font-weight:600;color:var(--theme-text-primary)}
.at-card__delta.is-up .zds-icon{color:var(--zivvy-success-text)}
.at-card__delta.is-down .zds-icon{color:var(--zivvy-danger-text)}
.at-card__reason{margin:0;font-size:14px;line-height:20px;color:var(--theme-text-secondary);text-wrap:pretty}
.at-card--pending{background:var(--theme-bg-secondary,var(--theme-bg-primary))}

/* ---- visits over time ---------------------------------------------------- */
.at-chart{padding:var(--zivvy-space-5);border:1px solid var(--theme-border-primary);border-radius:12px;background:var(--theme-bg-primary)}
.at-chart__plot{min-width:0}
.at-chart > .zds-button{align-self:flex-start}
.at-legend{display:flex;flex-wrap:wrap;gap:var(--zivvy-space-2) var(--zivvy-space-5);font-size:13px;line-height:18px;color:var(--theme-text-secondary)}
.at-legend__item{display:inline-flex;align-items:center;gap:var(--zivvy-space-2)}
.at-legend__swatch{width:20px;height:0;border-top:2px solid var(--chart-cat-1)}
.at-legend__swatch--prev{border-top:2px dashed var(--chart-axis-text)}
.at-table-wrap{overflow-x:auto}
.at-table{width:100%;border-collapse:collapse;font-size:14px;line-height:20px}
.at-table caption{text-align:left;font-weight:600;padding-bottom:var(--zivvy-space-2)}
.at-table th,.at-table td{padding:var(--zivvy-space-2) var(--zivvy-space-3);border-bottom:1px solid var(--theme-border-primary);text-align:left}
.at-table th{font-size:13px;font-weight:600;color:var(--theme-text-secondary)}
.at-table .at-num{font-variant-numeric:tabular-nums;text-align:right}
.at-table th:nth-child(2),.at-table th:nth-child(4){text-align:right}

/* ---- states -------------------------------------------------------------- */
.at-stack{display:flex;flex-direction:column;gap:var(--zivvy-space-8)}
.at-banner{display:flex;align-items:center;gap:var(--zivvy-space-3);padding:var(--zivvy-space-4);border:1px solid var(--theme-border-primary);border-left:4px solid var(--theme-border-control,var(--theme-border-primary));border-radius:8px;background:var(--theme-bg-primary)}
.at-banner > .zds-icon{flex:none;color:var(--theme-text-secondary)}
.at-banner__text{flex:1;min-width:0}
.at-banner__title{font-weight:600;font-size:15px;line-height:22px}
.at-banner__desc{font-size:14px;line-height:20px;color:var(--theme-text-secondary);text-wrap:pretty}
.at-empty{display:flex;flex-direction:column;align-items:center;gap:var(--zivvy-space-4);padding:var(--zivvy-space-12) var(--zivvy-space-6);border:1px dashed var(--theme-border-primary);border-radius:12px;text-align:center;color:var(--theme-text-secondary)}
.at-empty__title{margin:0;font-size:16px;line-height:24px;font-weight:600;color:var(--theme-text-primary)}
.at-skel{display:grid;grid-template-columns:1fr 1fr;gap:var(--zivvy-space-4)}

/* ---- phone (frame 1b) ---------------------------------------------------- */
@media (max-width:1023px){
  .at-cards--four{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media (max-width:767px){
  #at-view{gap:var(--zivvy-space-5)}
  .at-cards,.at-cards--four,.at-skel{grid-template-columns:1fr}
  .at-filters{flex-direction:column;align-items:stretch}
  .at-select{min-height:56px;width:100%}
  .at-facts{flex-direction:column}
  .at-banner{flex-wrap:wrap}
  #at-view .zds-button{min-height:56px}
  .at-chart > .zds-button{align-self:stretch}
}

/* ======== /css/agent-work.css ======== */
/* Agent work (admin/js/agent-work.js) — page layout on ZDS 1.6.0.
   Every block on this surface is a published ZDS port
   (public/assets/brand/zds-1.6.0): DataControls, DataTable, Card, StatusBadge,
   Tray, Sheet, DetailHeader, DescriptionList, Input, Textarea, FormGroup,
   ToggleGroup, Toggle, Button, Skeleton, EmptyState, Toast
   (docs/prds/child-14-agent-work.md §11.2). This file only places them and
   sets the text inside a table cell or a Card. It draws no component of its
   own, and every colour is a ZDS token.
   Layout switch (no horizontal scroll at any width). Both list renderings are
   built by the script and kept in step; CSS picks:
     1200px and up  DataControls + the table (.aw-desk, whole).
     768–1199px     DataControls (.aw-desk minus its table) above the task
                    Cards (.aw-phone-body) in two columns. A card opens the Tray.
     below 768px    SearchField + Filters Button, then the Cards (.aw-phone,
                    whole). A card opens the view region (.aw-region). */

#aw-view{display:flex;flex-direction:column;gap:var(--zivvy-space-6);font-family:var(--zivvy-font-text);color:var(--theme-text-primary)}
.aw-phone{display:none}
@media (max-width:767px){
  #aw-view{gap:var(--zivvy-space-4)}
  .aw-desk{display:none}
  .aw-phone{display:flex;flex-direction:column;gap:var(--zivvy-space-4)}
}

/* ---- title row: title, subtitle, New task ------------------------------ */
.aw-head{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--zivvy-space-4)}
.aw-titles{min-width:0;display:flex;flex-direction:column;gap:var(--zivvy-space-1)}
.aw-title{margin:0;font-family:var(--zivvy-font-display);font-size:28px;line-height:32px;font-weight:700;letter-spacing:-.01em;color:var(--theme-text-primary)}
.aw-subtitle{margin:0;font-size:14px;line-height:20px;color:var(--theme-text-secondary);text-wrap:pretty}
.aw-new{flex-shrink:0}
@media (max-width:767px){
  /* New task: full width under the title (§11.2). */
  .aw-head{flex-direction:column;align-items:stretch}
  .aw-titles{gap:var(--zivvy-space-2)}
  .aw-title{font-size:24px}
  .aw-new{width:100%}
}
.aw-foot{margin:0;font-size:12px;line-height:16px;color:var(--theme-text-secondary)}
.aw-foot[hidden]{display:none}

/* ---- DataControls slot: the two Toggles --------------------------------- */
.aw-toggles{display:flex;align-items:center;flex-wrap:wrap;gap:var(--zivvy-space-2) var(--zivvy-space-4)}
.aw-toggles .zds-toggle__label{white-space:nowrap}
.aw-desk .zds-data-controls{margin-bottom:var(--zivvy-space-4)}

/* ---- table cells --------------------------------------------------------
   Fixed layout: five columns carry widths from agent-work.js
   (140+250+100+150+160 = 800px) and Task takes what is left (at least 290px
   at the 1090px floor). The table only shows from 1200px, where its frame is
   at least 1152px wide, so the floor never makes it scroll. Cells use 16px
   side padding instead of the DataTable's 24. */
.aw-desk .zds-data-table__table{table-layout:fixed;min-width:1090px}
.aw-desk .zds-data-table__td,.aw-desk .zds-data-table__th{padding-left:16px;padding-right:16px;overflow:hidden}
.aw-task{display:flex;flex-direction:column;min-width:0}
.aw-task__title-line{display:flex;align-items:center;gap:var(--zivvy-space-2);min-width:0}
.aw-task__title{min-width:0;font-weight:600;color:var(--theme-text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.aw-task__title-line .zds-status-badge{flex-shrink:0}
.aw-task__sub{font-size:13px;line-height:20px;color:var(--theme-text-secondary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.aw-clip{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Next is never clipped: "lease stale" is the part that must be read. */
.aw-next{display:block;white-space:normal;overflow-wrap:anywhere}
.aw-none{color:var(--theme-text-secondary)}
.aw-row.is-open,.aw-card.is-open{background:var(--theme-bg-selected)}

/* ---- phone: search row --------------------------------------------------- */
.aw-phone-bar{display:flex;gap:var(--zivvy-space-2);align-items:center}
.aw-phone-bar .zds-search-field{flex:1;min-width:0}

/* ---- task Cards (tablet and phone) -------------------------------------- */
.aw-cards{display:flex;flex-direction:column;gap:var(--zivvy-space-3)}
.aw-card{cursor:pointer}
.aw-card__body{display:flex;flex-direction:column;gap:var(--zivvy-space-3)}
.aw-card__top{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--zivvy-space-3)}
.aw-card__top .aw-task{flex:1}
.aw-card__top > .zds-status-badge{flex-shrink:0}
/* A Card has room the table row does not: the title wraps to two lines. */
.aw-card .aw-task__title{font-size:16px;line-height:24px;white-space:normal;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;line-clamp:2;overflow-wrap:anywhere}
/* …and "<project> · <id>" wraps instead of losing the id, which is what tells
   two tasks in one project apart on a narrow phone. */
.aw-card .aw-task__sub{white-space:normal;overflow-wrap:anywhere}
.aw-card .aw-task__title-line{align-items:flex-start}
.aw-card .aw-task__title-line .zds-status-badge{margin-top:4px}
.aw-card__next{margin:0;font-size:14px;line-height:20px;overflow-wrap:anywhere}
.aw-card__foot{display:flex;flex-wrap:wrap;align-items:center;gap:var(--zivvy-space-1) var(--zivvy-space-3);padding-top:var(--zivvy-space-3);min-width:0;border-top:1px solid var(--theme-border-primary)}
.aw-card__meta{font-size:13px;line-height:20px;color:var(--theme-text-secondary);min-width:0}
.aw-card__updated{margin-left:auto;white-space:nowrap;font-variant-numeric:tabular-nums lining-nums}

/* ---- loading bones (ZDS Skeleton; only their layout is here) ------------ */
.aw-skel{display:flex;flex-direction:column}
.aw-skel--table{background:var(--theme-bg-primary);border:1px solid var(--theme-border-primary);border-radius:12px}
.aw-skel--table .aw-skel__item{display:flex;align-items:center;gap:var(--zivvy-space-6);padding:22px 24px;border-bottom:1px solid var(--theme-border-primary)}
.aw-skel--table .aw-skel__item:last-of-type{border-bottom:0}
.aw-skel--table .aw-skel__bone--a{width:auto;flex:1}
.aw-skel--table .aw-skel__bone--b{width:96px}
.aw-skel--table .aw-skel__bone--c{width:180px}
.aw-skel--table .aw-skel__bone--d{width:120px}
.aw-skel--cards{gap:var(--zivvy-space-3)}
.aw-skel--cards .aw-skel__item,.aw-skel--detail .aw-skel__item{display:flex;flex-direction:column;gap:10px;padding:var(--zivvy-space-4);background:var(--theme-bg-primary);border:1px solid var(--theme-border-primary);border-radius:12px}
.aw-skel--detail{gap:var(--zivvy-space-4)}
.aw-skel--cards .aw-skel__bone--a,.aw-skel--detail .aw-skel__bone--a{width:50%;height:16px}
.aw-skel--cards .aw-skel__bone--b,.aw-skel--detail .aw-skel__bone--b{width:35%}
.aw-skel--cards .aw-skel__bone--c,.aw-skel--detail .aw-skel__bone--c{width:90%}
.aw-skel--cards .aw-skel__bone--d,.aw-skel--detail .aw-skel__bone--d{width:70%}

/* ---- detail: the blocks in the Tray ------------------------------------- */
.aw-detail{display:flex;flex-direction:column;gap:var(--zivvy-space-6)}
/* In the Tray the DetailHeader shares the left edge of the blocks under it:
   the Tray's body already insets everything, so the header's own side padding
   is dropped here (placement; the port is not edited). */
.aw-detail > .zds-detail-header{padding-left:0;padding-right:0;padding-top:0}
/* Brief and Report (§11.2, Amendment 1): text someone typed, read in full.
   Line breaks are kept and long words wrap; nothing is cut to a line. */
.aw-prose .zds-description-list__value{white-space:pre-wrap;overflow-wrap:anywhere}
.aw-gate__body{display:flex;flex-direction:column;gap:var(--zivvy-space-3)}
.aw-gate__line{margin:0;font-size:14px;line-height:20px;overflow-wrap:anywhere}
.aw-gate__note{width:100%}
.aw-gate__actions{display:flex;flex-wrap:wrap;gap:var(--zivvy-space-2)}
.aw-evidence__url{display:block;overflow-wrap:anywhere;color:var(--theme-interactive-active)}
/* A link's target is at least 24px tall (its line is 20px). */
a.aw-evidence__url{padding:2px 0}
span.aw-evidence__url{color:var(--theme-text-primary)}
.aw-evidence__by{display:block;font-size:13px;line-height:20px;color:var(--theme-text-secondary)}

/* ---- the view region (below 768px): detail or New task form -------------
   The module's own full-screen region, as Build requests' phone detail: its
   header is DetailHeader `compact`, its body scrolls. */
.aw-region{position:fixed;inset:0;z-index:1000;background:var(--theme-bg-secondary);display:flex;flex-direction:column}
.aw-region[hidden]{display:none}
.aw-region__head{flex-shrink:0;min-width:0}
.aw-region__body{flex:1;min-width:0;overflow-y:auto;padding:var(--zivvy-space-4) var(--zivvy-space-4) var(--zivvy-space-8);display:flex;flex-direction:column;gap:var(--zivvy-space-4)}

/* ---- New task form: FormGroups and ToggleGroups, 16px apart -------------- */
.aw-form{display:flex;flex-direction:column;gap:var(--zivvy-space-4)}
.aw-form .zds-input,.aw-form .zds-textarea{width:100%}
.aw-form-actions{display:flex;align-items:center;justify-content:flex-end;gap:var(--zivvy-space-3)}
.aw-form .aw-form-actions{padding-top:var(--zivvy-space-2)}

/* ---- Filters Sheet (below 768px) ---------------------------------------- */
.aw-sheet-body{display:flex;flex-direction:column;gap:var(--zivvy-space-6)}
.aw-sheet-foot{display:flex;align-items:center;justify-content:flex-end;gap:var(--zivvy-space-3)}
.aw-sheet .zds-sheet__footer{padding-bottom:calc(24px + env(safe-area-inset-bottom,0px))}

/* Phone touch targets of at least 44px. The ports keep their default sizes;
   only this page's phone layout grows the small ones. */
@media (max-width:767px){
  .aw-phone .zds-search-field__clear{width:44px;height:44px}
  .aw-phone .zds-search-field__box{padding-right:0}
}

/* ---- 768–1199px: DataControls over the Cards in two columns --------------
   Last in the file on purpose: it overrides the phone rules above at equal
   specificity (the search row is DataControls' job here). */
@media (min-width:768px) and (max-width:1199px){
  .aw-desk-body,.aw-phone-bar{display:none}
  .aw-phone{display:block}
  .aw-desk .zds-data-controls{margin-bottom:0}
  .aw-cards,.aw-skel--cards{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--zivvy-space-4)}
  .aw-card{display:flex;flex-direction:column}
  .aw-card__body{flex:1}
  .aw-card__foot{margin-top:auto}
}
