/* FinFlow Layout — App shell, sidebar, topbar, page wrappers, primitives */

/* Counts are read when the current record set renders. */
const ffPendingCount = () => FF_DATA.expenses.filter(e => ['pending','flagged'].includes(e.status)).length;
const ffGreeting = () => {
  const hour = new Date().getHours();
  return hour >= 5 && hour < 12 ? 'Good morning' : hour >= 12 && hour < 18 ? 'Good afternoon' : 'Good evening';
};
// Largest remainder keeps whole-number category shares at exactly 100%.
const ffPercentShares = values => {
  const total = values.reduce((sum, value) => sum + value, 0);
  if (!total) return values.map(() => 0);
  const exact = values.map(value => value / total * 100);
  const rounded = exact.map(Math.floor);
  const order = exact.map((value, i) => ({ i, remainder:value-rounded[i] })).sort((a,b) => b.remainder-a.remainder || a.i-b.i);
  order.slice(0, 100-rounded.reduce((sum, value) => sum+value, 0)).forEach(({i}) => rounded[i]++);
  return rounded;
};

/* Navigate the app from any screen (App wires window.ffNavigate on mount). */
const ffGo = (id, params) => { if (window.ffNavigate) window.ffNavigate(id, params); };
const ffRowKeyDown = (e) => {
  if (e.target !== e.currentTarget) return;
  if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); e.currentTarget.click(); return; }
  if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp') return;
  const rows = [...(e.currentTarget.closest('tbody') || e.currentTarget.parentElement).querySelectorAll('[data-row-focus]')];
  const i = rows.indexOf(e.currentTarget); if (i < 0) return;
  e.preventDefault(); rows[(i + (e.key === 'ArrowDown' ? 1 : rows.length - 1)) % rows.length]?.focus();
};

const Icon = ({ name, size = 16, weight = "regular", style = {} }) => (
  <i className={`ph${weight === "fill" ? "-fill" : weight === "bold" ? "-bold" : ""} ph-${name}`}
     style={{ fontSize: size, lineHeight: 1, ...style }} aria-hidden="true"/>
);

/* BrandIcon — real third-party brand marks, not generic glyphs. Google and
   Microsoft render their official multi-color logos (standard "Sign in
   with…" button assets from each provider's own identity-platform branding
   guidelines). Okta, QuickBooks, Xero, Sage, and Brex use the exact path
   data from Simple Icons (simpleicons.org), an open-source, MIT-licensed,
   community-maintained registry of brand SVGs — not hand-approximated. */
