// Affiliations & appointments — three-column logo wall with click-modal detail.
// APPOINTED (courts & tribunals) · AFFILIATED (panels & roles) · PUBLISHED (outlets).

const AFFILIATIONS_BY_COL = {
  appointed: [
    {
      id: 'ca-2367', wm: 'U.S. Court of Appeals', sub: '2ND · 3RD · 7TH CIRCUITS', icon: 'fed-eagle', color: '#1F2D44',
      desc: 'Daniel has appeared before and been appointed by the United States Courts of Appeals for the Second, Third, and Seventh Circuits in matters involving software, electronic discovery, and forensic evidence at the appellate level.',
    },
    {
      id: 'wdpa', wm: 'U.S.D.C. W.D. Pa.', sub: 'eDISCOVERY SPECIAL MASTER', icon: 'fed-court', color: '#1F2D44',
      desc: 'Court-designated eDiscovery Special Master for the United States District Court for the Western District of Pennsylvania, authoring ESI protocols and resolving discovery disputes in real time.',
    },
    {
      id: 'sdny', wm: 'U.S.D.C. S.D.N.Y.', sub: 'FORENSIC NEUTRAL · S/M', icon: 'fed-court', color: '#1F2D44',
      desc: 'Forensic neutral and special master appointments in matters before the United States District Court for the Southern District of New York, including classified-data redaction and complex commercial discovery.',
    },
    {
      id: 'lasc', wm: 'L.A. Superior Court', sub: 'DISCOVERY REFEREE', icon: 'ca-bear', color: '#9F4E22',
      desc: 'Discovery Referee on dozens of matters in the Los Angeles County Superior Court — technical IP, trade secret, and complex commercial disputes. Authoring discovery rulings and protocol orders.',
    },
    {
      id: 'nyssc', wm: 'N.Y. Supreme Court', sub: 'APPEARED · APPOINTED', icon: 'ny-state', color: '#0E2A4F',
      desc: 'Appeared and been appointed in the New York Supreme Court (the trial-level court) in technically complex commercial matters, including matrimonial estate disputes with substantial digital-asset components.',
    },
    {
      id: 'desc', wm: 'Delaware Supreme Court', sub: 'APPEARED · APPOINTED', icon: 'de-state', color: '#0F4D8A',
      desc: 'Appeared in the Delaware Supreme Court — including in Genger v. T.R. Investors LLC, the seminal Delaware case on spoliation of electronically stored information.',
    },
    {
      id: 'lcia', wm: 'L.C.I.A.', sub: 'LONDON COURT OF INTL. ARBITRATION', icon: 'lcia', color: '#7B1F2B',
      desc: 'Member of the London Court of International Arbitration. Sole arbitrator and panelist on cross-border technology disputes seated in London — software licensing, cyber coverage, and SaaS service-level disputes.',
      link: 'https://www.lcia.org',
    },
    {
      id: 'hkiac', wm: 'H.K.I.A.C.', sub: 'HONG KONG INTL. ARBITRATION', icon: 'hkiac', color: '#0F2D55',
      desc: 'Arbitrator with the Hong Kong International Arbitration Centre. Cross-border technology and IP disputes seated in Asia, including matters involving multi-jurisdictional choice of law.',
      link: 'https://www.hkiac.org',
    },
  ],
  affiliated: [
    {
      id: 'lf', wm: 'Law & Forensics', sub: 'FOUNDER · MANAGING PARTNER', icon: 'lf-mark', color: '#0A1424',
      desc: 'Founder and Executive Managing Partner of Law & Forensics LLC — a global cybersecurity, eDiscovery, and digital forensics consulting firm. The firm\u2019s technical bench supports Daniel\u2019s neutral practice where matters require it; the neutral practice is independent of party representation.',
      link: 'https://www.lawandforensics.com',
    },
    {
      id: 'harvard', wm: 'Harvard', sub: 'EXTENSION SCHOOL · ADJUNCT', icon: 'harvard-shield', color: '#A41034',
      desc: 'Adjunct faculty at Harvard Extension School (2020–present). Teaches Cybersecurity Law, Computer Forensics, Cryptocurrency & Smart Contracts, Information Systems Forensics, and the Ethics of Cybersecurity.',
      link: 'https://extension.harvard.edu',
    },
    {
      id: 'fjc', wm: 'Federal Judicial Center', sub: 'AUTHOR · GUIDE FOR JUDGES', icon: 'fjc', color: '#1F2D44',
      desc: 'Author of "Understanding Software, the Internet, Mobile Computing, and the Cloud: A Guide for Judges" (2015) — commissioned by the FJC and distributed to the federal judiciary as a foundational reference on technology in litigation.',
      link: 'https://www.fjc.gov',
    },
    {
      id: 'sedona', wm: 'Sedona Conference', sub: 'WORKING GROUPS 1 & 6', icon: 'sedona', color: '#A6432B',
      desc: 'Member of Sedona Conference Working Group 1 (Electronic Document Retention and Production) and Working Group 6 (International Electronic Information Management, Discovery and Disclosure), 2004–2021. Contributor to influential commentaries on eDiscovery practice.',
      link: 'https://thesedonaconference.org',
    },
    {
      id: 'cpr', wm: 'CPR Institute', sub: 'DISTINGUISHED NEUTRAL', icon: 'cpr', color: '#1B5E7A',
      desc: 'Distinguished Neutral with the International Institute for Conflict Prevention & Resolution. Panel arbitrator and mediator for complex commercial disputes including technology and trade-secret matters.',
      link: 'https://www.cpradr.org',
    },
    {
      id: 'acan', wm: 'ACAN / ACAM', sub: 'FELLOW · DISTINGUISHED NEUTRAL', icon: 'acan', color: '#1F2D44',
      desc: 'Fellow of the Academy of Court Appointed Neutrals; Distinguished Neutral with the Academy of Court Appointed Masters. Both organizations credential and convene the leading court-appointed special masters and neutrals nationwide.',
    },
    {
      id: 'scotus', wm: 'U.S. Supreme Court Bar', sub: 'ADMITTED · 2022', icon: 'scotus', color: '#1F2D44',
      desc: 'Admitted to the bar of the Supreme Court of the United States in 2022. Eligible to argue and file before the highest court.',
      link: 'https://www.supremecourt.gov',
    },
    {
      id: 'forbes', wm: 'Forbes Tech Council', sub: 'MEMBER · 2019\u2013present', icon: 'forbes', color: '#0F1B2D',
      desc: 'Member of the Forbes Technology Council since 2019. Regular contributor on cybersecurity, AI, ransomware, and digital forensics — addressing the C-suite audience on emerging technology risk.',
      link: 'https://councils.forbes.com/forbestechcouncil',
    },
  ],
  published: [
    {
      id: 'aba', wm: 'American Bar Association', sub: 'LAW FIRM CYBERSECURITY \u00b7 BOOK', icon: 'aba', color: '#003F87',
      desc: 'Co-author of "Law Firm Cybersecurity" (American Bar Association, 2017) with Bill Spernow — the standard treatise on cybersecurity obligations for law firms.',
      link: 'https://www.americanbar.org',
    },
    {
      id: 'wk', wm: 'Wolters Kluwer', sub: 'CYBERSECURITY & THE COURTHOUSE', icon: 'wk', color: '#003366',
      desc: 'Co-author of "Cybersecurity & the Courthouse: Safeguarding the Judicial Process" (Wolters Kluwer, 2019) with Hon. L. Gordon — examines how courts must defend the integrity of judicial systems against cyber compromise.',
      link: 'https://www.wolterskluwer.com',
    },
    {
      id: 'tr', wm: 'Thomson Reuters', sub: 'TREATISES \u00b7 4 EDITIONS', icon: 'tr', color: '#FA6400',
      desc: 'Author/co-author of "Plugged In: Guidebook to Software and the Law" (4 editions, 2015–2020), "Software and the Law: Digital Forensic Investigations and E-Discovery," the multi-volume "Treatise on Electronic Discovery and Dispute Resolution," and "Cyberwarfare: Understanding the Law, Policy, and Technology."',
      link: 'https://legal.thomsonreuters.com',
    },
    {
      id: 'jlcw', wm: 'Journal of Law & Cyber Warfare', sub: 'EDITOR-IN-CHIEF', icon: 'jlcw', color: '#1F2D44',
      desc: 'Editor-in-Chief of the Journal of Law & Cyber Warfare since 2012. Founded the journal as the leading peer-reviewed venue for cyber-warfare law scholarship.',
      link: 'http://www.jlcw.org',
    },
    {
      id: 'harvard-nsj', wm: 'Harvard National Security Journal', sub: 'PEER REVIEW \u00b7 2 ARTICLES', icon: 'hnsj', color: '#A41034',
      desc: 'Author of two peer-reviewed articles in the Harvard National Security Journal on state-sponsored cyber attacks and the limited options available to corporations responding under existing international law.',
      link: 'https://harvardnsj.org',
    },
    {
      id: 'lawrev', wm: 'Cardozo · Brooklyn · Hastings', sub: 'LAW REVIEW ARTICLES', icon: 'lawreviews', color: '#3E5F7A',
      desc: 'Law-review articles in Cardozo Journal of Conflict Resolution, Brooklyn Journal of International Law, Hastings Business Law Journal, John Marshall Journal of Computer & Information Law, Northwestern Journal of Technology & Intellectual Property, and other top legal journals.',
    },
    {
      id: 'bloomberg', wm: 'Bloomberg Law', sub: 'CONTRIBUTOR \u00b7 2014\u2013present', icon: 'bloomberg', color: '#000000',
      desc: 'Contributing author since 2014. Coverage spans board-level cybersecurity oversight, SEC cyber regulations, FRCP proportionality, cloud eDiscovery, the EU AI Act, and emerging directors\u2019 personal liability under the new SEC rules.',
      link: 'https://news.bloomberglaw.com',
    },
    {
      id: 'dj', wm: 'Daily Journal · Law360 · Law.com', sub: 'TRADE PRESS \u00b7 100+ PIECES', icon: 'trade', color: '#0E2A4F',
      desc: '100+ trade-press pieces in the leading legal industry publications: LA Daily Journal, Law360, Law.com, American Lawyer, LegalTech News, ALM Cyber, Corporate Counsel, and the Recorder. Topics span deepfakes, smart-contract arbitration, special-master practice, AI in eDiscovery, and cyber-insurance mediation.',
    },
  ],
};

