<% var vis = snap || {}; var b = d || {};

  var hasRun  = vis.visibilityScore != null;
  var hasSeo  = b.seoHealth != null;
  var hasTech = b.techIssues != null;

  var num = function (v) { return (v == null || v === '') ? '<span class="noval">—</span>' : String(v); };

  function delta(v, unit) {
    if (v == null || v === 0) return '';
    var up = v > 0;
    return '<span class="chip ' + (up ? 'pos' : 'neg') + '">' + (up ? '▲' : '▼') + ' ' +
           Math.abs(v) + (unit || '') + '</span>';
  }
  function mini(v, unit) {

    if (v == null) return '';
    if (v === 0) return ' <span class="mini muted" title="Measured, and unchanged against the previous 90 days"><span class="flatbar" role="img" aria-label="unchanged"></span></span>';
    var up = v > 0;
    return ' <span class="mini ' + (up ? 'pos' : 'neg') + '">' + (up ? '▲' : '▼') +
           Math.abs(v) + (unit || '') + '</span>';
  }

  function rail(score) {
    if (score == null) return '';
    return score >= 75 ? 'r-good' : (score >= 50 ? 'r-ok' : 'r-bad');
  }
  function tint(delta) {
    if (delta == null || delta === 0) return '';
    return delta > 0 ? 't-up' : 't-down';
  }

  var _svc = locals.services || [];
  var _isAgency = locals.showStaff;
%>

<%

  var claimScore = hasRun ? vis.visibilityScore : null;

  var bits = [];
  if (vis.delta) {
    var up = vis.delta > 0;
    bits.push('AI visibility is ' + (up ? 'up' : 'down') +
      ' <b class="mini ' + (up ? 'pos' : 'neg') + '">' + (up ? '▲' : '▼') + ' ' +
      Math.abs(vis.delta) + ' point' + (Math.abs(vis.delta) === 1 ? '' : 's') + '</b>');
  }
  if (b.newCitations) bits.push('<b class="mini pos">' + b.newCitations + '</b> new citation' +
    (b.newCitations === 1 ? '' : 's') + ' landed this week');
%>
<div class="pg-head" style="margin-bottom:0">
  <div>

    <div class="eyebrow">Overview<% var _ls = locals.lastSyncAt ? new Date(locals.lastSyncAt) : null; if (_ls && !isNaN(_ls)) { %> / Data from <%= _ls.getDate() %> <%= ['Jan','Feb','March','April','May','June','July','Aug','Sept','Oct','Nov','Dec'][_ls.getMonth()] %><% } %></div>
  </div>
  <div class="ph-right"><%- include('../partials/range-picker') %></div>
</div>

<h1 class="claim"><%= title %></h1>
<% if (claimScore != null && claimScore > 0) { %>
  <p class="claim-lede">You are the answer in <em><%= claimScore %>%</em> of AI conversations.</p>
<% } else if (claimScore === 0) { %>
  <p class="claim-lede">No AI answer named you in the last run.</p>
<% } else { %>
  <p class="claim-lede">No AI Visibility run yet.</p>
<% } %>
<%

  var _alertTone = vis.delta ? (vis.delta > 0 ? 'pos' : 'neg') : 'pos';
%>
<% if (bits.length) { %>
  <%- include('../partials/claim-alert', { html: bits.join(', and ') + '.', tone: _alertTone }) %>
<% } else { %>

  <p class="claim-sub"><% if (hasRun) { %>From your latest AI Visibility run.<% } else { %>Your figures appear here after the first AI Visibility run.<% } %></p>
<% } %>

<%

  var _acts = [];
  var _svgMsg = '<svg viewBox="0 0 16 16" width="15" height="15" fill="none"><path d="M13.6 10.2a1.4 1.4 0 0 1-1.4 1.4H4.9L2.4 14V3.2a1.4 1.4 0 0 1 1.4-1.4h8.4a1.4 1.4 0 0 1 1.4 1.4z" stroke="currentColor" stroke-width="1.4" stroke-linejoin="round"/></svg>';
  var _svgChk = '<svg viewBox="0 0 16 16" width="15" height="15" fill="none"><path d="M3.4 8.4l3 3 6.2-6.8" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg>';
  var _svgDl  = '<svg viewBox="0 0 16 16" width="15" height="15" fill="none"><path d="M8 2.6v7.2M5.2 7.4L8 10.2l2.8-2.8M2.8 12.4h10.4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>';
  var _svgCal = '<svg viewBox="0 0 16 16" width="15" height="15" fill="none"><rect x="2.4" y="3.4" width="11.2" height="10.2" rx="1.6" stroke="currentColor" stroke-width="1.4"/><path d="M5.4 1.9v2.6M10.6 1.9v2.6M2.4 6.8h11.2" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>';
  var _svgInv = '<svg viewBox="0 0 16 16" width="15" height="15" fill="none"><rect x="1.9" y="3.9" width="12.2" height="8.2" rx="1.6" stroke="currentColor" stroke-width="1.4"/><path d="M1.9 6.9h12.2" stroke="currentColor" stroke-width="1.4"/></svg>';

  var _cw = (navCounts && navCounts.content) || 0;

  _acts.push({ href:'/messages',       lb:'Message manager', ic:_svgMsg, lead:true });

  if (_cw) _acts.push({ href:'/content-center', lb:'Approve content', ic:_svgChk, n:_cw });
  if (typeof report !== 'undefined' && report) _acts.push({ href:'/reports', lb:'Download report', ic:_svgDl });
  _acts.push({ href:'/meetings',       lb:'Book meeting',     ic:_svgCal });
  if (typeof invoice !== 'undefined' && invoice) _acts.push({ href:'/invoices', lb:'Pay invoice', ic:_svgInv });