const BRAND_ICON_PATHS = {
  okta:       { color: "#007DC1", d: "M12 0C5.389 0 0 5.35 0 12s5.35 12 12 12 12-5.35 12-12S18.611 0 12 0zm0 18c-3.325 0-6-2.675-6-6s2.675-6 6-6 6 2.675 6 6-2.675 6-6 6z" },
  quickbooks: { color: "#2CA01C", d: "M12 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0zm.642 4.1335c.9554 0 1.7296.776 1.7296 1.7332v9.0667h1.6c1.614 0 2.9275-1.3156 2.9275-2.933 0-1.6173-1.3136-2.9333-2.9276-2.9333h-.6654V7.3334h.6654c2.5722 0 4.6577 2.0897 4.6577 4.667 0 2.5774-2.0855 4.6666-4.6577 4.6666H12.642zM7.9837 7.333h3.3291v12.533c-.9555 0-1.73-.7759-1.73-1.7332V9.0662H7.9837c-1.6146 0-2.9277 1.316-2.9277 2.9334 0 1.6175 1.3131 2.9333 2.9277 2.9333h.6654v1.7332h-.6654c-2.5725 0-4.6577-2.0892-4.6577-4.6665 0-2.5771 2.0852-4.6666 4.6577-4.6666Z" },
  xero:       { color: "#13B5EA", d: "M12 0C5.373 0 0 5.373 0 12s5.373 12 12 12 12-5.373 12-12S18.627 0 12 0zm6.585 14.655c-1.485 0-2.69-1.206-2.69-2.689 0-1.485 1.207-2.691 2.69-2.691 1.485 0 2.69 1.207 2.69 2.691s-1.207 2.689-2.69 2.689zM7.53 14.644c-.099 0-.192-.041-.267-.116l-2.043-2.04-2.052 2.047c-.069.068-.16.108-.258.108-.202 0-.368-.166-.368-.368 0-.099.04-.191.111-.263l2.04-2.05-2.038-2.047c-.075-.069-.113-.162-.113-.261 0-.203.166-.366.368-.366.098 0 .188.037.258.105l2.055 2.048 2.048-2.045c.069-.071.162-.108.26-.108.211 0 .375.165.375.366 0 .098-.029.188-.104.258l-2.056 2.055 2.055 2.051c.068.069.104.16.104.258 0 .202-.165.368-.365.368h-.01zm8.017-4.591c-.796.101-.882.476-.882 1.404v2.787c0 .202-.165.366-.366.366-.203 0-.367-.165-.368-.366v-4.53c0-.204.16-.366.362-.366.166 0 .316.125.346.289.27-.209.6-.317.93-.317h.105c.195 0 .359.165.359.368 0 .201-.164.352-.375.359 0 0-.09 0-.164.008l.053-.002zm-3.091 2.205H8.625c0 .019.003.037.006.057.02.105.045.211.083.31.194.531.765 1.275 1.829 1.29.33-.003.631-.086.9-.229.21-.12.391-.271.525-.428.045-.058.09-.112.12-.168.18-.229.405-.186.54-.083.164.135.18.391.045.57l-.016.016c-.21.27-.435.495-.689.66-.255.164-.525.284-.811.345-.33.09-.645.104-.975.06-1.095-.135-2.01-.93-2.28-2.01-.06-.21-.09-.42-.09-.645 0-.855.421-1.695 1.125-2.205.885-.615 2.085-.66 3-.075.63.405 1.035 1.021 1.185 1.771.075.419-.21.794-.734.81l.068-.046zm6.129-2.223c-1.064 0-1.931.865-1.931 1.931 0 1.064.866 1.931 1.931 1.931s1.931-.867 1.931-1.931c0-1.065-.866-1.933-1.931-1.933v.002zm0 2.595c-.367 0-.666-.297-.666-.666 0-.367.3-.665.666-.665.367 0 .667.299.667.665 0 .369-.3.667-.667.666zm-8.04-2.603c-.91 0-1.672.623-1.886 1.466v.03h3.776c-.203-.855-.973-1.494-1.891-1.494v-.002z" },
  sage:       { color: "#00D639", d: "M2.702 5.316C1.167 5.316 0 6.48 0 7.972c0 1.635 1.167 2.267 2.46 2.655 1.224.387 1.804.818 1.804 1.666 0 .86-.64 1.465-1.477 1.465-.84 0-1.566-.604-1.566-1.535 0-.516.242-.647.242-.934 0-.33-.227-.574-.599-.574-.423 0-.864.647-.864 1.566 0 1.48 1.266 2.57 2.787 2.57 1.535 0 2.701-1.163 2.701-2.656 0-1.623-1.166-2.267-2.472-2.655-1.209-.372-1.792-.818-1.792-1.666 0-.845.626-1.45 1.463-1.45.867 0 1.565.617 1.577 1.465.016.388.285.617.599.617a.592.592 0 0 0 .61-.647c-.027-1.48-1.263-2.543-2.771-2.543zm6.171 9.52c.683 0 1.21-.23 1.21-.69a.57.57 0 0 0-.557-.574c-.2 0-.341.085-.668.085-.882 0-1.577-.76-1.577-1.65 0-.962.71-1.725 1.608-1.725 1.009 0 1.65.775 1.65 1.895v2.054c0 .36.284.604.625.604.327 0 .61-.244.61-.604v-2.097c0-1.72-1.178-2.984-2.858-2.984-1.566 0-2.86 1.22-2.86 2.856 0 1.58 1.282 2.83 2.817 2.83zm6.257 3.848c1.535 0 2.701-1.163 2.701-2.656 0-1.635-1.166-2.267-2.472-2.655-1.209-.387-1.792-.818-1.792-1.666s.64-1.465 1.463-1.465c.84 0 1.577.604 1.577 1.535 0 .519-.241.647-.241.934 0 .33.226.574.583.574.441 0 .882-.647.882-1.566 0-1.48-1.278-2.57-2.801-2.57-1.535 0-2.687 1.163-2.687 2.656 0 1.623 1.152 2.267 2.46 2.655 1.224.372 1.804.818 1.804 1.666 0 .86-.64 1.45-1.462 1.45-.883 0-1.566-.601-1.578-1.465-.015-.388-.3-.604-.598-.604-.327 0-.626.216-.61.631.011 1.499 1.247 2.546 2.77 2.546zm6.171-3.849c.795 0 1.424-.229 1.862-.503.426-.272.595-.504.595-.76 0-.272-.2-.516-.568-.516-.441 0-.795.66-1.877.66-.952 0-1.707-.76-1.707-1.722 0-.95.725-1.724 1.635-1.724.982 0 1.508.647 1.508 1.062 0 .116-.085.174-.2.174h-1.194c-.326 0-.568.216-.568.503 0 .314.242.546.568.546h1.636c.625 0 1.009-.33 1.009-.89 0-1.408-1.194-2.512-2.774-2.512-1.566 0-2.83 1.263-2.83 2.84s1.312 2.842 2.905 2.842z" },
  brex:       { color: "#212121", d: "M18.69 2.319a3.868 3.868 0 0 0-3.108 1.547l-.759 1.007a1.658 1.658 0 0 1-1.313.656H0V21.68h5.296a3.87 3.87 0 0 0 3.108-1.547l.759-1.006a1.656 1.656 0 0 1 1.313-.657H24V2.319h-5.31Zm1.108 11.949h-5.66a3.87 3.87 0 0 0-3.108 1.547l-.759 1.007a1.658 1.658 0 0 1-1.313.656H4.202V9.731h5.661a3.868 3.868 0 0 0 3.107-1.547l.759-1.006a1.658 1.658 0 0 1 1.313-.657h4.771l-.015 7.747Z" },
  figma:          { color: "#F24E1E", d: "M15.852 8.981h-4.588V0h4.588c2.476 0 4.49 2.014 4.49 4.49s-2.014 4.491-4.49 4.491zM12.735 7.51h3.117c1.665 0 3.019-1.355 3.019-3.019s-1.355-3.019-3.019-3.019h-3.117V7.51zm0 1.471H8.148c-2.476 0-4.49-2.014-4.49-4.49S5.672 0 8.148 0h4.588v8.981zm-4.587-7.51c-1.665 0-3.019 1.355-3.019 3.019s1.354 3.02 3.019 3.02h3.117V1.471H8.148zm4.587 15.019H8.148c-2.476 0-4.49-2.014-4.49-4.49s2.014-4.49 4.49-4.49h4.588v8.98zM8.148 8.981c-1.665 0-3.019 1.355-3.019 3.019s1.355 3.019 3.019 3.019h3.117V8.981H8.148zM8.172 24c-2.489 0-4.515-2.014-4.515-4.49s2.014-4.49 4.49-4.49h4.588v4.441c0 2.503-2.047 4.539-4.563 4.539zm-.024-7.51a3.023 3.023 0 0 0-3.019 3.019c0 1.665 1.365 3.019 3.044 3.019 1.705 0 3.093-1.376 3.093-3.068v-2.97H8.148zm7.704 0h-.098c-2.476 0-4.49-2.014-4.49-4.49s2.014-4.49 4.49-4.49h.098c2.476 0 4.49 2.014 4.49 4.49s-2.014 4.49-4.49 4.49zm-.097-7.509c-1.665 0-3.019 1.355-3.019 3.019s1.355 3.019 3.019 3.019h.098c1.665 0 3.019-1.355 3.019-3.019s-1.355-3.019-3.019-3.019h-.098z" },
  lyft:           { color: "#FF00BF", d: "M4.38 15.883c.036.042.125.135.125.135s-.094.059-.152.086a3.046 3.046 0 0 1-1.28.286C1.593 16.39 0 15.29 0 12.878v-8.78h3.512v9.365c0 .95.306 1.781.867 2.42zM24 11.122V7.61h-1.253c-.524-2.76-3.425-4.574-6.341-3.484-1.624.607-2.943 2.548-2.943 4.282v7.979a1608.8 1608.8 0 0 0 .153 0 3.495 3.495 0 0 0 2.38-1.077c.632-.658.98-1.522.98-2.432h1.463V9.366h-1.463V8.4c0-.375.198-.726.526-.909.9-.5 1.815.143 1.815.996v3.22c0 1.273.48 2.456 1.354 3.329a4.666 4.666 0 0 0 3.178 1.351H24v-3.51a1.17 1.17 0 0 1-1.17-1.17v-.586H24zm-14.927 1.17a.585.585 0 0 1-1.17 0V7.61H4.39v5.853a2.928 2.928 0 0 0 4.83 2.224c-.055.433-.294.792-.69 1.04-.373.234-.857.357-1.402.357a3.83 3.83 0 0 1-1.65-.382s-.093-.044-.21-.11v3.119a6.65 6.65 0 0 0 2.468.484c1.312 0 2.51-.41 3.371-1.155.967-.836 1.478-2.056 1.478-3.528V7.61H9.073v4.683z" },
  marriott:       { color: "#A70023", d: "M8.802 11.083l-1.178 2.41c-.8 1.425-1.931 3.167-3.646 3.603-.668.232-1.255.023-1.9-.023L0 20.476a1.626 1.626 0 0 0 .59.386c3.647 1.39 5.122-.1 8.722-8.238l3.403 7.249h4.53l-2.14-4.893 1.213-2.53 3.345 7.311 4.337.027-7.59-16.677-3.475 1.738 2.738 6.222-1.201 2.445L9.45 2.678l-3.7 1.877Z" },
  notion:         { color: "#000000", d: "M4.459 4.208c.746.606 1.026.56 2.428.466l13.215-.793c.28 0 .047-.28-.046-.326L17.86 1.968c-.42-.326-.981-.7-2.055-.607L3.01 2.295c-.466.046-.56.28-.374.466zm.793 3.08v13.904c0 .747.373 1.027 1.214.98l14.523-.84c.841-.046.935-.56.935-1.167V6.354c0-.606-.233-.933-.748-.887l-15.177.887c-.56.047-.747.327-.747.933zm14.337.745c.093.42 0 .84-.42.888l-.7.14v10.264c-.608.327-1.168.514-1.635.514-.748 0-.935-.234-1.495-.933l-4.577-7.186v6.952L12.21 19s0 .84-1.168.84l-3.222.186c-.093-.186 0-.653.327-.746l.84-.233V9.854L7.822 9.76c-.094-.42.14-1.026.793-1.073l3.456-.233 4.764 7.279v-6.44l-1.215-.139c-.093-.514.28-.887.747-.933zM1.936 1.035l13.31-.98c1.634-.14 2.055-.047 3.082.7l4.249 2.986c.7.513.934.653.934 1.213v16.378c0 1.026-.373 1.634-1.68 1.726l-15.458.934c-.98.047-1.448-.093-1.962-.747l-3.129-4.06c-.56-.747-.793-1.306-.793-1.96V2.667c0-.839.374-1.54 1.447-1.632z" },
  unitedairlines: { color: "#002244", d: "M5.327 3.067c8.654 0 15.695 7.068 15.695 15.754 0 1.762-.298 3.515-.875 5.179H24V0H0v4.003l.019-.007a15.569 15.569 0 0 1 5.308-.929M0 10.534c.975-1.389 1.116-2.983.26-3.761a1.56 1.56 0 0 0-.26-.19zm5.027-5.057c-.863-.99-2.3-1.33-3.969-1.092l-.135.02a7.873 7.873 0 0 0-.386.077C.28 4.542.104 4.6 0 4.64v.5a8.47 8.47 0 0 1 .505-.37c.333-.07.656-.116.968-.136C.99 4.91.434 5.283 0 5.627v.385l.015.009s1.224-.969 2.196-1.386c.234.017.458.05.672.099A14.624 14.624 0 0 0 .284 6.168c.15.088.285.199.303.213.019-.012 1.427-.892 2.977-1.42.21.096.413.216.589.351-1.688.474-3.31 1.321-3.31 1.321.092.106.172.221.242.344l.029-.011c1.727-.74 3.562-1.118 3.562-1.118.143.196.262.416.352.658 0 0-1.647.188-3.765.868.093.292.119.512.119.515 0 0 1.997-.447 3.839-.497.026.296.016.628-.026.969-1.09-.058-3.69.08-3.791.089 0 0-.01.374-.107.726 0 0 1.899.061 3.626.383a8.406 8.406 0 0 1-.507 1.22c-1.15-.346-2.897-.766-3.357-.871a5.64 5.64 0 0 1-.453.88s2.134.93 2.953 1.386h.002v.001c-.356.532-1.06 1.277-1.06 1.277a73.343 73.343 0 0 0-.58-.43L.005 11.685 0 11.68v1.765l1.107 1.292c-.364.294-.736.562-1.107.802v1.053l.041-.026a15.948 15.948 0 0 0 1.492-1.151c3.819-3.323 5.383-7.773 3.495-9.94m4.701.184C7.917 3.221 5.08 3.57 4.234 3.688c-.929.13-1.631.334-1.631.334.207.019.49.056.694.097.15-.036 1.454-.333 2.402-.209h.003c-.697.076-1.647.363-1.746.394h-.002a3.154 3.154 0 0 1 .663.3c.102-.026 1.392-.369 2.623-.393 0 0 .455.202.893.503-1.59-.006-2.907.3-2.942.308.186.165.371.364.537.603 1.744-.262 3.248-.148 3.248-.148s.204.25.296.383a5 5 0 0 1 .327.563c-1.779-.208-3.48-.059-3.482-.059.118.303.197.627.24.968.197-.002 1.704.001 3.623.346.062.44.068.912.02 1.41a25.761 25.761 0 0 0-3.622-.65c-.035.43-.116.877-.242 1.336.192.045 2.317.552 3.506 1.034a12.226 12.226 0 0 1-.707 1.76c-.958-.472-3.307-1.39-3.307-1.39a12.625 12.625 0 0 1-.858 1.588s2.014 1.15 2.984 1.786a18.19 18.19 0 0 1-1.511 1.875c-.704-.63-2.464-1.994-2.597-2.097a25.338 25.338 0 0 1-1.496 1.596l2.112 2.422-.06.053c-.458.38-.95.736-1.366 1.022-.361.245-.66.435-.762.501a302.864 302.864 0 0 1-1.615-2.596c-.152.113-.305.22-.458.326v4.539c.248-.12.497-.244.745-.376a18.882 18.882 0 0 0 3.422-2.19 21.666 21.666 0 0 0 2.125-1.93 18.942 18.942 0 0 0 2.2-2.704c2.329-3.438 2.952-7.023 1.236-9.333m3.701.829a3.523 3.523 0 0 0-.4-.468 4.523 4.523 0 0 0-.4-.344c-1.502-1.133-4.268-1.7-4.268-1.7.264.141.484.285.485.286.013.004 1.128.283 2.117.767 0 0-.9-.204-1.476-.284.238.21.465.45.664.703 0 0 1.835.335 2.64.776 0 0 .386.397.701 1.093-1.257-.51-2.682-.777-2.682-.777.19.424.325.878.408 1.35 0 0 1.566.383 2.742.948.102.559.14 1.136.118 1.72a21.613 21.613 0 0 0-2.77-1.134 9.298 9.298 0 0 1-.287 1.865s1.898.847 2.75 1.362a13.329 13.329 0 0 1-.77 2.201c-1.299-.844-2.673-1.594-2.673-1.594-.346.83-1.195 2.187-1.195 2.187.022.015 1.436.986 2.52 1.847a20.88 20.88 0 0 1-1.807 2.346 304.27 304.27 0 0 0-2.312-2.068 22.358 22.358 0 0 1-2.095 2.12l2.008 2.273c-1.302 1.074-2.601 1.887-2.601 1.887L3.17 21.47s-1.18.897-3.17 1.84V24h6.537c7.297-5.52 9.886-13.415 6.892-17.511M12.967 24c1.704-1.905 3.155-4.147 4.027-6.547.757-2.082 1.169-4.625.5-6.887a6.312 6.312 0 0 0-.155-.45 5.429 5.429 0 0 0-.794-1.415 15.18 15.18 0 0 0-2.749-2.413c.15.191.285.389.402.589 0 0 1.231.913 1.946 1.84-.917-.652-1.436-.917-1.503-.95l-.008-.004c.348.859.453 1.57.453 1.57s1.088.568 2.067 1.416c.136.627.192 1.27.183 1.913-.987-.869-2.13-1.547-2.13-1.547a11.7 11.7 0 0 1-.284 2.204s1.079.683 2.13 1.64c0 0-.302 1.358-.789 2.424a26.291 26.291 0 0 0-2.069-1.726s-.5 1.305-1.312 2.616a61.394 61.394 0 0 1 1.959 1.789 21.41 21.41 0 0 1-1.943 2.57v.001l-1.807-1.798a23.958 23.958 0 0 1-2.392 2.55c.04.046.404.45.553.615zm3.213 0h.902c2.567-3.792 2.696-7.153 2.696-7.797 0-1.216-.204-2.334-.546-3.219 0 0-.532-1.375-1.362-2.6a11.694 11.694 0 0 1 .377 1.413c.163.273.9 1.572.999 3.001v.004s-.52-.729-.907-1.19a12.068 12.068 0 0 1-.28 2.33s.772.894 1.117 1.47c0 0-.235 1.258-.738 2.462-.512-.745-1.166-1.468-1.166-1.468a19.217 19.217 0 0 1-1.406 2.778s.978 1.144 1.192 1.47c-.287.484-.567.905-.878 1.346m3.27 0c.194-.525.369-1.085.512-1.654a15.228 15.228 0 0 0 .28-5.658c-.069.998-.243 1.873-.243 1.873.041.132.114.349.147.482v.001a17.79 17.79 0 0 1-.575 2.995c-.131-.484-.307-.95-.318-.98h-.001c-.353.94-.881 2.05-1.361 2.941Z" },
  webflow:        { color: "#146EF5", d: "m24 4.515-7.658 14.97H9.149l3.205-6.204h-.144C9.566 16.713 5.621 18.973 0 19.485v-6.118s3.596-.213 5.71-2.435H0V4.515h6.417v5.278l.144-.001 2.622-5.277h4.854v5.244h.144l2.72-5.244H24Z" },
  visa:           { color: "#1A1F71", d: "M9.112 8.262L5.97 15.758H3.92L2.374 9.775c-.094-.368-.175-.503-.461-.658C1.447 8.864.677 8.627 0 8.479l.046-.217h3.3a.904.904 0 01.894.764l.817 4.338 2.018-5.102zm8.033 5.049c.008-1.979-2.736-2.088-2.717-2.972.006-.269.262-.555.822-.628a3.66 3.66 0 011.913.336l.34-1.59a5.207 5.207 0 00-1.814-.333c-1.917 0-3.266 1.02-3.278 2.479-.012 1.079.963 1.68 1.698 2.04.756.367 1.01.603 1.006.931-.005.504-.602.725-1.16.734-.975.015-1.54-.263-1.992-.473l-.351 1.642c.453.208 1.289.39 2.156.398 2.037 0 3.37-1.006 3.377-2.564m5.061 2.447H24l-1.565-7.496h-1.656a.883.883 0 00-.826.55l-2.909 6.946h2.036l.405-1.12h2.488zm-2.163-2.656l1.02-2.815.588 2.815zm-8.16-4.84l-1.603 7.496H8.34l1.605-7.496z" },
  googlecloud:    { color: "#4285F4", d: "M12.19 2.38a9.344 9.344 0 0 0-9.234 6.893c.053-.02-.055.013 0 0-3.875 2.551-3.922 8.11-.247 10.941l.006-.007-.007.03a6.717 6.717 0 0 0 4.077 1.356h5.173l.03.03h5.192c6.687.053 9.376-8.605 3.835-12.35a9.365 9.365 0 0 0-2.821-4.552l-.043.043.006-.05A9.344 9.344 0 0 0 12.19 2.38zm-.358 4.146c1.244-.04 2.518.368 3.486 1.15a5.186 5.186 0 0 1 1.862 4.078v.518c3.53-.07 3.53 5.262 0 5.193h-5.193l-.008.009v-.04H6.785a2.59 2.59 0 0 1-1.067-.23h.001a2.597 2.597 0 1 1 3.437-3.437l3.013-3.012A6.747 6.747 0 0 0 8.11 8.24c.018-.01.04-.026.054-.023a5.186 5.186 0 0 1 3.67-1.69z" },
  googlechat:     { color: "#34A853", d: "M1.637 0C.733 0 0 .733 0 1.637v16.5c0 .904.733 1.636 1.637 1.636h3.955v3.323c0 .804.97 1.207 1.539.638l3.963-3.96h11.27c.903 0 1.636-.733 1.636-1.637V5.592L18.408 0Zm3.955 5.592h12.816v8.59H8.455l-2.863 2.863Z" },
  wise:           { color: "#9FE870", d: "M6.488 7.469 0 15.05h11.585l1.301-3.576H7.922l3.033-3.507.01-.092L8.993 4.48h8.873l-6.878 18.925h4.706L24 .595H2.543l3.945 6.874Z" },
  starbucks:      { color: "#006241", d: "M13.2072 5.2801c-.1052-.0188-.6126-.104-1.2072-.104s-1.102.0848-1.2072.104c-.0605.0108-.0837-.0484-.0377-.0828.0417-.0308 1.2445-.9463 1.2445-.9463l1.244.9463c.0469.0344.024.0936-.0364.0828zm-2.0783 5.9446s-.0636.0228-.0804.0788c.252.1937.4257.6343.9515.6343s.6995-.4406.9511-.6343c-.0164-.0564-.08-.0788-.08-.0788s-.3293.0776-.8711.0776c-.5418 0-.8711-.0776-.8711-.0776zM12 10.4832c-.146 0-.178-.0552-.2777-.0548-.0948.0004-.2789.076-.319.1453a.1542.1542 0 00.0413.0948c.2129.032.309.1505.5558.1505.2469 0 .3425-.1185.5558-.1505a.1579.1579 0 00.0412-.0948c-.0396-.0692-.224-.1445-.3193-.1453-.1-.0008-.1324.0548-.2781.0548zm11.9868 2.27a11.964 11.964 0 01-.076.8528c-1.359.2249-1.8447-.986-3.2368-.9252.0832.2954.1508.5963.2029.9036 1.148-.0008 1.6105 1.0724 2.8878.9143-.0672.3281-.148.6519-.2413.9708-1.01.0992-1.3657-.9044-2.5345-.8767.0096.1664.0148.3345.0148.5041l-.0048.2805 2.2696.866a12.04 12.04 0 01-.3965.9479c-.6823-.0376-.9175-.9127-1.9555-.8431a9.0882 9.0882 0 01-.118.665c.9015-.0632 1.0955.7667 1.7414.834a12.2317 12.2317 0 01-.5302.8767c-.3826-.205-.7143-.8231-1.4398-.8612a8.6035 8.6035 0 00.195-.6994c-.6435 0-1.3794-.2509-1.9964-.8127.2-1.1388-1.5674-2.2984-1.5674-3.1324 0-.9059.4582-1.4073.4582-2.6285 0-.9063-.4402-1.8895-1.104-2.5614a2.2175 2.2175 0 00-.4114-.3309c.6098.7547 1.078 1.6494 1.078 2.6858 0 1.15-.535 1.757-.535 2.8186 0 1.0612 1.5526 1.9796 1.5526 3.074 0 .4305-.1377.851-.5914 1.677.697.6962 1.605 1.076 2.1908 1.076.19 0 .292-.058.3601-.2073a9.0925 9.0925 0 00.1665-.391c.631.0245.9199.5979 1.2692.8268-.1916.2573-.393.5057-.6038.7462-.234-.2593-.5486-.6954-1.0092-.8167a9.2087 9.2087 0 01-.2613.473c.3966.108.6679.5082.878.7715a12.1305 12.1305 0 01-.7075.6754c-.1532-.2384-.3917-.541-.659-.7042a8.3639 8.3639 0 01-.3077.391c.2272.154.4277.4313.5586.6574-.2833.2272-.5763.443-.8796.6446-.1496-1.2192-1.8138-2.0548-1.3653-3.4693-.1472.2493-.3229.561-.3229.9364 0 1.024 1.0908 1.8366 1.1776 2.8542-.226.1353-.4573.2625-.693.383-.0392-1.1185-1.194-2.3425-1.194-3.2604 0-1.0248 1.342-2.054 1.342-3.2636 0-1.2105-1.5485-2.0484-1.5485-3.1112 0-1.062.6586-1.673.6586-3.0343 0-.9972-.4738-2.0063-1.2056-2.651-.1297-.1144-.2573-.2052-.4106-.2849.6903.828 1.0904 1.579 1.0904 2.7186 0 1.2801-.7546 1.9908-.7546 3.244 0 1.2537 1.5197 1.9507 1.5197 3.1192 0 1.1684-1.4145 2.1532-1.4145 3.3536 0 1.092 1.2468 2.182 1.2653 3.4777a11.7704 11.7704 0 01-.8327.3257c.1584-1.3089-1.245-2.659-1.245-3.727 0-1.1676 1.4674-2.1712 1.4674-3.43 0-1.2597-1.4917-1.8451-1.4917-3.138 0-1.292.9151-2.0075.9151-3.4352 0-1.1129-.5494-2.1136-1.352-2.7338l-.0509-.0385c-.0756-.056-.138.0116-.0844.078.5682.7095.8719 1.427.8719 2.4894 0 1.306-1.0512 2.3673-1.0512 3.6325 0 1.4934 1.4117 1.9203 1.4117 3.1456 0 1.2248-1.5137 2.2048-1.5137 3.5053 0 1.206 1.4325 2.5445 1.1868 3.9366a11.6645 11.6645 0 01-.8743.192c.2689-1.7334-1.1364-2.9782-1.1364-4.1122 0-1.2277 1.5677-2.322 1.5677-3.5217 0-1.1316-1.1252-1.5014-1.2732-2.659-.0204-.158-.1473-.2753-.3221-.2461-.2285.0416-.5214.192-.9816.192-.4602 0-.753-.1508-.982-.192-.1744-.0288-.3013.0884-.3217.246-.1476 1.1577-1.2736 1.527-1.2736 2.659 0 1.1997 1.5681 2.2937 1.5681 3.5218 0 1.134-1.4053 2.3788-1.1368 4.1123a12.1233 12.1233 0 01-.8743-.1921c-.2457-1.3921 1.1872-2.7306 1.1872-3.9366 0-1.3005-1.5141-2.2805-1.5141-3.5053 0-1.2253 1.412-1.6522 1.412-3.1456 0-1.2652-1.0515-2.326-1.0515-3.6325 0-1.062.3037-1.7795.8723-2.4893.0532-.0665-.0088-.134-.0848-.078l-.0504.0384c-.802.6186-1.351 1.6193-1.351 2.7322 0 1.4277.9152 2.1431.9152 3.4352 0 1.2925-1.4917 1.878-1.4917 3.138 0 1.2588 1.4673 2.2624 1.4673 3.43 0 1.0684-1.4033 2.4181-1.2445 3.727a11.8995 11.8995 0 01-.833-.3257c.0188-1.2957 1.2648-2.3861 1.2648-3.4777 0-1.2004-1.4137-2.1852-1.4137-3.3536 0-1.1685 1.519-1.8655 1.519-3.1192 0-1.2532-.7543-1.9639-.7543-3.244 0-1.1396.3997-1.8907 1.09-2.7186-.1537.0797-.281.1705-.4102.285-.7318.6446-1.2052 1.6537-1.2052 2.651 0 1.3612.6586 1.9722.6586 3.0342 0 1.0628-1.5485 1.9007-1.5485 3.1112 0 1.2096 1.342 2.2392 1.342 3.2636 0 .9183-1.1556 2.1423-1.1944 3.2604a11.8754 11.8754 0 01-.693-.383c.0872-1.0176 1.1776-1.8303 1.1776-2.8542 0-.3754-.1753-.687-.323-.9364.4486 1.4145-1.2156 2.25-1.3652 3.4693a12.1204 12.1204 0 01-.8796-.6446c.1305-.2257.331-.5034.5586-.6575a7.9134 7.9134 0 01-.3077-.391c-.2677.1633-.5066.4659-.6594.7043a12.2459 12.2459 0 01-.707-.6754c.21-.2633.4813-.6635.8779-.7715a9.0433 9.0433 0 01-.2613-.473c-.4606.1213-.7755.5574-1.0092.8167a12.141 12.141 0 01-.6038-.7462c.3493-.229.6382-.8027 1.2688-.8267.0529.1312.1085.2617.1669.3909.068.1493.1705.2073.3601.2073.5858 0 1.4934-.3798 2.1908-1.076-.4537-.826-.5914-1.2465-.5914-1.677 0-1.094 1.5526-2.0124 1.5526-3.074 0-1.0615-.535-1.6686-.535-2.8186 0-1.0364.4682-1.9311 1.078-2.6858a2.2175 2.2175 0 00-.4114.331c-.6638.6722-1.104 1.655-1.104 2.5613 0 1.2212.4586 1.7226.4586 2.6285 0 .834-1.7679 1.9936-1.5678 3.1324-.617.5618-1.3529.8127-1.9967.8127a9.305 9.305 0 00.1949.6994c-.7251.0385-1.0568.6567-1.4398.8612a12.0872 12.0872 0 01-.5302-.8768c.6455-.0672.84-.897 1.7419-.8339a9.1275 9.1275 0 01-.1185-.665c-1.038-.0696-1.2732.8059-1.9555.8431a12.04 12.04 0 01-.3965-.948l2.27-.8659-.0048-.2805c0-.1696.0052-.3377.0144-.5041-1.1688-.0273-1.5246.976-2.5345.8767a12.106 12.106 0 01-.241-.9708c1.2766.158 1.7395-.9151 2.888-.9143a8.7482 8.7482 0 01.2024-.9036c-1.392-.0604-1.8779 1.1505-3.2364.9252a11.7352 11.7352 0 01-.076-.8527c1.5794.1764 2.1716-1.122 3.6097-.9632a8.4303 8.4303 0 01.471-.9963c-1.803-.317-2.4153 1.1908-4.0935.9591C.1813 5.2805 5.4844.0898 12 .0898S23.8187 5.2805 24 11.753c-1.6786.2317-2.2908-1.2757-4.0935-.9591.1773.32.335.6526.471.9963 1.4373-.1592 2.0295 1.1396 3.6093.9632zm-17.147-5.035c-.884-.3613-1.954-.278-2.868.309-.1416-.8504-.603-1.6058-1.26-2.0616-.0908-.0628-.1853-.0032-.1769.102.1389 1.7967-.9115 3.3569-2.2032 4.7282 1.3313.4001 2.4645-1.3141 4.1912-.7159a9.0364 9.0364 0 012.3168-2.3617zM12 6.6314c-1.1144 0-2.048.6303-2.2924 1.4446-.0188.0624.0068.1028.0788.0704.2005-.09.4285-.1333.6762-.1333.4546 0 .8551.1669 1.092.4574.1049.3457.1137.8463-.0048 1.132-.1872-.042-.2545-.1868-.4373-.1868-.1829 0-.3245.1284-.6347.1284-.3097 0-.346-.1465-.5498-.1465-.2396 0-.2837.247-.2837.5254 0 1.2417 1.1413 2.9503 2.3553 2.9503 1.2136 0 2.3549-1.7086 2.3549-2.9503 0-.2785-.0573-.517-.3077-.5494-.1249.09-.2397.1705-.5254.1705-.3102 0-.3958-.1284-.5783-.1284-.2204 0-.1984.465-.4601.491-.1745-.4194-.1829-.9572-.038-1.4362.2373-.2905.6374-.4574 1.092-.4574.2477 0 .4773.0437.6758.1333.0724.0324.0976-.0084.0788-.0704-.244-.8143-1.1772-1.4446-2.2916-1.4446zm1.7743 1.7815c-.2673 0-.5807.082-.7775.3013-.0204.0596-.0204.1484.0084.2077.4845-.166.9119-.1725 1.1184.0584.11-.1.1452-.19.1452-.2945 0-.1613-.164-.273-.4945-.273zm-3.8979.5674c.2337-.234.7263-.224 1.238-.0352.0225-.2545-.4333-.5326-.8887-.5326-.3309 0-.4945.1116-.4945.2733 0 .1044.0352.1949.1452.2945zm7.6804-4.2031c-.8799.0628-1.6442.3649-2.2624.8683.2625-.7443.5958-1.3953 1.0184-2.0264-1.1204.1189-2.0572.5286-2.7406 1.2289l-.535-1.4025 1.1876-1.0488-1.5902-.1125L12 .8053l-.635 1.479-1.5902.1124 1.1876 1.0488-.5346 1.4025c-.6838-.7003-1.6206-1.11-2.7402-1.2289.4218.6315.7551 1.2825 1.0176 2.0264-.6178-.5038-1.3821-.806-2.262-.8683.5278.6786.9955 1.402 1.342 2.18.0393.0876.1233.1164.2141.0712 1.2053-.599 2.5634-.936 4.0003-.936 1.437 0 2.7946.3374 4.0007.936.0908.0452.1748.0164.2136-.0712.347-.778.8147-1.5014 1.343-2.18zm1.9211 5.3035c1.7259-.5982 2.8595 1.1156 4.1908.7159-1.2917-1.3713-2.3417-2.9315-2.2028-4.7282.0084-.1052-.0865-.1652-.1769-.102-.6574.4558-1.1188 1.2112-1.26 2.0615-.9144-.587-1.984-.6706-2.868-.3089a9.0431 9.0431 0 012.317 2.3617z" },
  udemy:          { color: "#A435F0", d: "M12 0L5.81 3.573v3.574l6.189-3.574 6.191 3.574V3.573zM5.81 10.148v8.144c0 1.85.589 3.243 1.741 4.234S10.177 24 11.973 24s3.269-.482 4.448-1.474c1.179-.991 1.768-2.439 1.768-4.314v-8.064h-3.242v7.85c0 2.036-1.509 3.055-2.948 3.055-1.428 0-2.947-.991-2.947-3.027v-7.878z" },
  ticketmaster:   { color: "#026CDF", d: "M14.5153 11.3333c-.2454 0-.4826.0464-.716.1304l-.0776.4499c.2168-.105.4499-.1681.6912-.1681.1924 0 .4214.063.4214.2817 0 .063 0 .126-.0163.185h-.1923c-.5153 0-1.2924.0546-1.2924.7697 0 .3994.2699.6181.6502.6181.3026 0 .4909-.1388.679-.3828h.0082l-.0574.3324h.4624c.0491-.408.2576-1.2576.2576-1.5477 0-.5088-.3966-.6686-.818-.6686zm-.3805 1.8546c-.139 0-.2781-.0758-.2781-.2272 0-.3658.4418-.412.7076-.412h.1922c-.0857.349-.2125.6392-.6217.6392zm-8.647-.7826l.656 1.1947h-.6391l-.563-1.1647h-.0084L4.688 13.6h-.5546l.6731-3.2h.567l-.3767 1.8007h.0085l.7915-.798h.7366L5.488 12.4053zm3.8071.746c.0947 0 .1894-.0216.2562-.0517l-.0907.4485c-.0905.0216-.193.052-.2837.052-.3587 0-.6111-.1554-.6111-.5825 0-.1725.0316-.3407.067-.5175l.1498-.7506H8.4l.0828-.4228h.3824l.0907-.4574.5677-.2026-.1301.66h.4732l-.0828.4226h-.4734l-.193.9707a.9992.9992 0 00-.0236.2156c0 .1339.0826.2157.201.2157zm-8.4 0c.0947 0 .1894-.0216.2564-.0517l-.0906.4485c-.0908.0216-.1934.052-.284.052-.3587 0-.6111-.1554-.6111-.5825 0-.1725.0316-.3407.067-.5175l.1498-.7506H0l.0827-.4228h.3826l.0907-.4574.5675-.2026-.1302.66h.4734l-.0828.4226H.9107l-.1931.9707a1.004 1.004 0 00-.0237.2156c0 .1339.0828.2157.201.2157zm2.1018-.5521c0 .2816.0937.5633.4858.5633.1406 0 .3154-.0378.4644-.1093l-.0638.4459c-.1747.084-.3623.101-.5498.101-.5668 0-.9333-.3742-.9333-.9337 0-.757.5072-1.333 1.2956-1.333.213 0 .4176.0378.571.084l-.1406.4626c-.111-.0715-.26-.1093-.4176-.1093-.456 0-.7117.4205-.7117.8285zm-.4574-1.6433h-.61l.1276-.556h.6098l-.1274.556zm-.0956.408L1.9432 13.6h-.6099l.5006-2.236h.6098zm18.3563.7937c0 .164-.0199.3236-.0515.4836h-1.2524c.001-.1027.0094-.2168.0564-.387h.7276a.9136.9136 0 00.012-.1471c0-.2314-.1152-.3616-.3373-.3616-.3133 0-.4579.1904-.56.466a1.2249 1.2249 0 00-.0864.4297h-.0004l.0001.0063-.0002.012c0 .0208.0017.04.0026.0598h.0004c.0258.3406.2243.4686.5646.4686.2182 0 .4285-.0588.627-.1558l-.0677.446c-.2061.0672-.4324.122-.6507.122-.5873 0-.9841-.3029-.9841-.9464 0-.6726.4921-1.3204 1.1627-1.3204.504 0 .8373.2732.8373.8243zm1.773-.8243c.0755 0 .156.0042.227.0215l-.1247.5635a.7823.7823 0 00-.2272-.0344c-.4233 0-.628.3656-.704.7226l-.2137.9935h-.597l.4098-1.9183c.0177-.0946.0356-.1936.0535-.2968h.5702l-.0802.4174h.0089c.107-.241.401-.469.6773-.469zm1.1433.2631c0-.1183-.0707-.1763-.2142-.1763h-.239v.6255h.1018v-.2765h.0852l.1746.2765h.1082l-.178-.2765c.098 0 .1614-.0724.1614-.1727zm-.3514.093v-.1892h.1208c.0654 0 .129.0206.129.0915 0 .0812-.0507.0976-.129.0976h-.1208zM13.2 11.9398c0 .1977-.0497.4216-.0955.602L12.8804 13.6h-.5564l.2243-1.0796c.029-.1333.0706-.3399.0706-.473 0-.1635-.1205-.2667-.2616-.2667-.3862 0-.4817.4644-.5522.7656l-.22 1.0537h-.5564l.2242-1.0796c.0291-.1333.0707-.3399.0707-.473 0-.1635-.1205-.2667-.2616-.2667-.3779 0-.4817.4688-.5523.7656l-.22 1.0537h-.5564l.3903-1.9699c.0167-.086.0332-.1764.0457-.2453h.519l-.0498.297h.0082c.1496-.228.3944-.3485.656-.3485.2533 0 .5148.1548.544.4215h.0082c.1411-.2881.4526-.4215.7514-.4215.3197 0 .5937.271.5937.6066zM23.4668 11.2h-.0001a.5343.5343 0 00-.5334.5337.534.534 0 00.5334.533.5341.5341 0 00.5333-.533.5343.5343 0 00-.5332-.5337zm.0017.9872c-.2481 0-.4333-.198-.4333-.4535 0-.2556.1852-.4537.4332-.4537.2448 0 .4297.1981.4297.4537 0 .2555-.1849.4534-.4296.4535zm-5.4177.5328a1 1 0 00-.0236.2156c0 .1339.0828.2157.201.2157.0947 0 .1894-.0216.2563-.0517l-.0906.4485c-.0907.0216-.1932.052-.284.052-.3587 0-.6111-.1554-.6111-.5825 0-.1725.0317-.3407.067-.5175l.15-.7506h-.3825l.0827-.4228h.3827l.0906-.4574.5676-.2026-.13.66H18.8l-.0828.4226h-.4733l-.1931.9707zm-1.4036-1.3867c.216 0 .4364.0379.5528.0667l-.128.4247c-.0635-.033-.2267-.0792-.3941-.0792-.1762 0-.3967.0462-.3967.2186 0 .2734.767.3744.767.9042 0 .5636-.5157.7317-1.0226.7317-.2381 0-.4763-.0336-.6923-.1303l.128-.45c.1675.0883.335.1682.5642.1682.1984 0 .4056-.0632.4056-.2396 0-.3491-.767-.383-.767-.9254 0-.5088.5156-.6896.9831-.6896zm-8.3805.8243c0 .164-.02.3236-.0516.4836H6.9628c.001-.1027.0092-.2168.0565-.387h.7275a.9136.9136 0 00.012-.1471c0-.2314-.1152-.3616-.3373-.3616-.3134 0-.4579.1904-.56.466a1.2276 1.2276 0 00-.0864.4297h-.0004l.0001.0063-.0003.012c0 .0208.0018.04.0027.0598h.0005c.0255.3406.2243.4686.5644.4686.2182 0 .4286-.0588.627-.1558l-.0676.446c-.2062.0672-.4324.122-.6507.122-.5873 0-.9841-.3028-.9841-.9464 0-.6726.492-1.3204 1.1626-1.3204.504 0 .8374.2732.8374.8243z" },
  adp:            { color: "#D0271D", d: "M15.08584 11.9999a3.13031 3.13031 0 0 1-3.12003 3.12002h-1.2v-1.37144h1.2a1.74859 1.74859 0 1 0 0-3.49717h-1.2V8.87987h1.2a3.13031 3.13031 0 0 1 3.12003 3.12002M8.43436 8.87987v2.53716H6.27434l-.78858 1.37144H9.8058v-3.9086Zm15.56584 1.9543a4.28575 4.28575 0 0 1-4.28575 4.28575v2.33145h-3.70289V15.6342a5.36233 5.36233 0 0 1-4.08003 1.81716H8.43436v-2.33145H5.69148l-1.37144 2.33145H0L6.34291 6.54842h5.6229a5.59548 5.59548 0 0 1 4.08004 1.81716V6.54842h3.70289a4.2789 4.2789 0 0 1 4.25146 4.28575m-12.03439 5.24576a4.09032 4.09032 0 0 0 3.7029-2.33145h1.74858v2.33145h.96v-2.33145h1.37145a2.91088 2.91088 0 0 0 2.9143-2.91431 2.94174 2.94174 0 0 0-2.94859-2.91431H17.383v3.49717h-1.37144a4.11432 4.11432 0 0 0-4.04575-3.49717H7.16577l-4.76575 8.16007h1.13144l1.37144-2.33145h4.9029v2.33145zm7.74864-7.20006h-1.37144v1.37144h1.37144a.57943.57943 0 0 1 .58286.58286.6.6 0 0 1-.58286.58286h-1.37144v1.37144h1.37144a1.9543 1.9543 0 0 0 1.9543-1.9543 1.97487 1.97487 0 0 0-1.9543-1.9543 M21.63447 16.76565a.54858.54858 0 1 1-.54858-.54858.54172.54172 0 0 1 .54858.54858m.13714 0a.68572.68572 0 1 0-.68572.68572.68572.68572 0 0 0 .68572-.68572 M21.12018 16.45707a.13714.13714 0 1 1 0 .2743h-.13715v-.2743zm.17143-.03428a.26057.26057 0 0 0-.17143-.06857h-.2743v.82286h.10287v-.30857h.13714l.17143.30857h.13714l-.20571-.34286c.03428 0 .06857-.03429.10286-.06857a.20572.20572 0 0 0 .03428-.13715.192.192 0 0 0-.03428-.20571" },
  chase:          { color: "#117ACA", d: "M0 15.415c0 .468.38.85.848.85h5.937V.575L0 7.72v7.695m15.416 8.582c.467 0 .846-.38.846-.849v-5.937H.573l7.146 6.785h7.697M24 8.587a.844.844 0 0 0-.847-.846h-5.938V23.43l6.782-7.148L24 8.586M8.585.003a.847.847 0 0 0-.847.847v5.94h15.688L16.282.003H8.585Z" },
  sap:            { color: "#0FAAFF", d: "M0 6.064v11.872h12.13L24 6.064zm3.264 2.208h.005c.863.001 1.915.245 2.676.633l-.82 1.43c-.835-.404-1.255-.442-1.73-.467-.708-.038-1.064.215-1.069.488-.007.332.669.633 1.305.838.964.306 2.19.715 2.377 1.9L7.77 8.437h2.046l2.064 5.576-.007-5.575h2.37c2.257 0 3.318.764 3.318 2.519 0 1.575-1.09 2.514-2.936 2.514h-.763l-.01 2.094-3.588-.003-.25-.908c-.37.122-.787.189-1.23.189-.456 0-.885-.071-1.263-.2l-.358.919-2 .006.09-.462c-.029.025-.057.05-.087.074-.535.43-1.208.629-2.037.644l-.213.002a5.075 5.075 0 0 1-2.581-.675l.73-1.448c.79.467 1.286.572 1.956.558.347-.007.598-.07.761-.239a.557.557 0 0 0 .156-.369c.007-.376-.53-.553-1.185-.756-.531-.164-1.135-.389-1.606-.735-.559-.41-.825-.924-.812-1.65a1.99 1.99 0 0 1 .566-1.377c.519-.537 1.357-.863 2.363-.863zm10.597 1.67v1.904h.521c.694 0 1.247-.23 1.248-.964 0-.709-.554-.94-1.248-.94zm-5.087.767l-.748 2.362c.223.085.481.133.757.133.268 0 .52-.047.742-.126l-.736-2.37z" },
};