// =============================================================================
// PER-ORG MARKS — bespoke SVG monograms tinted with each organization's
// signature color. These read as logo tiles without copying real marks.
// =============================================================================

const orgMark = (id, color) => {
  const C = color;
  switch (id) {
    case 'fed-eagle': // US Court of Appeals — eagle silhouette + columns
      return (
        <svg viewBox="0 0 48 48" width="40" height="40" aria-hidden="true">
          <circle cx="24" cy="24" r="22" fill="none" stroke={C} strokeWidth="1"/>
          <path d="M 24 10 L 28 18 L 36 18 L 30 23 L 32 31 L 24 26 L 16 31 L 18 23 L 12 18 L 20 18 Z" fill={C}/>
          <line x1="14" y1="36" x2="34" y2="36" stroke={C} strokeWidth="1.2"/>
        </svg>
      );
    case 'fed-court': // US District Court — pillar + scales
      return (
        <svg viewBox="0 0 48 48" width="40" height="40" aria-hidden="true">
          <rect x="3" y="3" width="42" height="42" fill="none" stroke={C} strokeWidth="0.8"/>
          <line x1="24" y1="10" x2="24" y2="38" stroke={C} strokeWidth="1.2"/>
          <line x1="14" y1="14" x2="34" y2="14" stroke={C} strokeWidth="1"/>
          <ellipse cx="14" cy="22" rx="5" ry="2" fill="none" stroke={C} strokeWidth="0.8"/>
          <ellipse cx="34" cy="22" rx="5" ry="2" fill="none" stroke={C} strokeWidth="0.8"/>
          <line x1="14" y1="14" x2="14" y2="22" stroke={C} strokeWidth="0.8"/>
          <line x1="34" y1="14" x2="34" y2="22" stroke={C} strokeWidth="0.8"/>
          <rect x="20" y="36" width="8" height="2" fill={C}/>
        </svg>
      );
    case 'ca-bear': // L.A. Superior Court — California-bear-style profile
      return (
        <svg viewBox="0 0 48 48" width="40" height="40" aria-hidden="true">
          <circle cx="24" cy="24" r="22" fill="none" stroke={C} strokeWidth="0.9"/>
          <path d="M 12 28 L 14 26 L 17 26 L 18 23 Q 20 20 24 20 Q 30 20 33 24 Q 36 26 36 28 L 30 28 Q 30 30 28 30 L 22 30 Q 20 30 20 28 Z" fill={C}/>
          <circle cx="32" cy="24" r="0.8" fill="var(--paper)"/>
          <text x="24" y="40" textAnchor="middle" fontFamily="Georgia, serif" fontSize="6" fill={C} letterSpacing="0.2em">CALIFORNIA</text>
        </svg>
      );
    case 'ny-state': // NY Supreme Court — torch + crown motif
      return (
        <svg viewBox="0 0 48 48" width="40" height="40" aria-hidden="true">
          <rect x="3" y="3" width="42" height="42" fill="none" stroke={C} strokeWidth="0.8"/>
          <path d="M 24 10 L 24 18" stroke={C} strokeWidth="1"/>
          <path d="M 18 18 L 30 18 L 28 16 L 26 18 L 24 14 L 22 18 L 20 16 Z" fill={C}/>
          <rect x="22" y="22" width="4" height="14" fill={C}/>
          <text x="24" y="44" textAnchor="middle" fontFamily="Georgia, serif" fontSize="6" fill={C} letterSpacing="0.18em">EXCELSIOR</text>
        </svg>
      );
    case 'de-state': // Delaware — diamond + state silhouette
      return (
        <svg viewBox="0 0 48 48" width="40" height="40" aria-hidden="true">
          <rect x="3" y="3" width="42" height="42" fill="none" stroke={C} strokeWidth="0.8"/>
          <path d="M 24 10 L 32 24 L 24 38 L 16 24 Z" fill="none" stroke={C} strokeWidth="1.2"/>
          <text x="24" y="27" textAnchor="middle" fontFamily="Georgia, serif" fontSize="11" fill={C} fontWeight="700">DE</text>
        </svg>
      );
    case 'lcia': // London Court of International Arbitration — serif LCIA on shield
      return (
        <svg viewBox="0 0 48 48" width="40" height="40" aria-hidden="true">
          <path d="M 24 4 L 42 10 L 42 26 Q 42 38 24 44 Q 6 38 6 26 L 6 10 Z" fill="none" stroke={C} strokeWidth="1"/>
          <text x="24" y="28" textAnchor="middle" fontFamily="Georgia, serif" fontSize="11" fontWeight="500" fill={C} letterSpacing="0.06em">LCIA</text>
        </svg>
      );
    case 'hkiac': // HKIAC — minimalist HK lockup
      return (
        <svg viewBox="0 0 48 48" width="40" height="40" aria-hidden="true">
          <rect x="3" y="3" width="42" height="42" fill="none" stroke={C} strokeWidth="0.8"/>
          <text x="14" y="30" textAnchor="middle" fontFamily="Georgia, serif" fontSize="20" fontWeight="700" fill={C}>H</text>
          <text x="34" y="30" textAnchor="middle" fontFamily="Georgia, serif" fontSize="20" fontWeight="700" fill={C}>K</text>
          <line x1="22" y1="34" x2="26" y2="34" stroke={C} strokeWidth="2"/>
        </svg>
      );
    case 'lf-mark': // Law & Forensics — magnifier on shield
      return (
        <svg viewBox="0 0 48 48" width="40" height="40" aria-hidden="true">
          <path d="M 24 4 L 42 10 L 42 26 Q 42 38 24 44 Q 6 38 6 26 L 6 10 Z" fill="none" stroke={C} strokeWidth="1"/>
          <circle cx="22" cy="22" r="6" fill="none" stroke={C} strokeWidth="1.4"/>
          <line x1="26" y1="26" x2="32" y2="32" stroke={C} strokeWidth="1.4" strokeLinecap="round"/>
        </svg>
      );
    case 'harvard-shield': // Harvard — VE-RI-TAS shield
      return (
        <svg viewBox="0 0 48 48" width="40" height="40" aria-hidden="true">
          <path d="M 24 4 L 42 10 L 42 26 Q 42 38 24 44 Q 6 38 6 26 L 6 10 Z" fill={C}/>
          <text x="14" y="22" textAnchor="middle" fontFamily="Georgia, serif" fontSize="9" fontWeight="700" fill="var(--paper)">VE</text>
          <text x="34" y="22" textAnchor="middle" fontFamily="Georgia, serif" fontSize="9" fontWeight="700" fill="var(--paper)">RI</text>
          <text x="24" y="36" textAnchor="middle" fontFamily="Georgia, serif" fontSize="9" fontWeight="700" fill="var(--paper)">TAS</text>
        </svg>
      );
    case 'fjc': // Federal Judicial Center — federal eagle + book
      return (
        <svg viewBox="0 0 48 48" width="40" height="40" aria-hidden="true">
          <circle cx="24" cy="20" r="14" fill="none" stroke={C} strokeWidth="1"/>
          <path d="M 24 12 L 28 20 L 24 26 L 20 20 Z" fill={C}/>
          <path d="M 10 38 Q 18 36 24 38 Q 30 36 38 38 L 38 42 Q 30 40 24 42 Q 18 40 10 42 Z" fill="none" stroke={C} strokeWidth="0.9"/>
          <line x1="24" y1="38" x2="24" y2="42" stroke={C} strokeWidth="0.7"/>
        </svg>
      );
    case 'sedona': // Sedona — desert spires
      return (
        <svg viewBox="0 0 48 48" width="40" height="40" aria-hidden="true">
          <rect x="2" y="2" width="44" height="44" fill="none" stroke={C} strokeWidth="0.8"/>
          <path d="M 4 38 L 12 18 L 16 26 L 22 12 L 28 26 L 34 18 L 44 38 Z" fill={C}/>
          <line x1="4" y1="38" x2="44" y2="38" stroke={C} strokeWidth="1.2"/>
        </svg>
      );
    case 'cpr': // CPR Institute — interlocked CPR
      return (
        <svg viewBox="0 0 48 48" width="40" height="40" aria-hidden="true">
          <circle cx="24" cy="24" r="20" fill="none" stroke={C} strokeWidth="1"/>
          <text x="24" y="29" textAnchor="middle" fontFamily="Georgia, serif" fontSize="14" fontWeight="600" fill={C} letterSpacing="-0.02em">CPR</text>
        </svg>
      );
    case 'acan': // ACAN / ACAM — laurel wreath enclosing A
      return (
        <svg viewBox="0 0 48 48" width="40" height="40" aria-hidden="true">
          <path d="M 14 14 Q 8 24 14 36" fill="none" stroke={C} strokeWidth="1"/>
          <path d="M 34 14 Q 40 24 34 36" fill="none" stroke={C} strokeWidth="1"/>
          {[18,22,26,30].map(y => (
            <g key={y}>
              <path d={`M 11 ${y} Q 8 ${y+2} 11 ${y+4}`} stroke={C} strokeWidth="0.8" fill="none"/>
              <path d={`M 37 ${y} Q 40 ${y+2} 37 ${y+4}`} stroke={C} strokeWidth="0.8" fill="none"/>
            </g>
          ))}
          <text x="24" y="30" textAnchor="middle" fontFamily="Georgia, serif" fontSize="14" fontWeight="700" fill={C}>A</text>
        </svg>
      );
    case 'scotus': // SCOTUS — column + dome
      return (
        <svg viewBox="0 0 48 48" width="40" height="40" aria-hidden="true">
          <path d="M 12 16 Q 24 6 36 16" fill="none" stroke={C} strokeWidth="1.2"/>
          <line x1="14" y1="16" x2="14" y2="34" stroke={C} strokeWidth="1.2"/>
          <line x1="20" y1="16" x2="20" y2="34" stroke={C} strokeWidth="1.2"/>
          <line x1="28" y1="16" x2="28" y2="34" stroke={C} strokeWidth="1.2"/>
          <line x1="34" y1="16" x2="34" y2="34" stroke={C} strokeWidth="1.2"/>
          <rect x="10" y="34" width="28" height="3" fill={C}/>
          <rect x="8" y="38" width="32" height="3" fill={C}/>
        </svg>
      );
    case 'forbes': // Forbes Tech Council — angular F
      return (
        <svg viewBox="0 0 48 48" width="40" height="40" aria-hidden="true">
          <rect x="3" y="3" width="42" height="42" fill={C}/>
          <path d="M 14 12 L 34 12 L 34 18 L 22 18 L 22 22 L 30 22 L 30 28 L 22 28 L 22 38 L 14 38 Z" fill="var(--paper)"/>
        </svg>
      );
    case 'aba': // American Bar Association — scales + wreath
      return (
        <svg viewBox="0 0 48 48" width="40" height="40" aria-hidden="true">
          <circle cx="24" cy="24" r="20" fill="none" stroke={C} strokeWidth="1"/>
          <line x1="24" y1="14" x2="24" y2="34" stroke={C} strokeWidth="1.2"/>
          <line x1="14" y1="20" x2="34" y2="20" stroke={C} strokeWidth="1"/>
          <ellipse cx="14" cy="26" rx="4" ry="1.5" fill={C}/>
          <ellipse cx="34" cy="26" rx="4" ry="1.5" fill={C}/>
          <line x1="14" y1="20" x2="14" y2="26" stroke={C} strokeWidth="0.7"/>
          <line x1="34" y1="20" x2="34" y2="26" stroke={C} strokeWidth="0.7"/>
        </svg>
      );
    case 'wk': // Wolters Kluwer — overlapped circles
      return (
        <svg viewBox="0 0 48 48" width="40" height="40" aria-hidden="true">
          <circle cx="18" cy="24" r="11" fill={C} fillOpacity="0.85"/>
          <circle cx="30" cy="24" r="11" fill={C} fillOpacity="0.5"/>
        </svg>
      );
    case 'tr': // Thomson Reuters — eight rings simplified
      return (
        <svg viewBox="0 0 48 48" width="40" height="40" aria-hidden="true">
          {[0,1,2,3,4,5,6,7].map(i => {
            const a = (i * 45 - 90) * Math.PI / 180;
            return <circle key={i} cx={24 + 12 * Math.cos(a)} cy={24 + 12 * Math.sin(a)} r="3" fill={C}/>;
          })}
          <circle cx="24" cy="24" r="3" fill="var(--paper-2)" stroke={C} strokeWidth="1"/>
        </svg>
      );
    case 'jlcw': // Journal of Law & Cyber Warfare — quill + binary
      return (
        <svg viewBox="0 0 48 48" width="40" height="40" aria-hidden="true">
          <path d="M 8 40 Q 22 14 40 8 Q 34 26 16 36 Z" fill="none" stroke={C} strokeWidth="1.2"/>
          <line x1="8" y1="40" x2="20" y2="28" stroke={C} strokeWidth="1.2"/>
          <text x="38" y="42" textAnchor="end" fontFamily="JetBrains Mono, monospace" fontSize="6" fill={C}>10110</text>
        </svg>
      );
    case 'hnsj': // Harvard National Security Journal — same Harvard shield, different sub
      return orgMark('harvard-shield', color);
    case 'lawreviews': // Cardozo/Brooklyn/Hastings — three columns
      return (
        <svg viewBox="0 0 48 48" width="40" height="40" aria-hidden="true">
          <line x1="6" y1="10" x2="42" y2="10" stroke={C} strokeWidth="1"/>
          <line x1="6" y1="38" x2="42" y2="38" stroke={C} strokeWidth="1"/>
          <line x1="11" y1="13" x2="11" y2="35" stroke={C} strokeWidth="1.4"/>
          <line x1="24" y1="13" x2="24" y2="35" stroke={C} strokeWidth="1.4"/>
          <line x1="37" y1="13" x2="37" y2="35" stroke={C} strokeWidth="1.4"/>
        </svg>
      );
    case 'bloomberg': // Bloomberg — terminal block with B
      return (
        <svg viewBox="0 0 48 48" width="40" height="40" aria-hidden="true">
          <rect x="3" y="3" width="42" height="42" fill={C}/>
          <text x="24" y="34" textAnchor="middle" fontFamily="Helvetica, Arial, sans-serif" fontSize="22" fontWeight="700" fill="var(--paper)">B</text>
          <line x1="6" y1="42" x2="42" y2="42" stroke="#FA6400" strokeWidth="1.5"/>
        </svg>
      );
    case 'trade': // ALM/Daily Journal/Law360 — newspaper rule + DJ
      return (
        <svg viewBox="0 0 48 48" width="40" height="40" aria-hidden="true">
          <rect x="3" y="3" width="42" height="42" fill="none" stroke={C} strokeWidth="0.8"/>
          <line x1="6" y1="14" x2="42" y2="14" stroke={C} strokeWidth="0.8"/>
          <text x="24" y="32" textAnchor="middle" fontFamily="Georgia, serif" fontSize="16" fontWeight="700" fill={C}>DJ</text>
          {[36, 39, 42].map((y, i) => (
            <line key={i} x1="8" y1={y} x2="40" y2={y} stroke={C} strokeWidth="0.4"/>
          ))}
        </svg>
      );
    default:
      return (
        <svg viewBox="0 0 48 48" width="40" height="40" aria-hidden="true">
          <circle cx="24" cy="24" r="20" fill="none" stroke={C} strokeWidth="1"/>
          <text x="24" y="30" textAnchor="middle" fontFamily="Georgia, serif" fontSize="18" fontWeight="600" fill={C}>·</text>
        </svg>
      );
  }
};

