PageSourceSearch

https://arcnautical.com/

html arcnautical.com collected 2026-10-03 18:20:29 UTC 236,211 bytes, 4,829 lines download raw bytes

1<!DOCTYPE html>
2<html lang="en">
3<head>
4  <meta charset="UTF-8">
5  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6  <meta name="yandex-verification" content="30c101154cf20748" />
7  <meta name="naver-site-verification" content="e7a0092bbb012fac0c72ce9bb9054e0b02f7e67e" />
8  <title>ArcNautical — Vessel Sanctions &amp; Ownership Screening</title>
9  <meta name="description" content="Screen any vessel for sanctions and ownership-chain exposure — checked against OFAC, EU, UN, and the GLEIF ownership registry. Plus voyage risk scoring, vetting grades, fleet monitoring, and automated PDF reports for maritime insurers, charterers, and traders.">
10  <meta name="keywords" content="maritime intelligence, voyage risk, war risk premium, P&I club, hull machinery, marine insurance, JWC listed areas, piracy risk, AIS monitoring, vessel tracking, fleet management, Monte Carlo, sanctions screening, CII rating, PML, underwriting">
11  <meta property="og:title" content="ArcNautical — Vessel Sanctions &amp; Ownership Screening">
12  <meta property="og:description" content="Screen any vessel before you fix, insure, or finance it. Sanctions, ownership exposure, and a vetting grade for any IMO — checked against OFAC, EU, UN, and the ownership chain. Free vessel check, no signup.">
13  <meta property="og:type" content="website">
14  <meta property="og:url" content="https://arcnautical.com/">
15  <meta property="og:image" content="https://arcnautical.com/og-image.png">
16  <meta property="og:image:width" content="1200">
17  <meta property="og:image:height" content="630">
18  <meta name="twitter:card" content="summary_large_image">
19  <meta name="twitter:image" content="https://arcnautical.com/og-image.png">
20  <meta name="theme-color" content="#070a10">
21  <link rel="canonical" href="https://arcnautical.com/">
22  <link rel="alternate" hreflang="ko-KR" href="https://arcnautical.com/ko/">
23  <link rel="icon" type="image/svg+xml" href="/logo.svg" />
24  <link rel="preconnect" href="https://fonts.googleapis.com">
25  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
26  <link href="https://fonts.googleapis.com/css2?family=DM+Serif+Display:ital@0;1&family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
27  <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" crossorigin="">
28  
28<script src="/posthog-init.js" defer></script>
28
29  
29<script src="/lane-capture.js" defer></script>
29
30  
30<script src="/api-access.js?v=20260730" defer></script>
30
31  <style>
32    /* ================================================================
33       RESET & BASE
34       ================================================================ */
35    *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
36    html { scroll-behavior: smooth; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
37    body {
38      background: #070a10;
39      color: #d0d8e8;
40      font-family: 'Inter', system-ui, -apple-system, sans-serif;
41      line-height: 1.6;
42      overflow-x: hidden;
43    }
44    img { max-width: 100%; display: block; }
45    a { color: inherit; text-decoration: none; }
46    h2, h3 { font-weight: inherit; font-size: inherit; }
47
48    /* ================================================================
49       DESIGN TOKENS
50       ================================================================ */
51    :root {
52      --bg: #070a10;
53      --surface: #0d1420;
54      --surface-el: #152030;
55      --border: #1c2a3e;
56      --text: #d0d8e8;
57      --text-sec: #7e8fa6;
58      --text-dim: #445068;
59      --accent: #0891b2;
60      --accent-hover: #06b6d4;
61      --risk-low: #059669;
62      --risk-mod: #818cf8;
63      --risk-elev: #d97706;
64      --risk-high: #ea580c;
65      --risk-crit: #dc2626;
66      --mono: 'JetBrains Mono', 'Cascadia Code', 'Fira Code', monospace;
67      --display: 'DM Serif Display', 'Georgia', serif;
68      --body: 'Inter', system-ui, sans-serif;
69    }
70
71    /* ================================================================
72       UTILITY
73       ================================================================ */
74    .container { max-width: 1200px; margin: 0 auto; padding: 0 24px; }
75    .mono { font-family: var(--mono); }
76    .text-dim { color: var(--text-dim); }
77    .text-sec { color: var(--text-sec); }
78    .text-accent { color: var(--accent); }
79
80    /* Scroll-triggered reveal */
81    .reveal {
82      opacity: 0;
83      transform: translateY(30px);
84      transition: opacity 0.7s cubic-bezier(0.16, 1, 0.3, 1), transform 0.7s cubic-bezier(0.16, 1, 0.3, 1);
85    }
86    .reveal.visible { opacity: 1; transform: translateY(0); }
87    .reveal-delay-1 { transition-delay: 0.1s; }
88    .reveal-delay-2 { transition-delay: 0.2s; }
89    .reveal-delay-3 { transition-delay: 0.3s; }
90    .reveal-delay-4 { transition-delay: 0.4s; }
91    .reveal-delay-5 { transition-delay: 0.5s; }
92
93    /* ================================================================
94       SCROLL PROGRESS
95       ================================================================ */
96    .scroll-progress {
97      position: fixed;
98      top: 0;
99      left: 0;
100      height: 2px;
101      width: 0%;
102      background: linear-gradient(90deg, var(--accent), var(--accent-hover));
103      z-index: 1001;
104      transition: width 0.05s linear;
105    }
106
107    /* ================================================================
108       NAVIGATION
109       ================================================================ */
110    .nav {
111      position: fixed;
112      top: 2px;
113      left: 0;
114      right: 0;
115      z-index: 1000;
116      background: rgba(12, 14, 18, 0.85);
117      backdrop-filter: blur(12px);
118      -webkit-backdrop-filter: blur(12px);
119      border-bottom: 1px solid rgba(42, 47, 58, 0.5);
120      transition: background 0.3s;
121    }
122    .nav-inner {
123      max-width: 1200px;
124      margin: 0 auto;
125      padding: 0 24px;
126      height: 56px;
127      display: flex;
128      align-items: center;
129      justify-content: space-between;
130    }
131    .nav-brand {
132      display: flex;
133      align-items: center;
134      gap: 10px;
135      font-family: var(--mono);
136      font-weight: 600;
137      font-size: 14px;
138      letter-spacing: 2.5px;
139      color: var(--text);
140    }
141    .nav-brand-mark {
142      width: 24px;
143      height: 24px;
144      object-fit: contain;
145    }
146    .nav-links {
147      display: flex;
148      align-items: center;
149      gap: 28px;
150      list-style: none;
151    }
152    .nav-links a {
153      font-size: 13px;
154      font-weight: 500;
155      color: var(--text-sec);
156      transition: color 0.2s;
157      letter-spacing: 0.02em;
158    }
159    .nav-links a:hover { color: var(--text); }
160    .nav-cta {
161      font-size: 13px;
162      font-weight: 600;
163      padding: 8px 20px;
164      background: var(--accent);
165      color: #fff;
166      border-radius: 4px;
167      transition: background 0.2s, transform 0.2s;
168      letter-spacing: 0.02em;
169    }
170    .nav-cta:hover { background: var(--accent-hover); transform: translateY(-1px); }
171    /* `.nav-links a` (0,1,1) outranks `.nav-cta` (0,1,0), so the CTA inherited the grey link colour: 1.12:1 on teal (measured 2026-09-23). */
172    .nav-links a.nav-cta, .nav-links a.nav-cta:hover { color: #fff; }
173    .nav-signin {
174      font-size: 13px;
175      font-weight: 600;
176      padding: 8px 16px;
177      border: 1px solid rgba(255,255,255,0.18);
178      border-radius: 4px;
179      transition: border-color 0.2s, color 0.2s;
180      letter-spacing: 0.02em;
181    }
182    .nav-signin:hover { border-color: var(--accent); color: var(--accent) !important; }
183
184    /* Hamburger */
185    .nav-hamburger {
186      display: none;
187      flex-direction: column;
188      gap: 5px;
189      background: none;
190      border: none;
191      cursor: pointer;
192      padding: 4px;
193    }
194    .nav-hamburger span {
195      display: block;
196      width: 22px;
197      height: 2px;
198      background: var(--text-sec);
199      border-radius: 1px;
200      transition: transform 0.3s, opacity 0.3s;
201    }
202    .nav-hamburger.open span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
203    .nav-hamburger.open span:nth-child(2) { opacity: 0; }
204    .nav-hamburger.open span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
205
206    @media (max-width: 768px) {
207      .nav-links {
208        display: none;
209        position: absolute;
210        top: 56px;
211        left: 0;
212        right: 0;
213        flex-direction: column;
214        background: rgba(12, 14, 18, 0.97);
215        backdrop-filter: blur(16px);
216        padding: 24px;
217        gap: 20px;
218        border-bottom: 1px solid var(--border);
219      }
220      .nav-links.open { display: flex; }
221      .nav-hamburger { display: flex; }
222    }
223
224    /* ================================================================
225       HERO
226       ================================================================ */
227    .hero {
228      position: relative;
229      min-height: 100vh;
230      display: flex;
231      align-items: center;
232      padding-top: 58px;
233      overflow: hidden;
234    }
235    .hero-grid {
236      position: absolute;
237      inset: 0;
238      background-image:
239        linear-gradient(rgba(59, 130, 246, 0.03) 1px, transparent 1px),
240        linear-gradient(90deg, rgba(59, 130, 246, 0.03) 1px, transparent 1px);
241      background-size: 60px 60px;
242      animation: gridDrift 20s linear infinite;
243      pointer-events: none; /* decorative; same reason as .hero-routes below */
244    }
245    @keyframes gridDrift {
246      0% { background-position: 0 0; }
247      100% { background-position: 60px 60px; }
248    }
249    /* Decorative, like .hero-grain and .hero-glow below — and like them it must
250       not eat clicks. It is position:absolute inside #hero, so it paints above
251       every UNPOSITIONED descendant, and #scorerResults is one. Without this the
252       whole lane-result panel is click-dead: share, score-again, and the
253       lane-brief email capture all sit under it. .hero-content escapes only
254       because it sets z-index:2. */
255    .hero-routes {
256      position: absolute;
257      inset: 0;
258      opacity: 0.12;
259      pointer-events: none;
260    }
261    .hero-routes svg { width: 100%; height: 100%; }
262    .hero-grain {
263      position: absolute;
264      inset: 0;
265      opacity: 0.035;
266      background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
267      background-repeat: repeat;
268      background-size: 256px 256px;
269      pointer-events: none;
270    }
271    .hero-glow {
272      position: absolute;
273      top: -20%;
274      right: -10%;
275      width: 70%;
276      height: 70%;
277      background: radial-gradient(circle, rgba(59, 130, 246, 0.06) 0%, transparent 70%);
278      pointer-events: none;
279    }
280    .hero-content {
281      position: relative;
282      z-index: 2;
283      display: grid;
284      grid-template-columns: 1fr 1fr;
285      gap: 64px;
286      align-items: center;
287      padding: 80px 0;
288    }
289    .hero-text h1 {
290      font-family: var(--display);
291      font-size: clamp(2.4rem, 4.5vw, 3.6rem);
292      line-height: 1.15;
293      color: var(--text);
294      margin-bottom: 24px;
295      font-weight: 400;
296    }
297    .hero-text h1 em { font-style: italic; color: var(--accent); }
298    .hero-text .hero-sub {
299      font-size: 17px;
300      color: var(--text-sec);
301      line-height: 1.7;
302      margin-bottom: 40px;
303      max-width: 520px;
304    }
305    .hero-actions { display: flex; gap: 16px; flex-wrap: wrap; }
306    .btn-primary {
307      display: inline-flex;
308      align-items: center;
309      gap: 8px;
310      padding: 14px 32px;
311      background: var(--accent);
312      color: #fff;
313      font-size: 14px;
314      font-weight: 600;
315      border-radius: 4px;
316      border: none;
317      cursor: pointer;
318      transition: background 0.2s, transform 0.15s, box-shadow 0.2s;
319      letter-spacing: 0.02em;
320    }
321    .btn-primary:hover {
322      background: var(--accent-hover);
323      transform: translateY(-2px);
324      box-shadow: 0 8px 24px rgba(59, 130, 246, 0.25);
325    }
326    .btn-ghost {
327      display: inline-flex;
328      align-items: center;
329      gap: 8px;
330      padding: 14px 32px;
331      background: transparent;
332      color: var(--text-sec);
333      font-size: 14px;
334      font-weight: 500;
335      border-radius: 4px;
336      border: 1px solid var(--border);
337      cursor: pointer;
338      transition: border-color 0.2s, color 0.2s, transform 0.15s;
339      letter-spacing: 0.02em;
340    }
341    .btn-ghost:hover {
342      border-color: var(--text-dim);
343      color: var(--text);
344      transform: translateY(-2px);
345    }
346
347    .hero-visual {
348      position: relative;
349      display: flex;
350      flex-direction: column;
351      align-items: center;
352      gap: 24px;
353    }
354    .hero-gauge-wrap { position: relative; }
355    .hero-route-card {
356      background: var(--surface);
357      border: 1px solid var(--border);
358      border-radius: 6px;
359      padding: 16px 20px;
360      width: 100%;
361      max-width: 380px;
362    }
363    .hero-route-label {
364      font-family: var(--mono);
365      font-size: 11px;
366      color: var(--text-dim);
367      text-transform: uppercase;
368      letter-spacing: 0.1em;
369      margin-bottom: 8px;
370    }
371    .hero-route-ports {
372      font-family: var(--mono);
373      font-size: 15px;
374      color: var(--text);
375      font-weight: 600;
376      margin-bottom: 6px;
377    }
378    .hero-route-meta {
379      font-family: var(--mono);
380      font-size: 11px;
381      color: var(--text-dim);
382    }
383    .hero-route-waypoints {
384      display: flex;
385      align-items: center;
386      gap: 6px;
387      margin-top: 10px;
388      flex-wrap: wrap;
389    }
390    .hero-waypoint {
391      font-family: var(--mono);
392      font-size: 10px;
393      color: var(--text-sec);
394      background: var(--surface-el);
395      padding: 2px 8px;
396      border-radius: 3px;
397    }
398    .hero-waypoint-arrow { color: var(--text-dim); font-size: 10px; }
399
400    /* Hero cycling preview */
401    .hero-preview {
402      width: 100%;
403      max-width: 380px;
404      height: 42px;
405      position: relative;
406      overflow: hidden;
407    }
408    .hero-preview-item {
409      position: absolute;
410      inset: 0;
411      display: flex;
412      align-items: center;
413      gap: 10px;
414      padding: 8px 14px;
415      background: rgba(8, 145, 178, 0.06);
416      border: 1px solid rgba(8, 145, 178, 0.15);
417      border-radius: 4px;
418      opacity: 0;
419      transform: translateY(8px);
420      transition: opacity 0.4s, transform 0.4s;
421    }
422    .hero-preview-item.active {
423      opacity: 1;
424      transform: translateY(0);
425    }
426    .hero-preview-icon {
427      width: 20px;
428      height: 20px;
429      flex-shrink: 0;
430    }
431    .hero-preview-icon svg {
432      width: 20px;
433      height: 20px;
434      stroke: var(--accent);
435      fill: none;
436      stroke-width: 1.5;
437      stroke-linecap: round;
438      stroke-linejoin: round;
439    }
440    .hero-preview-text {
441      font-family: var(--mono);
442      font-size: 11px;
443      color: var(--text-sec);
444    }
445    .hero-preview-text strong { color: var(--text); font-weight: 600; }
446
447    @media (max-width: 900px) {
448      .hero-content { grid-template-columns: 1fr; gap: 40px; text-align: center; }
449      .hero-text .hero-sub { margin-left: auto; margin-right: auto; }
450      .hero-actions { justify-content: center; }
451      .hero-visual { order: -1; }
452    }
453
454    /* ================================================================
455       METRICS BAR
456       ================================================================ */
457    .proof {
458      border-top: 1px solid var(--border);
459      border-bottom: 1px solid var(--border);
460      background: var(--surface);
461      padding: 48px 0;
462    }
463    .proof-label {
464      text-align: center;
465      font-size: 13px;
466      color: var(--text-dim);
467      letter-spacing: 0.08em;
468      text-transform: uppercase;
469      margin-bottom: 32px;
470    }
471    .proof-grid {
472      display: grid;
473      grid-template-columns: repeat(6, 1fr);
474      gap: 24px;
475      text-align: center;
476    }
477    .proof-metric {
478      display: flex;
479      flex-direction: column;
480      align-items: center;
481      gap: 6px;
482    }
483    .proof-number {
484      font-family: var(--mono);
485      font-size: 32px;
486      font-weight: 600;
487      color: var(--text);
488      line-height: 1;
489    }
490    .proof-desc {
491      font-size: 12px;
492      color: var(--text-sec);
493      font-weight: 500;
494    }
495
496    @media (max-width: 900px) {
497      .proof-grid { grid-template-columns: repeat(3, 1fr); gap: 24px; }
498    }
499    @media (max-width: 600px) {
500      .proof-grid { grid-template-columns: repeat(2, 1fr); gap: 20px; }
501      .proof-number { font-size: 26px; }
502    }
503
504    /* ================================================================
505       HOW IT WORKS
506       ================================================================ */
507    .hiw-section {
508      padding: 80px 0;
509      background: var(--bg);
510      border-bottom: 1px solid var(--border);
511    }
512    .hiw-inner {
513      max-width: 860px;
514      margin: 0 auto;
515    }
516    .hiw-steps {
517      display: grid;
518      grid-template-columns: repeat(4, 1fr);
519      gap: 24px;
520      margin-bottom: 48px;
521    }
522    .hiw-step {
523      position: relative;
524      background: var(--surface);
525      border: 1px solid var(--border);
526      border-radius: 8px;
527      padding: 28px 20px 24px;
528      text-align: center;
529    }
530    .hiw-step-num {
531      display: inline-flex;
532      align-items: center;
533      justify-content: center;
534      width: 32px;
535      height: 32px;
536      border-radius: 50%;
537      background: rgba(8, 145, 178, 0.1);
538      border: 1px solid rgba(8, 145, 178, 0.3);
539      font-family: var(--mono);
540      font-size: 13px;
541      font-weight: 700;
542      color: var(--accent);
543      margin-bottom: 16px;
544    }
545    .hiw-step-title {
546      font-family: var(--heading);
547      font-size: 18px;
548      color: var(--text);
549      margin-bottom: 8px;
550    }
551    .hiw-step-desc {
552      font-size: 13px;
553      color: var(--text-dim);
554      line-height: 1.6;
555    }
556    .hiw-step-connector {
557      display: none;
558    }
559    @media (min-width: 601px) {
560      .hiw-step-connector {
561        display: block;
562        position: absolute;
563        top: 42px;
564        right: -14px;
565        color: var(--border);
566        font-size: 14px;
567        z-index: 1;
568      }
569    }
570    .hiw-built-for {
571      text-align: center;
572      margin-bottom: 36px;
573    }
574    .hiw-personas {
575      display: flex;
576      align-items: center;
577      justify-content: center;
578      gap: 24px;
579      flex-wrap: wrap;
580      margin-top: 16px;
581    }
582    .hiw-persona {
583      display: flex;
584      align-items: center;
585      gap: 8px;
586      font-size: 13px;
587      color: var(--text-sec);
588    }
589    .hiw-persona-icon {
590      width: 16px;
591      height: 16px;
592      flex-shrink: 0;
593      opacity: 0.6;
594    }
595    .hiw-persona-icon svg {
596      width: 16px;
597      height: 16px;
598      stroke: var(--accent);
599      fill: none;
600      stroke-width: 1.5;
601      stroke-linecap: round;
602      stroke-linejoin: round;
603    }
604    .hiw-persona-workflow {
605      font-family: var(--mono);
606      font-size: 11px;
607      color: var(--text-dim);
608      margin-top: 2px;
609    }
610    .hiw-cta {
611      display: flex;
612      align-items: center;
613      justify-content: center;
614      gap: 16px;
615      flex-wrap: wrap;
616    }
617    .hiw-free-note {
618      text-align: center;
619      font-family: var(--mono);
620      font-size: 11px;
621      color: var(--text-dim);
622      margin-top: 16px;
623      letter-spacing: 0.03em;
624    }
625
626    @media (max-width: 600px) {
627      .hiw-steps { grid-template-columns: 1fr; gap: 16px; }
628      .hiw-personas { flex-direction: column; gap: 12px; }
629    }
630
631    /* ================================================================
632       INTELLIGENCE TICKER
633       ================================================================ */
634    .ticker-section {
635      padding: 32px 0;
636      background: var(--bg);
637      border-bottom: 1px solid var(--border);
638      overflow: hidden;
639    }
640    .ticker-header {
641      display: flex;
642      align-items: center;
643      gap: 10px;
644      margin-bottom: 16px;
645      padding: 0 24px;
646    }
647    .ticker-dot {
648      width: 6px;
649      height: 6px;
650      background: var(--risk-low);
651      border-radius: 50%;
652      animation: tickerPulse 2s ease-in-out infinite;
653    }
654    @keyframes tickerPulse {
655      0%, 100% { opacity: 1; }
656      50% { opacity: 0.3; }
657    }
658    .ticker-title {
659      font-family: var(--mono);
660      font-size: 11px;
661      color: var(--text-dim);
662      text-transform: uppercase;
663      letter-spacing: 0.12em;
664    }
665    .ticker-track {
666      display: flex;
667      animation: tickerScroll 80s linear infinite;
668      width: max-content;
669    }
670    .ticker-track:hover { animation-play-state: paused; }
671    @keyframes tickerScroll {
672      0% { transform: translateX(0); }
673      100% { transform: translateX(-50%); }
674    }
675    .ticker-item {
676      display: flex;
677      align-items: stretch;
678      background: var(--surface);
679      border: 1px solid var(--border);
680      border-radius: 4px;
681      margin-right: 12px;
682      flex-shrink: 0;
683      min-width: 400px;
684      overflow: hidden;
685      transition: border-color 0.2s;
686    }
687    .ticker-item:hover { border-color: var(--text-dim); }
688    .ticker-accent { width: 3px; flex-shrink: 0; }
689    .ticker-accent[data-type="navwarn"] { background: var(--risk-elev); }
690    .ticker-accent[data-type="piracy"] { background: var(--risk-crit); }
691    .ticker-accent[data-type="jwc"] { background: var(--accent); }
692    .ticker-accent[data-type="ais"] { background: #a78bfa; }
693    .ticker-accent[data-type="risk"] { background: var(--risk-low); }
694    .ticker-accent[data-type="weather"] { background: #38bdf8; }
695    .ticker-accent[data-type="sanctions"] { background: #f472b6; }
696    .ticker-accent[data-type="disaster"] { background: var(--risk-high); }
697    .ticker-body {
698      padding: 10px 14px;
699      display: flex;
700      flex-direction: column;
701      gap: 3px;
702      flex: 1;
703    }
704    .ticker-type {
705      font-family: var(--mono);
706      font-size: 10px;
707      font-weight: 600;
708      letter-spacing: 0.08em;
709      text-transform: uppercase;
710    }
711    .ticker-type[data-type="navwarn"] { color: var(--risk-elev); }
712    .ticker-type[data-type="piracy"] { color: var(--risk-crit); }
713    .ticker-type[data-type="jwc"] { color: var(--accent); }
714    .ticker-type[data-type="ais"] { color: #a78bfa; }
715    .ticker-type[data-type="risk"] { color: var(--risk-low); }
716    .ticker-type[data-type="weather"] { color: #38bdf8; }
717    .ticker-type[data-type="sanctions"] { color: #f472b6; }
718    .ticker-type[data-type="disaster"] { color: var(--risk-high); }
719    .ticker-msg {
720      font-family: var(--mono);
721      font-size: 12px;
722      color: var(--text-sec);
723      line-height: 1.4;
724      white-space: nowrap;
725    }
726    .ticker-time {
727      font-family: var(--mono);
728      font-size: 10px;
729      color: var(--text-dim);
730    }
731
732    /* ================================================================
733       SECTION SHARED
734       ================================================================ */
735    .section { padding: 100px 0; }
736    .section-label {
737      font-family: var(--mono);
738      font-size: 11px;
739      color: var(--accent);
740      text-transform: uppercase;
741      letter-spacing: 0.15em;
742      margin-bottom: 12px;
743    }
744    .section-title {
745      font-family: var(--display);
746      font-size: clamp(1.8rem, 3vw, 2.4rem);
747      line-height: 1.2;
748      margin-bottom: 20px;
749      color: var(--text);
750      font-weight: 400;
751    }
752    .section-desc {
753      font-size: 16px;
754      color: var(--text-sec);
755      line-height: 1.7;
756      max-width: 600px;
757      margin-bottom: 32px;
758    }
759    .section-center { text-align: center; margin-bottom: 56px; }
760    .section-center .section-desc { margin-left: auto; margin-right: auto; }
761    .section-divider { height: 1px; background: linear-gradient(90deg, transparent, var(--border), transparent); }
762
763    /* ================================================================
764       "10 SIGNALS, ONE SCORE" — SIGNAL CONVERGENCE
765       ================================================================ */
766    .signals-section {
767      background: var(--surface);
768      border-top: 1px solid var(--border);
769      border-bottom: 1px solid var(--border);
770    }
771    .signals-layout {
772      display: grid;
773      grid-template-columns: 1fr 1fr;
774      gap: 64px;
775      align-items: center;
776    }
777    .signals-svg-wrap {
778      position: relative;
779      width: 100%;
780      max-width: 480px;
781      margin: 0 auto;
782    }
783    .signals-svg-wrap svg { width: 100%; height: auto; }
784    .signal-node {
785      opacity: 0;
786      transition: opacity 0.5s ease;
787    }
788    .signal-node.visible { opacity: 1; }
789    .signal-line {
790      stroke-dasharray: 200;
791      stroke-dashoffset: 200;
792      transition: stroke-dashoffset 0.8s ease;
793    }
794    .signal-line.drawn { stroke-dashoffset: 0; }
795    .signal-list {
796      list-style: none;
797      display: grid;
798      grid-template-columns: 1fr 1fr;
799      gap: 10px;
800    }
801    .signal-item {
802      display: flex;
803      align-items: center;
804      gap: 10px;
805      font-size: 13px;
806      color: var(--text-sec);
807      padding: 8px 12px;
808      background: var(--bg);
809      border: 1px solid var(--border);
810      border-radius: 4px;
811      transition: border-color 0.2s;
812    }
813    .signal-item:hover { border-color: var(--text-dim); }
814    .signal-dot {
815      width: 8px;
816      height: 8px;
817      border-radius: 2px;
818      flex-shrink: 0;
819    }
820    .signal-num {
821      font-family: var(--mono);
822      font-size: 10px;
823      color: var(--text-dim);
824      margin-left: auto;
825      flex-shrink: 0;
826    }
827
828    @media (max-width: 900px) {
829      .signals-layout { grid-template-columns: 1fr; gap: 40px; }
830      .signal-list { grid-template-columns: 1fr; }
831    }
832
833    /* ================================================================
834       DATA SOURCES BANNER
835       ================================================================ */
836    .sources-banner {
837      border-bottom: 1px solid var(--border);
838      padding: 40px 0;
839      background: var(--bg);
840    }
841    .sources-label {
842      text-align: center;
843      font-family: var(--mono);
844      font-size: 10px;
845      color: var(--text-dim);
846      text-transform: uppercase;
847      letter-spacing: 0.14em;
848      margin-bottom: 20px;
849    }
850    .sources-categories {
851      display: flex;
852      flex-direction: column;
853      gap: 16px;
854    }
855    .sources-cat-label {
856      font-family: var(--mono);
857      font-size: 9px;
858      color: var(--text-dim);
859      text-transform: uppercase;
860      letter-spacing: 0.12em;
861      width: 100px;
862      flex-shrink: 0;
863      padding-top: 8px;
864    }
865    .sources-cat-row {
866      display: flex;
867      align-items: center;
868      gap: 12px;
869      flex-wrap: wrap;
870    }
871    .source-badge {
872      display: flex;
873      align-items: center;
874      gap: 8px;
875      padding: 6px 14px;
876      background: var(--surface);
877      border: 1px solid var(--border);
878      border-radius: 4px;
879      transition: border-color 0.2s;
880    }
881    .source-badge:hover { border-color: var(--text-dim); }
882    .source-badge-icon {
883      width: 8px;
884      height: 8px;
885      border-radius: 2px;
886      flex-shrink: 0;
887    }
888    .source-badge-name {
889      font-family: var(--mono);
890      font-size: 11px;
891      font-weight: 600;
892      color: var(--text-sec);
893      letter-spacing: 0.04em;
894    }
895    .source-badge-org {
896      font-family: var(--mono);
897      font-size: 10px;
898      color: var(--text-dim);
899    }
900
901    @media (max-width: 768px) {
902      .sources-cat-row { justify-content: center; }
903      .sources-cat-label { width: auto; text-align: center; padding-top: 0; }
904      .source-badge { padding: 5px 10px; }
905    }
906
907    /* ================================================================
908       TABBED PRODUCT SHOWCASE
909       ================================================================ */
910    .showcase-section { background: var(--bg); }
911    .showcase-tabs {
912      display: flex;
913      gap: 4px;
914      margin-bottom: 40px;
915      overflow-x: auto;
916      padding-bottom: 4px;
917      -webkit-overflow-scrolling: touch;
918    }
919    .showcase-tab {
920      font-family: var(--mono);
921      font-size: 12px;
922      font-weight: 500;
923      color: var(--text-dim);
924      background: transparent;
925      border: 1px solid var(--border);
926      border-radius: 4px;
927      padding: 10px 20px;
928      cursor: pointer;
929      white-space: nowrap;
930      transition: color 0.2s, border-color 0.2s, background 0.2s;
931    }
932    .showcase-tab:hover { color: var(--text-sec); border-color: var(--text-dim); }
933    .showcase-tab.active {
934      color: var(--accent);
935      border-color: var(--accent);
936      background: rgba(8, 145, 178, 0.06);
937    }
938    .showcase-panels { position: relative; min-height: 400px; }
939    .showcase-panel {
940      display: none;
941      opacity: 0;
942      transform: translateY(12px);
943      transition: opacity 0.4s ease, transform 0.4s ease;
944    }
945    .showcase-panel.active {
946      display: grid;
947      grid-template-columns: 1fr 1fr;
948      gap: 48px;
949      align-items: center;
950      opacity: 1;
951      transform: translateY(0);
952    }
953
954    @media (max-width: 900px) {
955      .showcase-panel.active { grid-template-columns: 1fr; gap: 32px; }
956    }
957
958    /* Mockup card shared */
959    .mockup-card {
960      background: var(--surface);
961      border: 1px solid var(--border);
962      border-radius: 8px;
963      overflow: hidden;
964      transition: transform 0.3s, box-shadow 0.3s;
965    }
966    .mockup-card:hover {
967      transform: translateY(-4px);
968      box-shadow: 0 16px 48px rgba(0, 0, 0, 0.3), 0 0 0 1px rgba(59, 130, 246, 0.1);
969    }
970    .mockup-titlebar {
971      display: flex;
972      align-items: center;
973      gap: 6px;
974      padding: 10px 16px;
975      background: var(--surface-el);
976      border-bottom: 1px solid var(--border);
977    }
978    .mockup-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--border); }
979    .mockup-dot:first-child { background: #ef4444; }
980    .mockup-dot:nth-child(2) { background: #eab308; }
981    .mockup-dot:nth-child(3) { background: #22c55e; }
982    .mockup-titlebar-text {
983      margin-left: 8px;
984      font-family: var(--mono);
985      font-size: 11px;
986      color: var(--text-dim);
987    }
988    .mockup-body { padding: 20px; }
989
990    /* Breakdown bar */
991    .breakdown-bar {
992      display: flex;
993      height: 6px;
994      border-radius: 3px;
995      overflow: hidden;
996      margin: 16px 0 12px;
997    }
998    .breakdown-segment { transition: flex 0.6s ease; }
999    .breakdown-legend {
1000      display: flex;
1001      flex-wrap: wrap;
1002      gap: 10px;
1003    }
1004    .breakdown-legend-item {
1005      display: flex;
1006      align-items: center;
1007      gap: 5px;
1008      font-family: var(--mono);
1009      font-size: 10px;
1010      color: var(--text-dim);
1011    }
1012    .breakdown-legend-dot {
1013      width: 6px;
1014      height: 6px;
1015      border-radius: 1px;
1016      flex-shrink: 0;
1017    }
1018
1019    /* ETA distribution bar (stochastic tab) */
1020    .eta-bar-wrap {
1021      margin: 20px 0;
1022      padding: 16px;
1023      background: var(--bg);
1024      border: 1px solid var(--border);
1025      border-radius: 6px;
1026    }
1027    .eta-bar-label {
1028      font-family: var(--mono);
1029      font-size: 10px;
1030      color: var(--text-dim);
1031      text-transform: uppercase;
1032      letter-spacing: 0.08em;
1033      margin-bottom: 12px;
1034    }
1035    .eta-bar {
1036      position: relative;
1037      height: 32px;
1038      background: var(--surface-el);
1039      border-radius: 4px;
1040      overflow: hidden;
1041    }
1042    .eta-bar-range {
1043      position: absolute;
1044      top: 0;
1045      bottom: 0;
1046      background: linear-gradient(90deg, rgba(8, 145, 178, 0.15), rgba(8, 145, 178, 0.3), rgba(8, 145, 178, 0.15));
1047      border-left: 2px solid var(--accent);
1048      border-right: 2px solid var(--accent);
1049    }
1050    .eta-bar-median {
1051      position: absolute;
1052      top: 0;
1053      bottom: 0;
1054      width: 3px;
1055      background: #fff;
1056      border-radius: 1px;
1057    }
1058    .eta-bar-labels {
1059      display: flex;
1060      justify-content: space-between;
1061      margin-top: 6px;
1062      font-family: var(--mono);
1063      font-size: 10px;
1064      color: var(--text-dim);
1065    }
1066
1067    /* EP curve (underwriting tab) */
1068    .ep-curve-wrap {
1069      margin: 16px 0;
1070      padding: 16px;
1071      background: var(--bg);
1072      border: 1px solid var(--border);
1073      border-radius: 6px;
1074    }
1075    .ep-curve-svg {
1076      width: 100%;
1077      height: 140px;
1078    }
1079    .ep-curve-path {
1080      stroke-dasharray: 400;
1081      stroke-dashoffset: 400;
1082      transition: stroke-dashoffset 1.2s ease;
1083    }
1084    .ep-curve-path.drawn { stroke-dashoffset: 0; }
1085
1086    /* PDF stack (reports tab) */
1087    .pdf-stack {
1088      position: relative;
1089      height: 200px;
1090      margin: 16px 0;
1091    }
1092    .pdf-page {
1093      position: absolute;
1094      width: 140px;
1095      height: 180px;
1096      background: var(--surface-el);
1097      border: 1px solid var(--border);
1098      border-radius: 4px;
1099      padding: 12px;
1100      transition: transform 0.4s ease;
1101    }
1102    .pdf-page:nth-child(1) { left: 0; top: 10px; transform: rotate(-5deg); z-index: 1; }
1103    .pdf-page:nth-child(2) { left: 60px; top: 0; transform: rotate(-1deg); z-index: 2; }
1104    .pdf-page:nth-child(3) { left: 120px; top: 5px; transform: rotate(3deg); z-index: 3; }
1105    .pdf-page-title {
1106      font-family: var(--mono);
1107      font-size: 8px;
1108      color: var(--text-dim);
1109      text-transform: uppercase;
1110      letter-spacing: 0.08em;
1111      margin-bottom: 8px;
1112    }
1113    .pdf-page-line {
1114      height: 2px;
1115      background: var(--border);
1116      border-radius: 1px;
1117      margin-bottom: 4px;
1118    }
1119    .pdf-page-line.short { width: 60%; }
1120
1121    /* ================================================================
1122       OWNERSHIP & SANCTIONS
1123       ================================================================ */
1124    .ownership-section { background: var(--bg); }
1125    .ownership-layout {
1126      display: grid;
1127      grid-template-columns: 1fr 1fr;
1128      gap: 64px;
1129      align-items: center;
1130    }
1131    .ownership-chain {
1132      display: flex;
1133      flex-direction: column;
1134      gap: 0;
1135      align-items: center;
1136    }
1137    .ownership-entity {
1138      background: var(--surface);
1139      border: 1px solid var(--border);
1140      border-radius: 6px;
1141      padding: 16px 24px;
1142      width: 280px;
1143      text-align: center;
1144      opacity: 0;
1145      transform: translateY(20px);
1146      transition: opacity 0.5s ease, transform 0.5s ease, border-color 0.3s;
1147    }
1148    .ownership-entity.visible {
1149      opacity: 1;
1150      transform: translateY(0);
1151    }
1152    .ownership-entity:hover { border-color: var(--text-dim); }
1153    .ownership-entity-type {
1154      font-family: var(--mono);
1155      font-size: 9px;
1156      color: var(--text-dim);
1157      text-transform: uppercase;
1158      letter-spacing: 0.1em;
1159      margin-bottom: 6px;
1160    }
1161    .ownership-entity-name {
1162      font-size: 14px;
1163      font-weight: 600;
1164      color: var(--text);
1165      margin-bottom: 4px;
1166    }
1167    .ownership-entity-detail {
1168      font-family: var(--mono);
1169      font-size: 11px;
1170      color: var(--text-sec);
1171    }
1172    .ownership-entity.flagged { border-color: rgba(220, 38, 38, 0.4); }
1173    .ownership-entity.flagged .ownership-entity-detail { color: var(--risk-crit); }
1174    .ownership-connector {
1175      width: 1px;
1176      height: 28px;
1177      background: var(--border);
1178      opacity: 0;
1179      transition: opacity 0.4s ease;
1180    }
1181    .ownership-connector.visible { opacity: 1; }
1182
1183    .ownership-metrics {
1184      display: grid;
1185      grid-template-columns: 1fr 1fr;
1186      gap: 12px;
1187      margin-top: 20px;
1188    }
1189    .ownership-metric-card {
1190      background: var(--surface);
1191      border: 1px solid var(--border);
1192      border-radius: 6px;
1193      padding: 16px;
1194    }
1195    .ownership-metric-label {
1196      font-family: var(--mono);
1197      font-size: 10px;
1198      color: var(--text-dim);
1199      text-transform: uppercase;
1200      letter-spacing: 0.08em;
1201      margin-bottom: 6px;
1202    }
1203    .ownership-metric-value {
1204      font-family: var(--mono);
1205      font-size: 24px;
1206      font-weight: 700;
1207      line-height: 1;
1208    }
1209
1210    @media (max-width: 900px) {
1211      .ownership-layout { grid-template-columns: 1fr; gap: 40px; }
1212    }
1213
1214    /* ================================================================
1215       FUEL & CII
1216       ================================================================ */
1217    .fuel-section {
1218      background: var(--surface);
1219      border-top: 1px solid var(--border);
1220      border-bottom: 1px solid var(--border);
1221    }
1222    .fuel-layout {
1223      display: grid;
1224      grid-template-columns: 1fr 1fr;
1225      gap: 64px;
1226      align-items: center;
1227    }
1228    .cii-scale {
1229      display: flex;
1230      flex-direction: column;
1231      gap: 16px;
1232      margin: 24px 0;
1233    }
1234    .cii-bar-wrap { position: relative; }
1235    .cii-bar
1235 {
1236      display: flex;
1237      height: 40px;
1238      border-radius: 6px;
1239      overflow: hidden;
1240    }
1241    .cii-bar-seg {
1242      flex: 1;
1243      display: flex;
1244      align-items: center;
1245      justify-content: center;
1246      font-family: var(--mono);
1247      font-size: 14px;
1248      font-weight: 700;
1249      color: #fff;
1250    }
1251    .cii-bar-seg.a { background: #059669; }
1252    .cii-bar-seg.b { background: #34d399; color: #0d1420; }
1253    .cii-bar-seg.c { background: #fbbf24; color: #0d1420; }
1254    .cii-bar-seg.d { background: #f97316; }
1255    .cii-bar-seg.e { background: #dc2626; }
1256    .cii-pointer {
1257      position: absolute;
1258      bottom: -12px;
1259      width: 0;
1260      height: 0;
1261      border-left: 8px solid transparent;
1262      border-right: 8px solid transparent;
1263      border-bottom: 10px solid var(--text);
1264      transition: left 1s cubic-bezier(0.16, 1, 0.3, 1);
1265      left: 10%;
1266    }
1267    .cii-labels {
1268      display: flex;
1269      font-family: var(--mono);
1270      font-size: 10px;
1271      color: var(--text-dim);
1272    }
1273    .cii-labels span { flex: 1; text-align: center; }
1274    .fuel-metrics {
1275      display: grid;
1276      grid-template-columns: repeat(2, 1fr);
1277      gap: 12px;
1278    }
1279    .fuel-metric {
1280      background: var(--bg);
1281      border: 1px solid var(--border);
1282      border-radius: 6px;
1283      padding: 16px;
1284    }
1285    .fuel-metric-label {
1286      font-family: var(--mono);
1287      font-size: 10px;
1288      color: var(--text-dim);
1289      text-transform: uppercase;
1290      letter-spacing: 0.08em;
1291      margin-bottom: 6px;
1292    }
1293    .fuel-metric-value {
1294      font-family: var(--mono);
1295      font-size: 22px;
1296      font-weight: 700;
1297      color: var(--text);
1298      line-height: 1;
1299    }
1300    .fuel-metric-unit {
1301      font-family: var(--mono);
1302      font-size: 11px;
1303      color: var(--text-dim);
1304      margin-top: 4px;
1305    }
1306
1307    @media (max-width: 900px) {
1308      .fuel-layout { grid-template-columns: 1fr; gap: 40px; }
1309    }
1310
1311    /* ================================================================
1312       OCEAN ROUTING ANIMATION
1313       ================================================================ */
1314    .routing-section { background: var(--bg); }
1315    .routing-layout {
1316      display: grid;
1317      grid-template-columns: 1fr 1fr;
1318      gap: 64px;
1319      align-items: center;
1320    }
1321    .routing-map-wrap {
1322      width: 100%;
1323      position: relative;
1324    }
1325    .routing-map {
1326      width: 100%;
1327      height: 340px;
1328      border-radius: 8px;
1329      border: 1px solid var(--border);
1330      background: var(--surface);
1331    }
1332    .routing-map .leaflet-control-attribution { background: rgba(12, 14, 18, 0.8) !important; color: var(--text-dim) !important; font-size: 9px !important; }
1333    .routing-map .leaflet-control-attribution a { color: var(--text-dim) !important; }
1334    .routing-map .leaflet-control-zoom a { background: var(--surface) !important; color: var(--text) !important; border-color: var(--border) !important; }
1335    .routing-map-label {
1336      position: absolute;
1337      bottom: 12px;
1338      left: 12px;
1339      font-family: var(--mono);
1340      font-size: 10px;
1341      color: var(--text-dim);
1342      background: rgba(7, 10, 16, 0.85);
1343      padding: 4px 10px;
1344      border-radius: 4px;
1345      border: 1px solid var(--border);
1346      z-index: 500;
1347      pointer-events: none;
1348    }
1349    .routing-map-loading {
1350      display: flex;
1351      align-items: center;
1352      justify-content: center;
1353      height: 100%;
1354      color: var(--text-dim);
1355      font-family: var(--mono);
1356      font-size: 12px;
1357    }
1358    .route-showcase-label {
1359      background: rgba(7, 10, 16, 0.85) !important;
1360      border: 1px solid var(--border) !important;
1361      color: var(--text) !important;
1362      font-family: var(--mono) !important;
1363      font-size: 10px !important;
1364      padding: 2px 8px !important;
1365      border-radius: 3px !important;
1366      box-shadow: none !important;
1367    }
1368    .route-showcase-label::before { border-top-color: rgba(7, 10, 16, 0.85) !important; }
1369
1370    @media (max-width: 900px) {
1371      .routing-layout { grid-template-columns: 1fr; gap: 40px; }
1372    }
1373
1374    /* ================================================================
1375       VESSELWATCH ALERTS
1376       ================================================================ */
1377    .alerts-section { background: var(--bg); }
1378    .alerts-layout {
1379      display: grid;
1380      grid-template-columns: 1fr 1fr;
1381      gap: 64px;
1382      align-items: center;
1383    }
1384    .alerts-layout-reverse { direction: rtl; }
1385    .alerts-layout-reverse > * { direction: ltr; }
1386    .alert-feed { display: flex; flex-direction: column; gap: 1px; }
1387    .alert-item {
1388      display: flex;
1389      align-items: flex-start;
1390      gap: 12px;
1391      padding: 12px 16px;
1392      background: rgba(22, 26, 34, 0.6);
1393      border-left: 3px solid;
1394      transition: background 0.2s;
1395    }
1396    .alert-item:hover { background: rgba(32, 37, 46, 0.6); }
1397    .alert-item[data-severity="critical"] { border-left-color: var(--risk-crit); }
1398    .alert-item[data-severity="high"] { border-left-color: var(--risk-high); }
1399    .alert-item[data-severity="medium"] { border-left-color: var(--risk-mod); }
1400    .alert-item[data-severity="low"] { border-left-color: var(--risk-low); }
1401    .alert-badge {
1402      font-family: var(--mono);
1403      font-size: 9px;
1404      font-weight: 600;
1405      letter-spacing: 0.06em;
1406      padding: 2px 6px;
1407      border-radius: 2px;
1408      flex-shrink: 0;
1409      text-transform: uppercase;
1410    }
1411    .alert-badge[data-severity="critical"] { background: rgba(220, 38, 38, 0.15); color: var(--risk-crit); }
1412    .alert-badge[data-severity="high"] { background: rgba(234, 88, 12, 0.15); color: var(--risk-high); }
1413    .alert-badge[data-severity="medium"] { background: rgba(37, 99, 235, 0.15); color: var(--risk-mod); }
1414    .alert-badge[data-severity="low"] { background: rgba(22, 163, 74, 0.15); color: var(--risk-low); }
1415    .alert-content { flex: 1; min-width: 0; }
1416    .alert-type {
1417      font-family: var(--mono);
1418      font-size: 10px;
1419      font-weight: 600;
1420      text-transform: uppercase;
1421      letter-spacing: 0.06em;
1422      color: var(--text-dim);
1423      margin-bottom: 3px;
1424    }
1425    .alert-msg { font-size: 13px; color: var(--text-sec); line-height: 1.5; }
1426    .alert-vessel { color: var(--text); font-weight: 600; }
1427    .alert-time { font-family: var(--mono); font-size: 10px; color: var(--text-dim); margin-top: 4px; }
1428    .alert-types-grid {
1429      display: grid;
1430      grid-template-columns: 1fr 1fr 1fr;
1431      gap: 8px;
1432      margin-top: 16px;
1433    }
1434    .alert-type-badge {
1435      display: flex;
1436      align-items: center;
1437      gap: 6px;
1438      padding: 6px 10px;
1439      background: var(--surface);
1440      border: 1px solid var(--border);
1441      border-radius: 4px;
1442      font-family: var(--mono);
1443      font-size: 10px;
1444      color: var(--text-sec);
1445    }
1446    .alert-type-dot {
1447      width: 6px;
1448      height: 6px;
1449      border-radius: 50%;
1450      flex-shrink: 0;
1451    }
1452
1453    @media (max-width: 900px) {
1454      .alerts-layout { grid-template-columns: 1fr; gap: 40px; }
1455      .alerts-layout-reverse { direction: ltr; }
1456      .alert-types-grid { grid-template-columns: 1fr 1fr; }
1457    }
1458    @media (max-width: 600px) {
1459      .alert-types-grid { grid-template-columns: 1fr; }
1460    }
1461
1462
1463    /* ================================================================
1464       API PREVIEW — 3 TABBED EXAMPLES
1465       ================================================================ */
1466    .api-section { background: var(--bg); }
1467    .api-grid {
1468      display: grid;
1469      grid-template-columns: 1fr 1fr;
1470      gap: 48px;
1471      align-items: start;
1472    }
1473    .api-grid > * { min-width: 0; } /* a long <pre> line must scroll inside .code-body, not widen the grid track */
1474    .api-tabs {
1475      display: flex;
1476      flex-wrap: wrap;
1477      gap: 4px;
1478      margin-bottom: 16px;
1479    }
1480    .api-tab {
1481      font-family: var(--mono);
1482      font-size: 11px;
1483      font-weight: 500;
1484      color: var(--text-dim);
1485      background: transparent;
1486      border: 1px solid var(--border);
1487      border-radius: 4px;
1488      padding: 6px 14px;
1489      cursor: pointer;
1490      transition: color 0.2s, border-color 0.2s, background 0.2s;
1491    }
1492    .api-tab:hover { color: var(--text-sec); border-color: var(--text-dim); }
1493    .api-tab.active {
1494      color: var(--accent);
1495      border-color: var(--accent);
1496      background: rgba(8, 145, 178, 0.06);
1497    }
1498    .api-panel { display: none; }
1499    .api-panel.active { display: flex; flex-direction: column; gap: 16px; }
1500    .code-block {
1501      background: var(--surface);
1502      border: 1px solid var(--border);
1503      border-radius: 6px;
1504      overflow: hidden;
1505    }
1506    .code-header {
1507      display: flex;
1508      align-items: center;
1509      gap: 8px;
1510      padding: 10px 16px;
1511      background: var(--surface-el);
1512      border-bottom: 1px solid var(--border);
1513      font-family: var(--mono);
1514      font-size: 11px;
1515      color: var(--text-dim);
1516    }
1517    .code-method { color: var(--risk-low); font-weight: 600; }
1518    .code-body {
1519      padding: 16px;
1520      font-family: var(--mono);
1521      font-size: 12px;
1522      line-height: 1.7;
1523      color: var(--text-sec);
1524      overflow-x: auto;
1525    }
1526    .code-body .ck { color: var(--accent); }
1527    .code-body .cv { color: var(--risk-low); }
1528    .code-body .cn { color: var(--risk-elev); }
1529    .code-body .cs { color: #f472b6; }
1530    .code-body .cb { color: var(--text-dim); }
1531    .api-features { list-style: none; display: flex; flex-direction: column; gap: 12px; margin-top: 24px; }
1532    .api-feature { display: flex; align-items: center; gap: 10px; font-size: 14px; color: var(--text-sec); }
1533    .api-feature-check {
1534      width: 16px;
1535      height: 16px;
1536      display: flex;
1537      align-items: center;
1538      justify-content: center;
1539      background: rgba(22, 163, 74, 0.1);
1540      border-radius: 3px;
1541      flex-shrink: 0;
1542    }
1543    .api-feature-check svg { width: 10px; height: 10px; stroke: var(--risk-low); fill: none; stroke-width: 2.5; }
1544
1545    @media (max-width: 900px) { .api-grid { grid-template-columns: 1fr; } }
1546
1547    /* ================================================================
1548       CTA
1549       ================================================================ */
1550    .cta-section {
1551      padding: 100px 0;
1552      text-align: center;
1553      position: relative;
1554      background: linear-gradient(180deg, var(--bg) 0%, rgba(22, 26, 34, 0.5) 50%, var(--bg) 100%);
1555    }
1556    .cta-section::before {
1557      content: '';
1558      position: absolute;
1559      top: 50%;
1560      left: 50%;
1561      transform: translate(-50%, -50%);
1562      width: 600px;
1563      height: 400px;
1564      background: radial-gradient(circle, rgba(59, 130, 246, 0.06) 0%, transparent 70%);
1565      pointer-events: none;
1566    }
1567    .cta-title {
1568      font-family: var(--display);
1569      font-size: clamp(1.8rem, 3vw, 2.6rem);
1570      color: var(--text);
1571      margin-bottom: 16px;
1572      position: relative;
1573      font-weight: 400;
1574    }
1575    .cta-badge {
1576      display: inline-block;
1577      font-family: var(--mono);
1578      font-size: 11px;
1579      font-weight: 600;
1580      color: var(--risk-low);
1581      background: rgba(22, 163, 74, 0.1);
1582      border: 1px solid rgba(22, 163, 74, 0.25);
1583      padding: 4px 12px;
1584      border-radius: 3px;
1585      margin-bottom: 24px;
1586      letter-spacing: 0.06em;
1587      position: relative;
1588    }
1589    .cta-sub {
1590      font-size: 16px;
1591      color: var(--text-sec);
1592      margin-bottom: 36px;
1593      position: relative;
1594      max-width: 600px;
1595      margin-left: auto;
1596      margin-right: auto;
1597    }
1598    .cta-actions {
1599      display: flex;
1600      align-items: center;
1601      justify-content: center;
1602      gap: 24px;
1603      position: relative;
1604      flex-wrap: wrap;
1605    }
1606    .cta-email {
1607      font-family: var(--mono);
1608      font-size: 14px;
1609      color: var(--text-dim);
1610      margin-top: 24px;
1611      position: relative;
1612    }
1613    .cta-email a {
1614      color: var(--text-sec);
1615      border-bottom: 1px solid var(--border);
1616      transition: color 0.2s, border-color 0.2s;
1617    }
1618    .cta-email a:hover { color: var(--accent); border-color: var(--accent); }
1619
1620    /* ================================================================
1621       FOOTER
1622       ================================================================ */
1623    .footer {
1624      border-top: 1px solid var(--border);
1625      padding: 40px 0;
1626    }
1627    .footer-inner {
1628      display: flex;
1629      align-items: center;
1630      justify-content: space-between;
1631      flex-wrap: wrap;
1632      gap: 24px;
1633    }
1634    .footer-brand { display: flex; align-items: center; gap: 8px; }
1635    .footer-brand-mark { width: 18px; height: 18px; object-fit: contain; }
1636    .footer-brand-text {
1637      font-family: var(--mono);
1638      font-size: 12px;
1639      font-weight: 600;
1640      letter-spacing: 2px;
1641      color: var(--text-dim);
1642    }
1643    .footer-links { display: flex; gap: 24px; list-style: none; flex-wrap: wrap; }
1644    .footer-links a { font-size: 13px; color: var(--text-dim); transition: color 0.2s; }
1645    .footer-links a:hover { color: var(--text-sec); }
1646    .footer-right { font-size: 12px; color: var(--text-dim); }
1647    .footer-powered {
1648      font-size: 11px;
1649      color: var(--text-dim);
1650      margin-top: 16px;
1651      text-align: center;
1652      font-family: var(--mono);
1653      letter-spacing: 0.03em;
1654    }
1655
1656    /* ================================================================
1657       LIVE / DEMO BADGES
1658       ================================================================ */
1659    .live-badge {
1660      display: inline-flex;
1661      align-items: center;
1662      gap: 5px;
1663      font-family: var(--mono);
1664      font-size: 9px;
1665      font-weight: 700;
1666      letter-spacing: 0.1em;
1667      color: var(--risk-low);
1668      background: rgba(22, 163, 74, 0.1);
1669      border: 1px solid rgba(22, 163, 74, 0.25);
1670      padding: 2px 7px;
1671      border-radius: 3px;
1672    }
1673    .live-dot {
1674      width: 5px;
1675      height: 5px;
1676      background: var(--risk-low);
1677      border-radius: 50%;
1678      animation: tickerPulse 1.5s ease-in-out infinite;
1679      flex-shrink: 0;
1680    }
1681    .demo-badge {
1682      display: inline-flex;
1683      align-items: center;
1684      font-family: var(--mono);
1685      font-size: 9px;
1686      font-weight: 600;
1687      letter-spacing: 0.08em;
1688      color: var(--text-dim);
1689      background: rgba(106, 110, 122, 0.08);
1690      border: 1px solid rgba(106, 110, 122, 0.2);
1691      padding: 2px 7px;
1692      border-radius: 3px;
1693    }
1694
1695    /* ================================================================
1696       FREE VOYAGE SCORER
1697       ================================================================ */
1698    .scorer-form { margin-bottom: 24px; }
1699    .scorer-fields { display: flex; gap: 8px; align-items: flex-end; margin-bottom: 16px; }
1700    .scorer-field { flex: 1; position: relative; }
1701    .scorer-field label {
1702      display: block;
1703      font-family: var(--mono);
1704      font-size: 10px;
1705      font-weight: 600;
1706      color: var(--text-dim);
1707      text-transform: uppercase;
1708      letter-spacing: 0.1em;
1709      margin-bottom: 6px;
1710    }
1711    .scorer-input {
1712      width: 100%;
1713      padding: 12px 14px;
1714      background: var(--surface);
1715      border: 1px solid var(--border);
1716      border-radius: 4px;
1717      color: var(--text);
1718      font-family: var(--mono);
1719      font-size: 13px;
1720      outline: none;
1721      transition: border-color 0.2s, box-shadow 0.2s;
1722    }
1723    .scorer-input::placeholder { color: var(--text-dim); font-family: var(--body); font-size: 12px; }
1724    .scorer-input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); }
1725    .scorer-input.has-value { font-weight: 500; }
1726    .scorer-arrow-icon { font-size: 18px; color: var(--text-dim); padding-bottom: 12px; flex-shrink: 0; }
1727
1728    .scorer-dropdown {
1729      display: none;
1730      position: absolute;
1731      top: 100%;
1732      left: 0;
1733      right: 0;
1734      margin-top: 4px;
1735      background: var(--surface-el);
1736      border: 1px solid var(--border);
1737      border-radius: 4px;
1738      max-height: 240px;
1739      overflow-y: auto;
1740      z-index: 100;
1741      box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
1742    }
1743    .scorer-dropdown.open { display: block; }
1744    .scorer-dd-item {
1745      display: flex;
1746      align-items: center;
1747      gap: 8px;
1748      padding: 10px 14px;
1749      cursor: pointer;
1750      font-size: 13px;
1751      color: var(--text);
1752      border-left: 3px solid transparent;
1753      transition: background 0.1s, border-color 0.1s;
1754    }
1755    .scorer-dd-item:hover,
1756    .scorer-dd-item.hl {
1757      background: rgba(255, 255, 255, 0.04);
1758      border-left-color: var(--accent);
1759    }
1760    .scorer-dd-flag { font-size: 15px; flex-shrink: 0; }
1761    .scorer-dd-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1762    .scorer-dd-code { font-family: var(--mono); font-size: 11px; color: var(--text-dim); flex-shrink: 0; }
1763    .scorer-dd-msg { padding: 12px 14px; font-size: 12px; color: var(--text-dim); }
1764
1765    .scorer-btn {
1766      width: 100%;
1767      padding: 14px 24px;
1768      background: var(--accent);
1769      color: #fff;
1770      font-size: 14px;
1771      font-weight: 600;
1772      border: none;
1773      border-radius: 4px;
1774      cursor: pointer;
1775      display: flex;
1776      align-items: center;
1777      justify-content: center;
1778      gap: 8px;
1779      transition: background 0.2s, transform 0.15s, box-shadow 0.2s;
1780      letter-spacing: 0.02em;
1781    }
1782    .scorer-btn:hover:not(:disabled) {
1783      background: var(--accent-hover);
1784      transform: translateY(-1px);
1785      box-shadow: 0 4px 16px rgba(59, 130, 246, 0.3);
1786    }
1787    .scorer-btn:disabled { opacity: 0.4;
1787 cursor: not-allowed; transform: none; }
1788    .scorer-btn:active:not(:disabled) { transform: translateY(0); }
1789    .scorer-spinner { width: 18px; height: 18px; animation: scorerSpin 0.8s linear infinite; }
1790    @keyframes scorerSpin { to { transform: rotate(360deg); } }
1791
1792    .scorer-popular { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
1793    .scorer-popular-label { font-family: var(--mono); font-size: 11px; color: var(--text-dim); }
1794    .scorer-popular-btn {
1795      font-family: var(--mono);
1796      font-size: 11px;
1797      color: var(--text-sec);
1798      background: var(--surface);
1799      border: 1px solid var(--border);
1800      padding: 4px 10px;
1801      border-radius: 3px;
1802      cursor: pointer;
1803      transition: border-color 0.2s, color 0.2s, background 0.2s;
1804    }
1805    .scorer-popular-btn:hover { border-color: var(--accent); color: var(--text); background: var(--surface-el); }
1806
1807    .scorer-error {
1808      margin-top: 12px;
1809      padding: 10px 14px;
1810      background: rgba(220, 38, 38, 0.08);
1811      border: 1px solid rgba(220, 38, 38, 0.2);
1812      border-radius: 4px;
1813      font-family: var(--mono);
1814      font-size: 12px;
1815      color: var(--risk-crit);
1816      display: none;
1817    }
1818    .scorer-error.visible { display: block; }
1819
1820    /* Results Panel */
1821    .scorer-results {
1822      /* Belt and braces with the pointer-events fixes on the hero's decorative
1823         layers: lift the results panel into the same stacking position
1824         .hero-content uses, so a future absolutely-positioned hero decoration
1825         cannot silently make this panel unclickable again. */
1826      position: relative;
1827      z-index: 2;
1828      max-height: 0;
1829      overflow: hidden;
1830      opacity: 0;
1831      transition: max-height 0.7s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.5s ease, margin-top 0.5s ease;
1832    }
1833    .scorer-results.visible { max-height: 4000px; opacity: 1; margin-top: 48px; }
1834    .results-inner { background: var(--surface); border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
1835    .results-header {
1836      display: flex;
1837      align-items: center;
1838      justify-content: space-between;
1839      padding: 16px 24px;
1840      border-bottom: 1px solid var(--border);
1841      background: var(--surface-el);
1842      flex-wrap: wrap;
1843      gap: 12px;
1844    }
1845    .results-route-name { font-family: var(--mono); font-size: 14px; font-weight: 600; color: var(--text); }
1846    .results-route-name span { color: var(--text-dim); }
1847    .results-scored-at { font-family: var(--mono); font-size: 10px; color: var(--text-dim); margin-top: 2px; }
1848    .results-score-again-btn {
1849      font-family: var(--mono);
1850      font-size: 12px;
1851      color: var(--accent);
1852      background: none;
1853      border: 1px solid var(--accent);
1854      padding: 6px 14px;
1855      border-radius: 4px;
1856      cursor: pointer;
1857      transition: background 0.2s, color 0.2s;
1858    }
1859    .results-score-again-btn:hover { background: var(--accent); color: #fff; }
1860    .results-body { padding: 24px; }
1861    .results-grid { display: grid; grid-template-columns: 220px 1fr; gap: 24px; margin-bottom: 24px; }
1862    .results-score-col { display: flex; flex-direction: column; align-items: center; gap: 16px; }
1863    .results-meta { text-align: center; }
1864    .results-meta-item { font-family: var(--mono); font-size: 12px; color: var(--text-sec); margin-bottom: 4px; }
1865    .results-meta-item strong { color: var(--text); font-weight: 600; }
1866    .results-confidence {
1867      font-family: var(--mono);
1868      font-size: 10px;
1869      padding: 3px 8px;
1870      border-radius: 3px;
1871      margin-top: 4px;
1872      display: inline-block;
1873    }
1874    .results-confidence.good { color: var(--risk-low); background: rgba(22, 163, 74, 0.1); }
1875    .results-confidence.limited { color: var(--risk-elev); background: rgba(217, 119, 6, 0.1); }
1876    .results-map-col { position: relative; }
1877    .results-map {
1878      height: 320px;
1879      border-radius: 6px;
1880      border: 1px solid var(--border);
1881      overflow: hidden;
1882      background: #070a10;
1883    }
1884    .results-map .leaflet-control-attribution { background: rgba(12, 14, 18, 0.8) !important; color: var(--text-dim) !important; font-size: 9px !important; }
1885    .results-map .leaflet-control-attribution a { color: var(--text-dim) !important; }
1886    .results-map .leaflet-control-zoom a { background: var(--surface) !important; color: var(--text) !important; border-color: var(--border) !important; }
1887    .results-waypoints {
1888      display: flex;
1889      align-items: center;
1890      gap: 6px;
1891      flex-wrap: wrap;
1892      padding: 16px 0;
1893      border-bottom: 1px solid var(--border);
1894      margin-bottom: 24px;
1895    }
1896    .results-wp-label { font-family: var(--mono); font-size: 10px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.08em; }
1897    .results-wp-tag { font-family: var(--mono); font-size: 11px; color: var(--text-sec); background: rgba(255,255,255,0.04); border: 1px solid var(--border); padding: 3px 10px; border-radius: 3px; }
1898    .results-wp-arrow { color: var(--text-dim); font-size: 10px; }
1899    .results-drivers-title { font-family: var(--mono); font-size: 10px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.1em; margin-bottom: 12px; }
1900    .results-drivers { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 12px; margin-bottom: 24px; }
1901    .driver-card { background: var(--bg); border: 1px solid var(--border); border-radius: 6px; padding: 16px; transition: border-color 0.2s; }
1902    .driver-card:hover { border-color: var(--text-dim); }
1903    .driver-card-name { font-family: var(--mono); font-size: 10px; font-weight: 600; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 8px; }
1904    .driver-card-score { font-family: var(--mono); font-size: 28px; font-weight: 700; line-height: 1; margin-bottom: 4px; }
1905    .driver-card-weight { font-family: var(--mono); font-size: 10px; color: var(--text-dim); margin-bottom: 10px; }
1906    .driver-card-bar { height: 3px; background: var(--border); border-radius: 2px; margin-bottom: 10px; overflow: hidden; }
1907    .driver-card-bar-fill { height: 100%; border-radius: 2px; transition: width 0.6s ease; }
1908    .driver-card-detail { font-size: 12px; color: var(--text-sec); line-height: 1.5; }
1909    /* (removed) .results-gate* — the blur/lock signup gate on the lane result. The full
1910       computed result is shown unconditionally now;
1910 capture lives in /lane-capture.js. */
1911    .results-footer { display: flex; align-items: center; justify-content: center; gap: 16px; padding: 20px 24px; border-top: 1px solid var(--border); flex-wrap: wrap; }
1912
1913    @media (max-width: 900px) {
1914      .scorer-fields { flex-direction: column; gap: 12px; }
1915      .scorer-arrow-icon { display: none; }
1916      .results-grid { grid-template-columns: 1fr; }
1917      .results-score-col { flex-direction: row; justify-content: center; flex-wrap: wrap; }
1918    }
1919    @media (max-width: 600px) {
1920      .results-drivers { grid-template-columns: 1fr; }
1921      .results-map { height: 220px; }
1922      .scorer-popular-btn { font-size: 10px; padding: 3px 7px; }
1923    }
1924    /* Mobile: body{overflow-x:hidden} alone propagates to the viewport and stops clipping the body, so decorative overflow made mobile Chrome zoom the layout viewport out (innerWidth 495 on a 390 screen, hamburger off-screen). Setting html too makes the body clip. Measured 2026-09-13. */
1925    html { overflow-x: hidden; }
1926    /* The hero check form is a non-wrapping flex row; at phone width the button sat past the edge (right=457 on 390). */
1927    #landingCheckForm { flex-wrap: wrap; }
1928    #landing-imo { min-width: 0; flex: 1 1 200px; }
1929    #landing-check-btn { flex: 0 0 auto; }
1930  </style>
1931  <link rel="alternate" type="application/rss+xml" title="ArcNautical Blog" href="/blog/feed.xml">
1932  
1932<script type="application/ld+json">
1933  {
1934    "@context": "https://schema.org",
1935    "@type": "SoftwareApplication",
1936    "name": "ArcNautical",
1937    "applicationCategory": "BusinessApplication",
1938    "operatingSystem": "Web",
1939    "url": "https://arcnautical.com",
1940    "description": "Maritime intelligence platform providing route-level voyage risk scoring, vessel vetting, sanctions screening, and fleet monitoring for marine insurance underwriters and compliance teams.",
1941    "offers": {
1942      "@type": "Offer",
1943      "price": "0",
1944      "priceCurrency": "USD",
1945      "description": "Free tier available"
1946    },
1947    "author": {
1948      "@type": "Organization",
1949      "name": "ArcNautical",
1950      "url": "https://arcnautical.com"
1951    },
1952    "featureList": [
1953      "Voyage risk scoring with 11 intelligence signals",
1954      "Real-time vessel tracking via AIS",
1955      "Container tracking across 21 major carriers",
1956      "Real-time port congestion via IMF PortWatch",
1957      "Freight market index monitoring",
1958      "Sanctions screening (OFAC, UN, EU)",
1959      "Ownership chain resolution via GLEIF",
1960      "Monte Carlo stochastic analysis",
1961      "Fuel and CII compliance calculations",
1962      "PDF report generation",
1963      "Fleet monitoring with threat overlays"
1964    ]
1965  }
1966  </script>
1966
1967  
1967<script type="application/ld+json">
1968  {
1969    "@context": "https://schema.org",
1970    "@type": "Organization",
1971    "@id": "https://arcnautical.com/#org",
1972    "name": "ArcNautical",
1973    "url": "https://arcnautical.com",
1974    "logo": "https://arcnautical.com/og-image.png",
1975    "description": "Maritime intelligence platform for voyage risk scoring, vessel vetting, and fleet monitoring.",
1976    "sameAs": [
1977      "https://github.com/arcnautical",
1978      "https://www.npmjs.com/org/arcnautical"
1979    ]
1980  }
1981  </script>
1981
1982</head>
1983<body>
1984
1985  <!-- SCROLL PROGRESS -->
1986  <div class="scroll-progress" id="scrollProgress"></div>
1987
1988  <!-- ============================================================
1989       NAVIGATION
1990       ============================================================ -->
1991  <nav class="nav" id="nav">
1992    <div class="nav-inner">
1993      <a href="#" class="nav-brand">
1994        <img class="nav-brand-mark" src="/logo.svg" alt="ArcNautical" width="24" height="24">
1995        ARCNAUTICAL
1996      </a>
1997      <button class="nav-hamburger" id="navHamburger" aria-label="Toggle menu">
1998        <span></span><span></span><span></span>
1999      </button>
2000      <ul class="nav-links" id="navLinks">
2001        <li><a href="#how-it-works">How It Works</a></li>
2002        <li><a href="#api">API</a></li>
2003        <li><a href="#signals">Signals</a></li>
2004        <li><a href="#products">Products</a></li>
2005        <li><a href="#pricing">Pricing</a></li>
2006        <li><a href="/blog">Blog</a></li>
2007        <li><a href="/arcnautical.html#/congestion">Port Congestion</a></li>
2008        <li><a href="/check">Vessel Check</a></li>
2009        <li><a href="/arcnautical.html#/login" class="nav-signin">Sign In</a></li>
2010        <li><a href="/arcnautical.html#/register" class="nav-cta">Sign Up Free</a></li>
2011      </ul>
2012    </div>
2013  </nav>
2014
2015  <!-- ============================================================
2016       HERO
2017       ============================================================ -->
2018  <section class="hero" id="hero">
2019    <div class="hero-grid"></div>
2020    <div class="hero-routes">
2021      <svg viewBox="0 0 1200 700" preserveAspectRatio="xMidYMid slice">
2022        <defs>
2023          <linearGradient id="routeGrad" x1="0%" y1="0%" x2="100%" y2="0%">
2024            <stop offset="0%" stop-color="#0891b2" stop-opacity="0"/>
2025            <stop offset="50%" stop-color="#0891b2" stop-opacity="0.6"/>
2026            <stop offset="100%" stop-color="#0891b2" stop-opacity="0"/>
2027          </linearGradient>
2028        </defs>
2029        <!-- Route: Asia to Europe -->
2030        <path id="heroRoute1" d="M950,380 Q850,300 750,340 Q600,380 500,350 Q400,320 300,300 Q200,280 150,320" stroke="url(#routeGrad)" fill="none" stroke-width="1" opacity="0.4"/>
2031        <!-- Route: Gulf to East Africa -->
2032        <path d="M700,300 Q650,350 620,400 Q580,450 550,480" stroke="url(#routeGrad)" fill="none" stroke-width="0.8" opacity="0.3">
2033          <animate attributeName="stroke-dasharray" values="0,1000;1000,0" dur="6s" repeatCount="indefinite"/>
2034        </path>
2035        <!-- Route: Europe to Americas -->
2036        <path d="M200,280 Q150,250 100,260 Q50,300 30,350" stroke="url(#routeGrad)" fill="none" stroke-width="0.8" opacity="0.25">
2037          <animate attributeName="stroke-dasharray" values="0,800;800,0" dur="7s" repeatCount="indefinite"/>
2038        </path>
2039        <!-- Port dots -->
2040        <circle cx="950" cy="380" r="3" fill="#0891b2" opacity="0.5"><animate attributeName="r" values="2;4;2" dur="3s" repeatCount="indefinite"/></circle>
2041        <circle cx="750" cy="340" r="2.5" fill="#0891b2" opacity="0.4"/>
2042        <circle cx="500" cy="350" r="2.5" fill="#0891b2" opacity="0.4"/>
2043        <circle cx="300" cy="300" r="2.5" fill="#0891b2" opacity="0.4"/>
2044        <circle cx="150" cy="320" r="3" fill="#0891b2" opacity="0.5"><animate attributeName="r" values="2;4;2" dur="4s" repeatCount="indefinite"/></circle>
2045        <circle cx="620" cy="400" r="2" fill="#0891b2" opacity="0.3"/>
2046        <circle cx="700" cy="300" r="2" fill="#d97706" opacity="0.4"><animate attributeName="opacity" values="0.4;0.7;0.4" dur="2s" repeatCount="indefinite"/></circle>
2047        <!-- Traveling dots -->
2048        <circle r="2.5" fill="#0891b2" opacity="0.8">
2049          <animateMotion dur="8s" repeatCount="indefinite" path="M950,380 Q850,300 750,340 Q600,380 500,350 Q400,320 300,300 Q200,280 150,320"/>
2050        </circle>
2051        <circle r="2" fill="#06b6d4" opacity="0.6">
2052          <animateMotion dur="6s" repeatCount="indefinite" path="M700,300 Q650,350 620,400 Q580,450 550,480"/>
2053        </circle>
2054      </svg>
2055    </div>
2056    <div class="hero-grain"></div>
2057    <div class="hero-glow"></div>
2058
2059    <div class="container">
2060      <div class="hero-content">
2061        <div class="hero-text">
2062          <h1>Screen any vessel before you<br><em>fix, insure, or finance</em> it.</h1>
2063          <p class="hero-sub">
2064            Sanctions, ownership exposure, and a vetting grade for any IMO &mdash; checked against
2065            OFAC, EU, UN and the full ownership chain. Free. No signup.
2066          </p>
2067          <a href="/check" class="btn-primary" style="margin-bottom:12px;">Check a vessel &rarr;</a>
2068          <div style="font-family:var(--mono);font-size:12px;color:var(--text-dim);margin-bottom:24px;letter-spacing:0.02em;">Or from code, no key: <a href="#api" style="color:var(--accent);text-decoration:none;">GET /api/v1/vessels/{imo}/check &rarr;</a></div>
2069          <div class="scorer-secondary-label" style="font-family:var(--mono);font-size:12px;color:var(--text-dim);margin-bottom:10px;letter-spacing:0.02em;">Also &mdash; planning a voyage? Score any route:</div>
2070          <div class="scorer-form" id="scorerForm">
2071            <div class="scorer-fields">
2072              <div class="scorer-field">
2073                <label for="originInput">Origin Port</label>
2074                <input type="text" class="scorer-input" id="originInput"
2075                       placeholder="e.g. Singapore, SGSIN"
2076                       autocomplete="off" spellcheck="false">
2077                <div class="scorer-dropdown" id="originDropdown"></div>
2078              </div>
2079              <span class="scorer-arrow-icon">&rarr;</span>
2080              <div class="scorer-field">
2081                <label for="destInput">Destination Port</label>
2082                <input type="text" class="scorer-input" id="destInput"
2083                       placeholder="e.g. Rotterdam, NLRTM"
2084                       autocomplete="off" spellcheck="false">
2085                <div class="scorer-dropdown" id="destDropdown"></div>
2086              </div>
2087            </div>
2088            <button class="scorer-btn" id="scoreBtn" disabled>
2089              <span id="scoreBtnText">Score This Route</span>
2090              <svg id="scoreBtnSpinner" class="scorer-spinner" viewBox="0 0 24 24" style="display:none;">
2091                <circle cx="12" cy="12" r="10" fill="none" stroke="currentColor" stroke-width="2.5"
2092                        stroke-dasharray="31.4 31.4" stroke-linecap="round"/>
2093              </svg>
2094            </button>
2095            <div class="scorer-error" id="scorerError"></div>
2096          </div>
2097          <div class="scorer-popular">
2098            <span class="scorer-popular-label">Try:</span>
2099            <button class="scorer-popular-btn" data-origin="SGSIN" data-dest="NLRTM">Singapore &rarr; Rotterdam</button>
2100            <button class="scorer-popular-btn" data-origin="SGSIN" data-dest="EGPSD">Singapore &rarr; Port Said</button>
2101            <button class="scorer-popular-btn" data-origin="CNSHA" data-dest="DEHAM">Shanghai &rarr; Hamburg</button>
2102            <button class="scorer-popular-btn" data-origin="USHOU" data-dest="AEJEA">Houston &rarr; Jebel Ali</button>
2103          </div>
2104        </div>
2105        <div class="hero-visual">
2106          <div class="hero-gauge-wrap">
2107            <svg id="heroGauge" width="240" height="240" viewBox="0 0 240 240"></svg>
2108          </div>
2109          <div class="hero-route-card">
2110            <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:6px;">
2111              <div class="hero-route-label" style="margin-bottom:0;">Scored Route</div>
2112              <span class="live-badge" id="scoreLiveBadge" style="display:none;">
2113                <span class="live-dot"></span>LIVE
2114              </span>
2115              <span class="demo-badge" id="scoreDemoBadge">DEMO</span>
2116            </div>
2117            <div class="hero-route-ports" id="heroRoutePorts">SGSIN <span style="color:var(--text-dim);">&rarr;</span> NLRTM</div>
2118            <div class="hero-route-meta" id="heroRouteMeta">8,441 nm &middot; Risk Score: <span id="heroRiskLabel" style="color:#d97706;font-weight:600;">62 ELEVATED</span></div>
2119            <div id="heroUpdatedAt" style="font-family:var(--mono);font-size:10px;color:var(--text-dim);margin-top:4px;display:none;"></div>
2120            <div class="hero-route-waypoints" id="heroWaypoints">
2121              <span class="hero-waypoint">Malacca</span>
2122              <span class="hero-waypoint-arrow">&rarr;</span>
2123              <span class="hero-waypoint">Indian Ocean</span>
2124              <span class="hero-waypoint-arrow">&rarr;</span>
2125              <span class="hero-waypoint">Bab el-Mandeb</span>
2126              <span class="hero-waypoint-arrow">&rarr;</span>
2127              <span class="hero-waypoint">Suez</span>
2128              <span class="hero-waypoint-arrow">&rarr;</span>
2129              <span class="hero-waypoint">Mediterranean</span>
2130            </div>
2131          </div>
2132          <!-- Cycling preview -->
2133          <div class="hero-preview" id="heroPreview">
2134            <div class="hero-preview-item active">
2135              <span class="hero-preview-icon"><svg viewBox="0 0 24 24"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg></span>
2136              <span class="hero-preview-text"><strong>Sanctions &amp; Ownership</strong> &mdash; OFAC, UN, EU screening + ownership-chain exposure</span>
2137            </div>
2138            <div class="hero-preview-item">
2139              <span class="hero-preview-icon"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg></span>
2140              <span class="hero-preview-text"><strong>Fleet Tracking</strong> &mdash; 50K+ vessels, dark activity detection</span>
2141            </div>
2142            <div class="hero-preview-item">
2143              <span class="hero-preview-icon"><svg viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg></span>
2144              <span class="hero-preview-text"><strong>7 Report Types</strong> &mdash; AI-narrated PDF intelligence</span>
2145            </div>
2146            <div class="hero-preview-item">
2147              <span class="hero-preview-icon"><svg viewBox="0 0 24 24"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg></span>
2148              <span class="hero-preview-text"><strong>Monte Carlo</strong> &mdash; 500 stochastic simulations per route</span>
2149            </div>
2150          </div>
2151        </div>
2152      </div>
2153
2154      <!-- Results panel -->
2155      <div class="scorer-results" id="scorerResults"></div>
2156    </div>
2157  </section>
2158
2159  <!-- ============================================================
2160       METRICS BAR
2161       ============================================================ -->
2162  <section class="proof">
2163    <div class="container">
2164      <div class="proof-label reveal">Maritime intelligence at scale</div>
2165      <div class="proof-grid">
2166        <div class="proof-metric reveal reveal-delay-1">
2167          <div class="proof-number" data-count="11" data-suffix="">0</div>
2168          <div class="proof-desc">Intelligence Signals</div>
2169        </div>
2170        <div class="proof-metric reveal reveal-delay-1">
2171          <div class="proof-number" data-count="510" data-suffix="+">0</div>
2172          <div class="proof-desc">Global Ports</div>
2173        </div>
2174        <div class="proof-metric reveal reveal-delay-2">
2175          <div class="proof-number" data-count="500" data-suffix="">0</div>
2176          <div class="proof-desc">MC Simulations</div>
2177        </div>
2178        <div class="proof-metric reveal reveal-delay-2">
2179          <div class="proof-number" data-count="50" data-suffix="K+">0</div>
2180          <div class="proof-desc">Vessels Tracked</div>
2181        </div>
2182        <div class="proof-metric reveal reveal-delay-3">
2183          <div class="proof-number" data-count="9" data-suffix="">0</div>
2184          <div class="proof-desc">Alert Types</div>
2185        </div>
2186        <div class="proof-metric reveal reveal-delay-3">
2187          <div class="proof-number" data-count="6" data-suffix="">0</div>
2188          <div class="proof-desc">Report Types</div>
2189        </div>
2190      </div>
2191      <div class="reveal reveal-delay-3" style="text-align:center;margin-top:24px;color:var(--text-dim);font-size:12px;font-family:var(--mono);letter-spacing:0.02em;line-height:1.6;">
2192        Live coverage updated every 5 minutes from OFAC SDN, EU FSF, UN Consolidated, GDELT, NGA, IMB, ReCAAP, GLEIF, Tokyo MoU, and the Paris MoU.
2193      </div>
2194    </div>
2195  </section>
2196
2197  <!-- ============================================================
2198       COMPETITIVE WEDGE
2199       ============================================================ -->
2200  <section style="padding:56px 0;background:var(--bg);border-top:1px solid var(--accent);border-bottom:1px solid var(--border);">
2201    <div class="container" style="max-width:820px;text-align:center;">
2202      <div style="font-family:var(--mono);font-size:11px;font-weight:600;color:var(--accent);letter-spacing:0.1em;text-transform:uppercase;margin-bottom:14px;" class="reveal">Why ArcNautical</div>
2203      <h3 style="font-family:var(--display);font-size:clamp(1.4rem,2.2vw,1.9rem);color:var(--text);margin-bottom:14px;font-weight:400;" class="reveal">Published methodology. Defensible numbers.</h3>
2204      <p style="color:var(--text-sec);font-size:15px;line-height:1.7;" class="reveal reveal-delay-1">Most maritime intel platforms are closed black boxes. ArcNautical publishes every signal, every weight, every data source. If your team can&rsquo;t defend the number to a regulator, it&rsquo;s noise &mdash; not intelligence.</p>
2205    </div>
2206  </section>
2207
2208  <!-- ============================================================
2209       INTELLIGENCE TICKER
2210       ============================================================ -->
2211  <section class="ticker-section">
2212    <div class="ticker-header">
2213      <span class="ticker-dot" id="tickerDot"></span>
2214      <span class="ticker-title">Intelligence Feed</span>
2215      <span class="live-badge" id="feedLiveBadge" style="display:none;margin-left:8px;">
2216        <span class="live-dot"></span>LIVE
2217      </span>
2218      <span id="feedUpdatedAt" style="font-family:var(--mono);font-size:10px;color:var(--text-dim);margin-left:12px;"></span>
2219    </div>
2220    <div class="ticker-track" id="tickerTrack"></div>
2221  </section>
2222
2223  <!-- ============================================================
2224       HOW IT WORKS
2225       ============================================================ -->
2226
2227  <section class="hiw-section" id="how-it-works">
2228    <div class="container">
2229      <div class="hiw-inner">
2230        <div class="section-label reveal" style="text-align:center;">How it works</div>
2231        <h2 class="section-title reveal" style="text-align:center;">Vessel vetting in minutes, not hours</h2>
2232
2233        <div class="hiw-steps reveal reveal-delay-1">
2234          <div class="hiw-step">
2235            <span class="hiw-step-connector">&rarr;</span>
2236            <div class="hiw-step-num">1</div>
2237            <div class="hiw-step-title">Enter a voyage</div>
2238            <div class="hiw-step-desc">IMO number, origin and destination ports, or paste a full itinerary</div>
2239          </div>
2240          <div class="hiw-step">
2241            <span class="hiw-step-connector">&rarr;</span>
2242            <div class="hiw-step-num">2</div>
2243            <div class="hiw-step-title">Get a risk score</div>
2244            <div class="hiw-step-desc">10 live intelligence sources scored in under 2 seconds with full explainability</div>
2245          </div>
2246          <div class="hiw-step">
2247            <span class="hiw-step-connector">&rarr;</span>
2248            <div class="hiw-step-num">3</div>
2249            <div class="hiw-step-title">Screen the entity</div>
2250            <div class="hiw-step-desc">Sanctions, ownership chain, flag performance, and PSC detention history</div>
2251          </div>
2252          <div class="hiw-step">
2253            <div class="hiw-step-num">4</div>
2254            <div class="hiw-step-title">Export the report</div>
2255            <div class="hiw-step-desc">Defensible PDF for your compliance file, audit trail included</div>
2256          </div>
2257        </div>
2258
2259        <div class="hiw-built-for reveal reveal-delay-2">
2260          <div class="section-label" style="text-align:center;margin-bottom:16px;">Built for</div>
2261          <div class="hiw-personas">
2262            <div class="hiw-persona">
2263              <span class="hiw-persona-icon"><svg viewBox="0 0 24 24"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg></span>
2264              <div>
2265                <div>Marine hull underwriters</div>
2266                <div class="hiw-persona-workflow">Replaces manual vessel vetting</div>
2267              </div>
2268            </div>
2269            <div class="hiw-persona">
2270              <span class="hiw-persona-icon"><svg viewBox="0 0 24 24"><path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg></span>
2271              <div>
2272                <div>War risk brokers</div>
2273                <div class="hiw-persona-workflow">Replaces JWC + NAVAREA cross-referencing</div>
2274              </div>
2275            </div>
2276            <div class="hiw-persona">
2277              <span class="hiw-persona-icon"><svg viewBox="0 0 24 24"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/></svg></span>
2278              <div>
2279                <div>P&amp;I club analysts</div>
2280                <div class="hiw-persona-workflow">Replaces multi-source loss analysis</div>
2281              </div>
2282            </div>
2283            <div class="hiw-persona">
2284              <span class="hiw-persona-icon"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/></svg></span>
2285              <div>
2286                <div>Fleet operations teams</div>
2287                <div class="hiw-persona-workflow">Replaces manual route risk assessment</div>
2288              </div>
2289            </div>
2290            <div class="hiw-persona">
2291              <span class="hiw-persona-icon"><svg viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg></span>
2292              <div>
2293                <div>Compliance &amp; legal teams</div>
2294                <div class="hiw-persona-workflow">Audit trail for OFAC, EU, UNSC screening</div>
2295              </div>
2296            </div>
2297            <div class="hiw-persona">
2298              <span class="hiw-persona-icon"><svg viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18" rx="2"/><line x1="3" y1="9" x2="21" y2="9"/><line x1="9" y1="21" x2="9" y2="9"/></svg></span>
2299              <div>
2300                <div>Cargo owners &amp; charterers</div>
2301                <div class="hiw-persona-workflow">Vets vessels before loading decisions</div>
2302              </div>
2303            </div>
2304            <div class="hiw-persona">
2305              <span class="hiw-persona-icon"><svg viewBox="0 0 24 24"><path d="M12 2l3 7h7l-5.5 4.5L18 21l-6-4-6 4 1.5-7.5L2 9h7z"/></svg></span>
2306              <div>
2307                <div>Ship managers</div>
2308                <div class="hiw-persona-workflow">Port-call risk screening for day-to-day ops</div>
2309              </div>
2310            </div>
2311            <div class="hiw-persona">
2312              <span class="hiw-persona-icon"><svg viewBox="0 0 24 24"><path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/></svg></span>
2313              <div>
2314                <div>Ship finance &amp; maritime lenders</div>
2315                <div class="hiw-persona-workflow">Counterparty risk before loan origination</div>
2316              </div>
2317            </div>
2318            <div class="hiw-persona">
2319              <span class="hiw-persona-icon"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg></span>
2320              <div>
2321                <div>Port state control &amp; authorities</div>
2322                <div class="hiw-persona-workflow">Pre-arrival sanctions &amp; flag-performance check</div>
2323              </div>
2324            </div>
2325            <div class="hiw-persona">
2326              <span class="hiw-persona-icon"><svg viewBox="0 0 24 24"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg></span>
2327              <div>
2328                <div>Commodity traders &amp; brokers</div>
2329                <div class="hiw-persona-workflow">Voyage risk before chartering</div>
2330              </div>
2331            </div>
2332          </div>
2333        </div>
2334      </div>
2335    </div>
2336  </section>
2337
2338  <!-- ============================================================
2339       DEVELOPER API — keyless check first, then the full record
2340       ============================================================ -->
2341  <section class="section api-section" id="api">
2342    <div class="container">
2343      <div class="api-grid">
2344        <div class="reveal">
2345          <div class="section-label">Developer API</div>
2346          <h2 class="section-title">Screen a vessel from your own system</h2>
2347          <p class="section-desc">Sanctions status, ownership opacity and a vetting grade for any IMO, as JSON &mdash; wired into an order pipeline, a chartering desk or a spreadsheet. Start with one unauthenticated GET. Mint a key when you want the full evidence record, batches, standing monitors and webhooks.</p>
2348          <ul class="api-features">
2349            <li class="api-feature"><span class="api-feature-check"><svg viewBox="0 0 24 24"><path d="M20 6L9 17l-5-5"/></svg></span>Keyless check: 100 requests an hour per IP, no signup</li>
2350            <li class="api-feature"><span class="api-feature-check"><svg viewBox="0 0 24 24"><path d="M20 6L9 17l-5-5"/></svg></span>Self-serve test and live keys &mdash; no approval step, no waiting list</li>
2351            <li class="api-feature"><span class="api-feature-check"><svg viewBox="0 0 24 24"><path d="M20 6L9 17l-5-5"/></svg></span>5,000 vessel screenings to start and 10,000 voyage assessments a month, included</li>
2352            <li class="api-feature"><span class="api-feature-check"><svg viewBox="0 0 24 24">
2352<path d="M20 6L9 17l-5-5"/></svg></span>Batches of 50 hulls, standing vessel monitors, fleet change feeds</li>
2353            <li class="api-feature"><span class="api-feature-check"><svg viewBox="0 0 24 24"><path d="M20 6L9 17l-5-5"/></svg></span>HMAC-SHA256 signed webhooks, 24-hour idempotent replay</li>
2354            <li class="api-feature"><span class="api-feature-check"><svg viewBox="0 0 24 24"><path d="M20 6L9 17l-5-5"/></svg></span>Rate and quota headers on every response, OpenAPI 3.1 contract</li>
2355            <li class="api-feature"><span class="api-feature-check"><svg viewBox="0 0 24 24"><path d="M20 6L9 17l-5-5"/></svg></span>Screening records retained ten years, every source dated</li>
2356          </ul>
2357          <div style="display:flex;gap:10px;flex-wrap:wrap;margin-top:20px">
2358            <a href="/arcnautical.html?utm_source=landing&amp;utm_campaign=get_a_key&amp;intent=api#/register" class="btn-primary" style="text-decoration:none;">Get an API key</a>
2359            <a href="/developers/" class="btn-ghost" style="text-decoration:none;">Read API documentation &rarr;</a>
2360          </div>
2361          <p id="api-access" style="margin-top:18px;color:var(--text-sec);font-size:13.5px;line-height:1.65">The keyless call returns the verdict. A key returns what the engine already computed underneath it: every sanctions match with its list, programme and confidence class, the five weighted vetting factors, and per-source freshness. Both run the same engine. Machine-readable: <a href="/api/v1/openapi.json" style="color:var(--accent)">OpenAPI</a> &middot; <a href="/llms.txt" style="color:var(--accent)">llms.txt</a> &middot; <a href="/developers/AGENTS.md" style="color:var(--accent)">AGENTS.md</a> &middot; <a href="https://www.postman.com/arcnautical-6322764/arcnautical-s-workspace" target="_blank" rel="noopener" style="color:var(--accent)">Postman</a></p>
2362        </div>
2363        <div class="reveal reveal-delay-2">
2364          <div class="api-tabs" id="apiTabs">
2365            <button class="api-tab active" data-api="check">Check &middot; no key</button>
2366            <button class="api-tab" data-api="screening">Screening</button>
2367            <button class="api-tab" data-api="batch">Batch</button>
2368            <button class="api-tab" data-api="monitor">Monitor</button>
2369            <button class="api-tab" data-api="voyage">Voyage Risk</button>
2370          </div>
2371
2372          <!-- Keyless check -->
2373          <div class="api-panel active" data-api-panel="check">
2374            <div class="code-block">
2375              <div class="code-header"><span class="code-method">GET</span> /api/v1/vessels/{imo}/check <span style="margin-left:auto;color:var(--text-dim)">no key</span></div>
2376              <div class="code-body"><pre style="margin:0;white-space:pre;tab-size:2;">curl https://arcnautical.com/api/v1/vessels/9274446/check</pre></div>
2377            </div>
2378            <div class="code-block">
2379              <div class="code-header"><span style="color:var(--risk-low);font-weight:600;">200</span> Response <span style="margin-left:auto">x-ratelimit-limit: 100</span></div>
2380              <div class="code-body"><pre style="margin:0;white-space:pre;tab-size:2;">{
2381  <span class="ck">"imo"</span>: <span class="cs">"9274446"</span>,
2382  <span class="ck">"sanctions"</span>: {
2383    <span class="ck">"status"</span>: <span class="cs">"RED"</span>,
2384    <span class="ck">"detail"</span>: <span class="cs">"4 confirmed matches on vessel identifier."</span>,
2385    <span class="ck">"coverageComplete"</span>: <span class="cv">true</span>
2386  },
2387  <span class="ck">"ownership"</span>: { <span class="ck">"opacity"</span>: <span class="cs">"MEDIUM"</span>, <span class="ck">"score"</span>: <span class="cn">40</span> },
2388  <span class="ck">"vetting"</span>: { <span class="ck">"grade"</span>: <span class="cs">"E"</span>, <span class="ck">"score"</span>: <span class="cn">90</span>, <span class="ck">"status"</span>: <span class="cs">"unacceptable"</span> },
2389  <span class="ck">"assessed"</span>: <span class="cv">true</span>,
2390  <span class="ck">"tier"</span>: <span class="cs">"keyless"</span>
2391}</pre></div>
2392            </div>
2393            <a href="/api/v1/vessels/9274446/check" target="_blank" rel="noopener" style="font-family:var(--mono);font-size:11.5px;color:var(--accent);text-decoration:none;">Run this call in your browser &rarr;</a>
2394          </div>
2395
2396          <!-- Screening with a key -->
2397          <div class="api-panel" data-api-panel="screening">
2398            <div class="code-block">
2399              <div class="code-header"><span class="code-method">POST</span> /api/v1/screenings</div>
2400              <div class="code-body"><pre style="margin:0;white-space:pre;tab-size:2;"><span class="cb">Authorization: Bearer arc_live_...
2401Idempotency-Key: screening:9274446:2026-09-12</span>
2402{ <span class="ck">"imo"</span>: <span class="cs">"9274446"</span>, <span class="ck">"customer_reference"</span>: <span class="cs">"order-48213"</span> }</pre></div>
2403            </div>
2404            <div class="code-block">
2405              <div class="code-header"><span style="color:var(--risk-low);font-weight:600;">201</span> Response</div>
2406              <div class="code-body"><pre style="margin:0;white-space:pre;tab-size:2;">{
2407  <span class="ck">"id"</span>: <span class="cs">"dfa1bde9-..."</span>,
2408  <span class="ck">"imo"</span>: <span class="cs">"9274446"</span>,
2409  <span class="ck">"vessel_name"</span>: <span class="cs">"HS STAR"</span>,
2410  <span class="ck">"sanctions"</span>: {
2411    <span class="ck">"status"</span>: <span class="cs">"RED"</span>,
2412    <span class="ck">"matches"</span>: [
2413      { <span class="ck">"name"</span>: <span class="cs">"HS STAR"</span>, <span class="ck">"source"</span>: <span class="cs">"ofac_sdn"</span>,
2414        <span class="ck">"programs"</span>: [<span class="cs">"RUSSIA-EO14024"</span>],
2415        <span class="ck">"match_type"</span>: <span class="cs">"exact_imo"</span>,
2416        <span class="ck">"confidence_class"</span>: <span class="cs">"confirmed"</span> },
2417      <span class="cb">...</span>
2418    ],
2419    <span class="ck">"coverage_complete"</span>: <span class="cv">true</span>
2420  },
2421  <span class="ck">"ownership"</span>: { <span class="ck">"opacity"</span>: <span class="cs">"MEDIUM"</span>, <span class="ck">"score"</span>: <span class="cn">40</span> },
2422  <span class="ck">"vetting"</span>: { <span class="ck">"grade"</span>: <span class="cs">"E"</span>, <span class="ck">"detention_count"</span>: <span class="cn">1</span>, <span class="ck">"factors"</span>: [ <span class="cb">...</span> ] },
2423  <span class="ck">"sources"</span>: [
2424    { <span class="ck">"source"</span>: <span class="cs">"ofac_sdn"</span>, <span class="ck">"status"</span>: <span class="cs">"ok"</span>, <span class="ck">"checked_at"</span>: <span class="cs">"..."</span> },
2425    <span class="cb">...</span>
2426  ],
2427  <span class="ck">"customer_reference"</span>: <span class="cs">"order-48213"</span>,
2428  <span class="ck">"expires_at"</span>: <span class="cs">"..."</span>
2429}</pre></div>
2430            </div>
2431          </div>
2432
2433          <!-- Batch -->
2434          <div class="api-panel" data-api-panel="batch">
2435            <div class="code-block">
2436              <div class="code-header"><span class="code-method">POST</span> /api/v1/screening-batches</div>
2437              <div class="code-body"><pre style="margin:0;white-space:pre;tab-size:2;">{
2438  <span class="ck">"imos"</span>: [
2439    <span class="cs">"9274446"</span>,
2440    { <span class="ck">"imo"</span>: <span class="cs">"9141285"</span>, <span class="ck">"customer_reference"</span>: <span class="cs">"order-48214"</span> },
2441    <span class="cb">... up to 50</span>
2442  ]
2443}</pre></div>
2444            </div>
2445            <div class="code-block">
2446              <div class="code-header"><span style="color:var(--risk-low);font-weight:600;">202</span> Response</div>
2447              <div class="code-body"><pre style="margin:0;white-space:pre;tab-size:2;">{
2448  <span class="ck">"id"</span>: <span class="cs">"batch-id"</span>,
2449  <span class="ck">"status"</span>: <span class="cs">"queued"</span>,
2450  <span class="ck">"submitted_count"</span>: <span class="cn">50</span>,
2451  <span class="ck">"accepted_count"</span>: <span class="cn">49</span>,
2452  <span class="ck">"duplicate_count"</span>: <span class="cn">1</span>,
2453  <span class="ck">"failed_count"</span>: <span class="cn">0</span>
2454}
2455<span class="cb">// poll GET /screening-batches/{id}/items, or subscribe to screening_batch.completed</span></pre></div>
2456            </div>
2457          </div>
2458
2459          <!-- Monitor -->
2460          <div class="api-panel" data-api-panel="monitor">
2461            <div class="code-block">
2462              <div class="code-header"><span class="code-method">POST</span> /api/v1/vessel-monitors</div>
2463              <div class="code-body"><pre style="margin:0;white-space:pre;tab-size:2;">{ <span class="ck">"imo"</span>: <span class="cs">"9274446"</span>, <span class="ck">"customer_reference"</span>: <span class="cs">"supplier-book"</span> }</pre></div>
2464            </div>
2465            <div class="code-block">
2466              <div class="code-header"><span style="color:var(--risk-low);font-weight:600;">201</span> Response &middot; then a webhook only when the verdict moves</div>
2467              <div class="code-body"><pre style="margin:0;white-space:pre;tab-size:2;">{
2468  <span class="ck">"id"</span>: <span class="cs">"monitor-id"</span>,
2469  <span class="ck">"imo"</span>: <span class="cs">"9274446"</span>,
2470  <span class="ck">"status"</span>: <span class="cs">"active"</span>,
2471  <span class="ck">"next_run_at"</span>: <span class="cs">"..."</span>
2472}
2473<span class="cb">// webhook vessel_risk.changed:
2474//   { event_type: "changed", sanctions_status, vetting_grade, change_body: [...] }</span></pre></div>
2475            </div>
2476          </div>
2477
2478          <!-- Voyage Risk -->
2479          <div class="api-panel" data-api-panel="voyage">
2480            <div class="code-block">
2481              <div class="code-header"><span class="code-method">POST</span> /api/v1/voyage-assessments</div>
2482              <div class="code-body"><pre style="margin:0;white-space:pre;tab-size:2;">{
2483  <span class="ck">"customer_reference"</span>: <span class="cs">"lane-001"</span>,
2484  <span class="ck">
2484"route"</span>: {
2485    <span class="ck">"origin"</span>: { <span class="ck">"locode"</span>: <span class="cs">"NLRTM"</span> },
2486    <span class="ck">"destination"</span>: { <span class="ck">"locode"</span>: <span class="cs">"CNSHA"</span> },
2487    <span class="ck">"vessel_type"</span>: <span class="cs">"container"</span>
2488  }
2489}</pre></div>
2490            </div>
2491            <div class="code-block">
2492              <div class="code-header"><span style="color:var(--risk-low);font-weight:600;">201</span> Response</div>
2493              <div class="code-body"><pre style="margin:0;white-space:pre;tab-size:2;">{
2494  <span class="ck">"id"</span>: <span class="cs">"76e0b22d-..."</span>,
2495  <span class="ck">"score"</span>: <span class="cn">55</span>,
2496  <span class="ck">"risk_level"</span>: <span class="cs">"elevated"</span>,
2497  <span class="ck">"route"</span>: {
2498    <span class="ck">"origin_locode"</span>: <span class="cs">"NLRTM"</span>, <span class="ck">"dest_locode"</span>: <span class="cs">"CNSHA"</span>,
2499    <span class="ck">"distance_nm"</span>: <span class="cn">10082.3</span>
2500  },
2501  <span class="ck">"drivers"</span>: [
2502    { <span class="ck">"source"</span>: <span class="cs">"cii"</span>, <span class="ck">"signal_score"</span>: <span class="cn">74</span>, <span class="ck">"weight_pct"</span>: <span class="cn">12</span>,
2503      <span class="ck">"contribution_band"</span>: <span class="cs">"medium"</span>, <span class="ck">"relative_rank"</span>: <span class="cn">1</span> }
2504  ]
2505}</pre></div>
2506            </div>
2507          </div>
2508        </div>
2509      </div>
2510    </div>
2511  </section>
2512
2513  <!-- ============================================================
2514       "10 SIGNALS, ONE SCORE"
2515       ============================================================ -->
2516  <section class="section signals-section" id="signals">
2517    <div class="container">
2518      <div class="section-center">
2519        <div class="section-label reveal">Core Intelligence</div>
2520        <h2 class="section-title reveal">11 signals, one score</h2>
2521        <p class="section-desc reveal">Every voyage risk score fuses ten independent intelligence signals through weighted, active-signal scoring. Zero-count signals are excluded automatically&mdash;only real threats drive the composite.</p>
2522      </div>
2523      <div class="signals-layout">
2524        <div class="signals-svg-wrap reveal">
2525          <svg id="signalsSvg" viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg">
2526            <!-- Background arc -->
2527            <path d="M 50,350 A 250,250 0 0,1 350,350" fill="none" stroke="#1c2a3e" stroke-width="1" opacity="0.5"/>
2528            <!-- Central gauge circle -->
2529            <circle cx="200" cy="350" r="44" fill="#0d1420" stroke="#1c2a3e" stroke-width="1.5"/>
2530            <text x="200" y="345" text-anchor="middle" dominant-baseline="central" fill="#d0d8e8" font-family="'JetBrains Mono',monospace" font-size="20" font-weight="600" id="signalsCenterScore">0</text>
2531            <text x="200" y="368" text-anchor="middle" fill="#0891b2" font-family="'JetBrains Mono',monospace" font-size="8" letter-spacing="0.1em">COMPOSITE</text>
2532            <!-- Signal nodes + connecting lines (generated by JS) -->
2533            <g id="signalLines"></g>
2534            <g id="signalNodes"></g>
2535          </svg>
2536        </div>
2537        <div class="reveal reveal-delay-2">
2538          <ul class="signal-list">
2539            <li class="signal-item"><span class="signal-dot" style="background:var(--risk-crit)"></span>GDELT Conflict<span class="signal-num">01</span></li>
2540            <li class="signal-item"><span class="signal-dot" style="background:var(--risk-high)"></span>Piracy Intel<span class="signal-num">02</span></li>
2541            <li class="signal-item"><span class="signal-dot" style="background:var(--risk-elev)"></span>NGA NAVWARNs<span class="signal-num">03</span></li>
2542            <li class="signal-item"><span class="signal-dot" style="background:var(--accent)"></span>JWC Listed Areas<span class="signal-num">04</span></li>
2543            <li class="signal-item"><span class="signal-dot" style="background:#a78bfa"></span>AIS Disruption<span class="signal-num">05</span></li>
2544            <li class="signal-item"><span class="signal-dot" style="background:#6366f1"></span>Country Instability<span class="signal-num">06</span></li>
2545            <li class="signal-item"><span class="signal-dot" style="background:#38bdf8"></span>Weather &amp;
2545 Sea State<span class="signal-num">07</span></li>
2546            <li class="signal-item"><span class="signal-dot" style="background:#f472b6"></span>Sanctions Exposure<span class="signal-num">08</span></li>
2547            <li class="signal-item"><span class="signal-dot" style="background:#fb923c"></span>Dark-Fleet Activity<span class="signal-num">09</span></li>
2548            <li class="signal-item"><span class="signal-dot" style="background:#2dd4bf"></span>Chokepoint Disruption<span class="signal-num">10</span></li>
2549            <li class="signal-item"><span class="signal-dot" style="background:#fbbf24"></span>Natural Disasters<span class="signal-num">11</span></li>
2550          </ul>
2551        </div>
2552      </div>
2553    </div>
2554  </section>
2555
2556  <!-- ============================================================
2557       DATA SOURCES BANNER
2558       ============================================================ -->
2559  <section class="sources-banner" aria-label="Intelligence data sources">
2560    <div class="container">
2561      <div class="sources-label reveal">Intelligence sourced from 17+ open &amp; commercial data providers</div>
2562      <div class="sources-categories">
2563        <div class="sources-cat-row reveal reveal-delay-1">
2564          <span class="sources-cat-label">Security</span>
2565          <div class="source-badge"><span class="source-badge-icon" style="background:var(--risk-crit)"></span><span class="source-badge-name">GDELT</span><span class="source-badge-org">Conflict Events</span></div>
2566          <div class="source-badge"><span class="source-badge-icon" style="background:var(--risk-high)"></span><span class="source-badge-name">ICC-IMB</span><span class="source-badge-org">Live Piracy</span></div>
2567          <div class="source-badge"><span class="source-badge-icon" style="background:var(--risk-high)"></span><span class="source-badge-name">ReCAAP</span><span class="source-badge-org">Asia-Pacific</span></div>
2568          <div class="source-badge"><span class="source-badge-icon" style="background:var(--accent)"></span><span class="source-badge-name">JWC</span><span class="source-badge-org">Listed Areas</span></div>
2569          <div class="source-badge"><span class="source-badge-icon" style="background:var(--risk-elev)"></span><span class="source-badge-name">NGA</span><span class="source-badge-org">Broadcast Warnings</span></div>
2570        </div>
2571        <div class="sources-cat-row reveal reveal-delay-2">
2572          <span class="sources-cat-label">Compliance</span>
2573          <div class="source-badge"><span class="source-badge-icon" style="background:#f472b6"></span><span class="source-badge-name">OFAC SDN</span><span class="source-badge-org">US Sanctions</span></div>
2574          <div class="source-badge"><span class="source-badge-icon" style="background:#f472b6"></span><span class="source-badge-name">UN SCRL</span><span class="source-badge-org">Int'l Sanctions</span></div>
2575          <div class="source-badge"><span class="source-badge-icon" style="background:#f472b6"></span><span class="source-badge-name">OpenSanctions</span><span class="source-badge-org">Maritime Dataset</span></div>
2576          <div class="source-badge"><span class="source-badge-icon" style="background:var(--risk-low)"></span><span class="source-badge-name">GLEIF</span><span class="source-badge-org">Corporate LEI</span></div>
2577        </div>
2578        <div class="sources-cat-row reveal reveal-delay-3">
2579          <span class="sources-cat-label">Operations</span>
2580          <div class="source-badge"><span class="source-badge-icon" style="background:#38bdf8"></span><span class="source-badge-name">Open-Meteo</span><span class="source-badge-org">Marine Weather</span></div>
2581          <div class="source-badge"><span class="source-badge-icon" style="background:var(--risk-high)"></span><span class="source-badge-name">GDACS</span><span class="source-badge-org">Disasters</span></div>
2582          <div class="source-badge"><span class="source-badge-icon" style="background:#fbbf24"></span><span class="source-badge-name">NHC</span><span class="source-badge-org">Cyclones</span></div>
2583          <div class="source-badge"><span class="source-badge-icon" style="background:#fb923c"></span><span class="source-badge-name">Tokyo MOU</span><span class="source-badge-org">PSC Detentions</span></div>
2584          <div class="source-badge"><span class="source-badge-icon" style="background:#fb923c"></span><span class="source-badge-name">Paris MoU</span><span class="source-badge-org">THETIS PSC Inspections</span></div>
2585          <div class="source-badge"><span class="source-badge-icon" style="background:#fb923c"></span><span class="source-badge-name">Regional MoUs</span><span class="source-badge-org">6 more PSC regimes</span></div>
2586        </div>
2587        <div class="sources-cat-row reveal reveal-delay-4">
2588          <span class="sources-cat-label">Logistics</span>
2589          <div class="source-badge"><span class="source-badge-icon" style="background:#22d3ee"></span><span class="source-badge-name">IMF PortWatch</span><span class="source-badge-org">Port Activity &amp; Disruptions</span></div>
2590          <div class="source-badge"><span class="source-badge-icon" style="background:#34d399"></span><span class="source-badge-name">Terminal49</span><span class="source-badge-org">Container Tracking</span></div>
2591          <div class="source-badge"><span class="source-badge-icon" style="background:#a78bfa"></span><span class="source-badge-name">FRED</span><span class="source-badge-org">Freight Market Index</span></div>
2592        </div>
2593      </div>
2594    </div>
2595  </section>
2596
2597  <!-- ============================================================
2598       TABBED PRODUCT SHOWCASE
2599       ============================================================ -->
2600  <section class="section showcase-section" id="products">
2601    <div class="container">
2602      <div class="section-center">
2603        <div class="section-label reveal">Platform</div>
2604        <h2 class="section-title reveal">Everything a maritime underwriter needs</h2>
2605      </div>
2606      <div class="showcase-tabs reveal" id="showcaseTabs">
2607        <button class="showcase-tab active" data-tab="voyage">Voyage Risk Scoring</button>
2608        <button class="showcase-tab" data-tab="stochastic">Stochastic Monte Carlo</button>
2609        <button class="showcase-tab" data-tab="fleet">Fleet &amp; Dark Activity</button>
2610        <button class="showcase-tab" data-tab="tracking">Container Tracking</button>
2611        <button class="showcase-tab" data-tab="underwriting">Underwriting &amp; PML</button>
2612        <button class="showcase-tab" data-tab="reports">Reports &amp; Compliance</button>
2613      </div>
2614      <div class="showcase-panels">
2615        <!-- VOYAGE RISK TAB -->
2616        <div class="showcase-panel active" data-panel="voyage">
2617          <div>
2618            <h3 class="section-title" style="font-size:clamp(1.4rem,2.5vw,1.8rem);">VoyageRiskScore</h3>
2619            <p class="section-desc">Quantified port-to-port risk assessment fusing ten independent intelligence sources into a single 0&ndash;100 score. Full driver breakdown shows exactly what's driving the risk.</p>
2620            <ul style="list-style:none;display:flex;flex-direction:column;gap:8px;">
2621              <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:var(--risk-crit)"></span>11 weighted signal sources with active-signal redistribution</li>
2622              <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:var(--accent)"></span>CII safety floors prevent under-scoring war zones</li>
2623              <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:var(--risk-low)"></span>Data confidence indicator with missing source warnings</li>
2624              <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:var(--risk-elev)"></span>Sub-2s scoring across 510+ port pairs</li>
2625            </ul>
2626          </div>
2627          <div>
2628            <div class="mockup-card">
2629              <div class="mockup-titlebar">
2630                <span class="mockup-dot"></span><span class="mockup-dot"></span><span class="mockup-dot"></span>
2631                <span class="mockup-titlebar-text">arcnautical.com/voyage-scorer</span>
2632              </div>
2633              <div class="mockup-body">
2634                <div style="display:flex;align-items:center;gap:20px;margin-bottom:16px;">
2635                  <svg id="mockGauge" width="100" height="100" viewBox="0 0 100 100"></svg>
2636                  <div>
2637                    <div style="font-family:var(--mono);font-size:14px;font-weight:600;color:var(--text);margin-bottom:4px;">Singapore &rarr; Rotterdam</div>
2638                    <div style="font-family:var(--mono);font-size:11px;color:var(--text-dim);line-height:1.6;">SGSIN &rarr; NLRTM<br>Distance: 8,441 nm</div>
2639                  </div>
2640                </div>
2641                <div style="font-family:var(--mono);font-size:10px;color:var(--text-dim);text-transform:uppercase;letter-spacing:0.08em;margin-bottom:6px;">Signal Contribution</div>
2642                <div class="breakdown-bar">
2643                  <div class="breakdown-segment" style="flex:10;background:var(--risk-crit);"></div>
2644                  <div class="breakdown-segment" style="flex:18;background:var(--risk-high);"></div>
2645                  <div class="breakdown-segment" style="flex:12;background:var(--risk-elev);"></div>
2646                  <div class="breakdown-segment" style="flex:15;background:var(--accent);"></div>
2647                  <div class="breakdown-segment" style="flex:8;background:#a78bfa;"></div>
2648                  <div class="breakdown-segment" style="flex:12;background:#6366f1;"></div>
2649                  <div class="breakdown-segment" style="flex:8;background:#38bdf8;"></div>
2650                  <div class="breakdown-segment" style="flex:7;background:#f472b6;"></div>
2651                  <div class="breakdown-segment" style="flex:5;background:#fb923c;"></div>
2652                  <div class="breakdown-segment" style="flex:5;background:#fbbf24;"></div>
2653                </div>
2654                <div class="breakdown-legend">
2655                  <div class="breakdown-legend-item"><span class="breakdown-legend-dot" style="background:var(--risk-crit)"></span>Conflict</div>
2656                  <div class="breakdown-legend-item"><span class="breakdown-legend-dot" style="background:var(--risk-high)"></span>Piracy</div>
2657                  <div class="breakdown-legend-item"><span class="breakdown-legend-dot" style="background:var(--risk-elev)"></span>NAVWARN</div>
2658                  <div class="breakdown-legend-item"><span class="breakdown-legend-dot" style="background:var(--accent)"></span>JWC</div>
2659                  <div class="breakdown-legend-item"><span class="breakdown-legend-dot" style="background:#a78bfa"></span>AIS</div>
2660                  <div class="breakdown-legend-item"><span class="breakdown-legend-dot" style="background:#6366f1"></span>CII</div>
2661                  <div class="breakdown-legend-item"><span class="breakdown-legend-dot" style="background:#38bdf8"></span>Weather</div>
2662                  <div class="breakdown-legend-item"><span class="breakdown-legend-dot" style="background:#f472b6"></span>Sanctions</div>
2663                  <div class="breakdown-legend-item"><span class="breakdown-legend-dot" style="background:#fb923c"></span>PSC</div>
2664                  <div class="breakdown-legend-item"><span class="breakdown-legend-dot" style="background:#fbbf24"></span>Disaster</div>
2665                </div>
2666              </div>
2667            </div>
2668          </div>
2669        </div>
2670
2671        <!-- STOCHASTIC TAB -->
2672        <div class="showcase-panel" data-panel="stochastic">
2673          <div>
2674            <h3 class="section-title" style="font-size:clamp(1.4rem,2.5vw,1.8rem);">Stochastic Monte Carlo</h3>
2675            <p class="section-desc">500 weather-coupled simulations per voyage. AR(1) correlated weather sequences produce realistic ETA distributions, not just point estimates.</p>
2676            <ul style="list-style:none;display:flex;flex-direction:column;gap:8px;">
2677              <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:var(--accent)"></span>Beaufort speed curves per vessel type &amp; load condition</li>
2678              <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:#38bdf8"></span>Per-segment weather from Open-Meteo marine API</li>
2679              <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:var(--risk-elev)"></span>P10&ndash;P90 ETA distribution with median highlight</li>
2680              <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:var(--risk-low)"></span>Container, bulk, tanker, LNG, general cargo models</li>
2681            </ul>
2682          </div>
2683          <div>
2684            <div class="mockup-card">
2685              <div class="mockup-titlebar">
2686                <span class="mockup-dot"></span><span class="mockup-dot"></span><span class="mockup-dot"></span>
2687                <span class="mockup-titlebar-text">Stochastic Voyage Analysis</span>
2688              </div>
2689              <div class="mockup-body">
2690                <div style="font-family:var(--mono);font-size:11px;color:var(--text-dim);margin-bottom:6px;">CONTAINER &middot; LADEN &middot; 18 KT DESIGN SPEED</div>
2691                <div style="display:flex;gap:24px;margin-bottom:16px;">
2692                  <div>
2693                    <div style="font-family:var(--mono);font-size:10px;color:var(--text-dim);text-transform:uppercase;letter-spacing:0.08em;">Risk (P50)</div>
2694                    <div style="font-family:var(--mono);font-size:28px;font-weight:700;color:var(--risk-elev);">42</div>
2695                  </div>
2696                  <div>
2697                    <div style="font-family:var(--mono);font-size:10px;color:var(--text-dim);text-transform:uppercase;letter-spacing:0.08em;">ETA (Median)</div>
2698                    <div style="font-family:var(--mono);font-size:28px;font-weight:700;color:var(--text);">18.2d</div>
2699                  </div>
2700                  <div>
2701                    <div style="font-family:var(--mono);font-size:10px;color:var(--text-dim);text-transform:uppercase;letter-spacing:0.08em;">Simulations</div>
2702                    <div style="font-family:var(--mono);font-size:28px;font-weight:700;color:var(--accent);">500</div>
2703                  </div>
2704                </div>
2705                <div class="eta-bar-wrap">
2706                  <div class="eta-bar-label">ETA Distribution (P10 &ndash; P90)</div>
2707                  <div class="eta-bar">
2708                    <div class="eta-bar-range" style="left:15%;right:22%;"></div>
2709                    <div class="eta-bar-median" style="left:42%;"></div>
2710                  </div>
2711                  <div class="eta-bar-labels">
2712                    <span>16.1d (P10)</span>
2713                    <span>18.2d (P50)</span>
2714                    <span>21.4d (P90)</span>
2715                  </div>
2716                </div>
2717              </div>
2718            </div>
2719          </div>
2720        </div>
2721
2722        <!-- FLEET TAB -->
2723        <div class="showcase-panel" data-panel="fleet">
2724          <div>
2725            <h3 class="section-title" style="font-size:clamp(1.4rem,2.5vw,1.8rem);">Fleet &amp; Dark Activity</h3>
2726            <p class="section-desc">Real-time vessel tracking with automatic dark activity detection. AIS gaps, speed anomalies, and unauthorized zone entries trigger instant alerts.</p>
2727            <ul style="list-style:none;display:flex;flex-direction:column;gap:8px;">
2728              <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:var(--risk-crit)"></span>AIS gap detection with configurable thresholds</li>
2729              <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:var(--accent)"></span>Dead reckoning position estimation during gaps</li>
2730              <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:#a78bfa"></span>Geofence zones with entry/exit monitoring</li>
2731              <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:var(--risk-elev)"></span>Fleet-wide risk dashboard with KPI metrics</li>
2732            </ul>
2733          </div>
2734          <div>
2735            <div class="mockup-card">
2736              <div class="mockup-titlebar">
2737                <span class="mockup-dot"></span><span class="mockup-dot"></span><span class="mockup-dot"></span>
2738                <span class="mockup-titlebar-text">arcnautical.com/tracking</span>
2739              </div>
2740              <div class="mockup-body" style="padding:0;">
2741                <div class="alert-feed">
2742                  <div class="alert-item" data-severity="critical">
2743                    <span class="alert-badge" data-severity="critical">CRIT</span>
2744                    <div class="alert-content">
2745                      <div class="alert-type">AIS Gap &mdash; Dark Activity</div>
2746                      <div class="alert-msg"><span class="alert-vessel">MV DEMO ALPHA</span> &mdash; 6.2h signal loss &mdash; Bab el-Mandeb</div>
2747                    </div>
2748                  </div>
2749                  <div class="alert-item" data-severity="high">
2750                    <span class="alert-badge" data-severity="high">HIGH</span>
2751                    <div class="alert-content">
2752                      <div class="alert-type">Zone Entry &mdash; JWC Listed Area</div>
2753                      <div class="alert-msg"><span class="alert-vessel">MV DEMO BETA</span> &mdash; Yemen / Red Sea corridor</div>
2754                    </div>
2755                  </div>
2756                  <div class="alert-item" data-severity="medium">
2757                    <span class="alert-badge" data-severity="medium">MED</span>
2758                    <div class="alert-content">
2759                      <div class="alert-type">Speed Anomaly</div>
2760                      <div class="alert-msg"><span class="alert-vessel">MV DEMO DELTA</span> &mdash; 2.1 kt (avg 14 kt) &mdash; Persian Gulf</div>
2761                    </div>
2762                  </div>
2763                </div>
2764              </div>
2765            </div>
2766          </div>
2767        </div>
2768
2769        <!-- CONTAINER TRACKING TAB -->
2770        <div class="showcase-panel" data-panel="tracking">
2771          <div>
2772            <h3 class="section-title" style="font-size:clamp(1.4rem,2.5vw,1.8rem);">Container Tracking</h3>
2773            <p class="section-desc">Track containers across 21 major carriers by BOL, container number, or booking reference. Every tracked shipment is cross-referenced against live threat intelligence&mdash;so you don't just see where your cargo is, you see what risks surround it.</p>
2774            <ul style="list-style:none;display:flex;flex-direction:column;gap:8px;">
2775              <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:#34d399"></span>Track by BOL, container number, or booking reference</li>
2776              <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:var(--accent)"></span>21 carriers: Maersk, MSC, CMA CGM, Hapag-Lloyd, ONE, and more</li>
2777              <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:var(--risk-elev)"></span>Full milestone timeline: loaded, departed, transshipped, arrived, delivered</li>
2778              <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:var(--risk-crit)"></span>Cross-referenced with voyage risk scores and threat intelligence</li>
2779            </ul>
2780          </div>
2781          <div>
2782            <div class="mockup-card">
2783              <div class="mockup-titlebar">
2784                <span class="mockup-dot"></span><span class="mockup-dot"></span><span class="mockup-dot"></span>
2785                <span class="mockup-titlebar-text">arcnautical.com/tracking</span>
2786              </div>
2787              <div class="mockup-body" style="padding:0;">
2788                <div class="alert-feed">
2789                  <div class="alert-item" data-severity="low">
2790                    <span class="alert-badge" data-severity="low" style="font-size:9px;">SHIP</span>
2791                    <div class="alert-content">
2792                      <div class="alert-type" style="font-family:var(--mono);">MSKU7284930</div>
2793                      <div class="alert-msg"><span class="alert-vessel">Maersk (MAEU)</span> &mdash; Shanghai &rarr; Rotterdam &mdash; <span style="color:var(--accent);">ON SHIP</span> &mdash; ETA Apr 12</div>
2794                    </div>
2795                  </div>
2796                  <div class="alert-item" data-severity="critical">
2797                    <span class="alert-badge" data-severity="critical" style="font-size:9px;">RISK</span>
2798                    <div class="alert-content">
2799                      <div class="alert-type" style="font-family:var(--mono);">HLCU2091847</div>
2800                      <div class="alert-msg"><span class="alert-vessel">Hapag-Lloyd</span> &mdash; Jebel Ali &rarr; Felixstowe &mdash; <span style="color:var(--risk-crit);">RED SEA TRANSIT</span> &mdash; Risk: 74</div>
2801                    </div>
2802                  </div>
2803                  <div class="alert-item" data-severity="low">
2804                    <span class="alert-badge" data-severity="low" style="font-size:9px;">ARR</span>
2805                    <div class="alert-content">
2806                      <div class="alert-type" style="font-family:var(--mono);">CMDU5038271</div>
2807                      <div class="alert-msg"><span class="alert-vessel">CMA CGM</span> &mdash; Singapore &rarr; Los Angeles &mdash; <span style="color:var(--risk-low);">DELIVERED</span></div>
2808                    </div>
2809                  </div>
2810                </div>
2811              </div>
2812            </div>
2813          </div>
2814        </div>
2815
2816        <!-- UNDERWRITING TAB -->
2817        <div class="showcase-panel" data-panel="underwriting">
2818          <div>
2819            <h3 class="section-title" style="font-size:clamp(1.4rem,2.5vw,1.8rem);">Underwriting &amp; PML</h3>
2820            <p class="section-desc">Probable Maximum Loss engine with zone-based exposure analysis, EP curves, and stochastic frequency/severity modelling for portfolio-level risk.</p>
2821            <ul style="list-style:none;display:flex;flex-direction:column;gap:8px;">
2822              <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:var(--risk-crit)"></span>EP curve generation with zone-specific loss distributions</li>
2823              <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:var(--accent)"></span>Vessel vetting: detention, flag, age, ownership scoring</li>
2824              <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:#f472b6"></span>OFAC/UN/EU sanctions screening on all entity chains</li>
2825              <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:var(--risk-elev)"></span>Fleet-wide PML exposure snapshots on cron</li>
2826            </ul>
2827          </div>
2828          <div>
2829            <div class="mockup-card">
2830              <div class="mockup-titlebar">
2831                <span class="mockup-dot"></span><span class="mockup-dot"></span><span class="mockup-dot"></span>
2832                <span class="mockup-titlebar-text">arcnautical.com/underwriting</span>
2833              </div>
2834              <div class="mockup-body">
2835                <div style="font-family:var(--mono);font-size:10px;color:var(--text-dim);text-transform:uppercase;letter-spacing:0.08em;margin-bottom:12px;">Exceedance Probability Curve</div>
2836                <div class="ep-curve-wrap" style="margin:0;">
2837                  <svg class="ep-curve-svg" viewBox="0 0 300 120" preserveAspectRatio="none" id="epCurveSvg">
2838                    <line x1="30" y1="10" x2="30" y2="110" stroke="#1c2a3e" stroke-width="0.5"/>
2839                    <line x1="30" y1="110" x2="290" y2="110" stroke="#1c2a3e" stroke-width="0.5"/>
2840                    <text x="15" y="20" fill="#445068" font-size="7" font-family="'JetBrains Mono',monospace" text-anchor="middle">1.0</text>
2841                    <text x="15" y="60" fill="#445068" font-size="7" font-family="'JetBrains Mono',monospace" text-anchor="middle">0.5</text>
2842                    <text x="15" y="108" fill="#445068" font-size="7" font-family="'JetBrains Mono',monospace" text-anchor="middle">0.0</text>
2843                    <text x="160" y="120" fill="#445068" font-size="7" font-family="'JetBrains Mono',monospace" text-anchor="middle">Loss Amount ($M)</text>
2844                    <path class="ep-curve-path" id="epCurvePath" d="M 30,15 C 60,16 80,20 110,35 C 140,50 170,70 200,85 C 230,95 260,103 290,107" fill="none" stroke="#0891b2" stroke-width="2"/>
2845                    <path d="M 30,15 C 60,16 80,20 110,35 C 140,50 170,70 200,85 C 230,95 260,103 290,107 L 290,110 L 30,110 Z" fill="rgba(8,145,178,0.08)"/>
2846                  </svg>
2847                </div>
2848              </div>
2849            </div>
2850          </div>
2851        </div>
2852
2853        <!-- REPORTS TAB -->
2854        <div class="showcase-panel" data-panel="reports">
2855          <div>
2856            <h3 class="section-title" style="font-size:clamp(1.4rem,2.5vw,1.8rem);">Reports &amp; Compliance</h3>
2857            <p class="section-desc">Seven automated PDF report types with AI-generated intelligence narratives. Scheduled delivery or on-demand generation via API.</p>
2858            <ul style="list-style:none;display:flex;flex-direction:column;gap:8px;">
2859              <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:var(--accent)"></span>Voyage Risk Report &mdash; Full route intelligence briefing</li>
2860              <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:var(--risk-low)"></span>Fleet Summary &mdash; Portfolio-wide risk overview</li>
2861              <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:var(--risk-crit)"></span>Piracy Briefing &mdash; Regional threat assessment</li>
2862              <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:#f472b6"></span>Compliance Report &mdash; Sanctions + PSC screening</li>
2863              <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:var(--risk-elev)"></span>PML Report, Route Comparison, Vessel Dossier</li>
2864            </ul>
2865          </div>
2866          <div>
2867            <div class="mockup-card">
2868              <div class="mockup-titlebar">
2869                <span class="mockup-dot"></span><span class="mockup-dot"></span><span class="mockup-dot"></span>
2870                <span class="mockup-titlebar-text">Generated Reports</span>
2871              </div>
2872              <div class="mockup-body">
2873                <div class="pdf-stack">
2874                  <div class="pdf-page">
2875                    <div class="pdf-page-title">Piracy Briefing</div>
2876                    <div class="pdf-page-line"></div>
2877                    <div class="pdf-page-line short"></div>
2878                    <div class="pdf-page-line"></div>
2879                    <div class="pdf-page-line short"></div>
2880                    <div class="pdf-page-line"></div>
2881                    <div style="height:20px;margin:8px 0;background:rgba(8,145,178,0.08);border-radius:2px;"></div>
2882                    <div class="pdf-page-line"></div>
2883                    <div class="pdf-page-line short"></div>
2884                  </div>
2885                  <div class="pdf-page">
2886                    <div class="pdf-page-title">Fleet Summary</div>
2887                    <div class="pdf-page-line"></div>
2888                    <div class="pdf-page-line short"></div>
2889                    <div class="pdf-page-line"></div>
2890                    <div style="height:30px;margin:8px 0;background:rgba(5,150,105,0.08);border-radius:2px;"></div>
2891                    <div class="pdf-page-line"></div>
2892                    <div class="pdf-page-line short"></div>
2893                  </div>
2894                  <div class="pdf-page">
2895                    <div class="pdf-page-title">Voyage Risk</div>
2896                    <div class="pdf-page-line"></div>
2897                    <div class="pdf-page-line"></div>
2898                    <div class="pdf-page-line short"></div>
2899                    <div style="height:24px;margin:8px 0;background:rgba(217,119,6,0.08);border-radius:2px;"></div>
2900                    <div class="pdf-page-line"></div>
2901                    <div class="pdf-page-line short"></div>
2902                  </div>
2903                </div>
2904                <div style="font-family:var(--mono);font-size:11px;color:var(--text-sec);margin-top:8px;">AI-narrated intelligence &middot; Scheduled delivery &middot; API generation</div>
2905              </div>
2906            </div>
2907          </div>
2908        </div>
2909      </div>
2910    </div>
2911  </section>
2912
2913  <div class="section-divider"></div>
2914
2915  <!-- ============================================================
2916       OWNERSHIP & SANCTIONS
2917       ============================================================ -->
2918  <section class="section ownership-section" id="ownership">
2919    <div class="container">
2920      <div class="ownership-layout">
2921        <div class="reveal">
2922          <div class="section-label">Compliance Intelligence</div>
2923          <h3 class="section-title"><a href="/sanctions-screening.html" style="color:inherit;text-decoration:none;">Ownership chain analysis &amp; sanctions screening</a></h3>
2924          <p class="section-desc">Trace beneficial ownership through GLEIF corporate registries. Screen every entity in the chain against OFAC, UN, and OpenSanctions. Detect shell company jurisdictions automatically.</p>
2925          <div style="font-family:var(--mono);font-size:11px;color:var(--text-dim);margin:8px 0 16px;letter-spacing:0.02em;">Sample scan &mdash; Pacific Shipping Ltd (Marshall Islands registration, Panama parent, OFAC-listed UBO)</div>
2926          <div class="ownership-metrics">
2927            <div class="ownership-metric-card">
2928              <div class="ownership-metric-label">Opacity Score</div>
2929              <div class="ownership-metric-value" style="color:var(--risk-high);">72</div>
2930            </div>
2931            <div class="ownership-metric-card">
2932              <div class="ownership-metric-label">Sanctions Hits</div>
2933              <div class="ownership-metric-value" style="color:var(--risk-crit);">1</div>
2934            </div>
2935            <div class="ownership-metric-card">
2936              <div class="ownership-metric-label">Shell Jurisdictions</div>
2937              <div class="ownership-metric-value" style="color:var(--risk-elev);">2</div>
2938            </div>
2939            <div class="ownership-metric-card">
2940              <div class="ownership-metric-label">Chain Depth</div>
2941              <div class="ownership-metric-value" style="color:var(--accent);">3</div>
2942            </div>
2943          </div>
2944        </div>
2945        <div class="reveal reveal-delay-2">
2946          <div class="ownership-chain" id="ownershipChain">
2947            <div class="ownership-entity" data-delay="0">
2948              <div class="ownership-entity-type">Registered Owner</div>
2949              <div class="ownership-entity-name">Pacific Shipping Ltd</div>
2950              <div class="ownership-entity-detail">Marshall Islands &middot; No GLEIF record</div>
2951            </div>
2952            <div class="ownership-connector" data-delay="300"></div>
2953            <div class="ownership-entity" data-delay="400">
2954              <div class="ownership-entity-type">Parent Company</div>
2955              <div class="ownership-entity-name">Oceanic Holdings SA</div>
2956              <div class="ownership-entity-detail">Panama &middot; LEI: 5493001KJTIIGC8Y1R12</div>
2957            </div>
2958            <div class="ownership-connector" data-delay="700"></div>
2959            <div class="ownership-entity flagged" data-delay="800">
2960              <div class="ownership-entity-type">Ultimate Beneficial Owner</div>
2961              <div class="ownership-entity-name">Meridian Group Corp</div>
2962              <div class="ownership-entity-detail">OFAC SDN MATCH &mdash; Sanctioned entity</div>
2963            </div>
2964          </div>
2965        </div>
2966      </div>
2967    </div>
2968  </section>
2969
2970  <div class="section-divider"></div>
2971
2972  <!-- ============================================================
2973       FUEL & CII
2974       ============================================================ -->
2975  <section class="section fuel-section" id="fuel">
2976    <div class="container">
2977      <div class="fuel-layout">
2978        <div class="reveal">
2979          <div class="section-label">IMO Compliance</div>
2980          <h3 class="section-title">Fuel estimation &amp; CII rating</h3>
2981          <p class="section-desc">IMO MEPC-compliant CII calculator with Admiralty cubic law fuel consumption, CO2 emission factors, and A&ndash;E rating bands that tighten annually.</p>
2982          <div class="cii-scale" id="ciiScale">
2983            <div class="cii-bar-wrap">
2984              <div class="cii-bar">
2985                <div class="cii-bar-seg a">A</div>
2986                <div class="cii-bar-seg b">B</div>
2987                <div class="cii-bar-seg c">C</div>
2988                <div class="cii-bar-seg d">D</div>
2989                <div class="cii-bar-seg e">E</div>
2990              </div>
2991              <div class="cii-pointer" id="ciiPointer"></div>
2992            </div>
2993            <div class="cii-labels">
2994              <span>Superior</span><span>Lower</span><span>Moderate</span><span>Upper</span><span>Inferior</span>
2995            </div>
2996          </div>
2997          <div class="fuel-metrics">
2998            <div class="fuel-metric">
2999              <div class="fuel-metric-label">Fuel Consumption</div>
3000              <div class="fuel-metric-value">842</div>
3001              <div class="fuel-metric-unit">metric tonnes</div>
3002            </div>
3003            <div class="fuel-metric">
3004              <div class="fuel-metric-label">CO2 Emissions</div>
3005              <div class="fuel-metric-value">2,655</div>
3006              <div class="fuel-metric-unit">tonnes CO2</div>
3007            </div>
3008            <div class="fuel-metric">
3009              <div class="fuel-metric-label">Bunker Cost</div>
3010              <div class="fuel-metric-value">$521K</div>
3011              <div class="fuel-metric-unit">at $619/MT VLSFO</div>
3012            </div>
3013            <div class="fuel-metric">
3014              <div class="fuel-metric-label">CII Attained</div>
3015              <div class="fuel-metric-value" style="color:var(--risk-low);">4.82</div>
3016              <div class="fuel-metric-unit">gCO2/DWT&middot;nm</div>
3017            </div>
3018          </div>
3019        </div>
3020        <div class="reveal reveal-delay-2">
3021          <div class="mockup-card">
3022            <div class="mockup-titlebar">
3023              <span class="mockup-dot"></span><span class="mockup-dot"></span><span class="mockup-dot"></span>
3024              <span class="mockup-titlebar-text">Route Comparison &mdash; Fuel &amp; Emissions</span>
3025            </div>
3026            <div class="mockup-body">
3027              <div style="font-family:var(--mono);font-size:10px;color:var(--text-dim);text-transform:uppercase;letter-spacing:0.08em;margin-bottom:12px;">VLSFO &middot; 65,000 DWT &middot; Bulk Carrier</div>
3028              <table style="width:100%;border-collapse:collapse;font-family:var(--mono);font-size:11px;">
3029                <thead>
3030                  <tr style="border-bottom:1px solid var(--border);">
3031                    <th style="text-align:left;padding:8px 6px;color:var(--text-dim);font-weight:500;">Route</th>
3032                    <th style="text-align:right;padding:8px 6px;color:var(--text-dim);font-weight:500;">Risk</th>
3033                    <th style="text-align:right;padding:8px 6px;color:var(--text-dim);font-weight:500;">Fuel</th>
3034                    <th style="text-align:right;padding:8px 6px;color:var(--text-dim);font-weight:500;">CO2</th>
3035                    <th style="text-align:right;padding:8px 6px;color:var(--text-dim);font-weight:500;">CII</th>
3036                  </tr>
3037                </thead>
3038                <tbody>
3039                  <tr style="border-bottom:1px solid var(--border);">
3040                    <td style="padding:10px 6px;color:var(--text);">Via Suez</td>
3041                    <td style="text-align:right;padding:10px 6px;color:var(--risk-elev);font-weight:600;">42</td>
3042                    <td style="text-align:right;padding:10px 6px;color:var(--text-sec);">842 MT</td>
3043                    <td style="text-align:right;padding:10px 6px;color:var(--text-sec);">2,655 MT</td>
3044                    <td style="text-align:right;padding:10px 6px;"><span style="background:rgba(5,150,105,0.15);color:var(--risk-low);padding:2px 6px;border-radius:2px;font-weight:600;">B</span></td>
3045                  </tr>
3046                  <tr>
3047                    <td style="padding:10px 6px;color:var(--text);">Via Cape</td>
3048                    <td style="text-align:right;padding:10px 6px;color:var(--risk-low);font-weight:600;">18</td>
3049                    <td style="text-align:right;padding:10px 6px;color:var(--text-sec);">1,284 MT</td>
3050                    <td style="text-align:right;padding:10px 6px;color:var(--text-sec);">4,049 MT</td>
3051                    <td style="text-align:right;padding:10px 6px;"><span style="background:rgba(251,191,36,0.15);color:var(--risk-elev);padding:2px 6px;border-radius:2px;font-weight:600;">C</span></td>
3052                  </tr>
3053                </tbody>
3054              </table>
3055            </div>
3056          </div>
3057        </div>
3058      </div>
3059    </div>
3060  </section>
3061
3062  <!-- ============================================================
3063       OCEAN ROUTING ANIMATION
3064       ============================================================ -->
3065  <section class="section routing-section" id="routing">
3066    <div class="container">
3067      <div class="routing-layout">
3068        <div class="reveal">
3069          <div class="section-label">Navigation</div>
3070          <h3 class="section-title">Ocean pathfinding engine</h3>
3071          <p class="section-desc">A* graph search through a 7,200&times;3,600 ocean bitmap at 5.5km resolution. Forced passages through Suez, Panama, Bosphorus, and 12 other strategic straits. 510+ ports with UN/LOCODE.</p>
3072          <ul style="list-style:none;display:flex;flex-direction:column;gap:8px;margin-top:24px;">
3073            <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:var(--accent)"></span>8&ndash;50ms typical segment computation</li>
3074            <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:var(--risk-low)"></span>EEZ transit analysis with zone identification</li>
3075            <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:var(--risk-elev)"></span>Corridor smoothing eliminates jagged grid paths</li>
3076            <li class="signal-item" style="background:transparent;border:none;padding:4px 0;"><span class="signal-dot" style="background:#a78bfa"></span>Recursive subdivision for trans-oceanic routes</li>
3077          </ul>
3078        </div>
3079        <div class="routing-map-wrap reveal reveal-delay-2">
3080          <div class="routing-map" id="routingShowcaseMap">
3081            <div class="routing-map-loading">Loading route&hellip;</div>
3082          </div>
3083          <div class="routing-map-label">Rotterdam &rarr; Singapore &middot; Live pathfinding result</div>
3084        </div>
3085      </div>
3086    </div>
3087  </section>
3088
3089  <div class="section-divider"></div>
3090
3091  <!-- ============================================================
3092       VESSELWATCH ALERTS — 9 TYPES
3093       ============================================================ -->
3094  <section class="section alerts-section" id="alerts">
3095    <div class="container">
3096      <div class="alerts-layout alerts-layout-reverse">
3097        <div class="reveal reveal-delay-2">
3098          <div class="mockup-card">
3099            <div class="mockup-titlebar">
3100              <span class="mockup-dot"></span><span class="mockup-dot"></span><span class="mockup-dot"></span>
3101              <span class="mockup-titlebar-text">arcnautical.com/alerts</span>
3102            </div>
3103            <div class="mockup-body" style="padding:0;">
3104              <div class="alert-feed">
3105                <div class="alert-item" data-severity="critical">
3106                  <span class="alert-badge" data-severity="critical">CRIT</span>
3107                  <div class="alert-content">
3108                    <div class="alert-type">AIS Gap Detected</div>
3109                    <div class="alert-msg"><span class="alert-vessel">MV DEMO ALPHA</span> &mdash; 6.2h signal loss &mdash; 12&deg;41'N 043&deg;18'E</div>
3110                    <div class="alert-time">2 min ago &middot; Webhook delivered</div>
3111                  </div>
3112                </div>
3113                <div class="alert-item" data-severity="high">
3114                  <span class="alert-badge" data-severity="high">HIGH</span>
3115                  <div class="alert-content">
3116                    <div class="alert-type">Sanctions Hit</div>
3117                    <div class="alert-msg"><span class="alert-vessel">MV DEMO BETA</span> &mdash; OFAC SDN match on registered owner</div>
3118                    <div class="alert-time">18 min ago &middot; Webhook delivered</div>
3119                  </div>
3120                </div>
3121                <div class="alert-item" data-severity="medium">
3122                  <span class="alert-badge" data-severity="medium">MED</span>
3123                  <div class="alert-content">
3124                    <div class="alert-type">Geofence Exit</div>
3125                    <div class="alert-msg"><span class="alert-vessel">MV DEMO GAMMA</span> &mdash; Left "Gulf Operations Zone"</div>
3126                    <div class="alert-time">43 min ago</div>
3127                  </div>
3128                </div>
3129                <div class="alert-item" data-severity="low">
3130                  <span class="alert-badge" data-severity="low">LOW</span>
3131                  <div class="alert-content">
3132                    <div class="alert-type">Weather Alert</div>
3133                    <div class="alert-msg"><span class="alert-vessel">MV DEMO DELTA</span> &mdash; Beaufort 8+ forecast &mdash; Bay of Bengal</div>
3134                    <div class="alert-time">1h ago</div>
3135                  </div>
3136                </div>
3137              </div>
3138            </div>
3139          </div>
3140        </div>
3141        <div class="reveal">
3142          <div class="section-label">Fleet Monitoring</div>
3143          <h3 class="section-title">9 alert types, webhook delivery</h3>
3144          <p class="section-desc">Continuous 5-minute evaluation cycles across your insured fleet. HMAC-SHA256 signed webhooks with exponential backoff retry and per-type suppression windows.</p>
3145          <div class="alert-types-grid">
3146            <div class="alert-type-badge"><span class="alert-type-dot" style="background:#a78bfa"></span>AIS Gap</div>
3147            <div class="alert-type-badge"><span class="alert-type-dot" style="background:var(--risk-crit)"></span>Zone Entry</div>
3148            <div class="alert-type-badge"><span class="alert-type-dot" style="background:var(--risk-high)"></span>Piracy</div>
3149            <div class="alert-type-badge"><span class="alert-type-dot" style="background:var(--risk-elev)"></span>NAVWARN</div>
3150            <div class="alert-type-badge"><span class="alert-type-dot" style="background:#38bdf8"></span>Weather</div>
3151            <div class="alert-type-badge"><span class="alert-type-dot" style="background:#f472b6"></span>Sanctions</div>
3152            <div class="alert-type-badge"><span class="alert-type-dot" style="background:var(--risk-low)"></span>Geofence</div>
3153            <div class="alert-type-badge"><span class="alert-type-dot" style="background:var(--accent)"></span>Speed Anomaly</div>
3154            <div class="alert-type-badge"><span class="alert-type-dot" style="background:#fbbf24"></span>Dark Activity</div>
3155          </div>
3156          <div style="font-size:12px;color:var(--text-dim);line-height:1.7;margin-top:16px;font-family:var(--mono);">
3157            HMAC-SHA256 signed &middot; Exponential backoff &middot; 5-min cycles &middot; Per-type suppression
3158          </div>
3159        </div>
3160      </div>
3161    </div>
3162  </section>
3163
3164
3165  <!-- ============================================================
3166       PRICING
3167       ============================================================ -->
3168  <section id="pricing" style="padding:96px 0;background:var(--bg);border-top:1px solid var(--border);">
3169    <div class="container">
3170      <div style="text-align:center;margin-bottom:40px;">
3171        <div style="font-family:var(--mono);font-size:11px;font-weight:600;color:var(--accent);letter-spacing:0.1em;text-transform:uppercase;margin-bottom:16px;" class="reveal">
3171Pricing</div>
3172        <p style="color:var(--text-sec);font-size:15px;max-width:680px;margin:0 auto;" class="reveal reveal-delay-1">Free to use. Only the API is metered, and every number below is the limit it enforces.</p>
3173      </div>
3174
3175      <!-- Plan grid -->
3176      <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:24px;max-width:1080px;margin:0 auto;">
3177
3178        <!-- CHECK A VESSEL (no account) -->
3179        <div class="reveal reveal-delay-2" style="background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:32px 28px;display:flex;flex-direction:column;">
3180          <div style="font-family:var(--mono);font-size:11px;font-weight:700;color:var(--text-dim);letter-spacing:0.1em;text-transform:uppercase;margin-bottom:14px;">Check a vessel</div>
3181          <div style="display:flex;align-items:baseline;gap:8px;margin-bottom:6px;"><span style="font-family:var(--display);font-size:2.4rem;color:var(--text);font-weight:400;">No account</span></div>
3182          <div style="color:var(--text-dim);font-size:12px;margin-bottom:24px;font-family:var(--mono);">One IMO, one verdict</div>
3183          <ul style="list-style:none;padding:0;margin:0 0 28px;color:var(--text-sec);font-size:14px;line-height:1.9;flex:1;">
3184            <li>&#10003; <span data-limit="keylessCheckPerHour">100</span> checks an hour</li>
3185            <li>&#10003; Same lists, same engine as the API</li>
3186            <li>&#10003; <span data-limit="playgroundPerHour">5</span> route risk previews an hour</li>
3187          </ul>
3188          <a href="/check" class="btn-ghost" style="text-align:center;">Check a vessel</a>
3189        </div>
3190
3191        <!-- ACCOUNT (highlighted) -->
3192        <div class="reveal reveal-delay-2" style="background:var(--surface);border:2px solid var(--accent);border-radius:8px;padding:32px 28px;display:flex;flex-direction:column;position:relative;">
3193          <div style="position:absolute;top:-12px;left:50%;transform:translateX(-50%);background:var(--accent);color:#fff;font-family:var(--mono);font-size:10px;font-weight:700;letter-spacing:0.12em;padding:4px 14px;border-radius:4px;">SELF-SERVE</div>
3194          <div style="font-family:var(--mono);font-size:11px;font-weight:700;color:var(--accent);letter-spacing:0.1em;text-transform:uppercase;margin-bottom:14px;">Account</div>
3195          <div style="display:flex;align-items:baseline;gap:8px;margin-bottom:6px;"><span style="font-family:var(--display);font-size:2.4rem;color:var(--text);font-weight:400;">$0</span><span style="color:var(--text-dim);font-size:13px;">no card, no expiry</span></div>
3196          <div style="color:var(--text-dim);font-size:12px;margin-bottom:24px;font-family:var(--mono);">Workspace and API, one sign-up</div>
3197          <ul style="list-style:none;padding:0;margin:0 0 28px;color:var(--text-sec);font-size:14px;line-height:1.9;flex:1;">
3198            <li>&#10003; Dossiers, voyage risk, fleets, alerts &mdash; unmetered</li>
3199            <li>&#10003; <strong><span data-limit="liveScreeningLimit">5,000</span> sanctions screenings</strong> to start (one-time)</li>
3200            <li>&#10003; <span data-limit="liveAssessmentLimit">10,000</span> voyage risk assessments a month</li>
3201            <li>&#10003; <span data-limit="vesselMonitorLimit">50</span> vessels monitored daily</li>
3202            <li>&#10003; Records kept <span data-limit="screeningRetentionYears">10</span> years, every match cites its source</li>
3203            <li>&#10003; Full limits on <a href="/developers/" style="color:var(--accent);">/developers</a></li>
3204          </ul>
3205          <a href="/arcnautical.html#/register" class="btn-primary" style="text-align:center;">Open an account</a>
3206        </div>
3207
3208        <!-- PLATFORM -->
3209        <div class="reveal reveal-delay-3" style="background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:32px 28px;display:flex;flex-direction:column;">
3210          <div style="font-family:var(--mono);font-size:11px;font-weight:700;color:var(--text-dim);letter-spacing:0.1em;text-transform:uppercase;margin-bottom:14px;">Platform</div>
3211          <div style="display:flex;align-items:baseline;gap:8px;margin-bottom:6px;"><span style="font-family:var(--display);font-size:2.4rem;color:var(--text);font-weight:400;">
3211Per fleet</span></div>
3212          <div style="color:var(--text-dim);font-size:12px;margin-bottom:24px;font-family:var(--mono);">Annual, for screening a whole fleet</div>
3213          <ul style="list-style:none;padding:0;margin:0 0 28px;color:var(--text-sec);font-size:14px;line-height:1.9;flex:1;">
3214            <li>&#10003; Allowance sized to your fleet</li>
3215            <li>&#10003; <span data-limit="slaMonthlyUptimePct">99.5</span>% uptime <a href="/sla" style="color:var(--accent);">SLA</a> with credits</li>
3216            <li>&#10003; <a href="/dpa" style="color:var(--accent);">DPA</a> and <a href="/security" style="color:var(--accent);">security review</a></li>
3217            <li>&#10003; Same API, same records</li>
3218          </ul>
3219          <a href="/cdn-cgi/l/email-protection#650401080c0b250417060b0410110c0604094b060a085a1610070f000611582417062b0410110c06040940575535090411030a1708405755402057405d55405c514057550309000011405755160c1f00" class="btn-ghost" style="text-align:center;">Tell us your fleet size</a>
3220        </div>
3221
3222      </div>
3223    </div>
3224  </section>
3225
3226  <!-- ============================================================
3227       INSTANT VESSEL CHECK
3228       ============================================================ -->
3229  <section id="vessel-check" style="padding:80px 0;background:var(--surface);border-top:1px solid var(--border);border-bottom:1px solid var(--border);">
3230    <div class="container" style="max-width:720px;text-align:center;">
3231      <div style="font-family:var(--mono);font-size:11px;font-weight:600;color:var(--accent);letter-spacing:0.1em;text-transform:uppercase;margin-bottom:16px;" class="reveal">Instant Vessel Intelligence</div>
3232      <h2 style="font-family:var(--display);font-size:clamp(1.6rem,2.5vw,2.2rem);color:var(--text);margin-bottom:12px;font-weight:400;" class="reveal">Check any vessel in 3 seconds.</h2>
3233      <p style="color:var(--text-sec);margin-bottom:32px;font-size:15px;" class="reveal">Sanctions status, ownership transparency, and vetting grade &mdash; powered by OFAC, EU, UN sanctions lists, GLEIF ownership data, and global PSC records. Free, no signup required.</p>
3234
3235      <!-- IMO Input -->
3236      <form id="landingCheckForm" onsubmit="return landingQuickCheck(event)" style="display:flex;gap:12px;max-width:480px;margin:0 auto 24px;" class="reveal">
3237        <input type="text" id="landing-imo" placeholder="7-digit IMO number" required pattern="[0-9]{7}" title="Enter a 7-digit IMO number" style="flex:1;padding:14px 18px;background:var(--bg);border:1px solid var(--border);border-radius:4px;color:var(--text);font-family:var(--mono);font-size:16px;outline:none;letter-spacing:0.05em;">
3238        <button type="submit" id="landing-check-btn" class="btn-primary" style="padding:14px 28px;font-size:15px;cursor:pointer;border:none;white-space:nowrap;">Check Vessel</button>
3239      </form>
3240
3241      <!-- Results (hidden until check) -->
3242      <div id="landing-results" style="display:none;"></div>
3243
3244      <p style="color:var(--text-dim);font-size:12px;margin-top:16px;font-family:var(--mono);" class="reveal">Try: 9034690 (OFAC-sanctioned) &middot; 9811000 (Ever Given) &middot; 9295345 (Altomare SA case)</p>
3245    </div>
3246  </section>
3247
3248  <!-- ============================================================
3249       LIVE PORT CONGESTION (free, no signup)
3250       ============================================================ -->
3251  <section id="port-congestion" style="padding:80px 0;background:var(--bg);border-bottom:1px solid var(--border);">
3252    <div class="container" style="max-width:720px;text-align:center;">
3253      <div style="font-family:var(--mono);font-size:11px;font-weight:600;color:var(--accent);letter-spacing:0.1em;text-transform:uppercase;margin-bottom:16px;" class="reveal">Live Port Operations</div>
3254      <h2 style="font-family:var(--display);font-size:clamp(1.6rem,2.5vw,2.2rem);color:var(--text);margin-bottom:12px;font-weight:400;" class="reveal">Which ports are congested right now?</h2>
3255      <p style="color:var(--text-sec);margin-bottom:32px;font-size:15px;" class="reveal">Live vessel queues, average waiting time, and congestion trend for major global ports &mdash; powered by IMF PortWatch. Free, no signup required.</p>
3256      <div class="reveal">
3257        <a href="/arcnautical.html#/congestion" class="btn-primary" style="display:inline-block;padding:14px 32px;font-size:15px;">Open the congestion map &rarr;</a>
3258      </div>
3259      <p style="color:var(--text-dim);font-size:12px;margin-top:16px;font-family:var(--mono);" class="reveal">Singapore &middot; Rotterdam &middot; Shanghai &middot; Los Angeles &middot; +500 ports tracked</p>
3260    </div>
3261  </section>
3262
3263  <!-- ============================================================
3264       FINAL CTA
3265       ============================================================ -->
3266  <section class="cta-section" id="contact">
3267    <div class="container">
3268      <div class="cta-badge reveal">FREE TIER &mdash; NO CREDIT CARD REQUIRED</div>
3269      <h2 class="cta-title reveal">Ready for the full intelligence briefing?</h2>
3270      <div class="cta-sub reveal reveal-delay-1">Sign up to unlock fleet monitoring, PDF reports, Monte Carlo ETA, sanctions screening, ownership chain analysis, and 6 automated report types.</div>
3271      <div class="cta-actions reveal reveal-delay-2">
3272        <a href="/arcnautical.html#/register" class="btn-primary" style="font-size:15px;padding:16px 40px;">Create Free Account</a>
3273        <a href="/sample-report.pdf" class="btn-ghost" style="font-size:15px;padding:16px 40px;" download>See Sample Report</a>
3274      </div>
3275      <div class="cta-email reveal reveal-delay-2">Already have an account? <a href="/arcnautical.html#/login">Sign in</a></div>
3276    </div>
3277  </section>
3278
3279  <!-- ============================================================
3280       FOOTER
3281       ============================================================ -->
3282  <footer class="footer">
3283    <div class="container">
3284      <div class="footer-inner">
3285        <div class="footer-brand">
3286          <img class="footer-brand-mark" src="/logo.svg" alt="ArcNautical" width="18" height="18">
3287          <span class="footer-brand-text">ARCNAUTICAL</span>
3288        </div>
3289        <ul class="footer-links">
3290          <li><a href="/arcnautical.html#/dashboard">Platform</a></li>
3291          <li><a href="/arcnautical.html#/register">Get Started</a></li>
3292          <li><a href="/arcnautical.html#/login">Sign In</a></li>
3293          <li><a href="/developers/">API Docs</a></li>
3294          <li><a href="/sanctions-screening-api/">Sanctions Screening API</a></li>
3295          <li><a href="/ship-suppliers/">For Ship Suppliers</a></li>
3296          <li><a href="/blog">Blog</a></li>
3297          <li><a href="/methodology.html">Methodology</a></li>
3298          <li><a href="/trust.html">Trust &amp; Security</a></li>
3299          <li><a href="https://status.arcnautical.com">Status</a></li>
3300          <li><a href="/privacy.html">Privacy</a></li>
3301          <li><a href="/terms.html">Terms</a></li>
3302        </ul>
3303        <div class="footer-right">&copy; 2026 ArcNautical</div>
3304      </div>
3305      <!-- Intelligence directory: crawlable links from the homepage (highest-authority
3306           page) into the programmatic tree, so internal PageRank reaches the deep
3307           vessel/ports/sanctions pages. Server-rendered <a>s, read in Googlebot crawl phase 1. -->
3308      <nav class="footer-directory" aria-label="Maritime intelligence directory" style="margin-top:24px;padding-top:18px;border-top:1px solid #1c2a3e;font-family:'Inter',system-ui,sans-serif;display:flex;flex-wrap:wrap;gap:32px;justify-content:center;font-size:12.5px;line-height:2;color:#7e8fa6">
3309        <div>
3310          <div style="font-family:'JetBrains Mono',ui-monospace,monospace;font-size:10px;letter-spacing:0.07em;text-transform:uppercase;color:#5a6b82;margin-bottom:4px">Vessel &amp; maritime intelligence</div>
3311          <a href="/vessel/" style="color:#9fb2c9;text-decoration:none;margin-right:16px">Screened vessels</a>
3312          <a href="/ports/" style="color:#9fb2c9;text-decoration:none;margin-right:16px">Port intelligence</a>
3313          <a href="/regions/" style="color:#9fb2c9;text-decoration:none;margin-right:16px">Maritime regions</a>
3314          <a href="/routes/" style="color:#9fb2c9;text-decoration:none;margin-right:16px">Shipping lane risk</a>
3315          <a href="/mou/" style="color:#9fb2c9;text-decoration:none;margin-right:16px">Port State Control MoUs</a>
3316          <a href="/flags/" style="color:#9fb2c9;text-decoration:none">Flag registries</a>
3317        </div>
3318        <div>
3319          <div style="font-family:'JetBrains Mono',ui-monospace,monospace;font-size:10px;letter-spacing:0.07em;text-transform:uppercase;color:#5a6b82;margin-bottom:4px">Sanctions &amp; research</div>
3320          <a href="/sanctions/countries/" style="color:#9fb2c9;text-decoration:none;margin-right:16px">Country sanctions</a>
3321          <a href="/sanctions/entities/" style="color:#9fb2c9;text-decoration:none;margin-right:16px">Sanctioned entities</a>
3322          <a href="/data/" style="color:#9fb2c9;text-decoration:none;margin-right:16px">Open datasets</a>
3323          <a href="/reports/dark-fleet-flag-brief/01/" style="color:#9fb2c9;text-decoration:none;margin-right:16px">Dark-fleet flag brief</a>
3324          <a href="/reports/hk-shadow-fleet-ownership-layer/01/" style="color:#9fb2c9;text-decoration:none;margin-right:16px">HK ownership brief</a>
3325          <a href="/reports/global-sanctioned-fleet-index/" style="color:#9fb2c9;text-decoration:none">Global sanctioned-fleet index</a>
3326        </div>
3327        <div>
3328          <div style="font-family:'JetBrains Mono',ui-monospace,monospace;font-size:10px;letter-spacing:0.07em;text-transform:uppercase;color:#5a6b82;margin-bottom:4px">Developers &amp; API</div>
3329          <a href="/sanctions-screening-api/" style="color:#9fb2c9;text-decoration:none;margin-right:16px">Sanctions screening API</a>
3330          <a href="/voyage-risk-api/" style="color:#9fb2c9;text-decoration:none;margin-right:16px">Voyage risk API</a>
3331          <a href="/developers/" style="color:#9fb2c9;text-decoration:none;margin-right:16px">API docs</a>
3332          <a href="/developers/reference/" style="color:#9fb2c9;text-decoration:none;margin-right:16px">API reference</a>
3333          <a href="/developers/stability/" style="color:#9fb2c9;text-decoration:none">Stability &amp; changelog</a>
3334        </div>
3335        <div>
3336          <div style="font-family:'JetBrains Mono',ui-monospace,monospace;font-size:10px;letter-spacing:0.07em;text-transform:uppercase;color:#5a6b82;margin-bottom:4px">Guides &amp; research</div>
3337          <a href="/blog/posts/2026-09-15-sanctions-screening-api-first-call-needs-no-key/" style="color:#9fb2c9;text-decoration:none;margin-right:16px">A screening API where the first call needs no key</a>
3338          <a href="/blog/posts/2026-09-15-type-1234567-into-a-screening-api/" style="color:#9fb2c9;text-decoration:none;margin-right:16px">What a screening API returns for 1234567</a>
3339          <a href="/blog/posts/2026-09-15-ofac-ten-year-recordkeeping-what-a-screening-record-must-hold/" style="color:#9fb2c9;text-decoration:none;margin-right:16px">OFAC ten-year recordkeeping: what a record must hold</a>
3340          <a href="/blog/posts/2026-03-22-ownership-opacity/" style="color:#9fb2c9;text-decoration:none;margin-right:16px">The ownership-opacity problem</a>
3341          <a href="/blog/posts/2026-06-05-hk-shadow-fleet-ownership-layer/" style="color:#9fb2c9;text-decoration:none;margin-right:16px">
3341102 sanctioned ships, one Hong Kong company</a>
3342          <a href="/blog/posts/2026-05-19-dark-fleet-flag-brief/" style="color:#9fb2c9;text-decoration:none;margin-right:16px">2.3% of the sanctioned fleet flies a transparent flag</a>
3343          <a href="/methodology.html#cite" style="color:#9fb2c9;text-decoration:none">Methodology (DOI)</a>
3344        </div>
3345        <div>
3346          <div style="font-family:'JetBrains Mono',ui-monospace,monospace;font-size:10px;letter-spacing:0.07em;text-transform:uppercase;color:#5a6b82;margin-bottom:4px">Featured screening</div>
3347          <a href="/sanctions/countries/iran/" style="color:#9fb2c9;text-decoration:none;margin-right:16px">Iran-linked fleet</a>
3348          <a href="/vessel/9385879/" style="color:#9fb2c9;text-decoration:none">Sanctioned tanker (Grumant)</a>
3349        </div>
3350      </nav>
3351      <div style="text-align:center;margin-top:24px;padding-top:18px;border-top:1px solid #1c2a3e;font-family:'Inter',system-ui,sans-serif;font-size:12px;line-height:1.7;color:#7e8fa6">
3352        Built by <a href="/methodology.html" rel="author" style="color:#0891b2;text-decoration:none">ArcNautical</a> &middot; Maritime sanctions &amp; ownership intelligence
3353        <div style="margin-top:6px;font-family:'JetBrains Mono',ui-monospace,monospace;font-size:10.5px;letter-spacing:0.02em;color:#5a6b82">Screening sources: OFAC SDN &middot; EU &middot; UN &middot; UK HMT/OFSI &middot; OpenSanctions &middot; GLEIF &middot; Paris/Tokyo MoU &middot; Regional PSC MoUs</div>
3354      </div>
3355    </div>
3356  </footer>
3357
3358  <!-- ============================================================
3359       JAVASCRIPT
3360       ============================================================ -->
vendor: 111 bytes, lines 3360-3361
3360
3361  <script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script>
3361<script src="https://unpkg.com/[email protected]/dist/leaflet.js" crossorigin=""></script>
3361
3362  
3362<script>
3363    // ----------------------------------------------------------------
3364    // RISK GAUGE RENDERER
3365    // ----------------------------------------------------------------
3366    function renderGauge(svgEl, score, riskLevel, size) {
3367      const cx = size / 2, cy = size / 2;
3368      const r = size * 0.38, strokeW = size * 0.06;
3369      const ARC_START = 135, ARC_SPAN = 270;
3370      const RISK_COLORS = { low:'#059669', moderate:'#818cf8', elevated:'#d97706', high:'#ea580c', critical:'#dc2626' };
3371
3372      function polar(cx, cy, r, deg) {
3373        const rad = (deg * Math.PI) / 180;
3374        return { x: cx + r * Math.cos(rad), y: cy + r * Math.sin(rad) };
3375      }
3376      function arc(cx, cy, r, startDeg, endDeg) {
3377        if (Math.abs(endDeg - startDeg) < 0.01) { const p = polar(cx,cy,r,startDeg); return 'M ' + p.x + ' ' + p.y; }
3378        const s = polar(cx,cy,r,startDeg), e = polar(cx,cy,r,endDeg);
3379        return 'M ' + s.x + ' ' + s.y + ' A ' + r + ' ' + r + ' 0 ' + ((endDeg-startDeg)>180?1:0) + ' 1 ' + e.x + ' ' + e.y;
3380      }
3381
3382      const ns = 'http://www.w3.org/2000/svg';
3383      function mk(tag, attrs) {
3384        const el = document.createElementNS(ns, tag);
3385        for (const [k,v] of Object.entries(attrs)) el.setAttribute(k,v);
3386        return el;
3387      }
3388
3389      let currentColor = RISK_COLORS[riskLevel] || '#818cf8';
3390
3391      svgEl.appendChild(mk('path', { d:arc(cx,cy,r,ARC_START,ARC_START+ARC_SPAN), fill:'none', stroke:'#1c2a3e', 'stroke-width':strokeW, 'stroke-linecap':'round' }));
3392
3393      const fillPath = mk('path', { d:arc(cx,cy,r,ARC_START,ARC_START), fill:'none', stroke:currentColor, 'stroke-width':strokeW, 'stroke-linecap':'round' });
3394      svgEl.appendChild(fillPath);
3395
3396      const tickG = mk('g', {});
3397      const tickOuterR = r + strokeW/2 + size*0.02;
3398      for (let val=0; val<=100; val+=5) {
3399        const deg = ARC_START + (val/100)*ARC_SPAN;
3400        const isMajor = val%10===0;
3401        const len = isMajor ? size*0.04 : size*0.02;
3402        const o = polar(cx,cy,tickOuterR,deg), i = polar(cx,cy,tickOuterR+len,deg);
3403        tickG.appendChild(mk('line', { x1:o.x, y1:o.y, x2:i.x, y2:i.y, stroke:isMajor?'#445068':'#253550', 'stroke-width':isMajor?1.5:0.75 }));
3404        if (isMajor && size > 120) {
3405          const lp = polar(cx,cy,tickOuterR+len+size*0.04,deg);
3406          const txt = document.createElementNS(ns,'text');
3407          txt.setAttribute('x',lp.x); txt.setAttribute('y',lp.y);
3408          txt.setAttribute('fill','#445068'); txt.setAttribute('font-size',size*0.05);
3409          txt.setAttribute('font-family',"'JetBrains Mono',monospace"); txt.setAttribute('text-anchor','middle');
3410          txt.setAttribute('dominant-baseline','central'); txt.textContent=val;
3411          tickG.appendChild(txt);
3412        }
3413      }
3414      svgEl.appendChild(tickG);
3415
3416      const scoreTxt = document.createElementNS(ns,'text');
3417      scoreTxt.setAttribute('x',cx); scoreTxt.setAttribute('y',cy-size*0.02);
3418      scoreTxt.setAttribute('fill','#d0d8e8'); scoreTxt.setAttribute('font-size',size*0.22);
3419      scoreTxt.setAttribute('font-family',"'JetBrains Mono',monospace"); scoreTxt.setAttribute('font-weight','600');
3420      scoreTxt.setAttribute('text-anchor','middle'); scoreTxt.setAttribute('dominant-baseline','central');
3421      scoreTxt.textContent = '0';
3422      svgEl.appendChild(scoreTxt);
3423
3424      const levelTxt = document.createElementNS(ns,'text');
3425      levelTxt.setAttribute('x',cx); levelTxt.setAttribute('y',cy+size*0.13);
3426      levelTxt.setAttribute('fill',currentColor); levelTxt.setAttribute('font-size',size*0.065);
3427      levelTxt.setAttribute('font-family',"'JetBrains Mono',monospace"); levelTxt.setAttribute('font-weight','500');
3428      levelTxt.setAttribute('text-anchor','middle'); levelTxt.setAttribute('dominant-baseline','central');
3429      levelTxt.setAttribute('letter-spacing','0.1em');
3430      levelTxt.textContent = riskLevel.toUpperCase();
3431      svgEl.appendChild(levelTxt);
3432
3433      function animateTo(targetScore, targetLevel) {
3434        const newColor = RISK_COLORS[targetLevel] || '#818cf8';
3435        fillPath.setAttribute('stroke', newColor);
3436        levelTxt.setAttribute('fill', newColor);
3437        levelTxt.textContent = targetLevel.toUpperCase();
3438
3439        let fromScore = parseFloat(scoreTxt.textContent) || 0;
3440        const duration = 900;
3441        const start = performance.now();
3442        function frame(now) {
3443          const t = Math.min((now - start) / duration, 1);
3444          const eased = 1 - Math.pow(1 - t, 3);
3445          const current = fromScore + (targetScore - fromScore) * eased;
3446          fillPath.setAttribute('d', arc(cx,cy,r, ARC_START, ARC_START + (current/100)*ARC_SPAN));
3447          scoreTxt.textContent = Math.round(current);
3448          if (t < 1) requestAnimationFrame(frame);
3449        }
3450        requestAnimationFrame(frame);
3451      }
3452
3453      // Track the CURRENT value, not just the seeded one. animate() used to
3454      // close over the seed, so a live score arriving before the delayed
3455      // animate() fired got dragged back to the seed -- leaving the gauge and
3456      // the route card beneath it showing two different numbers for the same
3457      // route. Both entry points now read and write the same pair.
3458      var curScore = score, curLevel = riskLevel;
3459      return {
3460        animate: function() { animateTo(curScore, curLevel); },
3461        updateScore: function(newScore, newLevel) {
3462          curScore = newScore;
3463          curLevel = newLevel;
3464          animateTo(newScore, newLevel);
3465        },
3466      };
3467    }
3468
3469    // There is no demo feed. Until 2026-09-15 a hardcoded strip of invented
3470    // events (a made-up NAVWARN number, "OFAC SDN update \u2014 3 new maritime
3471    // entities") rendered here with timestamps stamped at page load so it
3472    // always read "4m ago", badged DEMO DATA. On a compliance product's front
3473    // page that is a placeholder with fake times. If the live feed does not
3474    // load, the strip says so and shows nothing.
3475
3476    // ----------------------------------------------------------------
3477    // TICKER BUILDER
3478    // ----------------------------------------------------------------
3479    // Dedupe incoming items by (type + msg prefix + hour-bucket) before
3480    // concatenating for the infinite-scroll loop. Handles the case where
3481    // the live piracy feed returns the same event from IMB + ReCAAP + UKMTO,
3482    // which previously showed "Strait of Malacca - Armed robbery" 3x.
3483    function dedupeTickerItems(items) {
3484      var seen = Object.create(null);
3485      var out = [];
3486      for (var i = 0; i < items.length; i++) {
3487        var it = items[i];
3488        if (!it || typeof it.msg !== 'string') continue;
3489        var hourBucket = '';
3490        if (it.time) {
3491          try { hourBucket = new Date(it.time).toISOString().slice(0, 13); } catch (e) { /* ignore */ }
3492        }
3493        var key = (it.type || '') + '|' + it.msg.slice(0, 60) + '|' + hourBucket;
3494        if (seen[key]) continue;
3495        seen[key] = true;
3496        out.push(it);
3497      }
3498      return out;
3499    }
3500
3501    function buildTickerFromItems(items) {
3502      var track = document.getElementById('tickerTrack');
3503      var deduped = dedupeTickerItems(items);
3504      var html = deduped.concat(deduped).map(function(item) {
3505        return '<div class="ticker-item">' +
3506          '<div class="ticker-accent" data-type="' + item.type + '"></div>' +
3507          '<div class="ticker-body">' +
3508            '<div class="ticker-type" data-type="' + item.type + '">' + item.label + '</div>' +
3509            '<div class="ticker-msg">' + escHtml(item.msg) + '</div>' +
3510            '<div class="ticker-time">' + (item.time ? relativeTime(item.time) : '') + '</div>' +
3511          '</div>' +
3512        '</div>';
3513      }).join('');
3514      track.innerHTML = html;
3515    }
3516
3517    function escHtml(str) {
3518      return str.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
3519    }
3520
3521    function relativeTime(isoStr) {
3522      var diff = Date.now() - new Date(isoStr).getTime();
3523      var m = Math.floor(diff / 60000);
3524      if (m < 2) return 'just now';
3525      if (m < 60) return m + 'm ago';
3526      var h = Math.floor(m / 60);
3527      if (h < 24) return h + 'h ago';
3528      return Math.floor(h/24) + 'd ago';
3529    }
3530
3531    // ----------------------------------------------------------------
3532    // LIVE DATA INIT
3533    // ----------------------------------------------------------------
3534    var API = '/api/arcnautical/v1';
3535
3536    function initLiveData(gaugeCtrl) {
3537      Promise.allSettled([
3538        fetch(API + '/public/featured-score?origin=SGSIN&dest=NLRTM')
3539          .then(function(r) { return r.ok ? r.json() : null; })
3540          .catch(function() { return null; }),
3541        fetch(API + '/public/intel-feed')
3542          .then(function(r) { return r.ok ? r.json() : null; })
3543          .catch(function() { return null; }),
3544      ]).then(function(results) {
3545        var score = results[0].status === 'fulfilled' ? results[0].value : null;
3546        var feed  = results[1].status === 'fulfilled' ? results[1].value : null;
3547
3548        if (score && typeof score.riskScore === 'number') {
3549          gaugeCtrl.updateScore(score.riskScore, score.riskLevel);
3550          var RISK_COLORS = { low:'#059669', moderate:'#818cf8', elevated:'#d97706', high:'#ea580c', critical:'#dc2626' };
3551          var col = RISK_COLORS[score.riskLevel] || '#818cf8';
3552          document.getElementById('heroRiskLabel').textContent = score.riskScore + ' ' + score.riskLevel.toUpperCase();
3553          document.getElementById('heroRiskLabel').style.color = col;
3554          var updatedEl = document.getElementById('heroUpdatedAt');
3555          updatedEl.textContent = 'as of ' + relativeTime(score.computedAt);
3556          updatedEl.style.display = 'block';
3557          document.getElementById('scoreLiveBadge').style.display = 'inline-flex';
3558          document.getElementById('scoreDemoBadge').style.display = 'none';
3559        }
3560
3561        var updatedAt = document.getElementById('feedUpdatedAt');
3562        if (feed && Array.isArray(feed.items) && feed.items.length > 0) {
3563          var tickerItems = feed.items.map(function(item) {
3564            return {
3565              type: item.type || 'jwc',
3566              label: item.label,
3567              msg: item.message,
3568              time: item.timestamp,
3569            };
3570          });
3571          buildTickerFromItems(tickerItems);
3572          document.getElementById('feedLiveBadge').style.display = 'inline-flex';
3573          // The stamp is the newest EVENT on the strip, never the cache write:
3574          // "updated 2m ago" over a week-old report is the fetch succeeding, not
3575          // the source delivering. newestAt comes from the server; older
3576          // servers are covered by reading the items.
3577          var newest = feed.newestAt || null;
3578          if (!newest) {
3579            for (var i = 0; i < tickerItems.length; i++) {
3580              var ts = tickerItems[i].time;
3581              if (ts && (!newest || ts > newest)) newest = ts;
3582            }
3583          }
3584          if (newest) updatedAt.textContent = 'latest event ' + relativeTime(newest);
3585        } else {
3586          // No fabricated fallback. Say it, and show nothing.
3587          updatedAt.textContent = 'feed unavailable';
3588          var dot = document.getElementById('tickerDot');
3589          if (dot) dot.style.display = 'none';
3590          var track = document.getElementById('tickerTrack');
3591          if (track) track.style.display = 'none';
3592        }
3593      });
3594    }
3595
3596    // ----------------------------------------------------------------
3597    // COUNT-UP ANIMATION
3598    // ----------------------------------------------------------------
3599    function animateCountUp(el) {
3600      var target = parseFloat(el.dataset.count);
3601      var suffix = el.dataset.suffix || '';
3602      var decimals = parseInt(el.dataset.decimal || '0', 10);
3603      var duration = 1500, start = performance.now();
3604      function frame(now) {
3605        var t = Math.min((now - start) / duration, 1);
3606        var eased = 1 - Math.pow(1 - t, 3);
3607        var current = target * eased;
3608        el.textContent = decimals > 0 ? current.toFixed(decimals) + suffix : Math.round(current) + suffix;
3609        if (t < 1) requestAnimationFrame(frame);
3610      }
3611      requestAnimationFrame(frame);
3612    }
3613
3614    // ----------------------------------------------------------------
3615    // SCROLL REVEAL
3616    // ----------------------------------------------------------------
3617    function initReveal() {
3618      var obs = new IntersectionObserver(function(entries) {
3619        entries.forEach(function(entry) {
3620          if (!entry.isIntersecting) return;
3621          entry.target.classList.add('visible');
3622          var counter = entry.target.querySelector('[data-count]');
3623          if (counter && !counter.dataset.animated) {
3624            counter.dataset.animated = 'true';
3625            animateCountUp(counter);
3626          }
3627          obs.unobserve(entry.target);
3628        });
3629      }, { threshold: 0.15, rootMargin: '0px 0px -40px 0px' });
3630      document.querySelectorAll('.reveal').forEach(function(el) { obs.observe(el); });
3631    }
3632
3633    // ----------------------------------------------------------------
3634    // PORT AUTOCOMPLETE
3635    // ----------------------------------------------------------------
3636    var SEARCH_API = '/api/arcnautical/v1/public/search-ports';
3637    var SCORE_API = '/api/arcnautical/v1/public/score-route';
3638
3639    function countryFlag(code) {
3640      if (!code) return '';
3641      var up = code.toUpperCase();
3642      if (up.length !== 2) return '';
3643      var a = 0x1f1e6;
3644      return String.fromCodePoint(a + up.charCodeAt(0) - 65, a + up.charCodeAt(1) - 65);
3645    }
3646
3647    function PortAutocomplete(inputEl, dropdownEl, onSelect) {
3648      this.input = inputEl;
3649      this.dropdown = dropdownEl;
3650      this.onSelect = onSelect;
3651      this.selected = null;
3652      this.results = [];
3653      this.hlIndex = -1;
3654      this.timer = null;
3655      this.controller = null;
3656
3657      var self = this;
3658      this.input.addEventListener('input', function() { self._onInput(); });
3659      this.input.addEventListener('keydown', function(e) { self._onKey(e); });
3660      this.input.addEventListener('focus', function() {
3661        if (self.results.length > 0 && !self.selected) self._open();
3662      });
3663      document.addEventListener('click', function(e) {
3664        if (!self.input.parentElement.contains(e.target)) self._close();
3665      }, true);
3666    }
3667
3668    PortAutocomplete.prototype._onInput = function() {
3669      this.selected = null;
3670      this.input.classList.remove('has-value');
3671      var q = this.input.value.trim();
3672      if (q.length < 2) { this._close(); updateScoreBtn(); return; }
3673      if (this.timer) clearTimeout(this.timer);
3674      var self = this;
3675      this.timer = setTimeout(function() { self._search(q); }, 200);
3676    };
3677
3678    PortAutocomplete.prototype._search = function(q) {
3679      if (this.controller) this.controller.abort();
3680      this.controller = new AbortController();
3681      this._showMsg('Searching...');
3682      var self = this;
3683      fetch(SEARCH_API + '?query=' + encodeURIComponent(q) + '&limit=8', {
3684        signal: this.controller.signal
3685      }).then(function(r) {
3686        if (!r.ok) { self._close(); return; }
3687        return r.json();
3688      }).then(function(data) {
3689        if (!data) return;
3690        self.results = data.ports || [];
3691        self.hlIndex = -1;
3692        if (self.results.length === 0) self._noMatch(q);
3693        else self._renderResults();
3694      }).catch(function(e) {
3695        if (e.name === 'AbortError') return;
3696        self._close();
3697      });
3698    };
3699
3700    // A bare "No ports found" was a dead end: a visitor typing a UN/LOCODE we do
3701    // not hold (DKLIN, DETRV on 2026-09-28) got it and left. The code carries its
3702    // country, so offer the ports we cover there; any other miss says how to get
3703    // unstuck. Uppercase only: "Sines" is a port, not Slovenia.
3704    PortAutocomplete.prototype._noMatch = function(q) {
3705      var self = this;
3706      var hint = "No ports found. Try the nearest larger port, or type the country name to list the ports we cover there.";
3707      if (!/^[A-Z]{2}[A-Z2-9]{3}$/.test(q)) { self._showMsg(hint); return; }
3708      var cc = q.slice(0, 2);
3709      fetch(SEARCH_API + '?query=' + cc + '&limit=20', { signal: this.controller.signal })
3710        .then(function(r) { return r.ok ? r.json() : null; })
3711        .then(function(data) {
3712          var ports = ((data && data.ports) || []).filter(function(p) {
3713            return String(p.countryCode || p.country_code || '').toUpperCase() === cc;
3714          });
3715          if (!ports.length) { self._showMsg(hint); return; }
3716          self.results = ports;
3717          self.hlIndex = -1;
3718          self._renderResults('No port matches ' + q + '. Ports we cover in ' + ports[0].c
3718ountry + ':');
3719        })
3720        .catch(function(e) { if (e.name !== 'AbortError') self._showMsg(hint); });
3721    };
3722
3723    PortAutocomplete.prototype._renderResults = function(heading) {
3724      var self = this;
3725      this.dropdown.innerHTML = (heading ? '<div class="scorer-dd-msg">' + escHtml(heading) + '</div>' : '') + this.results.map(function(p, i) {
3726        return '<div class="scorer-dd-item' + (i === self.hlIndex ? ' hl' : '') + '" data-idx="' + i + '">' +
3727          '<span class="scorer-dd-flag">' + countryFlag(p.countryCode || p.country_code || '') + '</span>' +
3728          '<span class="scorer-dd-name">' + escHtml(p.name) + ', ' + escHtml(p.country) + '</span>' +
3729          '<span class="scorer-dd-code">' + escHtml(p.locode) + '</span>' +
3730        '</div>';
3731      }).join('');
3732
3733      this.dropdown.querySelectorAll('.scorer-dd-item').forEach(function(el) {
3734        el.addEventListener('mousedown', function(e) { e.preventDefault(); });
3735        el.addEventListener('click', function() { self._selectIdx(parseInt(el.dataset.idx)); });
3736        el.addEventListener('mouseenter', function() { self._highlight(parseInt(el.dataset.idx)); });
3737      });
3738      this._open();
3739    };
3740
3741    PortAutocomplete.prototype._showMsg = function(text) {
3742      this.dropdown.innerHTML = '<div class="scorer-dd-msg">' + escHtml(text) + '</div>';
3743      this._open();
3744    };
3745
3746    PortAutocomplete.prototype._selectIdx = function(idx) {
3747      var port = this.results[idx];
3748      if (!port) return;
3749      this.selected = port;
3750      this.input.value = port.name + ' (' + port.locode + ')';
3751      this.input.classList.add('has-value');
3752      this._close();
3753      this.onSelect(port);
3754      updateScoreBtn();
3755    };
3756
3757    PortAutocomplete.prototype.setValue = function(port) {
3758      this.selected = port;
3759      this.input.value = port.name + ' (' + port.locode + ')';
3760      this.input.classList.add('has-value');
3761      this._close();
3762      updateScoreBtn();
3763    };
3764
3765    PortAutocomplete.prototype.reset = function() {
3766      this.selected = null;
3767      this.input.value = '';
3768      this.input.classList.remove('has-value');
3769      this.results = [];
3770      this._close();
3771    };
3772
3773    PortAutocomplete.prototype._onKey = function(e) {
3774      if (!this.dropdown.classList.contains('open')) return;
3775      if (e.key === 'ArrowDown') { e.preventDefault(); this._moveHL(1); }
3776      else if (e.key === 'ArrowUp') { e.preventDefault(); this._moveHL(-1); }
3777      else if (e.key === 'Enter') { e.preventDefault(); if (this.hlIndex >= 0) this._selectIdx(this.hlIndex); }
3778      else if (e.key === 'Escape') { this._close(); this.input.blur(); }
3779    };
3780
3781    PortAutocomplete.prototype._moveHL = function(d) {
3782      var len = this.results.length;
3783      if (!len) return;
3784      var next = this.hlIndex + d;
3785      if (next < 0) next = len - 1;
3786      if (next >= len) next = 0;
3787      this._highlight(next);
3788    };
3789
3790    PortAutocomplete.prototype._highlight = function(idx) {
3791      this.dropdown.querySelectorAll('.scorer-dd-item').forEach(function(el, i) {
3792        el.classList.toggle('hl', i === idx);
3793      });
3794      this.hlIndex = idx;
3795    };
3796
3797    PortAutocomplete.prototype._open = function() { this.dropdown.classList.add('open'); };
3798    PortAutocomplete.prototype._close = function() { this.dropdown.classList.remove('open'); this.hlIndex = -1; };
3799
3800    // ----------------------------------------------------------------
3801    // SCORER STATE
3802    // ----------------------------------------------------------------
3803    var originAC, destAC, heroGauge, resultsMap, resultsGauge;
3804
3805    function updateScoreBtn() {
3806      var btn = document.getElementById('scoreBtn');
3807      if (btn) btn.disabled = !(originAC && originAC.selected && destAC && destAC.selected);
3808    }
3809
3810    function scoreRoute() {
3811      if (!originAC.selected || !destAC.selected) return;
3812      if (originAC.selected.locode === destAC.selected.locode) {
3813        showScorerError('Origin and destination must be different ports.');
3814        return;
3815      }
3816
3817      var btn = document.getElementById('scoreBtn');
3818      var btnText = document.getElementById('scoreBtnText');
3819      var spinner = document.getElementById('scoreBtnSpinner');
3820      var errorEl = document.getElementById('scorerError');
3821
3822      btn.disabled = true;
3823      btnText.textContent = 'Scoring...';
3824      spinner.style.display = 'block';
3825      errorEl.classList.remove('visible');
3826
3827      fetch(SCORE_API, {
3828        method: 'POST',
3829        headers: { 'Content-Type': 'application/json' },
3830        body: JSON.stringify({
3831          origin_locode: originAC.selected.locode,
3832          dest_locode: destAC.selected.locode,
3833        }),
3834      }).then(function(resp) {
3835        if (resp.status === 429) {
3836          return resp.json().catch(function() { return {}; }).then(function(errData) {
3837            showScorerError(errData.error || 'Too many requests in a short period — please try again in a minute.');
3838            throw new Error('rate_limit');
3839          });
3840        }
3841        if (!resp.ok) {
3842          return resp.json().catch(function() { return {}; }).then(function(errData) {
3843            showScorerError(errData.error || 'Could not score this route. Please try again.');
3844            throw new Error('api_error');
3845          });
3846        }
3847        return resp.json();
3848      }).then(function(data) {
3849        updateHeroCard(data);
3850        renderResults(data);
3851      }).catch(function(err) {
3852        if (err.message !== 'rate_limit' && err.message !== 'api_error') {
3853          console.error('[ArcNautical] Score error:', err);
3854          showScorerError(err && err.message ? err.message : 'Network error. Please check your connection and try again.');
3855        }
3856      }).finally(function() {
3857        btn.disabled = false;
3858        btnText.textContent = 'Score This Route';
3859        spinner.style.display = 'none';
3860      });
3861    }
3862
3863    function showScorerError(msg) {
3864      var el = document.getElementById('scorerError');
3865      el.textContent = msg;
3866      el.classList.add('visible');
3867      var btn = document.getElementById('scoreBtn');
3868      btn.disabled = false;
3869      document.getElementById('scoreBtnText').textContent = 'Score This Route';
3870      document.getElementById('scoreBtnSpinner').style.display = 'none';
3871    }
3872
3873    function updateHeroCard(data) {
3874      var RISK_COLORS = { low:'#059669', moderate:'#818cf8', elevated:'#d97706', high:'#ea580c', critical:'#dc2626' };
3875      var col = RISK_COLORS[data.riskLevel] || '#818cf8';
3876
3877      if (heroGauge) heroGauge.updateScore(data.riskScore, data.riskLevel);
3878
3879      var routePorts = document.getElementById('heroRoutePorts');
3880      if (routePorts) routePorts.innerHTML = data.origin.locode + ' <span style="color:var(--text-dim);">&rarr;</span> ' + data.destination.locode;
3881
3882      var routeMeta = document.getElementById('heroRouteMeta');
3883      if (routeMeta) routeMeta.innerHTML = data.distanceNm.toLocaleString() + ' nm &middot; Risk Score: <span id="heroRiskLabel" style="color:' + col + ';font-weight:600;">' + data.riskScore + ' ' + data.riskLevel.toUpperCase() + '</span>';
3884
3885      var liveBadge = document.getElementById('scoreLiveBadge');
3886      var demoBadge = document.getElementById('scoreDemoBadge');
3887      if (liveBadge) liveBadge.style.display = 'inline-flex';
3888      if (demoBadge) demoBadge.style.display = 'none';
3889
3890      var updatedEl = document.getElementById('heroUpdatedAt');
3891      if (updatedEl) {
3892        updatedEl.textContent = 'scored ' + relativeTime(data.computedAt);
3893        updatedEl.style.display = 'block';
3894      }
3895
3896      var wpContainer = document.getElementById('heroWaypoints');
3897      if (wpContainer && data.waypoints && data.waypoints.length > 0) {
3898        wpContainer.innerHTML = data.waypoints.map(function(wp, i) {
3899          var arrow = i < data.waypoints.length - 1 ? '<span class="hero-waypoint-arrow">&rarr;</span>' : '';
3900          return '<span class="hero-waypoint">' + escHtml(wp.name) + '</span>' + arrow;
3901        }).join('');
3902      }
3903    }
3904
3905    // ----------------------------------------------------------------
3906    // RESULTS RENDERER
3907    // ----------------------------------------------------------------
3908    function renderResults(data) {
3909      var panel = document.getElementById('scorerResults');
3910
3911      if (resultsMap) {
3912        try { resultsMap.off(); resultsMap.remove(); } catch(e) {}
3913        resultsMap = null;
3914      }
3915
3916      var RISK_COLORS = { low:'#059669', moderate:'#818cf8', elevated:'#d97706', high:'#ea580c', critical:'#dc2626' };
3917      var col = RISK_COLORS[data.riskLevel] || '#818cf8';
3918
3919      var confPct = Math.round((data.dataConfidence || 0) * 100);
3920      var confClass = confPct >= 50 ? 'good' : 'limited';
3921      var confLabel = confPct >= 50 ? confPct + '% data coverage' : 'Limited coverage (' + confPct + '%)';
3922
3923      var driversHtml = (data.drivers || []).map(function(d) {
3924        var dCol = d.score >= 70 ? RISK_COLORS.critical :
3925                   d.score >= 50 ? RISK_COLORS.high :
3926                   d.score >= 30 ? RISK_COLORS.elevated :
3927                   d.score >= 15 ? RISK_COLORS.moderate : RISK_COLORS.low;
3928        return '<div class="driver-card">' +
3929          '<div class="driver-card-name">' + escHtml(d.factor) + '</div>' +
3930          '<div class="driver-card-score" style="color:' + dCol + '">' + d.score + '</div>' +
3931          '<div class="driver-card-weight">Weight: ' + Math.round(d.weight * 100) + '%</div>' +
3932          '<div class="driver-card-bar"><div class="driver-card-bar-fill" style="width:' + d.score + '%;background:' + dCol + '"></div></div>' +
3933          '<div class="driver-card-detail">' + escHtml(d.details) + '</div>' +
3934        '</div>';
3935      }).join('');
3936
3937      var wpHtml = (data.waypoints || []).map(function(wp, i) {
3938        var arrow = i < data.waypoints.length - 1 ? '<span class="results-wp-arrow">&rarr;</span>' : '';
3939        return '<span class="results-wp-tag">' + escHtml(wp.name) + '</span>' + arrow;
3940      }).join('');
3941
3942      var durationHours = data.durationHours || Math.round(data.distanceNm / 14);
3943      var durationDays = (durationHours / 24).toFixed(1);
3944
3945      panel.innerHTML =
3946        '<div class="results-inner">' +
3947          '<div class="results-header">' +
3948            '<div>' +
3949              '<div class="results-route-name">' + escHtml(data.origin.name) + ' <span>&rarr;</span> ' + escHtml(data.destination.name) + '</div>' +
3950              '<div class="results-scored-at">' + data.origin.locode + ' &rarr; ' + data.destination.locode + ' &middot; Scored ' + relativeTime(data.computedAt) + '</div>' +
3951            '</div>' +
3952            '<div style="display:flex;gap:8px;flex-wrap:wrap">' +
3953              '<button class="results-score-again-btn" id="shareLaneBtn" type="button">🔗 Copy shareable link</button>' +
3954              '<button class="results-score-again-btn" id="scoreAgainBtn">Score Another Route</button>' +
3955            '</div>' +
3956          '</div>' +
3957          '<div class="results-body">' +
3958            '<div class="results-grid">' +
3959              '<div class="results-score-col">' +
3960                '<svg id="resultsGauge" width="200" height="200" viewB
3960ox="0 0 200 200"></svg>' +
3961                '<div class="results-meta">' +
3962                  '<div class="results-meta-item"><strong>' + data.distanceNm.toLocaleString() + '</strong> nm</div>' +
3963                  '<div class="results-meta-item"><strong>' + Math.round(durationHours) + '</strong> hours (~' + durationDays + ' days)</div>' +
3964                  '<div class="results-confidence ' + confClass + '">' + confLabel + '</div>' +
3965                '</div>' +
3966              '</div>' +
3967              '<div class="results-map-col">' +
3968                '<div class="results-map" id="resultsMap"></div>' +
3969              '</div>' +
3970            '</div>' +
3971            (wpHtml ? '<div class="results-waypoints"><span class="results-wp-label">Via:</span>' + wpHtml + '</div>' : '') +
3972            '<div class="results-drivers-title">Risk Drivers</div>' +
3973            '<div class="results-drivers">' + driversHtml + '</div>' +
3974            // Delivery-framed capture (mounted below). The full result above is shown
3975            // unconditionally — email is how you TAKE the brief with you, never a toll
3976            // to reveal it. Replaces the old blur/lock signup gate, which hid fields the
3977            // public lane path never computes (Monte Carlo / ownership / Cape-vs-Suez /
3978            // AI narrative) — a scarcity + placeholder-integrity defect.
3979            '<div id="lane-capture-slot"></div>' +
3980          '</div>' +
3981          '<div class="results-footer" style="flex-direction:column;gap:12px">' +
3982            // The one thing this result did not offer before: a way to keep it.
3983            '<a id="laneSignupCta" href="' + escHtml(laneSignupUrl(data.origin.locode, data.destination.locode)) + '"' +
3984              ' style="display:block;width:100%;max-width:520px;text-align:center;text-decoration:none;' +
3985              'background:linear-gradient(135deg,#4f46e5,#6366f1);border:1px solid #818cf8;border-radius:8px;' +
3986              'padding:14px 22px;transition:filter .15s">' +
3987              '<span style="display:block;color:#fff;font-weight:600;font-size:14px">Keep this lane — create a free account</span>' +
3988              '<span style="display:block;color:rgba(255,255,255,0.78);font-size:12px;margin-top:3px">' +
3989                'Score it again anytime and get alerted when it changes.</span>' +
3990            '</a>' +
3991            '<button class="scorer-popular-btn" id="scoreAnotherBtn2" style="padding:10px 24px;font-size:13px;">Score Another Route</button>' +
3992          '</div>' +
3993        '</div>';
3994
3995      document.getElementById('scoreAgainBtn').addEventListener('click', resetScorer);
3996      document.getElementById('scoreAnotherBtn2').addEventListener('click', resetScorer);
3997
3998      var shareLaneBtn = document.getElementById('shareLaneBtn');
3999      if (shareLaneBtn) shareLaneBtn.addEventListener('click', function () {
4000        var url = laneShareUrl(data.origin.locode, data.destination.locode);
4001        arcCopyToClipboard(url, function (ok) {
4002          shareLaneBtn.textContent = ok ? 'Link copied ✓' : 'Copy failed';
4003          setTimeout(function () { shareLaneBtn.textContent = '🔗 Copy shareable link'; }, 2400);
4004        });
4005        try { window.posthog && posthog.capture('lane_result_shared', { origin: data.origin.locode, dest: data.destination.locode, surface: 'arcnautical-landing' }); } catch (e) {}
4006      });
4007
4008      var laneSignupCta = document.getElementById('laneSignupCta');
4009      if (laneSignupCta) laneSignupCta.addEventListener('click', function () {
4010        // Fired on the way out, so the funnel can tell "scored and left" from
4011        // "scored and went to sign up" — the step that was previously invisible.
4012        try {
4013          window.posthog && posthog.capture('lane_signup_cta_clicked', {
4014            origin: data.origin.locode,
4015            dest: data.destination.locode,
4016            score: data.riskScore,
4017            surface: 'arcnautical-landing',
4018          });
4019        } catch (e) {}
4020      });
4021
4022      var gaugeEl = document.getElementById('resultsGauge');
4023      resultsGauge = renderGauge(gaugeEl, 0, 'low', 200);
4024      setTimeout(function() { resultsGauge.updateScore(data.riskScore, data.riskLevel); }, 100);
4025
4026      // Delivery-framed lane-brief capture — email = take the brief with you, not a gate.
4027      if (window.ArcLaneCapture) {
4028        ArcLaneCapture.mount('lane-capture-slot', {
4029          originLocode: data.origin.locode,
4030          destLocode: data.destination.locode,
4031          originName: data.origin.name,
4032          destName: data.destination.name,
4033          geojson: data.routeGeojson,
4034          surface: 'arcnautical-landing',
4035        });
4036      }
4037
4038      requestAnimationFrame(function() {
4039        panel.classList.add('visible');
4040        setTimeout(function() {
4041          renderResultsMap(data);
4042          panel.scrollIntoView({ behavior: 'smooth', block: 'start' });
4043        }, 500);
4044      });
4045    }
4046
4047    function resetScorer() {
4048      var panel = document.getElementById('scorerResults');
4049      panel.classList.remove('visible');
4050      setTimeout(function() { panel.innerHTML = ''; }, 700);
4051
4052      if (resultsMap) { resultsMap.remove(); resultsMap = null; }
4053      originAC.reset();
4054      destAC.reset();
4055      updateScoreBtn();
4056
4057      document.getElementById('hero').scrollIntoView({ behavior: 'smooth' });
4058      setTimeout(function() { document.getElementById('originInput').focus(); }, 500);
4059    }
4060
4061    // ----------------------------------------------------------------
4062    // MAP RENDERER
4063    // ----------------------------------------------------------------
4064    function renderResultsMap(data) {
4065      if (resultsMap) {
4066        try { resultsMap.off(); resultsMap.remove(); } catch(e) {}
4067        resultsMap = null;
4068      }
4069      var mapEl = document.getElementById('resultsMap');
4070      if (!mapEl || !window.L) return;
4071
4072      resultsMap = L.map(mapEl, {
4073        zoomControl: false,
4074        attributionControl: true,
4075        scrollWheelZoom: false,
4076      });
4077
4078      L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
4079        attribution: '&copy; <a href="https://carto.com/">CARTO</a>',
4080        subdomains: 'abcd',
4081        maxZoom: 19,
4082      }).addTo(resultsMap);
4083
4084      L.control.zoom({ position: 'topright' }).addTo(resultsMap);
4085
4086      var initBounds = null;
4087      if (data.routeGeojson) {
4088        initBounds = L.geoJSON(data.routeGeojson).getBounds();
4089      }
4090      if (initBounds && initBounds.isValid()) {
4091        resultsMap.fitBounds(initBounds, { padding: [40, 40] });
4092      } else if (data.origin && data.destination) {
4093        resultsMap.fitBounds([
4094          [data.origin.lat, data.origin.lng],
4095          [data.destination.lat, data.destination.lng]
4096        ], { padding: [40, 40] });
4097      } else {
4098        resultsMap.setView([20, 40], 3);
4099      }
4100
4101      resultsMap.invalidateSize();
4102
4103      if (data.routeGeojson) {
4104        L.geoJSON(data.routeGeojson, {
4105          style: { color: '#0891b2', weight: 2.5, opacity: 0.8 },
4106        }).addTo(resultsMap);
4107      }
4108
4109      if (data.origin && data.origin.lat) {
4110        L.circleMarker([data.origin.lat, data.origin.lng], {
4111          radius: 7, fillColor: '#059669', fillOpacity: 0.9, color: '#fff', weight: 2,
4112        }).bindTooltip(data.origin.name, { permanent: false }).addTo(resultsMap);
4113      }
4114
4115      if (data.destination && data.destination.lat) {
4116        L.circleMarker([data.destination.lat, data.destination.lng], {
4117          radius: 7, fillColor: '#dc2626', fillOpacity: 0.9, color: '#fff', weight: 2,
4118        }).bindTooltip(data.destination.name, { permanent: false }).addTo(resultsMap);
4119      }
4120
4121      if (data.waypoints) {
4122        data.waypoints.forEach(function(wp) {
4123          if (!wp.lat || !wp.lng) return;
4124          L.circleMarker([wp.lat, wp.lng], {
4125            radius: 4, fillColor: '#f59e0b', fillOpacity: 0.8, color: '#fff', weight: 1,
4126          }).bindTooltip(wp.name, { permanent: false }).addTo(resultsMap);
4127        });
4128      }
4129    }
4130
4131    // ----------------------------------------------------------------
4132    // SHAREABLE LANE PERMALINK — a zero-cost rung between "anonymous" and "gave
4133    // email": copy a link to THIS lane result; /?origin=…&dest=… re-scores it live
4134    // for whoever opens it (see the score-from-URL block in INIT). Every forward is
4135    // a fresh top-of-funnel touch, no email required. Mirrors /check?imo= on the
4136    // vessel side.
4137    // ----------------------------------------------------------------
4138    function laneShareUrl(oL, dL) {
4139      return 'https://arcnautical.com/?origin=' + encodeURIComponent(oL) + '&dest=' + encodeURIComponent(dL);
4140    }
4141
4142    // SIGNUP BRIDGE THAT CARRIES THE LANE. On 2026-08-02 a visitor arrived from
4143    // Brave Search, scored a lane here, registered 52 seconds later — and got a
4144    // seeded "Demo Fleet" and a global dashboard, because the scorer persists
4145    // nothing (Redis cache only) and every signup link was a bare #/register.
4146    // The lane they came for was simply gone.
4147    //
4148    // No new persistence is needed to fix it: #/voyage?origin=&dest= already
4149    // auto-scores, and an AUTHED score already upserts arcnautical_saved_lanes.
4150    // Handing the account the lane in the URL is enough — the row writes itself.
4151    //
4152    // UTM in the search string, route in the hash: RegisterPage reads
4153    // window.location.search for attribution, and the SPA router owns the hash.
4154    // Same shape as check.html's vessel-side signup bridge.
4155    function laneSignupUrl(oL, dL) {
4156      return '/arcnautical.html?utm_source=landing&utm_medium=lane_scorer&utm_campaign=lane_bridge'
4157        + '&lane=' + encodeURIComponent(oL) + '-' + encodeURIComponent(dL) + '#/register';
4158    }
4159
4160    function arcCopyToClipboard(text, cb) {
4161      cb = cb || function () {};
4162      try {
4163        if (navigator.clipboard && navigator.clipboard.writeText) {
4164          navigator.clipboard.writeText(text).then(function () { cb(true); }, function () { arcCopyFallback(text, cb); });
4165          return;
4166        }
4167      } catch (e) {}
4168      arcCopyFallback(text, cb);
4169    }
4170
4171    function arcCopyFallback(text, cb) {
4172      try {
4173        var ta = document.createElement('textarea');
4174        ta.value = text; ta.setAttribute('readonly', '');
4175        ta.style.position = 'fixed'; ta.style.top = '-1000px'; ta.style.opacity = '0';
4176        document.body.appendChild(ta); ta.focus(); ta.select();
4177        var ok = document.execCommand('copy');
4178        document.body.removeChild(ta); cb(!!ok);
4179      } catch (e) { cb(false); }
4180    }
4181
4182    // Score a lane from bare LOCODEs (shared-link entry). A shared URL carries only
4183    // codes, so bypass the autocomplete and POST the two codes straight to the scorer
4184    // API — the result is deterministic, so the colleague who opens the link sees
4185    // exactly what was shared, freshly recomputed.
4186    var LANE_LOCODE_RE = /^[A-Z]{2}[A-Z0-9]{3}$/;
4187    function scoreLaneByLocodes(oL, dL) {
4188      oL = String(oL || '').toUpperCase(); dL = String(dL || '').toUpperCase();
4189      if (!LANE_LOCODE_RE.test(oL) || !LANE_LOCODE_RE.test(dL) || oL === dL) return;
4190      fetch(SCORE_API, {
4191        method: 'POST',
4192        headers: { 'Content-Type': 'application/json' },
4193        body: JSON.stringify({ origin_locode: oL, dest_locode: dL }),
4194      }).then(function (resp) {
4195        if (!resp.ok) throw new Error('score_failed');
4196        return resp.json();
4197      }).then(function (data) {
4198        updateHeroCard(data);
4199        renderResults(data);
4200        try { window.posthog && posthog.capture('lane_deep_link_landed', { origin: oL, dest: dL, source: 'url_param' }); } catch (e) {}
4201      }).catch(function () { /* silent: visitor can still score manually */ });
4202    }
4203
4204    // ----------------------------------------------------------------
4205    // POPULAR ROUTES
4206    // ----------------------------------------------------------------
4207    var POPULAR_PORTS = {
4208      SGSIN: { locode:'SGSIN', name:'Singapore', country:'Singapore', countryCode:'SG', lat:1.29, lng:103.85 },
4209      NLRTM: { locode:'NLRTM', name:'Rotterdam', country:'Netherlands', countryCode:'NL', lat:51.92, lng:4.48 },
4210      EGPSD: { locode:'EGPSD', name:'Port Said', country:'Egypt', countryCode:'EG', lat:31.26, lng:32.30 },
4211      CNSHA: { locode:'CNSHA', name:'Shanghai', country:'China', countryCode:'CN', lat:31.23, lng:121.47 },
4212      DEHAM: { locode:'DEHAM', name:'Hamburg', country:'Germany', countryCode:'DE', lat:53.55, lng:9.97 },
4213      USHOU: { locode:'USHOU', name:'Houston', country:'United States', countryCode:'US', lat:29.76, lng:-95.36 },
4214      AEJEA: { locode:'AEJEA', name:'Jebel Ali', country:'United Arab Emirates', countryCode:'AE', lat:25.01, lng:55.06 },
4215    };
4216
4217    function initPopularRoutes() {
4218      document.querySelectorAll('.scorer-popular-btn[data-origin]').forEach(function(btn
4218) {
4219        btn.addEventListener('click', function() {
4220          var o = POPULAR_PORTS[btn.dataset.origin];
4221          var d = POPULAR_PORTS[btn.dataset.dest];
4222          if (o && d) {
4223            originAC.setValue(o);
4224            destAC.setValue(d);
4225            updateScoreBtn();
4226            scoreRoute();
4227          }
4228        });
4229      });
4230    }
4231
4232    // ----------------------------------------------------------------
4233    // SCROLL PROGRESS BAR
4234    // ----------------------------------------------------------------
4235    function initScrollProgress() {
4236      var bar = document.getElementById('scrollProgress');
4237      window.addEventListener('scroll', function() {
4238        var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
4239        var docHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight;
4240        var pct = docHeight > 0 ? (scrollTop / docHeight) * 100 : 0;
4241        bar.style.width = pct + '%';
4242      }, { passive: true });
4243    }
4244
4245    // ----------------------------------------------------------------
4246    // HAMBURGER MENU
4247    // ----------------------------------------------------------------
4248    function initHamburger() {
4249      var btn = document.getElementById('navHamburger');
4250      var links = document.getElementById('navLinks');
4251      btn.addEventListener('click', function() {
4252        btn.classList.toggle('open');
4253        links.classList.toggle('open');
4254      });
4255      // Close on link click
4256      links.querySelectorAll('a').forEach(function(a) {
4257        a.addEventListener('click', function() {
4258          btn.classList.remove('open');
4259          links.classList.remove('open');
4260        });
4261      });
4262    }
4263
4264    // ----------------------------------------------------------------
4265    // PRODUCT SHOWCASE TABS
4266    // ----------------------------------------------------------------
4267    function initProductTabs() {
4268      var tabs = document.querySelectorAll('#showcaseTabs .showcase-tab');
4269      var panels = document.querySelectorAll('.showcase-panel');
4270      tabs.forEach(function(tab) {
4271        tab.addEventListener('click', function() {
4272          var target = tab.dataset.tab;
4273          tabs.forEach(function(t) { t.classList.remove('active'); });
4274          tab.classList.add('active');
4275          panels.forEach(function(p) {
4276            if (p.dataset.panel === target) {
4277              p.classList.add('active');
4278              // Re-trigger EP curve animation if underwriting tab
4279              if (target === 'underwriting') {
4280                var epPath = document.getElementById('epCurvePath');
4281                if (epPath) { epPath.classList.remove('drawn'); void epPath.offsetWidth; epPath.classList.add('drawn'); }
4282              }
4283            } else {
4284              p.classList.remove('active');
4285            }
4286          });
4287        });
4288      });
4289    }
4290
4291    // ----------------------------------------------------------------
4292    // API PREVIEW TABS
4293    // ----------------------------------------------------------------
4294    function initApiTabs() {
4295      var tabs = document.querySelectorAll('#apiTabs .api-tab');
4296      var panels = document.querySelectorAll('.api-panel');
4297      tabs.forEach(function(tab) {
4298        tab.addEventListener('click', function() {
4299          var target = tab.dataset.api;
4300          tabs.forEach(function(t) { t.classList.remove('active'); });
4301          tab.classList.add('active');
4302          panels.forEach(function(p) {
4303            p.classList.toggle('active', p.dataset.apiPanel === target);
4304          });
4305        });
4306      });
4307    }
4308
4309    // ----------------------------------------------------------------
4310    // SIGNAL CONVERGENCE ANIMATION
4311    // ----------------------------------------------------------------
4312    function initSignalConvergence() {
4313      var svg = document.getElementById('signalsSvg');
4314      if (!svg) return;
4315
4316      var linesG = document.getElementById('signalLines');
4317      var nodesG = document.getElementById('signalNodes');
4318      var centerScore = document.getElementById('signalsCenterScore');
4319      var ns = 'http://www.w3.org/2000/svg';
4320
4321      var colors = ['#dc2626','#ea580c','#d97706','#0891b2','#a78bfa','#6366f1','#38bdf8','#f472b6','#fb923c','#fbbf24'];
4322      var labels = ['CON','PIR','NAV','JWC','AIS','CII','WX','SAN','PSC','DIS'];
4323      var cx = 200, cy = 350;
4324
4325      // Place 10 nodes in a semicircle above center
4326      for (var i = 0; i < 10; i++) {
4327        var angle = Math.PI + (Math.PI * (i + 0.5) / 10);
4328        var nx = cx + 160 * Math.cos(angle);
4329        var ny = cy + 160 * Math.sin(angle);
4330
4331        // Line
4332        var line = document.createElementNS(ns, 'line');
4333        line.setAttribute('x1', nx);
4334        line.setAttribute('y1', ny);
4335        line.setAttribute('x2', cx);
4336        line.setAttribute('y2', cy - 44);
4337        line.setAttribute('stroke', colors[i]);
4338        line.setAttribute('stroke-width', '1');
4339        line.setAttribute('opacity', '0.4');
4340        line.setAttribute('class', 'signal-line');
4341        line.style.transitionDelay = (i * 0.12) + 's';
4342        linesG.appendChild(line);
4343
4344        // Node circle
4345        var circle = document.createElementNS(ns, 'circle');
4346        circle.setAttribute('cx', nx);
4347        circle.setAttribute('cy', ny);
4348        circle.setAttribute('r', '18');
4349        circle.setAttribute('fill', '#0d1420');
4350        circle.setAttribute('stroke', colors[i]);
4351        circle.setAttribute('stroke-width', '1.5');
4352        circle.setAttribute('class', 'signal-node');
4353        circle.style.transitionDelay = (i * 0.12) + 's';
4354        nodesG.appendChild(circle);
4355
4356        // Node label
4357        var text = document.createElementNS(ns, 'text');
4358        text.setAttribute('x', nx);
4359        text.setAttribute('y', ny);
4360        text.setAttribute('text-anchor', 'middle');
4361        text.setAttribute('dominant-baseline', 'central');
4362        text.setAttribute('fill', colors[i]);
4363        text.setAttribute('font-size', '8');
4364        text.setAttribute('font-family', "'JetBrains Mono',monospace");
4365        text.setAttribute('font-weight', '600');
4366        text.setAttribute('class', 'signal-node');
4367        text.style.transitionDelay = (i * 0.12) + 's';
4368        text.textContent = labels[i];
4369        nodesG.appendChild(text);
4370      }
4371
4372      // Trigger on scroll
4373      var triggered = false;
4374      var obs = new IntersectionObserver(function(entries) {
4375        if (triggered) return;
4376        entries.forEach(function(entry) {
4377          if (!entry.isIntersecting) return;
4378          triggered = true;
4379          svg.querySelectorAll('.signal-node').forEach(function(n) { n.classList.add('visible'); });
4380          svg.querySelectorAll('.signal-line').forEach(function(l) { l.classList.add('drawn'); });
4381          // Animate center score
4382          var start = performance.now();
4383          function frame(now) {
4384            var t = Math.min((now - start) / 1500, 1);
4385            var eased = 1 - Math.pow(1 - t, 3);
4386            centerScore.textContent = Math.round(34 * eased);
4387            if (t < 1) requestAnimationFrame(frame);
4388          }
4389          requestAnimationFrame(frame);
4390        });
4391      }, { threshold: 0.3 });
4392      obs.observe(svg);
4393    }
4394
4395    // ----------------------------------------------------------------
4396    // OWNERSHIP CHAIN ANIMATION
4397    // ----------------------------------------------------------------
4398    function initOwnershipChain() {
4399      var chain = document.getElementById('ownershipChain');
4400      if (!chain) return;
4401
4402      var obs = new IntersectionObserver(function(entries) {
4403        entries.forEach(function(entry) {
4404          if (!entry.isIntersecting) return;
4405          chain.querySelectorAll('.ownership-entity, .ownership-connector').forEach(function(el) {
4406            var delay = parseInt(el.dataset.delay || '0');
4407            setTimeout(function() { el.classList.add('visible'); }, delay);
4408          });
4409          obs.unobserve(chain);
4410        });
4411      }, { threshold: 0.3 });
4412      obs.observe(chain);
4413    }
4414
4415    // ----------------------------------------------------------------
4416    // CII POINTER ANIMATION
4417    // ----------------------------------------------------------------
4418    function initCiiPointer() {
4419      var pointer = document.getElementById('ciiPointer');
4420      if (!pointer) return;
4421
4422      var obs = new IntersectionObserver(function(entries) {
4423        entries.forEach(function(entry) {
4424          if (!entry.isIntersecting) return;
4425          // Slide to B rating (30% position)
4426          pointer.style.left = '30%';
4427          obs.unobserve(entry.target);
4428        });
4429      }, { threshold: 0.3 });
4430      obs.observe(document.getElementById('ciiScale'));
4431    }
4432
4433    // ----------------------------------------------------------------
4434    // ROUTE DRAWING ANIMATION
4435    // ----------------------------------------------------------------
4436    var routingShowcaseMap = null;
4437    function initRouteShowcase() {
4438      var mapEl = document.getElementById('routingShowcaseMap');
4439      if (!mapEl || !window.L) return;
4440
4441      var loaded = false;
4442      var obs = new IntersectionObserver(function(entries) {
4443        entries.forEach(function(entry) {
4444          if (!entry.isIntersecting || loaded) return;
4445          loaded = true;
4446          obs.unobserve(entry.target);
4447
4448          // Init map
4449          routingShowcaseMap = L.map(mapEl, {
4450            zoomControl: false,
4451            attributionControl: true,
4452            scrollWheelZoom: false,
4453            dragging: true,
4454          });
4455          L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
4456            attribution: '&copy; <a href="https://carto.com/">CARTO</a>',
4457            subdomains: 'abcd', maxZoom: 19,
4458          }).addTo(routingShowcaseMap);
4459          L.control.zoom({ position: 'topright' }).addTo(routingShowcaseMap);
4460
4461          // Default view while loading
4462          routingShowcaseMap.setView([20, 60], 3);
4463
4464          // Fetch real route from pathfinding engine
4465          fetch('/api/arcnautical/v1/public/score-route', {
4466            method: 'POST',
4467            headers: { 'Content-Type': 'application/json' },
4468            body: JSON.stringify({ origin_locode: 'NLRTM', dest_locode: 'SGSIN' }),
4469          })
4470          .then(function(r) { return r.ok ? r.json() : null; })
4471          .then(function(data) {
4472            if (!data || !routingShowcaseMap) return;
4473
4474            // Draw route
4475            if (data.routeGeojson || data.route_geojson) {
4476              var geojson = data.routeGeojson || data.route_geojson;
4477              var routeLayer = L.geoJSON(geojson, {
4478                style: { color: '#0891b2', weight: 3, opacity: 0.9 },
4479              }).addTo(routingShowcaseMap);
4480              routingShowcaseMap.fitBounds(routeLayer.getBounds(), { padding: [30, 30] });
4481            }
4482
4483            // Origin marker
4484            if (data.origin && data.origin.lat) {
4485              L.circleMarker([data.origin.lat, data.origin.lng], {
4486                radius: 7, fillColor: '#059669', fillOpacity: 0.9, color: '#fff', weight: 2,
4487              }).bindTooltip(data.origin.name || 'Rotterdam', { permanent: true, direction: 'top', className: 'route-showcase-label' }).addTo(routingShowcaseMap);
4488            }
4489
4490            // Destination marker
4491            if (data.destination && data.destination.lat) {
4492              L.circleMarker([data.destination.lat, data.destination.lng], {
4493                radius: 7, fillColor: '#dc2626', fillOpacity: 0.9, color: '#fff', weight: 2,
4494              }).bindTooltip(data.destination.name || 'Singapore', { permanent: true, direction: 'top', className: 'route-showcase-label' }).addTo(routingShowcaseMap);
4495            }
4496
4497            // Waypoints
4498            if (data.waypoints) {
4499              data.waypoints.forEach(function(wp) {
4500                if (!wp.lat || !wp.lng) return;
4501                L.circleMarker([wp.lat, wp.lng], {
4502                  radius: 4, fillColor: '#f59e0b', fillOpacity: 0.8, color: '#fff', weight: 1,
4503                }).bindTooltip(wp.name, { permanent: false, direction: 'top', className: 'route-showcase-label' }).addTo(routingShowcaseMap);
4504              });
4505            }
4506
4507            // Update label with distance
4508            var label = document.querySelector('.routing-map-label');
4509            if (label && data.distanceNm) {
4510              label.textContent = 'Rotterdam \u2192 Singapore \u00B7 ' + Math.round(data.distanceNm).toLocaleString() + ' nm \u00B7 Live pathfinding result';
4511            }
4512          })
4513          .catch(function() {
4514            // API unavailable — show static fallback view
4515            var label = document.querySelector('.routing-map-label');
4516            if (label) label.textContent = 'Rotterdam \u2192 Singapore \u00B7 Connect API for live route';
4517          });
4518        });
4519      }, { threshold: 0.2 });
4520      obs.observe(mapEl);
4521    }
4522
4523    // ----------------------------------------------------------------
4524    // EP CURVE ANIMATION
4525    // ----------------------------------------------------------------
4526    function initEpCurve() {
4527      var obs = new IntersectionObserver(function(entries) {
4528        entries.forEach(function(entry) {
4529          if (!entry.isIntersecting) return;
4530          var path = document.getElementById('epCurvePath');
4531          if (path) path.classList.add('drawn');
4532          obs.unobserve(entry.target);
4533        });
4534      }, { threshold: 0.3 });
4535      var epSvg = document.getElementById('epCurveSvg');
4536      if (epSvg) obs.observe(epSvg);
4537    }
4538
4539    // ----------------------------------------------------------------
4540    // HERO CYCLING PREVIEW
4541    // ----------------------------------------------------------------
4542    function initHeroPreview() {
4543      var items = document.querySelectorAll('#heroPreview .hero-preview-item');
4544      if (items.length < 2) return;
4545      var idx = 0;
4546      setInterval(function() {
4547        items[idx].classList.remove('active');
4548        idx = (idx + 1) % items.length;
4549        items[idx].classList.add('active');
4550      }, 3500);
4551    }
4552
4553    // ----------------------------------------------------------------
4554    // INIT
4555    // ----------------------------------------------------------------
4556    document.addEventListener('DOMContentLoaded', function() {
4557      // Hero gauge
4558      var heroGaugeEl = document.getElementById('heroGauge');
4559      heroGauge = renderGauge(heroGaugeEl, 34, 'low', 240);
4560
4561      var mockGaugeEl = document.getElementById('mockGauge');
4562      if (mockGaugeEl) renderGauge(mockGaugeEl, 34, 'low', 100).animate();
4563
4564      setTimeout(function() { heroGauge.animate(); }, 400);
4565
4566      // Live data
4567      initLiveData(heroGauge);
4568
4569      // Port autocomplete
4570      originAC = new PortAutocomplete(
4571        document.getElementById('originInput'),
4572        document.getElementById('originDropdown'),
4573        function() {}
4574      );
4575      destAC = new PortAutocomplete(
4576        document.getElementById('destInput'),
4577        document.getElementById('destDropdown'),
4578        function() {}
4579      );
4580
4581      // Score button
4582      document.getElementById('scoreBtn').addEventListener('click', scoreRoute);
4583      document.getElementById('destInput').addEventListener('keydown', function(e) {
4584        if (e.key === 'Enter' && !document.getElementById('destDropdown').classList.contains('open')) {
4585          if (originAC.selected && destAC.selected) scoreRoute();
4586        }
4587      });
4588
4589      // Popular routes
4590      initPopularRoutes();
4591
4592      // New features
4593      initScrollProgress();
4594      initHamburger();
4595      initProductTabs();
4596      initApiTabs();
4597      initSignalConvergence();
4598      initOwnershipChain();
4599      initCiiPointer();
4600      initRouteShowcase();
4601      initEpCurve();
4602      initHeroPreview();
4603
4604      // The landing #api capture form is gone: it asked people to wait for
4605      // access that has been self-serve since 2026-07-30. The section now sends
4606      // them to mint a key instead. The form still exists on /developers/ and
4607      // /voyage-risk-api/ for the things that ARE granted by hand — quota above
4608      // 10,000/month and corridor monitors.
4609
4610      // Scroll reveal (last, so all elements are ready)
4611      initReveal();
4612
4613      // Score-from-URL: a shared lane permalink (/?origin=…&dest=…) auto-runs, landing
4614      // the recipient straight on the result (mirrors /check?imo= on the vessel side).
4615      try {
4616        var _laneQs = new URLSearchParams(window.location.search);
4617        var _lo = (_laneQs.get('origin') || '').trim();
4618        var _ld = (_laneQs.get('dest') || '').trim();
4619        if (_lo && _ld) scoreLaneByLocodes(_lo, _ld);
4620      } catch (e) {}
4621    });
4622
4623    // Landing page instant vessel check
4624    async function landingQuickCheck(e) {
4625      e.preventDefault();
4626      var imo = document.getElementById('landing-imo').value.trim();
4627      if (!/^\d{7}$/.test(imo)) return false;
4628
4629      try { window.posthog && posthog.capture('check_vessel_submitted', { imo: imo, surface: 'arcnautical-landing' }); } catch(_){}
4630
4631      var btn = document.getElementById('landing-check-btn');
4632      var resultsEl = document.getElementById('landing-results');
4633      btn.textContent = 'Checking...'; btn.disabled = true;
4634      resultsEl.style.display = 'block';
4635      resultsEl.innerHTML = '<div style="padding:32px;color:var(--text-sec);font-size:0.85rem">Screening vessel across OFAC, EU, UN sanctions databases, GLEIF ownership registry, and PSC detention records...</div>';
4636
4637      try {
4638        // Fetch gets its own catch — see the same split in check.html. Sharing
4639        // one catch with the render block below reported every rendering
4640        // TypeError as `reason: 'network', status: 0`.
4641        var r;
4642        try {
4643          r = await fetch('/api/arcnautical/v1/public/quick-check', {
4644            method: 'POST',
4645            headers: { 'Content-Type': 'application/json', 'X-Arc-Browser-Id': (window.arcBrowserId || '') },
4646            body: JSON.stringify({ imo: imo })
4647          });
4648        } catch (netErr) {
4649          try { window.posthog && posthog.capture('check_vessel_failed', { imo: imo, reason: 'network', status: 0, message: String((netErr && netErr.message) || netErr).slice(0, 120), surface: 'arcnautical-landing' }); } catch(_){}
4650          resultsEl.innerHTML = '<div style="padding:24px;color:var(--risk-high)">Check failed. Please try again.</div>';
4651          return false;
4652        }
4653        if (r.status === 429) {
4654          try { window.posthog && posthog.capture('check_vessel_failed', { imo: imo, reason: 'rate_limited', status: r.status, surface: 'arcnautical-landing' }); } catch(_){}
4655          resultsEl.innerHTML = '<div style="padding:24px;color:var(--risk-elev)">Too many requests in a short period &mdash; please try again in a minute.</div>';
4656          return false;
4657        }
4658        var data = {};
4659        try { data = await r.json(); } catch (_) {
4660          try { window.posthog && posthog.capture('check_vessel_failed', { imo: imo, reason: 'invalid_json', status: r.status, surface: 'arcnautical-landing' }); } catch(_){}
4661          resultsEl.innerHTML = '<div style="padding:24px;color:var(--risk-high)">Check failed</div>';
4662          return false;
4663        }
4664        if (!r.ok || !data || data.error) {
4665          try { window.posthog && posthog.capture('check_vessel_failed', { imo: imo, reason: data && data.error ? 'not_found_or_error' : 'http_error', status: r.status, surface: 'arcnautical-landing' }); } catch(_){}
4666          resultsEl.innerHTML = '<div style="padding:24px;color:var(--risk-high)">' + escapeLandingHtml(data && data.error || 'Check failed') + '</div>';
4667          return false;
4668        }
4669        try { window.posthog && posthog.capture('check_vessel_succeeded', { imo: imo, sanctions_status: data.sanctions && data.sanctions.status, vetting_grade: data.vetting && data.vetting.grade, ownership_opacity: data.ownership && data.ownership.opacity, surface: 'arcnautical-landing' }); } catch(_){}
4670
4671        var sColor = data.sanctions.status === 'RED' ? 'var(--risk-crit)' : data.sanctions.status === 'AMBER' ? 'var(--risk-elev)' : data.sanctions.status === 'INCOMPLETE' ? '#6b7280' : 'var(--risk-low)';
4672        var oColor = data.ownership.opacity === 'HIGH' ? 'var(--risk-crit)' : data.ownership.opacity === 'MEDIUM' ? 'var(--risk-elev)' : 'var(--risk-low)';
4673        var gColor = 'AB'.indexOf(data.vetting.grade) >= 0 ? 'var(--risk-low)' : data.vetting.grade === 'C' ? 'var(--risk-elev)' : 'var(--risk-crit)';
4674
4675        resultsEl.innerHTML =
4676          '<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:16px;margin-bottom:28px;text-align:center">' +
4677            '<div style="background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:24px">' +
4678              '<div style="font-family:var(--mono);font-size:10px;color:var(--text-dim);text-transform:uppercase;letter-spacing:0.1em;margin-bottom:12px">Sanctions</div>' +
4679              '<div style="width:56px;height:56px;border-radius:50%;background:color-mix(in srgb, ' + sColor + ' 15%, transparent);border:2px solid ' + sColor + ';margin:0 auto 10px;display:flex;align-items:center;justify-content:center"><div style="width:20px;height:20px;border-radius:50%;background:' + sColor + '"></div></div>' +
4680              '<div style="font-size:1rem;font-weight:700;color:' + sColor + '">' + escapeLandingHtml(data.sanctions.status) + '</div>' +
4681              '<div style="font-size:0.7rem;color:var(--text-dim);margin-top:4px">' + escapeLandingHtml(data.sanctions.detail) + '</div>' +
4682            '</div>' +
4683            '<div style="background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:24px">' +
4684              '<div style="font-family:var(--mono);font-size:10px;color:var(--text-dim);text-transform:uppercase;letter-spacing:0.1em;margin-bottom:12px">Ownership Opacity</div>' +
4685              '<div style="font-size:2.2rem;font-weight:700;font-family:var(--mono);color:' + oColor + '">' + data.ownership.score + '</div>' +
4686              '<div style="font-size:0.8rem;color:' + oColor + ';margin-top:4px">' + escapeLandingHtml(data.ownership.opacity) + '</div>' +
4687            '</div>' +
4688            '<div style="background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:24px">' +
4689              '<div style="font-family:var(--mono);font-size:10px;color:var(--text-dim);text-transform:uppercase;letter-spacing:0.1em;margin-bottom:12px">Vetting Grade</div>' +
4690              '<div style="font-size:2.2rem;font-weight:700;font-family:var(--mono);color:' + gColor + '">' + escapeLandingHtml(data.vetting.grade) + '</div>' +
4691              '<div style="font-size:0.8rem;color:var(--text-dim);margin-top:4px">' + data.vetting.score + '/100 &middot; ' + escapeLandingHtml(data.vetting.status) + '</div>' +
4692            '</div>' +
4693          '</div>' +
4694          landingRenderCtas(data, imo);
4695      } catch (err) {
4696        // Reachable only after `r` is set (fetch failures return above), so this
4697        // is a parse/render bug in our own code, not the network.
4698        try {
4699          window.posthog && posthog.capture('check_vessel_failed', {
4700            imo: imo,
4701            reason: r ? 'render' : 'client',
4702            status: r ? r.status : 0,
4703            message: String((err && err.message) || err).slice(0, 200),
4704            surface: 'arcnautical-landing',
4705          });
4706        } catch(_){}
4707        resultsEl.innerHTML = '<div style="padding:24px;color:var(--risk-high)">Check failed. Please try again.</div>';
4708      } finally {
4709        btn.textContent = 'Check Vessel'; btn.disabled = false;
4710      }
4711      return false;
4712    }
4713
4714    function landingCtaProfile(data) {
4715      var sanctions = data && data.sanctions && data.sanctions.status;
4716      var grade = data && data.vetting && data.vetting.grade;
4717      var opacity = data && data.ownership && data.ownership.opacity;
4718      if (sanctions === 'RED' || sanctions === 'AMBER' || grade === 'D' || grade === 'E' || opacity === 'HIGH') return 'evidence';
4719      if (sanctions === 'GREEN' && (grade === 'A' || grade === 'B') && (opacity === 'LOW' || opacity === 'MEDIUM')) return 'watch';
4720      return 'mixed';
4721    }
4722
4723    function landingDossierCta(imo, profile, isSecondary) {
4724      var title = profile === 'evidence' ? 'Request reviewed source evidence' : 'Request the reviewed intelligence dossier';
4725      var body = profile === 'evidence'
4726        ? 'Sanctions match details, ownership chain, PSC records, and source evidence after manual review.'
4727        : 'Ownership chain, sanctions match details, PSC detention records, and PDF after manual review.';
4728      var button = profile === 'evidence' ? 'Request Reviewed Evidence' : 'Request Reviewed Dossier';
4729      return '<div id="landing-email-gate" style="background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:28px;text-align:center' + (isSecondary ? ';margin-top:16px' : '') + '">' +
4730        '<div style="font-family:var(--display);font-size:1.2rem;color:var(--text);margin-bottom:6px">' + title + '</div>' +
4731        '<div style="color:var(--text-sec);font-size:0.8rem;margin-bottom:16px">' + body + '</div>' +
4732        '<form onsubmit="return landingRequestDossier(event,\'' + imo + '\')" style="display:flex;gap:8px;max-width:420px;margin:0 auto;flex-wrap:wrap">' +
4733          '<input type="email" id="landing-lead-email" placeholder="Work email" required style="flex:1;min-width:190px;padding:12px 16px;background:var(--surface);border:1px solid var(--border);border-radius:4px;color:var(--text);font-size:14px;outline:none">' +
4734          '<button type="submit" id="landing-dossier-btn" data-default-label="' + button + '" class="btn-primary" style="padding:12px 20px;font-size:14px;cursor:pointer;border:none;white-space:nowrap">' + button + '</button>' +
4735        '</form>' +
4736      '</div>';
4737    }
4738
4739    function landingWatchCta(imo, isSecondary) {
4740      return '<div id="landing-watch-gate" style="background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:28px;text-align:center' + (isSecondary ? ';margin-top:16px' : '') + '">' +
4741        '<div style="font-family:var(--display);font-size:1.2rem;color:var(--text);margin-bottom:6px">Watch this vessel for changes</div>' +
4742        '<div style="color:var(--text-sec);font-size:0.8rem;margin-bottom:16px">Get an email if sanctions status, ownership opacity, or vetting grade changes.</div>' +
4743        '<form onsubmit="return landingWatchVessel(event,\'' + imo + '\')" style="display:flex;gap:8px;max-width:420px;margin:0 auto;flex-wrap:wrap">' +
4744          '<input type="email" id="landing-watch-email" placeholder="Work email" required style="flex:1;min-width:190px;padding:12px 16px;background:var(--surface);border:1px solid var(--border);border-radius:4px;color:var(--text);font-size:14px;outline:none">' +
4745          '<button type="submit" id="landing-watch-btn" class="btn-primary" style="padding:12px 20px;font-size:14px;cursor:pointer;border:none;white-space:nowrap">Watch Vessel</button>' +
4746        '</form>' +
4747      '</div>';
4748    }
4749
4750    function landingRenderCtas(data, imo) {
4751      var profile = landingCtaProfile(data);
4752      if (profile === 'watch') return landingWatchCta(imo, false) + landingDossierCta(imo, 'mixed', true);
4753      if (profile === 'mixed') return landingDossierCta(imo, 'mixed', false) + landingWatchCta(imo, true);
4754      return landingDossierCta(imo, 'evidence', false);
4755    }
4756
4757    async function landingRequestDossier(e, imo) {
4758      e.preventDefault();
4759      var email = document.getElementById('landing-lead-email').value.trim();
4760      var btn = document.getElementById('landing-dossier-btn');
4761      var defaultLabel = btn.getAttribute('data-default-label') || 'Request Reviewed Dossier';
4762      btn.textContent = 'Requesting...'; btn.disabled = true;
4763      try {
4764        if (window.posthog) {
4765          posthog.identify(window.arcBrowserId, { email: email, lead_source: 'landing_dossier_request' });
4766          posthog.capture('dossier_review_requested', { imo: imo, email: email });
4767        }
4768      } catch(_){}
4769      try {
4770        var resp = await fetch('/api/arcnautical/v1/public/request-dossier-link', {
4771          method: 'POST',
4772          headers: { 'Content-Type': 'application/json', 'X-Arc-Browser-Id': (window.arcBrowserId || '') },
4773          body: JSON.stringify({ email: email, imo: imo })
4774        });
4775        var data = {}; try { data = await resp.json(); } catch(_){}
4776        if (!resp.ok || !data.success) throw { status: resp.status, reason: (data && data.error) || 'request_failed' };
4777        btn.parentElement.parentElement.innerHTML =
4778          '<div style="padding:16px;background:rgba(22,163,74,0.1);border:1px solid rgba(22,163,74,0.3);border-radius:6px">' +
4779            '<div style="color:var(--risk-low);font-weight:600;margin-bottom:4px">Dossier review requested.</div>' +
4780            '<div style="color:var(--text-sec);font-size:0.85rem">I will review this IMO and email ' + escapeLandingHtml(email) + ' once the dossier is cleared for release.</div>' +
4781          '</div>';
4782      } catch (err) {
4783        try { window.posthog && posthog.capture('dossier_review_failed', { imo: imo, reason: err && err.reason || 'network', status: err && err.status || 0, surface: 'arcnautical-landing' }); } catch(_){}
4784        btn.textContent = defaultLabel; btn.disabled = false;
4785      }
4786      return false;
4787    }
4788
4789    async function landingWatchVessel(e, imo) {
4790      e.preventDefault();
4791      var email = document.getElementById('landing-watch-email').value.trim();
4792      var btn = document.getElementById('landing-watch-btn');
4793      btn.textContent = 'Sending...'; btn.disabled = true;
4794      try {
4795        if (window.posthog) {
4796          posthog.identify(window.arcBrowserId, { email: email, lead_source: 'landing_watch_request' });
4797          posthog.capture('watch_requested_client', { imo: imo, email: email });
4798        }
4799      } catch(_){}
4800      try {
4801        var resp = await fetch('/api/arcnautical/v1/public/watch-vessel', {
4802          method: 'POST',
4803          headers: { 'Content-Type': 'application/json', 'X-Arc-Browser-Id': (window.arcBrowserId || '') },
4804          body: JSON.stringify({ email: email, imo: imo })
4805        });
4806        var data = {}; try { data = await resp.json(); } catch(_){}
4807        if (!resp.ok || !data.success) throw { status: resp.status, reason: (data && data.error) || 'request_failed' };
4808        var already = data && data.status === 'already_watching';
4809        document.getElementById('landing-watch-gate').innerHTML =
4810          '<div style="padding:16px;background:rgba(22,163,74,0.1);border:1px solid rgba(22,163,74,0.3);border-radius:6px">' +
4811            '<div style="color:var(--risk-low);font-weight:600;margin-bottom:4px">' + (already ? 'Already watching this vessel.' : 'Almost there - confirm your watch.') + '</div>' +
4812            '<div style="color:var(--text-sec);font-size:0.85rem">' + (already ? 'You will get an email if its status changes.' : 'Check your inbox at ' + escapeLandingHtml(email) + ' and click the confirm link to activate it.') + '</div>' +
4813          '</div>';
4814      } catch (err) {
4815        try { window.posthog && posthog.capture('watch_request_failed', { imo: imo, reason: err && err.reason || 'network', status: err && err.status || 0, surface: 'arcnautical-landing' }); } catch(_){}
4816        btn.textContent = 'Watch Vessel'; btn.disabled = false;
4817      }
4818      return false;
4819    }
4820
4821    function escapeLandingHtml(str) {
4822      var div = document.createElement('div');
4823      div.appendChild(document.createTextNode(String(str || '')));
4824      return div.innerHTML;
4825    }
4826  </script>
vendor: 1 bytes, line 4826
4826
4827<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"1af6d678532a473c837804ef17df055d","r":1,"spa":2}' crossorigin="anonymous"></script>
4827
4828</body>
4829</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.