/* Merchant/vendor display names (from FF_DATA) mapped to their Simple Icons
   slug. Names not listed here have no verified brand asset available and
   fall back to a generic glyph rather than an invented mark. */
const MERCHANT_ICON_MAP = {
  "Figma": "figma",
  "Lyft": "lyft",
  "Marriott": "marriott",
  "Marriott Austin": "marriott",
  "Marriott SF": "marriott",
  "Notion": "notion",
  "United Airlines": "unitedairlines",
  "Webflow": "webflow",
  "Google Cloud": "googlecloud",
  "Google Chat": "googlechat",
  "Xero": "xero",
  "Wise": "wise",
  "Starbucks": "starbucks",
  "Udemy": "udemy",
  "Ticketmaster": "ticketmaster",
  "ADP": "adp",
  "Chase": "chase",
};

const MerchantIcon = ({ name, size = 16, style = {} }) => {
  const key = MERCHANT_ICON_MAP[name];
  if (!key) return <Icon name="storefront" size={size} style={style}/>;
  return <BrandIcon name={key} size={size} style={style}/>;
};

const BrandIcon = ({ name, size = 16, style = {} }) => {
  if (name === "google") {
    return (
      <svg width={size} height={size} viewBox="0 0 18 18" style={{ flexShrink: 0, ...style }} aria-hidden="true">
        <path fill="#4285F4" d="M17.64 9.2045c0-.6381-.0573-1.2518-.1636-1.8409H9v3.4814h4.8436c-.2086 1.125-.8427 2.0782-1.7955 2.7164v2.2581h2.9087c1.7018-1.5668 2.6836-3.874 2.6836-6.615z"/>
        <path fill="#34A853" d="M9 18c2.43 0 4.4673-.806 5.9564-2.1805l-2.9087-2.2581c-.806.5399-1.8368.8618-3.0477.8618-2.3436 0-4.3282-1.5831-5.036-3.7104H.9573v2.3318C2.4382 15.9832 5.4818 18 9 18z"/>
        <path fill="#FBBC05" d="M3.964 10.71c-.18-.5399-.2822-1.1155-.2822-1.71s.1023-1.1701.2822-1.71V4.9582H.9573C.3477 6.1732 0 7.5477 0 9c0 1.4523.3477 2.8268.9573 4.0418L3.964 10.71z"/>
        <path fill="#EA4335" d="M9 3.5795c1.3214 0 2.5077.4541 3.4405 1.346l2.5813-2.5814C13.4632.8918 11.4259 0 9 0 5.4818 0 2.4382 2.0168.9573 4.9582L3.964 7.29C4.6718 5.1627 6.6564 3.5795 9 3.5795z"/>
      </svg>
    );
  }
  if (name === "microsoft") {
    return (
      <svg width={size} height={size} viewBox="0 0 21 21" style={{ flexShrink: 0, ...style }} aria-hidden="true">
        <rect x="1" y="1" width="9" height="9" fill="#F25022"/>
        <rect x="11" y="1" width="9" height="9" fill="#7FBA00"/>
        <rect x="1" y="11" width="9" height="9" fill="#00A4EF"/>
        <rect x="11" y="11" width="9" height="9" fill="#FFB900"/>
      </svg>
    );
  }
  const icon = BRAND_ICON_PATHS[name];
  if (!icon) return null;
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill={icon.color} style={{ flexShrink: 0, ...style }} aria-hidden="true">
      <path d={icon.d}/>
    </svg>
  );
};