const LogoCard = ({ a, onDark = false, onClick }) => {
  const ink = onDark ? 'var(--paper)' : 'var(--ink)';
  const muted = onDark ? 'var(--slate-300)' : 'var(--slate-700)';
  const bg = onDark ? 'rgba(244,240,230,0.04)' : 'var(--paper)';
  const border = onDark ? 'rgba(212,185,122,0.22)' : 'var(--line-soft)';
  const hover = onDark ? 'var(--gold)' : 'var(--gold-deep)';
  return (
    <button onClick={() => onClick && onClick(a)} style={{
      background: bg, border: `1px solid ${border}`,
      padding: '20px 18px', minHeight: 132,
      display: 'flex', flexDirection: 'column', justifyContent: 'space-between',
      transition: 'all 0.18s', cursor: 'pointer', textAlign: 'left',
      width: '100%', font: 'inherit',
    }}
    onMouseEnter={(e) => { e.currentTarget.style.borderColor = hover; e.currentTarget.style.transform = 'translateY(-1px)'; }}
    onMouseLeave={(e) => { e.currentTarget.style.borderColor = border; e.currentTarget.style.transform = 'none'; }}
    aria-label={`Learn more about ${a.wm}`}
    >
      {orgMark(a.icon, a.color || '#1F2D44')}
      <div style={{ marginTop: 12 }}>
        <div className="serif" style={{
          fontSize: 15, fontWeight: 500, lineHeight: 1.18,
          color: ink, letterSpacing: '-0.01em',
        }}>
          {a.wm}
        </div>
        <div className="mono" style={{
          fontSize: 9, letterSpacing: '0.18em', marginTop: 6,
          color: muted, textTransform: 'uppercase',
        }}>
          {a.sub}
        </div>
      </div>
    </button>
  );
};