%>

<div class="qbar">
  <div class="qbar-acts">
    <% _acts.forEach(function (a) { %>
      <a class="qact<%= a.lead ? ' qact-lead' : '' %>" href="<%= a.href %>"><%- a.ic %><span><%= a.lb %><% if (a.n) { %> <b class="qn"><%= a.n %></b><% } %></span></a>
    <% }) %>
  </div>

  <% if (meeting) { %>
  <div class="qmeet">
    <div class="qmeet-d">
      <b><%= new Date(meeting.startsAt).getDate() %></b>
      <span><%= new Date(meeting.startsAt).toLocaleDateString('en-GB', { month: 'short' }) %></span>
    </div>

    <a class="qmeet-b" href="/meetings">
      <div class="qmeet-t"><%= meeting.title %></div>
      <div class="qmeet-m"><%= h.time(meeting.startsAt) %> · <%= (meeting.attendees||[]).length %> attending</div>
    </a>

    <div class="qmeet-acts">
      <% if (meeting.zoomLink) { %><a class="btn btn-primary btn-sm" href="<%= meeting.zoomLink %>">Join</a><% } %>
      <a class="btn btn-sm" href="/meetings">Reschedule</a>
    </div>
  </div>
  <% } %>
</div>

<% if (typeof growNudge !== 'undefined' && growNudge) { %>
<div class="vnotch" id="growNudgeNotch" style="margin:26px 0 0">
  <span class="vn-fillet"></span>

  <form method="POST" action="/grow/seen" class="inline-form" style="position:absolute;top:0;right:0">
    <input type="hidden" name="go" value="grow">
    <button class="vn-cut" type="submit">Take a look
      <svg viewBox="0 0 12 12" fill="none" width="13" height="13" aria-hidden="true"><path d="M3 9L9 3M9 3H4.2M9 3v4.8" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"/></svg>
    </button>
  </form>
  <div class="vn-h"><%= growNudge.title %><% if (growNudge.count > 1) { %>, and <%= growNudge.count - 1 %> other<%= growNudge.count > 2 ? 's' : '' %><% } %></div>

  <div style="margin-top:14px">

    <form method="POST" action="/grow/seen" class="inline-form js-ajax-form" data-hide-after="#growNudgeNotch">
      <button class="btn btn-sm" type="submit" style="background:rgba(255,255,255,.14);color:#fff;border:0">Not now</button>
    </form>
  </div>
</div>
<% } %>