const Money = ({ value, signed = false, className = "" }) => {
  const sign = signed && value > 0 ? "+" : "";
  const fmt = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD", minimumFractionDigits: 2 });
  return <span className={`ff-tnum ${className}`}>{sign}{fmt.format(value)}</span>;
};

/* One date format everywhere: ISO in, "May 22, 2026" out. */
const fmtDate = (iso) => new Date(iso + "T00:00:00").toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });

/* Status → semantic group + icon. Every status string used anywhere in the
   app (and every label named in the design-system brief, whether or not
   FinFlow's mock data currently produces it) resolves through this one
   table — no component picks its own color or icon. Group = which of the
   seven --ff-status-* token sets renders; icon/label are per-status. */
const STATUS_MAP = {
  // success
  approved:      { group: "success", label: "Approved",  icon: "check-circle" },
  paid:          { group: "success", label: "Paid",      icon: "check-circle" },
  completed:     { group: "success", label: "Completed", icon: "check-circle" },
  active:        { group: "success", label: "Active",    icon: "check-circle" },
  connected:     { group: "success", label: "Connected", icon: "check-circle" },
  // warning
  pending:          { group: "warning", label: "Pending",         icon: "clock" },
  "awaiting-review":{ group: "warning", label: "Awaiting review", icon: "clock" },
  waiting:          { group: "warning", label: "Waiting",         icon: "clock" },
  "in-progress":    { group: "warning", label: "In progress",     icon: "clock" },
  scheduled:        { group: "warning", label: "Scheduled",       icon: "clock" },
  // info
  submitted:      { group: "info", label: "Submitted",     icon: "file-text" },
  processing:     { group: "info", label: "Processing",    icon: "spinner-gap" },
  "policy-check": { group: "info", label: "Policy check",  icon: "shield-check" },
  "under-review": { group: "info", label: "Under review",  icon: "eye" },
  information:    { group: "info", label: "Information",   icon: "info" },
  available:      { group: "info", label: "Available",     icon: "info" },
  // review
  flagged:          { group: "review", label: "Flagged",        icon: "flag" },
  escalated:        { group: "review", label: "Escalated",      icon: "flag" },
  "manual-review":  { group: "review", label: "Manual review",  icon: "flag" },
  suspicious:       { group: "review", label: "Suspicious",     icon: "flag" },
  // action required
  "needs-info":       { group: "action", label: "Needs info",       icon: "warning-circle" },
  needs:               { group: "action", label: "Needs info",       icon: "warning-circle" },
  "missing-receipt":  { group: "action", label: "Missing receipt",  icon: "warning-circle" },
  "awaiting-user":    { group: "action", label: "Awaiting you",     icon: "warning-circle" },
  "requires-action":  { group: "action", label: "Requires action",  icon: "warning-circle" },
  // danger
  rejected:          { group: "danger", label: "Rejected",         icon: "x-circle" },
  failed:            { group: "danger", label: "Failed",           icon: "x-circle" },
  "over-cap":        { group: "danger", label: "Over cap",         icon: "warning" },
  over:               { group: "danger", label: "Over cap",         icon: "warning" },
  "policy-violation":{ group: "danger", label: "Policy violation", icon: "warning" },
  violate:            { group: "danger", label: "Policy violation", icon: "warning" },
  declined:          { group: "danger", label: "Declined",         icon: "x-circle" },
  // neutral
  draft:      { group: "neutral", label: "Draft",     icon: "circle" },
  archived:   { group: "neutral", label: "Archived",  icon: "archive" },
  cancelled:  { group: "neutral", label: "Cancelled", icon: "circle" },
  disabled:   { group: "neutral", label: "Disabled",  icon: "circle" },
  expired:    { group: "neutral", label: "Expired",   icon: "clock" },
  frozen:     { group: "neutral", label: "Frozen",    icon: "snowflake" },
  ok:         { group: "neutral", label: "OK",        icon: "check-circle" }
};