const LogoModal = ({ a, onClose }) => {
  const { useEffect } = React;
  useEffect(() => {
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    document.addEventListener('keydown', onKey);
    document.body.style.overflow = 'hidden';
    return () => {
      document.removeEventListener('keydown', onKey);
      document.body.style.overflow = '';
    };
  }, [onClose]);
  if (!a) return null;
  return (
    <div onClick={onClose} style={{
      position: 'fixed', inset: 0, zIndex: 1000,
      background: 'rgba(10,20,36,0.55)',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      padding: 24, animation: 'modal-fade 0.18s ease',
    }}>
      <div onClick={(e) => e.stopPropagation()} style={{
        background: 'var(--paper)', maxWidth: 560, width: '100%',
        border: '1px solid var(--line-soft)',
        boxShadow: '0 24px 64px rgba(10,20,36,0.35)',
        padding: '40px 40px 32px', position: 'relative',
      }}>
        <button onClick={onClose} aria-label="Close" style={{
          position: 'absolute', top: 14, right: 16,
          background: 'transparent', border: 'none', fontSize: 20,
          color: 'var(--slate-700)', cursor: 'pointer', padding: 4, lineHeight: 1,
        }}>×</button>
        <div style={{ display: 'flex', gap: 20, alignItems: 'flex-start', marginBottom: 24 }}>
          <div style={{ flexShrink: 0 }}>{orgMark(a.icon, a.color || '#1F2D44')}</div>
          <div>
            <div className="mono" style={{ fontSize: 10, letterSpacing: '0.2em', color: 'var(--gold-deep)', textTransform: 'uppercase' }}>
              {a.sub}
            </div>
            <h3 className="display" style={{ fontSize: 28, marginTop: 6, lineHeight: 1.1 }}>{a.wm}</h3>
          </div>
        </div>
        <p className="serif" style={{ fontSize: 17, lineHeight: 1.65, color: 'var(--slate-900)' }}>
          {a.desc}
        </p>
        {a.link && (
          <a href={a.link} target="_blank" rel="noopener noreferrer" className="mono" style={{
            display: 'inline-block', marginTop: 24,
            fontSize: 11, letterSpacing: '0.2em', color: 'var(--gold-deep)',
            textTransform: 'uppercase', borderBottom: '1px solid currentColor',
            paddingBottom: 2,
          }}>
            Visit {a.link.replace(/^https?:\/\/(www\.)?/, '').replace(/\/$/, '')} →
          </a>
        )}
      </div>
    </div>
  );
};