<%

  var _bh = bh || {}, _bd = _bh.breakdown || {};
  var BHL = {};
  ['visibility','authority','citationQuality','sentiment','entityStrength','shareOfVoice'].forEach(function (k) { BHL[k] = h.sigName(k); });
  var bhKnown = Object.keys(BHL).filter(function (k) { return _bd[k] != null; });
  var bhShow  = bhKnown.slice().sort(function (x, y) { return _bd[x] - _bd[y]; });
  var bhLever = bhShow.length ? bhShow[0] : null;

  var bhCount = bhKnown.length;

  var BH_C = 314.16;

  var _hasOrganic = b.organicTraffic != null && b.organicTraffic !== '';

  var _organicDays = (typeof b.organicDays === 'number' && b.organicDays > 0) ? b.organicDays : null;

  var _organicWhen  = b.organicWhen || (_organicDays ? 'last ' + _organicDays + ' days' : 'from GA4');
  var _organicHelp  = 'Organic search sessions in GA4'
    + (b.organicWhen ? ' (' + b.organicWhen + ')' : (_organicDays ? ', last ' + _organicDays + ' days' : ''))
    + ', compared with the period before. Paid traffic is excluded.';
  var _shelf = [], _off = [];

  var _shelfFacts = [];
  var _shelfNote = '';
  function _cell(l, v, x) { _shelf.push({ l: l, v: v, x: x || '' }); }
  function _blank(n, cta, href) { _off.push({ n: n, cta: cta, href: href || '' }); }

  if (!_hasOrganic) _blank('Organic traffic', 'Connect Google Analytics', '/integrations');

  if (_svc.indexOf('seo') !== -1) {
    var _kw = false;
    if (b.keywordsTop3 != null)  { _cell('Top 3 keywords',  b.keywordsTop3,  mini(b.top3Delta));  _kw = true; }
    if (b.keywordsTop10 != null) { _cell('Top 10 keywords', b.keywordsTop10, mini(b.top10Delta)); _kw = true; }
    if (b.keywordsTop20 != null) { _cell('Top 20 keywords', b.keywordsTop20, mini(b.top20Delta)); _kw = true; }
    if (b.keywordsTop50 != null) { _cell('Top 50 keywords', b.keywordsTop50, mini(b.top50Delta)); _kw = true; }

    if (b.keywordsTotal != null) {

      _cell('All keywords', b.keywordsTotal,
            mini(b.totalDelta) + (b.keywordsCapped ? ' <span class="mini muted">capped</span>' : ''));
      _kw = true;
    }

    if (_kw) {

      var _kwWin = b.keywordsWindow;

      var _kwYear = _kwWin && _kwWin.to ? new Date(_kwWin.to).getFullYear() : null;
      _shelfFacts.push(_kwWin && _kwWin.from
        ? { k: 'Window',
            v: h.date(_kwWin.from) + ' → ' + h.date(_kwWin.to) + (_kwYear && !isNaN(_kwYear) ? ' ' + _kwYear : ''),
            s: '90 days, at the last SEO sync' }
        : { k: 'Window', v: 'Last 90 days', s: 'at the last SEO sync' });
      _shelfFacts.push({
        k: 'Counted from',
        v: 'Search Console queries',
        s: 'searches where your site appeared'
      });
      _shelfFacts.push({ k: 'Buckets', v: 'Cumulative', s: 'Top 10 includes Top 3' });

      var _kwMin = +b.keywordsMinImpressions || 0;
      if (_kwMin > 1) {
        _shelfFacts.push({
          k: 'Floor',
          v: _kwMin + '+ searches',
          s: 'keywords searched less often are excluded'
        });
      }
    }

    if (_kw && b.deltaBlocked) {

      var _cap = b.keywordsPageCap;
      _shelfNote = (b.deltaBlocked === 'capped'
        ? 'No change shown: Search Console returned the maximum number of rows'
          + (_cap ? ' (' + _cap.toLocaleString('en-US') + ')' : '')
          + ' for one of the two periods, so they cannot be compared.'
        : 'Change appears after the next SEO sync.');
    }
    if (!_kw) _blank('Keyword rankings', 'No ranking pull recorded yet');
  }

  if (b.conversions != null) _cell('Conversions', b.conversions, mini(b.convDelta, '%'));
  else _blank('Conversions', 'Connect Google Analytics', '/integrations');

  var _open = (navCounts && navCounts.tasks) || 0;
  var _donePct = (b.donePct == null) ? null : b.donePct + '%';
  var _doneOf = (b.tasksTotal ? b.tasksDone + ' of ' + b.tasksTotal + ' tasks' : 'no tasks yet');
  var _recent = (b.completedInRange != null ? b.completedInRange : (b.completedThisMonth || 0));

  var _openN = b.tasksTotal ? Math.max(0, b.tasksTotal - (b.tasksDone || 0)) : null;
  var _delivery = [
    { l: 'Completed', v: _donePct,
      m: _doneOf + (b.tasksTotal ? ' · ' + _recent + ' in ' + range.label.toLowerCase() : '') },
    { l: 'Open tasks', v: _openN == null ? null : String(_openN),
      m: (b.tasksDue || 0) + ' overdue or due today' }
  ];

  var _span = _hasOrganic ? 'b3' : 'b4';

  var _dots = (vis.platforms || []).filter(function (p) { return p && p.mentions; });
%>