const StatusBadge = ({ status }) => {
  const m = STATUS_MAP[status] || { group: "neutral", label: status, icon: "circle" };
  return (
    <span className={`ff-badge ff-badge--${m.group}`}>
      <span className="ff-badge__icon"><Icon name={m.icon} size={12}/></span>
      {m.label}
    </span>
  );
};

/* One consistent headshot per person, keyed by full name — same photo
   everywhere that person appears. Names without a mapped photo fall back
   to the existing initials badge rather than a mismatched or invented image. */
const PERSON_PHOTOS = {
  "Jordan Lee": "assets/avatars/jordan-lee.jpg",
  "Alex Morgan": "assets/avatars/alex-morgan.jpg",
};

const Avatar = ({ initials, name, size = "md", style = {} }) => {
  const cls = size === "lg" ? "ff-avatar ff-avatar--lg" : size === "xl" ? "ff-avatar ff-avatar--xl" : "ff-avatar";
  const photo = name && PERSON_PHOTOS[name];
  if (photo) {
    return (
      <span className={cls} style={{...style, padding: 0, overflow: 'hidden'}}>
        <img src={photo} alt={name} style={{width: '100%', height: '100%', objectFit: 'cover', borderRadius: 'inherit'}}/>
      </span>
    );
  }
  return <span className={cls} style={style}>{initials}</span>;
};

