Ctrl K
ComunidadGuías…

mockups/client-reports-dashboard/responsive-dashboard.html

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
<!doctype html>
<html lang="en" data-theme="dark">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>Responsive Client Reports Dashboard</title>
  <style>
    :root{color-scheme:light;--bg:#f6f6f4;--surface:#fff;--subtle:#f0f0ed;--ink:#181817;--support:#545450;--muted:#71716b;--border:#deded9;--strong:#c7c7c0;--accent:#3658d4;--accent-soft:#edf0fc;--success:#167b5b;--warning:#ad6410;--sidebar:220px;--radius:11px;--sans:Inter,ui-sans-serif,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;--mono:"Geist Mono","SFMono-Regular",Consolas,monospace}
    :root[data-theme="dark"]{color-scheme:dark;--bg:#101110;--surface:#171817;--subtle:#1f201e;--ink:#f2f2ef;--support:#c3c3bd;--muted:#979790;--border:#292a27;--strong:#3b3c37;--accent:#7590ff;--accent-soft:#202946;--success:#5bcea2;--warning:#eda957}
    *{box-sizing:border-box}html,body{min-width:320px;min-height:100%;margin:0;background:var(--bg);color:var(--ink);font:14px/1.45 var(--sans)}button,a{font:inherit}button{color:inherit}a{color:inherit;text-decoration:none}button:focus-visible,a:focus-visible{outline:2px solid var(--accent);outline-offset:2px}svg{display:block}.sr-only{position:absolute!important;width:1px!important;height:1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;clip-path:inset(50%)!important}
    .shell{min-height:100vh;padding-left:var(--sidebar)}.sidebar{position:fixed;z-index:40;inset:0 auto 0 0;display:flex;width:var(--sidebar);height:100vh;flex-direction:column;border-right:1px solid var(--border);background:var(--surface);padding:13px 11px}
    .brand,.nav-link,.user,.topbar,.context,.top-actions,.tabs,.heading,.actions,.button,.metric-head,.widget-head,.status-row,.pdf-toolbar,.pdf-actions{display:flex;align-items:center}.brand{min-height:42px;gap:10px;padding:0 6px}.mark{display:grid;width:32px;height:32px;place-items:center;border-radius:8px;background:var(--accent);color:#fff;font-size:10px;font-weight:800}.brand strong,.brand span,.user strong,.user span{display:block}.brand strong{font-size:12px}.brand span,.user span{margin-top:1px;color:var(--muted);font-size:9px}
    .group{margin-top:23px}.group-label{display:block;margin:0 7px 7px;color:var(--muted);font-size:9px;font-weight:750;letter-spacing:.06em;text-transform:uppercase}.nav{display:grid;gap:3px}.nav-link{min-height:38px;gap:10px;border-radius:8px;color:var(--support);font-size:12px;font-weight:620;padding:7px 9px}.nav-link:hover{background:var(--subtle);color:var(--ink)}.nav-link.active{background:var(--accent-soft);color:var(--accent)}.user{gap:9px;margin-top:auto;border-top:1px solid var(--border);padding:14px 6px 2px}.avatar{display:grid;width:30px;height:30px;place-items:center;border-radius:50%;background:var(--accent-soft);color:var(--accent);font-size:9px;font-weight:800}.user strong{font-size:10px}
    .topbar{position:sticky;z-index:30;top:0;min-height:58px;justify-content:space-between;border-bottom:1px solid var(--border);background:var(--surface);padding:0 20px}.context{gap:9px}.context-icon{display:grid;width:28px;height:28px;place-items:center;border:1px solid var(--border);border-radius:7px;background:var(--subtle);color:var(--accent)}.context strong{font-size:12px}.top-actions{gap:7px}.prototype{border:1px solid var(--border);border-radius:999px;background:var(--subtle);color:var(--muted);font-size:8px;font-weight:750;letter-spacing:.06em;padding:4px 8px;text-transform:uppercase}.icon,.button{justify-content:center;border:1px solid var(--border);border-radius:8px;background:var(--surface);cursor:pointer}.icon{display:grid;width:34px;height:34px;place-items:center;padding:0}.icon:hover,.button:hover{border-color:var(--strong);background:var(--subtle)}.menu{display:none}
    .tabs{min-height:46px;gap:24px;border-bottom:1px solid var(--border);background:var(--surface);padding:0 20px}.tab{position:relative;display:grid;min-height:46px;place-items:center;color:var(--muted);font-size:11px;font-weight:650}.tab.active{color:var(--ink)}.tab.active:after{position:absolute;inset:auto 0 -1px;height:2px;background:var(--accent);content:""}
    .workspace{width:100%;padding:20px 22px 26px}.heading{align-items:flex-end;justify-content:space-between;gap:28px}.heading h1{margin:0;font-size:28px;font-weight:730;letter-spacing:-.03em;line-height:1.08}.heading p{max-width:72ch;margin:6px 0 0;color:var(--muted);font-size:12px}.live{display:inline-flex;align-items:center;gap:6px}.live:before{width:5px;height:5px;border-radius:50%;background:var(--success);content:""}.actions{flex:0 0 auto;flex-wrap:wrap;justify-content:flex-end;gap:8px}.button{min-height:36px;gap:7px;padding:7px 11px;font-size:10px;font-weight:700}.button.primary{border-color:var(--ink);background:var(--ink);color:var(--surface)}.reset{display:none}body.editing .reset{display:flex}
    .metrics{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));margin-top:18px;overflow:hidden;border:1px solid var(--border);border-radius:var(--radius);background:var(--surface)}.metric{min-width:0;padding:14px 17px}.metric+.metric{border-left:1px solid var(--border)}.metric-head{justify-content:space-between;color:var(--muted)}.metric-label{font-size:9px;font-weight:760;letter-spacing:.04em;text-transform:uppercase}.metric-value{display:block;margin-top:10px;font-size:clamp(25px,2.2vw,34px);font-weight:735;letter-spacing:-.04em;line-height:1;font-variant-numeric:tabular-nums}.metric-note{display:block;margin-top:6px;color:var(--muted);font-size:9px}.metric-note.warning{color:var(--warning)}.metric-note.success{color:var(--success)}
    .dashboard{display:grid;min-height:calc(100vh - 284px);grid-template-columns:repeat(12,minmax(0,1fr));grid-template-rows:minmax(300px,1fr) minmax(260px,.84fr);gap:12px;margin-top:12px}.widget{position:relative;min-width:0;overflow:hidden;border:1px solid var(--border);border-radius:var(--radius);background:var(--surface)}.status{grid-column:span 5}.budget{grid-column:span 7}.activity{grid-column:span 8}.recent{grid-column:span 4}.widget-head{min-height:58px;align-items:flex-start;justify-content:space-between;gap:16px;border-bottom:1px solid var(--border);padding:12px 15px}.widget-title strong,.widget-title span{display:block}.widget-title strong{font-size:11px}.widget-title span{margin-top:2px;color:var(--muted);font-size:9px}.widget-total{font:650 14px/1 var(--mono)}.widget-body{height:calc(100% - 58px);min-height:0;padding:15px;container-type:size}.widget-body.status-layout,.widget-body.bars,.widget-body.activity-body,.widget-body.recent-list{height:calc(100% - 58px)}
    .status-layout{display:grid;height:100%;grid-template-columns:minmax(220px,1.1fr) minmax(190px,.9fr);align-items:center;gap:clamp(20px,4cqw,56px)}.donut-wrap{position:relative;width:min(100%,calc(100cqh - 10px),320px);margin:auto}.donut{width:100%;transform:rotate(-90deg)}.donut circle{fill:none;stroke-width:8}.donut .track{stroke:var(--subtle)}.donut-center{position:absolute;inset:0;display:grid;place-content:center;text-align:center}.donut-center strong{font-size:clamp(31px,8cqh,48px);letter-spacing:-.04em;line-height:1}.donut-center span{margin-top:5px;color:var(--muted);font-size:10px}.status-list{display:grid;height:min(100%,280px);align-content:stretch}.status-row{min-height:46px;display:grid;grid-template-columns:9px minmax(0,1fr) auto;gap:11px;border-bottom:1px solid var(--border)}.status-row:last-child{border:0}.dot{width:8px;height:8px;border-radius:50%;background:var(--dot)}.status-row span{color:var(--support);font-size:11px}.status-row strong{font:650 11px/1 var(--mono)}
    .bars{display:grid;height:100%;grid-template-rows:repeat(5,minmax(36px,1fr));align-content:stretch;gap:clamp(8px,2.5cqh,20px)}.bar{display:grid;height:100%;grid-template-columns:minmax(138px,.75fr) minmax(190px,2fr) 78px;align-items:center;gap:14px}.bar>span:first-child{overflow:hidden;color:var(--support);font-size:11px;font-weight:600;text-overflow:ellipsis;white-space:nowrap}.bar-track{height:clamp(10px,4cqh,17px);overflow:hidden;border-radius:999px;background:var(--subtle)}.bar-fill{display:block;width:var(--w);height:100%;border-radius:inherit;background:var(--accent)}.bar strong{text-align:right;font:620 11px/1 var(--mono)}
    .activity-body{display:grid;height:100%;grid-template-rows:auto minmax(0,1fr);gap:10px}.activity-summary{display:flex;align-items:baseline;gap:8px}.activity-summary strong{font-size:22px;letter-spacing:-.035em}.activity-summary>span{color:var(--muted);font-size:9px}.activity-summary .activity-change{margin-left:auto;color:var(--accent);font-weight:700}.line-chart{display:grid;min-height:150px;height:100%;grid-template-columns:28px minmax(0,1fr);grid-template-rows:minmax(0,1fr) 22px;margin:0}.line-scale{position:relative;grid-column:1;grid-row:1;color:var(--muted);font:8px/1 var(--mono)}.line-scale span{position:absolute;right:5px;top:var(--y);transform:translateY(-50%)}.activity-plot{position:relative;min-width:0;min-height:0;grid-column:2;grid-row:1;margin-inline:4px}.activity-plot svg{position:absolute;inset:0;width:100%;height:100%;overflow:visible}.line-grid{opacity:.82;stroke:var(--border);stroke-width:1;vector-effect:non-scaling-stroke}.line-area{fill:var(--accent);opacity:.18}.line-path{fill:none;stroke:var(--accent);stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;vector-effect:non-scaling-stroke}.chart-point{position:absolute;z-index:2;top:var(--y);left:var(--x);width:8px;height:8px;transform:translate(-50%,-50%);border:2px solid var(--surface);border-radius:50%;background:var(--accent);box-shadow:0 0 0 1px var(--accent)}.chart-point.latest{width:9px;height:9px}.chart-value{position:absolute;bottom:12px;left:50%;transform:translateX(-50%);color:var(--muted);font:650 8px/1 var(--mono);font-variant-numeric:tabular-nums}.chart-point.latest .chart-value{color:var(--accent);font-weight:750}.line-axis{position:relative;grid-column:2;grid-row:2;margin-inline:4px;color:var(--muted);font:9px/1 var(--mono)}.line-axis span{position:absolute;top:0;left:var(--x);transform:translateX(-50%)}.line-axis .first{transform:none}.line-axis .last{transform:translateX(-100%)}
    .recent-list{display:grid;height:100%}.recent-row{display:grid;min-height:25%;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:12px;border-bottom:1px solid var(--border);padding:8px 0}.recent-row:last-child{border:0}.recent-copy strong,.recent-copy span{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.recent-copy strong{font-size:11px;line-height:1.25}.recent-copy span{margin-top:3px;color:var(--muted);font-size:9px}.badge{border-radius:999px;background:var(--soft);color:var(--color);font-size:9px;font-weight:700;padding:4px 7px}
    .handle{position:absolute;z-index:3;display:none;width:27px;height:27px;place-items:center;border:1px solid var(--accent);border-radius:7px;background:var(--surface);color:var(--accent)}.handle.move{top:7px;right:7px}.handle.resize{right:7px;bottom:7px}body.editing .dashboard{outline:1px dashed var(--strong);outline-offset:6px}body.editing .widget{border-color:var(--accent)}body.editing .handle{display:grid}
    .motion-ready .widget{animation:widget-resolve 420ms cubic-bezier(.16,1,.3,1) both;animation-delay:calc(var(--load-order)*55ms)}.dashboard>.widget:nth-child(1){--load-order:0}.dashboard>.widget:nth-child(2){--load-order:1}.dashboard>.widget:nth-child(3){--load-order:2}.dashboard>.widget:nth-child(4){--load-order:3}.motion-ready .activity .line-path{stroke-dasharray:var(--line-length,1000) var(--line-length,1000);stroke-dashoffset:var(--line-length,1000);animation:chart-trace 430ms cubic-bezier(.16,1,.3,1) 380ms both}.motion-ready .activity .line-area{animation:chart-area 430ms cubic-bezier(.16,1,.3,1) 380ms both}.motion-ready .activity .chart-point{animation:chart-points 120ms ease-out 810ms both}@keyframes widget-resolve{0%{opacity:.58;clip-path:inset(0 0 78% 0 round var(--radius));filter:blur(1px)}45%{opacity:1;filter:blur(0)}100%{opacity:1;clip-path:inset(0 0 0 0 round var(--radius));filter:blur(0)}}@keyframes chart-trace{to{stroke-dashoffset:0}}@keyframes chart-area{from{clip-path:inset(0 100% 0 0)}to{clip-path:inset(0 0 0 0)}}@keyframes chart-points{from{opacity:0}to{opacity:1}}
    .pdf-modal{position:fixed;z-index:100;inset:0;display:none;overflow:auto;background:rgb(0 0 0/.72);padding:20px}body.pdf-open{overflow:hidden}body.pdf-open .pdf-modal{display:block}.pdf-shell{width:min(100%,900px);margin:auto}.pdf-toolbar{position:sticky;z-index:4;top:0;justify-content:space-between;gap:20px;margin-bottom:12px;border:1px solid #34363b;border-radius:10px;background:#17191d;color:#f4f4f2;padding:10px 12px}.pdf-toolbar strong,.pdf-toolbar span{display:block}.pdf-toolbar strong{font-size:12px}.pdf-toolbar span{color:#aaa;font-size:9px}.pdf-actions{gap:7px}.pdf-page{width:816px;min-height:1056px;margin:auto;background:#fff;color:#191918;box-shadow:0 24px 70px rgb(0 0 0/.32);padding:42px}.pdf-head{display:flex;align-items:flex-end;justify-content:space-between;border-bottom:1px solid #d9d9d4;padding-bottom:18px}.pdf-head p{margin:0 0 5px;color:#6b6b66;font-size:9px;font-weight:750;letter-spacing:.06em;text-transform:uppercase}.pdf-head h2{margin:0;font-size:25px}.pdf-head time{color:#6b6b66;font-size:9px}.pdf-metrics{display:grid;grid-template-columns:repeat(4,1fr);margin-top:20px;border:1px solid #deded9;border-radius:8px}.pdf-metric{padding:12px}.pdf-metric+.pdf-metric{border-left:1px solid #deded9}.pdf-metric span{display:block;color:#6b6b66;font-size:8px;font-weight:700;text-transform:uppercase}.pdf-metric strong{display:block;margin-top:8px;font-size:20px}.pdf-grid{display:grid;grid-template-columns:1fr 1.45fr;gap:12px;margin-top:12px}.pdf-card{border:1px solid #deded9;border-radius:8px;padding:14px}.pdf-card h3{margin:0;font-size:11px}.pdf-card p{margin:3px 0 0;color:#6b6b66;font-size:8px}.pdf-card.wide{grid-column:1/-1}.pdf-status{display:grid;grid-template-columns:100px 1fr;align-items:center;gap:14px;margin-top:12px}.pdf-donut{width:100px}.pdf-legend{display:grid;gap:5px}.pdf-legend div{display:flex;justify-content:space-between;border-bottom:1px solid #e6e6e2;font-size:8px;padding-bottom:4px}.pdf-bars{display:grid;gap:8px;margin-top:14px}.pdf-bar{display:grid;grid-template-columns:74px 1fr 40px;align-items:center;gap:7px;font-size:8px}.pdf-track{height:6px;border-radius:99px;background:#eeeeeb}.pdf-fill{display:block;width:var(--w);height:100%;border-radius:inherit;background:#3658d4}.pdf-line{width:100%;height:190px;margin-top:10px}.pdf-line .grid{stroke:#deded9}.pdf-line .area{fill:#3658d4;opacity:.14}.pdf-line .path{fill:none;stroke:#3658d4;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter}.pdf-line .point{fill:#fff;stroke:#3658d4;stroke-width:2}.pdf-line .value{fill:#3658d4;font-weight:700}.pdf-line text{fill:#6b6b66;font:8px var(--mono)}.pdf-footer{display:flex;justify-content:space-between;margin-top:18px;border-top:1px solid #deded9;color:#6b6b66;font-size:8px;padding-top:10px}
    .backdrop{display:none}
    @media(max-width:1100px){.status,.budget,.activity,.recent{grid-column:span 6}.dashboard{grid-template-rows:auto}.widget-body{min-height:280px}.status-layout{grid-template-columns:1fr}.donut-wrap{width:min(100%,260px)}}
    @media(max-width:820px){.shell{padding-left:0}.sidebar{width:min(278px,calc(100vw - 40px));transform:translateX(-100%)}body.menu-open .sidebar{transform:none}.menu{display:grid}.backdrop{position:fixed;z-index:35;inset:0;border:0;background:rgb(0 0 0/.45)}body.menu-open .backdrop{display:block}.workspace{padding:18px 16px 28px}.heading{align-items:flex-start;flex-direction:column;gap:16px}.actions{justify-content:flex-start}.metrics{grid-template-columns:repeat(2,1fr)}.metric:nth-child(3){border-left:0}.metric:nth-child(n+3){border-top:1px solid var(--border)}.status,.budget,.activity,.recent{grid-column:1/-1}.widget-body.status-layout{height:auto;min-height:510px}.status-layout{grid-template-columns:1fr;grid-template-rows:auto auto}.status-list{height:auto}.bar{grid-template-columns:minmax(96px,.75fr) minmax(100px,1.5fr) 60px;gap:8px}.line-chart{min-height:220px}}
    @media(max-width:470px){.topbar,.tabs{padding-inline:14px}.prototype{display:none}.actions{display:grid;width:100%;grid-template-columns:1fr}.actions .button{width:100%}body.editing .actions{grid-template-columns:1fr 1fr}.actions .primary{grid-column:1/-1}.bar{grid-template-columns:92px 1fr 54px}.pdf-modal{padding:0}.pdf-toolbar{border-radius:0}}
    @media(prefers-reduced-motion:reduce){.motion-ready .widget,.motion-ready .activity .line-path,.motion-ready .activity .line-area,.motion-ready .activity .chart-point{animation:none!important}}
    @media print{@page{size:letter;margin:.35in}body *{visibility:hidden!important}.pdf-modal,.pdf-modal *{visibility:visible!important}.pdf-modal{position:absolute!important;inset:0!important;display:block!important;overflow:visible!important;background:#fff!important;padding:0!important}.pdf-toolbar{display:none!important}.pdf-shell{width:auto!important;margin:0!important}.pdf-page{width:7.8in!important;min-height:10.3in!important;margin:0!important;box-shadow:none!important;padding:.24in!important;print-color-adjust:exact;-webkit-print-color-adjust:exact}}
  </style>
</head>
<body>
  <div class="shell">
    <aside class="sidebar" aria-label="Client portal navigation">
      <a class="brand" href="#"><span class="mark">TW</span><span><strong>Twenty Portal</strong><span>Client workspace</span></span></a>
      <nav><section class="group"><span class="group-label">Workspace</span><div class="nav"><a class="nav-link" href="#">⌂ Home</a></div></section><section class="group"><span class="group-label">Shared views</span><div class="nav"><a class="nav-link active" href="#">▣ Projects</a><a class="nav-link" href="#">□ Invoices</a></div></section><section class="group"><span class="group-label">Account</span><div class="nav"><a class="nav-link" href="#">⚙ Settings</a></div></section></nav>
      <div class="user"><span class="avatar">AV</span><span><strong>Alex Vaughan</strong><span>Client contributor</span></span></div>
    </aside>
    <button class="backdrop" type="button" data-action="close-menu" aria-label="Close navigation"></button>
    <main>
      <header class="topbar"><div class="context"><button class="icon menu" type="button" data-action="menu" aria-label="Open navigation">☰</button><span class="context-icon">▣</span><strong>Projects</strong></div><div class="top-actions"><span class="prototype">Responsive charts · demo data</span><button class="icon" type="button" data-action="theme" aria-label="Switch theme">◐</button><span class="avatar">AV</span></div></header>
      <nav class="tabs"><a class="tab" href="#">Records</a><a class="tab active" href="#">Reports</a></nav>
      <div class="workspace">
        <section class="heading"><div><h1>Project overview</h1><p>A current summary of the 24 projects shared with your organization. <span class="live">Updated just now</span></p></div><div class="actions"><button class="button" type="button" data-action="edit">☷ <span>Edit layout</span></button><button class="button reset" type="button">↶ Reset layout</button><button class="button primary" type="button" data-action="export">↓ Export PDF</button></div></section>
        <section class="metrics"><article class="metric"><div class="metric-head"><span class="metric-label">Active projects</span><span>▣</span></div><strong class="metric-value">24</strong><span class="metric-note">Count of scoped records</span></article><article class="metric"><div class="metric-head"><span class="metric-label">Total budget</span><span>$</span></div><strong class="metric-value">$838,250</strong><span class="metric-note">Sum across shared projects</span></article><article class="metric"><div class="metric-head"><span class="metric-label">At risk</span><span>△</span></div><strong class="metric-value">5</strong><span class="metric-note warning">Needs attention</span></article><article class="metric"><div class="metric-head"><span class="metric-label">Complete</span><span>✓</span></div><strong class="metric-value">4</strong><span class="metric-note success">Current portfolio</span></article></section>
        <section class="dashboard">
          <article class="widget status"><button class="handle move" aria-label="Move Portfolio status">⠿</button><button class="handle resize" aria-label="Resize Portfolio status">↗</button><header class="widget-head"><span class="widget-title"><strong>Portfolio status</strong><span>Projects grouped by current stage</span></span><span class="widget-total">24</span></header><div class="widget-body status-layout"><div class="donut-wrap"><svg class="donut" viewBox="0 0 120 120" role="img" aria-label="10 in progress, 5 at risk, 5 planning, 4 complete"><circle class="track" cx="60" cy="60" r="50"/><circle cx="60" cy="60" r="50" pathLength="100" stroke="#5978ee" stroke-dasharray="41.67 58.33"/><circle cx="60" cy="60" r="50" pathLength="100" stroke="#d98a2f" stroke-dasharray="20.83 79.17" stroke-dashoffset="-41.67"/><circle cx="60" cy="60" r="50" pathLength="100" stroke="#8b8b84" stroke-dasharray="20.83 79.17" stroke-dashoffset="-62.5"/><circle cx="60" cy="60" r="50" pathLength="100" stroke="#26956e" stroke-dasharray="16.67 83.33" stroke-dashoffset="-83.33"/></svg><div class="donut-center"><strong>24</strong><span>Projects</span></div></div><div class="status-list"><div class="status-row"><i class="dot" style="--dot:#5978ee"></i><span>In progress</span><strong>10</strong></div><div class="status-row"><i class="dot" style="--dot:#d98a2f"></i><span>At risk</span><strong>5</strong></div><div class="status-row"><i class="dot" style="--dot:#8b8b84"></i><span>Planning</span><strong>5</strong></div><div class="status-row"><i class="dot" style="--dot:#26956e"></i><span>Complete</span><strong>4</strong></div></div></div></article>
          <article class="widget budget"><button class="handle move" aria-label="Move Budget by project">⠿</button><button class="handle resize" aria-label="Resize Budget by project">↗</button><header class="widget-head"><span class="widget-title"><strong>Budget by project</strong><span>Largest shared project budgets</span></span><span class="widget-total">$838k</span></header><div class="widget-body bars"><div class="bar"><span>Atlas website launch</span><span class="bar-track"><i class="bar-fill" style="--w:100%"></i></span><strong>$245k</strong></div><div class="bar"><span>Northstar research</span><span class="bar-track"><i class="bar-fill" style="--w:76%"></i></span><strong>$186k</strong></div><div class="bar"><span>Orbit analytics</span><span class="bar-track"><i class="bar-fill" style="--w:64%"></i></span><strong>$156k</strong></div><div class="bar"><span>Harbor client portal</span><span class="bar-track"><i class="bar-fill" style="--w:57%"></i></span><strong>$139k</strong></div><div class="bar"><span>Cedar operations</span><span class="bar-track"><i class="bar-fill" style="--w:46%"></i></span><strong>$112k</strong></div></div></article>
          <article class="widget activity"><button class="handle move" aria-label="Move Project activity">⠿</button><button class="handle resize" aria-label="Resize Project activity">↗</button><header class="widget-head"><span class="widget-title"><strong>Project activity</strong><span>Record updates during the last six months</span></span><span class="widget-total">82</span></header><div class="widget-body activity-body"><div class="activity-summary"><strong>20</strong><span>updates in July · highest month</span><span class="activity-change">+25% vs June</span></div><figure class="line-chart"><div class="line-scale" aria-hidden="true"><span style="--y:12.8%">20</span><span style="--y:54.1%">10</span><span style="--y:95.5%">0</span></div><div class="activity-plot" aria-hidden="true"><svg width="600" height="220" viewBox="0 0 600 220" preserveAspectRatio="none" focusable="false"><line class="line-grid" x1="0" y1="28.2" x2="600" y2="28.2"/><line class="line-grid" x1="0" y1="119.1" x2="600" y2="119.1"/><line class="line-grid" x1="0" y1="210" x2="600" y2="210"/><path class="line-area" d="M0 137.3 L120 119.1 L240 91.8 L360 73.6 L480 64.5 L600 28.2 L600 210 L0 210 Z"/><path class="line-path" d="M0 137.3 L120 119.1 L240 91.8 L360 73.6 L480 64.5 L600 28.2"/></svg><span class="chart-point" style="--x:0%;--y:62.4%"><span class="chart-value">8</span></span><span class="chart-point" style="--x:20%;--y:54.1%"><span class="chart-value">10</span></span><span class="chart-point" style="--x:40%;--y:41.7%"><span class="chart-value">13</span></span><span class="chart-point" style="--x:60%;--y:33.5%"><span class="chart-value">15</span></span><span class="chart-point" style="--x:80%;--y:29.3%"><span class="chart-value">16</span></span><span class="chart-point latest" style="--x:100%;--y:12.8%"><span class="chart-value">20</span></span></div><div class="line-axis" aria-hidden="true"><span class="first" style="--x:0%">Feb</span><span style="--x:20%">Mar</span><span style="--x:40%">Apr</span><span style="--x:60%">May</span><span style="--x:80%">Jun</span><span class="last" style="--x:100%">Jul</span></div><figcaption class="sr-only">Project activity rose from 8 updates in February to 20 updates in July.</figcaption><table class="sr-only"><caption>Monthly project activity</caption><thead><tr><th scope="col">Month</th><th scope="col">Updates</th></tr></thead><tbody><tr><th scope="row">February</th><td>8</td></tr><tr><th scope="row">March</th><td>10</td></tr><tr><th scope="row">April</th><td>13</td></tr><tr><th scope="row">May</th><td>15</td></tr><tr><th scope="row">June</th><td>16</td></tr><tr><th scope="row">July</th><td>20</td></tr></tbody></table></figure></div></article>
          <article class="widget recent"><button class="handle move" aria-label="Move Recently updated">⠿</button><button class="handle resize" aria-label="Resize Recently updated">↗</button><header class="widget-head"><span class="widget-title"><strong>Recently updated</strong><span>Latest activity in shared projects</span></span><span class="widget-total">4</span></header><div class="widget-body recent-list"><div class="recent-row"><span class="recent-copy"><strong>Atlas website launch</strong><span>Updated 5 minutes ago</span></span><span class="badge" style="--soft:var(--accent-soft);--color:var(--accent)">In progress</span></div><div class="recent-row"><span class="recent-copy"><strong>Northstar research sprint</strong><span>Updated 42 minutes ago</span></span><span class="badge" style="--soft:color-mix(in srgb,var(--warning) 16%,var(--surface));--color:var(--warning)">At risk</span></div><div class="recent-row"><span class="recent-copy"><strong>Orbit analytics rollout</strong><span>Updated 1 hour ago</span></span><span class="badge" style="--soft:var(--accent-soft);--color:var(--accent)">In progress</span></div><div class="recent-row"><span class="recent-copy"><strong>Harbor client portal</strong><span>Updated 3 hours ago</span></span><span class="badge" style="--soft:color-mix(in srgb,var(--success) 16%,var(--surface));--color:var(--success)">Complete</span></div></div></article>
        </section>
      </div>
    </main>
  </div>
  <section class="pdf-modal" role="dialog" aria-modal="true"><div class="pdf-shell"><header class="pdf-toolbar"><div><strong>PDF-friendly report</strong><span>Letter format · print-safe colors</span></div><div class="pdf-actions"><button class="button" data-action="print">Print / Save PDF</button><button class="icon" data-action="close-pdf" aria-label="Close PDF preview">×</button></div></header><article class="pdf-page"><header class="pdf-head"><div><p>Client project report</p><h2>Project overview</h2></div><time>July 27, 2026</time></header><section class="pdf-metrics"><div class="pdf-metric"><span>Active projects</span><strong>24</strong></div><div class="pdf-metric"><span>Total budget</span><strong>$838,250</strong></div><div class="pdf-metric"><span>At risk</span><strong>5</strong></div><div class="pdf-metric"><span>Complete</span><strong>4</strong></div></section><section class="pdf-grid"><article class="pdf-card wide"><h3>Project activity</h3><p>82 record updates during the last six months</p><svg class="pdf-line" width="680" height="210" viewBox="0 0 680 210"><line class="grid" x1="40" y1="33.6" x2="640" y2="33.6"/><line class="grid" x1="40" y1="101.8" x2="640" y2="101.8"/><line class="grid" x1="40" y1="170" x2="640" y2="170"/><path class="area" d="M40 115.5 L160 101.8 L280 81.4 L400 67.7 L520 60.9 L640 33.6 L640 170 L40 170 Z"/><path class="path" d="M40 115.5 L160 101.8 L280 81.4 L400 67.7 L520 60.9 L640 33.6"/><circle class="point" cx="40" cy="115.5" r="4"/><circle class="point" cx="160" cy="101.8" r="4"/><circle class="point" cx="280" cy="81.4" r="4"/><circle class="point" cx="400" cy="67.7" r="4"/><circle class="point" cx="520" cy="60.9" r="4"/><circle class="point" cx="640" cy="33.6" r="4"/><text class="value" x="50" y="104" text-anchor="start">8</text><text class="value" x="160" y="90" text-anchor="middle">10</text><text class="value" x="280" y="70" text-anchor="middle">13</text><text class="value" x="400" y="56" text-anchor="middle">15</text><text class="value" x="520" y="49" text-anchor="middle">16</text><text class="value" x="640" y="22" text-anchor="end">20</text><text x="28" y="36">20</text><text x="28" y="105">10</text><text x="32" y="173">0</text><text x="40" y="200" text-anchor="start">Feb</text><text x="160" y="200" text-anchor="middle">Mar</text><text x="280" y="200" text-anchor="middle">Apr</text><text x="400" y="200" text-anchor="middle">May</text><text x="520" y="200" text-anchor="middle">Jun</text><text x="640" y="200" text-anchor="end">Jul</text></svg></article></section><footer class="pdf-footer"><span>Twenty Portal · Confidential client report</span><span>1 / 1</span></footer></article></div></section>
  <script>
    const root=document.documentElement,body=document.body,edit=document.querySelector('[data-action="edit"]');
    const activityLine=document.querySelector(".line-path");
    const syncActivityLineLength=()=>{
      if(!activityLine)return;
      const sourceLength=activityLine.getTotalLength(),matrix=activityLine.getScreenCTM();
      if(!matrix)return;
      let renderedLength=0,previous=activityLine.getPointAtLength(0);
      for(let index=1;index<=120;index++){
        const current=activityLine.getPointAtLength(sourceLength*index/120);
        const dx=(current.x-previous.x)*matrix.a+(current.y-previous.y)*matrix.c;
        const dy=(current.x-previous.x)*matrix.b+(current.y-previous.y)*matrix.d;
        renderedLength+=Math.hypot(dx,dy);
        previous=current;
      }
      activityLine.style.setProperty("--line-length",String(renderedLength+2));
    };
    syncActivityLineLength();
    new ResizeObserver(syncActivityLineLength).observe(activityLine.ownerSVGElement);
    root.classList.add("motion-ready");
    document.querySelector(".pdf-grid").insertAdjacentHTML("afterbegin",`
      <article class="pdf-card">
        <h3>Portfolio status</h3><p>Projects grouped by current stage</p>
        <div class="pdf-status">
          <svg class="pdf-donut donut" viewBox="0 0 120 120" aria-label="Portfolio status">
            <circle cx="60" cy="60" r="50" fill="none" stroke="#eeeeeb" stroke-width="8"/>
            <circle cx="60" cy="60" r="50" pathLength="100" fill="none" stroke="#3658d4" stroke-width="8" stroke-dasharray="41.67 58.33"/>
            <circle cx="60" cy="60" r="50" pathLength="100" fill="none" stroke="#d98a2f" stroke-width="8" stroke-dasharray="20.83 79.17" stroke-dashoffset="-41.67"/>
            <circle cx="60" cy="60" r="50" pathLength="100" fill="none" stroke="#8b8b84" stroke-width="8" stroke-dasharray="20.83 79.17" stroke-dashoffset="-62.5"/>
            <circle cx="60" cy="60" r="50" pathLength="100" fill="none" stroke="#26956e" stroke-width="8" stroke-dasharray="16.67 83.33" stroke-dashoffset="-83.33"/>
          </svg>
          <div class="pdf-legend"><div><span>In progress</span><strong>10</strong></div><div><span>At risk</span><strong>5</strong></div><div><span>Planning</span><strong>5</strong></div><div><span>Complete</span><strong>4</strong></div></div>
        </div>
      </article>
      <article class="pdf-card">
        <h3>Budget by project</h3><p>Largest shared project budgets</p>
        <div class="pdf-bars">
          <div class="pdf-bar"><span>Atlas</span><span class="pdf-track"><i class="pdf-fill" style="--w:100%"></i></span><strong>$245k</strong></div>
          <div class="pdf-bar"><span>Northstar</span><span class="pdf-track"><i class="pdf-fill" style="--w:76%"></i></span><strong>$186k</strong></div>
          <div class="pdf-bar"><span>Orbit</span><span class="pdf-track"><i class="pdf-fill" style="--w:64%"></i></span><strong>$156k</strong></div>
          <div class="pdf-bar"><span>Harbor</span><span class="pdf-track"><i class="pdf-fill" style="--w:57%"></i></span><strong>$139k</strong></div>
          <div class="pdf-bar"><span>Cedar</span><span class="pdf-track"><i class="pdf-fill" style="--w:46%"></i></span><strong>$112k</strong></div>
        </div>
      </article>
    `);
    document.querySelector('[data-action="theme"]').onclick=()=>root.dataset.theme=root.dataset.theme==="dark"?"light":"dark";
    edit.onclick=()=>{const active=body.classList.toggle("editing");edit.querySelector("span").textContent=active?"Done editing":"Edit layout"};
    document.querySelector('[data-action="export"]').onclick=()=>body.classList.add("pdf-open");
    document.querySelector('[data-action="close-pdf"]').onclick=()=>body.classList.remove("pdf-open");
    document.querySelector('[data-action="print"]').onclick=()=>window.print();
    document.querySelector('[data-action="menu"]').onclick=()=>body.classList.add("menu-open");
    document.querySelector('[data-action="close-menu"]').onclick=()=>body.classList.remove("menu-open");
    document.querySelectorAll('a[href="#"]').forEach(a=>a.onclick=e=>e.preventDefault());
    document.addEventListener("keydown",e=>{if(e.key==="Escape")body.classList.remove("pdf-open","menu-open")});
  </script>
</body>
</html>