<div class="bento" style="margin-top:22px">

  <div class="vdark vd-hero b7">

    <span class="vd-deco"><svg class="vd-orbit" viewBox="0 0 400 400" fill="none" aria-hidden="true">
      <ellipse cx="200" cy="200" rx="176" ry="62" stroke="#A6DB6E" stroke-width="3" opacity=".55"/>
      <ellipse cx="200" cy="200" rx="176" ry="62" stroke="#fff" stroke-width="2.4" opacity=".22" transform="rotate(60 200 200)"/>
      <ellipse cx="200" cy="200" rx="176" ry="62" stroke="#4FCAD4" stroke-width="2.8" opacity=".5" transform="rotate(-60 200 200)"/>
      <circle cx="200" cy="200" r="34" fill="#A6DB6E" opacity=".14"/>
      <circle cx="200" cy="200" r="19" fill="#A6DB6E" opacity=".9"/>
      <circle cx="376" cy="200" r="6" fill="#fff" opacity=".5"/>
      <circle cx="112" cy="352" r="5" fill="#4FCAD4" opacity=".7"/>
    </svg></span>
    <div class="vd-k">AI Visibility Score <%- h.ihelp('AI Visibility Score', 'How often AI engines name you when they answer your tracked prompts.') %></div>
    <div class="vd-num tnum"><% if (hasRun) { %><%= vis.visibilityScore %><% } else { %><span class="noval">—</span><% } %><% if (hasRun) { %><small>/100</small><% } %></div>
    <% if (vis.delta) { %>
      <div class="vd-drow"><span class="vd-d <%= vis.delta > 0 ? '' : 'neg' %>"><%= vis.delta > 0 ? '▲' : '▼' %> <%= Math.abs(vis.delta) %> point<%= Math.abs(vis.delta) === 1 ? '' : 's' %> since the last run</span></div>
    <% } %>
    <div class="vd-sub">
      <% if (hasRun) { %>

        <span class="vd-l2"><b><%= vis.visibilityScore %>%</b> of AI answers about your market named you.<% var _st = locals.brandStanding; if (_st && _st.rank) { %> <b>#<%= _st.rank %> of <%= _st.total %></b> brand<%= _st.total === 1 ? '' : 's' %> named in the answers.<% } %></span>
      <% } else { %>
        No AI Visibility run yet.
      <% } %>
    </div>
    <div class="vd-act">
      <a class="btn btn-sm" href="/ai-visibility">See the answers</a>
      <% if (hasRun) { %><a class="btn btn-sm" href="#trend">What changed</a><% } %>
    </div>
  </div>

  <div class="card rr b5">
    <div class="card-h"><h3>Brand health<% if (_bh.score != null) { %><%- h.ihelp('Brand health', 'The average of ' + bhCount + ' Brand Health signals.') %><% } %></h3><a class="more" href="/brand-health">Open Brand Health</a></div>
    <div class="card-p" style="padding-top:14px">
      <% if (_bh.score != null) { %>
        <div style="display:flex; align-items:center; gap:24px; margin-top:18px; flex-wrap:wrap">
          <svg class="vring" viewBox="0 0 120 120" role="img" aria-label="Brand health <%= _bh.score %> out of 100">
            <circle cx="60" cy="60" r="50" fill="none" stroke="var(--surface-2)" stroke-width="13"/>

            <circle cx="60" cy="60" r="50" fill="none" stroke="var(--teal)" stroke-width="13" stroke-linecap="round"
                    stroke-dasharray="<%= (BH_C * Math.max(0, Math.min(100, _bh.score)) / 100).toFixed(1) %> <%= BH_C %>"
                    transform="rotate(-90 60 60)"/>
            <text class="vring-t" x="60" y="59" text-anchor="middle" fill="var(--ink)"><%= _bh.score %></text>
            <text x="60" y="76" text-anchor="middle" fill="var(--muted-2)" font-size="11">out of 100</text>
          </svg>
          <% if (bhShow.length) { %>
          <div class="vsig">
            <% bhShow.forEach(function (k) { var v = _bd[k]; %>
              <div class="vsig-r">
                <span class="n"><%= BHL[k] %></span>
                <span class="v tnum"><%- h.sigVal(k, v) %></span>

                <span class="b"><i style="width:<%= Math.max(0, Math.min(100, v)) %>%<%= (k === bhLever && v < 50) ? '; background:var(--warn)' : '' %>"></i></span>
              </div>
            <% }) %>
          </div>
          <% } %>
        </div>
        <% if (bhLever) { %>
          <p class="rr-meta" style="margin-top:18px"><b><%= BHL[bhLever] %></b> is your lowest signal.</p>
        <% } %>
      <% } else { %>

        <p class="rr-meta" style="margin-top:0">No score yet. It appears after the first AI Visibility run.</p>
        <p class="rr-meta" style="margin-top:10px"><a href="/ai-visibility">Run AI Visibility</a></p>
      <% } %>
    </div>
  </div>

  <div class="card card-p rr <%= _span %> <%= rail(hasSeo ? b.seoHealth : null) %> <%= tint(b.seoDelta) %>">
    <div class="row-between"><span class="rr-lbl">SEO Health</span><span class="rr-end"><%- delta(b.seoDelta) %><%- h.ihelp('SEO Health', 'Average of ' + ((b.seoHealthFrom && b.seoHealthFrom.length) ? b.seoHealthFrom.join(', ') : 'average position, click-through rate and Core Web Vitals') + '. Technical issues are counted separately below.') %></span></div>
    <div class="score-num tnum" style="margin-top:12px"><% if (hasSeo) { %><%= b.seoHealth %><% } else { %><span class="noval">—</span><% } %><% if (hasSeo) { %><small>/100</small><% } %></div>
    <div class="meter"><span style="width:<%= hasSeo ? b.seoHealth : 0 %>%"></span></div>

    <div class="rr-meta" style="margin-top:10px"><% if (hasTech) { %><%= b.techIssues %> technical issue<%= b.techIssues === 1 ? '' : 's' %> open<%= b.techFrom === 'crawl' ? (b.techPages ? ', crawled ' + b.techPages + ' pages' : ', from our crawl') : (b.techFrom === 'articles' ? ' · your articles only, no site crawl' : '') %><% } else { %>Not checked yet<% } %></div>
  </div>

  <% if (_hasOrganic) { %>

  <div class="card card-p rr b3 <%= tint(b.organicDelta) %>">
    <div class="row-between"><span class="rr-lbl">Organic Traffic</span><span class="rr-end"><%- delta(b.organicDelta, '%') %></span></div>
    <div class="score-num tnum" style="margin-top:12px"><%= b.organicTraffic %></div>
    <div class="rr-meta" style="margin-top:10px">Sessions, <%= _organicWhen %></div>
  </div>
  <% } %>

  <div class="card card-p rr <%= _span %> <%= tint(b.aiDelta) %>">
    <div class="row-between"><span class="rr-lbl">AI Mentions</span><span class="rr-end"><%- delta(b.aiDelta, '%') %></span></div>

    <div class="score-num tnum" style="margin-top:12px"><%- num(b.aiMentions) %></div>
    <div class="rr-meta" style="margin-top:10px"><%= b.aiMentions != null ? 'Across AI engines' : 'No run yet' %></div>
    <% if (_dots.length) { %>

      <div style="display:flex; gap:7px; margin-top:auto; padding-top:16px">
        <% _dots.forEach(function (p) { %>
          <span title="<%= p.name %> · <%= h.int(p.mentions) %> mentions" style="flex:<%= p.mentions %>; height:6px; border-radius:99px; background:var(--teal)"></span>
        <% }) %>
      </div>
    <% } %>
  </div>

  <% var _sentAll = (b.sentimentPos||0) + (b.sentimentNeu||0) + (b.sentimentNeg||0); var hasSent = _sentAll > 0; %>
  <div class="card card-p rr <%= _span %> <%= rail(_sentAll ? 100 - (b.sentimentNeg||0) : null) %> <%= tint(b.sentDelta) %>">
    <div class="row-between"><span class="rr-lbl">Brand Sentiment</span><span class="rr-end"><%- delta(b.sentDelta, '%') %><%- h.ihelp('Brand Sentiment', 'The share of AI answers that speak positively about you.') %></span></div>
    <div class="score-num tnum" style="margin-top:12px"><% if (hasSent) { %><%= b.sentimentPos %><% } else { %><span class="noval">—</span><% } %><% if (hasSent) { %><small>%</small><% } %></div>
    <% if (hasSent) { %>
      <div class="stack"><i style="width:<%= b.sentimentPos||0 %>%; background:var(--pos)"></i><i style="width:<%= b.sentimentNeu||0 %>%; background:var(--muted-2)"></i><i style="width:<%= b.sentimentNeg||0 %>%; background:var(--neg)"></i></div>

      <div class="legend-s"><span><i class="sd" style="background:var(--pos)"></i><%= b.sentimentPos||0 %>% positive</span><span><i class="sd" style="background:var(--muted-2)"></i><%= b.sentimentNeu||0 %>% neutral</span><span><i class="sd" style="background:var(--neg)"></i><%= b.sentimentNeg||0 %>% negative</span></div>
    <% } else { %>
      <div class="rr-meta" style="margin-top:10px">No answers mentioning you yet</div>
    <% } %>
  </div>

  <% if (_shelf.length) { %>

  <%

    var _sw = { 1:'b4', 2:'b6', 3:'b4', 4:'b3', 6:'b2', 12:'b1' }[_shelf.length] || 'b2';
    var _tints = ['sc-violet', 'sc-lime', 'sc-navy', 'sc-sky', 'sc-sand', 'sc-rose'];
  %>
  <% _shelf.forEach(function (s, i) { %>
    <div class="card shelf-c <%= _sw %> <%= _tints[i % _tints.length] %>">
      <div class="cl"><%= s.l %></div>
      <div class="cv tnum"><%= s.v %><%- s.x %></div>
    </div>
  <% }) %>
  <% if (_shelfFacts.length || _shelfNote) { %>

    <div class="voff voff-info b12 howbar">
      <div class="voff-i" style="flex:1; min-width:0">
        <div class="howbar-h">How these were counted</div>
        <% if (_shelfFacts.length) { %>
        <dl class="howbar-g">
          <% _shelfFacts.forEach(function (f) { %>
            <div class="how-c">
              <dt class="how-k"><%= f.k %></dt>
              <dd class="how-d"><span class="how-v"><%= f.v %></span><% if (f.s) { %><span class="how-s"><%= f.s %></span><% } %></dd>
            </div>
          <% }) %>
        </dl>
        <% } %>

        <% if (_shelfNote) { %><div class="how-why"><%= _shelfNote %></div><% } %>
      </div>
    </div>
  <% } %>
  <% } %>

  <% if (_off.length) { %>

  <div class="voff b12">
    <div class="voff-h"><b>Not connected yet</b></div>
    <% _off.forEach(function (o) { %>
      <div class="voff-i">
        <span class="n"><%= o.n %></span>
        <% if (o.href) { %><a href="<%= o.href %>"><%= o.cta %></a><% } else { %><span class="n"><%= o.cta %></span><% } %>
      </div>
    <% }) %>
  </div>
  <% } %>

  <div class="card b7">

    <div class="card-h"><h3>Where you appear</h3><span class="hint">last run</span><a class="more" href="/ai-visibility">Open AI Visibility</a></div>
    <% var plats = (vis.platforms||[]).slice(0,7); %>
    <% if(!plats.length){ %>
      <div class="card-p rr-meta" style="text-align:center; padding:34px">No engine has been asked yet. Run AI Visibility to fill this in.</div>
    <% } else { %>
    <div class="plat">
      <% plats.forEach(function(p){ var pv = p.visibility != null ? p.visibility : null; %>
        <div class="plat-row">
          <div class="plat-name"><%- include('../partials/engine-mark', { engine: p.name || p.code }) %><div><div class="nm"><%= p.name %></div><div class="mc"><%= h.int(p.mentions) %> mentions</div></div></div>
          <div class="bar"><span class="grad" style="width:<%= pv || 0 %>%"></span></div>
          <div class="plat-val"><%= pv != null ? pv + '%' : '—' %><% if(p.delta){ %><span class="d <%= p.delta>0?'pos':'neg' %>"><%= p.delta>0?'▲'+p.delta:'▼'+Math.abs(p.delta) %></span><% } else { %><span class="d flat" title="Measured, and unchanged against the previous run"><span class="flatbar" role="img" aria-label="unchanged"></span></span><% } %></div>
        </div>
      <% }) %>
    </div>
    <% } %>
  </div>

  <div class="card b5 team-activity">
    <div class="card-h"><h3>Team activity</h3><span class="hint">latest 4</span></div>
    <% var acts = activities || []; %>
    <% if(!acts.length){ %>
      <div class="card-p rr-meta" style="text-align:center; padding:28px">Nothing has happened here yet.</div>
    <% } else { %>
    <div class="feed">
      <% acts.forEach(function(a){ %>
        <div class="fi"><%- include('../partials/avatar', { url: a.actor && a.actor.avatarUrl, initials: a.actorInitials || '✦', color: a.actorColor, name: a.actorName, cls: 'fav' }) %><div><div class="ft"><%- h.rich(a.text) %></div><div class="ftime"><%= h.timeAgo(a.at) %><%= a.category ? ' · ' + a.category : '' %></div></div></div>
      <% }) %>
    </div>
    <% } %>
    <a class="feed-foot" href="/team-activity">Open activity feed</a>
  </div>

  <%

    var tr = (typeof trend !== 'undefined' && trend) ? trend : null;
    var hist = tr ? tr.points : ((snap && snap.history) || []).filter(function (p) { return p && p.score != null; });
    var iso = function (dt) { return dt ? new Date(dt).toISOString().slice(0, 10) : ''; };
    var today = new Date().toISOString().slice(0, 10);
    var L = 46, R = 668, TOP = 34, BOT = 196;
    var Y = function (v) { return BOT - (Math.max(0, Math.min(100, v)) / 100) * (BOT - TOP); };

    var n = hist.length;

    var dated = n >= 2 && hist.every(function (p) { return p.at; });
    var t0 = dated ? new Date(hist[0].at).getTime() : 0;
    var t1 = dated ? new Date(hist[n - 1].at).getTime() : 0;
    var spanOk = dated && t1 > t0;
    var X = function (p, i) {
      if (!spanOk) return L + (n === 1 ? 0 : (i / (n - 1)) * (R - L));
      return L + ((new Date(p.at).getTime() - t0) / (t1 - t0)) * (R - L);
    };

    var cs = (workspace && workspace.contractStartedAt) ? new Date(workspace.contractStartedAt) : null;
    var csT = cs ? cs.getTime() : null;
    var csInside = spanOk && csT && csT >= t0 && csT <= t1;
    var csBefore = spanOk && csT && csT < t0;
    var csX = csInside ? (L + ((csT - t0) / (t1 - t0)) * (R - L)) : null;

    var line = hist.map(function (p, i) { return Math.round(X(p, i)) + ',' + Math.round(Y(p.score)); }).join(' ');
    var area = n >= 2 ? ('M' + line.split(' ').join(' L').replace(/^ L/, '') + ' L' + Math.round(X(hist[n-1], n-1)) + ',' + BOT + ' L' + Math.round(X(hist[0], 0)) + ',' + BOT + ' Z') : '';

    var tickLabel = function (p, i) {
      if (p.at) return new Date(p.at).toLocaleDateString('en-GB', { day: 'numeric', month: 'short' });
      return 'Run ' + (i + 1);
    };

    var tickIdx = [];
    if (n) {
      var want = Math.min(5, n);
      var raw = [];
      for (var t = 0; t < want; t++) raw.push(Math.round(t * (n - 1) / Math.max(1, want - 1)));
      raw = raw.filter(function (v, i, a) { return a.indexOf(v) === i; });

      var seenTickLabels = {};
      raw.forEach(function (idx) {
        var lbl = tickLabel(hist[idx], idx);
        var isEdge = (idx === 0 || idx === n - 1);
        if (isEdge || !seenTickLabels[lbl]) {
          tickIdx.push(idx);
          seenTickLabels[lbl] = true;
        }
      });

      var MIN_GAP = 62;
      var spaced = [];
      tickIdx.forEach(function (idx) {
        var x = X(hist[idx], idx);
        var prev = spaced.length ? spaced[spaced.length - 1] : null;
        if (prev == null || x - X(hist[prev], prev) >= MIN_GAP) { spaced.push(idx); return; }
        if (idx === n - 1) { spaced[spaced.length - 1] = idx; }
      });
      tickIdx = spaced;
    }
    var pointLabel = function (p, i) {
      return p.at ? tickLabel(p, i) : (p.label ? p.label + ' · run ' + (i + 1) : 'Run ' + (i + 1));
    };
    var last = n ? hist[n - 1] : null;
    var first = n ? hist[0] : null;
  %>

  <div class="card b12" id="trend">
    <div class="card-h">

      <h3>AI Visibility over time</h3>
      <span class="hint">one point per run</span>
      <% if(n >= 2 && last && first){ var mv = last.score - first.score; %>
        <span style="margin-left:auto" class="chip <%= mv > 0 ? 'pos' : (mv < 0 ? 'neg' : 'flat') %>">
          <%- mv > 0 ? '▲' : (mv < 0 ? '▼' : '<span class="flatbar" role="img" aria-label="unchanged"></span>') %> <%= Math.abs(mv) %> pts<%= tr && tr.filtered ? ' in this range' : ' across all runs' %>
        </span>
      <% } %>
    </div>

    <% if (tr && tr.filterable) { %>
    <div class="rangebar">
      <div class="presets">
        <% if (tr.allRuns) { %>
          <span class="rp on">All <%= tr.total %> runs</span>
          <a class="rp" href="/dashboard?allRuns=0#trend">Only <%= range.label.toLowerCase() %></a>
        <% } else { %>
          <span class="rp on"><%= range.label %></span>
          <% if (tr.total > tr.points.length) { %>
            <a class="rp" href="/dashboard#trend">Show all <%= tr.total %> runs</a>
          <% } %>
        <% } %>
      </div>
    </div>
    <% } %>

    <div class="card-p" style="padding-top:12px">
      <% if (n >= 2) { %>
      <%

        var chartPts = hist.map(function (p, i) {
          return {
            x: Math.round(X(p, i)),
            label: pointLabel(p, i),
            rows: [{
              k: 'AI Visibility',
              v: p.score + '%',
              y: Math.round(Y(p.score)),
              c: 'var(--teal)',
              d: i === 0 ? null : p.score - hist[i - 1].score,
              u: ' pts'
            }]
          };
        });
      %>
      <div class="vchart-wrap">
      <svg class="chart vchart" viewBox="0 0 700 244" role="img" tabindex="0"
           data-points="<%= JSON.stringify(chartPts) %>"
           aria-label="AI Visibility over time, from <%= first.score %>% to <%= last.score %>%. Use the arrow keys to read each run.">

        <line class="ax" x1="<%= L %>" y1="<%= TOP %>" x2="<%= L %>" y2="<%= BOT %>"/>
        <line class="ax" x1="<%= L %>" y1="<%= BOT %>" x2="<%= R %>" y2="<%= BOT %>"/>

        <% [0,25,50,75,100].forEach(function(v){ %>
          <line x1="<%= L %>" y1="<%= Y(v) %>" x2="<%= R %>" y2="<%= Y(v) %>" stroke="var(--line-2)" stroke-width="1"/>
          <text class="ylab" x="<%= L - 10 %>" y="<%= Y(v) + 4 %>" text-anchor="end" font-size="11" fill="var(--muted-2)"><%= v %>%</text>
        <% }) %>

        <% if (csInside) { %>

          <line x1="<%= Math.round(csX) %>" y1="<%= TOP - 6 %>" x2="<%= Math.round(csX) %>" y2="<%= BOT %>"
                stroke="var(--navy)" stroke-width="1.5" stroke-dasharray="4 4" opacity=".55"/>
          <image href="/img/voctos-logo.png" x="<%= Math.round(Math.max(L, Math.min(R - 54, csX - 27))) %>" y="4"
                 width="54" height="23" preserveAspectRatio="xMidYMid meet"/>
          <text x="<%= Math.round(Math.max(L + 26, Math.min(R - 26, csX))) %>" y="<%= BOT + 30 %>" text-anchor="middle"
                font-size="10.5" font-weight="600" fill="var(--navy)">VOCTOS started · <%= h.date(cs) %></text>
        <% } %>

        <path d="<%= area %>" fill="var(--teal)" opacity=".07"/>
        <polyline points="<%= line %>" fill="none" stroke="var(--teal)" stroke-width="2.6"
                  stroke-linecap="round" stroke-linejoin="round"/>

        <% hist.forEach(function(p, i){ %>
          <circle cx="<%= Math.round(X(p,i)) %>" cy="<%= Math.round(Y(p.score)) %>" r="3.5"
                  fill="var(--surface)" stroke="var(--teal)" stroke-width="2"><title><%= pointLabel(p, i) %> · <%= p.score %>%</title></circle>
        <% }) %>

        <text x="<%= Math.round(Math.min(R, X(last, n-1))) %>" y="<%= Math.round(Y(last.score)) - 11 %>"
              text-anchor="end" font-size="12" font-weight="700" fill="var(--teal)"><%= last.score %>%</text>

        <% tickIdx.forEach(function(i){ var p = hist[i]; %>
          <text class="tick" x="<%= Math.round(Math.max(L, Math.min(R, X(p, i)))) %>" y="<%= BOT + 16 %>"
                text-anchor="<%= i === 0 ? 'start' : (i === n-1 ? 'end' : 'middle') %>"
                font-size="11" fill="var(--muted-2)"><%= tickLabel(p, i) %></text>
        <% }) %>

        <line class="vc-cross" x1="0" y1="<%= TOP - 8 %>" x2="0" y2="<%= BOT %>"/>
        <circle class="vc-dot" cx="0" cy="0" r="6"/>
      </svg>

        <div class="vchart-tip" hidden aria-live="polite"></div>
      </div>

      <div class="rr-meta" style="margin-top:10px">
        <% if (csInside) { %>
          The dashed line marks <%= h.date(cs) %>, when we started working together.
        <% } else if (csBefore) { %>
          Working together since <b style="color:var(--ink)"><%= h.date(cs) %></b>.
        <% } else if (cs && !spanOk) { %>
          Working together since <b style="color:var(--ink)"><%= h.date(cs) %></b>. Once a few more runs are recorded we'll mark that point on the line.
        <% } else if (!cs && _isAgency) { %>
          No contract start date set for this client. Add one in <a href="/staff/clients/<%= workspace.slug %>/edit">their settings</a> to mark it here.
        <% } %>
        <% if (!dated) { %><br>Older runs have no date, so they are spaced evenly.<% } %>
        <% if (tr && tr.filtered && n < tr.total) { %><br>Showing <b style="color:var(--ink)"><%= n %></b> of <%= tr.total %> runs.<% } %>

        <% if (tr && tr.dropped) { %><br><%= tr.dropped %> early test run<%= tr.dropped === 1 ? '' : 's' %> not shown.<% } %>
      </div>
      <% } else if (n === 1) { %>
      <div class="rr-meta" style="padding:44px 8px; text-align:center">
        <% if (tr && tr.filtered) { %>
          Only one run falls in this range, <b style="color:var(--ink)"><%= hist[0].score %>%</b> on <%= pointLabel(hist[0], 0) %>.<br>
          <% if (tr.total > 1) { %> <a href="/dashboard#trend">Show all <%= tr.total %> runs</a>.<% } %>
        <% } else { %>
          One run so far, <b style="color:var(--ink)"><%= hist[0].score %>%</b> on <%= pointLabel(hist[0], 0) %>.<br>The line appears after the next run.
        <% } %>
        <% if (tr && tr.dropped) { %><br><%= tr.dropped %> early test run<%= tr.dropped === 1 ? '' : 's' %> not shown.<% } %>
      </div>
      <% } else if (tr && tr.filtered) { %>
      <div class="rr-meta" style="padding:44px 8px; text-align:center">
        No AI Visibility runs recorded in <b style="color:var(--ink)"><%= range.label.toLowerCase() %></b> (<%= range.span %>).<br>
        <a href="/dashboard#trend">Show all <%= tr.total %> runs</a><% if(tr.earliest){ %> (the first was <%= h.date(tr.earliest) %>)<% } %>.
      </div>
      <% } else { %>
      <div class="rr-meta" style="padding:44px 8px; text-align:center">The trend builds as AI Visibility runs. Run it a few times to see the line here.</div>
      <% } %>
    </div>
  </div>

  <%

    var overdue = invoice && invoice.dueDate && new Date(invoice.dueDate) < new Date();
  %>

  <div class="card card-p rr b6" id="dash-invoice-card"<%= invoice ? '' : ' hidden' %>>
  <% if (invoice) { %>
    <div class="row-between"><div class="rr-lbl">Current invoice</div><span class="tag <%= overdue ? 'overdue' : 'pending' %>"><%= overdue ? 'Overdue' : 'Pending' %></span></div>
    <div style="margin-top:10px"><div class="inv-amt tnum"><%= h.money(invoice.amount, invoice.currency || (locals.workspace && locals.workspace.subscription && locals.workspace.subscription.currency)) %></div><div class="rr-meta" style="margin-top:2px"><%= invoice.number %> · due <%= h.date(invoice.dueDate) %></div></div>

    <div class="rr-actions"><% if(_isAgency){ %><form method="POST" action="/api/invoices/<%= invoice._id %>/pay" class="js-ajax-form" data-refresh="#dash-invoice-card" style="flex:1"><button class="btn btn-primary btn-sm" style="width:100%">Mark paid</button></form><% } %><a class="btn btn-primary btn-sm" style="flex:1" href="/invoices">View invoice</a></div>
  <% } %>
  </div>

  <div class="card card-p rr b6">

    <div class="row-between"><div class="rr-lbl">Delivery</div><span class="rr-meta">all tasks</span></div>
    <div class="rr-3" style="--rr-n:<%= _delivery.length %>">
      <% _delivery.forEach(function (d) { %>
        <div>

          <div class="rr-3-v tnum"><%= d.v == null ? '—' : d.v %></div>
          <div class="rr-3-l"><%= d.l %></div>
          <div class="rr-meta"><%= d.m %></div>
        </div>
      <% }) %>
    </div>

    <div class="rr-actions"><a class="btn btn-primary btn-sm" style="flex:1" href="/tasks">View tasks</a></div>
  </div>

  <% if (report) { %>
  <div class="card card-p rr b6">
    <div class="rr-lbl">Latest report</div>
    <div class="rr-title"><%= report.title %></div>
    <%

      var rf = (report.files || []).slice();
      if (report.fileUrl && !rf.some(function(f){ return f.url === report.fileUrl; })) rf.unshift({ url: report.fileUrl, name: report.title, size: report.fileSize });

      var rfF = rf.filter(function(f){ return !f.link; }).length, rfL = rf.length - rfF;
      var rb = [];
      if (rfF) rb.push(rfF + ' file' + (rfF === 1 ? '' : 's'));
      if (rfL) rb.push(rfL + ' link' + (rfL === 1 ? '' : 's'));
      if (report.publishedAt) rb.push(h.date(report.publishedAt));
    %>
    <div class="rr-meta"><%= rb.join(', ') %></div>
    <div class="rr-actions">
      <a class="btn btn-primary btn-sm" style="flex:1" href="/reports">Open folder</a>

      <% if(rf.length === 1 && !rf[0].link){ %><a class="btn btn-sm" style="flex:1" href="<%= rf[0].url %>" download="<%= rf[0].name || '' %>">Download</a>
      <% } else if(rf.length === 1){ %><a class="btn btn-sm" style="flex:1" href="<%= rf[0].url %>" target="_blank" rel="noopener">Open ↗</a><% } %>
    </div>
  </div>
  <% } %>

</div>
<%

  var srcs = [];
  if (workspace && workspace.gscSiteUrl) srcs.push('Search Console');
  if (workspace && workspace.ga4PropertyId) srcs.push('GA4');
  if (workspace && workspace.websiteDomain) srcs.push('Semrush');
  if (vis.platforms && vis.platforms.length) srcs.push('the AI engines');
%>
<div class="foot-note">VOCTOS Client Portal · <%= workspace ? workspace.name : '' %> workspace<%= srcs.length ? ' · synced from ' + srcs.join(', ') : ' · no data sources connected yet' %></div>