/* Pilot redesign: horizontal nav, no sidebar. Each role gets its 5-7
   highest-frequency destinations in the row itself; everything else lives
   behind "More" (opens the same ⌘K directory used for search) rather than
   cramming a 12-item sidebar into one row. */
const TOPNAV_ITEMS = {
  finance: [
    { id: "dashboard",  label: "Dashboard" },
    { id: "expenses",   label: "Expenses",      count: 14 },
    { id: "approvals",  label: "Approvals",     count: ffPendingCount },
    { id: "reimburse",  label: "Reimbursements" },
    { id: "reports",    label: "Reports" }
  ],
  manager: [
    { id: "dashboard-mgr", label: "Team overview" },
    { id: "approvals",     label: "Approvals", count: ffPendingCount },
    { id: "expenses",      label: "Team expenses" },
    { id: "reports",       label: "Reports" },
    { id: "budgets",       label: "Budgets" }
  ],
  employee: [
    { id: "dashboard-emp", label: "My spend" },
    { id: "new-expense",   label: "New expense" },
    { id: "my-expenses",   label: "My expenses" },
    { id: "my-cards",      label: "My cards" },
    { id: "my-reimburse",  label: "Reimbursements" }
  ]
};

/* Real product functionality, not a screen-jump list — the same set behind
   every role's "More" (per the IA: low-frequency destinations get identical
   treatment regardless of role, reachable by search or here, never buried
   per-role). Global ⌘K search is offered as its own explicit last item. */