const AffiliationsStrip = ({ onDark = false }) => {
  const { useState } = React;
  const [active, setActive] = useState(null);
  const cols = [
    { key: 'appointed',  title: 'Appointed',  sub: 'COURTS & TRIBUNALS',           items: AFFILIATIONS_BY_COL.appointed },
    { key: 'affiliated', title: 'Affiliated', sub: 'PANELS · INSTITUTES · ROLES',   items: AFFILIATIONS_BY_COL.affiliated },
    { key: 'published',  title: 'Published',  sub: 'PUBLISHERS · JOURNALS · TRADE', items: AFFILIATIONS_BY_COL.published },
  ];
  return (
    <section style={{
      background: onDark ? 'var(--ink)' : 'var(--paper-2)',
      borderTop: '1px solid ' + (onDark ? 'rgba(212,185,122,0.18)' : 'var(--line-soft)'),
      borderBottom: '1px solid ' + (onDark ? 'rgba(212,185,122,0.18)' : 'var(--line-soft)'),
      padding: '64px 0',
      color: onDark ? 'var(--paper)' : 'var(--ink)',
    }}>
      <div className="container">
        <div className="aff-cols">
          {cols.map(col => (
            <div key={col.key} className="aff-col">
              <div className="aff-col-head">
                <span className="display aff-col-title" style={{ color: onDark ? 'var(--paper)' : 'var(--ink)' }}>
                  {col.title}
                </span>
                <span className="mono aff-col-sub" style={{ color: onDark ? 'var(--gold)' : 'var(--gold-deep)' }}>
                  {col.sub}
                </span>
              </div>
              <div className="aff-col-grid">
                {col.items.map(a => (
                  <LogoCard key={a.id} a={a} onDark={onDark} onClick={setActive}/>
                ))}
              </div>
            </div>
          ))}
        </div>
        <p className="mono" style={{
          fontSize: 10, letterSpacing: '0.18em', marginTop: 24,
          color: onDark ? 'var(--slate-300)' : 'var(--slate-700)',
          textTransform: 'uppercase',
        }}>
          Click any card for details on Daniel's relationship with that organization.
        </p>
      </div>
      <LogoModal a={active} onClose={() => setActive(null)}/>
    </section>
  );
};

const AffiliationsGrid = () => {
  const { useState } = React;
  const [active, setActive] = useState(null);
  return (
    <>
      <div style={{
        display: 'grid',
        gridTemplateColumns: 'repeat(auto-fill, minmax(220px, 1fr))',
        gap: 16,
      }}>
        {[...AFFILIATIONS_BY_COL.appointed, ...AFFILIATIONS_BY_COL.affiliated, ...AFFILIATIONS_BY_COL.published]
          .map(a => <LogoCard key={a.id} a={a} onClick={setActive}/>)}
      </div>
      <LogoModal a={active} onClose={() => setActive(null)}/>
    </>
  );
};

// Flat list still useful for some pages
const AFFILIATIONS = [
  ...AFFILIATIONS_BY_COL.appointed.map(a => ({ ...a, group: 'court' })),
  ...AFFILIATIONS_BY_COL.affiliated.map(a => ({ ...a, group: 'role' })),
  ...AFFILIATIONS_BY_COL.published.map(a => ({ ...a, group: 'scholarship' })),
];

Object.assign(window, {
  AffiliationsStrip, AffiliationsGrid, AFFILIATIONS,
  AFFILIATIONS_BY_COL, LogoCard, LogoModal, orgMark,
});
