<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  <title>eli foner</title>
  <link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><rect width='100' height='100' fill='%230a0a0a'/></svg>">
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@200;300;400;500&display=swap" rel="stylesheet">
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }

    body {
      font-family: 'JetBrains Mono', monospace;
      background: #0a0a0a;
      color: #d4d0ca;
      min-height: 100dvh;
      overflow: hidden;
      touch-action: none;
    }

    .scene { position: fixed; top: 2.5rem; left: 2.5rem; z-index: 1; }

    .line { overflow: hidden; }
    .line-inner {
      transform: translateY(105%);
      animation: reveal 0.9s cubic-bezier(0.16, 1, 0.3, 1) 0.3s forwards;
    }

    .name {
      font-weight: 200;
      font-size: clamp(1rem, 2vw, 1.125rem);
      letter-spacing: -0.02em;
      line-height: 1.4;
      color: #ede9e3;
    }

    .stats {
      position: fixed;
      bottom: 2.5rem;
      left: 2.5rem;
      z-index: 1;
      font-weight: 300;
      font-size: 0.6875rem;
      letter-spacing: 0.02em;
      color: #5a5650;
      display: flex;
      flex-direction: column;
      gap: 0.25rem;
      opacity: 0;
      animation: fadeIn 1.2s ease 1.2s forwards;
    }

    .stats-header {
      color: #ede9e3;
      margin-bottom: 0.15rem;
      white-space: nowrap;
      display: flex;
      align-items: center;
      gap: 0.5rem;
      cursor: pointer;
      -webkit-user-select: none;
      user-select: none;
    }

    .stats-details {
      display: grid;
      grid-template-rows: 0fr;
      transition: grid-template-rows 0.3s ease;
    }
    .stats-details.open { grid-template-rows: 1fr; }
    .stats-details-inner {
      overflow: hidden;
      display: flex;
      flex-direction: column;
      gap: 0.25rem;
    }

    .status-dot {
      width: 6px;
      height: 6px;
      border-radius: 50%;
      background: #34d399;
      box-shadow: 0 0 8px #34d399;
      animation: pulse 2s ease-in-out infinite;
      flex-shrink: 0;
    }

    .stats .label {
      color: #8a847b;
      display: inline-block;
      width: 10ch;
    }

    @keyframes reveal { to { transform: translateY(0); } }
    @keyframes fadeIn { to { opacity: 1; } }
    @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.6; } }

    @media (max-width: 640px) {
      .scene { top: 1.5rem; left: 1.5rem; }
      .stats { bottom: 1.5rem; left: 1.5rem; font-size: 0.5625rem; }
    }
  </style>
</head>
<body>
  <div class="scene">
    <div class="name">
      <div class="line"><div class="line-inner">eli.foner.com</div></div>
    </div>
  </div>

  <div class="stats">
    <span class="stats-header" id="stats-toggle"><span class="status-dot"></span> visitor imprint</span>
    <div class="stats-details" id="stats-details">
      <div class="stats-details-inner">
        <span id="device-line"></span>
        <span id="location-line"></span>
        <span id="network-line"></span>
      </div>
    </div>
  </div>

  <script>
    // visitor imprint
    const touch = navigator.maxTouchPoints > 0;
    const sw = screen.width, sh = screen.height;
    const ua = navigator.userAgent;
    const plat = navigator.userAgentData?.platform || navigator.platform || '';
    const device = /iPhone/.test(ua) ? 'iPhone'
      : /iPad/.test(ua) ? 'iPad'
      : /Android/.test(ua) ? (Math.min(sw, sh) >= 768 ? 'android tablet' : 'android')
      : /Mac/.test(plat) ? 'macOS'
      : /Win/.test(plat) ? 'windows'
      : /Linux/.test(plat) ? 'linux'
      : touch ? 'mobile' : 'desktop';
    const tz = new Date().toLocaleTimeString('en-US', { timeZoneName: 'short' }).split(' ').pop();

    function line(id, label, parts) {
      const vals = parts.filter(Boolean);
      if (vals.length) document.getElementById(id).innerHTML =
        `<span class="label">${label}</span>${vals.join(' \u00b7 ')}`;
    }

    let gpu = '';
    try {
      const gl = document.createElement('canvas').getContext('webgl');
      if (gl) {
        const ext = gl.getExtension('WEBGL_debug_renderer_info');
        if (ext) {
          gpu = gl.getParameter(ext.UNMASKED_RENDERER_WEBGL)
            .replace(/^ANGLE\s*\([^,]+,\s*/, '').replace(/,\s*[^)]*\)$/, '')
            .replace(/^ANGLE\s+[\w\s]+Renderer:\s*/i, '')
            .replace(/\(TM\)|\(R\)/gi, '').trim();
          if (/^Apple/i.test(gpu) && !/M\d/.test(gpu)) gpu = '';
        }
      }
    } catch {}

    const cores = navigator.hardwareConcurrency || '?';
    line('device-line', 'device', [device, gpu, `${cores} cores`, `${sw}x${sh} @${devicePixelRatio}x`]);

    (async () => {
      try {
        if (!navigator.getBattery) return;
        const b = await navigator.getBattery();
        if (b.charging && b.level === 1) return;
        const pct = Math.round(b.level * 100) + '%';
        document.getElementById('device-line').innerHTML +=
          ` \u00b7 ${b.charging ? pct + ' charging' : pct + ' battery'}`;
      } catch {}
    })();

    fetch('/api/visitor').then(r => r.json()).then(d => {
      const loc = [];
      const place = [d.city, d.regionCode || d.region].filter(Boolean).join(', ');
      if (place) loc.push(place);
      if (d.postal) loc.push(d.postal);
      if (d.lat && d.lon) {
        loc.push(Math.abs(d.lat).toFixed(2) + '\u00b0' + (d.lat >= 0 ? 'N' : 'S')
          + ' ' + Math.abs(d.lon).toFixed(2) + '\u00b0' + (d.lon >= 0 ? 'E' : 'W'));
      }
      loc.push(tz);
      line('location-line', 'location', loc);
      const net = [d.ip, d.proto, d.asn];
      if (d.tls) net.push('tls ' + d.tls);
      line('network-line', 'network', net);
    }).catch(() => {
      line('location-line', 'location', [tz]);
      line('network-line', 'network', ['unavailable']);
    });

    // toggle visitor imprint details
    document.getElementById('stats-toggle').addEventListener('click', () => {
      document.getElementById('stats-details').classList.toggle('open');
    });

    // iOS Safari ignores touch-action for zoom — JS required
    document.addEventListener('gesturestart', e => e.preventDefault());
    document.addEventListener('gesturechange', e => e.preventDefault());
    let last = 0;
    document.addEventListener('touchend', e => {
      if (Date.now() - last <= 300) e.preventDefault();
      last = Date.now();
    }, false);
  </script>
</body>
</html>