const MORE_MENU_ITEMS = [
  { id: "cards",                 label: "Cards",          icon: "credit-card" },
  { id: "vendors",               label: "Vendors",        icon: "storefront" },
  { id: "settings-profile",      label: "Settings",      icon: "gear" },
  { id: "settings-policies",     label: "Policies",       icon: "scales" },
  { id: "settings-team",         label: "Team & roles",   icon: "users-three" },
  { id: "settings-integrations", label: "Integrations",   icon: "plugs" },
  { id: "audit",                 label: "Audit log",      icon: "scroll" },
  { id: "notif",                 label: "Notifications",  icon: "bell" },
  { id: "help",                  label: "Help",           icon: "question" },
];

const TopNav = ({ role, current, onNavigate, theme, onTheme, onRole, onSearchClick, onNotif, onResetData }) => {
  const user = FF_DATA.me[role];
  const [moreOpen, setMoreOpen] = React.useState(false);
  const [resetNotice, setResetNotice] = React.useState('');
  const resetTimer = React.useRef(null);
  React.useEffect(() => () => clearTimeout(resetTimer.current), []);
  const resetDemo = () => {
    onResetData();
    setResetNotice('Demo data reset');
    clearTimeout(resetTimer.current);
    resetTimer.current = setTimeout(() => setResetNotice(''), 3000);
  };
  const moreRef = React.useRef(null);
  React.useEffect(() => {
    if (!moreOpen) return;
    const onDocClick = (e) => { if (moreRef.current && !moreRef.current.contains(e.target)) setMoreOpen(false); };
    const onEsc = (e) => { if (e.key === "Escape") setMoreOpen(false); };
    document.addEventListener("mousedown", onDocClick);
    document.addEventListener("keydown", onEsc);
    return () => { document.removeEventListener("mousedown", onDocClick); document.removeEventListener("keydown", onEsc); };
  }, [moreOpen]);
  return (
    <header className="ff-topnav">
      <a href="#" className="ff-topnav__brand" onClick={e=>{e.preventDefault(); onSearchClick();}}>
        <BrandMark variant="mark" size={24}/>
        <BrandMark variant="wordmark" size={17}/>
      </a>
      <nav className="ff-topnav__items" aria-label="Primary">
        {TOPNAV_ITEMS[role].map(item => ({...item, count:item.id === 'approvals' ? ffQueue().length : item.id === 'expenses' && role === 'finance' ? FF_DATA.expenses.length : item.count})).map(it => (
          <a key={it.id} href="#"
             aria-current={current === it.id ? "page" : undefined}
             onClick={(e)=>{e.preventDefault(); onNavigate(it.id);}}>
            {it.label}
            {it.count !== undefined && it.count > 0 && <span className="ff-topnav__count ff-tnum">{it.count}</span>}
          </a>
        ))}
        <div ref={moreRef} style={{position:'relative'}}>
          <a href="#" className="ff-topnav__more" aria-haspopup="menu" aria-expanded={moreOpen}
             onClick={(e)=>{e.preventDefault(); setMoreOpen(o => !o);}}>
            More <Icon name="caret-down" size={11}/>
          </a>
          {moreOpen && (
            <div role="menu" style={{
              position:'absolute', top:'calc(100% + 6px)', left:0, minWidth:240, zIndex:60,
              background:'var(--ff-card)', border:'1px solid var(--ff-border-strong)', borderRadius:'var(--ff-radius-lg)',
              boxShadow:'var(--ff-shadow-lg)', padding:6,
            }}>
              {MORE_MENU_ITEMS.filter(it => ffCanAccess(it.id, role)).map(it => (
                <a key={it.id} role="menuitem" href="#" className="ff-nav-item"
                   onClick={(e)=>{e.preventDefault(); setMoreOpen(false); onNavigate(it.id);}}>
                  <span className="ff-nav-item__icon"><Icon name={it.icon} size={16}/></span>
                  <span>{it.label}</span>
                </a>
              ))}
              <hr className="ff-divider" style={{margin:'6px 4px'}}/>
              <a role="menuitem" href="#" className="ff-nav-item"
                 onClick={(e)=>{e.preventDefault(); setMoreOpen(false); onSearchClick();}}>
                <span className="ff-nav-item__icon"><Icon name="magnifying-glass" size={16}/></span>
                <span>All screens</span>
                <span className="ff-nav-item__count">⌘K</span>
              </a>
            </div>
          )}
        </div>
      </nav>
      <div style={{flex:1}}/>
      <div className="ff-segmented ff-segmented--sm" role="tablist" aria-label="Viewing role">
        {[
          { id: "finance",  label: "Admin",    short: "Adm" },
          { id: "manager",  label: "Manager",  short: "Mgr" },
          { id: "employee", label: "Employee", short: "Emp" }
        ].map(r => (
          <button key={r.id} role="tab" aria-selected={role === r.id} onClick={() => onRole(r.id)} aria-label={r.label}>
            <span className="ff-segmented__full">{r.label}</span>
            <span className="ff-segmented__short">{r.short}</span>
          </button>
        ))}
      </div>
      <button className="ff-btn ff-btn--ghost ff-btn--icon" onClick={onSearchClick} aria-label="Screens" title="Open screen directory">
        <Icon name="magnifying-glass" size={16}/>
      </button>
      <button className="ff-btn ff-btn--ghost ff-btn--icon" onClick={onTheme} aria-label="Toggle theme">
        <Icon name={theme === "dark" ? "sun" : "moon"} size={16}/>
      </button>
      <button className="ff-btn ff-btn--ghost ff-btn--icon" onClick={onNotif} aria-label="Notifications" style={{position:'relative'}}>
        <Icon name="bell" size={16}/>
        <span style={{position:'absolute', top:6, right:6, width:6, height:6, background:'var(--ff-rejected)', borderRadius:999}}/>
      </button>
      <button className="ff-btn ff-btn--ghost ff-reset-demo" onClick={resetDemo} aria-label="Reset demo data" title="Restore the original FinFlow demo records"><Icon name={resetNotice ? "check" : "arrow-counter-clockwise"} size={14}/> <span role="status">{resetNotice || "Reset demo data"}</span></button>
      <button className="ff-topnav__profile ff-btn ff-btn--ghost" aria-label={`${user.name} profile settings`} onClick={()=>onNavigate('settings-profile')}>
        <Avatar initials={user.initials} name={user.name} style={{width:30, height:30, fontSize:12}}/>
        <div style={{minWidth:0}}>
          <div className="ff-topnav__profile-name">{user.name}</div>
          <div className="ff-topnav__profile-title">{user.title}</div>
        </div>
      </button>
    </header>
  );
};

/* Refresh button — shared across dashboards/expenses/approvals. Tracks "last synced" locally. */
const RefreshButton = () => {
  const [spinning, setSpinning] = React.useState(false);
  const [synced, setSynced] = React.useState("2m ago");
  const onClick = () => {
    setSpinning(true);
    setTimeout(() => { setSpinning(false); setSynced("just now"); }, 500);
  };
  return (
    <button className="ff-btn ff-btn--ghost" onClick={onClick}>
      <Icon name="arrows-clockwise" size={14} style={{transform: spinning ? 'rotate(360deg)' : 'rotate(0deg)', transition: 'transform 0.5s var(--ff-ease)'}}/>
      Last synced {synced}
    </button>
  );
};

/* Density toggle — shared. Parent owns the boolean, this is just the button. */
const DensityToggle = ({ compact, onToggle }) => (
  <button className="ff-btn ff-btn--ghost" onClick={onToggle} aria-pressed={compact}>
    <Icon name={compact ? "rows" : "list"} size={14}/> Density: {compact ? "Compact" : "Comfortable"}
  </button>
);

/* PageHead — title + actions */
const PageHead = ({ eyebrow, title, sub, actions, children }) => (
  <div className="ff-page__head">
    <div>
      {eyebrow && <div className="ff-eyebrow" style={{marginBottom:8}}>{eyebrow}</div>}
      <h1 className="ff-page__title">{title}</h1>
      {sub && <div className="ff-page__sub">{sub}</div>}
      {children}
    </div>
    <div className="ff-row" style={{gap:8}}>{actions}</div>
  </div>
);

/* KPI tile */
const KpiTile = ({ label, value, delta, trend, spark, hero = false }) => (
  <div className={hero ? "ff-kpi ff-kpi--hero" : "ff-kpi"}>
    <div className="ff-kpi__label">{label}</div>
    <div className="ff-kpi__value" style={hero ? {fontSize:40} : undefined}>{value}</div>
    <div className="ff-row" style={{justifyContent:'space-between'}}>
      <div className={`ff-kpi__delta ff-kpi__delta--${trend === "up" ? "up" : trend === "down" ? "down" : ""}`}>
        {trend === "up" && <Icon name="trend-up" size={12}/>}
        {trend === "down" && <Icon name="trend-down" size={12}/>}
        {delta}
      </div>
      {spark && <Sparkline data={spark} width={80} height={28}/>}
    </div>
  </div>
);

/* Inline stat item/row — label/value/delta, no card. Shared by every screen
   that needs a compact stat strip instead of a KPI-card grid (dashboards,
   reports, vendor/reimbursement detail). Consolidates what had drifted into
   five separately hand-rolled copies (20/22/26px values, 28/32px gaps) into
   one definition; delta reuses the same .ff-kpi__delta tokens KpiTile and
   badges already use, instead of each call site picking its own color. */
const StatItem = ({ label, value, delta, trend }) => (
  <div>
    <div className="ff-eyebrow">{label}</div>
    <div className="ff-row" style={{gap:8, marginTop:3}}>
      <span style={{fontSize:22, fontWeight:600, letterSpacing:'-0.015em'}} className="ff-tnum">{value}</span>
      {delta && <span className={`ff-kpi__delta ff-kpi__delta--${trend === "up" ? "up" : trend === "down" ? "down" : ""}`} style={{fontSize:12}}>{delta}</span>}
    </div>
  </div>
);
const StatRow = ({ items, style = {} }) => (
  <div className="ff-row" style={{gap:32, flexWrap:'wrap', ...style}}>
    {items.map((it, i) => <StatItem key={i} {...it}/>)}
  </div>
);

const Card = ({ title, action, children, padded = true, style = {} }) => (
  <section className="ff-card" style={style}>
    {(title || action) && (
      <header className="ff-card__head">
        <div className="ff-card__title">{title}</div>
        {action}
      </header>
    )}
    <div style={{padding: padded ? 20 : 0, overflowX: 'auto'}}>{children}</div>
  </section>
);

/* Category tag — a colored dot + text, for a category column that isn't a
   status (so it shouldn't pull StatusBadge's visual weight). Color comes
   from the category's own `color` field in FF_DATA (already the same
   --ff-chart-N token category-breakdown charts use for that category), not
   a separately hand-picked hue — "Software" is the same color as a dot here,
   a bar in a chart, or a dashboard legend swatch. Shared so every table with
   a category column (Vendors, Expenses) renders it identically. */
const CategoryTag = ({ color, name }) => (
  <span className="ff-row" style={{gap:7}}>
    <span style={{width:7, height:7, borderRadius:999, background:color, flexShrink:0}}/>
    {name}
  </span>
);

/* Empty state — shared so every list screen (Vendors, Reimbursements,
   Approval history, Audit log, Cards) renders the same thing when its data
   is empty, instead of a bare table header over nothing. Same visual
   language as the dedicated empty-state gallery screen, just without
   forcing a bordered Card around it, so it sits on the page like the
   borderless tables it replaces. */
const EmptyState = ({ icon, title, body, actions }) => (
  <div style={{display:'flex', alignItems:'center', justifyContent:'center', minHeight:'40vh'}}>
    <div className="ff-empty" style={{maxWidth:420}}>
      <div className="ff-empty__icon"><Icon name={icon} size={24}/></div>
      <div className="ff-empty__title">{title}</div>
      <div className="ff-empty__body">{body}</div>
      {actions && <div className="ff-row" style={{marginTop:12, gap:8, justifyContent:'center'}}>{actions}</div>}
    </div>
  </div>
);

/* Shared interaction language for validation, saves, and destructive actions. */
const ActionFeedback = ({ message }) => message ? (
  <div role="status" className="ff-alert ff-alert--info" style={{marginBottom:16}}>{message}</div>
) : null;
const FormSummary = ({ errors, title = "Check this form" }) => {
  const entries = Object.entries(errors || {}).filter(([, value]) => value);
  if (!entries.length) return null;
  return <div className="ff-alert ff-alert--error" role="alert" style={{marginBottom:16}}><div><strong>{title}</strong><ul>{entries.map(([key, value]) => <li key={key}>{value}</li>)}</ul></div></div>;
};
const FieldError = ({ error }) => error ? <div role="alert" style={{fontSize:12,color:'var(--ff-rejected)',marginTop:4}}>{error}</div> : null;
const ConfirmDialog = ({ title, body, onConfirm, onCancel }) => {
  const dialog = React.useRef(null);
  React.useEffect(()=>{const previous=document.activeElement;dialog.current?.querySelector('button')?.focus();return ()=>previous?.isConnected&&previous.focus();},[]);
  const keys=e=>{if(e.key==='Escape'){e.preventDefault();onCancel();}if(e.key==='Tab'){const buttons=dialog.current.querySelectorAll('button');const first=buttons[0],last=buttons[buttons.length-1];if(e.shiftKey&&document.activeElement===first){e.preventDefault();last.focus();}else if(!e.shiftKey&&document.activeElement===last){e.preventDefault();first.focus();}}};
  return (
  <div className="ff-modal-backdrop" role="presentation" onClick={onCancel}>
    <div ref={dialog} onKeyDown={keys} className="ff-modal" role="dialog" aria-modal="true" aria-labelledby="ff-confirm-title" onClick={e=>e.stopPropagation()}>
      <div className="ff-modal__head"><div id="ff-confirm-title" className="ff-modal__title">{title}</div><div className="ff-modal__sub">{body}</div></div>
      <div className="ff-modal__foot"><button className="ff-btn" onClick={onCancel}>Keep it</button><button className="ff-btn ff-btn--danger" onClick={onConfirm}>Confirm</button></div>
    </div>
  </div>
);};

/* Filter chip row */
const ChipBar = ({ items, value, onChange }) => (
  <div className="ff-row" style={{flexWrap:'wrap'}}>
    {items.map(it => (
      <button key={it.id} className="ff-chip" aria-pressed={value === it.id} onClick={() => onChange(it.id)}>
        {it.label}{it.count !== undefined && <span style={{color:'var(--ff-fg-muted)'}}>· {it.count}</span>}
      </button>
    ))}
  </div>
);

Object.assign(window, { Icon, BrandIcon, Money, fmtDate, StatusBadge, Avatar, TopNav, PageHead, KpiTile, StatItem, StatRow, Card, CategoryTag, EmptyState, ActionFeedback, FormSummary, FieldError, ConfirmDialog, ChipBar, RefreshButton, DensityToggle, ffGo, ffRowKeyDown, ffPendingCount, ffGreeting, ffPercentShares });
