1 2 3 4 5<!DOCTYPE html> 6<html lang="en"> 7<head> 8 <meta charset="UTF-8"> 9 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 10 <title>TumiTrust - Portable Trust Infrastructure (PTI)</title> 11 12 13 14 15 16 <link rel="icon" type="image/x-icon" href="https://tumitrust.com/static/favicon.aad01b850f6f.ico?v=5" sizes="any"> 17 <link rel="shortcut icon" type="image/x-icon" href="https://tumitrust.com/static/favicon.aad01b850f6f.ico?v=5"> 18 <link rel="icon" type="image/svg+xml" href="https://tumitrust.com/static/favicon-bright.d34c929d63ac.svg?v=5"> 19 <link rel="icon" type="image/svg+xml" href="https://tumitrust.com/static/favicon-simple.78d788d341cb.svg?v=5"> 20 <link rel="icon" type="image/svg+xml" href="https://tumitrust.com/static/favicon.58fd00830344.svg?v=5" sizes="any"> 21 <link rel="apple-touch-icon" href="https://tumitrust.com/static/favicon.58fd00830344.svg?v=5"> 22 <link rel="manifest" href="https://tumitrust.com/static/manifest.9c66f0b33644.json"> 23 24 25 26 27 <!-- SEO Meta Tags --> 28 29 30 31 32
33<meta name="description" content="Portable trust infrastructure for emerging markets. People keep a trust record from community validation and verified activity. Institutions look it up with their consent."> 34<meta name="keywords" content="Portable Trust Infrastructure, PTI, TumiTrust, portable trust, trust infrastructure, peer endorsements, verified badges, multi-context trust, trust verification, trust network, financial inclusion Africa, emerging markets fintech, trust lookups, African fintech"> 35<meta name="author" content="TumiTrust"> 36<meta name="robots" content="index, follow"> 37 38<meta name="googlebot" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1"> 39<meta name="bingbot" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1"> 40 41 42<!-- Canonical URL --> 43 44<link rel="canonical" href="https://tumitrust.com/"> 45 46 47<!-- Open Graph Meta Tags --> 48<meta property="og:title" content="TumiTrust - Portable Trust Infrastructure (PTI)"> 49<meta property="og:description" content="Portable trust infrastru
49cture for emerging markets. People keep a trust record from community validation and verified activity. Institutions look it up with their consent."> 50 51<meta property="og:image" content="/static/images/tumitrust-og-image.jpg"> 52 53<meta property="og:image:width" content="1200"> 54<meta property="og:image:height" content="630"> 55<meta property="og:image:type" content="image/jpeg"> 56<meta property="og:image:alt" content="TumiTrust - Portable Trust Infrastructure for emerging markets"> 57<meta property="og:url" content="https://tumitrust.com/"> 58<meta property="og:type" content="website"> 59<meta property="og:site_name" content="TumiTrust"> 60<meta property="og:locale" content="en_US"> 61<meta property="og:locale:alternate" content="en_ZA"> 62<meta property="og:locale:alternate" content="en_KE"> 63<meta property="og:locale:alternate" content="en_NG"> 64<meta property="og:locale:alternate" content="en_GH"> 65<meta property="og:locale:alternate" content="en_ZW"> 66 67<!-- Twitter Card Meta Tags --> 68<meta name="twitter:card" content="summary_large_image"> 69<meta name="twitter:site" content="@tumitrust"> 70 71<meta name="twitter:creator" content="@tumitrust"> 72 73<meta name="twitter:title" content="TumiTrust - Portable Trust Infrastructure (PTI)"> 74<meta name="twitter:description" content="Portable trust infrastru
74cture for emerging markets. People keep a trust record from community validation and verified activity. Institutions look it up with their consent."> 75 76<meta name="twitter:image" content="/static/images/tumitrust-og-image.jpg"> 77 78<meta name="twitter:image:alt" content="TumiTrust - Portable Trust Infrastructure (PTI)"> 79 80<!-- Additional Meta Tags --> 81<meta name="viewport" content="width=device-width, initial-scale=1.0"> 82<meta name="theme-color" content="#FF8C00"> 83<meta name="msapplication-TileColor" content="#FF8C00"> 84 85<meta name="msapplication-TileImage" content="https://tumitrust.com/static/favicon-bright.d34c929d63ac.svg"> 86<meta name="msapplication-config" content="https://tumitrust.com/static/browserconfig.01340ae38fec.xml"> 87 88<meta name="format-detection" content="telephone=no"> 89<meta name="apple-mobile-web-app-capable" content="yes"> 90<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"> 91<meta name="apple-mobile-web-app-title" content="TumiTrust"> 92 93<!-- Hreflang for Internationalization --> 94 95 96<!-- Preconnect to External Domains for Performance --> 97<link rel="preconnect" href="https://fonts.googleapis.com"> 98<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 99<link rel="preconnect" href="https://www.google-analytics.com"> 100<link rel="preconnect" href="https://www.googletagmanager.com"> 101 102<!-- DNS Prefetch for Performance --> 103<link rel="dns-prefetch" href="//fonts.googleapis.com"> 104<link rel="dns-prefetch" href="//www.google-analytics.com"> 105<link rel="dns-prefetch" href="//www.googletagmanager.com"> 106 107<!-- Structured Data (JSON-LD) - Custom Schema if provided --> 108 109<!-- Default Schema.org Structured Data for Rich Snippets --> 110<meta name="generator" content="TumiTrust"> 111<meta name="rating" content="General"> 112<meta name="distribution" content="Global"> 113<meta name="language" content="en"> 114<meta name="geo.region" content="ZM"> 115<meta name="geo.country" content="Zambia"> 116<meta name="geo.placename" content="Lusaka"> 117<meta name="geo.position" content="-15.3875;28.3228"> 118<meta name="ICBM" content="-15.3875, 28.3228"> 119<meta name="coverage" content="Worldwide"> 120<meta name="target" content="all"> 121<meta name="audience" content="all"> 122<meta name="revisit-after" content="7 days"> 123<meta name="expires" content="never"> 124<meta name="copyright" content="TumiTrust"> 125<meta name="reply-to" content="[email protected]"> 126<meta name="owner" content="TumiTrust"> 127<meta name="url" content="https://tumitrust.com/"> 128<meta name="identifier-URL" content="https://tumitrust.com"> 129<meta name="category" content="Financial Technology, Portable Trust Infrastructure, Fintech, Trust Network"> 130<meta name="classification" content="Business, Finance, Technology, Social Network"> 131<meta name="subject" content="Portable Trust Infrastructure, Multi-Context Trust, Community Validation, Verified Activity, Financial Inclusion">
132<meta name="summary" content="Portable trust infrastructure for emerging markets. People keep a trust record. Institutions look it up with their consent."> 133<meta name="topic" content="Portable Trust Infrastructure, Community Trust, Financial Inclusion, TumiTrust"> 134<meta name="designer" content="TumiTrust Design Team"> 135<meta name="publisher" content="TumiTrust"> 136<meta name="contact" content="[email protected]"> 137<meta name="directory" content="submission"> 138<meta name="pagename" content="TumiTrust - Portable Trust Infrastructure (PTI)"> 139<meta name="HandheldFriendly" content="True"> 140<meta name="MobileOptimized" content="320"> 141<meta name="apple-itunes-app" content="app-id=6760616608"> 142<meta name="google-play-app" content="app-id=com.tumitrust.mobile"> 143
144<script type="application/ld+json"> 145{ 146 "@context": "https://schema.org", 147 "@type": "Organization", 148 "name": "TumiTrust", 149 "alternateName": "TumiTrust PTI", 150 "url": "https://tumitrust.com", 151 "logo": "https://tumitrust.com/static/img/logo.4cbf73b23224.svg", 152 "description": "Portable trust infrastructure for emerging markets. People keep a trust record from community validation and verified activity. Institutions look it up with their consent.", 153 "foundingDate": "2025", 154 "founders": [{ 155 "@type": "Person", 156 "name": "Alison Mukoma" 157 }], 158 "contactPoint": { 159 "@type": "ContactPoint", 160 "contactType": "Customer Support", 161 "email": "[email protected]", 162 "availableLanguage": ["en", "sw", "zu", "xh", "af"] 163 }, 164 "sameAs": [ 165 "https://twitter.com/tumitrust", 166 "https://facebook.com/tumitrust", 167 "https://linkedin.com/company/tumitrust" 168 ], 169 "areaServed": { 170 "@type": "Place", 171 "name": "Africa" 172 }, 173 "knowsAbout": [ 174 "Portable Trust Infrastructure", 175 "Portable trust", 176 "Multi-context trust", 177 "Community validation", 178 "Verified activity", 179 "Trust lookups", 180 "Financial Inclusion", 181 "Peer endorsements", 182 "Trust verification" 183 ] 184} 185</script>
vendor: 1 bytes, line 185
185
186<script type="application/ld+json"> 187{ 188 "@context": "https://schema.org", 189 "@type": "WebApplication", 190 "name": "TumiTrust", 191 "description": "TumiTrust on the web and in the app. People keep a trust record, share it, and let an institution look it up.", 192 "applicationCategory": "FinanceApplication", 193 "operatingSystem": "Web, iOS, Android", 194 "offers": { 195 "@type": "Offer", 196 "price": "0", 197 "priceCurrency": "USD" 198 } 199} 200</script>
200 201 202 203<!-- Additional SEO Meta Tags --> 204 205<!-- Security Headers (Note: X-Frame-Options must be set via HTTP headers, not meta tags) --> 206<meta http-equiv="X-Content-Type-Options" content="nosniff"> 207<meta http-equiv="X-XSS-Protection" content="1; mode=block"> 208<meta http-equiv="Referrer-Policy" content="strict-origin-when-cross-origin"> 209 210 211 <!-- Google Analytics 4 -->
vendor: 73 bytes, lines 211-213
211 212 213 <script async src="https://www.googletagmanager.com/gtag/js?id=
213G-XXXXXXXXXX
vendor: 16 bytes, lines 213-214
213"></script> 214
214<script> 215
vendor: 145 bytes, lines 215-218
215window.dataLayer = window.dataLayer || []; 216 function gtag(){dataLayer.push(arguments);} 217 gtag('js', new Date()); 218 gtag('config', '
218G-XXXXXXXXXX
vendor: 80 bytes, lines 218-222
218', { 219 'anonymize_ip': true, 220 'send_page_view': true 221 }); 222
222</script>
222 223 224 225 <!-- Google Tag Manager --> 226 227 228
229<script src="https://cdn.tailwindcss.com"></script>
vendor: 1 bytes, line 229
229
230<script> 231 tailwind.config = { 232 theme: { 233 extend: { 234 colors: { 235 'sunset-orange': '#ff6b35', 236 'golden-yellow': '#f7931e', 237 'earth-brown': '#8b4513', 238 'safari-green': '#228b22', 239 'ocean-blue': '#0066cc', 240 'sunrise-pink': '#ff69b4', 241 'desert-sand': '#f4e4bc', 242 'baobab-bark': '#654321', 243 'savanna-gold': '#daa520', 244 'kente-red': '#dc143c', 245 'kente-yellow': '#ffd700', 246 'kente-green': '#32cd32', 247 'kente-blue': '#4169e1', 248 'kente-purple': '#8a2be2', 249 'tech-cyan': '#00ffff', 250 'tech-magenta': '#ff00ff', 251 'tech-lime': '#00ff00', 252 'tech-orange': '#ff8c00', 253 'tech-purple': '#9370db', 254 'african-sunset': 'linear-gradient(135deg, #ff6b35, #f7931e, #ffd700)', 255 'savanna-dawn': 'linear-gradient(135deg, #ff69b4, #ff6b35, #f7931e)', 256 'ocean-horizon': 'linear-gradient(135deg, #0066cc, #00ffff, #32cd32)', 257 'kente-pride': 'linear-gradient(135deg, #dc143c, #ffd700, #32cd32, #4169e1)', 258 } 259 } 260 } 261 }; 262</script>
262 263<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" crossorigin="anonymous" referrerpolicy="no-referrer"> 264 265 266 267<!-- Google tag (gtag.js) - Google Analytics 4 -->
vendor: 64 bytes, lines 267-268
267 268<script async src="https://www.googletagmanager.com/gtag/js?id=
268G-8ZQYRMXQE7
vendor: 12 bytes, line 268
268"></script>
269<script> 270
vendor: 133 bytes, lines 270-273
270window.dataLayer = window.dataLayer || []; 271 function gtag(){dataLayer.push(arguments);} 272 gtag('js', new Date()); 273 gtag('config', '
273G-8ZQYRMXQE7
vendor: 4 bytes, line 273
273');
274</script>
274 275 276<!-- Google Search Console Verification (replace with real code from Search Console) --> 277<meta name="google-site-verification" content="YOUR_VERIFICATION_CODE_HERE" /> 278<meta name="tumitrust-landing-build" content="score-calc-v20260513-1000" /> 279 280<!-- Homepage-only: mobile app structured data (omit unverified aggregateRating) -->
281<script type="application/ld+json"> 282{ 283 "@context": "https://schema.org", 284 "@type": "SoftwareApplication", 285 "name": "TumiTrust", 286 "description": "Portable Trust Infrastructure (PTI) for emerging markets - portable proof people can carry from community validation and verified activity, with trust lookups whenever they authorize a decision. One platform for people, institutions, and partners.", 287 "operatingSystem": "iOS, Android", 288 "applicationCategory": "FinanceApplication", 289 "offers": { 290 "@type": "Offer", 291 "price": "0", 292 "priceCurrency": "USD" 293 } 294} 295</script>
295 296 297 298 <!-- PWA Configuration (manifest + icons in favicon_links.html) --> 299 <meta name="theme-color" content="#ff6b35"> 300 <meta name="apple-mobile-web-app-capable" content="yes"> 301 <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"> 302 <meta name="apple-mobile-web-app-title" content="TumiTrust"> 303 304 <!-- Dashboard CSS --> 305 <link rel="stylesheet" href="/static/core/css/dashboard.f184951e4655.css"> 306
307<script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
vendor: 1 bytes, line 307
307
308<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
vendor: 1 bytes, line 308
308
309<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/graphology.umd.min.js"></script>
vendor: 1 bytes, line 309
309
310<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/sigma.min.js"></script>
310 311 312 313 <!-- Custom CSS --> 314 <link rel="stylesheet" href="/static/core/css/main.19a2ba15a31b.css"> 315 <link rel="stylesheet" href="/static/core/css/careers.185e85e1aa7c.css"> 316 <link rel="stylesheet" href="/static/core/css/tt_site_nav.74ff8c858fa0.css?v=nav5"> 317 <link rel="stylesheet" href="/static/core/css/nav_account_menu.c9410c09ffe8.css?v=acct1"> 318 <link rel="stylesheet" href="/static/core/css/brand/tokens.1e153cea9a1e.css"> 319 <link rel="stylesheet" href="/static/core/css/brand/mesh.2e37d78cfe39.css?v=mesh2"> 320 <link rel="stylesheet" href="/static/core/css/brand/enterprise_hub.fef5c54b0e40.css?v=nav4"> 321 322 <style> 323 /* Firefox Compatibility Fixes - Global */ 324 @-moz-document url-prefix() { 325 /* Firefox-specific fixes */ 326 * { 327 -moz-box-sizing: border-box; 328 } 329 330 body { 331 -moz-font-feature-settings: "liga" on, "kern" on; 332 -moz-osx-font-smoothing: grayscale; 333 text-rendering: optimizeLegibility; 334 } 335 336 /* Ensure gradients work in Firefox */ 337 .gradient-text, 338 [class*="gradient"], 339 .holographic-text { 340 background: linear-gradient(135deg, #ff6600, #ffaa00); 341 -webkit-background-clip: text; 342 -moz-background-clip: text; 343 background-clip: text; 344 -webkit-text-fill-color: transparent; 345 color: #ffaa00; /* Fallback for Firefox */ 346 } 347 348 /* Firefox backdrop-filter fallbacks */ 349 [class*="backdrop-blur"], 350 [style*="backdrop-filter"], 351 .backdrop-blur-xl, 352 .backdrop-blur-sm {
353 background-color: rgba(30, 41, 59, 0.9) !important; 354 } 355 356 /* Firefox font loading */ 357 @font-face { 358 font-family: 'Inter'; 359 font-display: swap; 360 } 361 362 /* Ensure all text is visible in Firefox */ 363 h1, h2, h3, h4, h5, h6, 364 p, span, div, label, input, select, textarea, button, a { 365 text-rendering: optimizeLegibility; 366 -moz-font-feature-settings: "liga" on, "kern" on; 367 } 368 } 369 370 /* Cross-browser backdrop-filter support */ 371 @supports not (backdrop-filter: blur(10px)) { 372 [class*="backdrop-blur"], 373 .backdrop-blur-xl, 374 .backdrop-blur-sm, 375 [style*="backdrop-filter"] { 376 background-color: rgba(30, 41, 59, 0.9) !important; 377 } 378 } 379 380 /* Base Styles - Fallback */ 381 :root { 382 /* Ubuntu/African Color Palette */ 383 --neon-orange: #ff6600; 384 --neon-gold: #ffaa00; 385 --neon-amber: #fbbf24; 386 --neon-red: #dc143c; 387 /* Legacy support - map to Ubuntu colors */ 388 --neon-blue: #ffaa00; 389 --neon-purple: #ff6600; 390 --neon-pink: #fbbf24; 391 } 392 393 * { 394 box-sizing: border-box; 395 margin: 0; 396 padding: 0; 397 } 398 399 html { 400 overflow-x: hidden; 401 width: 100%; 402 max-width: 100vw; 403 } 404 405 body { 406 font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; 407 background: linear-gradient(135deg, #1e293b 0%, #334155 50%, #475569 100%); 408 background-attachment: fixed; 409 color: #e2e8f0; 410 min-height: 100vh; 411 position: relative; 412 overflow-x: hidden; 413 width: 100%; 414 max-width: 100vw; 415 /* Firefox font rendering */ 416 -moz-osx-font-smoothing: grayscale; 417 -webkit-font-smoothing: antialiased; 418 font-smoothing: antialiased; 419 text-rendering: optimizeLegibility; 420 } 421 422 * { 423 box-sizing: border-box; 424 } 425 426 body::before { 427 content: ''; 428 position: fixed; 429 top: 0; 430 left: 0; 431 width: 100%; 432 height: 100%; 433 background: 434 radial-gradient(circle at 20% 80%, rgba(255, 170, 0, 0.12) 0%, transparent 50%), 435 radial-gradient(circle at 80% 20%, rgba(255, 102, 0, 0.1) 0%, transparent 50%), 436 radial-gradient(circle at 40% 40%, rgba(220, 38, 38, 0.08) 0%, transparent 50%), 437 radial-gradient(circle at 60% 60%, rgba(234, 88, 12, 0.1) 0%, transparent 50%); 438 pointer-events: none; 439 z-index: 1; 440 animation: backgroundShift 20s ease-in-out infinite; 441 } 442 443 @keyframes backgroundShift { 444 0%, 100% { 445 background: 446 radial-gradient(circle at 20% 80%, rgba(255, 170, 0, 0.12) 0%, transparent 50%), 447 radial-gradient(circle at 80% 20%, rgba(255, 102, 0, 0.1) 0%, transparent 50%), 448 radial-gradient(circle at 40% 40%, rgba(220, 38, 38, 0.08) 0%, transparent 50%), 449 radial-gradient(circle at 60% 60%, rgba(234, 88, 12, 0.1) 0%, transparent 50%); 450 } 451 25% { 452 background: 453 radial-gradient(circle at 80% 20%, rgba(255, 170, 0, 0.12) 0%, transparent 50%), 454 radial-gradient(circle at 20% 80%, rgba(255, 102, 0, 0.1) 0%, transparent 50%), 455 radial-gradient(circle at 60% 60%, rgba(220, 38, 38, 0.08) 0%, transparent 50%), 456 radial-gradient(circle at 40% 40%, rgba(234, 88, 12, 0.1) 0%, transparent 50%); 457 } 458 50% { 459 background: 460 radial-gradient(circle at 40% 40%, rgba(255, 170, 0, 0.12) 0%, transparent 50%), 461 radial-gradient(circle at 60% 60%, rgba(255, 102, 0, 0.1) 0%, transparent 50%), 462 radial-gradient(circle at 20% 80%, rgba(220, 38, 38, 0.08) 0%, transparent 50%), 463 radial-gradient(circle at 80% 20%, rgba(234, 88, 12, 0.1) 0%, transparent 50%); 464 } 465 75% { 466 background: 467 radial-gradient(circle at 60% 60%, rgba(255, 170, 0, 0.12) 0%, transparent 50%), 468 radial-gradient(circle at 40% 40%, rgba(255, 102, 0, 0.1) 0%, transparent 50%), 469 radial-gradient(circle at 80% 20%, rgba(220, 38, 38, 0.08) 0%, transparent 50%), 470 radial-gradient(circle at 20% 80%, rgba(234, 88, 12, 0.1) 0%, transparent 50%); 471 } 472 } 473 474 /* Navbar pattern animation */ 475 @keyframes patternMove { 476 0% { transform: translate(0, 0); } 477 100% { transform: translate(30px, 30px); } 478 } 479 480 .container { 481 max-width: 1200px; 482 margin: 0 auto; 483 padding: 0 1rem; 484 } 485 486 /* Additional Base Template Styles */ 487 .footer { 488 background: #f8fafc; 489 border-top: 1px solid #e2e8f0; 490 } 491 492 .footer a:hover { 493 color: #ff6b35; 494 } 495 496 /* Navigation Styles */ 497 nav { 498 background: rgba(248, 250, 252, 0.95); 499 backdrop-filter: blur(20px); 500 border-bottom: 1px solid rgba(255, 107, 53, 0.3); 501 position: sticky; 502 top: 0; 503 z-index: 9999 !important; 504 box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); 505 } 506 507 .nav-link { 508 color: #1e293b; 509 text-decoration: none; 510 padding: 0.5rem 1rem; 511 border-radius: 0.5rem; 512 transition: all 0.3s ease; 513 position: relative; 514 overflow: hidden; 515 } 516 517 .nav-link::before { 518 content: ''; 519 position: absolute; 520 top: 0; 521 left: -100%; 522 width: 100%; 523 height: 100%; 524 background: linear-gradient(90deg, transparent, rgba(255, 107, 53, 0.2), transparent); 525 transition: left 0.5s; 526 } 527 528 .nav-link:hover::before { 529 left: 100%; 530 } 531 532 .nav-link:hover { 533 color: #ff6b35; 534 background: rgba(255, 107, 53, 0.1); 535 transform: translateY(-2px); 536 } 537 538 /* Button Styles */ 539 .btn { 540 display: inline-flex; 541 align-items: center; 542 justify-content: center; 543 padding: 0.5rem 1rem; 544 font-size: 0.875rem; 545 font-weight: 500; 546 border: 1px solid transparent; 547 border-radius: 0.375rem; 548 cursor: pointer; 549 transition: all 0.3s ease; 550 text-decoration: none; 551 } 552 553 .btn-primary { 554 background: linear-gradient(135deg, #00d4ff, #0099cc); 555 color: white; 556 border-color: #00d4ff; 557 } 558 559 .btn-primary:hover { 560 background: linear-gradient(135deg, #0099cc, #00d4ff); 561 transform: translateY(-1px); 562 box-shadow: 0 4px 12px rgba(0, 212, 255, 0.3); 563 } 564 565 .btn-secondary { 566 background: #f1f5f9; 567 color: #334155; 568 border-color: #cbd5e1; 569 } 570 571 .btn-secondary:hover { 572 background: #e2e8f0; 573 transform: translateY(-1px); 574 } 575 576 /* Card Styles */ 577 .card { 578 background: #ffffff; 579 border: 1px solid #e2e8f0; 580 border-radius: 0.5rem; 581 box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); 582 overflow: hidden; 583 transition: all 0.3s ease; 584 } 585 586 .card:hover { 587 box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); 588 transform: translateY(-2px); 589 } 590 591 .card-header { 592 padding: 1rem; 593 border-bottom: 1px solid #e2e8f0; 594 background: linear-gradient(135deg, rgba(0, 212, 255, 0.05), rgba(139, 92, 246, 0.05)); 595 } 596 597 .card-body { 598 padding: 1rem; 599 } 600 601 /* Grid Styles */ 602 .grid { 603 display: grid; 604 gap: 1rem; 605 } 606 607 .grid-cols-1 { grid-template-columns: repeat(1, minmax(0, 1fr)); } 608 .grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } 609 .grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } 610 .grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } 611 612 @media (min-width: 768px) { 613 .md\\:grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } 614 .md\\:grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } 615 .md\\:grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } 616 } 617 618 @media (min-width: 1024px) { 619 .lg\\:grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } 620 .lg\\:grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } 621 .lg\\:grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } 622 } 623 624 /* Flexbox Utilities */ 625 .flex { display: flex; } 626 .items-center { align-items: center; } 627 .justify-between { justify-content: space-between; } 628 .justify-center { justify-content: center; } 629 .space-x-2 > * + * { margin-left: 0.5rem; } 630 .space-x-4 > * + * { margin-left: 1rem; } 631 .space-x-6 > * + * { margin-left: 1.5rem; } 632 633 /* Spacing */ 634 .p-4 { padding: 1rem; } 635 .px-4 { padding-left: 1rem; padding-right: 1rem; } 636 .py-2 { padding-top: 0.5rem; padding-bottom: 0.5rem; } 637 .py-8 { padding-top: 2rem; padding-bottom: 2rem; } 638 .mb-2 { margin-bottom: 0.5rem; } 639 .mb-4 { margin-bottom: 1rem; } 640 .mb-8 { margin-bottom: 2rem; } 641 .mt-4 { margin-top: 1rem; } 642 643 /* Text Styles */ 644 .text-xl { font-size: 1.25rem; } 645 .text-2xl { font-size: 1.5rem; } 646 .text-3xl { font-size: 1.875rem; } 647 .text-4xl { font-size: 2.25rem; } 648 .font-bold { font-weight: 700; } 649 .font-semibold { font-weight: 600; } 650 .text-white { color: #f1f5f9; } 651 .text-secondary { color: #94a3b8; } 652 .text-center { text-align: center; } 653 654 /* Additional Utilities */ 655 .hidden { display: none; } 656 .block { display: block; } 657 .inline-block { display: inline-block; } 658 .w-full { width: 100%; } 659 .h-full { height: 100%; } 660 .min-h-screen { min-height: 100vh; } 661 .flex-1 { flex: 1; } 662 .gap-2 { gap: 0.5rem; } 663 .gap-3 { gap: 0.75rem; } 664 .gap-4 { gap: 1rem; } 665 .gap-6 { gap: 1.5rem; } 666 .gap-8 { gap: 2rem; } 667 .rounded { border-radius: 0.375rem; } 668 .rounded-lg { border-radius: 0.5rem; } 669 .rounded-full { border-radius: 9999px; } 670 .shadow-md { box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); } 671 .shadow-lg { box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); } 672 .transition { transition: all 0.3s ease; } 673 .hover\\:text-white:hover { color: #f1f5f9; } 674 .hover\\:bg-dark-surface-2:hover { background: #334155; } 675 676 /* Table Styles */ 677 .table { 678 width: 100%; 679 border-collapse: collapse; 680 background: #1e293b; 681 border-radius: 0.5rem; 682 overflow: hidden; 683 } 684 685 .table th, 686 .table td { 687 padding: 0.75rem; 688 text-align: left; 689 border-bottom: 1px solid #475569; 690 } 691 692 .table th { 693 background: #334155; 694 font-weight: 600; 695 color: #f1f5f9; 696 font-size: 0.875rem; 697 } 698 699 .table tbody tr:hover { 700 background: rgba(0, 212, 255, 0.05); 701 } 702 703 /* Badge Styles */ 704 .badge { 705 display: inline-flex; 706 align-items: center; 707 padding: 0.25rem 0.5rem; 708 font-size: 0.75rem; 709 font-weight: 500; 710 border-radius: 9999px; 711 text-transform: uppercase; 712 } 713 714 /* Ubuntu/African Theme Colors */ 715 .bg-primary { 716 background: linear-gradient(135deg, #ff6600 0%, #ffaa00 100%); 717 color: white; 718 } 719 .bg-secondary { 720 background: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%); 721 color: white; 722 } 723 .bg-success { 724 background: linear-gradient(135deg, #10b981 0%, #059669 100%); 725 color: white; 726 } 727 .bg-warning { 728 background: linear-gradient(135deg, #f59e0b 0%, #fb923c 100%); 729 color: white; 730 } 731 .bg-danger { 732 background: linear-gradient(135deg, #dc143c 0%, #b91c1c 100%); 733 color: white; 734 } 735 736 /* Responsive */ 737 @media (max-width: 768px) { 738 .md\\:hidden { display: none; } 739 .md\\:grid-cols-2 { grid-template-columns: repeat(1, minmax(0, 1fr)); } 740 .md\\:grid-cols-3 { grid-template-columns: repeat(1, minmax(0, 1fr)); } 741 .md\\:grid-cols-4 { grid-template-columns: repeat(1, minmax(0, 1fr)); } 742 } 743 744 @media (max-width: 1024px) { 745 .lg\\:grid-cols-2 { grid-template-columns: repeat(1, minmax(0, 1fr)); } 746 .lg\\:grid-cols-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); } 747 .lg\\:grid-cols-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } 748 .lg\\:grid-cols-5 { grid-template-columns: repeat(2, minmax(0, 1fr)); } 749 } 750 751 /* Floating Particles */ 752 .particles { 753 position: fixed; 754 top: 0; 755 left: 0; 756 width: 100%; 757 height: 100%; 758 z-index: -1; 759 overflow: hidden; 760 pointer-events: none; 761 } 762 763 /* === STUNNING BACKGROUND EFFECTS (Global) === */
764 /* Hexagon Grid Background */ 765 .hex-grid-bg { 766 position: fixed; 767 inset: 0; 768 background-image: 769 linear-gradient(30deg, transparent 48%, rgba(255, 140, 0, 0.03) 48%, rgba(255, 140, 0, 0.03) 52%, transparent 52%), 770 linear-gradient(150deg, transparent 48%, rgba(218, 165, 32, 0.03) 48%, rgba(218, 165, 32, 0.03) 52%, transparent 52%), 771 linear-gradient(90deg, transparent 48%, rgba(205, 133, 63, 0.03) 48%, rgba(205, 133, 63, 0.03) 52%, transparent 52%); 772 background-size: 80px 138px; 773 animation: hexMove 25s linear infinite; 774 z-index: 0; 775 pointer-events: none; 776 } 777 778 @keyframes hexMove { 779 0% { transform: translate(0, 0); } 780 100% { transform: translate(80px, 138px); } 781 } 782 783 /* Energy Rings */ 784 .energy-ring-bg { 785 position: fixed; 786 border-radius: 50%; 787 border: 2px solid rgba(255, 140, 0, 0.15); 788 animation: energyPulse 5s ease-out infinite; 789 z-index: 0; 790 pointer-events: none; 791 } 792 793 @keyframes energyPulse { 794 0% { 795 transform: scale(0.5); 796 opacity: 1; 797 } 798 100% { 799 transform: scale(2.5); 800 opacity: 0; 801 } 802 } 803 804 /* Particle System */ 805 .particles-bg { 806 position: fixed; 807 inset: 0; 808 pointer-events: none; 809 overflow: hidden; 810 z-index: 0; 811 } 812 813 .particle-bg { 814 position: absolute; 815 width: 3px; 816 height: 3px; 817 background: rgba(255, 140, 0, 0.4); 818 border-radius: 50%; 819 box-shadow: 0 0 10px rgba(255, 140, 0, 0.6); 820 top: -10px; 821 animation: particleFall 10s linear infinite; 822 } 823 824 @keyframes particleFall { 825 0% { 826 transform: translateY(-10px); 827 opacity: 1; 828 } 829 100% { 830 transform: translateY(calc(100vh + 10px)); 831 opacity: 0; 832 } 833 } 834 835 836 @keyframes scan { 837 0% { 838 transform: translateY(0); 839 opacity: 0.8; 840 } 841 100% { 842 transform: translateY(100vh); 843 opacity: 0.2; 844 } 845 } 846 847 /* Glassmorphic Enhancement for Cards - Firefox Compatible */ 848 .analytics-card { 849 -webkit-backdrop-filter: blur(12px); 850 -moz-backdrop-filter: blur(12px); 851 backdrop-filter: blur(12px); 852 } 853 854 /* Accessibility: Reduce motion for users who prefer it */ 855 @media (prefers-reduced-motion: reduce) { 856 .hex-grid-bg, 857 .energy-ring-bg, 858 .particle-bg, 859 .scan-line-bg { 860 animation: none !important; 861 } 862 } 863 864 /* Mobile Optimization - Clean Approach */ 865 @media (max-width: 768px) { 866 /* Ensure viewport is properly set */ 867 html { 868 -webkit-text-size-adjust: 100%; 869 -ms-text-size-adjust: 100%; 870 } 871 872 /* Touch-friendly interactive elements */ 873 button, 874 a, 875 input[type="button"], 876 input[type="submit"], 877 .btn, 878 .clickable { 879 min-height: 44px; 880 min-width: 44px; 881 font-size: 16px; 882 } 883 884 /* Prevent iOS zoom on input focus */ 885 input, 886 select, 887 textarea { 888 font-size: 16px !important; 889 } 890 891 /* Remove any top gaps on mobile */ 892 body { 893 margin: 0 !important; 894 padding: 0 !important; 895 } 896 897 /* Navbar sticky positioning */ 898 nav { 899 position: -webkit-sticky !important; 900 position: sticky !important; 901 top: 0 !important; 902 width: 100vw !important; 903 max-width: 100vw !important; 904 z-index: 9999 !important; 905 } 906 907 .hex-grid-bg { 908 background-size: 50px 86px; 909 } 910 911 .energy-ring-bg { 912 display: none; 913 } 914 915 .particle-bg { 916 width: 2px; 917 height: 2px; 918 } 919 920 /* Footer mobile adjustments */ 921 footer .max-w-7xl { 922 padding-left: 1.5rem !important; 923 padding-right: 1.5rem !important; 924 } 925 926 footer .grid { 927 padding-left: 0.5rem !important; 928 padding-right: 0.5rem !important; 929 } 930 931 footer .space-y-4, 932 footer ul { 933 padding-left: 0.5rem !important; 934 } 935 936 /* Center footer content on mobile */ 937 footer h3 { 938 text-align: left; 939 padding-left: 0; 940 } 941 942 footer .text-sm, 943 footer .text-gray-400 { 944 text-align: center; 945 padding-left: 1rem; 946 padding-right: 1rem; 947 } 948 949 /* Status banner mobile */ 950 #footer-status-link { 951 margin-left: 1rem !important; 952 margin-right: 1rem !important; 953 max-width: calc(100vw - 2rem) !important; 954 } 955 956 /* Logo - smaller on mobile */ 957 nav .flex > a > div:last-child > div:last-child { 958 display: none !important; /* Hide tagline */ 959 } 960 961 /* Profile button - adjusted for mobile */ 962 button.btn-profile { 963 padding: 0.5rem 1rem !important; 964 } 965 966 /* Network status indicator */ 967 button.btn-profile > div.relative, 968 button.btn-profile > div.relative > div { 969 overflow: visible !important; 970 } 971 972 /* Mobile menu */ 973 .mobile-menu { 974 padding: 1rem !important; 975 } 976
977 /* Prevent all content overflow on mobile - but not navbar elements */ 978 main { 979 max-width: 100vw !important; 980 overflow-x: hidden !important; 981 } 982 983 section { 984 max-width: 100vw !important; 985 } 986 987 .container { 988 max-width: 100vw !important; 989 } 990 } 991 992 @keyframes float { 993 0%, 100% { transform: translateY(100vh) scale(0); opacity: 0; } 994 10% { opacity: 1; } 995 90% { opacity: 1; } 996 100% { transform: translateY(-100px) scale(1); opacity: 0; } 997 } 998 999 /* Icon Pulse Animation */ 1000 .icon-pulse { 1001 animation: iconPulse 2s ease-in-out infinite; 1002 } 1003 1004 @keyframes iconPulse { 1005 0%, 100% { transform: scale(1); opacity: 1; } 1006 50% { transform: scale(1.1); opacity: 0.8; } 1007 } 1008 1009 /* Gradient Text */ 1010 .gradient-text { 1011 background: linear-gradient(135deg, var(--neon-blue), var(--neon-purple)); 1012 -webkit-background-clip: text; 1013 -webkit-text-fill-color: transparent; 1014 background-clip: text; 1015 } 1016 1017 /* Glass Effect */ 1018 .glass-effect { 1019 background: rgba(255, 255, 255, 0.1); 1020 backdrop-filter: blur(10px); 1021 border: 1px solid rgba(255, 255, 255, 0.2); 1022 } 1023 1024 /* Neon Glow */ 1025 .neon-glow { 1026 box-shadow: 0 0 20px rgba(0, 212, 255, 0.3); 1027 } 1028 1029 @keyframes gridMove { 1030 0% { transform: translate(0, 0); } 1031 100% { transform: translate(50px, 50px); } 1032 } 1033 1034 /* Futuristic text effects - Ubuntu/African colors */ 1035 .tech-text { 1036 background: linear-gradient(45deg, #ff6600, #ffaa00, #fbbf24, #dc143c); 1037 background-size: 400% 400%; 1038 -webkit-background-clip: text; 1039 -webkit-text-fill-color: transparent; 1040 background-clip: text; 1041 animation: techGradient 3s ease infinite; 1042 } 1043 1044 @keyframes techGradient { 1045 0% { background-position: 0% 50%; } 1046 50% { background-position: 100% 50%; } 1047 100% { background-position: 0% 50%; } 1048 } 1049 1050 /* Footer Brand Gradient Animation */ 1051 @keyframes gradientShift { 1052 0% { background-position: 0% 50%; } 1053 50% { background-position: 100% 50%; } 1054 100% { background-position: 0% 50%; } 1055 } 1056 1057 /* Gentle Float Animation for Logo */ 1058 @keyframes gentleFloat {
1059 0%, 100% { transform: translateY(0px) rotate(0deg); } 1060 50% { transform: translateY(-5px) rotate(2deg); } 1061 } 1062 1063 /* Improve text readability on dark backgrounds */ 1064 .text-gray-600 { 1065 color: #d1d5db !important; 1066 } 1067 1068 .text-gray-700 { 1069 color: #e5e7eb !important; 1070 } 1071 1072 .text-gray-800 { 1073 color: #f3f4f6 !important; 1074 } 1075 1076 .text-gray-900 { 1077 color: #ffffff !important; 1078 } 1079 1080 /* Card styling - Ubuntu/African Theme */ 1081 .card { 1082 background: linear-gradient(135deg, rgba(58, 36, 26, 0.9) 0%, rgba(68, 44, 32, 0.9) 100%) !important; 1083 backdrop-filter: blur(10px) !important; 1084 border: 2px solid rgba(255, 170, 0, 0.3) !important; 1085 color: #e5e7eb !important; 1086 box-shadow: 0 4px 20px rgba(255, 102, 0, 0.15) !important; 1087 border-radius: 1rem !important; 1088 } 1089 1090 .card-header { 1091 background: linear-gradient(135deg, rgba(255, 102, 0, 0.1) 0%, rgba(255, 170, 0, 0.1) 100%) !important; 1092 border-bottom: 2px solid rgba(255, 170, 0, 0.3) !important; 1093 color: #fbbf24 !important; 1094 font-weight: 700 !important; 1095 padding: 1rem 1.5rem !important; 1096 } 1097 1098 .card-body { 1099 color: #d1d5db !important; 1100 padding: 1.5rem !important; 1101 } 1102 1103 .card:hover { 1104 border-color: rgba(255, 170, 0, 0.5) !important; 1105 box-shadow: 0 8px 30px rgba(255, 102, 0, 0.25) !important; 1106 transform: translateY(-2px); 1107 transition: all 0.3s ease; 1108 } 1109 1110 /* Global Button Styles - Ubuntu/African Theme */ 1111 .btn, button:not(.unstyled), input[type="submit"], input[type="button"] { 1112 position: relative; 1113 overflow: hidden; 1114 font-weight: 600; 1115 border-radius: 0.75rem; 1116 padding: 0.75rem 1.5rem; 1117 transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); 1118 border: 2px solid transparent; 1119 } 1120 1121 .btn::before, button:not(.unstyled)::before { 1122 content: ''; 1123 position: absolute; 1124 inset: 0; 1125 background: linear-gradient(135deg, rgba(255, 255, 255, 0.2) 0%, transparent 50%); 1126 transform: translateX(-100%); 1127 transition: transform 0.6s; 1128 } 1129 1130 .btn:hover::before, button:not(.unstyled):hover::before { 1131 transform: translateX(100%); 1132 } 1133 1134 /* Nav auth CTAs - solid enough to read on dark chrome (esp. mobile) */ 1135 .btn-primary, .btn.btn-primary { 1136 background: linear-gradient(135deg, #e95420 0%, #f79500 100%); 1137 color: #ffffff; 1138 border: 1.5px solid rgba(255, 184, 77, 0.55); 1139 box-shadow: 0 2px 10px rgba(233, 84, 32, 0.35); 1140 font-weight: 700; 1141 font-size: 0.875rem; 1142 padding: 0.625rem 1.25rem; 1143 position: relative; 1144 overflow: hidden; 1145 } 1146 1147 .btn-primary::before { 1148 content: ''; 1149 position: absolute; 1150 top: 0; 1151 left: -100%; 1152 width: 100%; 1153 height: 100%; 1154 background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); 1155 transition: left 0.6s ease; 1156 } 1157 1158 .btn-primary:hover::before { 1159 left: 100%; 1160 } 1161 1162 .btn-primary:hover { 1163 background: linear-gradient(135deg, #f06430 0%, #ffaa22 100%); 1164 border-color: rgba(255, 200, 100, 0.75); 1165 box-shadow: 0 4px 16px rgba(233, 84, 32, 0.45); 1166 transform: translateY(-1px); 1167 color: #ffffff; 1168 } 1169 1170 .btn-secondary, .btn.btn-secondary { 1171 background: rgba(255, 255, 255, 0.08); 1172 color: #ffffff; 1173 border: 1.5px solid rgba(255, 255, 255, 0.35); 1174 backdrop-filter: blur(10px); 1175 box-shadow: none; 1176 font-weight: 600; 1177 font-size: 0.875rem; 1178 padding: 0.625rem 1.25rem; 1179 position: relative; 1180 overflow: hidden; 1181 } 1182 1183 .btn-secondary::before { 1184 content: ''; 1185 position: absolute; 1186 top: 0; 1187 left: -100%; 1188 width: 100%; 1189 height: 100%; 1190 background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent); 1191 transition: left 0.6s ease; 1192 } 1193 1194 .btn-secondary:hover::before { 1195 left: 100%; 1196 } 1197 1198 .btn-secondary:hover { 1199 background: rgba(255, 255, 255, 0.14); 1200 border-color: rgba(255, 255, 255, 0.5); 1201 color: #ffffff; 1202 } 1203 1204 .tt-nav-auth-compact { 1205 padding: 0.45rem 0.75rem !important; 1206 font-size: 0.8125rem !important; 1207 white-space: nowrap; 1208 } 1209 1210 .btn-success, .btn.btn-success { 1211 background: linear-gradient(135deg, #10b981 0%, #059669 100%); 1212 color: white; 1213 border-color: #10b981; 1214 box-shadow: 0 4px 15px rgba(16, 185, 129, 0.3); 1215 } 1216 1217 .btn-success:hover { 1218 box-shadow: 0 6px 25px rgba(16, 185, 129, 0.5); 1219 transform: translateY(-2px); 1220 } 1221 1222 .btn-danger, .btn.btn-danger { 1223 background: linear-gradient(135deg, #dc143c 0%, #b91c1c 100%); 1224 color: white; 1225 border-color: #dc143c; 1226 box-shadow: 0 4px 15px rgba(220, 20, 60, 0.3); 1227 } 1228 1229 .btn-danger:hover { 1230 box-shadow: 0 6px 25px rgba(220, 20, 60, 0.5); 1231 transform: translateY(-2px); 1232 } 1233 1234 .btn-warning, .btn.btn-warning { 1235 background: linear-gradient(135deg, #f59e0b 0%, #fb923c 100%); 1236 color: white; 1237 border-color: #f59e0b; 1238 box-shadow: 0 4px 15px rgba(245, 158, 11, 0.3); 1239 } 1240 1241 .btn-warning:hover { 1242 box-shadow: 0 6px 25px rgba(245, 158, 11, 0.5); 1243 transform: translateY(-2px); 1244 } 1245 1246 .btn-outline { 1247 background: transparent; 1248 border: 2px solid #ffaa00; 1249 color: #ffaa00; 1250 } 1251 1252 .btn-outline:hover { 1253 background: linear-gradient(135deg, #ff6600 0%, #ffaa00 100%); 1254 color: white; 1255 border-color: #ff6600; 1256 } 1257 1258 /* Form Elements - Ubuntu/African Theme */ 1259 input[type="text"], input[type="email"], input[type="password"], 1260 input[type="number"], input[type="tel"], input[type="url"], 1261 input[type="date"], input[type="time"], input[type="datetime-local"], 1262 select, textarea { 1263 background: rgba(58, 36, 26, 0.5) !important; 1264 border: 2px solid rgba(255, 170, 0, 0.3) !important; 1265 color: #e5e7eb !important; 1266 border-radius: 0.75rem !important; 1267 padding: 0.75rem 1rem !important; 1268 transition: all 0.3s ease !important; 1269 } 1270 1271 input:focus, select:focus, textarea:focus { 1272 outline: none !important; 1273 border-color: #ffaa00 !important; 1274 box-shadow: 0 0 0 3px rgba(255, 170, 0, 0.1) !important; 1275 background: rgba(58, 36, 26, 0.7) !important; 1276 } 1277 1278 input::placeholder, textarea::placeholder { 1279 color: #9ca3af !important; 1280 } 1281 1282 /* Table Styles - Ubuntu/African Theme */ 1283 table { 1284 background: linear-gradient(135deg, rgba(58, 36, 26, 0.9) 0%, rgba(68, 44, 32, 0.9) 100%); 1285 border-radius: 1rem; 1286 overflow: hidden; 1287 } 1288 1289 th { 1290 background: linear-gradient(135deg, rgba(255, 102, 0, 0.2) 0%, rgba(255, 170, 0, 0.2) 100%); 1291 color: #fbbf24; 1292 font-weight: 700; 1293 padding: 1rem; 1294 border-bottom: 2px solid rgba(255, 170, 0, 0.3); 1295 } 1296 1297 td { 1298 color: #d1d5db; 1299 padding: 0.75rem 1rem; 1300 border-bottom: 1px solid rgba(255, 170, 0, 0.1); 1301 } 1302 1303 tr:hover { 1304 background: rgba(255, 170, 0, 0.05); 1305 } 1306 1307 /* Dropdown menus - clean slate (exclude enterprise marketing nav) */ 1308 .dropdown-menu, [class*="dropdown"]:not(.tt-ent-nav-dropdown) > div[class*="absolute"] { 1309 background: linear-gradient(180deg, rgba(30, 41, 59,
13090.98) 0%, rgba(15, 23, 42, 0.98) 100%) !important; 1310 backdrop-filter: blur(18px) !important; 1311 border: 1px solid rgba(148, 163, 184, 0.16) !important; 1312 border-radius: 0.85rem !important; 1313 box-shadow: 0 18px 40px -20px rgba(2, 6, 23, 0.65) !important; 1314 } 1315 1316 .dropdown-item, [class*="dropdown"]:not(.tt-ent-nav-dropdown) a { 1317 color: #cbd5e1 !important; 1318 transition: background 0.15s ease, color 0.15s ease !important; 1319 padding: 0.65rem 0.85rem !important; 1320 } 1321 1322 .dropdown-item:hover, [class*="dropdown"]:not(.tt-ent-nav-dropdown) a:hover { 1323 background: rgba(247, 149, 0, 0.12) !important; 1324 color: #fff7ed !important; 1325 } 1326 1327 /* Badge Styles - Ubuntu/African Theme */ 1328 .badge, span[class*="badge"] { 1329 background: linear-gradient(135deg, #ff6600 0%, #ffaa00 100%); 1330 color: white; 1331 padding: 0.25rem 0.75rem; 1332 border-radius: 9999px; 1333 font-weight: 600; 1334 font-size: 0.75rem; 1335 } 1336 1337 .badge-success { 1338 background: linear-gradient(135deg, #10b981 0%, #059669 100%); 1339 } 1340 1341 .badge-danger { 1342 background: linear-gradient(135deg, #dc143c 0%, #b91c1c 100%); 1343 } 1344 1345 .badge-warning { 1346 background: linear-gradient(135deg, #f59e0b 0%, #fb923c 100%); 1347 } 1348 1349 /* Modal/Dialog Styles - Ubuntu/African Theme */ 1350 .modal, [role="dialog"] { 1351 background: linear-gradient(135deg, rgba(58, 36, 26, 0.95) 0%, rgba(68, 44, 32, 0.95) 100%) !important; 1352 backdrop-filter: blur(20px) !important; 1353 border: 2px solid rgba(255, 170, 0, 0.3) !important; 1354 border-radius: 1.5rem !important; 1355 box-shadow: 0 20px 60px rgba(255, 102, 0, 0.4) !important; 1356 } 1357
1358 .modal-header { 1359 border-bottom: 2px solid rgba(255, 170, 0, 0.3) !important; 1360 color: #fbbf24 !important; 1361 } 1362 1363 .modal-footer { 1364 border-top: 2px solid rgba(255, 170, 0, 0.3) !important; 1365 } 1366 1367 /* Alert Styles - Ubuntu/African Theme */ 1368 .alert { 1369 border-radius: 1rem; 1370 padding: 1rem 1.5rem; 1371 border: 2px solid; 1372 backdrop-filter: blur(10px); 1373 } 1374 1375 .alert-success { 1376 background: rgba(16, 185, 129, 0.1); 1377 border-color: rgba(16, 185, 129, 0.5); 1378 color: #10b981; 1379 } 1380 1381 .alert-danger, .alert-error { 1382 background: rgba(220, 20, 60, 0.1); 1383 border-color: rgba(220, 20, 60, 0.5); 1384 color: #dc143c; 1385 } 1386 1387 .alert-warning { 1388 background: rgba(245, 158, 11, 0.1); 1389 border-color: rgba(245, 158, 11, 0.5); 1390 color: #f59e0b; 1391 } 1392 1393 .alert-info { 1394 background: rgba(255, 170, 0, 0.1); 1395 border-color: rgba(255, 170, 0, 0.5); 1396 color: #ffaa00; 1397 } 1398 1399 /* Dashboard Widget Styles */ 1400 .widget, .stat-card, [class*="stats"] { 1401 background: linear-gradient(135deg, rgba(58, 36, 26, 0.9) 0%, rgba(68, 44, 32, 0.9) 100%); 1402 backdrop-filter: blur(10px); 1403 border: 2px solid rgba(255, 170, 0, 0.3); 1404 border-radius: 1rem; 1405 padding: 1.5rem; 1406 transition: all 0.3s ease; 1407 } 1408 1409 .widget:hover, .stat-card:hover { 1410 border-color: rgba(255, 170, 0, 0.5); 1411 box-shadow: 0 8px 30px rgba(255, 102, 0, 0.25); 1412 transform: translateY(-2px); 1413 } 1414 1415 /* Progress Bar - Ubuntu/African Theme */ 1416 .progress { 1417 background: rgba(58, 36, 26, 0.5); 1418 border-radius: 9999px; 1419 overflow: hidden; 1420 height: 0.75rem; 1421 } 1422 1423 .progress-bar { 1424 background: linear-gradient(90deg, #ff6600 0%, #ffaa00 100%); 1425 border-radius: 9999px; 1426 transition: width 0.6s ease; 1427 } 1428 1429 /* Scrollbar - Ubuntu/African Theme */ 1430 ::-webkit-scrollbar {
1431 width: 12px; 1432 height: 12px; 1433 } 1434 1435 ::-webkit-scrollbar-track { 1436 background: rgba(58, 36, 26, 0.3); 1437 border-radius: 6px; 1438 } 1439 1440 ::-webkit-scrollbar-thumb { 1441 background: linear-gradient(135deg, #ff6600 0%, #ffaa00 100%); 1442 border-radius: 6px; 1443 border: 2px solid rgba(58, 36, 26, 0.3); 1444 } 1445 1446 ::-webkit-scrollbar-thumb:hover { 1447 background: linear-gradient(135deg, #ffaa00 0%, #fbbf24 100%); 1448 } 1449 </style> 1450 1451 <!-- PWA Service Worker Registration --> 1452
1452<script> 1453 // Service Worker temporarily disabled to avoid caching issues 1454 // if ('serviceWorker' in navigator) { 1455 // window.addEventListener('load', function() { 1456 // navigator.serviceWorker.register('/sw.js') 1457 // .then(function(registration) { 1458 // console.log('ServiceWorker registered:', registration.scope); 1459 // }) 1460 // .catch(function(error) { 1461 // console.error('ServiceWorker registration failed:', error); 1462 // }); 1463 // }); 1464 // } 1465 </script>
1465 1466</head> 1467<body class="min-h-screen flex flex-col"> 1468 <!-- Google Tag Manager (noscript) --> 1469 1470 1471 <!-- Stunning Background Effects (Global) --> 1472 <div class="hex-grid-bg"></div> 1473 <div class="energy-ring-bg" style="width: 300px; height: 300px; top: 10%; left: 5%;"></div> 1474 <div class="energy-ring-bg" style="width: 400px; height: 400px; top: 50%; right: 10%; animation-delay: 1.5s;"></div> 1475 <div class="energy-ring-bg" style="width: 250px; height: 250px; bottom: 15%; left: 50%; animation-delay: 0.7s;"></div> 1476 1477 <!-- Particle System --> 1478 <div class="particles-bg"> 1479 <div class="particle-bg" style="left: 10%; animation-delay: 0s;"></div> 1480 <div class="particle-bg" style="left: 25%; animation-delay: 1s;"></div> 1481 <div class="particle-bg" style="left: 40%; animation-delay: 2s;"></div> 1482 <div class="particle-bg" style="left: 60%; animation-delay: 1.5s;"></div> 1483 <div class="particle-bg" style="left: 75%; animation-delay: 0.5s;"></div> 1484 <div class="particle-bg" style="left: 90%; animation-delay: 2.5s;"></div> 1485 </div> 1486 1487 <!-- Navigation - Streamlined & Beautiful --> 1488 <div id="tt-site-nav-spacer" class="tt-site-nav-spacer" aria-hidden="true"></div> 1489 <nav id="tt-site-nav" data-nav-hide-on-scroll class="bg-gradient-to-r from-gray-900/95 via-gray-800/95 to-gray-900/95 backdrop-blur-xl border-b border-amber-500/20 shadow-2xl tt-site-nav--fixed"> 1490 <!-- Animated background pattern --> 1491 <div class="absolute inset-0 opacity-5 pointer-events-none" style="background-image: url('data:image/svg+xml,%3Csvg width="60" height="60" viewBox="0 0 60 60" xmlns="http://www.w3.org/2000/svg"%3E%3Cpath d="M30 0l30 30-30 30L0 30z" fill="%23FFF" fill-opacity="0.1"/%3E%3C/svg%3E'); background-size: 30px 30px; animation: patternMove 30s linear infinite;"></div> 1492 1493 <!-- Subtle gradient glow --> 1494 <div class="absolute bottom-0 left-0 right-0 h-px bg-gradient-to-r from-transparent via-amber-500/50 to-transparent"></div> 1495 1496 <div class="container mx-auto px-6 relative" style="z-index: 10000 !important;"> 1497 <div class="flex items-center justify-between h-16"> 1498 <!-- Brand - Refined --> 1499 <a href="/" class="flex items-center space-x-2 sm:space-x-3 text-white hover:opacity-90 transition-all duration-300 group min-w-0 flex-1 md:flex-none pr-3"> 1500 <div class="relative shrink-0"> 1501 <!-- Animated glow ring --> 1502 <div class="absolute inset-0 rounded-full bg-gradient-to-r from-orange-500/20 via-amber-500/20 to-yellow-500/20 blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-300 animate-pulse"></div> 1503 <div class="relative w-11 h-11 sm:w-16 sm:h-16 flex items-center justify-center group-hover:scale-110 transition-transform duration-300"> 1504 <img src="/static/img/logo-dark.d5385145e919.svg?v=clean" alt="TumiTrust Logo" class="w-full h-full object-contain"> 1505 </div> 1506 </div> 1507 <div class="min-w-0"> 1508 <div class="text-sm font-bold bg-gradient-to-r from-amber-400 via-orange-400 to-amber-400 bg-clip-text text-transparent truncate"> 1509 TumiTrust 1510 </div> 1511 <div class="text-[9px] text-amber-500/80 font-medium -mt-0.5 tracking-wider truncate hidden xs:block sm:block">Portable Trust Infrastructure · PTI</div> 1512 </div> 1513 </a> 1514 1515 <!-- Desktop Navigation - Streamlined --> 1516 <div class="hidden md:flex items-center space-x-2"> 1517 1518<link rel="stylesheet" href="/static/core/css/brand/tokens.1e153cea9a1e.css"> 1519<link rel="stylesheet" href="/static/core/css/brand/enterprise_hub.fef5c54b0e40.css?v=nav3"> 1520 1521<!-- Enterprise marketing nav (anonymous + supplement for authenticated) --> 1522<div class="tt-enterprise-nav-links hidden md:flex items-center space-x-1"> 1523 <div class="tt-ent-nav-dropdown"> 1524 <a href="/docs/pti/introduction/" class="tt-ent-nav-dropdown__trigger px-3 py-2 rounded-lg text-gray-300 hover:text-white hover:bg-white/10 transition-all text-sm font-medium flex items-center gap-1"> 1525 PTI <i class="fas fa-chevron-down text-[10px] opacity-60"></i> 1526 </a> 1527 <div class="tt-ent-nav-dropdown__panel"> 1528 <a href="/docs/pti/why-pti"><i class="fas fa-lightbulb"></i> Why PTI</a> 1529 <a href="/docs/pti/introduction/"><i class="fas fa-book"></i> What is PTI</a> 1530 <a href="/docs/pti/specification/v1.0/"><i class="fas fa-file-contract"></i> Specification v1.0</a> 1531 <a href="/docs/pti/reference-architecture/"><i class="fas fa-sitemap"></i> Reference architecture</a> 1532 <a href="/docs/pti/specification/v1.0/security"><i class="fas fa-shield-halved"></i> Security & privacy</a> 1533 <a href="/docs/pti/governance/"><i class="fas fa-scale-balanced"></i> Governance</a> 1534 <a href="/docs/pti/origin/"><i class="fas fa-landmark"></i> Origin & stewardship</a> 1535 <a href="/docs/pti/comparisons/"><i class="fas fa-balance-scale"></i> How PTI compares</a> 1536 </div> 1537 </div> 1538 <div class="tt-ent-nav-dropdown"> 1539 <a href="/platform/" class="tt-ent-nav-dropdown__trigger px-3 py-2 rounded-lg text-gray-300 hover:text-white hover:bg-white/10 transition-all text-sm font-medium flex items-center gap-1"> 1540 TumiTrust <i class="fas fa-chevron-down text-[10px] opacity-60"></i> 1541 </a> 1542 <div class="tt-ent-nav-dropdown__panel"> 1543 <a href="/platform/"><i class="fas fa-layer-group"></i> Platform overview</a> 1544 <a href="/docs/tumitrust/product-overview/"><i class="fas fa-info-circle"></i> Product documentation</a> 1545 <a href="/docs/tumitrust/platform/screening-services"><i class="fas fa-shield-alt"></i> Screening services</a> 1546 <a href="/docs/tumitrust/platform/trust-platform-overview"><i class="fas fa-brain"></i> Trust intelligence</a> 1547 <a href="/docs/tumitrust/developer-guides/trust-platform-api"><i class="fas fa-plug"></i> Trust platform API</a>
1548 <a href="/docs/tumitrust/audiences/for-partners"><i class="fas fa-handshake"></i> Partner ecosystem</a> 1549 </div> 1550 </div> 1551 <div class="tt-ent-nav-dropdown"> 1552 <a href="/solutions/" class="tt-ent-nav-dropdown__trigger px-3 py-2 rounded-lg text-gray-300 hover:text-white hover:bg-white/10 transition-all text-sm font-medium flex items-center gap-1"> 1553 Solutions <i class="fas fa-chevron-down text-[10px] opacity-60"></i> 1554 </a> 1555 <div class="tt-ent-nav-dropdown__panel"> 1556 <a href="/docs/tumitrust/solutions/financial-services"><i class="fas fa-coins"></i> Financial services</a> 1557 <a href="/docs/tumitrust/platform/screening-services"><i class="fas fa-user-shield"></i> Screening services</a> 1558 <a href="/docs/tumitrust/solutions/insurance"><i class="fas fa-shield-alt"></i> Insurance</a> 1559 <a href="/docs/tumitrust/solutions/telecom"><i class="fas fa-broadcast-tower"></i> Telecom</a> 1560 <a href="/docs/tumitrust/solutions/employment"><i class="fas fa-briefcase"></i> Employment</a> 1561 <a href="/docs/tumitrust/solutions/commerce"><i class="fas fa-store"></i> Commerce</a> 1562 <a href="/docs/tumitrust/solutions/government"><i class="fas fa-landmark"></i> Government</a> 1563 <a href="/docs/tumitrust/solutions/housing"><i class="fas fa-home"></i> Housing</a> 1564 <a href="/docs/tumitrust/solutions/education"><i class="fas fa-graduation-cap"></i> Education</a> 1565 <a href="/docs/tumitrust/solutions/agriculture"><i class="fas fa-seedling"></i> Agriculture</a> 1566 </div> 1567 </div> 1568 <div class="tt-ent-nav-dropdown"> 1569 <a href="/developers/" class="tt-ent-nav-dropdown__trigger px-3 py-2 rounded-lg text-gray-300 hover:text-white hover:bg-white/10 transition-all text-sm font-medium flex items-center gap-1"> 1570 Developers <i class="fas fa-chevron-down text-[10px] opacity-60"></i> 1571 </a> 1572 <div class="tt-ent-nav-dropdown__panel"> 1573 <a href="/developers/"><i class="fas fa-code"></i> Developers hub</a> 1574 <a href="/docs/"><i class="fas fa-book"></i> Documentation</a> 1575 <a href="/docs/tumitrust/platform/screening-services"><i class="fas fa-shield-alt"></i> Screening services</a> 1576 <a href="/docs/tumitrust/developer-guides/trust-platform-api"><i class="fas fa-plug"></i> Trust platform API</a> 1577 <a href="/docs/pti/build-your-pti/"><i class="fas fa-hammer"></i> Build your own PTI</a> 1578 1579 </div> 1580 </div> 1581 <div class="tt-ent-nav-dropdown"> 1582 <a href="/company/" class="tt-ent-nav-dropdown__trigger px-3 py-2 rounded-lg text-gray-300 hover:text-white hover:bg-white/10 transition-all text-sm font-medium flex items-center gap-1"> 1583 Company <i class="fas fa-chevron-down text-[10px] opacity-60"></i> 1584 </a> 1585 <div class="tt-ent-nav-dropdown__panel"> 1586 <a href="/company/"><i class="fas fa-info-circle"></i> About</a> 1587 <a href="/docs/pti/why-pti"><i class="fas fa-compass"></i> Vision</a> 1588 <a href="/careers/"><i class="fas fa-users"></i> Careers</a> 1589 <a href="/docs/tumitrust/product-overview/get-started"><i class="fas fa-rocket"></i> Get started</a> 1590 <a href="mailto:[email protected]"><i class="fas fa-envelope"></i> Contact</a> 1591 </div> 1592 </div> 1593</div> 1594 1595 1596 1597 <a href="/docs/" class="px-3 py-2 rounded-lg text-gray-300 hover:text-white hover:bg-white/10 border border-white/15 transition-all duration-200 flex items-center space-x-2"> 1598 <i class="fas fa-book text-sm"></i> 1599 <span class="text-sm font-medium">Docs</span> 1600 </a> 1601 <a href="/login/" class="btn btn-primary"> 1602 <i class="fas fa-sign-in-alt mr-2"></i>Login 1603 </a> 1604 1605 <a href="/register/" class="btn btn-secondary"> 1606 <i class="fas fa-user-plus mr-2"></i>Register 1607 </a> 1608 1609 1610 1611 </div> 1612 1613 <!-- Mobile: menu only - Login/Register live in the drawer below --> 1614 <div class="md:hidden flex items-center shrink-0"> 1615 <button type="button" class="text-white hover:text-amber-300 p-2.5 rounded-lg hover:bg-white/10 transition-colors border border-white/25" data-tt
1615-nav-toggle onclick="toggleMobileMenu()" aria-controls="mobileMenu" aria-expanded="false" aria-label="Open menu"> 1616 <i class="fas fa-bars text-xl" aria-hidden="true"></i> 1617 </button> 1618 </div> 1619 </div> 1620 1621 <!-- Mobile Navigation --> 1622 <div id="mobileMenu" class="hidden md:hidden py-4 border-t border-dark-border"> 1623 1624 1625 <div class="flex flex-col gap-2 mb-3"> 1626 <a href="/login/" class="btn btn-primary w-full justify-center"> 1627 <i class="fas fa-sign-in-alt mr-2"></i>Login 1628 </a> 1629 1630 <a href="/register/" class="btn btn-secondary w-full justify-center"> 1631 <i class="fas fa-user-plus mr-2"></i>Register 1632 </a> 1633 1634 </div> 1635 <div class="border-t border-amber-500/20 mb-3" role="separator"></div> 1636 1637 1638 1639<!-- Mobile enterprise nav - public-safe PTI + TumiTrust core --> 1640<div class="tt-enterprise-nav-mobile space-y-1 pb-1"> 1641 <p class="text-[10px] uppercase tracking-wider text-amber-500/80 px-1 mb-1 font-semibold">Explore</p> 1642 <p class="text-[10px] uppercase tracking-wider text-gray-500 px-1 mb-1">Portable Trust</p> 1643 <a href="/docs/pti/why-pti" class="block py-1.5 text-sm text-amber-200 hover:text-white font-medium">Why PTI</a> 1644 <a href="/docs/pti/introduction/" class="block py-1.5 text-sm text-gray-300 hover:text-white">What is PTI</a> 1645 <a href="/docs/pti/specification/v1.0/" class="block py-1.5 text-sm text-gray-300 hover:text-white">Specification v1.0</a> 1646 <a href="/docs/pti/origin/" class="block py-1.5 text-sm text-gray-300 hover:text-white">Origin & stewardship</a> 1647 <p class="text-[10px] uppercase tracking-wider text-gray-500 px-1 mb-1 mt-2">Platform</p> 1648 <a href="/platform/" class="block py-1.5 text-sm text-gray-300 hover:text-white">Platform overview</a> 1649 <a href="/docs/" class="block py-1.5 text-sm text-gray-300 hover:text-white">Documentation</a> 1650 <a href="/docs/tumitrust/platform/screening-services" class="block py-1.5 text-sm text-gray-300 hover:text-white">Screening services</a> 1651 <p class="text-[10px] uppercase tracking-wider text-gray-500 px-1 mb-1 mt-2">Solutions</p> 1652 <a href="/solutions/" class="block py-1.5 text-sm text-gray-300 hover:text-white">All solutions</a> 1653 <a href="/docs/tumitrust/solutions/financial-services" class="block py-1.5 text-sm text-gray-300 hover:text-white">Financial services</a> 1654 <p class="text-[10px] uppercase tracking-wider text-gray-500 px-1 mb-1 mt-2">Company</p> 1655 <a href="/company/" class="block py-1.5 text-sm text-gray-300 hover:text-white">Company</a> 1656 <a href="/help/" class="block py-1.5 text-sm text-gray-300 hover:text-white">Help</a> 1657 <a href="/careers/" class="block py-1.5 text-sm text-gray-300 hover:text-white">Careers</a> 1658</div> 1659 1660 <div class="border-t border-amber-500/20 my-3" role="separator"></div> 1661 1662 </div> 1663 </div> 1664 </nav> 1665 1666 <!-- Main Content --> 1667 <main class="flex-1"> 1668 <!-- Messages --> 1669 1670 1671 <!-- Debug Mode Warning --> 1672 1673 1674 <!-- Page Content --> 1675 1676 1677 1678<!-- BACKGROUND ANIMATIONS - Fixed position, always visible as you scroll --> 1679<div style="position: fixed; inset: 0; pointer-events: none; z-index: 1;"> 1680<!-- Network Canvas - Interconnected Nodes --> 1681 <canvas id="networkCanvas" style="position: fixed; inset: 0; width: 100%; height: 100%;"></canvas> 1682 1683 <!-- Network darkening overlay for depth --> 1684 <div class="network-overlay"></div> 1685 1686 1687<!-- Energy Rings --> 1688<div class="energy-ring" style="width: 300px; height: 300px; left: 10%; top: 20%;"></div> 1689<div class="energy-ring" style="width: 400px; height: 400px; right: 10%; top: 40%; animation-delay: 1s;"></div> 1690<div class="energy-ring" style="width: 250px; height: 250px; left: 50%; bottom: 20%; animation-delay: 2s;"></div> 1691 1692<!-- Starfield - Beautiful Twinkling Stars --> 1693 <div class="starfield" style="position: fixed; inset: 0; width: 100%; height: 100%;"> 1694 <!-- Small Stars (50 stars) --> 1695 <div class="star small" style="left: 5%; top: 10%; animation-delay: 0s;"></div> 1696 <div class="star small" style="left: 12%; top: 25%; animation-delay: 0.5s;"></div> 1697 <div class="star small" style="left: 18%; top: 45%; animation-delay: 1s;"></div> 1698 <div class="star small" style="left: 25%; top: 15%; animation-delay: 1.5s;"></div> 1699 <div class="star small" style="left: 32%; top: 35%; animation-delay: 2s;"></div> 1700 <div class="star small" style="left: 38%; top: 55%; animation-delay: 0.3s;"></div> 1701 <div class="star small" style="left: 45%; top: 20%; animation-delay: 0.8s;"></div> 1702 <div class="star small" style="left: 52%; top: 40%; animation-delay: 1.3s;"></div> 1703 <div class="star small" style="left: 58%; top: 60%; animation-delay: 1.8s;"></div> 1704 <div class="star small" style="left: 65%; top: 25%; animation-delay: 2.3s;"></div> 1705 <div class="star small" style="left: 72%; top: 45%; animation-delay: 0.6s;"></div> 1706 <div class="star small" style="left: 78%; top: 65%; animation-delay: 1.1s;"></div> 1707 <div class="star small" style="left: 85%; top: 30%; animation-delay: 1.6s;"></div> 1708 <div class="star small" style="left: 92%; top: 50%; animation-delay: 2.1s;"></div> 1709 <div class="star small" style="left: 8%; top: 70%; animation-delay: 0.4s;"></div> 1710 <div class="star small" style="left: 15%; top: 80%; animation-delay: 0.9s;"></div> 1711 <div class="star small" style="left: 22%; top: 60%; animation-delay: 1.4s;"></div> 1712 <div class="star small" style="left: 28%; top: 75%; animation-delay: 1.9s;"></div> 1713 <div class="star small" style="left: 35%; top: 85%; animation-delay: 2.4s;"></div> 1714 <div class="star small" style="left: 42%; top: 70%; animation-delay: 0.2s;"></div> 1715 <div class="star small" style="left: 48%; top: 80%; animation-delay: 0.7s;"></div> 1716 <div class="star small" style="left: 55%; top: 90%; animation-delay: 1.2s;"></div> 1717 <div class="star small" style="left: 62%; top: 75%; animation-delay: 1.7s;"></div> 1718 <div class="star small" style="left: 68%; top: 85%; animation-delay: 2.2s;"></div> 1719 <div class="star small" style="left: 75%; top: 95%; animation-delay: 0.5s;"></div> 1720 <div class="star small" style="left: 82%; top: 80%; animation-delay: 1s;"></div> 1721 <div class="star small" style="left: 88%; top: 90%; animation-delay: 1.5s;"></div> 1722 <div class="star small" style="left: 95%; top: 70%; animation-delay: 2s;"></div> 1723 <div class="star small" style="left: 10%; top: 5%; animation-delay: 0.1s;"></div> 1724 <div class="star small" style="left: 20%; top: 8%; animation-delay: 0.6s;"></div> 1725 <div class="star small" style="left: 30%; top: 12%; animation-delay: 1.1s;"></div> 1726 <div class="star small" style="left: 40%; top: 18%; animation-delay: 1.6s;"></div> 1727 <div class="star small" style="left: 50%; top: 22%; animation-delay: 2.1s;"></div> 1728 <div class="star small" style="left: 60%; top: 28%; animation-delay: 0.3s;"></div> 1729 <div class="star small" style="left: 70%; top: 32%; animation-delay: 0.8s;"></div> 1730 <div class="star small" style="left: 80%; top: 38%; animation-delay: 1.3s;"></div> 1731 <div class="star small" style="left: 90%; top: 42%; animation-delay: 1.8s;"></div> 1732 <div class="star small" style="left: 13%; top: 48%; animation-delay: 2.3s;"></div> 1733 <div class="star small" style="left: 23%; top: 52%; animation-delay: 0.4s;"></div> 1734 <div class="star small" style="left: 33%; top: 58%; animation-delay: 0.9s;"></div> 1735 <div class="star small" style="left: 43%; top: 62%; animation-delay: 1.4s;"></div> 1736 <div class="star small" style="left: 53%; top: 68%; animation-delay: 1.9s;"></div> 1737 <div class="star small" style="left: 63%; top: 72%; animation-delay: 2.4s;"></div> 1738 <div class="star small" style="left: 73%; top: 78%; animation-delay: 0.2s;"></div> 1739 <div class="star small" style="left: 83%; top: 82%; animation-delay: 0.7s;"></div> 1740 <div class="star small" style="left: 93%; top: 88%; animation-delay: 1.2s;"></div> 1741 <div class="star small" style="left: 7%; top: 92%; animation-delay: 1.7s;"></div> 1742 <div class="star small" style="left: 17%; top: 95%; animation-delay: 2.2s;"></div> 1743 <div class="star small" style="left: 27%; top: 3%; animation-delay: 0.5s;"></div> 1744 <div class="star small" style="left: 37%; top: 7%; animation-delay: 1s;"></div> 1745 <div class="star small" style="left: 47%; top: 13%; animation-delay: 1.5s;"></div> 1746 1747 <!-- Medium Stars (20 stars) --> 1748 <div class="star medium" style="left: 8%; top: 15%; animation-delay: 0s;"></div> 1749 <div class="star medium" style="left: 20%; top: 30%; animation-delay: 0.7s;"></div> 1750 <div class="star medium" style="left: 35%; top: 50%; animation-delay: 1.4s;"></div> 1751 <div class="star medium" style="left: 50%; top: 35%; animation-delay: 2.1s;"></div> 1752 <div class="star medium" style="left: 65%; top: 55%; animation-delay: 0.3s;"></div> 1753 <div class="star medium" style="left: 80%; top: 25%; animation-delay: 1s;"></div> 1754 <div class="star medium" style="left: 15%; top: 65%; animation-delay: 1.7s;"></div> 1755 <div class="star medium" style="left: 30%; top: 80%; animation-delay: 2.4s;"></div> 1756 <div class="star medium" style="left: 45%; top: 70%; animation-delay: 0.5s;"></div> 1757 <div class="star medium" style="left: 60%; top: 85%; animation-delay: 1.2s;"></div> 1758 <div class="star medium" style="left: 75%; top: 75%; animation-delay: 1.9s;"></div> 1759 <div class="star medium" style="left: 90%; top: 60%; animation-delay: 0.2s;"></div> 1760 <div class="star medium" style="left: 12%; top: 40%; animation-delay: 0.9s;"></div> 1761 <div class="star medium" style="left: 25%; top: 20%; animation-delay: 1.6s;"></div> 1762 <div class="star medium" style="left: 40%; top: 45%; animation-delay: 2.3s;"></div> 1763 <div class="star medium" style="left: 55%; top: 10%; animation-delay: 0.4s;"></div> 1764 <div class="star medium" style="left: 70%; top: 50%; animation-delay: 1.1s;"></div> 1765 <div class="star medium" style="left: 85%; top: 70%; animation-delay: 1.8s;"></div> 1766 <div class="star medium" style="left: 95%; top: 35%; animation-delay: 2.5s;"></div> 1767 <div class="star medium" style="left: 5%; top: 90%; animation-delay: 0.6s;"></div> 1768 1769 <!-- Large Stars (10 stars) --> 1770 <div class="star large" style="left: 10%; top: 20%; animation-delay: 0s;"></div> 1771 <div class="star large" style="left: 30%; top: 40%; animation-delay: 1s;"></div> 1772 <div class="star large" style="left: 50%; top: 60%; animation-delay: 2s;"></div> 1773 <div class="star large" style="left: 70%; top: 30%; animation-delay: 0.5s;"></div> 1774 <div class="star large" style="left: 90%; top: 50%; animation-delay: 1.5s;"></div> 1775 <div class="star large" style="left: 20%; top: 75%; animation-delay: 0.8s;"></div> 1776 <div class="star large" style="left: 40%; top: 85%; animation-delay: 1.8s;"></div> 1777 <div class="star large" style="left: 60%; top: 15%; animation-delay: 0.3s;"></div> 1778 <div class="star large" style="left: 80%; top: 65%; animation-delay: 1.3s;"></div> 1779 <div class="star large" style="left: 15%; top: 55%; animation-delay: 2.3s;"></div> 1780 </div> 1781 1782<!-- Meteors - Falling from the Sky --> 1783 <div class="meteor-shower" style="position: fixed; inset: 0; width: 100%; height: 100%;"> 1784 <!-- Fast Meteors --> 1785 <div class="meteor fast" style="left: 10%; animation-delay: 0s;"></div> 1786 <div class="meteor fast" style="left: 30%; animation-delay: 3s;"></div> 1787 <div class="meteor fast" style="left: 50%; animation-delay: 6s;"></div> 1788 <div class="meteor fast" style="left: 70%; animation-delay: 9s;"></div> 1789 <div class="meteor fast" style="left: 90%; animation-delay: 12s;"></div> 1790 1791 <!-- Medium Meteors --> 1792 <div class="meteor medium" style="left: 20%; animation-delay: 1s;"></div> 1793 <div class="meteor medium" style="left: 40%; animation-delay: 4s;"></div> 1794 <div class="meteor medium" style="left: 60%; animation-delay: 7s;"></div> 1795 <div class="meteor medium" style="left: 80%; animation-delay: 10s;"></div> 1796 <div class="meteor medium" style="left: 15%; animation-delay: 13s;"></div> 1797 1798 <!-- Slow Meteors --> 1799 <div class="meteor slow" style="left: 25%; animation-delay: 2s;"></div> 1800 <div class="meteor slow" style="left: 45%; animation-delay: 5s;"></div> 1801 <div class="meteor slow" style="left: 65%; animation-delay: 8s;"></div> 1802 <div class="meteor slow" style="left: 85%; animation-delay: 11s;"></div> 1803 <div class="meteor slow" style="left: 5%; animation-delay: 14s;"></div> 1804</div> 1805 1806<!-- Data Streams --> 1807<div class="data-stream" style="left: 10%; animation-delay: 0s;"></div> 1808<div class="data-stream" style="left: 30%; animation-delay: 1s;"></div> 1809<div class="data-stream" style="left: 50%; animation-delay: 2s;"></div> 1810<div class="data-stream" style="left: 70%; animation-delay: 1.5s;"></div> 1811<div class="data-stream" style="left: 90%; animation-delay: 0.5s;"></div> 1812</div> 1813 1814<!-- Dynamic Docs URL Helper -->
1815<script> 1816 /** 1817 * Construct documentation URL using nginx routing. 1818 * All documentation is accessible through /docs/ path (no port needed). 1819 * 1820 * @param {string} path - Documentation path (e.g., '/intro/quick-start') 1821 * @returns {string} Full documentation URL 1822 */ 1823 function getDocsUrl(path) { 1824 // Always use /docs/ path routed through nginx 1825 // Works in both development and production 1826 // No port needed - nginx handles routing on port 80/443 1827 1828 // Ensure path starts with / 1829 if (!path.startsWith('/')) { 1830 path = '/' + path; 1831 } 1832 1833 // Return nginx-routed docs URL 1834 return `/docs${path}`; 1835 } 1836 1837 /** 1838 * Path mapping for redirecting old/invalid paths to correct docs locations. 1839 * Maps deprecated or moved documentation paths to their current locations. 1840 */ 1841 const docsPathMap = { 1842 '/backend/api-reference/overview': '/pti/introduction/', 1843 '/backend/api-reference/endorsement-api': '/tumitrust/audiences/for-institutions', 1844 '/backend/api-reference/mobile-money-upload': '/pti/introduction/', 1845 '/guides/integration/badge-system': '/tumitrust/audiences/for-institutions', 1846 '/backend/services/credit-score-engine': '/pti/introduction/', 1847 '/backend/services/neo4j-integration': '/pti/introduction/', 1848 '/intro/what-is-tumitrust': '/pti/introduction/', 1849 '/pti/introduction/key-concepts': '/pti/introduction/', 1850 '/intro/quick-start': '/tumitrust/product-overview/get-started', 1851 '/tumitrust/product-overview/get-started-mobile': '/tumitrust/product-overview/get-started', 1852 '/pti/glossary/': '/pti/glossary/', 1853 '/tumitrust/faq': '/tumitrust/faq', 1854 '/ubuntu-philosophy/trust-contexts': '/tumitrust/platform/partner-trust-contexts', 1855 '/ubuntu-philosophy/pti/introduction': '/pti/introduction/', 1856 '/tumitrust/developer-guides/trust-platform-api': '/tumitrust/developer-guides/trust-platform-api', 1857 '/guides/integration/institution-api-integration': '/tumitrust/developer-guides/trust-platform-api', 1858 '/guides/public/trust-report-verification': '/tumitrust/audiences/for-institutions', 1859 '/guides/public/organizations-on-tumitrust': '/tumitrust/audiences/for-institutions', 1860 '/tumitrust/audiences/for-individuals': '/tumitrust/audiences/for-individuals', 1861 '/guides/users/trust-network-guide': '/pti/introduction/', 1862 '/intro/what-is-tumitrust?_highlight=techn#technology-stack': '/pti/introduction/' 1863 }; 1864 1865 /** 1866 * Initialize documentation links on page load. 1867 * Updates all links to use nginx routing instead of direct ports. 1868 */ 1869 document.addEventListener('DOMContentLoaded', function() { 1870 // Find all links that point to old documentation URLs 1871 // Matches: localhost:3002, localhost:3000, :3002, :3000, or direct docs references 1872 const docsLinks = document.querySelectorAll( 1873 'a[href*="localhost:3002"], a[href*="localhost:3000"], ' + 1874 'a[href*=":3002"], a[href*=":3000"], ' + 1875 'a[data-docs-link="true"]' 1876 ); 1877 1878 docsLinks.forEach(link => { 1879 const href = link.getAttribute('href'); 1880 1881 // Skip if already using nginx routing 1882 if (href.startsWith('/docs/') || href.startsWith('/staff-docs/')) { 1883 return; 1884 } 1885 1886 // Extract path from URL 1887 let path = href.replace(/https?:\/\/[^\/]+/, ''); 1888 1889 // Remove any port references 1890 path = path.replace(/:\d+/, ''); 1891 1892 // Map to correct path if needed 1893 if (docsPathMap[path]) { 1894 path = docsPathMap[path]; 1895 } 1896 1897 // Update with nginx-routed URL 1898 link.setAttribute('href', getDocsUrl(path)); 1899 }); 1900 }); 1901</script>
1901 1902 1903<!-- MAIN CONTENT CONTAINER --> 1904<div class="landing-page min-h-screen relative"> 1905 1906 <!-- HERO SECTION - ABSOLUTELY STUNNING --> 1907 <section class="hero-section relative flex items-center justify-center px-4 py-20" style="z-index: 150 !important; min-height: 100vh; position: relative; margin-top: -80px; padding-top: 100px;"> 1908 <div class="container mx-auto" style="position: relative; z-index: 150;"> 1909 1910 <!-- Main Hero Content --> 1911 <div class="text-center mb-16"> 1912 <!-- Logo - Fade in animation --> 1913 <div class="mb-8 opacity-0 flex justify-center" id="heroLogo" style="z-index: 60; position: relative; animation: fadeInDown 1s ease-out 0.1s forwards;"> 1914 <img src="/static/img/logo-dark.d5385145e919.svg" alt="TumiTrust Logo" style="width: 120px; height: 120px;"> 1915 </div> 1916 1917 <!-- Ubuntu Quote - Fade in animation --> 1918 <div class="mb-6 opacity-0" id="ubuntuQuote" style="z-index: 60; position: relative; animation: fadeInDown 1s ease-out 0.3s forwards;"> 1919 <p class="text-sm md:text-base uppercase tracking-[0.22em] text-amber-300/90 font-bold mb-2"> 1920 Portable Trust Infrastructure · PTI 1921 </p> 1922 <p class="text-xl md:text-2xl text-amber-400/90 font-semibold tracking-wide not-italic"> 1923 Verified activity becomes portable proof people can carry. 1924 </p> 1925 </div> 1926 1927 <!-- Glitch Title --> 1928 <h1 class="text-7xl md:text-9xl font-black mb-6 glitch" style="z-index: 60; position: relative;"> 1929 <span class="holographic-text neon-glow" style="display: inline-block; position: relative;"> 1930 <span style="display: inline-block; position: relative;"> 1931 Tumi<span style="position: relative; display: inline-block;">Trust 1932 <span style=" 1933 display: block; 1934 font-size: 0.18em; 1935 font-weight: 700; 1936 letter-spacing: 0.42em; 1937 background: linear-gradient(135deg, #ffb84d 0%, #ff8c00 45%, #fbbf24 100%); 1938 -webkit-background-clip: text; 1939 -webkit-text-fill-color: transparent; 1940 background-clip: text; 1941 text-transform: uppercase; 1942 position: absolute; 1943 left: 0.08em; 1944 top: 100%; 1945 margin-top: 0.1em; 1946 font-family: 'Arial', 'Helvetica', sans-serif; 1947 text-shadow: 0 0 18px rgba(255, 184, 77, 0.45), 0 2px 6px rgba(0, 0, 0, 0.25); 1948 opacity: 0.95; 1949 font-style: normal; 1950 line-height: 1; 1951 white-space: nowrap; 1952 transform: translateY(0); 1953 animation: subtleGlow 3s ease-in-out infinite; 1954 ">pti</span> 1955 </span> 1956 </span> 1957 </span> 1958 </h1> 1959 1960 <!-- Main Headline with Typing Effect --> 1961 <div class="mb-8"> 1962 <h2 class="text-3xl md:text-5xl font-black text-white mb-6 leading-tight"> 1963 <span class="bg-gradient-to-r from-amber-400 via-orange-400 to-red-400 bg-clip-text text-transparent" id="typingHeadline"> 1964 Organizations already create trust every day. 1965 </span> 1966 </h2> 1967 <p class="text-lg md:text-xl text-amber-200/90 mb-6 max-w-3xl mx-auto leading-relaxed"> 1968 Employment, lending, transactions, certifications, memberships, and relationships - 1969 TumiTrust helps people turn those trusted events into <a href="/docs/pti/introduction/" class="tt-public-docs-link">
1969portable, verifiable proof</a> 1970 they can reuse when they authorize a decision. 1971 </p> 1972 1973 <!-- Audience routing - full paths live in #whoIsTumiTrustFor --> 1974 <p class="text-gray-300 leading-none mx-auto mb-6 whitespace-nowrap" style="font-size: clamp(0.7rem, 2.15vw, 1.05rem);"> 1975 Built for institutions that decide, partners that attest, and people who carry proof - 1976 <a href="#whoIsTumiTrustFor" class="tt-public-docs-link text-amber-300 font-semibold">pick your path â</a> 1977 </p> 1978 1979 </div> 1980 1981 <!-- CTA: PTI / organizations first; account secondary --> 1982 <div class="flex flex-col sm:flex-row gap-4 justify-center items-center mb-8 flex-wrap"> 1983 1984 <a href="#whatIsPti" class="btn-primary text-xl px-8 py-4 inline-flex items-center justify-center"> 1985 <i class="fas fa-layer-group mr-2"></i> 1986 Explore PTI 1987 </a> 1988 <a href="#whoIsTumiTrustFor" class="btn-outline text-xl px-8 py-4 inline-flex items-center justify-center"> 1989 <i class="fas fa-building mr-2"></i> 1990 For Organizations 1991 </a> 1992 1993 </div> 1994 1995 <!-- Official store badges (same-origin SVG - reliable vs hotlinking) --> 1996 <div class="flex flex-col sm:flex-row gap-6 justify-center items-center mb-10"> 1997 <a href="https://apps.apple.com/app/id6760616608" target="_blank" rel="noopener noreferrer" class="inline-block hover:opacity-90 transition-opacity" aria-label="Download on the App Store"> 1998 <img src="/static/img/badges/app-store.d0558d910630.svg" alt="Download on the App Store" class="h-14 w-auto" width="180" height="54" loading="lazy" decoding="async"> 1999 </a> 2000 <a href="https://play.google.com/store/apps/details?id=com.tumitrust.mobile&pcampaignid=web_share" target="_blank" rel="noopener noreferrer" class="inline-block hover:opacity-90 transition-opacity" aria-label="Get it on Google Play"> 2001 <img src="/static/img/badges/google-play.17615144cc51.svg" alt="Get it on Google Play" class="h-14 w-auto" width="180" height="54" loading="lazy" decoding="async"> 2002 </a> 2003 </div> 2004 2005 <div class="text-center mb-8 space-y-2"> 2006 <a href="/docs/tumitrust/product-overview/" class="inline-flex items-center gap-2 text-sm text-amber-300/90 hover:text-orange-400 transition-colors"> 2007 <i class="fas fa-book-open"></i> 2008 <span>Documentation: get started</span> 2009 </a> 2010 2011 </div> 2012 </div> 2013 </div> 2014 </section> 2015 2016 <!-- WHAT IS PTI - open specification (vendor-neutral layer) --> 2017 <section id="whatIsPti" class="py-16 md:py-20 px-4 relative" style="z-index: 50; position: relative;"> 2018 <div class="container mx-auto max-w-6xl"> 2019 <div class="text-center mb-12"> 2020 <div class="inline-flex items-center gap-2 px-5 py-2 bg-gradient-to-r from-orange-500/20 to-amber-500/20 border border-orange-500/30 rounded-full mb-6"> 2021 <i class="fas fa-book-open text-orange-400"></i> 2022 <span class="text-orange-400 font-semibold">Open infrastructure standard</span> 2023 </div> 2024 <h2 class="text-4xl md:text-5xl lg:text-6xl font-black text-white mb-5"> 2025 <span class="holographic-text">What is Portable Trust Infrastructure?</span> 2026 </h2> 2027 <p class="text-lg md:text-xl text-gray-300 max-w-3xl mx-auto leading-relaxed mb-6"> 2028 PTI is the <strong class="text-amber-200/90">vendor-neutral specification</strong> for how trust is 2029 <a href="/docs/pti/introduction/" class="tt-public-docs-link"><span class="text-amber-300 font-semibold">
2029produced, exchanged, resolved, and consumed</span></a> 2030 across <a href="/docs/pti/reference-architecture/trust-contexts" class="tt-public-docs-link"><span class="text-orange-400 font-semibold">20+ contexts</span></a> - portable, explainable, and governed. Any organization can implement it. 2031 </p> 2032 <div class="tt-landing-pill-row justify-center" aria-label="PTI properties"> 2033 <span class="tt-landing-pill"><i class="fas fa-route" aria-hidden="true"></i> Portable</span> 2034 <span class="tt-landing-pill"><i class="fas fa-code-branch" aria-hidden="true"></i> Interoperable</span> 2035 <span class="tt-landing-pill"><i class="fas fa-layer-group" aria-hidden="true"></i> Contextual</span> 2036 <span class="tt-landing-pill"><i class="fas fa-scale-balanced" aria-hidden="true"></i> Governed</span> 2037 </div> 2038 </div> 2039 2040 <div class="gradient-border rounded-3xl p-6 md:p-10 bg-gradient-to-br from-orange-900/15 to-amber-900/10 backdrop-blur-xl mb-10" style="background-image: linear-gradient(135deg, rgba(120, 53, 15, 0.22) 0%, rgba(146, 64, 14, 0.16) 50%, rgba(180, 83, 9, 0.12) 100%);"> 2041 <div class="grid sm:grid-cols-2 lg:grid-cols-4 gap-
20415 md:gap-6"> 2042 <a href="/docs/pti/origin/" class="group block rounded-2xl border border-orange-500/25 bg-slate-900/50 p-6 transition-all duration-300 hover:-translate-y-1 hover:border-orange-400/55 hover:shadow-[0_16px_40px_rgba(233,84,32,0.22)]" style="text-decoration: none; color: inherit;"> 2043 <div class="flex items-center gap-3 mb-4"> 2044 <div class="flex h-11 w-11 items-center justify-center rounded-xl bg-gradient-to-br from-orange-500/25 to-amber-500/20 border border-orange-500/30"> 2045 <i class="fas fa-landmark text-orange-400"></i> 2046 </div> 2047 <h3 class="text-lg font-bold text-white m-0">PTI origin</h3> 2048 </div> 2049 <p class="text-sm text-gray-400 leading-relaxed m-0 mb-3">Who pioneered the standard, why it exists, and how the open ecosystem grows.</p> 2050 <span class="text-sm font-semibold text-amber-400 group-hover:text-amber-300">Read the origin story â</span> 2051 </a> 2052 <a href="/docs/pti/why-pti" class="group block rounded-2xl border border-orange-500/25 bg-slate-900/50 p-6 transition-all duration-300 hover:-translate-y-1 hover:border-orange-400/55 hover:shadow-[0_16px_40px_rgba(233,84,32,0.22)]" style="text-decoration: none; color: inherit;"> 2053 <div class="flex items-center gap-3 mb-4"> 2054 <div class="flex h-11 w-11 items-center justify-center rounded-xl bg-gradient-to-br from-orange-500/25 to-amber-500/20 border border-orange-500/30"> 2055 <i class="fas fa-compass text-amber-400"></i> 2056 </div> 2057 <h3 class="text-lg font-bold text-white m-0">Why PTI exists</h3> 2058 </div> 2059 <p class="text-sm text-gray-400 leading-relaxed m-0 mb-3">Trust rebuilt in silos at every institution - PTI makes it shared infrastructure.</p> 2060 <span class="text-sm font-semibold text-amber-400 group-hover:text-amber-300">Read why â</span> 2061 </a> 2062 <a href="/docs/pti/comparisons/" class="group block rounded-2xl border border-orange-500/25 bg-slate-900/50 p-6 transition-all duration-300 hover:-translate-y-1 hover:border-orange-400/55 hover:shadow-[0_16px_40px_rgba(233,84,32,0.22)]" style="text-decoration: none; color: inherit;"> 2063 <div class="flex items-center gap-3 mb-4"> 2064 <div class="flex h-11 w-11 items-center justify-center rounded-xl bg-gradient-to-br from-orange-500/25 to-amber-500/20 border border-orange-500/30"> 2065 <i class="fas fa-balance-scale text-orange-300"></i> 2066 </div> 2067 <h3 class="text-lg font-bold text-white m-0">How PTI differs</h3> 2068 </div> 2069 <p class="text-sm text-gray-400 leading-relaxed m-0 mb-3">Complements identity, KYC, and payments - PTI orchestrates portable trust signals across them.</p> 2070 <span class="text-sm font-semibold text-amber-400 group-hover:text-amber-300">Comparisons â</span> 2071 </a> 2072 <a href="/docs/pti/build-your-pti/" class="group block rounded-2xl border border-orange-500/25 bg-slate-900/50 p-6 transition-all duration-300 hover:-translate-y-1 hover:border-orange-400/55 hover:shadow-[0_16px_40px_rgba(233,84,32,0.22)]" style="text-decoration: none; color: inherit;"> 2073 <div class="flex items-center gap-3 mb-4"> 2074 <div class="flex h-11 w-11 items-center justify-center rounded-xl bg-gradient-to-br from-orange-500/25 to-amber-500/20 border border-orange-500/30"> 2075 <i class="fas fa-hammer text-amber-300"></i> 2076 </div> 2077 <h3 class="text-lg font-bold text-white m-0">Build on PTI</h3> 2078 </div> 2079 <p class="text-sm text-gray-400 leading-relaxed m-0 mb-3">Specification, RFCs, and conformance - implement a compatible platform from the docs.</p>
2080 <span class="text-sm font-semibold text-amber-400 group-hover:text-amber-300">Build your own â</span> 2081 </a> 2082 </div> 2083 </div> 2084 2085 <div class="flex flex-col sm:flex-row flex-wrap items-center justify-center gap-3 md:gap-4"> 2086 <a href="/docs/pti/origin/" class="inline-flex items-center justify-center gap-2 px-8 py-3.5 rounded-xl font-bold text-white transition-transform hover:scale-[1.02]" style="background: linear-gradient(135deg, #e95420 0%, #f79500 50%, #ffb300 100%); box-shadow: 0 8px 28px rgba(233, 84, 32, 0.35);"> 2087 <i class="fas fa-book-open"></i> 2088 PTI origin story 2089 </a> 2090 <a href="/docs/pti/introduction/" class="inline-flex items-center justify-center gap-2 px-6 py-3.5 rounded-xl font-semibold text-amber-200 border border-orange-500/40 bg-orange-500/10 hover:bg-orange-500/20 transition-colors"> 2091 Explore architecture 2092 </a> 2093 <a href="/docs/pti/governance/" class="inline-flex items-center justify-center gap-2 px-6 py-3.5 rounded-xl font-semibold text-amber-200 border border-orange-500/40 bg-orange-500/10 hover:bg-orange-500/20 transition-colors"> 2094 Governance & ecosystem 2095 </a> 2096 </div> 2097 </div> 2098 </section> 2099 2100 2101<section id="whoIsTumiTrustFor" class="py-16 md:py-20 px-4 relative" style="z-index: 50;"> 2102 <div class="container mx-auto max-w-6xl"> 2103 <div class="text-center mb-12"> 2104 <div class="inline-flex items-center gap-2 px-5 py-2 bg-gradient-to-r from-orange-500/20 to-amber-500/20 border border-orange-500/30 rounded-full mb-6"> 2105 <i class="fas fa-users text-orange-400"></i> 2106 <span class="text-orange-400 font-semibold">Who is TumiTrust for?</span> 2107 </div> 2108 <h2 class="text-3xl md:text-5xl font-black text-white mb-4"> 2109 Three clear paths into <span class="holographic-text">PTI</span> 2110 </h2> 2111 <p class="text-lg text-gray-300 max-w-3xl mx-auto leading-relaxed"> 2112 Everyone understands a little when we talk to everyone. Pick the path that matches your job. 2113 </p> 2114 </div> 2115 2116 <div class="grid md:grid-cols-3 gap-6 mb-4"> 2117 <a href="/docs/tumitrust/audiences/for-institutions" class="group block rounded-2xl border border-orange-500/30 bg-slate-900/55 p-7 transition-all duration-300 hover:-translate-y-1 hover:border-orange-400/60 hover:shadow-[0_16px_40px_rgba(233,84,32,0.2)]" style="text-decoration:none;color:inherit;"> 2118 <p class="text-xs font-bold uppercase tracking-[0.16em] text-orange-400 mb-3">Decision-makers</p> 2119 <h3 class="text-xl font-bold text-white mb-3 m-0">Organizations that make decisions</h3> 2120 <p class="text-sm text-gray-400 leading-relaxed mb-4">Banks, lenders, insurers, employers, marketplaces, governments.</p> 2121 <p class="text-base text-amber-100/90 font-semibold mb-2">You need better trust signals.</p> 2122 <p class="text-sm text-gray-400 leading-relaxed m-0">Verify, assess, and consume structured trust intelligence alongside your existing processes.</p> 2123 <span class="inline-block mt-5 text-sm font-semibold text-amber-400 group-hover:text-amber-300">For institutions â</span> 2124 </a> 2125 2126 <a href="/docs/tumitrust/audiences/for-partners" class="group block rounded-2xl border border-amber-500/30 bg-slate-900/55 p-7 transition-all duration-300 hover:-translate-y-1 hover:border-amber-400/60 hover:shadow-[0_16px_40px_rgba(251,191,36,0.18)]" style="text-decoration:none;color:inherit;"> 2127 <p class="text-xs font-bold uppercase tracking-[0.16em] text-amber-400 mb-3">Trust producers</p> 2128 <h3 class="text-xl font-bold text-white mb-3 m-0">Organizations that create trusted activity</h3> 2129 <p class="text-sm text-gray-400 leading-relaxed mb-4">Employers, cooperatives, platforms, schools, telcos, NGOs.</p> 2130 <p class="text-base text-amber-100/90 font-semibold mb-2">Help people carry proof beyond one system.</p> 2131 <p class="text-sm text-gray-400 leading-relaxed m-0">Attest trusted events so individuals can reuse that history - with consent - when a decision matters.</p>
2132 <span class="inline-block mt-5 text-sm font-semibold text-amber-400 group-hover:text-amber-300">For trust producers â</span> 2133 </a> 2134 2135 <a href="/docs/tumitrust/audiences/for-individuals" class="group block rounded-2xl border border-orange-500/25 bg-slate-900/55 p-7 transition-all duration-300 hover:-translate-y-1 hover:border-orange-400/50 hover:shadow-[0_16px_40px_rgba(233,84,32,0.16)]" style="text-decoration:none;color:inherit;"> 2136 <p class="text-xs font-bold uppercase tracking-[0.16em] text-orange-300 mb-3">Individuals</p> 2137 <h3 class="text-xl font-bold text-white mb-3 m-0">Build portable proof</h3> 2138 <p class="text-sm text-gray-400 leading-relaxed mb-4">Members who need verified history to travel with them.</p> 2139 <p class="text-base text-amber-100/90 font-semibold mb-2">Carry verified evidence.</p> 2140 <p class="text-sm text-gray-400 leading-relaxed m-0">Employment, credentials, relationships, and achievements - with privacy and consent controls.</p> 2141 <span class="inline-block mt-5 text-sm font-semibold text-amber-400 group-hover:text-amber-300">For individuals â</span> 2142 </a> 2143 </div> 2144 </div> 2145</section> 2146 2147<section id="whatPtiIsNot" class="py-14 md:py-16 px-4 relative" style="z-index: 50;"> 2148 <div class="container mx-auto max-w-5xl"> 2149 <div class="text-center mb-10"> 2150 <h2 class="text-3xl md:text-4xl font-black text-white mb-3">What TumiTrust is - and is not</h2> 2151 <p class="text-gray-400 max-w-2xl mx-auto">Short answers. No jargon.</p> 2152 </div> 2153 <div class="grid md:grid-cols-2 gap-6"> 2154 <div class="rounded-2xl border border-red-500/25 bg-slate-900/60 p-7"> 2155 <h3 class="text-lg font-bold text-red-300 mb-4 flex items-center gap-2"> 2156 <i class="fas fa-times-circle" aria-hidden="true"></i> TumiTrust is not 2157 </h3> 2158 <ul class="space-y-3 text-gray-300 text-sm leading-relaxed m-0 pl-0 list-none"> 2159 <li class="flex gap-3"><span class="text-red-400 shrink-0">â</span><span>A credit bureau</span></li> 2160 <li class="flex gap-3"><span class="text-red-400 shrink-0">â</span><span>A replacement for your ID or KYC checks</span></li> 2161 <li class="flex gap-3"><span class="text-red-400 shrink-0">â</span><span>A place that sells peopleâs data</span></li> 2162 <li class="flex gap-3"><span class="text-red-400 shrink-0">â</span><span>A background-check company</span></li> 2163 <li class="flex gap-3"><span class="text-red-400 shrink-0">â</span><span>An app that only shows one score</span></li> 2164 </ul> 2165 </div> 2166 <div class="rounded-2xl border border-emerald-500/30 bg-slate-900/60 p-7"> 2167 <h3 class="text-lg font-bold text-emerald-300 mb-4 flex items-center gap-2"> 2168 <i class="fas fa-check-circle" aria-hidden="true"></i> TumiTrust is 2169 </h3> 2170 <ul class="space-y-3 text-gray-300 text-sm leading-relaxed m-0 pl-0 list-none"> 2171 <li class="flex gap-3"><span class="text-emerald-400 shrink-0">â</span><span>Infrastructure so trust proof can move with a person</span></li> 2172 <li class="flex gap-3"><span class="text-emerald-400 shrink-0">â</span><span>A shared language for verified activity across life contexts</span></li> 2173 <li class="flex gap-3"><span class="text-emerald-400 shrink-0">â</span><span>A way to review someoneâs trust story - with reasons - before you decide</span></li> 2174 <li class="flex gap-3"><span class="text-emerald-400 shrink-0">â</span><span>A bridge so organisations can reuse that proof safely across systems</span></li> 2175 <li class="flex gap-3"><span class="text-emerald-400 shrink-0">â</span><span>Optional sanctions / PEP / watchlist checks - extras for a trust decision, not a full compliance suite</span></li> 2176 </ul> 2177 </div> 2178 </div> 2179 </div> 2180</section> 2181 2182<section id="howOrgsUsePti" class="py-14 md:py-18 px-4 relative" style="z-index: 50;"> 2183 <div class="container mx-auto max-w-5xl"> 2184 <div class="text-center mb-12"> 2185 <div class="inline-flex items-center gap-2 px-5 py-2 bg-gradient-to-r from-orange-500/20 to-amber-500/20 border border-orange-500/30 rounded-full mb-6"> 2186 <i class="fas fa-diagram-project text-orange-400"></i>
2187 <span class="text-orange-400 font-semibold">How it works</span> 2188 </div> 2189 <h2 class="text-3xl md:text-4xl font-black text-white mb-4">How organizations use PTI</h2> 2190 <p class="text-gray-300 max-w-2xl mx-auto">Business language for the same rails - verified activity becomes portable proof when the person authorizes a purpose.</p> 2191 </div> 2192 2193 <ol class="space-y-5 m-0 pl-0 list-none"> 2194 <li class="rounded-2xl border border-orange-500/25 bg-slate-900/55 p-6 md:p-7 flex gap-4 md:gap-6"> 2195 <span class="flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-orange-500/20 border border-orange-500/40 text-orange-300 font-black">1</span> 2196 <div> 2197 <h3 class="text-lg font-bold text-white m-0 mb-2">Trusted activity happens</h3> 2198 <p class="text-sm text-gray-400 leading-relaxed m-0">Employee completes training · farmer repays an input loan · merchant fulfils orders · member participates in a cooperative · business completes compliance checks.</p> 2199 </div> 2200 </li> 2201 <li class="rounded-2xl border border-orange-500/25 bg-slate-900/55 p-6 md:p-7 flex gap-4 md:gap-6"> 2202 <span class="flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-orange-500/20 border border-orange-500/40 text-orange-300 font-black">2</span> 2203 <div> 2204 <h3 class="text-lg font-bold text-white m-0 mb-2">Trust signals are created</h3> 2205 <p class="text-sm text-gray-400 leading-relaxed m-0">Verified events become structured signals - so the person can carry them, with the producer still accountable for what was attested.</p> 2206 </div> 2207 </li> 2208 <li class="rounded-2xl border border-orange-500/25 bg-slate-900/55 p-6 md:p-7 flex gap-4 md:gap-6"> 2209 <span class="flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-orange-500/20 border border-orange-500/40 text-orange-300 font-black">3</span> 2210 <div> 2211 <h3 class="text-lg font-bold text-white m-0 mb-2">PTI structures and verifies those signals</h3> 2212 <p class="text-sm text-gray-400 leading-relaxed m-0">Portable Trust Infrastructure makes them consistent and explainable - ready for the person to reuse in contexts they authorize.</p> 2213 </div> 2214 </li> 2215 <li class="rounded-2xl border border-amber-500/30 bg-gradient-to-br from-orange-900/25 to-amber-900/15 p-6 md:p-7 flex gap-4 md:gap-6"> 2216 <span class="flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-amber-500/25 border border-amber-400/50 text-amber-200 font-black">4</span> 2217 <div> 2218 <h3 class="text-lg font-bold text-white m-0 mb-2">Authorized organizations use that trust when deciding</h3> 2219 <p class="text-sm text-gray-300 leading-relaxed m-0">Approve lending · verify employment · onboard partners · reduce fraud · assess risk - without replacing your core systems.</p> 2220 </div> 2221 </li> 2222 </ol> 2223 </div> 2224</section> 2225 2226<section id="trustProducers" class="py-14 md:py-16 px-4 relative" style="z-index: 50;"> 2227 <div class="container mx-auto max-w-5xl"> 2228 <div class="rounded-3xl border border-orange-500/35 bg-gradient-to-br from-orange-900/30 via-slate-900/80 to-amber-900/20 p-8 md:p-12"> 2229 <p class="text-xs font-bold uppercase tracking-[0.2em] text-amber-400 mb-3">Trust producers</p> 2230 <h2 class="text-3xl md:text-4xl font-black text-white mb-5">Your organization already creates trust</h2> 2231 <p class="text-lg text-gray-200 leading-relaxed max-w-3xl mb-6"> 2232 Every organization attests valuable history - employment, repayments, transactions, certifications, memberships, compliance events. 2233 PTI lets people <strong class="text-amber-200">carry that proof with them</strong> - you stay accountable for what you attested. 2234 </p> 2235 <p class="text-base text-gray-400 leading-relaxed max-w-3xl mb-8"> 2236 This is not âhand over your customersâ data.â You help people keep a portable Trust CV from activity that already happened - shared only when they consent. 2237 </p> 2238 <div class="flex flex-wrap gap-3">
2239 <a href="/docs/tumitrust/audiences/for-partners" class="inline-flex items-center gap-2 px-6 py-3 rounded-xl font-bold text-white" style="background: linear-gradient(135deg, #e95420 0%, #f79500 100%);"> 2240 Become a trust producer â 2241 </a> 2242 <a href="/platform/" class="inline-flex items-center gap-2 px-6 py-3 rounded-xl font-semibold text-amber-200 border border-orange-500/40 bg-orange-500/10 hover:bg-orange-500/20"> 2243 Explore the platform 2244 </a> 2245 </div> 2246 </div> 2247 </div> 2248</section> 2249 2250 2251 <!-- ========================================== --> 2252 <!-- TUMITRUST PLATFORM - reference implementation --> 2253 <!-- ========================================== --> 2254 <section id="whatIsTumiTrust" style=" 2255 position: relative; 2256 z-index: 140; 2257 padding: 20px 30px 40px; 2258 margin: 0 auto 60px; 2259 max-width: 1200px; 2260 "> 2261 <!-- Main Card Container --> 2262 <div style=" 2263 background: linear-gradient(135deg, rgba(30, 41, 59, 0.95) 0%, rgba(51, 65, 85, 0.95) 100%); 2264 backdrop-filter: blur(20px); 2265 border: 2px solid rgba(255, 170, 0, 0.4); 2266 border-radius: 24px; 2267 padding: 50px 40px; 2268 box-shadow: 0 25px 70px rgba(0, 0, 0, 0.6), 0 0 60px rgba(255, 170, 0, 0.15); 2269 position: relative; 2270 overflow: hidden; 2271 opacity: 0; 2272 transform: translateY(30px); 2273 animation: fadeInUp 0.6s ease-out 0.3s forwards; 2274 "> 2275 <!-- Animated Network Background Pattern --> 2276 <div style=" 2277 position: absolute; 2278 inset: 0; 2279 background-image: 2280 radial-gradient(circle at 20% 30%, rgba(255, 170, 0, 0.08) 0%, transparent 50%), 2281 radial-gradient(circle at 80% 70%, rgba(233, 84, 32, 0.08) 0%, transparent 50%), 2282 radial-gradient(circle at 2px 2px, rgba(255, 170, 0, 0.12) 1px, transparent 0); 2283 background-size: 100% 100%, 100% 100%, 40px 40px; 2284 opacity: 0.4; 2285 pointer-events: none; 2286 animation: subtlePulse 8s ease-in-out infinite; 2287 "></div> 2288 2289 <!-- Floating Particles Background --> 2290 <div class="particles-bg" style="position: absolute; inset: 0; pointer-events: none; overflow: hidden;"> 2291 <div style="position: absolute; width: 5px; height: 5px; background: rgba(255, 170, 0, 0.5); border-radius: 50%; left: 15%; top: 25%; animation: floatUp 10s infinite ease-in-out; box-shadow: 0 0 12px rgba(255, 170, 0, 0.4);"></div> 2292 <div style="position: absolute; width: 4px; height: 4px; background: rgba(255, 102, 0, 0.4); border-radius: 50%; left: 85%; top: 35%; animation: floatUp 12s infinite ease-in-out 2s; box-shadow: 0 0 10px rgba(255, 102, 0, 0.3);"></div> 2293 <div style="position: absolute; width: 6px; height: 6px; background: rgba(251, 191, 36, 0.4); border-radius: 50%; left: 50%; top: 15%; animation: floatUp 14s infinite ease-in-out 4s; box-shadow: 0 0 14px rgba(251, 191, 36, 0.3);"></div> 2294 </div> 2295 2296 <!-- MAIN HEADLINE --> 2297 <div style=" 2298 text-align: center; 2299 margin-bottom: 40px; 2300 position: relative; 2301 z-index: 2; 2302 "> 2303 <div style=" 2304 display: inline-flex; 2305 align-items: center; 2306 gap: 12px; 2307 margin-bottom: 16px; 2308 padding: 8px 20px; 2309 background: rgba(255, 170, 0, 0.1); 2310 border: 1px solid rgba(255, 170, 0, 0.3); 2311 border-radius: 50px; 2312 animation: gentleGlow 3s ease-in-out infinite; 2313 "> 2314 <img src="/static/img/logo-dark.d5385145e919.svg" alt="TumiTrust" style=" 2315 width: 32px; 2316 height: 32px; 2317 filter: drop-shadow(0 2px 8px rgba(255, 170, 0, 0.4)); 2318 ">
2319 <span style=" 2320 font-size: 16px; 2321 font-weight: 700; 2322 background: linear-gradient(135deg, #e95420 0%, #f79500 50%, #ffb300 100%); 2323 -webkit-background-clip: text; 2324 -webkit-text-fill-color: transparent; 2325 background-clip: text; 2326 letter-spacing: 0.5px; 2327 ">TumiTrust</span> 2328 <span style=" 2329 font-size: 11px; 2330 font-weight: 600; 2331 color: rgba(253, 230, 138, 0.85); 2332 text-transform: uppercase; 2333 letter-spacing: 0.12em; 2334 ">Reference implementation</span> 2335 </div> 2336 2337 <h2 style=" 2338 font-size: 34px; 2339 font-weight: 900; 2340 color: white; 2341 margin: 0 0 10px 0; 2342 line-height: 1.3; 2343 letter-spacing: -0.5px; 2344 text-shadow: 0 2px 20px rgba(255, 170, 0, 0.3); 2345 "> 2346 For everyone: earn credibility, <span style="color: #fde68a;">run your own trust lookups</span>, decide with confidence 2347 </h2> 2348 <p style=" 2349 font-size: 15px; 2350 font-weight: 700; 2351 color: rgba(254, 243, 199, 0.95); 2352 margin: 0 auto 14px; 2353 max-width: 760px; 2354 line-height: 1.45; 2355 letter-spacing: 0.02em; 2356 "> 2357 Members run <strong style="color: #fff;">trust lookups</strong> on the platform - tiers and summaries. <strong style="color: #fde68a;">Same rails</strong> partners and institutions scale on via API and dashboards. 2358 </p> 2359 <div class="tt-landing-pill-row" aria-label="Key product facts"> 2360 <span class="tt-landing-pill"><i class="fas fa-user-check" aria-hidden="true"></i> Trust lookups</span> 2361 <span class="tt-landing-pill"><i class="fas fa-layer-group" aria-hidden="true"></i> Basic · Detailed · Predictive</span> 2362 <span class="tt-landing-pill"><i class="fas fa-mobile-screen-button" aria-hidden="true"></i> In-app on iOS & Android</span> 2363 </div> 2364 <p style=" 2365 font-size: 18px; 2366 color: rgba(226, 232, 240, 0.9); 2367 margin: 0 auto; 2368 max-width: 720px; 2369 line-height: 1.6; 2370 font-weight: 400; 2371 "> 2372 Endorsements and badges build <em>your</em> proof. Need clarity on someone? Open a <a href="/docs/tumitrust/audiences/for-institutions" class="tt-public-docs-link"><span style="color: #f79500; font-weight: 600;">lookup</span></a>. <a href="/docs/pti/introduction/" class="tt-public-docs-link"><span style="color: #f79500; font-weight: 600; font-style: italic;">Portable trust</span></a> - proof travels; signals help you choose. 2373 </p> 2374 </div> 2375 2376 <!-- SPLIT CARD: FOR YOU vs ORGS & TEAMS (individual lookups live in-app) --> 2377 <div style=" 2378 display: grid; 2379 grid-template-columns: 1fr 1fr; 2380 gap: 24px; 2381 margin-bottom: 30px; 2382 position: relative; 2383 z-index: 2; 2384 " class="value-prop-grid"> 2385 <!-- LEFT: For Everyone --> 2386 <div style=" 2387 background: linear-gradient(135deg, rgba(233, 84, 32, 0.12) 0%, rgba(247, 149, 0, 0.08) 100%); 2388 border: 2px solid rgba(233, 84, 32, 0.4); 2389 border-radius: 20px; 2390 padding: 32px 28px; 2391 transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); 2392 position: relative; 2393 overflow: hidden; 2394 box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2); 2395 " onmouseover="this.style.transform='translateY(-6px)'; this.style.borderColor='rgba(233, 84, 32, 0.8)'; this.style.boxShadow='0 20px 50px rgba(233, 84, 32, 0.3)';" onmouseout="this.style.transform='translateY(0)'; this.style.borderColor='rgba(233, 84, 32, 0.4)'; this.style.boxShadow='0 4px 20px rgba(0, 0, 0, 0.2)';"> 2396 <!-- Glow Effect --> 2397 <div style="position: absolute; top: -50%; right: -50%; width: 200%; height: 200%; background: radial-gradient(circle, rgba(233, 84, 32, 0.15) 0%, transparent 70%); pointer-events: none;"></div> 2398 2399 <!-- Icon & Badge --> 2400 <div style="display: flex; align-items: center; gap: 12px; margin-bottom: 18px; position: relative;"> 2401 <div style=" 2402 width: 50px; 2403 height: 50px; 2404 background: linear-gradient(135deg, rgba(233, 84, 32, 0.3) 0%, rgba(247, 149, 0, 0.3) 100%); 2405 border-radius: 12px; 2406 display: flex; 2407 align-items: center; 2408 justify-content: center; 2409 box-shadow: 0 4px 16px rgba(233, 84, 32, 0.3); 2410 "> 2411 <i class="fas fa-users" style=" 2412 font-size: 26px; 2413 color: #f79500; 2414 filter: drop-shadow(0 0 8px rgba(247, 149, 0, 0.6)); 2415 animation: iconPulse 2s ease-in-out infinite; 2416 "></i> 2417 </div> 2418 <div style=" 2419 padding: 4px 14px; 2420 background: linear-gradient(135deg, #e95420 0%, #f79500 100%); 2421 border-radius: 20px; 2422 font-size: 12px; 2423 font-weight: 700; 2424 color: white; 2425 text-transform: uppercase; 2426 letter-spacing: 0.5px; 2427 box-shadow: 0 2px 10px rgba(233, 84, 32, 0.4); 2428 ">FOR YOU</div> 2429 </div> 2430 2431 <!-- Headline --> 2432 <h3 style=" 2433 font-size: 26px; 2434 font-weight: 900; 2435 color: white; 2436 margin: 0 0 10px 0; 2437 line-height: 1.2; 2438 "> 2439 100% FREE Forever 2440 </h3> 2441 2442 <p style=" 2443 font-size: 15px; 2444 color: rgba(226, 232, 240, 0.85); 2445 margin: 0 0 20px 0; 2446 line-height: 1.5; 2447 "> 2448 Build your Trust CV. Unlock: 2449 </p> 2450 2451 <!-- Benefits --> 2452 <div style="margin-bottom: 24px;"> 2453 <div style="display: flex; align-items: start; gap: 12px; margin-bottom: 14px; padding: 12px; background: rgba(139, 92, 246, 0.12); border-radius: 10px; border-left: 3px solid #c084fc;"> 2454 <i class="fas fa-file-signature" style="font-size: 24px; flex-shrink: 0; color: #c4b5fd;"></i> 2455 <div> 2456 <div style="font-size: 15px; font-weight: 700; color: white; margin-bottom: 2px;">Trust lookups</div> 2457 <div style="font-size: 13px; color: rgba(226, 232, 240, 0.75);"><strong style="color: #fde68a;">Basic · Detailed · Predictive</strong> - credits or fees when applicable.</div> 2458 </div> 2459 </div> 2460 <div style="display: flex; align-items: start; gap: 12px; margin-bottom: 14px; padding: 12px; background: rgba(255, 255, 255, 0.05); border-radius: 10px; border-left: 3px solid #fbbf24;"> 2461 <i class="fas fa-coins" style="font-size: 24px; flex-shrink: 0; color: #fbbf24;"></i> 2462 <div> 2463 <div style="font-size: 15px; font-weight: 700; color: white; margin-bottom: 2px;">
246320 trust contexts</div> 2464 <div style="font-size: 13px; color: rgba(226, 232, 240, 0.7);">10 primaries + 10 lenses - one portable map. <a href="/docs/tumitrust/platform/partner-trust-contexts" class="tt-public-docs-link">See the table â</a></div> 2465 </div> 2466 </div> 2467 <div style="display: flex; align-items: start; gap: 12px; margin-bottom: 14px; padding: 12px; background: rgba(255, 255, 255, 0.05); border-radius: 10px; border-left: 3px solid #f79500;"> 2468 <i class="fas fa-home" style="font-size: 24px; flex-shrink: 0; color: #f79500;"></i> 2469 <div> 2470 <div style="font-size: 15px; font-weight: 700; color: white; margin-bottom: 2px;">Institutions & partners</div> 2471 <div style="font-size: 13px; color: rgba(226, 232, 240, 0.7);">Run trust lookups or ingest verified events - same network, anywhere</div> 2472 </div> 2473 </div> 2474 <div style="display: flex; align-items: start; gap: 12px; padding: 12px; background: rgba(255, 255, 255, 0.05); border-radius: 10px; border-left: 3px solid #e95420;"> 2475 <i class="fas fa-briefcase" style="font-size: 24px; flex-shrink: 0; color: #e95420;"></i> 2476 <div> 2477 <div style="font-size: 15px; font-weight: 700; color: white; margin-bottom: 2px;">Expansion optionality</div> 2478 <div style="font-size: 13px; color: rgba(226, 232, 240, 0.7);">Rental, employment, insurance & more - same map, per contract</div> 2479 </div> 2480 </div> 2481 </div> 2482 2483 <!-- CTA Button --> 2484 <a href="/register/" style=" 2485 display: inline-flex; 2486 align-items: center; 2487 justify-content: center; 2488 gap: 8px; 2489 width: 100%; 2490 padding: 14px 24px; 2491 background: linear-gradient(135deg, #e95420 0%, #f79500 100%); 2492 color: white; 2493 text-decoration: none; 2494 border-radius: 12px; 2495 font-size: 16px; 2496 font-weight: 800; 2497 transition: all 0.3s ease; 2498 border: none; 2499 cursor: pointer; 2500 box-shadow: 0 6px 24px rgba(233, 84, 32, 0.4); 2501 position: relative; 2502 overflow: hidden; 2503 " onmouseover="this.style.transform='scale(1.03)'; this.style.boxShadow='0 8px 32px rgba(233, 84, 32, 0.6)';" onmouseout="this.style.transform='scale(1)'; this.style.boxShadow='0 6px 24px rgba(233, 84, 32, 0.4)';"> 2504 <i class="fas fa-rocket" style="font-size: 18px;"></i> 2505 <span>Get Started Free</span> 2506 </a> 2507 </div> 2508 2509 <!-- RIGHT: For organisations (individuals use lookups in-app; this is for teams/API volume) --> 2510 <div style=" 2511 background: linear-gradient(135deg, rgba(251, 191, 36, 0.12) 0%, rgba(255, 170, 0, 0.08) 100%); 2512 border: 2px solid rgba(251, 191, 36, 0.4); 2513 border-radius: 20px; 2514 padding: 32px 28px; 2515 transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); 2516 position: relative; 2517 overflow: hidden; 2518 box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2); 2519 " onmouseover="this.style.transform='translateY(-6px)'; this.style.borderColor='rgba(251, 191, 36, 0.8)'; this.style.boxShadow='0 20px 50px rgba(251, 191, 36, 0.3)';" onmouseout="this.style.transform='translateY(0)'; this.style.borderColor='rgba(251, 191, 36, 0.4)'; this.style.boxShadow='0 4px 20px rgba(0, 0, 0, 0.2)';"> 2520 <!-- Glow Effect --> 2521 <div style="position: absolute; top: -50%; left: -50%; width: 200%; height: 200%; background: radial-gradient(circle, rgba(251, 191, 36, 0.15) 0%, transparent 70%); pointer-events: none;"></div> 2522 2523 <!-- Icon & Badge --> 2524 <div style="display: flex; align-items: center; gap: 12px; margin-bottom: 18px; position: relative;"> 2525 <div style=" 2526 width: 50px; 2527 height: 50px; 2528 background: linear-gradient(135deg, rgba(251, 191, 36, 0.3) 0%, rgba(255, 170, 0, 0.3) 100%); 2529 border-radius: 12px; 2530 display: flex; 2531 align-items: center; 2532 justify-content: center; 2533 box-shadow: 0 4px 16px rgba(251, 191, 36, 0.3); 2534 "> 2535 <i class="fas fa-building" style=" 2536 font-size: 26px; 2537 color: #fbbf24; 2538 filter: drop-shadow(0 0 8px rgba(251, 191, 36, 0.6)); 2539 animation: iconPulse 2s ease-in-out infinite 0.5s; 2540 "></i> 2541 </div> 2542 <div style=" 2543 padding: 4px 14px; 2544 background: linear-gradient(135deg, #fbbf24 0%, #f79500 100%); 2545 border-radius: 20px; 2546 font-size: 12px; 2547 font-weight: 700; 2548 color: #1e293b; 2549 text-transform: uppercase; 2550 letter-spacing: 0.5px; 2551 box-shadow: 0 2px 10px rgba(251, 191, 36, 0.4); 2552 ">FOR ORGS & TEAMS</div> 2553 </div> 2554 2555 <!-- Headline --> 2556 <h3 style=" 2557 font-size: 26px; 2558 font-weight: 900; 2559 color: white; 2560 margin: 0 0 10px 0; 2561 line-height: 1.2; 2562 "> 2563 Verify at scale 2564 </h3> 2565 2566 <p style=" 2567 font-size: 15px; 2568 color: rgba(226, 232, 240, 0.85); 2569 margin: 0 0 20px 0; 2570 line-height: 1.5; 2571 "> 2572 <strong style="color: #fef3c7;">Members first.</strong> Partners scale the same signals-<a href="/docs/tumitrust/developer-guides/trust-platform-api#institution-report-lookup" class="tt-public-docs-link">API</a>, dashboards, volume. 2573 </p> 2574 2575 <!-- Benefits --> 2576 <div style="margin-bottom: 24px;"> 2577 <div style="display: flex; align-items: start; gap: 12px; margin-bottom: 14px; padding: 12px; background: rgba(255, 255, 255, 0.05); border-radius: 10px; border-left: 3px solid #10b981;">
2578 <span style="font-size: 24px; flex-shrink: 0;">â²</span> 2579 <div> 2580 <div style="font-size: 15px; font-weight: 700; color: white; margin-bottom: 2px;">Reach More People</div> 2581 <div style="font-size: 13px; color: rgba(226, 232, 240, 0.7);">Reach people on the <a href="/docs/tumitrust/platform/partner-trust-contexts" class="tt-public-docs-link">full context map</a>-including thin-file lives.</div> 2582 </div> 2583 </div> 2584 <div style="display: flex; align-items: start; gap: 12px; margin-bottom: 14px; padding: 12px; background: rgba(255, 255, 255, 0.05); border-radius: 10px; border-left: 3px solid #3b82f6;"> 2585 <i class="fas fa-shield-alt" style="font-size: 24px; flex-shrink: 0; color: #3b82f6;"></i> 2586 <div> 2587 <div style="font-size: 15px; font-weight: 700; color: white; margin-bottom: 2px;">Lower Risk</div> 2588 <div style="font-size: 13px; color: rgba(226, 232, 240, 0.7);">Community trust shows who's reliable</div> 2589 </div> 2590 </div> 2591 <div style="display: flex; align-items: start; gap: 12px; padding: 12px; background: rgba(255, 255, 255, 0.05); border-radius: 10px; border-left: 3px solid #8b5cf6;"> 2592 <i class="fas fa-bolt" style="font-size: 24px; flex-shrink: 0; color: #fbbf24;"></i> 2593 <div> 2594 <div style="font-size: 15px; font-weight: 700; color: white; margin-bottom: 2px;">Reports at org scale</div> 2595 <div style="font-size: 13px; color: rgba(226, 232, 240, 0.7);">Same <a href="/docs/tumitrust/platform/partner-trust-contexts" class="tt-public-docs-link">20-context</a> map members use-wired for teams and API.</div> 2596 </div> 2597 </div> 2598 </div> 2599 2600 <!-- Stats Quick --> 2601 <div style=" 2602 padding: 14px; 2603 background: rgba(251, 191, 36, 0.08); 2604 border-radius: 10px; 2605 border: 1px solid rgba(251, 191, 36, 0.2); 2606 margin-bottom: 20px; 2607 "> 2608 <div style="font-size: 13px; color: rgba(226, 232, 240, 0.9); line-height: 1.5;"> 2609 <strong style="color: #fbbf24;">Used by:</strong> Banks ⢠Landlords ⢠Employers ⢠Insurers ⢠More 2610 </div> 2611 </div> 2612 2613 <!-- CTA Button --> 2614 <a href="/register/institution/" style=" 2615 display: inline-flex; 2616 align-items: center; 2617 justify-content: center; 2618 gap: 8px; 2619 width: 100%; 2620 padding: 14px 24px; 2621 background: linear-gradient(135deg, #fbbf24 0%, #f79500 100%); 2622 color: #1e293b; 2623 text-decoration: none; 2624 border-radius: 12px; 2625 font-size: 16px; 2626 font-weight: 800; 2627 transition: all 0.3s ease; 2628 border: none; 2629 cursor: pointer; 2630 box-shadow: 0 6px 24px rgba(251, 191, 36, 0.4); 2631 position: relative; 2632 overflow: hidden; 2633 " onmouseover="this.style.transform='scale(1.03)'; this.style.boxShadow='0 8px 32px rgba(251, 191, 36, 0.6)';" onmouseout="this.style.transform='scale(1)'; this.style.boxShadow='0 6px 24px rgba(251, 191, 36, 0.4)';"> 2634 <i class="fas fa-chart-line" style="font-size: 18px;"></i> 2635 <span>Create verified workspace</span> 2636 </a> 2637 </div> 2638 </div> 2639
2640 <!-- Individual trust lookups callout --> 2641 <div style=" 2642 position: relative; 2643 z-index: 2; 2644 margin-bottom: 28px; 2645 padding: 22px 24px; 2646 background: linear-gradient(135deg, rgba(139, 92, 246, 0.22) 0%, rgba(233, 84, 32, 0.14) 100%); 2647 border: 1px solid rgba(196, 181, 253, 0.45); 2648 border-radius: 18px; 2649 text-align: center; 2650 box-shadow: 0 12px 40px rgba(0, 0, 0, 0.25), inset 0 1px 0 rgba(255, 255, 255, 0.06); 2651 "> 2652 <p class="tt-individual-callout-title">Lookups for real decisions</p> 2653 <p style="margin: 0; font-size: 15px; color: rgba(248, 250, 252, 0.95); line-height: 1.55; max-width: 720px; margin-left: auto; margin-right: auto;"> 2654 <a href="/docs/tumitrust/audiences/for-institutions" class="tt-public-docs-link"><strong style="color: #fde68a;">Trust lookups</strong></a> - whenever a decision matters - credits where they apply. 2655 </p> 2656 </div> 2657 2658 <!-- TRUST CONTEXT BADGE STRIP --> 2659 <div style=" 2660 position: relative; 2661 z-index: 2; 2662 text-align: center; 2663 padding-top: 8px; 2664 "> 2665 <div style=" 2666 font-size: 13px; 2667 font-weight: 600; 2668 color: rgba(226, 232, 240, 0.6); 2669 margin-bottom: 12px; 2670 text-transform: uppercase; 2671 letter-spacing: 1px; 2672 ">20 documented contexts · 10 primaries + 10 lenses</div> 2673 <div style=" 2674 overflow-x: auto; 2675 overflow-y: hidden; 2676 -webkit-overflow-scrolling: touch; 2677 scroll-behavior: smooth; 2678 padding: 8px 0; 2679 margin: 0 -10px; 2680 padding: 0 10px; 2681 " class="context-strip"> 2682 <div style=" 2683 display: flex; 2684 gap: 10px; 2685 min-width: max-content; 2686 justify-content: center; 2687 "> 2688 <!-- Context Badges --> 2689 <div class="context-badge" style="display: inline-flex; align-items: center; gap: 6px; padding: 8px 16px;
2689 background: rgba(30, 41, 59, 0.6); border: 1px solid rgba(255, 170, 0, 0.3); border-radius: 20px; transition: all 0.3s ease; cursor: pointer; white-space: nowrap; backdrop-filter: blur(10px);" onmouseover="this.style.transform='translateY(-2px) scale(1.05)'; this.style.background='rgba(233, 84, 32, 0.2)'; this.style.borderColor='rgba(233, 84, 32, 0.6)'; this.style.boxShadow='0 6px 20px rgba(233, 84, 32, 0.3)';" onmouseout="this.style.transform='translateY(0) scale(1)'; this.style.background='rgba(30, 41, 59, 0.6)'; this.style.borderColor='rgba(255, 170, 0, 0.3)'; this.style.boxShadow='none';"><i class="fas fa-coins" style="font-size: 14px; color: #fbbf24;"></i><span style="font-size: 12px; font-weight: 600; color: #e2e8f0;">Lending</span></div> 2690 2691 <div class="context-badge" style="display: inline-flex; align-items: center; gap: 6px; padding: 8px 16px; background: rgba(30, 41, 59, 0.6); border: 1px solid rgba(255, 170, 0, 0.3); border-radius: 20px; transition: all 0.3s ease; cursor: pointer; white-space: nowrap; backdrop-filter: blur(10px);" onmouseover="this.style.transform='translateY(-2px) scale(1.05)'; this.style.background='rgba(233, 84, 32, 0.2)'; this.style.borderColor='rgba(233, 84, 32, 0.6)'; this.style.boxShadow='0 6px 20px rgba(233, 84, 32, 0.3)';" onmouseout="this.style.transform='translateY(0) scale(1)';
2691 this.style.background='rgba(30, 41, 59, 0.6)'; this.style.borderColor='rgba(255, 170, 0, 0.3)'; this.style.boxShadow='none';"><i class="fas fa-home" style="font-size: 14px; color: #fbbf24;"></i><span style="font-size: 12px; font-weight: 600; color: #e2e8f0;">Rental</span></div> 2692 2693 <div class="context-badge" style="display: inline-flex; align-items: center; gap: 6px; padding: 8px 16px; background: rgba(30, 41, 59, 0.6); border: 1px solid rgba(255, 170, 0, 0.3); border-radius: 20px; transition: all 0.3s ease; cursor: pointer; white-space: nowrap; backdrop-filter: blur(10px);" onmouseover="this.style.transform='translateY(-2px) scale(1.05)'; this.style.background='rgba(233, 84, 32, 0.2)'; this.style.borderColor='rgba(233, 84, 32, 0.6)'; this.style.boxShadow='0 6px 20px rgba(233, 84, 32, 0.3)';" onmouseout="this.style.transform='translateY(0) scale(1)'; this.style.background='rgba(30, 41, 59, 0.6)'; this.style.borderColor='rgba(255, 170, 0, 0.3)'; this.style.boxShadow='none';"><i class="fas fa-briefcase" style="font-size: 14px; color: #fbbf24;"></i><span style="font-size: 12px; font-weight: 600; color: #e2e8f0;">Employment</span></div> 2694 2695 <div class="context-badge" style="display: inline-flex; align-items: center; gap: 6px; padding: 8px 16px;
2695 background: rgba(30, 41, 59, 0.6); border: 1px solid rgba(255, 170, 0, 0.3); border-radius: 20px; transition: all 0.3s ease; cursor: pointer; white-space: nowrap; backdrop-filter: blur(10px);" onmouseover="this.style.transform='translateY(-2px) scale(1.05)'; this.style.background='rgba(233, 84, 32, 0.2)'; this.style.borderColor='rgba(233, 84, 32, 0.6)'; this.style.boxShadow='0 6px 20px rgba(233, 84, 32, 0.3)';" onmouseout="this.style.transform='translateY(0) scale(1)'; this.style.background='rgba(30, 41, 59, 0.6)'; this.style.borderColor='rgba(255, 170, 0, 0.3)'; this.style.boxShadow='none';"><i class="fas fa-shield-alt" style="font-size: 14px; color: #fbbf24;"></i><span style="font-size: 12px; font-weight: 600; color: #e2e8f0;">Insurance</span></div> 2696 2697 <div class="context-badge" style="display: inline-flex; align-items: center; gap: 6px; padding: 8px 16px; background: rgba(30, 41, 59, 0.6); border: 1px solid rgba(255, 170, 0, 0.3); border-radius: 20px; transition: all 0.3s ease; cursor: pointer; white-space: nowrap; backdrop-filter: blur(10px);" onmouseover="this.style.transform='translateY(-2px) scale(1.05)'; this.style.background='rgba(233, 84, 32, 0.2)'; this.style.borderColor='rgba(233, 84, 32, 0.6)'; this.style.boxShadow='0 6px 20px rgba(233, 84, 32, 0.3)';" onmouseout="this.style.transform='translateY(0) scale(1)';
2697 this.style.background='rgba(30, 41, 59, 0.6)'; this.style.borderColor='rgba(255, 170, 0, 0.3)'; this.style.boxShadow='none';"><i class="fas fa-cart-shopping" style="font-size: 14px; color: #fbbf24;"></i><span style="font-size: 12px; font-weight: 600; color: #e2e8f0;">Merchant</span></div> 2698 2699 <div class="context-badge" style="display: inline-flex; align-items: center; gap: 6px; padding: 8px 16px; background: rgba(30, 41, 59, 0.6); border: 1px solid rgba(255, 170, 0, 0.3); border-radius: 20px; transition: all 0.3s ease; cursor: pointer; white-space: nowrap; backdrop-filter: blur(10px);" onmouseover="this.style.transform='translateY(-2px) scale(1.05)'; this.style.background='rgba(233, 84, 32, 0.2)'; this.style.borderColor='rgba(233, 84, 32, 0.6)'; this.style.boxShadow='0 6px 20px rgba(233, 84, 32, 0.3)';" onmouseout="this.style.transform='translateY(0) scale(1)'; this.style.background='rgba(30, 41, 59, 0.6)'; this.style.borderColor='rgba(255, 170, 0, 0.3)'; this.style.boxShadow='none';"><i class="fas fa-handshake" style="font-size: 14px; color: #fbbf24;"></i><span style="font-size: 12px; font-weight: 600; color: #e2e8f0;">Partnership</span></div> 2700 2701 <div class="context-badge" style="display: inline-flex; align-items: center; gap: 6px; padding: 8px 16px;
2701 background: rgba(30, 41, 59, 0.6); border: 1px solid rgba(255, 170, 0, 0.3); border-radius: 20px; transition: all 0.3s ease; cursor: pointer; white-space: nowrap; backdrop-filter: blur(10px);" onmouseover="this.style.transform='translateY(-2px) scale(1.05)'; this.style.background='rgba(233, 84, 32, 0.2)'; this.style.borderColor='rgba(233, 84, 32, 0.6)'; this.style.boxShadow='0 6px 20px rgba(233, 84, 32, 0.3)';" onmouseout="this.style.transform='translateY(0) scale(1)'; this.style.background='rgba(30, 41, 59, 0.6)'; this.style.borderColor='rgba(255, 170, 0, 0.3)'; this.style.boxShadow='none';"><i class="fas fa-box" style="font-size: 14px; color: #fbbf24;"></i><span style="font-size: 12px; font-weight: 600; color: #e2e8f0;">Supplier</span></div> 2702 2703 <div class="context-badge" style="display: inline-flex; align-items: center; gap: 6px; padding: 8px 16px; background: rgba(30, 41, 59, 0.6); border: 1px solid rgba(255, 170, 0, 0.3); border-radius: 20px; transition: all 0.3s ease; cursor: pointer; white-space: nowrap; backdrop-filter: blur(10px);" onmouseover="this.style.transform='translateY(-2px) scale(1.05)'; this.style.background='rgba(233, 84, 32, 0.2)'; this.style.borderColor='rgba(233, 84, 32, 0.6)'; this.style.boxShadow='0 6px 20px rgba(233, 84, 32, 0.3)';" onmouseout="this.style.transform='translateY(0) scale(1)';
2703 this.style.background='rgba(30, 41, 59, 0.6)'; this.style.borderColor='rgba(255, 170, 0, 0.3)'; this.style.boxShadow='none';"><i class="fas fa-store" style="font-size: 14px; color: #fbbf24;"></i><span style="font-size: 12px; font-weight: 600; color: #e2e8f0;">Informal</span></div> 2704 2705 <div class="context-badge" style="display: inline-flex; align-items: center; gap: 6px; padding: 8px 16px; background: rgba(30, 41, 59, 0.6); border: 1px solid rgba(255, 170, 0, 0.3); border-radius: 20px; transition: all 0.3s ease; cursor: pointer; white-space: nowrap; backdrop-filter: blur(10px);" onmouseover="this.style.transform='translateY(-2px) scale(1.05)'; this.style.background='rgba(233, 84, 32, 0.2)'; this.style.borderColor='rgba(233, 84, 32, 0.6)'; this.style.boxShadow='0 6px 20px rgba(233, 84, 32, 0.3)';" onmouseout="this.style.transform='translateY(0) scale(1)'; this.style.background='rgba(30, 41, 59, 0.6)'; this.style.borderColor='rgba(255, 170, 0, 0.3)'; this.style.boxShadow='none';"><i class="fas fa-seedling" style="font-size: 14px; color: #fbbf24;"></i><span style="font-size: 12px; font-weight: 600; color: #e2e8f0;">Agricultural</span></div> 2706 2707 <div class="context-badge" style="display: inline-flex; align-items: center; gap: 6px; padding: 8px 16px;
2707 background: rgba(30, 41, 59, 0.6); border: 1px solid rgba(255, 170, 0, 0.3); border-radius: 20px; transition: all 0.3s ease; cursor: pointer; white-space: nowrap; backdrop-filter: blur(10px);" onmouseover="this.style.transform='translateY(-2px) scale(1.05)'; this.style.background='rgba(233, 84, 32, 0.2)'; this.style.borderColor='rgba(233, 84, 32, 0.6)'; this.style.boxShadow='0 6px 20px rgba(233, 84, 32, 0.3)';" onmouseout="this.style.transform='translateY(0) scale(1)'; this.style.background='rgba(30, 41, 59, 0.6)'; this.style.borderColor='rgba(255, 170, 0, 0.3)'; this.style.boxShadow='none';"><i class="fas fa-money-bill-wave" style="font-size: 14px; color: #fbbf24;"></i><span style="font-size: 12px; font-weight: 600; color: #e2e8f0;">Remittance</span></div> 2708 <div class="context-badge" style="display: inline-flex; align-items: center; gap: 6px; padding: 8px 16px; background: rgba(30, 41, 59, 0.6); border: 1px solid rgba(147, 197, 253, 0.35); border-radius: 20px; transition: all 0.3s ease; cursor: pointer; white-space: nowrap; backdrop-filter: blur(10px);" onmouseover="this.style.transform='translateY(-2px) scale(1.05)'; this.style.background='rgba(59, 130, 246, 0.18)'; this.style.borderColor='rgba(147, 197, 253, 0.65)'; this.style.boxShadow='0 6px 20px rgba(59, 130, 246, 0.25)';" onmouseout="this.style.transform='translateY(0) scale(1)';
2708 this.style.background='rgba(30, 41, 59, 0.6)'; this.style.borderColor='rgba(147, 197, 253, 0.35)'; this.style.boxShadow='none';"><i class="fas fa-graduation-cap" style="font-size: 14px; color: #93c5fd;"></i><span style="font-size: 12px; font-weight: 600; color: #e2e8f0;">Education</span></div> 2709 <div class="context-badge" style="display: inline-flex; align-items: center; gap: 6px; padding: 8px 16px; background: rgba(30, 41, 59, 0.6); border: 1px solid rgba(252, 165, 165, 0.35); border-radius: 20px; transition: all 0.3s ease; cursor: pointer; white-space: nowrap; backdrop-filter: blur(10px);" onmouseover="this.style.transform='translateY(-2px) scale(1.05)'; this.style.background='rgba(248, 113, 113, 0.15)'; this.style.borderColor='rgba(252, 165, 165, 0.65)'; this.style.boxShadow='0 6px 20px rgba(248, 113, 113, 0.22)';" onmouseout="this.style.transform='translateY(0) scale(1)'; this.style.background='rgba(30, 41, 59, 0.6)'; this.style.borderColor='rgba(252, 165, 165, 0.35)'; this.style.boxShadow='none';"><i class="fas fa-heart-pulse" style="font-size: 14px; color: #fca5a5;"></i><span style="font-size: 12px; font-weight: 600; color: #e2e8f0;">Health</span></div> 2710 <div class="context-badge" style="display: inline-flex; align-items: center; gap: 6px; padding: 8px 16px;
2710 background: rgba(30, 41, 59, 0.6); border: 1px solid rgba(251, 207, 232, 0.35); border-radius: 20px; transition: all 0.3s ease; cursor: pointer; white-space: nowrap; backdrop-filter: blur(10px);" onmouseover="this.style.transform='translateY(-2px) scale(1.05)'; this.style.background='rgba(244, 114, 182, 0.14)'; this.style.borderColor='rgba(251, 207, 232, 0.65)'; this.style.boxShadow='0 6px 20px rgba(244, 114, 182, 0.22)';" onmouseout="this.style.transform='translateY(0) scale(1)'; this.style.background='rgba(30, 41, 59, 0.6)'; this.style.borderColor='rgba(251, 207, 232, 0.35)'; this.style.boxShadow='none';"><i class="fas fa-people-roof" style="font-size: 14px; color: #fbcfe8;"></i><span style="font-size: 12px; font-weight: 600; color: #e2e8f0;">Family</span></div> 2711 <div class="context-badge" style="display: inline-flex; align-items: center; gap: 6px; padding: 8px 16px; background: rgba(30, 41, 59, 0.6); border: 1px solid rgba(167, 243, 208, 0.35); border-radius: 20px; transition: all 0.3s ease; cursor: pointer; white-space: nowrap; backdrop-filter: blur(10px);" onmouseover="this.style.transform='translateY(-2px) scale(1.05)'; this.style.background='rgba(52, 211, 153, 0.14)'; this.style.borderColor='rgba(167, 243, 208, 0.65)'; this.style.boxShadow='0 6px 20px rgba(52, 211, 153, 0.22)';" onmouseout="this.style.transform='translateY(0) scale(1)';
2711 this.style.background='rgba(30, 41, 59, 0.6)'; this.style.borderColor='rgba(167, 243, 208, 0.35)'; this.style.boxShadow='none';"><i class="fas fa-landmark" style="font-size: 14px; color: #a7f3d0;"></i><span style="font-size: 12px; font-weight: 600; color: #e2e8f0;">Civic</span></div> 2712 <div class="context-badge" style="display: inline-flex; align-items: center; gap: 6px; padding: 8px 16px; background: rgba(30, 41, 59, 0.6); border: 1px solid rgba(196, 181, 253, 0.35); border-radius: 20px; transition: all 0.3s ease; cursor: pointer; white-space: nowrap; backdrop-filter: blur(10px);" onmouseover="this.style.transform='translateY(-2px) scale(1.05)'; this.style.background='rgba(167, 139, 250, 0.16)'; this.style.borderColor='rgba(196, 181, 253, 0.65)'; this.style.boxShadow='0 6px 20px rgba(167, 139, 250, 0.22)';" onmouseout="this.style.transform='translateY(0) scale(1)'; this.style.background='rgba(30, 41, 59, 0.6)'; this.style.borderColor='rgba(196, 181, 253, 0.35)'; this.style.boxShadow='none';"><i class="fas fa-laptop-code" style="font-size: 14px; color: #c4b5fd;"></i><span style="font-size: 12px; font-weight: 600; color: #e2e8f0;">Digital</span></div> 2713 <div class="context-badge" style="display: inline-flex; align-items: center; gap: 6px; padding: 8px 16px;
2713 background: rgba(30, 41, 59, 0.6); border: 1px solid rgba(253, 230, 138, 0.35); border-radius: 20px; transition: all 0.3s ease; cursor: pointer; white-space: nowrap; backdrop-filter: blur(10px);" onmouseover="this.style.transform='translateY(-2px) scale(1.05)'; this.style.background='rgba(250, 204, 21, 0.12)'; this.style.borderColor='rgba(253, 230, 138, 0.65)'; this.style.boxShadow='0 6px 20px rgba(250, 204, 21, 0.2)';" onmouseout="this.style.transform='translateY(0) scale(1)'; this.style.background='rgba(30, 41, 59, 0.6)'; this.style.borderColor='rgba(253, 230, 138, 0.35)'; this.style.boxShadow='none';"><i class="fas fa-route" style="font-size: 14px; color: #fde68a;"></i><span style="font-size: 12px; font-weight: 600; color: #e2e8f0;">Mobility</span></div> 2714 <div class="context-badge" style="display: inline-flex; align-items: center; gap: 6px; padding: 8px 16px; background: rgba(30, 41, 59, 0.6); border: 1px solid rgba(254, 240, 138, 0.35); border-radius: 20px; transition: all 0.3s ease; cursor: pointer; white-space: nowrap; backdrop-filter: blur(10px);" onmouseover="this.style.transform='translateY(-2px) scale(1.05)'; this.style.background='rgba(234, 179, 8, 0.12)'; this.style.borderColor='rgba(254, 240, 138, 0.65)'; this.style.boxShadow='0 6px 20px rgba(234, 179, 8, 0.2)';" onmouseout="this.style.transform='translateY(0) scale(1)';
2714 this.style.background='rgba(30, 41, 59, 0.6)'; this.style.borderColor='rgba(254, 240, 138, 0.35)'; this.style.boxShadow='none';"><i class="fas fa-bolt" style="font-size: 14px; color: #fef08a;"></i><span style="font-size: 12px; font-weight: 600; color: #e2e8f0;">Utilities</span></div> 2715 <div class="context-badge" style="display: inline-flex; align-items: center; gap: 6px; padding: 8px 16px; background: rgba(30, 41, 59, 0.6); border: 1px solid rgba(251, 191, 36, 0.35); border-radius: 20px; transition: all 0.3s ease; cursor: pointer; white-space: nowrap; backdrop-filter: blur(10px);" onmouseover="this.style.transform='translateY(-2px) scale(1.05)'; this.style.background='rgba(245, 158, 11, 0.14)'; this.style.borderColor='rgba(251, 191, 36, 0.65)'; this.style.boxShadow='0 6px 20px rgba(245, 158, 11, 0.22)';" onmouseout="this.style.transform='translateY(0) scale(1)'; this.style.background='rgba(30, 41, 59, 0.6)'; this.style.borderColor='rgba(251, 191, 36, 0.35)'; this.style.boxShadow='none';"><i class="fas fa-palette" style="font-size: 14px; color: #fbbf24;"></i><span style="font-size: 12px; font-weight: 600; color: #e2e8f0;">Creative</span></div> 2716 <div class="context-badge" style="display: inline-flex; align-items: center; gap: 6px; padding: 8px 16px;
2716 background: rgba(30, 41, 59, 0.6); border: 1px solid rgba(254, 215, 170, 0.35); border-radius: 20px; transition: all 0.3s ease; cursor: pointer; white-space: nowrap; backdrop-filter: blur(10px);" onmouseover="this.style.transform='translateY(-2px) scale(1.05)'; this.style.background='rgba(251, 146, 60, 0.12)'; this.style.borderColor='rgba(254, 215, 170, 0.65)'; this.style.boxShadow='0 6px 20px rgba(251, 146, 60, 0.2)';" onmouseout="this.style.transform='translateY(0) scale(1)'; this.style.background='rgba(30, 41, 59, 0.6)'; this.style.borderColor='rgba(254, 215, 170, 0.35)'; this.style.boxShadow='none';"><i class="fas fa-handshake-angle" style="font-size: 14px; color: #fed7aa;" aria-hidden="true"></i><span style="font-size: 12px; font-weight: 600; color: #e2e8f0;">Faith & mutual aid</span></div> 2717 <div class="context-badge" style="display: inline-flex; align-items: center; gap: 6px; padding: 8px 16px; background: rgba(30, 41, 59, 0.6); border: 1px solid rgba(248, 113, 113, 0.35); border-radius: 20px; transition: all 0.3s ease; cursor: pointer; white-space: nowrap; backdrop-filter: blur(10px);" onmouseover="this.style.transform='translateY(-2px) scale(1.05)'; this.style.background='rgba(239, 68, 68, 0.12)'; this.style.borderColor='rgba(248, 113, 113, 0.65)'; this.style.boxShadow='0 6px 20px rgba(239, 68, 68, 0.22)';" onmouseout="this.style.transform='translateY(0) scale(1)';
2717 this.style.background='rgba(30, 41, 59, 0.6)'; this.style.borderColor='rgba(248, 113, 113, 0.35)'; this.style.boxShadow='none';"><i class="fas fa-shield-halved" style="font-size: 14px; color: #fca5a5;"></i><span style="font-size: 12px; font-weight: 600; color: #e2e8f0;">Risk & compliance</span></div> 2718 </div> 2719 </div> 2720 </div> 2721 </div> 2722 2723 <!-- Custom Animations for This Section --> 2724 <style> 2725 @keyframes fadeInUp { 2726 from { 2727 opacity: 0; 2728 transform: translateY(30px); 2729 } 2730 to { 2731 opacity: 1; 2732 transform: translateY(0); 2733 } 2734 } 2735 2736 @keyframes floatUp { 2737 0%, 100% { 2738 transform: translateY(0) scale(1); 2739 opacity: 0.4; 2740 } 2741 50% { 2742 transform: translateY(-40px) scale(1.15); 2743 opacity: 0.9; 2744 } 2745 } 2746 2747 @keyframes subtlePulse { 2748 0%, 100% { 2749 opacity: 0.4; 2750 } 2751 50% { 2752 opacity: 0.6; 2753 } 2754 } 2755 2756 @keyframes gentleGlow { 2757 0%, 100% { 2758 box-shadow: 0 0 20px rgba(255, 170, 0, 0.2); 2759 } 2760 50% { 2761 box-shadow: 0 0 30px rgba(255, 170, 0, 0.4); 2762 } 2763 } 2764 2765 /* Responsive Styles */ 2766 @media (max-width: 768px) { 2767 #whatIsTumiTrust { 2768 padding: 30px 20px !important; 2769 margin: 0 auto 40px !important; 2770 } 2771 2772 #whatIsTumiTrust > div { 2773 padding: 35px 24px !important; 2774 } 2775 2776 .value-prop-grid { 2777 grid-template-columns: 1fr !important; 2778 gap: 20px !important; 2779 } 2780 2781 #whatIsTumiTrust h2 { 2782 font-size: 26px !important; 2783 } 2784 2785 #whatIsTumiTrust h3 { 2786 font-size: 22px !important; 2787 } 2788 2789 .context-strip { 2790 margin: 0 -24px !important; 2791 padding: 8px 24px !important; 2792 } 2793 } 2794 </style> 2795 </section> 2796 2797
2797<script> 2798 // Animated Counter for Live Stats 2799 function animateCounter(element) { 2800 const target = parseInt(element.getAttribute('data-target')); 2801 const duration = 2000; // 2 seconds 2802 const increment = target / (duration / 16); // 60fps 2803 let current = 0; 2804 2805 const timer = setInterval(() => { 2806 current += increment; 2807 if (current >= target) { 2808 element.textContent = target.toLocaleString(); 2809 clearInterval(timer); 2810 } else { 2811 element.textContent = Math.floor(current).toLocaleString(); 2812 } 2813 }, 16); 2814 } 2815 2816 // Animate all counters when page loads 2817 window.addEventListener('load', () => { 2818 document.querySelectorAll('.counter[data-target]').forEach(counter => { 2819 animateCounter(counter); 2820 }); 2821 }); 2822 2823 // Live platform stats are polled from /api/v1/platform/network-stats/ in landing_infrastructure_section.html 2824 </script>
2824 2825 2826 <!-- TUMITRUST PLATFORM - product depth (follows PTI spec above) --> 2827 <section id="tumitrustPlatform" class="py-20 px-4 relative" style="z-index: 50; position: relative;"> 2828 <div class="container mx-auto max-w-6xl"> 2829 <div class="text-center mb-16"> 2830 <div class="inline-flex items-center gap-2 px-5 py-2 bg-gradient-to-r from-orange-500/20 to-amber-500/20 border border-orange-500/30 rounded-full mb-6"> 2831 <img src="/static/img/logo-dark.d5385145e919.svg" alt="" class="w-5 h-5" aria-hidden="true"> 2832 <span class="text-orange-400 font-semibold">TumiTrust · reference implementation</span> 2833 </div> 2834 <h2 class="text-4xl md:text-5xl lg:text-6xl font-black mb-6"> 2835 <span class="holographic-text">The platform built on PTI</span> 2836 </h2> 2837 <p class="text-lg md:text-xl text-gray-300 max-w-3xl mx-auto mb-4 leading-relaxed"> 2838 Product surface for the open standard: Trust CV, context-scoped lookups, partner connectors, and optional screening - 2839 <a href="/docs/tumitrust/product-overview/" class="tt-public-docs-link text-amber-300">how the product works â</a> 2840 </p> 2841 </div> 2842 2843 <!-- HOW WE STACK UP - Comparison Section --> 2844 <div class="mt-20"> 2845 <div class="text-center mb-12"> 2846 <div class="inline-flex items-center gap-2 px-5 py-2 bg-gradient-to-r from-orange-500/20 to-amber-500/20 border border-orange-500/30 rounded-full mb-6"> 2847 <i class="fas fa-chart-line text-orange-400"></i> 2848 <span class="text-orange-400 font-semibold">How We Stack Up</span> 2849 </div> 2850 <h2 class="text-4xl md:text-5xl font-black text-white mb-4"> 2851 <span class="holographic-text">TumiTrust vs. Traditional Systems</span> 2852 </h2> 2853 <p class="text-lg text-gray-300 max-w-2xl mx-auto"> 2854 One map. 20+ contexts. <a href="/docs/tumitrust/platform/partner-trust-contexts" class="tt-public-docs-link text-amber-400">Why it matters â</a> 2855 </p> 2856 </div> 2857 2858 <!-- Comparison Table --> 2859 <div class="max-w-6xl mx-auto"> 2860 <div class="gradient-border rounded-2xl overflow-hidden"> 2861 <div class="overflow-x-auto"> 2862 <table class="w-full"> 2863 <thead> 2864 <tr class="bg-gradient-to-r from-slate-800/80 to-slate-900/80 border-b border-white/10"> 2865 <th class="px-6 py-4 text-left text-sm font-bold text-white uppercase tracking-wider">Feature</th> 2866 <th class="px-6 py-4 text-center text-sm font-bold text-orange-400 uppercase tracking-wider"> 2867 <div class="flex items-center justify-center gap-2"> 2868 <i class="fas fa-star text-amber-400"></i> 2869 <span>TumiTrust</span> 2870 </div> 2871 </th> 2872 <th class="px-6 py-4 text-center text-sm font-bold text-gray-400 uppercase tracking-wider">Legacy credit files</th> 2873 <th class="px-6 py-4 text-center text-sm font-bold text-gray-400 uppercase tracking-wider">Other Platforms</th> 2874 </tr> 2875 </thead> 2876 <tbody class="divide-y divide-white/5"> 2877 <!-- Trust Contexts --> 2878 <tr class="hover:bg-white/5 transition-colors"> 2879 <td class="px-6 py-5 text-gray-300 font-semibold"> 2880 <div class="flex items-center gap-2"> 2881 <i class="fas fa-layer-group text-orange-400"></i>
2882 <span>Trust Contexts Covered</span> 2883 </div> 2884 </td> 2885 <td class="px-6 py-5 text-center"> 2886 <span class="inline-flex items-center gap-2 px-3 py-1 bg-gradient-to-r from-orange-500/20 to-amber-500/20 border border-orange-500/30 rounded-full text-green-400 font-bold"> 2887 <i class="fas fa-check-circle"></i> 2888 20+ contexts 2889 </span> 2890 </td> 2891 <td class="px-6 py-5 text-center text-gray-400">1-2 (Lending only)</td> 2892 <td class="px-6 py-5 text-center text-gray-400">1-3 contexts</td> 2893 </tr> 2894 2895 <!-- Data Sources --> 2896 <tr class="hover:bg-white/5 transition-colors"> 2897 <td class="px-6 py-5 text-gray-300 font-semibold"> 2898 <div class="flex items-center gap-2"> 2899 <i class="fas fa-database text-cyan-400"></i> 2900 <span>Data Sources</span> 2901 </div> 2902 </td> 2903 <td class="px-6 py-5 text-center"> 2904 <span class="text-green-400 font-semibold">Community endorsements, verified activities, mobile money, savings groups, rental history, employment, partnerships, & more</span> 2905 </td> 2906 <td class="px-6 py-5 text-center text-gray-400">Bank accounts & formal credit only</td> 2907 <td class="px-6 py-5 text-center text-gray-400">Limited to specific sectors</td> 2908 </tr> 2909 2910 <!-- Accessibility --> 2911 <tr class="hover:bg-white/5 transition-colors"> 2912 <td class="px-6 py-5 text-gray-300 font-semibold"> 2913 <div class="flex items-center gap-2"> 2914 <i class="fas fa-users text-purple-400"></i> 2915 <span>Who Can Build a Score</span> 2916 </div> 2917 </td> 2918 <td class="px-6 py-5 text-center"> 2919 <span class="inline-flex items-center gap-2 px-3 py-1 bg-gradient-to-r from-green-500/20 to-emerald-500/20 border border-green-500/30 rounded-full text-green-400 font-bold"> 2920 <i class="fas fa-check-circle"></i> 2921 Everyone 2922 </span> 2923 </td> 2924 <td class="px-6 py-5 text-center text-gray-400">Requires bank account & credit history</td> 2925 <td class="px-6 py-5 text-center text-gray-400">Limited eligibility</td> 2926 </tr> 2927 2928 <!-- Cost for Users --> 2929 <tr class="hover:bg-white/5 transition-colors"> 2930 <td class="px-6 py-5 text-gray-300 font-semibold"> 2931 <div class="flex items-center gap-2"> 2932 <i class="fas fa-dollar-sign text-yellow-400"></i>
2933 <span>Cost to Build Score</span> 2934 </div> 2935 </td> 2936 <td class="px-6 py-5 text-center"> 2937 <span class="inline-flex items-center gap-2 px-3 py-1 bg-gradient-to-r from-green-500/20 to-emerald-500/20 border border-green-500/30 rounded-full text-green-400 font-bold text-lg"> 2938 <i class="fas fa-gift"></i> 2939 100% FREE 2940 </span> 2941 </td> 2942 <td class="px-6 py-5 text-center text-gray-400">Fees for reports & access</td> 2943 <td class="px-6 py-5 text-center text-gray-400">Subscription fees</td> 2944 </tr> 2945 2946 <!-- Who can buy trust reports --> 2947 <tr class="hover:bg-white/5 transition-colors"> 2948 <td class="px-6 py-5 text-gray-300 font-semibold"> 2949 <div class="flex items-center gap-2"> 2950 <i class="fas fa-magnifying-glass-chart text-violet-400"></i> 2951 <span>Who can run trust lookups</span> 2952 </div> 2953 </td> 2954 <td class="px-6 py-5 text-center"> 2955 <span class="text-green-400 font-semibold">Individuals (in-app) and organisations (dashboard/API)-same underlying trust signals</span> 2956 </td> 2957 <td class="px-6 py-5 text-center text-gray-400">Typically lenders only</td> 2958 <td class="px-6 py-5 text-center text-gray-400">Varies; often org-only or narrow use</td> 2959 </tr> 2960 2961 <!-- Philosophy --> 2962 <tr class="hover:bg-white/5 transition-colors"> 2963 <td class="px-6 py-5 text-gray-300 font-semibold"> 2964 <div class="flex items-center gap-2"> 2965 <i class="fas fa-heart text-red-400"></i> 2966 <span>Philosophy</span> 2967 </div> 2968 </td> 2969 <td class="px-6 py-5 text-center"> 2970 <span class="text-orange-400 font-semibold">Portable trust - community trust</span> 2971 </td> 2972 <td class="px-6 py-5 text-center text-gray-400">Individual financial history</td> 2973 <td class="px-6 py-5 text-center text-gray-400">Varies by platform</td> 2974 </tr> 2975 2976 <!-- Real-time Updates --> 2977 <tr class="hover:bg-white/5 transition-colors"> 2978 <td class="px-6 py-5 text-gray-300 font-semibold"> 2979 <div class="flex items-center gap-2"> 2980 <i class="fas fa-bolt text-yellow-400"></i> 2981 <span>Score Updates</span> 2982 </div> 2983 </td> 2984 <td class="px-6 py-5 text-center">
2985 <span class="inline-flex items-center gap-2 px-3 py-1 bg-gradient-to-r from-cyan-500/20 to-blue-500/20 border border-cyan-500/30 rounded-full text-cyan-400 font-bold"> 2986 <i class="fas fa-sync-alt animate-spin"></i> 2987 Real-time 2988 </span> 2989 </td> 2990 <td class="px-6 py-5 text-center text-gray-400">Monthly/quarterly updates</td> 2991 <td class="px-6 py-5 text-center text-gray-400">Delayed updates</td> 2992 </tr> 2993 2994 <!-- Trust lookups --> 2995 <tr class="hover:bg-white/5 transition-colors"> 2996 <td class="px-6 py-5 text-gray-300 font-semibold"> 2997 <div class="flex items-center gap-2"> 2998 <i class="fas fa-file-alt text-blue-400"></i> 2999 <span>Trust lookups for decisions</span> 3000 </div> 3001 </td> 3002 <td class="px-6 py-5 text-center"> 3003 <span class="inline-flex items-center gap-2 px-3 py-1 bg-gradient-to-r from-orange-500/20 to-amber-500/20 border border-orange-500/30 rounded-full text-green-400 font-bold"> 3004 <i class="fas fa-check-circle"></i> 3005 Yes, 20-context coverage 3006 </span> 3007 </td> 3008 <td class="px-6 py-5 text-center text-gray-400">Lending context only</td> 3009 <td class="px-6 py-5 text-center text-gray-400">Limited contexts</td> 3010 </tr> 3011 3012 <!-- Network Effect --> 3013 <tr class="hover:bg-white/5 transition-colors"> 3014 <td class="px-6 py-5 text-gray-300 font-semibold"> 3015 <div class="flex items-center gap-2"> 3016 <i class="fas fa-project-diagram text-purple-400"></i> 3017 <span>Community Network Value</span> 3018 </div> 3019 </td> 3020 <td class="px-6 py-5 text-center"> 3021 <span class="text-green-400 font-semibold">Endorsements from your network strengthen your score</span> 3022 </td> 3023 <td class="px-6 py-5 text-center text-gray-400">No network effect</td> 3024 <td class="px-6 py-5 text-center text-gray-400">Limited or none</td> 3025 </tr> 3026 3027 <!-- Mobile Money Integration --> 3028 <tr class="hover:bg-white/5 transition-colors"> 3029 <td class="px-6 py-5 text-gray-300 font-semibold"> 3030 <div class="flex items-center gap-2"> 3031 <i class="fas fa-mobile-alt text-pink-400"></i> 3032 <span>Mobile Money & Informal Economy</span> 3033 </div> 3034 </td> 3035 <td class="px-6 py-5 text-center">
3036 <span class="inline-flex items-center gap-2 px-3 py-1 bg-gradient-to-r from-green-500/20 to-emerald-500/20 border border-green-500/30 rounded-full text-green-400 font-bold"> 3037 <i class="fas fa-check-circle"></i> 3038 Fully Integrated 3039 </span> 3040 </td> 3041 <td class="px-6 py-5 text-center text-gray-400">Not recognized</td> 3042 <td class="px-6 py-5 text-center text-gray-400">Partial support</td> 3043 </tr> 3044 </tbody> 3045 </table> 3046 </div> 3047 </div> 3048 3049 </div> 3050 </div> 3051 3052 </div> 3053 </section> 3054 3055 <!-- LIVE IMPACT FEED --> 3056 <section class="py-20 px-4 relative" style="z-index: 50; position: relative;"> 3057 <div class="container mx-auto"> 3058 <!-- Real-time activity ticker --> 3059 <div class="tt-motion-strip gradient-border rounded-2xl overflow-hidden mb-12"> 3060 <div class="tt-motion-strip__head"> 3061 <div class="tt-motion-strip__head-left"> 3062 <span class="tt-motion-strip__pulse" aria-hidden="true"></span> 3063 <div> 3064 <p class="tt-motion-strip__eyebrow mb-0">
3064Live infrastructure</p> 3065 <h3 class="tt-motion-strip__title mb-0">Portable trust, in motion</h3> 3066 </div> 3067 </div> 3068 <span class="tt-motion-strip__badge">LIVE</span> 3069 </div> 3070 3071 3072 3073 3074<div 3075 class="tt-landing-stats" 3076 data-tt-landing-infra 3077 data-stats-url="/api/v1/platform/network-stats/" 3078 aria-label="Live platform infrastructure metrics" 3079> 3080 <div class="tt-landing-stats__glow" aria-hidden="true"></div> 3081 <p class="tt-landing-stats__note"> 3082 Live from platform telemetry - trust computations, report lookups, and onboarded entities update every 30s. 3083 </p> 3084 <div class="tt-landing-stats__flux"> 3085 <div class="tt-landing-stat tt-landing-stat--compute"> 3086 <span class="tt-landing-stat__value" data-tt-landing-metric="trust_computations_mtd">7</span> 3087 <span class="tt-landing-stat__label">Trust computations</span> 3088 <span class="tt-landing-stat__hint">MTD</span> 3089 </div> 3090 <div class="tt-landing-stat tt-landing-stat--lookups"> 3091 <span class="tt-landing-stat__value" data-tt-landing-metric="report_lookups_mtd">0</span> 3092 <span class="tt-landing-stat__label">Report lookups</span> 3093 <span class="tt-landing-stat__hint">MTD</span> 3094 </div> 3095 <div class="tt-landing-stat tt-landing-stat--entities"> 3096 <span class="tt-landing-stat__value" data-tt-landing-metric="entities_onboarded">12</span> 3097 <span class="tt-landing-stat__label">Entities onboarded</span> 3098 </div> 3099 <div class="tt-landing-stat tt-landing-stat--partners"> 3100 <span class="tt-landing-stat__value" data-tt-landing-metric="partners_active">3</span> 3101 <span class="tt-landing-stat__label">Partners</span> 3102 </div> 3103 <div class="tt-landing-stat tt-landing-stat--contexts"> 3104 <span class="tt-landing-stat__value" data-tt-landing-metric="trust_contexts">20</span> 3105 <span class="tt-landing-stat__label">Contexts</span> 3106 <span class="tt-landing-stat__hint">10 primaries + 10 lenses</span> 3107 </div> 3108 </div> 3109</div> 3110 3111 3112<style> 3113.tt-landing-stats { 3114 position: relative; 3115 padding: 1.1rem 1.25rem 0.95rem; 3116 background: transparent; 3117 border-bottom: 1px solid rgba(255, 255, 255, 0.06); 3118 overflow: hidden; 3119} 3120.tt-landing-stats__note { 3121 position: relative; 3122 z-index: 1; 3123 margin: 0 auto 0.65rem; 3124 max-width: 52rem; 3125 text-align: center; 3126 font-size: 0.68rem; 3127 letter-spacing: 0.04em; 3128 color: rgba(203, 213, 225, 0.65); 3129} 3130.tt-landing-stats__glow { 3131 position: absolute; 3132 inset: 0; 3133 pointer-events: none; 3134 background: linear-gradient(90deg, rgba(52, 211, 153, 0.08), rgba(96, 165, 250, 0.06), rgba(251, 146, 60, 0.08)); 3135 opacity: 0.9; 3136} 3137.tt-landing-stats__flux { 3138 position: relative; 3139 z-index: 1; 3140 display: flex; 3141 align-items: stretch; 3142 justify-content: space-between; 3143 gap: 0.5rem; 3144 flex-wrap: wrap; 3145 max-width: 52rem; 3146 margin: 0 auto; 3147} 3148.tt-landing-stat { 3149 flex: 1 1 7rem; 3150 min-width: 5.5rem; 3151 text-align: center; 3152 padding: 0.25rem 0.35rem; 3153 background: transparent; 3154 border: none; 3155} 3156.tt-landing-stat__value { 3157 display: block; 3158 font-size: clamp(1.45rem, 2.8vw, 2rem); 3159 font-weight: 800; 3160 line-height: 1; 3161 font-variant-numeric: tabular-nums; 3162 letter-spacing: -0.02em; 3163 transition: transform 0.35s ease; 3164} 3165.tt-landing-stat:hover .tt-landing-stat__value { 3166 transform: translateY(-2px); 3167} 3168.tt-landing-stat__label { 3169 display: block; 3170 margin-top: 0.35rem; 3171 font-size: 0.62rem; 3172 font-weight: 700; 3173 letter-spacing: 0.14em; 3174 text-transform: uppercase; 3175 color: rgba(203, 213, 225, 0.72); 3176} 3177.tt-landing-stat__hint { 3178 display: block; 3179 margin-top: 0.15rem; 3180 font-size: 0.58rem; 3181 font-weight: 600; 3182 letter-spacing: 0.08em; 3183 text-transform: uppercase; 3184 color: rgba(148, 163, 184, 0.75); 3185} 3186.tt-landing-stat--partners .tt-landing-stat__value { color: #6ee7b7; text-shadow: 0 0 28px rgba(52, 211, 153, 0.35); } 3187.tt-landing-stat--entities .tt-landing-stat__value { color: #93c5fd; text-shadow: 0 0 28px rgba(96, 165, 250, 0.32); } 3188.tt-landing-stat--contexts .tt-landing-stat__value { color: #fcd34d; text-shadow: 0 0 28px rgba(251, 191, 36, 0.32); } 3189.tt-landing-stat--compute .tt-landing-stat__value { color: #c4b5fd; text-shadow: 0 0 28px rgba(167, 139, 250, 0.32); } 3190.tt-landing-stat--lookups .tt-landing-stat__value { color: #fdba74; text-shadow: 0 0 28px rgba(251, 146, 60, 0.35); } 3191.tt-landing-stat__value.is-animating { 3192 animation: tt-landing-stats-pop 0.55s cubic-bezier(0.22, 1, 0.36, 1); 3193} 3194@keyframes tt-landing-stats-pop { 3195 0% { transform: scale(0.9); opacity: 0.55; } 3196 60% { transform: scale(1.05); } 3197 100% { transform: scale(1); opacity: 1; } 3198} 3199@media (max-width: 640px) { 3200 .tt-landing-stats__flux { 3201 display: grid; 3202 grid-template-columns: repeat(2, minmax(0, 1fr)); 3203 gap: 0.65rem; 3204 } 3205 .tt-landing-stat:last-child { 3206 grid-column: 1 / -1; 3207 } 3208} 3209@media (prefers-reduced-motion: reduce) { 3210 .tt-landing-stat__value.is-animating { animation: none; } 3211 .tt-landing-stat:hover .tt-landing-stat__value { transform: none; } 3212} 3213</style> 3214
3215<script> 3216(function () { 3217 function animateLandingCounter(el, target) { 3218 if (!el || !isFinite(target)) return; 3219 if (window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches) { 3220 el.textContent = Number.isInteger(target) ? target.toLocaleString() : target.toFixed(1); 3221 return; 3222 } 3223 var start = parseFloat(String(el.textContent).replace(/,/g, '')); 3224 if (!isFinite(start)) start = 0; 3225 var t0 = Date.now(); 3226 el.classList.add('is-animating'); 3227 (function tick() { 3228 var p = Math.min((Date.now() - t0) / 900, 1); 3229 var eased = 1 - Math.pow(1 - p, 3); 3230 var val = start + (target - start) * eased; 3231 el.textContent = Number.isInteger(target) ? Math.round(val).toLocaleString() : val.toFixed(1); 3232 if (p < 1) requestAnimationFrame(tick); 3233 else el.classList.remove('is-animating'); 3234 })(); 3235 } 3236 3237 function applyStats(payload) { 3238 if (!payload) return; 3239 var stats = payload.raw || payload; 3240 document.querySelectorAll('[data-tt-landing-metric]').forEach(function (el) { 3241 var key = el.getAttribute('data-tt-landing-metric'); 3242 if (!key || stats[key] == null) return; 3243 animateLandingCounter(el, Number(stats[key])); 3244 }); 3245 } 3246 3247 function poll() { 3248 var root = document.querySelector('[data-tt-landing-infra]'); 3249 if (!root) return; 3250 fetch(root.getAttribute('data-stats-url') || '/api/v1/platform/network-stats/', { headers: { 'Accept': 'application/json' } }) 3251 .then(function (r) { return r.json(); }) 3252 .then(applyStats) 3253 .catch(function () {}); 3254 } 3255 3256 document.addEventListener('DOMContentLoaded', function () { 3257 poll(); 3258 setInterval(poll, 30000); 3259 }); 3260})(); 3261</script>
3261 3262 3263 3264 3265<section class="tt-arch-teaser tt-arch-showcase--dark" aria-label="Integration flow"> 3266 <p class="tt-arch-teaser__kicker">PTI architecture</p> 3267 <p class="tt-arch-teaser__tagline">Partner â Events â PTI Core â Trust intelligence â Your decision</p> 3268 <ol class="tt-arch-flow tt-arch-flow--compact"> 3269 <li><span>Integrate</span></li> 3270 <li><span>Trust lookup</span></li> 3271 <li><span>Contexts</span></li> 3272 <li><span>Intelligence</span></li> 3273 <li class="tt-arch-flow__decision"><span>Decision</span></li> 3274 </ol> 3275 <div class="tt-arch-teaser__cta"> 3276 <a href="/platform/" class="tt-enterprise-btn tt-enterprise-btn--primary" style="font-size:0.8rem;">Platform</a> 3277 <a href="/docs/tumitrust/product-overview/architecture" class="tt-enterprise-btn tt-enterprise-btn--secondary" style="font-size:0.8rem;">Architecture guide</a> 3278 <a href="/docs/tumitrust/product-overview/company-portfolio" class="tt-enterprise-btn tt-enterprise-btn--secondary" style="font-size:0.8rem;">Portfolio</a> 3279 </div> 3280</section> 3281 3282 3283 <div class="tt-motion-strip__ticker"> 3284 <div class="absolute inset-0 bg-gradient-to-r from-transparent via-white/5 to-transparent animate-shimmer"></div> 3285 <div class="ticker-wrap relative"> 3286 <div class="ticker flex items-center gap-12" id="activityTicker"> 3287 <!-- Items will be duplicated by JS for seamless loop --> 3288 <div class="ticker-item flex items-center gap-2 whitespace-nowrap"> 3289 <i class="fas fa-file-contract text-amber-300"></i> 3290 <span class="text-white"><span class="font-bold text-amber-300">Lookups in hand</span> - Basic · Detailed · Predictive</span> 3291 </div> 3292 <div class="ticker-item flex items-center gap-2 whitespace-nowrap"> 3293 <i class="fas fa-bolt text-yellow-400 animate-pulse"></i> 3294 <span class="text-white"><span class="font-bold text-cyan-400">Portable trust</span> - one profile, many doors</span> 3295 </div> 3296 <div class="ticker-item flex items-center gap-2 whitespace-nowrap"> 3297 <i class="fas fa-users text-cyan-400"></i> 3298 <span class="text-white"><span class="font-bold text-green-400">Earn</span> and <span class="font-bold text-green-400">verify</span> - same profile</span> 3299 </div> 3300 <div class="ticker-item flex items-center gap-2 whitespace-nowrap"> 3301 <i class="fas fa-handshake text-green-400"></i> 3302 <span class="text-white">Endorsements + badges - share proof in a tap</span> 3303 </div> 3304 <div class="ticker-item flex items-center gap-2 whitespace-nowrap"> 3305 <i class="fas fa-building text-purple-400"></i> 3306 <span class="text-white">Lenders, landlords, employers - <span class="font-bold text-purple-400">same rails</span></span> 3307 </div> 3308 <div class="ticker-item flex items-center gap-2 whitespace-nowrap"> 3309 <i class="fas fa-chart-line text-orange-400"></i> 3310 <span class="text-white"><span class="font-bold text-yellow-400">20 contexts</span> - one map</span> 3311 </div> 3312 <div class="ticker-item flex items-center gap-2 whitespace-nowrap"> 3313 <i class="fas fa-mobile-alt text-pink-400"></i> 3314 <span class="text-white"><span class="font-bold text-pink-400">Daily rhythm</span> - endorse, prep, decide</span> 3315 </div> 3316 <div class="ticker-item flex items-center gap-2 whitespace-nowrap"> 3317 <i class="fas fa-trophy text-amber-400 animate-pulse"></i>
3318 <span class="text-white">Ubuntu: <span class="font-bold text-amber-400">âI am because we areâ</span> - trust is community-powered</span> 3319 </div> 3320 <div class="ticker-item flex items-center gap-2 whitespace-nowrap"> 3321 <i class="fas fa-arrow-trend-up text-purple-400"></i> 3322 <span class="text-white">QR or report - <span class="font-bold text-purple-400">your score</span>, not one gatekeeper</span> 3323 </div> 3324 <div class="ticker-item flex items-center gap-2 whitespace-nowrap"> 3325 <i class="fas fa-users-line text-cyan-400"></i> 3326 <span class="text-white">Portable trust - community to formal rails, anywhere</span> 3327 </div> 3328 </div> 3329 </div> 3330 </div> 3331 </div> 3332 3333 <style> 3334 /* Motion strip - glass card + flowing stats */ 3335 .tt-motion-strip.gradient-border { 3336 background: linear-gradient( 3337 155deg, 3338 rgba(15, 23, 42, 0.72) 0%,
3339 rgba(30, 41, 59, 0.58) 48%, 3340 rgba(17, 24, 39, 0.68) 100% 3341 ); 3342 backdrop-filter: blur(22px); 3343 -webkit-backdrop-filter: blur(22px); 3344 box-shadow: 3345 0 28px 70px rgba(0, 0, 0, 0.38), 3346 inset 0 1px 0 rgba(255, 255, 255, 0.07); 3347 } 3348 .tt-motion-strip.gradient-border::before { 3349 opacity: 0.85; 3350 } 3351 .tt-motion-strip__head { 3352 display: flex; 3353 align-items: center; 3354 justify-content: space-between; 3355 gap: 1rem; 3356 flex-wrap: wrap; 3357 padding: 1rem 1.25rem; 3358 border-bottom: 1px solid rgba(255, 255, 255, 0.06); 3359 background: linear-gradient( 3360 90deg, 3361 rgba(16, 185, 129, 0.08), 3362 rgba(59, 130, 246, 0.06), 3363 rgba(251, 146, 60, 0.07) 3364 ); 3365 } 3366 .tt-motion-strip__head-left { 3367 display: flex; 3368 align-items: center; 3369 gap: 0.75rem; 3370 min-width: 0; 3371 } 3372 .tt-motion-strip__pulse { 3373 width: 0.55rem; 3374 height: 0.55rem; 3375 border-radius: 50%; 3376 background: #34d399; 3377 box-shadow: 0 0 0 4px rgba(52, 211, 153, 0.22); 3378 animation: tt-motion-pulse 1.8s ease-in-out infinite; 3379 flex-shrink: 0; 3380 } 3381 @keyframes tt-motion-pulse { 3382 0%, 100% { opacity: 1; transform: scale(1); } 3383 50% { opacity: 0.7; transform: scale(1.12); } 3384 } 3385 .tt-motion-strip__eyebrow { 3386 font-size: 0.62rem; 3387 font-weight: 700; 3388 letter-spacing: 0.16em; 3389 text-transform: uppercase; 3390 color: rgba(251, 191, 36, 0.82); 3391 } 3392 .tt-motion-strip__title { 3393 font-size: clamp(1.05rem, 2vw, 1.25rem); 3394 font-weight: 800; 3395 color: #f8fafc; 3396 letter-spacing: -0.02em; 3397 } 3398 .tt-motion-strip__badge { 3399 display: inline-flex; 3400 align-items: center; 3401 padding: 0.32rem 0.8rem; 3402 border-radius: 999px; 3403 font-size: 0.65rem; 3404 font-weight: 800; 3405 letter-spacing: 0.1em; 3406 color: #6ee7b7; 3407 background: rgba(16, 185, 129, 0.12); 3408 border: 1px solid rgba(52, 211, 153, 0.28); 3409 } 3410 .tt-motion-strip__ticker { 3411 position: relative; 3412 padding: 1rem 0; 3413 overflow: hidden; 3414 background: linear-gradient( 3415 90deg, 3416 rgba(251, 146, 60, 0.06), 3417 rgba(167, 139, 250, 0.05), 3418 rgba(34, 211, 238, 0.06) 3419 ); 3420 } 3421 @keyframes shimmer { 3422 0% { transform: translateX(-100%); } 3423 100% { transform: translateX(100%); } 3424 } 3425 .animate-shimmer { 3426 animation: shimmer 3s infinite; 3427 } 3428 .ticker-wrap { 3429 width: 100%; 3430 overflow: hidden; 3431 } 3432 .ticker { 3433 display: inline-flex; 3434 white-space: nowrap; 3435 animation: ticker 45s linear infinite; 3436 } 3437 @keyframes ticker { 3438 0% { transform: translate3d(0, 0, 0); } 3439 100% { transform: translate3d(-50%, 0, 0); } 3440 } 3441 .ticker-item { 3442 display: inline-flex; 3443 padding: 0 2rem; 3444 } 3445 </style> 3446 3447
3447<script> 3448 // Duplicate ticker items for seamless loop 3449 const ticker = document.getElementById('activityTicker'); 3450 if (ticker) { 3451 const items = ticker.innerHTML; 3452 ticker.innerHTML = items + items; // Duplicate for seamless loop 3453 } 3454 3455 // Ticker copy is factual - no fake âliveâ counters (badges use real API counts in the app). 3456 </script>
3456 3457 3458 </div> 3459 </section> 3460 3461 3462 3463 <!-- UBUNTU IN ACTION - Animated Visualization --> 3464 <section class="py-20 px-4 relative overflow-hidden" style="z-index: 50; position: relative;"> 3465 <!-- Animated Background Particles --> 3466 <div class="absolute inset-0 pointer-events-none opacity-30"> 3467 <canvas id="ubuntuCanvas" class="w-full h-full"></canvas> 3468 </div> 3469 3470 <div class="container mx-auto relative z-10"> 3471 <div class="text-center mb-16"> 3472 <div class="inline-flex items-center gap-2 px-5 py-2 bg-gradient-to-r from-orange-500/20 to-amber-500/20 border border-orange-500/30 rounded-full mb-6"> 3473 <i class="fas fa-play-circle text-orange-400"></i> 3474 <span class="text-orange-400 font-semibold">Ubuntu Philosophy in Motion</span> 3475 </div> 3476 <h2 class="text-5xl md:text-6xl font-black mb-6"> 3477 <span class="holographic-text">Portable Trust Infrastructure in Action</span> 3478 </h2> 3479 <p class="text-2xl text-gray-300 max-w-3xl mx-auto mb-4"> 3480 <em class="text-orange-400 font-bold">Portable trust</em> 3481 </p> 3482 <p class="text-lg text-gray-400 max-w-3xl mx-auto"> 3483 See how trust moves: <strong class="text-gray-300">build</strong> it, <strong class="text-gray-300">use</strong> it - <a href="/docs/tumitrust/platform/partner-trust-contexts" class="tt-public-docs-link text-amber-400 font-semibold">20 contexts</a>. 3484 </p> 3485 </div> 3486 3487 <!-- Interactive Animation Area --> 3488 <div class="max-w-6xl mx-auto"> 3489 <div class="gradient-border rounded-3xl p-8 md:p-12 bg-gradient-to-br from-orange-900/20 to-amber-900/20 backdrop-blur-xl" style="background-image: linear-gradient(135deg, rgba(120, 53, 15, 0.3) 0%, rgba(146, 64, 14, 0.25) 50%, rgba(180, 83, 9, 0.2) 100%);"> 3490 <!-- Animation Canvas --> 3491 <div class="relative" style="height: 600px;"> 3492 <canvas id="trustFlowCanvas" class="w-full h-full rounded-2xl" style="background: linear-gradient(135deg, rgba(20, 14, 10, 0.6) 0%, rgba(30, 20, 15, 0.5) 100%);"></canvas> 3493 3494 <!-- Overlay Controls --> 3495 <div class="absolute top-4 right-4 flex gap-2 z-20"> 3496 <button onclick="pauseAnimation()" id="pauseBtn" class="px-4 py-2 bg-slate-700/80 hover:bg-slate-600 border border-slate-500 rounded-xl text-white font-semibold transition-all flex items-center gap-2"> 3497 <i class="fas fa-pause"></i> 3498 <span>Pause</span> 3499 </button> 3500 <button onclick="restartAnimation()" class="px-4 py-2 bg-orange-500/80 hover:bg-orange-600 border border-orange-400 rounded-xl text-white font-semibold transition-all flex items-center gap-2"> 3501 <i class="fas fa-redo"></i> 3502 <span>Restart</span> 3503 </button> 3504 </div> 3505 </div> 3506 3507 <!-- Info Panel - Moved Outside Canvas --> 3508 <div class="mt-4 bg-slate-900/90 backdrop-blur-md border border-slate-700 rounded-xl p-4"> 3509 <div class="flex items-center justify-between flex-wrap gap-4"> 3510 <div class="flex items-center gap-6"> 3511 <div class="flex items-center gap-2"> 3512 <div class="w-4 h-4 bg-gradient-to-r from-blue-400 to-cyan-400 rounded-full"></div> 3513 <span class="text-sm text-gray-300">User</span> 3514 </div> 3515 <div class="flex items-center gap-2"> 3516 <div class="w-4 h-4 bg-gradient-to-r from-orange-400 to-amber-400 rounded-full"></div>
3517 <span class="text-sm text-gray-300">Endorsement</span> 3518 </div> 3519 <div class="flex items-center gap-2"> 3520 <div class="w-4 h-4 bg-gradient-to-r from-green-400 to-emerald-400 rounded-full animate-pulse"></div> 3521 <span class="text-sm text-gray-300">Score Boost</span> 3522 </div> 3523 </div> 3524 <div class="text-right"> 3525 <div class="text-2xl font-black text-transparent bg-clip-text bg-gradient-to-r from-orange-400 to-amber-400" id="networkScore">750</div> 3526 <div class="text-xs text-gray-400">Illustrative journey (interactive preview)</div> 3527 </div> 3528 </div> 3529 </div> 3530 3531 <!-- Story Narration --> 3532 <div class="mt-8 space-y-4" id="storyNarration"> 3533 <div class="flex items-start gap-4 p-4 bg-blue-500/10 border border-blue-500/20 rounded-xl opacity-0 story-step" data-step="1"> 3534 <div class="w-10 h-10 bg-gradient-to-br from-blue-500 to-cyan-600 rounded-full flex items-center justify-center text-white font-bold flex-shrink-0">1</div> 3535 <div> 3536 <p class="text-white font-semibold">Nandi joins TumiTrust</p> 3537 <p class="text-sm text-gray-400">Starting with a base score of 300</p> 3538 </div> 3539 </div> 3540 <div class="flex items-start gap-4 p-4 bg-orange-500/10 border border-orange-500/20 rounded-xl opacity-0 story-step" data-step="2"> 3541 <div class="w-10 h-10 bg-gradient-to-br from-orange-500 to-amber-600 rounded-full flex items-center justify-center text-white font-bold flex-shrink-0">2</div> 3542 <div> 3543 <p class="text-white font-semibold">Friends and family endorse her character</p> 3544 <p class="text-sm text-gray-400">5 endorsements: +50 points â Score: 350</p> 3545 </div> 3546 </div> 3547 <div class="flex items-start gap-4 p-4 bg-purple-500/10 border border-purple-500/20 rounded-xl opacity-0 story-step" data-step="3"> 3548 <div class="w-10 h-10 bg-gradient-to-br from-purple-500 to-pink-600 rounded-full flex items-center justify-center text-white font-bold flex-shrink-0">3</div> 3549 <div> 3550 <p class="text-white font-semibold">Employer verifies her employment badge</p> 3551 <p class="text-sm text-gray-400">Institutional verification: +120 points â Score: 470</p> 3552 </div> 3553 </div> 3554 <div class="flex items-start gap-4 p-4 bg-green-500/10 border border-green-500/20 rounded-xl opacity-0 story-step" data-step="4"> 3555 <div class="w-10 h-10 bg-gradient-to-br from-green-500 to-emerald-600 rounded-full flex items-center justify-center text-white font-bold flex-shrink-0">4</div> 3556 <div> 3557 <p class="text-white font-semibold">Uploads mobile money statement showing consistent income</p> 3558 <p class="text-sm text-gray-400">Financial pattern analysis: +180 points â Score: 650</p> 3559 </div> 3560 </div> 3561 <div class="flex items-start gap-4 p-4 bg-amber-500/10 border border-amber-500/20 rounded-xl opacity-0 story-step" data-step="5"> 3562 <div class="w-10 h-10 bg-gradient-to-br from-amber-500 to-orange-600 rounded-full flex items-center justify-center text-white font-bold flex-shrink-0">5</div> 3563 <div> 3564 <p class="text-white font-semibold">Community members endorse her across multiple contexts</p> 3565 <p class="text-sm text-gray-400">Multi-context trust: +100 points â Score: 750 â¨</p> 3566 </div> 3567 </div> 3568 <div class="flex items-start gap-4 p-4 bg-gradient-to-r from-orange-500/20 to-amber-500/20 border-2 border-orange-500/50 rounded-xl opacity-0 story-step" data-step="6"> 3569 <div class="w-10 h-10 bg-gradient-to-br from-orange-500 to-amber-600 rounded-full flex items-center justify-center flex-shrink-0"> 3570 <i class="fas fa-trophy text-white"></i> 3571 </div> 3572 <div class="flex-1"> 3573 <p class="text-white font-bold text-lg">Nandi is now trust-ready across multiple contexts! ð</p> 3574 <p class="text-sm text-gray-300">Score: 882/1000 ⢠Lending Trust: 918 ⢠15 endorsements ⢠3 badges</p> 3575 </div> 3576 </div> 3577 </div> 3578 </div> 3579 </div> 3580 3581 </div> 3582 </section> 3583 3584 <!-- Animation Script --> 3585
3585<script> 3586 // Ubuntu Flow Animation - Nandi's Story 3587 const canvas = document.getElementById('trustFlowCanvas'); 3588 const ctx = canvas.getContext('2d'); 3589 let animationId; 3590 let isPaused = false; 3591 let animationTime = 0; 3592 const ANIMATION_DURATION = 15000; // 15 seconds per cycle 3593 3594 // Resize canvas 3595 function resizeCanvas() { 3596 const container = canvas.parentElement; 3597 canvas.width = container.offsetWidth; 3598 canvas.height = container.offsetHeight; 3599 } 3600 resizeCanvas(); 3601 window.addEventListener('resize', resizeCanvas); 3602 3603 // Central user (Nandi) 3604 const centerUser = { 3605 x: canvas.width / 2, 3606 y: canvas.height / 2, 3607 radius: 40, 3608 score: 300, 3609 color: '#3B82F6' 3610 }; 3611 3612 // Surrounding users (friends, family, employers) 3613 const users = []; 3614 const userCount = 12; 3615 const specialUsers = [2, 5, 8, 11]; // Users with 2-layer networks 3616 3617 for (let i = 0; i < userCount; i++) { 3618 const angle = (i / userCount) * Math.PI * 2; 3619 const distance = Math.min(canvas.width, canvas.height) * 0.35; 3620 const hasDeepNetwork = specialUsers.includes(i); 3621 3622 // Each user has their own mini network (2-3 connections) 3623 const subNetwork = []; 3624 const subCount = hasDeepNetwork ? 3 : (2 + Math.floor(Math.random() * 2)); 3625 3626 for (let j = 0; j < subCount; j++) { 3627 const subAngle = angle + (j / subCount) * Math.PI * 0.5 - Math.PI * 0.25; 3628 const subDistance = 60 + Math.random() * 20; 3629 3630 // Level 2 connections (tertiary network) - only for special users 3631 const tertiaryNetwork = []; 3632 if (hasDeepNetwork && j < 2) { 3633 const tertiaryCount = 2; 3634 for (let k = 0; k < tertiaryCount; k++) { 3635 const tertiaryAngle = subAngle + (k / tertiaryCount) * Math.PI * 0.4 - Math.PI * 0.2; 3636 const tertiaryDistance = 45 + Math.random() * 15; 3637 tertiaryNetwork.push({ 3638 angle: tertiaryAngle, 3639 distance: tertiaryDistance, 3640 active: false 3641 }); 3642 } 3643 } 3644 3645 subNetwork.push({ 3646 angle: subAngle, 3647 distance: subDistance, 3648 active: false, 3649 tertiaryNetwork: tertiaryNetwork 3650 }); 3651 } 3652 3653 // Mutual connections (some users connect to each other) 3654 const mutualConnections = []; 3655 if (i % 3 === 0 && i < userCount - 1) { 3656 mutualConnections.push((i + 1) % userCount); 3657 } 3658 if (i === 5) { 3659 mutualConnections.push(8); // Bidirectional between users 5 and 8 3660 } 3661 3662 users.push({ 3663 x: canvas.width / 2 + Math.cos(angle) * distance, 3664 y: canvas.height / 2 + Math.sin(angle) * distance, 3665 radius: 25, 3666 angle: angle, 3667 distance: distance, 3668 endorsed: false, 3669 endorsementDelay: 2000 + (i * 1000), 3670 subNetwork: subNetwork, 3671 rippleRadius: 0, 3672 showingRipple: false, 3673 hasDeepNetwork: hasDeepNetwork, 3674 mutualConnections: mutualConnections 3675 }); 3676 } 3677 3678 // Endorsement particles 3679 const endorsements = []; 3680 3681 // Secondary endorsement particles (ripple effects) 3682 const secondaryEndorsements = []; 3683 3684 function drawUser(user, highlight = false) { 3685 ctx.save(); 3686 3687 // Glow effect 3688 if (highlight) { 3689 const gradient = ctx.createRadialGradient(user.x, user.y, 0, user.x, user.y, user.radius * 2); 3690 gradient.addColorStop(0, 'rgba(251, 146, 60, 0.3)'); 3691 gradient.addColorStop(1, 'rgba(251, 146, 60, 0)'); 3692 ctx.fillStyle = gradient; 3693 ctx.beginPath();
3694 ctx.arc(user.x, user.y, user.radius * 2, 0, Math.PI * 2); 3695 ctx.fill(); 3696 } 3697 3698 // User circle 3699 const userGradient = ctx.createRadialGradient(user.x, user.y, 0, user.x, user.y, user.radius); 3700 if (user === centerUser) { 3701 userGradient.addColorStop(0, '#FB923C'); 3702 userGradient.addColorStop(1, '#F97316'); 3703 } else if (user.endorsed) { 3704 userGradient.addColorStop(0, '#34D399'); 3705 userGradient.addColorStop(1, '#10B981'); 3706 } else { 3707 userGradient.addColorStop(0, '#60A5FA'); 3708 userGradient.addColorStop(1, '#3B82F6'); 3709 } 3710 ctx.fillStyle = userGradient; 3711 ctx.beginPath(); 3712 ctx.arc(user.x, user.y, user.radius, 0, Math.PI * 2); 3713 ctx.fill(); 3714 3715 // Border 3716 ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)'; 3717 ctx.lineWidth = 2; 3718 ctx.stroke(); 3719 3720 // Add text label for center user (Nandi) 3721 if (user === centerUser) { 3722 ctx.fillStyle = 'white'; 3723 ctx.font = 'bold 12px Inter, sans-serif'; 3724 ctx.textAlign = 'center'; 3725 ctx.textBaseline = 'middle'; 3726 ctx.fillText('NA', user.x, user.y); 3727 3728 // Add TumiTrust label below 3729 ctx.font = '10px Inter, sans-serif'; 3730 ctx.fillStyle = 'rgba(255, 255, 255, 0.8)'; 3731 ctx.fillText('TumiTrust', user.x, user.y + user.radius + 15); 3732 } 3733 3734 ctx.restore(); 3735 } 3736 3737 function drawArrow(fromX, fromY, toX, toY, color, alpha = 0.6, nodeRadius = 12) { 3738 const angle = Math.atan2(toY - fromY, toX - fromX); 3739 const headLength = 10; 3740 3741 ctx.save(); 3742 ctx.globalAlpha = alpha; 3743 ctx.strokeStyle = color; 3744 ctx.fillStyle = color; 3745 ctx.lineWidth = 2; 3746 3747 // Calculate proper end point (stop at node edge) 3748 const distance = Math.sqrt((toX - fromX) ** 2 + (toY - fromY) ** 2); 3749 const shortenBy = nodeRadius + 2; // Stop just before node edge 3750 const endX = fromX + (toX - fromX) * ((distance - shortenBy) / distance); 3751 const endY = fromY + (toY - fromY) * ((distance - shortenBy) / distance); 3752 3753 // Arrow line 3754 ctx.beginPath(); 3755 ctx.moveTo(fromX, fromY); 3756 ctx.lineTo(endX, endY); 3757 ctx.stroke(); 3758 3759 // Arrow head (solid triangle) 3760 ctx.beginPath(); 3761 ctx.moveTo(endX, endY); 3762 ctx.lineTo( 3763 endX - headLength * Math.cos(angle - Math.PI / 6), 3764 endY - headLength * Math.sin(angle - Math.PI / 6) 3765 ); 3766 ctx.lineTo( 3767 endX - headLength * Math.cos(angle + Math.PI / 6), 3768 endY - headLength * Math.sin(angle + Math.PI / 6) 3769 ); 3770 ctx.closePath(); 3771 ctx.fill(); 3772 ctx.restore(); 3773 } 3774 3775 function drawSubNetwork(user) { 3776 if (!user.endorsed || !user.subNetwork) return; 3777 3778 user.subNetwork.forEach((sub, index) => {
3779 const subX = user.x + Math.cos(sub.angle) * sub.distance; 3780 const subY = user.y + Math.sin(sub.angle) * sub.distance; 3781 3782 // Connection line with arrow 3783 if (sub.active) { 3784 drawArrow(user.x, user.y, subX, subY, '#34D399', 0.7, 12); 3785 } else { 3786 ctx.save(); 3787 ctx.globalAlpha = 0.15; 3788 ctx.strokeStyle = '#60A5FA'; 3789 ctx.lineWidth = 1; 3790 ctx.setLineDash([5, 5]); 3791 ctx.beginPath(); 3792 ctx.moveTo(user.x, user.y); 3793 ctx.lineTo(subX, subY); 3794 ctx.stroke(); 3795 ctx.setLineDash([]); 3796 ctx.restore(); 3797 } 3798 3799 // Sub-user node (Level 2) 3800 ctx.save(); 3801 ctx.fillStyle = sub.active ? '#10B981' : '#3B82F6'; 3802 ctx.globalAlpha = sub.active ? 0.8 : 0.5; 3803 ctx.beginPath(); 3804 ctx.arc(subX, subY, 12, 0, Math.PI * 2); 3805 ctx.fill(); 3806 3807 ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)'; 3808 ctx.lineWidth = 1; 3809 ctx.stroke(); 3810 ctx.restore(); 3811 3812 // Tertiary network (Level 3) - connections of connections 3813 if (sub.tertiaryNetwork && sub.tertiaryNetwork.length > 0 && sub.active) { 3814 sub.tertiaryNetwork.forEach((tertiary, tIndex) => { 3815 const tertiaryX = subX + Math.cos(tertiary.angle) * tertiary.distance; 3816 const tertiaryY = subY + Math.sin(tertiary.angle) * tertiary.distance; 3817 3818 // Tertiary connection with arrow 3819 if (tertiary.active) { 3820 drawArrow(subX, subY, tertiaryX, tertiaryY, '#FBBF24', 0.6, 8); 3821 } else { 3822 ctx.save(); 3823 ctx.globalAlpha = 0.2; 3824 ctx.strokeStyle = '#34D399'; 3825 ctx.lineWidth = 1; 3826 ctx.setLineDash([3, 3]); 3827 ctx.beginPath(); 3828 ctx.moveTo(subX, subY); 3829 ctx.lineTo(tertiaryX, tertiaryY); 3830 ctx.stroke(); 3831 ctx.setLineDash([]); 3832 ctx.restore(); 3833 } 3834 3835 // Tertiary node (Level 3) 3836 ctx.save(); 3837 ctx.fillStyle = tertiary.active ? '#FBBF24' : '#10B981'; 3838 ctx.globalAlpha = tertiary.active ? 0.9 : 0.4; 3839 ctx.beginPath(); 3840 ctx.arc(tertiaryX, tertiaryY, 8, 0, Math.PI * 2); 3841 ctx.fill(); 3842 3843 ctx.strokeStyle = 'rgba(255, 255, 255, 0.4)'; 3844 ctx.lineWidth = 1; 3845 ctx.stroke(); 3846 ctx.restore(); 3847 }); 3848 } 3849 }); 3850 } 3851 3852 function drawMutualConnections() { 3853 users.forEach((user, index) => { 3854 if (user.endorsed && user.mutualConnections && user.mutualConnections.length > 0) { 3855 user.mutualConnections.forEach(targetIndex => { 3856 const targetUser = users[targetIndex]; 3857 if (targetUser && targetUser.endorsed) { 3858 // Calculate curve parameters 3859 const midX = (user.x + targetUser.x) / 2; 3860 const midY = (user.y + targetUser.y) / 2; 3861 const perpAngle = Math.atan2(targetUser.y - user.y, targetUser.x - user.x) + Math.PI / 2; 3862 const offset = 15;
3863 const controlX = midX + Math.cos(perpAngle) * offset; 3864 const controlY = midY + Math.sin(perpAngle) * offset; 3865 3866 // Calculate end point (accounting for node radius) 3867 const angleToTarget = Math.atan2(targetUser.y - controlY, targetUser.x - controlX); 3868 const nodeRadius = 25; 3869 const endX = targetUser.x - Math.cos(angleToTarget) * (nodeRadius + 2); 3870 const endY = targetUser.y - Math.sin(angleToTarget) * (nodeRadius + 2); 3871 3872 // Draw curved line 3873 ctx.save(); 3874 ctx.globalAlpha = 0.5; 3875 ctx.strokeStyle = '#FB923C'; 3876 ctx.lineWidth = 2; 3877 ctx.beginPath(); 3878 ctx.moveTo(user.x, user.y); 3879 ctx.quadraticCurveTo(controlX, controlY, endX, endY); 3880 ctx.stroke(); 3881 ctx.restore(); 3882 3883 // Draw arrow head at end point 3884 ctx.save(); 3885 ctx.globalAlpha = 0.5; 3886 ctx.fillStyle = '#FB923C'; 3887 const headLength = 10; 3888 ctx.beginPath(); 3889 ctx.moveTo(endX, endY); 3890 ctx.lineTo( 3891 endX - headLength * Math.cos(angleToTarget - Math.PI / 6), 3892 endY - headLength * Math.sin(angleToTarget - Math.PI / 6) 3893 ); 3894 ctx.lineTo( 3895 endX - headLength * Math.cos(angleToTarget + Math.PI / 6), 3896 endY - headLength * Math.sin(angleToTarget + Math.PI / 6) 3897 ); 3898 ctx.closePath(); 3899 ctx.fill(); 3900 ctx.restore(); 3901 } 3902 }); 3903 } 3904 }); 3905 } 3906 3907 function drawRippleEffect(user) { 3908 if (!user.showingRipple) return; 3909 3910 ctx.save(); 3911 ctx.globalAlpha = 1 - (user.rippleRadius / 100); 3912 ctx.strokeStyle = '#34D399'; 3913 ctx.lineWidth = 3; 3914 ctx.beginPath(); 3915 ctx.arc(user.x, user.y, user.rippleRadius, 0, Math.PI * 2); 3916 ctx.stroke(); 3917 3918 ctx.strokeStyle = '#10B981'; 3919 ctx.lineWidth = 2; 3920 ctx.beginPath(); 3921 ctx.arc(user.x, user.y, user.rippleRadius * 0.7, 0, Math.PI * 2); 3922 ctx.stroke(); 3923 ctx.restore(); 3924 3925 user.rippleRadius += 2; 3926 if (user.rippleRadius > 100) { 3927 user.showingRipple = false; 3928 user.rippleRadius = 0; 3929 } 3930 } 3931 3932 function createEndorsement(fromUser, toUser) { 3933 endorsements.push({ 3934 from: { x: fromUser.x, y: fromUser.y }, 3935 to: { x: toUser.x, y: toUser.y }, 3936 progress: 0, 3937 completed: false, 3938 targetUser: toUser 3939 }); 3940 } 3941 3942 // Flowing particles for dynamic trust visualization 3943 const flowingParticles = []; 3944 3945 function createFlowingParticle(fromX, fromY, toX, toY, color, size = 4) { 3946 flowingParticles.push({ 3947 from: { x: fromX, y: fromY }, 3948 to: { x: toX, y: toY }, 3949 progress: Math.random() * 0.3, // Stagger start 3950 color: color, 3951 size: size, 3952 speed: 0.015 + Math.random() * 0.01, 3953 completed: false 3954 }); 3955 } 3956 3957 function drawFlowingParticles() { 3958 flowingParticles.forEach((particle, index) => { 3959 if (particle.completed) { 3960 flowingParticles.splice(index, 1); 3961 return; 3962 } 3963 3964 const currentX = particle.from.x + (particle.to.x - particle.from.x) * particle.progress; 3965 const currentY = particle.from.y + (particle.to.y - particle.from.y) * particle.progress; 3966 3967 // Glowing particle 3968 ctx.save(); 3969 const gradient = ctx.createRadialGradient(currentX, currentY, 0, currentX, currentY, particle.size * 3); 3970 gradient.addColorStop(0, particle.color); 3971 gradient.addColorStop(0.5, particle.color + '88'); 3972 gradient.addColorStop(1, particle.color + '00'); 3973 ctx.fillStyle = gradient; 3974 ctx.beginPath(); 3975 ctx.arc(currentX, currentY, particle.size * 3, 0, Math.PI * 2); 3976 ctx.fill(); 3977 3978 // Core particle 3979 ctx.fillStyle = particle.color; 3980 ctx.shadowColor = particle.color; 3981 ctx.shadowBlur = 10; 3982 ctx.beginPath(); 3983 ctx.arc(currentX, currentY, particle.size, 0, Math.PI * 2); 3984 ctx.fill();
3985 ctx.restore(); 3986 3987 particle.progress += particle.speed; 3988 if (particle.progress >= 1) { 3989 particle.progress = 0; // Loop the particle 3990 } 3991 }); 3992 } 3993 3994 function triggerRippleEffect(user) { 3995 user.showingRipple = true; 3996 user.rippleRadius = 0; 3997 3998 // Activate sub-network 3999 if (user.subNetwork) { 4000 user.subNetwork.forEach((sub, index) => { 4001 setTimeout(() => { 4002 sub.active = true; 4003 // Create mini particles to sub-nodes 4004 const subX = user.x + Math.cos(sub.angle) * sub.distance; 4005 const subY = user.y + Math.sin(sub.angle) * sub.distance; 4006 secondaryEndorsements.push({ 4007 from: { x: user.x, y: user.y }, 4008 to: { x: subX, y: subY }, 4009 progress: 0, 4010 completed: false 4011 }); 4012 4013 // Create continuous flowing particles 4014 for (let i = 0; i < 3; i++) { 4015 setTimeout(() => { 4016 createFlowingParticle(user.x, user.y, subX, subY, '#34D399', 3); 4017 }, i * 200); 4018 } 4019 4020 // Activate tertiary networks (Level 3) 4021 if (sub.tertiaryNetwork && sub.tertiaryNetwork.length > 0) { 4022 sub.tertiaryNetwork.forEach((tertiary, tIndex) => { 4023 setTimeout(() => { 4024 tertiary.active = true; 4025 const tertiaryX = subX + Math.cos(tertiary.angle) * tertiary.distance; 4026 const tertiaryY = subY + Math.sin(tertiary.angle) * tertiary.distance; 4027 4028 // Create flowing particles to tert
4028iary nodes 4029 for (let i = 0; i < 2; i++) { 4030 setTimeout(() => { 4031 createFlowingParticle(subX, subY, tertiaryX, tertiaryY, '#FBBF24', 2.5); 4032 }, i * 300); 4033 } 4034 }, tIndex * 400); 4035 }); 4036 } 4037 }, index * 300); 4038 }); 4039 } 4040 4041 // Create flowing particles for mutual connections 4042 if (user.mutualConnections && user.mutualConnections.length > 0) { 4043 user.mutualConnections.forEach((targetIndex, i) => { 4044 const targetUser = users[targetIndex]; 4045 if (targetUser && targetUser.endorsed) { 4046 setTimeout(() => { 4047 for (let j = 0; j < 2; j++) { 4048 setTimeout(() => { 4049 createFlowingParticle(user.x, user.y, targetUser.x, targetUser.y, '#FB923C', 3.5); 4050 }, j * 250); 4051 } 4052 }, i * 500); 4053 } 4054 }); 4055 } 4056 } 4057 4058 function drawEndorsements() { 4059 endorsements.forEach((end, index) => { 4060 if (end.completed) return; 4061 4062 const currentX = end.from.x + (end.to.x - end.from.x) * end.progress; 4063 const currentY = end.from.y + (end.to.y - end.from.y) * end.progress; 4064 4065 // Trail 4066 ctx.save(); 4067 ctx.globalAlpha = 0.6; 4068 const gradient = ctx.createRadialGradient(currentX, currentY, 0, currentX, currentY, 15); 4069 gradient.addColorStop(0, '#FB923C'); 4070 gradient.addColorStop(1, 'rgba(251, 146, 60, 0)'); 4071 ctx.fillStyle = gradient; 4072 ctx.beginPath(); 4073 ctx.arc(currentX, currentY, 15, 0, Math.PI * 2); 4074 ctx.fill(); 4075 ctx.restore(); 4076 4077 // Particle 4078 ctx.save(); 4079 ctx.fillStyle = '#FCD34D'; 4080 ctx.shadowColor = '#FB923C'; 4081 ctx.shadowBlur = 10; 4082 ctx.beginPath(); 4083 ctx.arc(currentX, currentY, 5, 0, Math.PI * 2); 4084 ctx.fill(); 4085 ctx.restore(); 4086 4087 end.progress += 0.02; 4088 if (end.progress >= 1) { 4089 end.completed = true; 4090 // Trigger ripple effect when endorsement reaches target 4091 if (end.targetUser) { 4092 triggerRippleEffect(end.targetUser); 4093 } 4094 endorsements.splice(index, 1); 4095 } 4096 }); 4097 4098 // Draw secondary endorsements (to sub-networks) 4099 secondaryEndorsements.forEach((end, index) => { 4100 if (end.completed) return; 4101 4102 const currentX = end.from.x + (end.to.x - end.from.x) * end.progress; 4103 const currentY = end.from.y + (end.to.y - end.from.y) * end.progress; 4104 4105 // Smaller particle for secondary effects 4106 ctx.save(); 4107 ctx.globalAlpha = 0.6; 4108 ctx.fillStyle = '#34D399'; 4109 ctx.shadowColor = '#10B981'; 4110 ctx.shadowBlur = 8; 4111 ctx.beginPath(); 4112 ctx.arc(currentX, currentY, 3, 0, Math.PI * 2); 4113 ctx.fill(); 4114 ctx.restore(); 4115 4116 end.progress += 0.03; 4117 if (end.progress >= 1) { 4118 end.completed = true; 4119 secondaryEndorsements.splice(index, 1); 4120 } 4121 }); 4122 } 4123 4124 function updateStoryStep(step) { 4125 document.querySelectorAll('.story-step').forEach(el => { 4126 const stepNum = parseInt(el.dataset.step); 4127 if (stepNum <= step) { 4128 el.style.opacity = '1'; 4129 el.style.transform = 'translateX(0)'; 4130 } else { 4131 el.style.opacity = '0'; 4132 el.style.transform = 'translateX(-20px)'; 4133 } 4134 }); 4135 } 4136 4137 function animate() { 4138 if (isPaused) return; 4139 4140 ctx.clearRect(0, 0, canvas.width, canvas.height); 4141 4142 // Draw TumiTrust watermark in background (subtle) 4143 ctx.save(); 4144 ctx.globalAlpha = 0.03; 4145 ctx.font = 'bold 60px Inter, sans-serif'; 4146 ctx.textAlign = 'center'; 4147 ctx.textBaseline = 'middle'; 4148 ctx.fillStyle = '#FB923C'; 4149 ctx.fillText('TumiTrust', canvas.width / 2, canvas.height / 2);
4150 ctx.restore(); 4151 4152 // Update center position (responsive) 4153 centerUser.x = canvas.width / 2; 4154 centerUser.y = canvas.height / 2; 4155 4156 // Update user positions (recalculate distance for responsiveness) 4157 users.forEach((user, i) => { 4158 const distance = Math.min(canvas.width, canvas.height) * 0.35; 4159 user.x = canvas.width / 2 + Math.cos(user.angle) * distance; 4160 user.y = canvas.height / 2 + Math.sin(user.angle) * distance; 4161 4162 // Check if it's time to endorse 4163 if (!user.endorsed && animationTime > user.endorsementDelay) { 4164 user.endorsed = true; 4165 createEndorsement(user, centerUser); 4166 centerUser.score += 10; 4167 const networkScore = document.getElementById('networkScore'); 4168 if (networkScore) networkScore.textContent = Math.min(750, centerUser.score); 4169 4170 // Update story steps 4171 if (i === 4) updateStoryStep(2); 4172 if (i === 6) updateStoryStep(3); 4173 if (i === 8) updateStoryStep(4); 4174 if (i === 10) updateStoryStep(5); 4175 if (i === 11) updateStoryStep(6); 4176 } 4177 }); 4178 4179 // Draw connections 4180 ctx.save(); 4181 ctx.globalAlpha = 0.1; 4182 ctx.strokeStyle = '#60A5FA'; 4183 ctx.lineWidth = 1; 4184 users.forEach(user => { 4185 if (user.endorsed) { 4186 ctx.beginPath(); 4187 ctx.moveTo(user.x, user.y); 4188 ctx.lineTo(centerUser.x, centerUser.y); 4189 ctx.stroke(); 4190 } 4191 }); 4192 ctx.restore(); 4193 4194 // Draw mutual connections (peer-to-peer trust) 4195 drawMutualConnections(); 4196 4197 // Draw sub-networks and ripple effects 4198 users.forEach(user => { 4199 drawSubNetwork(user); 4200 drawRippleEffect(user); 4201 }); 4202 4203 // Draw flowing particles (continuous trust flow) 4204 drawFlowingParticles(); 4205 4206 // Draw users 4207 users.forEach(user => drawUser(user)); 4208 drawUser(centerUser, true); 4209 4210 // Draw endorsements 4211 drawEndorsements(); 4212 4213 animationTime += 16; // ~60fps 4214 4215 // Loop animation 4216 if (animationTime > ANIMATION_DURATION) { 4217 animationTime = 0; 4218 users.forEach(user => { 4219 user.endorsed = false; 4220 user.showingRipple = false; 4221 user.rippleRadius = 0; 4222 if (user.subNetwork) { 4223 user.subNetwork.forEach(sub => { 4224 sub.active = false; 4225 if (sub.tertiaryNetwork) { 4226 sub.tertiaryNetwork.forEach(tertiary => { 4227 tertiary.active = false; 4228 }); 4229 } 4230 }); 4231 } 4232 }); 4233 centerUser.score = 300; 4234 endorsements.length = 0; 4235 secondaryEndorsements.length = 0; 4236 flowingParticles.length = 0; 4237 updateStoryStep(1); 4238 } 4239 4240 animationId = requestAnimationFrame(animate); 4241 } 4242 4243 function pauseAnimation() { 4244 isPaused = !isPaused; 4245 const btn = document.getElementById('pauseBtn'); 4246 if (isPaused) { 4247 btn.innerHTML = '<i class="fas fa-play"></i><span>Play</span>'; 4248 } else { 4249 btn.innerHTML = '<i class="fas fa-pause"></i><span>Pause</span>'; 4250 animate(); 4251 } 4252 } 4253 4254 function restartAnimation() { 4255 animationTime = 0;
4256 users.forEach(user => { 4257 user.endorsed = false; 4258 user.showingRipple = false; 4259 user.rippleRadius = 0; 4260 if (user.subNetwork) { 4261 user.subNetwork.forEach(sub => { 4262 sub.active = false; 4263 if (sub.tertiaryNetwork) { 4264 sub.tertiaryNetwork.forEach(tertiary => { 4265 tertiary.active = false; 4266 }); 4267 } 4268 }); 4269 } 4270 }); 4271 centerUser.score = 300; 4272 endorsements.length = 0; 4273 secondaryEndorsements.length = 0; 4274 flowingParticles.length = 0; 4275 const networkScore = document.getElementById('networkScore'); 4276 if (networkScore) networkScore.textContent = '300'; 4277 updateStoryStep(1); 4278 if (isPaused) { 4279 isPaused = false; 4280 document.getElementById('pauseBtn').innerHTML = '<i class="fas fa-pause"></i><span>Pause</span>'; 4281 } 4282 } 4283 4284 // Start animation 4285 updateStoryStep(1); 4286 animate(); 4287 4288 // Background particles canvas 4289 const bgCanvas = document.getElementById('ubuntuCanvas'); 4290 const bgCtx = bgCanvas.getContext('2d'); 4291 4292 function resizeBgCanvas() { 4293 bgCanvas.width = bgCanvas.offsetWidth; 4294 bgCanvas.height = bgCanvas.offsetHeight; 4295 } 4296 resizeBgCanvas(); 4297 window.addEventListener('resize', resizeBgCanvas); 4298 4299 const particles = []; 4300 for (let i = 0; i < 50; i++) { 4301 particles.push({ 4302 x: Math.random() * bgCanvas.width, 4303 y: Math.random() * bgCanvas.height, 4304 radius: Math.random() * 2 + 1, 4305 vx: (Math.random() - 0.5) * 0.5, 4306 vy: (Math.random() - 0.5) * 0.5, 4307 opacity: Math.random() * 0.5 4308 }); 4309 } 4310 4311 function animateBackground() { 4312 bgCtx.clearRect(0, 0, bgCanvas.width, bgCanvas.height); 4313 4314 particles.forEach(p => { 4315 p.x += p.vx; 4316 p.y += p.vy; 4317 4318 if (p.x < 0 || p.x > bgCanvas.width) p.vx *= -1; 4319 if (p.y < 0 || p.y > bgCanvas.height) p.vy *= -1; 4320 4321 bgCtx.save(); 4322 bgCtx.globalAlpha = p.opacity; 4323 bgCtx.fillStyle = '#FB923C'; 4324 bgCtx.beginPath(); 4325 bgCtx.arc(p.x, p.y, p.radius, 0, Math.PI * 2); 4326 bgCtx.fill(); 4327 bgCtx.restore(); 4328 }); 4329 4330 requestAnimationFrame(animateBackground); 4331 } 4332 animateBackground(); 4333 </script>
4333 4334 4335 <!-- Interactive mobile app preview --> 4336 <section class="py-24 px-4 relative" style="z-index: 50; position: relative;"> 4337 <div class="container mx-auto max-w-7xl"> 4338 <div class="text-center mb-16"> 4339 <div class="inline-flex items-center gap-2 px-5 py-2 bg-gradient-to-r from-purple-500/20 to-pink-500/20 border border-purple-500/30 rounded-full mb-6"> 4340 <i class="fas fa-mobile-alt text-purple-400"></i> 4341 <span class="text-purple-300 font-semibold text-sm">Experience TumiTrust</span> 4342 </div> 4343 <h2 class="text-5xl md:text-6xl font-black mb-6"> 4344 <span class="holographic-text">Your Trust Network</span> 4345 <br/> 4346 <span class="text-white">In Your Pocket ð¤ð¿</span> 4347 </h2> 4348 <p class="text-xl text-gray-300 max-w-3xl mx-auto leading-relaxed"> 4349 Real screens from the app - discover, endorse, check trust, and run lookups from your phone. 4350 </p> 4351 </div> 4352 4353 <div class="grid md:grid-cols-2 gap-12 items-center"> 4354 <!-- 3D Phone Mockup --> 4355 <div class="relative"> 4356 <!-- Glowing Background --> 4357 <div class="absolute inset-0 bg-gradient-to-br from-orange-500/20 via-amber-500/10 to-transparent rounded-full blur-3xl"></div> 4358 4359 <!-- tt-landing-phone: real PNG carousel (see meta tumitrust-landing-build) --> 4360 <div class="phone-mockup tt-landing-phone-root mx-auto relative max-w-[min(100%,360px)]" style="perspective: 1000px;"> 4361 <div class="phone-container" style="transform-style: preserve-3d; transition: transform 0.6s;"> 4362 <!-- Device chrome: fixed aspect so real screenshots always fill the âscreenâ --> 4363 <div class="tt-landing-device-chrome relative mx-auto rounded-[2.5rem] p-3 shadow-[0_50px_100px_rgba(255,102,0,0.35),inset_0_0_0_1px_rgba(255,255,255,0.12)]" style="width: min(100%, 320px); background: linear-gradient(145deg, #1e293b, #0f172a);"> 4364 <div class="pointer-events-none absolute top-3 left-1/2 z-30 h-7 w-[7.5rem] -translate-x-1/2 rounded-b-2xl bg-black/95 shadow-lg ring-1 ring-white/10"></div> 4365 <div class="tt-landing-phone-viewport relative overflow-hidden rounded-[1.75rem] bg-black ring-1 ring-white/10" style="aspect-ratio: 9 / 19.5; min-height: 520px;"> 4366 <div class="tt-landing-carousel absolute inset-0"> 4367 <div class="tt-landing-slide tt-landing-slide-active" data-screen="1"> 4368 <img src="/static/img/landing/app-screens/01-splash.ee49ee24c3fb.png?v=20260414" alt="TumiTrust app welcome - Portable trust" class="tt-landing-shot" width="390" height="844" loading="eager" decoding="async" fetchpriority="high"> 4369 </div> 4370 <div class="tt-landing-slide" data-screen="2"> 4371 <img src="/static/img/landing/app-screens/02-home-score.ed27d5d6a2f7.png?v=20260414" alt="Home - Trust CV and trust check" class="tt-landing-shot" width="390" height="844" loading="eager" decoding="async"> 4372 </div> 4373 <div class="tt-landing-slide" data-screen="3"> 4374 <img src="/static/img/landing/app-screens/03-discover.e0419b6aa68e.png?v=20260414" alt="Discover - matches and endorsements" class="tt-landing-shot" width="390" height="844" loading="eager" decoding="async"> 4375 </div> 4376 <div class="tt-landing-slide" data-screen="4"> 4377 <img src="/static/img/landing/app-screens/04-endorse.ae2bc3823555.png?v=20260414" alt="Endorse trust - compatibility" class="tt-landing-shot" width="390" height="844" loading="eager" decoding="async"> 4378 </div> 4379 <div class="tt-landing-slide" data-screen="5"> 4380 <img src="/static/img/landing/app-screens/05-trust-lookups.c0be992669bd.png?v=20260414" alt="Trust lookups and reports" class="tt-landing-shot" width="390" height="844" loading="eager" decoding="async"> 4381 </div> 4382 <div class="tt-landing-slide" data-screen="6"> 4383 <img src="/static/img/landing/app-screens/06-cooperative-instant-preview.f4912101ef21.png?v=20260421" alt="Cooperative circle - instant preview of a moment" class="tt-landing-shot" width="390" height="844" loading="lazy" decoding="async"> 4384 </div> 4385 <div class="tt-landing-slide" data-screen="7"> 4386 <img src="/static/img/landing/app-screens/07-trust-request-review-send.7f183d1342e3.png?v=20260421" alt="Create trust request - review and send" class="tt-landing-shot" width="390" height="844" loading="lazy" decoding="async"> 4387 </div> 4388 </div> 4389 </div> 4390 </div> 4391 </div> 4392 </div> 4393 </div> 4394 4395 <!-- Features List --> 4396 <div class="space-y-6"> 4397 <div class="flex gap-4 items-start"> 4398 <div class="w-14 h-14 bg-gradient-to-br from-orange-500 to-amber-500 rounded-2xl flex items-center justify-center flex-shrink-0"> 4399 <i class="fas fa-fingerprint text-white text-2xl"></i> 4400 </div> 4401 <div> 4402 <h3 class="text-2xl font-black text-white mb-2">
440220 trust contexts</h3> 4403 <p class="text-gray-300 leading-relaxed">Primaries + lenses on <a href="/docs/tumitrust/platform/partner-trust-contexts" class="tt-public-docs-link text-amber-300 font-semibold">one map</a> - lending to civic life, endorsements where your build allows.</p> 4404 </div> 4405 </div> 4406 4407 <div class="flex gap-4 items-start"> 4408 <div class="w-14 h-14 bg-gradient-to-br from-purple-500 to-pink-500 rounded-2xl flex items-center justify-center flex-shrink-0"> 4409 <i class="fas fa-users-between-lines text-white text-2xl"></i> 4410 </div> 4411 <div> 4412 <h3 class="text-2xl font-black text-white mb-2">Discover Trust Connections</h3> 4413 <p class="text-gray-300 leading-relaxed">Swipe, spot mutual trust, connect-your circle grows with real signal.</p> 4414 </div> 4415 </div> 4416 4417 <div class="flex gap-4 items-start"> 4418 <div class="w-14 h-14 bg-gradient-to-br from-blue-500 to-cyan-500 rounded-2xl flex items-center justify-center flex-shrink-0"> 4419 <i class="fas fa-award text-white text-2xl"></i> 4420 </div> 4421 <div> 4422 <h3 class="text-2xl font-black text-white mb-2">Collect Verified Badges</h3> 4423 <p class="text-gray-300 leading-relaxed">Employers, schools, landlords-request verification; each badge lifts your score.</p> 4424 </div> 4425 </div> 4426 4427 <div class="flex gap-4 items-start"> 4428 <div class="w-14 h-14 bg-gradient-to-br from-violet-500 to-purple-600 rounded-2xl flex items-center justify-center flex-shrink-0"> 4429 <i class="fas fa-magnifying-glass-chart text-white text-2xl"></i> 4430 </div> 4431 <div> 4432 <h3 class="text-2xl font-black text-white mb-2">Trust lookups</h3> 4433 <p class="text-gray-300 leading-relaxed"><strong class="text-white">Basic · Detailed · Predictive</strong> in the app. Same signals partners wire in at scale.</p> 4434 </div> 4435 </div> 4436 4437 <div class="flex gap-4 items-start"> 4438 <div class="w-14 h-14 bg-gradient-to-br from-green-500 to-emerald-500 rounded-2xl flex items-center justify-center flex-shrink-0"> 4439 <i class="fas fa-bolt text-white text-2xl"></i> 4440 </div> 4441 <div> 4442 <h3 class="text-2xl font-black text-white mb-2">Real-Time Updates</h3> 4443 <p class="text-gray-300 leading-relaxed">Endorsements and badges land-your score moves with them.</p> 4444 </div> 4445 </div> 4446 </div> 4447 </div> 4448 4449 </div> 4450 </section> 4451 4452 4453 4454
4454<script> 4455 // Hero Section Enhancements - Animated Counters 4456 document.addEventListener('DOMContentLoaded', function() { 4457 // Animate stat counters 4458 function animateCounter(id, targetValue, duration = 2000, suffix = '') { 4459 const element = document.getElementById(id); 4460 if (!element) return; 4461 4462 const startValue = 0; 4463 const increment = targetValue / (duration / 16); // 60 FPS 4464 let currentValue = 0; 4465 4466 const timer = setInterval(() => { 4467 currentValue += increment; 4468 if (currentValue >= targetValue) { 4469 currentValue = targetValue; 4470 clearInterval(timer); 4471 } 4472 element.textContent = Math.floor(currentValue) + suffix; 4473 }, 16); 4474 4475 // Add animation class 4476 element.style.animation = 'countUp 0.8s ease-out'; 4477 } 4478 4479 // Trigger animations when hero section is in view 4480 const observerOptions = { 4481 threshold: 0.2, 4482 rootMargin: '0px' 4483 }; 4484 4485 const heroObserver = new IntersectionObserver((entries) => { 4486 entries.forEach(entry => { 4487 if (entry.isIntersecting) { 4488 // Animate stats with delay 4489 setTimeout(() => animateCounter('statBoost', 43, 1500, '+'), 300); 4490 setTimeout(() => animateCounter('statUsers', 184, 1800, ''), 600); 4491 heroObserver.unobserve(entry.target); 4492 } 4493 }); 4494 }, observerOptions); 4495 4496 const heroSection = document.querySelector('.hero-section'); 4497 if (heroSection) { 4498 heroObserver.observe(heroSection); 4499 } 4500 4501 // Add pulse effect to power stats on hover 4502 const statCards = document.querySelectorAll('.hero-section .grid > div'); 4503 statCards.forEach(card => { 4504 card.addEventListener('mouseenter', function() { 4505 this.style.transform = 'scale(1.1) translateY(-5px)'; 4506 this.style.boxShadow = '0 20px 60px rgba(255, 170, 0, 0.4)'; 4507 }); 4508 card.addEventListener('mouseleave', function() { 4509 this.style.transform = 'scale(1)'; 4510 this.style.boxShadow = 'none'; 4511 }); 4512 }); 4513 4514 // Add typing effect to headline (optional) 4515 const headline = document.getElementById('typingHeadline'); 4516 if (headline && headline.textContent) { 4517 const originalText = headline.textContent; 4518 headline.textContent = ''; 4519 let charIndex = 0; 4520 4521 const typingInterval = setInterval(() => { 4522 if (charIndex < originalText.length) { 4523 headline.textContent += originalText.charAt(charIndex); 4524 charIndex++; 4525 } else { 4526 clearInterval(typingInterval); 4527 } 4528 }, 50); 4529 } 4530 }); 4531 </script>
4531 4532 4533
4533<script> 4534 // Phone carousel: rotate real screenshots only (no on-screen dots/captions - keeps app chrome visible) 4535 document.addEventListener('DOMContentLoaded', function initLandingPhoneCarousel() { 4536 const root = document.querySelector('.tt-landing-phone-root'); 4537 if (!root) return; 4538 4539 const slides = root.querySelectorAll('.tt-landing-slide'); 4540 const totalScreens = slides.length; 4541 if (!totalScreens) return; 4542 4543 let currentScreen = 1; 4544 4545 function switchScreen(screenNum) { 4546 slides.forEach((slide) => slide.classList.remove('tt-landing-slide-active')); 4547 const target = root.querySelector(`.tt-landing-slide[data-screen="${screenNum}"]`); 4548 if (target) target.classList.add('tt-landing-slide-active'); 4549 currentScreen = screenNum; 4550 } 4551 4552 if (totalScreens > 1) { 4553 setInterval(() => { 4554 switchScreen((currentScreen % totalScreens) + 1); 4555 }, 4500); 4556 } 4557 switchScreen(1); 4558 }); 4559 4560 // 3D phone tilt effect 4561 const phoneContainer = document.querySelector('.phone-container'); 4562 if (phoneContainer) { 4563 phoneContainer.parentElement.addEventListener('mousemove', (e) => { 4564 const rect = phoneContainer.getBoundingClientRect(); 4565 const x = e.clientX - rect.left; 4566 const y = e.clientY - rect.top; 4567 const centerX = rect.width / 2; 4568 const centerY = rect.height / 2; 4569 const rotateX = (y - centerY) / 20; 4570 const rotateY = (centerX - x) / 20; 4571 4572 phoneContainer.style.transform = `rotateX(${rotateX}deg) rotateY(${rotateY}deg)`; 4573 }); 4574 4575 phoneContainer.parentElement.addEventListener('mouseleave', () => { 4576 phoneContainer.style.transform = 'rotateX(0) rotateY(0)'; 4577 }); 4578 } 4579 </script>
4579 4580 4581 <style> 4582 .tt-landing-carousel { 4583 position: absolute; 4584 inset: 0; 4585 overflow: hidden; 4586 border-radius: inherit; 4587 } 4588 4589 .tt-landing-slide { 4590 position: absolute; 4591 inset: 0; 4592 width: 100%; 4593 height: 100%; 4594 opacity: 0; 4595 transition: opacity 0.55s ease-in-out; 4596 pointer-events: none; 4597 } 4598 4599 .tt-landing-slide-active { 4600 opacity: 1; 4601 z-index: 2; 4602 } 4603 4604 .tt-landing-shot { 4605 display: block; 4606 width: 100%; 4607 height: 100%; 4608 object-fit: contain; 4609 object-position: center bottom; 4610 background: #000; 4611 } 4612 4613 .phone-container { 4614 transition: transform 0.3s ease-out !important; 4615 } 4616 </style> 4617 4618 4619<!-- REAL-WORLD APPLICATIONS - role-based use cases --> 4620<section class="py-20 px-4 relative tt-applications-section" style="z-index: 50; position: relative;"> 4621 <div class="container mx-auto max-w-6xl"> 4622 <div class="text-center mb-12"> 4623 <div class="inline-flex items-center gap-2 px-5 py-2 bg-gradient-to-r from-orange-500/20 to-amber-500/20 border border-orange-500/35 rounded-full mb-6"> 4624 <i class="fas fa-arrows-spin text-amber-400"></i> 4625 <span class="text-amber-300 font-semibold text-sm">Everyone gains · no one donates data for free</span> 4626 </div> 4627 <h2 class="text-4xl md:text-6xl font-black mb-5"> 4628 <span class="holographic-text">Real-World Applications</span> 4629 </h2> 4630 <p class="text-lg md:text-xl text-gray-300 max-w-3xl mx-auto leading-relaxed"> 4631 Concrete workflows by role - what you gain, what you attest or look up, and why it compounds. Audience paths are above; these are the day-to-day stories. 4632 </p> 4633 </div> 4634 4635 <div class="tt-app-tabs" role="tablist" aria-label="Use case categories"> 4636 <button type="button" class="tt-app-tab tt-app-tab--active" data-app-tab="producers" role="tab" aria-selected="true"> 4637 <i class="fas fa-plug"></i> Trust producers 4638 </button> 4639 <button type="button" class="tt-app-tab" data-app-tab="institutions" role="tab" aria-selected="false"> 4640 <i class="fas fa-landmark"></i> Institutions 4641 </button> 4642 <button type="button" class="tt-app-tab" data-app-tab="people" role="tab" aria-selected="false"> 4643 <i class="fas fa-users"></i> People & groups 4644 </button> 4645 <button type="button" class="tt-app-tab" data-app-tab="compliance" role="tab" aria-selected="false"> 4646 <i class="fas fa-shield-halved"></i> Screening & risk 4647 </button> 4648 </div> 4649 4650 <div id="app-panel-producers" class="tt-app-panel tt-app-panel--active space-y-4" role="tabpanel"> 4651 <div class="tt-app-callout tt-app-callout--producer"> 4652 <i class="fas fa-handshake"></i> 4653 <p><strong>Not a one-way feed.</strong> Producers attest on their terms (webhook, API, CSV), see volume and funnel health in <strong>Pulse</strong>, enable contexts per contract, and often <strong>also run lookups</strong> as consumers. The more people can reuse proof from your contexts, the more your relationships compound.</p> 4654 </div> 4655 <div class="gradient-border rounded-2xl overflow-hidden"> 4656 <button type="button" onclick="toggleExample('app-commerce')" class="tt-app-acc-btn"> 4657 <div class="tt-app-acc-btn__main"> 4658 <div class="tt-app-acc-icon tt-app-acc-icon--orange"><i class="fas fa-store"></i></div> 4659 <div class="text-left"> 4660 <div class="tt-app-acc-meta"> 4661 <span class="tt-app-scale tt-app-scale--growth">Growth</span> 4662 <span class="tt-app-context">merchant · digital_platform</span> 4663 </div> 4664 <h3>Commerce platform - help merchants carry proof they earn</h3> 4665 <p>You are not handing us a feed. You help merchants reuse activity you already see - when they choose.</p> 4666 </div> 4667 </div> 4668 <i class="fas fa-chevron-down tt-app-chevron" id="app-commerce-icon"></i> 4669 </button> 4670 <div id="app-commerce" class="hidden tt-app-acc-body"> 4671 <div class="tt-app-flow">Your attestations â portable merchant proof â lenders & insurers query when authorized</div> 4672 <div class="tt-app-grid-3"> 4673 <div><h4>What you gain</h4><p>Higher merchant retention and GMV: sellers carry portable proof into finance without you building a scoring stack. Stronger platform value when merchants unlock capital and insurance on their terms.</p></div> 4674 <div><h4>What you attest</h4><p>Catalogued merchant events you already hold - onboarding, settlement, dispute outcomes - via webhook or CSV. TCU-metered; context-bound; no open-ended data dump.</p></div> 4675 <div><h4>Why it compounds</h4><p>Every authorized lookup that uses merchant context helps a seller you already serve. Competitors cannot replicate isolated silos - you hold a producer seat that puts merchants first.</p></div> 4676 </div> 4677 </div> 4678</div> 4679 4680 <div class="gradient-border rounded-2xl overflow-hidden"> 4681 <button type="button" onclick="toggleExample('app-lender-producer')" class="tt-app-acc-btn"> 4682 <div class="tt-app-acc-btn__main"> 4683 <div class="tt-app-acc-icon tt-app-acc-icon--amber"><i class="fas fa-hand-holding-usd"></i></div> 4684 <div class="text-left"> 4685 <div class="tt-app-acc-meta">
4686 <span class="tt-app-scale tt-app-scale--sme">SME</span> 4687 <span class="tt-app-context">lending · hybrid</span> 4688 </div> 4689 <h3>Lender as producer - repayments become proof borrowers carry</h3> 4690 <p>Attest once; approve faster when the same person brings proof from employers, telcos, and merchants.</p> 4691 </div> 4692 </div> 4693 <i class="fas fa-chevron-down tt-app-chevron" id="app-lender-producer-icon"></i> 4694 </button> 4695 <div id="app-lender-producer" class="hidden tt-app-acc-body"> 4696 4697 <div class="tt-app-grid-3"> 4698 <div><h4>What you gain</h4><p>Outbound: repayment history travels with your borrowers - they return for the next loan. Inbound: lookups on applicants include signals from partners you never could have sourced alone.</p></div> 4699 <div><h4>What you attest</h4><p>Repayment and facility events into the lending context - structured, consented, auditable. Separate metering: TCU for ingest, report credits for lookups you run.</p></div> 4700 <div><h4>Why it compounds</h4><p>Hybrid producers grow fairer thin-file decisions for people in the network. You are not subsidizing TumiTrust - you are buying network effects cheaper than bilateral data deals.</p></div> 4701 </div> 4702 </div> 4703</div> 4704 4705 <div class="gradient-border rounded-2xl overflow-hidden"> 4706 <button type="button" onclick="toggleExample('app-telco')" class="tt-app-acc-btn"> 4707 <div class="tt-app-acc-btn__main"> 4708 <div class="tt-app-acc-icon tt-app-acc-icon--cyan"><i class="fas fa-broadcast-tower"></i></div> 4709 <div class="text-left"> 4710 <div class="tt-app-acc-meta"> 4711 <span class="tt-app-scale tt-app-scale--enterprise">Enterprise</span> 4712 <span class="tt-app-context">utilities · digital_platform</span> 4713 </div> 4714 <h3>Telco - help subscribers carry payment trust without becoming a bank</h3> 4715 <p>Bill-pay and wallet behaviour becomes portable proof subscribers can reuse - you keep the relationship.</p> 4716 </div> 4717 </div> 4718 <i class="fas fa-chevron-down tt-app-chevron" id="app-telco-icon"></i> 4719 </button> 4720 <div id="app-telco" class="hidden tt-app-acc-body"> 4721 4722 <div class="tt-app-grid-3"> 4723 <div><h4>What you gain</h4><p>Stickier subscribers when loan and insurance partners approve faster using telco-attributed proof they authorize. Optional enterprise paths when institutions contract for lookups in your contexts.</p></div> 4724 <div><h4>What you attest</h4><p>Subscriber events you already process - payment consistency, tenure, product usage - through a connector you control. Pulse shows ingest health; no bespoke scoring engineering.</p></div> 4725 <div><h4>Why it compounds</h4><p>Institutions see thin-file truth through authorized lookups, not raw telco dumps. You remain the trusted interface; PTI is infrastructure, not a competitor for your wallet.</p></div> 4726 </div> 4727 </div> 4728</div> 4729 4730 <div class="gradient-border rounded-2xl overflow-hidden"> 4731 <button type="button" onclick="toggleExample('app-employer-producer')" class="tt-app-acc-btn"> 4732 <div class="tt-app-acc-btn__main"> 4733 <div class="tt-app-acc-icon tt-app-acc-icon--green"><i class="fas fa-briefcase"></i></div> 4734 <div class="text-left"> 4735 <div class="tt-app-acc-meta"> 4736 <span class="tt-app-scale tt-app-scale--enterprise">Enterprise</span> 4737 <span class="tt-app-context">employment · verifier</span> 4738 </div> 4739 <h3>Employer or HR platform - issue badges people can carry</h3> 4740 <p>Verification you already do becomes portable employment proof employees reuse across lenders and landlords.</p> 4741 </div> 4742 </div> 4743 <i class="fas fa-chevron-down tt-app-chevron" id="app-employer-producer-icon"></i> 4744 </button> 4745 <div id="app-employer-producer" class="hidden tt-app-acc-body"> 4746 4747 <div class="tt-app-grid-3"> 4748 <div><h4>What you gain</h4><p>Employees and alumni carry proof to rentals and credit - you strengthen your brand as a verifier. HR tech partners differentiate with programmable trust APIs instead of PDF letters.</p></div> 4749 <div><h4>What you attest</h4><p>Employment verification events and badge issuance - purpose-limited to employment c
4749ontext. You choose which cohorts and fields are attested.</p></div> 4750 <div><h4>Why it compounds</h4><p>Every hire or lending decision that uses employment context reinforces the value of your verification program - reciprocal for people, not extractive.</p></div> 4751 </div> 4752 </div> 4753</div> 4754 4755 </div> 4756 4757 <div id="app-panel-institutions" class="tt-app-panel space-y-4" role="tabpanel" hidden> 4758 <div class="tt-app-callout"> 4759 <i class="fas fa-scale-balanced"></i> 4760 <p><strong>Institutions consume - they do not feed the network by default.</strong> You purchase context-scoped trust lookups and optional screening. Explainable drivers, provenance, and audit trails are the product - not a black-box score or a mandate to upload your portfolio.</p> 4761 </div> 4762 <div class="gradient-border rounded-2xl overflow-hidden"> 4763 <button type="button" onclick="toggleExample('app-lending')" class="tt-app-acc-btn"> 4764 <div class="tt-app-acc-btn__main"> 4765 <div class="tt-app-acc-icon tt-app-acc-icon--amber"><i class="fas fa-coins"></i></div> 4766 <div class="text-left"> 4767 <div class="tt-app-acc-meta"> 4768 <span class="tt-app-scale tt-app-scale--sme">SME</span> 4769 <span class="tt-app-context">lending · financial services</span> 4770 </div> 4771 <h3>Digital lender approves a thin-file borrower</h3> 4772 <p>You buy a lookup - you keep the decision. No mandate to upload your loan book.</p> 4773 </div> 4774 </div> 4775 <i class="fas fa-chevron-down tt-app-chevron" id="app-lending-icon"></i> 4776 </button> 4777 <div id="app-lending" class="hidden tt-app-acc-body"> 4778 <div class="tt-app-flow">Directory search â generate lookup â explain drivers â you decide</div> 4779 <div class="tt-app-grid-3"> 4780 <div><h4>What you gain</h4><p>Approve more good thin-file applicants with defensible drivers - confidence band, ranked signals, explicit gaps. Faster ops than manual document chasing.</p></div> 4781 <div><h4>What you use</h4><p>A context-scoped lending lookup - structured JSON and PDF. Partner and community signals arrive as explainable intelligence, not raw third-party dumps.</p></div> 4782 <div><h4>Your outcome</h4><p>Your credit policy stays yours. Borrower leaves with portable proof - better retention when they need you again.</p></div> 4783 </div> 4784 </div> 4785</div> 4786 4787 <div class="gradient-border rounded-2xl overflow-hidden"> 4788 <button type="button" onclick="toggleExample('app-bank')" class="tt-app-acc-btn"> 4789 <div class="tt-app-acc-btn__main"> 4790 <div class="tt-app-acc-icon tt-app-acc-icon--cyan"><i class="fas fa-building-columns"></i></div> 4791 <div class="text-left"> 4792 <div class="tt-app-acc-meta"> 4793 <span class="tt-app-scale tt-app-scale--enterprise">Enterprise</span> 4794 <span class="tt-app-context">API · webhooks</span> 4795 </div> 4796 <h3>Regional bank - one API, many decision types</h3> 4797 <p>Programmable trust across lending, merchant onboarding, and hire verification.</p> 4798 </div> 4799 </div> 4800 <i class="fas fa-chevron-down tt-app-chevron" id="app-bank-icon"></i> 4801 </button> 4802 <div id="app-bank" class="hidden tt-app-acc-body"> 4803 <div class="tt-app-flow">ping â directory â generate â poll JSON â webhook delivery</div> 4804 <div class="tt-app-grid-3"> 4805 <div><h4>What you gain</h4><p>Replace emailed PDF chains with audited API workflows. Package entitlements per line of business - pay for contexts you enable, not a monolithic data lock-in.</p></div> 4806 <div><h4>What you use</h4><p>TT_LIVE keys, verified webhooks, Compliance Center export. Same golden path your hub users and core banking integrators share.</p></div> 4807 <div><h4>Your outcome</h4><p>Shorter time-to-yes on thin file. Committee packs with provenance - regulators see process, not opaque scores.</p></div> 4808 </div> 4809 </div> 4810</div> 4811 4812 <div class="gradient-border rounded-2xl overflow-hidden"> 4813 <button type="button" onclick="toggleExample('app-insurer')" class="tt-app-acc-btn"> 4814 <div class="tt-app-acc-btn__main"> 4815 <div class="tt-app-acc-icon tt-app-acc-icon--purple"><i class="fas fa-shield-alt"></i></div> 4816 <div class="text-left"> 4817 <div class="tt-app-acc-meta">
4818 <span class="tt-app-scale tt-app-scale--growth">Growth</span> 4819 <span class="tt-app-context">insurance · risk_compliance</span> 4820 </div> 4821 <h3>Insurer prices risk with context - not guesswork</h3> 4822 <p>Underwriting sees drivers your actuarial team can defend.</p> 4823 </div> 4824 </div> 4825 <i class="fas fa-chevron-down tt-app-chevron" id="app-insurer-icon"></i> 4826 </button> 4827 <div id="app-insurer" class="hidden tt-app-acc-body"> 4828 4829 <div class="tt-app-grid-3"> 4830 <div><h4>What you gain</h4><p>Reach profitable informal-sector lives traditional files mis-price. Optional risk_compliance lens when screening is in scope.</p></div> 4831 <div><h4>What you use</h4><p>Insurance + risk_compliance contexts, Insights Studio explain panel, verify QR for broker and reinsurer packs.</p></div> 4832 <div><h4>Your outcome</h4><p>Fairer premiums, fewer silent exclusions. Adverse-action fields stay with your workflow - we supply infrastructure.</p></div> 4833 </div> 4834 </div> 4835</div> 4836 4837 </div> 4838 4839 <div id="app-panel-people" class="tt-app-panel space-y-4" role="tabpanel" hidden> 4840 <div class="tt-app-callout tt-app-callout--member"> 4841 <i class="fas fa-id-card-clip"></i> 4842 <p><strong>Members are not the product.</strong> You build and <em>choose</em> what to share. Partners and institutions add verified signals that strengthen your Trust CV - but portable proof stays with you across lending, rental, work, and trade.</p> 4843 </div> 4844 <div class="gradient-border rounded-2xl overflow-hidden"> 4845 <button type="button" onclick="toggleExample('app-salon')" class="tt-app-acc-btn"> 4846 <div class="tt-app-acc-btn__main"> 4847 <div class="tt-app-acc-icon tt-app-acc-icon--amber"><i class="fas fa-scissors"></i></div> 4848 <div class="text-left"> 4849 <div class="tt-app-acc-meta"> 4850 <span class="tt-app-scale tt-app-scale--sme">Micro business</span> 4851 <span class="tt-app-context">merchant · lending</span> 4852 </div> 4853 <h3>Salon owner - proof once, capital and leases later</h3> 4854 <p>Your daily business becomes visible to institutions through portable proof.</p> 4855 </div> 4856 </div> 4857 <i class="fas fa-chevron-down tt-app-chevron" id="app-salon-icon"></i> 4858 </button> 4859 <div id="app-salon" class="hidden tt-app-acc-body"> 4860 4861 <div class="tt-app-grid-3"> 4862 <div><h4>What you gain</h4><p>Working-capital and supplier terms without restarting paperwork at every lender. Endorsements and partner merchant events count toward your Trust CV.</p></div> 4863 <div><h4>What you contribute</h4><p>Consented profile, community validation, and shareable Trust CV when a lender requests a lookup - you control the moment of sharing.</p></div> 4864 <div><h4>Your outcome</h4><p>Institution decides with explainable drivers. Same proof works for rental, insurance, and the next loan.</p></div> 4865 </div> 4866 </div> 4867</div> 4868 4869 <div class="gradient-border rounded-2xl overflow-hidden"> 4870 <button type="button" onclick="toggleExample('app-coop')" class="tt-app-acc-btn"> 4871 <div class="tt-app-acc-btn__main"> 4872 <div class="tt-app-acc-icon tt-app-acc-icon--green"><i class="fas fa-seedling"></i></div> 4873 <div class="text-left"> 4874 <div class="tt-app-acc-meta"> 4875 <span class="tt-app-scale tt-app-scale--sme">Cooperative</span> 4876 <span class="tt-app-context">informal_sector · agricultural</span> 4877 </div> 4878 <h3>Farming cooperative - group trust, individual upside</h3> 4879 <p>Ubuntu in practice: collective credibility with portable member proof.</p> 4880 </div> 4881 </div> 4882 <i class="fas fa-chevron-down tt-app-chevron" id="app-coop-icon"></i> 4883 </button> 4884 <div id="app-coop" class="hidden tt-app-acc-body"> 4885 4886 <div class="tt-app-grid-3"> 4887 <div><h4>What you gain</h4><p>Equipment finance and buyer contracts that recognize group accountability - not only individual collateral.</p></div> 4888 <div><h4>
4888What you contribute</h4><p>Member endorsements, officer badges, and seasonal sales signals in agricultural context - strengthened when partner producers participate.</p></div> 4889 <div><h4>Your outcome</h4><p>Investor runs a trust lookup on the group; each member's portable proof compounds season over season.</p></div> 4890 </div> 4891 </div> 4892</div> 4893 4894 <div class="gradient-border rounded-2xl overflow-hidden"> 4895 <button type="button" onclick="toggleExample('app-rental')" class="tt-app-acc-btn"> 4896 <div class="tt-app-acc-btn__main"> 4897 <div class="tt-app-acc-icon tt-app-acc-icon--purple"><i class="fas fa-home"></i></div> 4898 <div class="text-left"> 4899 <div class="tt-app-acc-meta"> 4900 <span class="tt-app-scale tt-app-scale--sme">Individual</span> 4901 <span class="tt-app-context">rental · employment</span> 4902 </div> 4903 <h3>First-time renter - bring proof, not just a deposit</h3> 4904 <p>University and salary history travel as rental context.</p> 4905 </div> 4906 </div> 4907 <i class="fas fa-chevron-down tt-app-chevron" id="app-rental-icon"></i> 4908 </button> 4909 <div id="app-rental" class="hidden tt-app-acc-body"> 4910 4911 <div class="tt-app-grid-3"> 4912 <div><h4>What you gain</h4><p>Fair deposit terms when landlords see consistent payments and verified employment - without restarting paperwork from scratch.</p></div> 4913 <div><h4>What you contribute</h4><p>Trust CV and consented share when the landlord runs an optional lookup; employment badge from a verifier you already trust.</p></div> 4914 <div><h4>Your outcome</h4><p>Documented rental history for the next lease - portable across cities and landlords.</p></div> 4915 </div> 4916 </div> 4917</div> 4918 4919 </div> 4920 4921 <div id="app-panel-compliance" class="tt-app-panel space-y-4" role="tabpanel" hidden> 4922 <div class="tt-app-callout"> 4923 <i class="fas fa-circle-info"></i> 4924 <p><strong>Fail-closed by design.</strong> Screening returns clear, match_review, not_run, or unavailable - never silent clearance. Institutions keep the adverse-action workflow.</p> 4925 </div> 4926 <div class="gradient-border rounded-2xl overflow-hidden"> 4927 <button type="button" onclick="toggleExample('app-aml-bank')" class="tt-app-acc-btn"> 4928 <div class="tt-app-acc-btn__main"> 4929 <div class="tt-app-acc-icon tt-app-acc-icon--red"><i class="fas fa-user-shield"></i></div> 4930 <div class="text-left"> 4931 <div class="tt-app-acc-meta"> 4932 <span class="tt-app-scale tt-app-scale--enterprise">Enterprise</span> 4933 <span class="tt-app-context">risk_compliance · screening</span> 4934 </div> 4935 <h3>Bank onboarding - sanctions, PEP, identity</h3> 4936 <p>Compliance intelligence with provenance for committee packs.</p> 4937 </div> 4938 </div> 4939 <i class="fas fa-chevron-down tt-app-chevron" id="app-aml-bank-icon"></i> 4940 </button> 4941 <div id="app-aml-bank" class="hidden tt-app-acc-body"> 4942 <div class="tt-app-flow">Lookup Studio â risk assessment â compliance_intelligence JSON â audit export</div> 4943 <div class="tt-app-grid-3"> 4944 <div><h4>What you gain</h4><p>Faster onboarding with defensible AML packs - sanctions, PEP, identity, registry, contracted UNSCR when enabled.</p></div> 4945 <div><h4>What you use</h4><p>screening_summary, risk_indicators, coverage_gaps - structured for officers, not black-box clearance.</p></div> 4946 <div><h4>Your outcome</h4><p>Every check is clear, match_review, not_run, or unavailable - and traceable in Compliance Center.</p></div> 4947 </div> 4948 </div> 4949</div> 4950 4951 <div class="gradient-border rounded-2xl overflow-hidden"> 4952 <button type="button" onclick="toggleExample('app-fintech-kyc')" class="tt-app-acc-btn"> 4953 <div class="tt-app-acc-btn__main"> 4954 <div class="tt-app-acc-icon tt-app-acc-icon--orange"><i class="fas fa-user-check"></i></div> 4955 <div class="text-left"> 4956 <div class="tt-app-acc-meta">
4957 <span class="tt-app-scale tt-app-scale--growth">Growth</span> 4958 <span class="tt-app-context">merchant · risk_compliance</span> 4959 </div> 4960 <h3>Fintech merchant KYC + trust lookup in one flow</h3> 4961 <p>Speed for ops; defensibility for compliance.</p> 4962 </div> 4963 </div> 4964 <i class="fas fa-chevron-down tt-app-chevron" id="app-fintech-kyc-icon"></i> 4965 </button> 4966 <div id="app-fintech-kyc" class="hidden tt-app-acc-body"> 4967 4968 <div class="tt-app-grid-3"> 4969 <div><h4>What you gain</h4><p>High-volume signup with screening dossier tier when required - same hub and API contract.</p></div> 4970 <div><h4>What you use</h4><p>merchant_onboarding persona, external-subject screening route, producer events optional on the same platform.</p></div> 4971 <div><h4>Your outcome</h4><p>Risk and growth teams share one audit trail - producers feeding events does not bypass your compliance review.</p></div> 4972 </div> 4973 </div> 4974</div> 4975 4976 <div class="gradient-border rounded-2xl overflow-hidden"> 4977 <button type="button" onclick="toggleExample('app-external')" class="tt-app-acc-btn"> 4978 <div class="tt-app-acc-btn__main"> 4979 <div class="tt-app-acc-icon tt-app-acc-icon--cyan"><i class="fas fa-magnifying-glass"></i></div> 4980 <div class="text-left"> 4981 <div class="tt-app-acc-meta"> 4982 <span class="tt-app-scale tt-app-scale--enterprise">Enterprise</span> 4983 <span class="tt-app-context">external screening</span> 4984 </div> 4985 <h3>Subject not on TumiTrust yet - still screen with confidence</h3> 4986 <p>No dead-end 'not found' when counterparty is external.</p> 4987 </div> 4988 </div> 4989 <i class="fas fa-chevron-down tt-app-chevron" id="app-external-icon"></i> 4990 </button> 4991 <div id="app-external" class="hidden tt-app-acc-body"> 4992 4993 <div class="tt-app-grid-3"> 4994 <div><h4>What you gain</h4><p>Proceed with risk assessment when directory misses - strong identifiers trigger screening path automatically.</p></div> 4995 <div><h4>What you use</h4><p>External screening API (billed separately); preprofile flows when subject joins later - continuity without rework.</p></div> 4996 <div><h4>Your outcome</h4><p>Documented provenance for committees; optional trust layer when they become members.</p></div> 4997 </div> 4998 </div> 4999</div> 5000 5001 </div> 5002 5003 <div class="text-center mt-12"> 5004 <p class="text-lg text-gray-300 mb-6 max-w-2xl mx-auto"> 5005 <span class="text-amber-400 font-bold">20 contexts</span> on one map - 5006 <a href="/docs/pti/reference-architecture/trust-contexts" class="text-amber-300 underline decoration-amber-500/40 hover:text-white">catalogue</a> · 5007 <a href="/solutions/" class="text-amber-300 underline decoration-amber-500/40 hover:text-white">solutions</a> · 5008 <a href="/docs/pti/specification/v1.0/compliance" class="text-amber-300 underline decoration-amber-500/40 hover:text-white">risk & compliance</a> 5009 </p> 5010 <div class="flex flex-wrap gap-3 justify-center"> 5011 <a href="/docs/tumitrust/audiences/for-partners" class="tt-enterprise-btn tt-enterprise-btn--primary">For trust producers</a> 5012 <a href="/docs/tumitrust/audiences/for-institutions" class="tt-enterprise-btn tt-enterprise-btn--secondary">For institutions</a> 5013 <a href="/docs/tumitrust/audiences/for-individuals" class="tt-enterprise-btn tt-enterprise-btn--secondary">For individuals</a> 5014 </div> 5015 </div> 5016 </div> 5017</section> 5018 5019<style> 5020 .tt-applications-section .tt-app-door { 5021 position: relative; padding: 1.25rem 1.15rem; border-radius: 1rem; 5022 border: 1px solid rgba(255,255,255,0.1); background: rgba(15,23,42,0.55); 5023 text-align: left; transition: transform 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease; 5024 } 5025 .tt-applications-section .tt-app-door:hover { 5026 transform: translateY(-3px); border-color: rgba(251,191,36,0.35); 5027 box-shadow: 0 16px 40px -20px rgba(233,84,32,0.35); 5028 } 5029 .tt-applications-section .tt-app-door i { font-size: 1.35rem; margin-bottom: 0.5rem; display: block; } 5030 .tt-applications-section .tt-app-door h3 { color: #fff; font-weight: 800; font-size: 1.05rem; margin: 0 0 0.35rem; } 5031 .tt-applications-section .tt-app-door p { color: #94a3b8; font-size: 0.88rem; line-height: 1.5; margin: 0; } 5032 .tt-applications-section .tt-app-door strong { color: #e2e8f0; } 5033 .tt-applications-section .tt-app-door__tag { 5034 position: absolute; top: 0.65rem; right: 0.65rem; 5035 font-size: 0.62rem; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; 5036 padding: 0.15rem 0.45rem; border-radius: 999px; 5037 } 5038 .tt-app-door--consumer .tt-app-door__tag { background: rgba(34,211,238,0.15); color: #67e8f9; } 5039 .tt-app-door--producer .tt-app-door__tag { background: rgba(251,191,36,0.15); color: #fcd34d; } 5040 .tt-app-door--member .tt-app-door__tag { background: rgba(167,139,250,0.15); color: #c4b5fd; } 5041 .tt-app-door--consumer i { color: #22d3ee; } 5042 .tt-app-door--producer i { color: #fbbf24; } 5043 .tt-app-door--member i { color: #a78bfa; } 5044 .tt-app-value-strip { 5045 display: grid; gap: 0.75rem; margin-bottom: 1.5rem; 5046 grid-template-columns: 1fr; 5047 } 5048 @media (min-width: 768px) { 5049 .tt-app-value-strip { grid-template-columns: repeat(3, 1fr); } 5050 } 5051 .tt-app-value-strip__item { 5052 padding: 0.85rem 1rem; border-radius: 0.75rem; 5053 background: rgba(15,23,42,0.4); border: 1px solid rgba(255,255,255,0.08); 5054 } 5055 .tt-app-value-strip__label { 5056 display: block; font-size: 0.65rem; font-weight: 800; letter-spacing: 0.1em; 5057 text-transform: uppercase; color: #fbbf24; margin-bottom: 0.35rem; 5058 } 5059 .tt-app-value-strip__item p { 5060 margin: 0; font-size: 0.82rem; line-height: 1.5; color: #cbd5e1; 5061 } 5062 .tt-app-tabs { 5063 display: flex; flex-wrap: wrap; gap: 0.5rem; justify-content: center; 5064 margin-bottom: 1.5rem; padding: 0.35rem; 5065 background: rgba(15,23,42,0.45); border-radius: 999px; border: 1px solid rgba(255,255,255,0.08); 5066 } 5067 .tt-app-tab { 5068 display: inline-flex; align-items: center; gap: 0.4rem; 5069 padding: 0.55rem 1rem; border-radius: 999px; border: none; 5070 background: transparent; color: #94a3b8; font-size: 0.82rem; font-weight: 600; 5071 cursor: pointer; transition: all 0.2s ease; 5072 } 5073 .tt-app-tab:hover { color: #e2e8f0; background: rgba(255,255,255,0.06); } 5074 .tt-app-tab--active { 5075 background: linear-gradient(135deg, rgba(233,84,32,0.9), rgba(245,158,11,0.85)); 5076 color: #fff; box-shadow: 0 4px 16px rgba(233,84,32,0.35); 5077 } 5078 .tt-app-panel { display: none; } 5079 .tt-app-panel--active { display: block; animation: ttAppFade 0.35s ease; }
5080 @keyframes ttAppFade { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } } 5081 .tt-app-acc-btn { 5082 width: 100%; padding: 1.15rem 1.35rem; 5083 background: linear-gradient(90deg, rgba(30,41,59,0.65), rgba(15,23,42,0.75)); 5084 display: flex; align-items: center; justify-content: space-between; gap: 1rem; 5085 border: none; cursor: pointer; text-align: left; transition: background 0.2s ease; 5086 } 5087 .tt-app-acc-btn:hover { background: linear-gradient(90deg, rgba(30,41,59,0.85), rgba(15,23,42,0.9)); } 5088 .tt-app-acc-btn__main { display: flex; align-items: center; gap: 1rem; flex: 1; min-width: 0; } 5089 .tt-app-acc-icon { 5090 width: 3rem; height: 3rem; border-radius: 0.85rem; flex-shrink: 0; 5091 display: flex; align-items: center; justify-content: center; font-size: 1.15rem; color: #fff; 5092 } 5093 .tt-app-acc-icon--amber { background: linear-gradient(135deg, #ea580c, #f59e0b); } 5094 .tt-app-acc-icon--cyan { background: linear-gradient(135deg, #0891b2, #22d3ee); } 5095 .tt-app-acc-icon--purple { background: linear-gradient(135deg, #7c3aed, #a78bfa); } 5096 .tt-app-acc-icon--orange { background: linear-gradient(135deg, #e95420, #fb923c); } 5097 .tt-app-acc-icon--green { background: linear-gradient(135deg, #15803d, #4ade80); } 5098 .tt-app-acc-icon--red { background: linear-gradient(135deg, #b91c1c, #f87171); } 5099 .tt-app-acc-btn h3 { color: #fff; font-weight: 800; font-size: 1.05rem; margin: 0 0 0.2rem; line-height: 1.3; } 5100 .tt-app-acc-btn p { color: #94a3b8; font-size: 0.82rem; margin: 0; } 5101 .tt-app-acc-meta { display: flex; flex-wrap: wrap; gap: 0.35rem; margin-bottom: 0.35rem; } 5102 .tt-app-scale { 5103 font-size: 0.62rem; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; 5104 padding: 0.12rem 0.4rem; border-radius: 999px; 5105 } 5106 .tt-app-scale--sme { background: rgba(167,139,250,0.2); color: #c4b5fd; } 5107 .tt-app-scale--growth { background: rgba(251,191,36,0.18); color: #fcd34d; } 5108 .tt-app-scale--enterprise { background: rgba(34,211,238,0.18); color: #67e8f9; } 5109 .tt-app-context { font-size: 0.68rem; color: #64748b; font-family: ui-monospace, monospace; } 5110 .tt-app-chevron { color: #fbbf24; transition: transform 0.3s ease; flex-shrink: 0; } 5111 .tt-app-chevron.rotate-180 { transform: rotate(180deg); } 5112 .tt-app-acc-body { 5113 padding: 1.25rem 1.35rem 1.5rem; background: rgba(15,23,42,0.4); 5114 border-top: 1px solid rgba(255,255,255,0.06); 5115 } 5116 .tt-app-flow { 5117 font-family: ui-monospace, monospace; font-size: 0.75rem; color: #fbbf24; 5118 padding: 0.65rem 0.85rem; margin-bottom: 1rem; border-radius: 0.5rem; 5119 background: rgba(233,84,32,0.08); border: 1px solid rgba(233,84,32,0.22); 5120 } 5121 .tt-app-grid-3 { display: grid; gap: 1rem; grid-template-columns: 1fr; } 5122 @media (min-width: 768px) { .tt-app-grid-3 { grid-template-columns: repeat(3, 1fr); } } 5123 .tt-app-grid-3 h4 { 5124 font-size: 0.72rem; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; 5125 color: #fbbf24; margin: 0 0 0.4rem; 5126 } 5127 .tt-app-grid-3 p { color: #cbd5e1; font-size: 0.88rem; line-height: 1.55; margin: 0; } 5128 .tt-app-grid-3 strong { color: #f1f5f9; } 5129 .tt-app-callout { 5130 display: flex; gap: 0.75rem; align-items: flex-start; 5131 padding: 1rem 1.15rem; border-radius: 0.75rem; 5132 background: rgba(233,84,32,0.1); border: 1px solid rgba(233,84,32,0.28); margin-bottom: 0.5rem; 5133 } 5134 .tt-app-callout i { color: #fbbf24; margin-top: 0.15rem; } 5135 .tt-app-callout p { margin: 0; color: #e2e8f0; font-size: 0.9rem; line-height: 1.55; } 5136 .tt-app-callout--producer { 5137 background: rgba(251,191,36,0.12); border-color: rgba(251,191,36,0.35); 5138 } 5139 .tt-app-callout--producer i { color: #fcd34d; } 5140 .tt-app-callout--member { 5141 background: rgba(167,139,250,0.1); border-color: rgba(167,139,250,0.3); 5142 } 5143 .tt-app-callout--member i { color: #c4b5fd; } 5144</style> 5145
5146<script> 5147 function toggleExample(exampleId) { 5148 const content = document.getElementById(exampleId); 5149 const icon = document.getElementById(exampleId + '-icon'); 5150 if (!content || !icon) return; 5151 const isHidden = content.classList.contains('hidden'); 5152 document.querySelectorAll('.tt-app-acc-body[id^="app-"]').forEach(el => el.classList.add('hidden')); 5153 document.querySelectorAll('.tt-app-chevron').forEach(el => el.classList.remove('rotate-180')); 5154 if (isHidden) { 5155 content.classList.remove('hidden'); 5156 icon.classList.add('rotate-180'); 5157 setTimeout(() => content.closest('.gradient-border')?.scrollIntoView({ behavior: 'smooth', block: 'nearest' }), 80); 5158 } 5159 } 5160 document.querySelectorAll('.tt-app-tab').forEach(tab => { 5161 tab.addEventListener('click', () => { 5162 const target = tab.getAttribute('data-app-tab'); 5163 document.querySelectorAll('.tt-app-tab').forEach(t => { 5164 t.classList.remove('tt-app-tab--active'); 5165 t.setAttribute('aria-selected', 'false'); 5166 }); 5167 tab.classList.add('tt-app-tab--active'); 5168 tab.setAttribute('aria-selected', 'true'); 5169 document.querySelectorAll('.tt-app-panel').forEach(panel => { 5170 const active = panel.id === 'app-panel-' + target; 5171 panel.classList.toggle('tt-app-panel--active', active); 5172 panel.hidden = !active; 5173 }); 5174 document.querySelectorAll('.tt-app-acc-body').forEach(el => el.classList.add('hidden')); 5175 document.querySelectorAll('.tt-app-chevron').forEach(el => el.classList.remove('rotate-180')); 5176 }); 5177 }); 5178</script>
5178 5179 5180 5181 <!-- Interactive trust score calculator --> 5182 <section class="py-24 px-4 relative" style="z-index: 50; position: relative;"> 5183 <div class="container mx-auto max-w-6xl"> 5184 <div class="text-center mb-16"> 5185 <div class="inline-flex items-center gap-2 px-5 py-2 bg-gradient-to-r from-green-500/20 to-emerald-500/20 border border-green-500/30 rounded-full mb-6"> 5186 <i class="fas fa-passport text-green-400"></i> 5187 <span class="text-green-300 font-semibold text-sm">Interactive PTI preview</span> 5188 </div> 5189 <h2 class="text-5xl md:text-6xl font-black mb-6"> 5190 <span class="holographic-text">Feel your</span> 5191 <br/> 5192 <span class="text-white">TumiTrust score</span> 5193 </h2> 5194 <p class="text-xl text-gray-300 max-w-3xl mx-auto leading-relaxed"> 5195 One Portable Trust ID. Twenty life contexts. This demo shows how endorsements, coverage, and proof combine into a readable indicator - not a bureau black box. 5196 </p> 5197 </div> 5198 5199 <div class="gradient-border rounded-3xl p-8 md:p-12"> 5200 <div class="grid md:grid-cols-2 gap-12"> 5201 <!-- Calculator Inputs --> 5202 <div class="space-y-6"> 5203 <h3 class="text-2xl font-black text-white mb-8">Build Your Profile</h3> 5204 5205 <!-- Endorsements Slider --> 5206 <div> 5207 <div class="flex items-center justify-between mb-3"> 5208 <label class="text-white font-semibold flex items-center gap-2"> 5209 <i class="fas fa-users text-orange-400"></i> 5210 Trust Endorsements 5211 </label> 5212 <span class="text-2xl font-black text-orange-400" id="endorsement-count">0</span> 5213 </div> 5214 <input type="range" min="0" max="50" value="0" class="score-slider w-full" id="endorsements" oninput="ttRecalcLandingTrustDemo()"> 5215 <div class="flex justify-between text-xs text-gray-400 mt-1"> 5216 <span>0</span> 5217 <span>50+</span> 5218 </div> 5219 </div> 5220 5221 <!-- Context Coverage --> 5222 <div> 5223 <div class="flex items-center justify-between mb-3"> 5224 <label class="text-white font-semibold flex items-center gap-2"> 5225 <i class="fas fa-th-large text-cyan-400"></i> 5226 Trust Contexts Covered 5227 </label> 5228 <span class="text-2xl font-black text-cyan-400" id="context-count">0</span> 5229 </div> 5230 <input type="range" min="0" max="20" value="0" class="score-slider w-full" id="contexts" oninput="ttRecalcLandingTrustDemo()"> 5231 <div class="flex justify-between text-xs text-gray-400 mt-1"> 5232 <span>0</span> 5233 <span>20 contexts</span> 5234 </div> 5235 <div class="text-xs text-gray-400 mt-2 leading-relaxed"> 5236 <span class="text-amber-300/80 font-semibold">10 primary</span> decision areas + <span class="text-cyan-300/80 font-semibold">10 lenses</span> on the same proof fabric - chips on the right light up as you slide. 5237 <a href="/docs/tumitrust/platform/partner-trust-contexts" class="tt-public-docs-link">Canonical map â</a> 5238 </div> 5239 </div> 5240 5241 <!-- Badges Slider --> 5242 <div> 5243 <div class="flex items-center justify-between mb-3"> 5244 <label class="text-white font-semibold flex items-center gap-2"> 5245 <i class="fas fa-award text-amber-400"></i> 5246 Verified Badges 5247 </label>
5248 <span class="text-2xl font-black text-amber-400" id="badge-count">0</span> 5249 </div> 5250 <input type="range" min="0" max="10" value="0" class="score-slider w-full" id="badges" oninput="ttRecalcLandingTrustDemo()"> 5251 <div class="flex justify-between text-xs text-gray-400 mt-1"> 5252 <span>0</span> 5253 <span>10+</span> 5254 </div> 5255 </div> 5256 5257 <!-- Document Upload History --> 5258 <div> 5259 <div class="flex items-center justify-between mb-3"> 5260 <label class="text-white font-semibold flex items-center gap-2"> 5261 <i class="fas fa-file-invoice text-green-400"></i> 5262 Documents Uploaded 5263 </label> 5264 <span class="text-2xl font-black text-green-400" id="document-count">0</span> 5265 </div> 5266 <input type="range" min="0" max="15" value="0" class="score-slider w-full" id="documents" oninput="ttRecalcLandingTrustDemo()"> 5267 <div class="flex justify-between text-xs text-gray-400 mt-1"> 5268 <span>0</span> 5269 <span>15+</span> 5270 </div> 5271 <div class="text-xs text-gray-400 mt-2"> 5272 Payslips, utility bills, receipts, mobile money statements 5273 </div> 5274 </div> 5275 5276 <!-- Network Size --> 5277 <div> 5278 <div class="flex items-center justify-between mb-3"> 5279 <label class="text-white font-semibold flex items-center gap-2"> 5280 <i class="fas fa-project-diagram text-blue-400"></i> 5281 Network Size 5282 </label> 5283 <span class="text-2xl font-black text-blue-400" id="network-count">0</span> 5284 </div> 5285 <input type="range" min="0" max="100" value="0" class="score-slider w-full" id="network" oninput="ttRecalcLandingTrustDemo()"> 5286 <div class="flex justify-between text-xs text-gray-400 mt-1"> 5287 <span>0</span> 5288 <span>100+</span> 5289 </div> 5290 </div> 5291 5292 <!-- Employment Status --> 5293 <div> 5294 <label class="text-white font-semibold flex items-center gap-2 mb-3"> 5295 <i class="fas fa-briefcase text-purple-400"></i> 5296 Employment Status 5297 </label> 5298 <select class="w-full bg-white/10 border border-white/20 rounded-xl px-4 py-3 text-white" id="employment" onchange="ttRecalcLandingTrustDemo()"> 5299 <option value="0">Unemployed</option> 5300 <option value="30">Informal Sector</option> 5301 <option value="60">Formal Employment (Unverified)</option> 5302 <option value="120">Formal Employment (Verified)</option> 5303 </select> 5304 </div> 5305 </div> 5306 5307 <!-- Score Display --> 5308 <div class="flex flex-col justify-center"> 5309 <div class="relative"> 5310 <!-- Circular Progress --> 5311 <div class="relative w-80 h-80 mx-auto mb-8"> 5312 <svg class="transform -rotate-90 w-full h-full"> 5313 <!-- Background Circle --> 5314 <circle cx="160" cy="160" r="140" stroke="rgba(255,255,255,0.1)" stroke-width="20" fill="none"/> 5315 <!-- Progress Circle --> 5316 <circle id="progress-circle" cx="160" cy="160" r="140" stroke="url
5316(#gradient)" stroke-width="20" fill="none" stroke-linecap="round" 5317 style="stroke-dasharray: 880; stroke-dashoffset: 880; transition: stroke-dashoffset 0.5s ease;"/> 5318 <defs> 5319 <linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="100%"> 5320 <stop offset="0%" style="stop-color:#ff6600;stop-opacity:1" /> 5321 <stop offset="50%" style="stop-color:#ffaa00;stop-opacity:1" /> 5322 <stop offset="100%" style="stop-color:#fbbf24;stop-opacity:1" /> 5323 </linearGradient> 5324 </defs> 5325 </svg> 5326 5327 <!-- Profile indicator text --> 5328 <div class="absolute inset-0 flex flex-col items-center justify-center px-3 min-w-0"> 5329 <div class="text-xs uppercase tracking-widest text-amber-300/70 mb-1">TumiTrust score</div> 5330 <div class="w-full min-w-0 max-w-[min(100%,11rem)] sm:max-w-[min(100%,13rem)] mx-auto text-4xl sm:text-5xl md:text-6xl font-black holographic-text mb-1 leading-none tabular-nums tracking-tight text-center overflow-hidden text-ellipsis whitespace-nowrap" id="calculated-score">300</div> 5331 <div class="text-gray-400 text-sm tabular-nums" id="score-denominator" aria-hidden="true">/1000 · demo</div> 5332 <div class="mt-4 px-4 py-2 bg-gradient-to-r from-orange-500/20 to-amber-500/20 border border-orange-500/50 rounded-full"> 5333 <span class="text-orange-300 font-bold text-sm" id="score-level">Starting Out</span> 5334 </div> 5335 </div> 5336 </div> 5337 5338 <!-- What This Unlocks --> 5339 <div class="bg-gradient-to-br from-white/5 to-white/0 backdrop-blur-sm border border-white/10 rounded-2xl p-6"> 5340 <h4 class="text-xl font-black text-white mb-1 flex items-center gap-2"> 5341 <i class="fas fa-id-card text-amber-400"></i> 5342 Your trust passport 5343 </h4> 5344 <p class="text-sm text-gray-400 mb-1 leading-relaxed"> 5345 PTI covers <strong class="text-white">20 life contexts</strong> - 10 primary decision areas, plus 10 lenses. Slide <strong class="text-cyan-300">Trust Contexts Covered</strong> to light them up. 5346 </p> 5347 <p class="text-xs text-gray-500 mb-4"> 5348 Illustrative only. Live scores are TumiTrust indicators (0â1000 headline) with reasons - not a bureau number. 5349 </p> 5350 <div id="opportunities" class="space-y-1.5 max-h-56 md:max-h-72 overflow-y-auto pr-1 text-left"> 5351 <div class="flex items-center gap-3 text-gray-400"> 5352 <i class="fas fa-lock text-gray-600"></i> 5353 <span>Build coverage to unlock context rows</span> 5354 </div> 5355 </div> 5356 5357 <div class="mt-5 pt-4 border-t border-white/10" id="documented-contexts-legend" aria-label="Portable Trust ID - 20 contexts"> 5358 <div class="flex items-center justify-between gap-2 mb-2"> 5359 <p class="text-[11px] font-bold uppercase tracking-[0.14em] text-amber-300/90 m-0">Primary · 10</p> 5360 <p class="text-[10px] text-gray-500 m-0">Where decisions usually start</p> 5361 </div> 5362 <div class="flex flex-wrap gap-1.5 w-full min-w-0 mb-4" aria-label="Primary trust c
5362ontexts"> 5363 <span data-context-slot="1" class="tt-calc-ctx-chip inline-flex items-center gap-1 px-2 py-0.5 rounded-md bg-white/5 border border-white/10 text-[11px] text-gray-300 transition-all duration-300"><i class="fas fa-coins text-[9px] text-amber-400/80" aria-hidden="true"></i>Lending</span> 5364 <span data-context-slot="2" class="tt-calc-ctx-chip inline-flex items-center gap-1 px-2 py-0.5 rounded-md bg-white/5 border border-white/10 text-[11px] text-gray-300 transition-all duration-300"><i class="fas fa-home text-[9px] text-amber-400/80" aria-hidden="true"></i>Rental</span> 5365 <span data-context-slot="3" class="tt-calc-ctx-chip inline-flex items-center gap-1 px-2 py-0.5 rounded-md bg-white/5 border border-white/10 text-[11px] text-gray-300 transition-all duration-300"><i class="fas fa-briefcase text-[9px] text-amber-400/80" aria-hidden="true"></i>Employment</span> 5366 <span data-context-slot="4" class="tt-calc-ctx-chip inline-flex items-center gap-1 px-2 py-0.5 rounded-md bg-white/5 border border-white/10 text-[11px] text-gray-300 transition-all duration-300"><i class="fas fa-shield-alt text-[9px] text-amber-400/80" aria-hidden="true"></i>Insurance</span> 5367 <span data-context-slot="5" class="tt-calc-ctx-chip inline-flex items-center gap-1 px-2 py-0.5 rounded-md bg-white/5 border border-white/10 text-[11px] text-gray-300 transition-all duration-300"><i class="fas fa-store text-[9px] text-amber-400/80" aria-hidden="true"></i>Merchant</span> 5368 <span data-context-slot="6" class="tt-calc-ctx-chip inline-flex items-center gap-1 px-2 py-0.5 rounded-md bg-white/5 border border-white/10 text-[11px] text-gray-300 transition-all duration-300"><i class="fas fa-handshake text-[9px] text-amber-400/80" aria-hidden="true"></i>Partnership</span> 5369 <span data-context-slot="7" class="tt-calc-ctx-chip inline-flex items-center gap-1 px-2 py-0.5 rounded-md bg-white/5 border border-white/10 text-[11px] text-gray-300 transition-all duration-300"><i class="fas fa-truck text-[9px] text-amber-400/80" aria-hidden="true"></i>Supplier</span> 5370 <span data-context-slot="8" class="tt-calc-ctx-chip inline-flex items-center gap-1 px-2 py-0.5 rounded-md bg-white/5 border border-white/10 text-[11px] text-gray-300 transition-all duration-300"><i class="fas fa-users text-[9px] text-amber-400/80" aria-hidden="true"></i>Informal</span> 5371 <span data-context-slot="9" class="tt-calc-ctx-chip inline-flex items-center gap-1 px-2 py-0.5 rounded-md bg-white/5 border border-white/10 text-[11px] text-gray-300 transition-all duration-300"><i class="fas fa-seedling text-[9px] text-amber-400/80" aria-hidden="true"></i>Agriculture</span> 5372 <span data-context-slot="10" class="tt-calc-ctx-chip inline-flex items-center gap-1 px-2 py-0.5 rounded-md bg-white/5 border border-white/10 text-[11px] text-gray-300 transition-all duration-300"><i class="fas fa-exchange-alt text-[9px] text-amber-400/80" aria-hidden="true"></i>Remittance</span> 5373 </div> 5374 5375 <div class="flex items-center justify-between gap-2 mb-2"> 5376 <p class="text-[11px] font-bold uppercase tracking-[0.14em] text-cyan-300/90 m-0">Lenses · 10</p> 5377 <p class="text-[10px] text-gray-500 m-0">Cross-cutting views on the same proof</p> 5378 </div> 5379 <div class="flex flex-wrap gap-1.5 w-full min-w-0" aria-label="Trust context lenses"> 5380 <span data-context-slot="11" class="tt-calc-ctx-chip inline-flex items-center gap-1 px-2 py-0.5 rounded-md bg-sky-500/10 border border-sky-400/25 text-[11px] text-sky-200 transition-all duration-300"><i class="fas fa-graduation-cap text-[9px]" aria-hidden="true"></i>Education</span>
5381 <span data-context-slot="12" class="tt-calc-ctx-chip inline-flex items-center gap-1 px-2 py-0.5 rounded-md bg-rose-500/10 border border-rose-400/25 text-[11px] text-rose-200 transition-all duration-300"><i class="fas fa-heartbeat text-[9px]" aria-hidden="true"></i>Health</span> 5382 <span data-context-slot="13" class="tt-calc-ctx-chip inline-flex items-center gap-1 px-2 py-0.5 rounded-md bg-pink-500/10 border border-pink-400/25 text-[11px] text-pink-200 transition-all duration-300"><i class="fas fa-people-roof text-[9px]" aria-hidden="true"></i>Family</span> 5383 <span data-context-slot="14" class="tt-calc-ctx-chip inline-flex items-center gap-1 px-2 py-0.5 rounded-md bg-emerald-500/10 border border-emerald-400/25 text-[11px] text-emerald-200 transition-all duration-300"><i class="fas fa-landmark text-[9px]" aria-hidden="true"></i>Civic</span> 5384 <span data-context-slot="15" class="tt-calc-ctx-chip inline-flex items-center gap-1 px-2 py-0.5 rounded-md bg-violet-500/10 border border-violet-400/25 text-[11px] text-violet-200 transition-all duration-300"><i class="fas fa-laptop text-[9px]" aria-hidden="true"></i>Digital</span> 5385 <span data-context-slot="16" class="tt-calc-ctx-chip inline-flex items-center gap-1 px-2 py-0.5 rounded-md bg-amber-500/10 border border-amber-400/25 text-[11px] text-amber-200 transition-all duration-300"><i class="fas fa-route text-[9px]" aria-hidden="true"></i>Mobility</span> 5386 <span data-context-slot="17" class="tt-calc-ctx-chip inline-flex items-center gap-1 px-2 py-0.5 rounded-md bg-yellow-500/10 border border-yellow-400/25 text-[11px] text-yellow-100 transition-all duration-300"><i class="fas fa-bolt text-[9px]" aria-hidden="true"></i>Utilities</span> 5387 <span data-context-slot="18" class="tt-calc-ctx-chip inline-flex items-center gap-1 px-2 py-0.5 rounded-md bg-orange-500/10 border border-orange-400/25 text-[11px] text-orange-200 transition-all duration-300"><i class="fas fa-palette text-[9px]" aria-hidden="true"></i>Creative</span> 5388 <span data-context-slot="19" class="tt-calc-ctx-chip inline-flex items-center gap-1 px-2 py-0.5 rounded-md bg-orange-500/10 border border-orange-300/30 text-[11px] text-orange-100 transition-all duration-300"><i class="fas fa-handshake-angle text-[9px]" aria-hidden="true"></i>Faith & aid</span> 5389 <span data-context-slot="20" class="tt-calc-ctx-chip inline-flex items-center gap-1 px-2 py-0.5 rounded-md bg-red-500/15 border border-red-400/35 text-[11px] text-red-100 transition-all duration-300"><i class="fas fa-shield-halved text-[9px]" aria-hidden="true"></i>Risk & compliance</span> 5390 </div> 5391 </div> 5392 </div> 5393 5394 <!-- CTA --> 5395 <div class="mt-8 text-center"> 5396 <a href="/register/" class="inline-flex items-center gap-3 px-8 py-4 bg-gradient-to-r from-orange-500 to-amber-500 hover:from-orange-600 hover:to-amber-600 rounded-xl text-white font-bold text-lg transition-all shadow-lg hover:shadow-xl hover:scale-105"> 5397 <i class="fas fa-rocket"></i> 5398 Get Started 5399 <i class="fas fa-arrow-right"></i> 5400 </a> 5401 <p class="text-gray-400 text-sm mt-3">Free ⢠Takes 2 minutes ⢠No credit card required</p> 5402 </div> 5403 </div> 5404 </div> 5405 </div> 5406 </div> 5407 </div> 5408 </section> 5409 5410
5410<script> 5411 (function () { 5412 const TT_CALC_MAX = 1000; 5413 const TT_CALC_ROWS = [ 5414 ['fa-coins', 'Lending'], 5415 ['fa-home', 'Rental'], 5416 ['fa-briefcase', 'Employment'], 5417 ['fa-shield-alt', 'Insurance'], 5418 ['fa-store', 'Merchant'], 5419 ['fa-handshake', 'Partnership'], 5420 ['fa-truck', 'Supplier'], 5421 ['fa-users', 'Informal sector'], 5422 ['fa-seedling', 'Agricultural'], 5423 ['fa-exchange-alt', 'Remittance'], 5424 ['fa-graduation-cap', 'Education'], 5425 ['fa-heart-pulse', 'Health'], 5426 ['fa-people-roof', 'Family'], 5427 ['fa-landmark', 'Civic'], 5428 ['fa-laptop-code', 'Digital platform'], 5429 ['fa-route', 'Mobility'], 5430 ['fa-bolt', 'Utilities'], 5431 ['fa-palette', 'Creative'], 5432 ['fa-handshake-angle', 'Faith & mutual aid'], 5433 ['fa-shield-halved', 'Risk & compliance'], 5434 ]; 5435 5436 function ttCalcUpdateLegendChips(contexts) { 5437 document.querySelectorAll('#documented-contexts-legend [data-context-slot]').forEach(function (el) { 5438 var slot = parseInt(el.getAttribute('data-context-slot'), 10); 5439 var on = contexts >= slot; 5440 el.classList.toggle('opacity-40', !on); 5441 el.classList.toggle('scale-95', !on); 5442 el.classList.toggle('ring-2', on); 5443 el.classList.toggle('ring-emerald-400/70', on); 5444 el.classList.toggle('shadow', on); 5445 el.classList.toggle('shadow-emerald-500/25', on); 5446 el.classList.toggle('brightness-110', on); 5447 }); 5448 } 5449 5450 function ttRecalcLandingTrustDemo() { 5451 var endorsements = parseInt(document.getElementById('endorsements').value, 10) || 0; 5452 var contexts = parseInt(document.getElementById('contexts').value, 10) || 0; 5453 var badges = parseInt(document.getElementById('badges').value, 10) || 0; 5454 var documents = parseInt(document.getElementById('documents').value, 10) || 0; 5455 var network = parseInt(document.getElementById('network').value, 10) || 0; 5456 var employment = parseInt(document.getElementById('employment').value, 10) || 0; 5457 5458 var endorsementCount = document.getElementById('endorsement-count'); 5459 var contextCount = document.getElementById('context-count'); 5460 var badgeCount = document.getElementById('badge-count'); 5461 var documentCount = document.getElementById('document-count'); 5462 var networkCount = document.getElementById('network-count'); 5463 if (endorsementCount) endorsementCount.textContent = endorsements; 5464 if (contextCount) contextCount.textContent = contexts; 5465 if (badgeCount) badgeCount.textContent = badges; 5466 if (documentCount) documentCount.textContent = documents; 5467 if (networkCount) networkCount.textContent = network; 5468 5469 var raw = 5470 300 + 5471 endorsements * 8 + 5472 Math.round((contexts * 250) / 20) + 5473 badges * 15 + 5474 documents * 6 + 5475 network * 2 + 5476 employment; 5477 var score = Math.min(Math.max(0, Math.round(Number(raw)) || 0), TT_CALC_MAX); 5478 5479 var calculatedScore = document.getElementById('calculated-score'); 5480 if (calculatedScore) calculatedScore.textContent = String(score); 5481 var scoreDenom = document.getElementById('score-denominator'); 5482 if (scoreDenom) scoreDenom.textContent = '/' + TT_CALC_MAX; 5483 5484 var circumference = 880; 5485 var progress = (score / TT_CALC_MAX) * circumference; 5486 var offset = circumference - progress; 5487 var pc = document.getElementById('progress-circle'); 5488 if (pc) pc.style.strokeDashoffset = String(offset); 5489 5490 var level, levelColor; 5491 if (score < 450) { 5492 level = 'Starting Out'; 5493 levelColor = 'text-gray-400'; 5494 } else if (score < 600) { 5495 level = 'Building Trust'; 5496 levelColor = 'text-blue-400'; 5497 } else if (score < 750) { 5498 level = 'Good Standing'; 5499 levelColor = 'text-green-400'; 5500 } else if (score < 900) { 5501 level = 'Excellent'; 5502 levelColor = 'text-amber-400'; 5503 } else { 5504 level = 'Outstanding'; 5505 levelColor = 'text-orange-400'; 5506 } 5507 5508 var levelEl = document.getElementById('score-level'); 5509 if (levelEl) { 5510 levelEl.textContent = level; 5511 levelEl.className = 'font-bold text-sm ' + levelColor; 5512 } 5513 5514 var rowsHtml = []; 5515 for (var i = 0; i < TT_CALC_ROWS.length; i++) { 5516 var slot = i + 1; 5517 var on = contexts >= slot; 5518 var pair = TT_CALC_ROWS[i]; 5519 var icon = pair[0]; 5520 var label = pair[1]; 5521 var rowClass = on ? 'text-emerald-300' : 'text-gray-500'; 5522 var iconClass = on ? 'text-emerald-400' : 'text-gray-600'; 5523 var mark = on ? 'fa-check-circle' : 'fa-lock'; 5524 rowsHtml.push( 5525 '<div class="flex items-center gap-2 text-xs sm:text-sm ' + 5526 rowClass + 5527 '">' + 5528 '<span class="w-5 text-center text-[10px] font-mono text-gray-500">' + 5529 slot + 5530 '</span>' + 5531 '<i class="fas ' + 5532 icon + 5533 ' w-4 ' + 5534 iconClass + 5535 '" aria-hidden="true"></i>' + 5536 '<span class="font-medium flex-1 min-w-0">' + 5537 label + 5538 '</span>' + 5539 '<i class="fas ' + 5540 mark + 5541 ' ' + 5542 iconClass + 5543 '" aria-hidden="true"></i>' + 5544 '</div>' 5545 ); 5546 } 5547 if (contexts >= 20) { 5548 rowsHtml.push( 5549 '<div class="mt-2 pt-2 border-t border-white/10 flex items-center gap-2 text-amber-300 text-xs">' + 5550 '<i class="fas fa-star" aria-hidden="true"></i>' + 5551 '<span><strong>Full map</strong> - all 20 documented contexts in this preview.</span>' + 5552 '</div>' 5553 ); 5554 } 5555 5556 var opp = document.getElementById('opportunities'); 5557 if (opp) opp.innerHTML = rowsHtml.join(''); 5558 5559 ttCalcUpdateLegendChips(contexts); 5560 } 5561 5562 window.ttRecalcLandingTrustDemo = ttRecalcLandingTrustDemo; 5563 window.calculateScore = ttRecalcLandingTrustDemo; 5564 5565 ttRecalcLandingTrustDemo(); 5566 })(); 5567 </script>
5567 5568 5569 <style> 5570 .score-slider { 5571 -webkit-appearance: none; 5572 appearance: none; 5573 height: 8px; 5574 border-radius: 5px; 5575 background: linear-gradient(90deg, rgba(255,102,0,0.3) 0%, rgba(255,170,0,0.3) 50%, rgba(251,191,36,0.3) 100%); 5576 outline: none; 5577 transition: all 0.3s; 5578 } 5579 5580 .score-slider::-webkit-slider-thumb { 5581 -webkit-appearance: none; 5582 appearance: none; 5583 width: 24px; 5584 height: 24px; 5585 border-radius: 50%; 5586 background: linear-gradient(135deg, #ff6600, #ffaa00); 5587 cursor: pointer; 5588 box-shadow: 0 4px 12px rgba(255,102,0,0.5); 5589 transition: all 0.3s; 5590 } 5591 5592 .score-slider::-webkit-slider-thumb:hover { 5593 transform: scale(1.2); 5594 box-shadow: 0 6px 16px rgba(255,102,0,0.7); 5595 } 5596 5597 .score-slider::-moz-range-thumb { 5598 width: 24px; 5599 height: 24px; 5600 border-radius: 50%; 5601 background: linear-gradient(135deg, #ff6600, #ffaa00); 5602 cursor: pointer; 5603 border: none; 5604 box-shadow: 0 4px 12px rgba(255,102,0,0.5); 5605 transition: all 0.3s; 5606 } 5607 5608 .score-slider::-moz-range-thumb:hover { 5609 transform: scale(1.2); 5610 box-shadow: 0 6px 16px rgba(255,102,0,0.7); 5611 } 5612 </style> 5613 5614 5615 5616 <!-- ð¯ FAQ SECTION WITH STRUCTURED DATA --> 5617 <section class="py-24 px-4 relative" style="z-index: 50;" itemscope itemtype="https://schema.org/FAQPage"> 5618 <div class="container mx-auto max-w-4xl"> 5619 <div class="text-center mb-16"> 5620 <div class="inline-flex items-center gap-2 px-4 py-2 bg-gradient-to-r from-orange-500/20 to-amber-500/20 border border-orange-500/30 rounded-full mb-6"> 5621 <i class="fas fa-question-circle text-orange-400"></i> 5622 <span class="text-orange-300 font-semibold text-sm">Frequently Asked Questions</span> 5623 </div> 5624 <h2 class="text-4xl md:text-5xl font-black text-white mb-4"> 5625 Got Questions? We've Got Answers 5626 </h2> 5627 <p class="text-lg text-gray-300"> 5628 Category, value, and data - the questions enterprises ask first 5629 </p> 5630 </div> 5631 5632 <div class="space-y-4"> 5633 5634 5635 5636<div class="bg-gradient-to-br from-gray-800/50 to-gray-900/50 backdrop-blur-sm rounded-2xl border border-gray-700/50 overflow-hidden hover:border-orange-500/50 transition-all" itemscope itemprop="mainEntity" itemtype="https://schema.org/Question"> 5637 <button class="w-full px-6 py-5 flex items-center justify-between text-left" onclick="toggleFAQ(this)"> 5638 <h3 class="text-lg font-bold text-white pr-4" itemprop="name">What is TumiTrust?</h3> 5639 <i class="fas fa-chevron-down text-orange-400 transition-transform duration-300"></i> 5640 </button> 5641 <div class="faq-answer hidden px-6 pb-5" itemscope itemprop="acceptedAnswer" itemtype="https://schema.org/Answer"> 5642 <div itemprop="text" class="text-gray-300 leading-relaxed"> 5643 <p>Portable Trust Infrastructure (PTI) in production - verified activity becomes structured trust signals for authorized decisions. <a href="#whatIsPti" class="tt-public-docs-link">What is PTI â</a> · <a href="/faq/" class="tt-public-docs-link">Full FAQ</a></p> 5644 </div> 5645 </div> 5646</div> 5647 5648<div class="bg-gradient-to-br from-gray-800/50 to-gray-900/50 backdrop-blur-sm rounded-2xl border border-gray-700/50 overflow-hidden hover:border-orange-500/50 transition-all" itemscope itemprop="mainEntity" itemtype="https://schema.org/Question"> 5649 <button class="w-full px-6 py-5 flex items-center justify-between text-left" onclick="toggleFAQ(this)"> 5650 <h3 class="text-lg font-bold text-white pr-4" itemprop="name">Who uses TumiTrust?</h3> 5651 <i class="fas fa-chevron-down text-orange-400 transition-transform duration-300"></i> 5652 </button> 5653 <div class="faq-answer hidden px-6 pb-5" itemscope itemprop="acceptedAnswer" itemtype="https://schema.org/Answer"> 5654 <div itemprop="text" class="text-gray-300 leading-relaxed"> 5655 <p>Institutions that decide, partners that attest, and people who carry a Trust CV. <a href="#whoIsTumiTrustFor" class="tt-public-docs-link">Three paths â</a></p> 5656 </div> 5657 </div> 5658</div> 5659 5660<div class="bg-gradient-to-br from-gray-800/50 to-gray-900/50 backdrop-blur-sm rounded-2xl border border-gray-700/50 overflow-hidden hover:border-orange-500/50 transition-all" itemscope itemprop="mainEntity" itemtype="https://schema.org/Question"> 5661 <button class="w-full px-6 py-5 flex items-center justify-between text-left" onclick="toggleFAQ(this)"> 5662 <h3 class="text-lg font-bold text-white pr-4" itemprop="name">Are organizations sharing their data lakes with you?</h3> 5663 <i class="fas fa-chevron-down text-orange-400 transition-transform duration-300"></i> 5664 </button> 5665 <div class="faq-answer hidden px-6 pb-5" itemscope itemprop="acceptedA
5665nswer" itemtype="https://schema.org/Answer"> 5666 <div itemprop="text" class="text-gray-300 leading-relaxed"> 5667 <p>No. Signals move when there is an authorized purpose and permissions - not a mandate to upload your book. <a href="#trustProducers" class="tt-public-docs-link">For trust producers â</a></p> 5668 </div> 5669 </div> 5670</div> 5671 5672<div class="bg-gradient-to-br from-gray-800/50 to-gray-900/50 backdrop-blur-sm rounded-2xl border border-gray-700/50 overflow-hidden hover:border-orange-500/50 transition-all" itemscope itemprop="mainEntity" itemtype="https://schema.org/Question"> 5673 <button class="w-full px-6 py-5 flex items-center justify-between text-left" onclick="toggleFAQ(this)"> 5674 <h3 class="text-lg font-bold text-white pr-4" itemprop="name">What about screening / sanctions checks?</h3> 5675 <i class="fas fa-chevron-down text-orange-400 transition-transform duration-300"></i> 5676 </button> 5677 <div class="faq-answer hidden px-6 pb-5" itemscope itemprop="acceptedAnswer" itemtype="https://schema.org/Answer"> 5678 <div itemprop="text" class="text-gray-300 leading-relaxed"> 5679 <p>Optional product alongside PTI - sanctions, PEP, and related lists when compliance needs them. <a href="/docs/tumitrust/platform/screening-services" class="tt-public-docs-link">Screening services â</a></p> 5680 </div> 5681 </div> 5682</div> 5683 5684<div class="bg-gradient-to-br from-gray-800/50 to-gray-900/50 backdrop-blur-sm rounded-2xl border border-gray-700/50 overflow-hidden hover:border-orange-500/50 transition-all" itemscope itemprop="mainEntity" itemtype="https://schema.org/Question"> 5685 <button class="w-full px-6 py-5 flex items-center justify-between text-left" onclick="toggleFAQ(this)"> 5686 <h3 class="text-lg font-bold text-white pr-4" itemprop="name">How do we integrate?</h3> 5687 <i class="fas fa-chevron-down text-orange-400 transition-transform duration-300"></i> 5688 </button> 5689 <div class="faq-answer hidden px-6 pb-5" itemscope itemprop="acceptedAnswer" itemtype="https://schema.org/Answer"> 5690 <div itemprop="text" class="text-gray-300 leading-relaxed"> 5691 <p>API-first: authenticate, resolve directory, generate a trust lookup, then poll or webhook. <a href="/docs/tumitrust/developer-guides/trust-platform-api" class="tt-public-docs-link">Trust platform API â</a> · <a href="/developers/" class="tt-public-docs-link">Developers hub</a></p> 5692 </div> 5693 </div> 5694</div> 5695 5696 5697 5698 </div> 5699 5700 <!-- CTA after FAQ --> 5701 <div class="mt-12 text-center"> 5702 <p class="text-gray-400 mb-6">Still have questions?</p> 5703 <a href="/help/" class="inline-flex items-center gap-2 px-8 py-4 bg-gradient-to-r from-orange-600 to-amber-600 hover:from-orange-500 hover:to-amber-500 text-white font-bold rounded-xl shadow-lg shadow-orange-500/30 hover:shadow-orange-500/50 transform hover:scale-105 transition-all duration-300 mr-3 mb-3"> 5704 <i class="fas fa-life-ring"></i> 5705 <span>Help center</span> 5706 </a> 5707 <a href="/docs/tumitrust/faq" class="inline-flex items-center gap-2 px-8 py-4 border border-orange-500/40 bg-orange-500/10 hover:bg-orange-500/20 text-amber-200 font-bold rounded-xl transition-all duration-300 mb-3"> 5708 <i class="fas fa-book-open"></i> 5709 <span>Full FAQ in docs</span> 5710 </a> 5711 </div> 5712 </div> 5713 </section> 5714 5715
5715<script> 5716 // Interactive Africa Map Visualization - REMOVED 5717 const mapCanvas = null; // Section removed 5718 if (false && mapCanvas) { 5719 const mapCtx = mapCanvas.getContext('2d'); 5720 5721 // Simplified Africa outline (Zambia-focused) 5722 const zambiaRegions = [ 5723 { name: 'Lusaka', x: 300, y: 450, users: 4521, active: true }, 5724 { name: 'Copperbelt', x: 280, y: 350, users: 3842, active: true }, 5725 { name: 'Southern', x: 300, y: 520, users: 2156, active: true }, 5726 { name: 'Eastern', x: 380, y: 420, users: 1893, active: true }, 5727 { name: 'Central', x: 300, y: 400, users: 987, active: true }, 5728 { name: 'Northern', x: 320, y: 280, users: 645, active: true }, 5729 { name: 'Luapula', x: 340, y: 320, users: 523, active: true }, 5730 { name: 'North-Western', x: 240, y: 350, users: 412, active: true }, 5731 { name: 'Western', x: 220, y: 450, users: 189, active: true }, 5732 { name: 'Muchinga', x: 360, y: 360, users: 156, active: true } 5733 ]; 5734 5735 // Other African countries (approximate positions) 5736 const otherCountries = [ 5737 { name: 'Kenya', x: 450, y: 380, users: 8942, color: '#10B981' }, 5738 { name: 'South Africa', x: 300, y: 620, users: 6571, color: '#3B82F6' }, 5739 { name: 'Nigeria', x: 180, y: 300, users: 4289, color: '#A855F7' } 5740 ]; 5741 5742 // Network connections 5743 const connections = []; 5744 5745 function drawMap() { 5746 mapCtx.clearRect(0, 0, mapCanvas.width, mapCanvas.height); 5747 5748 // Draw Zambia country outline (more accurate shape) 5749 mapCtx.save(); 5750 mapCtx.strokeStyle = 'rgba(255, 170, 0, 0.4)'; 5751 mapCtx.fillStyle = 'rgba(255, 170, 0, 0.05)'; 5752 mapCtx.lineWidth = 3; 5753 5754 // Zambia's approximate shape (butterfly-like) 5755 mapCtx.beginPath(); 5756 // North-Western corner 5757 mapCtx.moveTo(220, 320); 5758 // Northern border (relatively straight) 5759 mapCtx.lineTo(260, 310); 5760 mapCtx.lineTo(310, 305); 5761 mapCtx.lineTo(360, 315); 5762 // North-Eastern protrusion (Luapula/Northern Province) 5763 mapCtx.lineTo(380, 300); 5764 mapCtx.lineTo(390, 290); 5765 mapCtx.lineTo(395, 310); 5766 // Eastern border (going south) 5767 mapCtx.lineTo(400, 350); 5768 mapCtx.lineTo(405, 400); 5769 mapCtx.lineTo(410, 450); 5770 // South-Eastern corner (near Victoria Falls area) 5771 mapCtx.lineTo(405, 500); 5772 mapCtx.lineTo(390, 530); 5773 // Southern border 5774 mapCtx.lineTo(350, 540); 5775 mapCtx.lineTo(300, 545); 5776 mapCtx.lineTo(250, 540); 5777 // South-Western corner 5778 mapCtx.lineTo(220, 530); 5779 // Western border (Zambezi River shape) 5780 mapCtx.lineTo(210, 490); 5781 mapCtx.lineTo(205, 450); 5782 // Western bulge (Barotseland) 5783 mapCtx.lineTo(200, 410); 5784 mapCtx.lineTo(205, 370); 5785 mapCtx.lineTo(215, 340); 5786 mapCtx.closePath(); 5787 mapCtx.fill(); 5788 mapCtx.stroke(); 5789 mapCtx.restore(); 5790 5791 // Draw connections 5792 connections.forEach(conn => { 5793 if (conn.opacity > 0) { 5794 mapCtx.save(); 5795 mapCtx.globalAlpha = conn.opacity; 5796 mapCtx.strokeStyle = conn.color; 5797 mapCtx.lineWidth = 2; 5798 mapCtx.beginPath(); 5799 mapCtx.moveTo(conn.from.x, conn.from.y); 5800 mapCtx.lineTo(conn.to.x, conn.to.y); 5801 mapCtx.stroke();
5802 mapCtx.restore(); 5803 5804 conn.opacity -= 0.005; 5805 } 5806 }); 5807 5808 // Clean up faded connections 5809 for (let i = connections.length - 1; i >= 0; i--) { 5810 if (connections[i].opacity <= 0) { 5811 connections.splice(i, 1); 5812 } 5813 } 5814 5815 // Draw Zambia regions 5816 zambiaRegions.forEach(region => { 5817 // Pulsing circle 5818 const pulseSize = 3 + Math.sin(Date.now() / 500 + region.users) * 2; 5819 5820 // Glow 5821 mapCtx.save(); 5822 mapCtx.globalAlpha = 0.3; 5823 mapCtx.fillStyle = '#FF6600'; 5824 mapCtx.beginPath(); 5825 mapCtx.arc(region.x, region.y, pulseSize * 3, 0, Math.PI * 2); 5826 mapCtx.fill(); 5827 mapCtx.restore(); 5828 5829 // Core 5830 mapCtx.fillStyle = '#FF6600'; 5831 mapCtx.beginPath(); 5832 mapCtx.arc(region.x, region.y, pulseSize, 0, Math.PI * 2); 5833 mapCtx.fill(); 5834 5835 // Label (on hover - for now just show major ones) 5836 if (region.users > 2000) { 5837 mapCtx.fillStyle = 'rgba(255, 255, 255, 0.9)'; 5838 mapCtx.font = 'bold 11px sans-serif'; 5839 mapCtx.fillText(region.name, region.x + 10, region.y - 5); 5840 mapCtx.font = '9px sans-serif'; 5841 mapCtx.fillStyle = 'rgba(255, 170, 0, 0.8)'; 5842 mapCtx.fillText(region.users.toLocaleString(), region.x + 10, region.y + 8); 5843 } 5844 }); 5845 5846 // Draw other countries 5847 otherCountries.forEach(country => { 5848 const size = Math.sqrt(country.users / 100); 5849 5850 // Glow 5851 mapCtx.save(); 5852 mapCtx.globalAlpha = 0.2; 5853 mapCtx.fillStyle = country.color; 5854 mapCtx.beginPath(); 5855 mapCtx.arc(country.x, country.y, size * 2, 0, Math.PI * 2); 5856 mapCtx.fill(); 5857 mapCtx.restore(); 5858 5859 // Core 5860 mapCtx.fillStyle = country.color; 5861 mapCtx.beginPath(); 5862 mapCtx.arc(country.x, country.y, size, 0, Math.PI * 2); 5863 mapCtx.fill(); 5864 5865 // Label 5866 mapCtx.fillStyle = 'rgba(255, 255, 255, 0.9)'; 5867 mapCtx.font = 'bold 11px sans-serif'; 5868 mapCtx.fillText(country.name, country.x + 15, country.y - 5); 5869 mapCtx.font = '9px sans-serif'; 5870 mapCtx.fillStyle = country.color; 5871 mapCtx.fillText(country.users.toLocaleString(), country.x + 15, country.y + 8); 5872 }); 5873 5874 requestAnimationFrame(drawMap); 5875 } 5876 5877 // Create random connections for animation 5878 function createConnection() { 5879 const allPoints = [...zambiaRegions, ...otherCountries]; 5880 const from = allPoints[Math.floor(Math.random() * allPoints.length)]; 5881 const to = allPoints[Math.floor(Math.random() * allPoints.length)]; 5882 5883 if (from !== to) { 5884 connections.push({ 5885 from: from, 5886 to: to, 5887 color: ['#10B981', '#FBBF24', '#3B82F6', '#A855F7'][Math.floor(Math.random() * 4)], 5888 opacity: 0.6 5889 }); 5890 } 5891 } 5892 5893 // Create connections periodically 5894 setInterval(createConnection, 2000); 5895 5896 // Start animation 5897 drawMap(); 5898 } 5899 </script>
5899 5900 5901 5902</div> 5903
5904<script> 5905// Suppress console warnings for unused graphology libraries 5906console.warn = function(message) { 5907 if (typeof message === 'string' && message.includes('cdn.tailwindcss.com')) { 5908 return; // Suppress Tailwind CDN warning 5909 } 5910 Function.prototype.bind.call(console.warn, console)(message); 5911}; 5912 5913// Suppress script loading errors that don't affect this page 5914window.addEventListener('error', function(e) { 5915 if (e.target && e.target.tagName === 'SCRIPT' && e.target.src.includes('graphology')) { 5916 e.preventDefault(); // Suppress graphology errors (not needed for landing page) 5917 return false; 5918 } 5919}, true); 5920 5921// Counter Animation 5922document.addEventListener('DOMContentLoaded', function() { 5923 const counters = document.querySelectorAll('.counter'); 5924 5925 const animateCounter = (el) => { 5926 const text = el.textContent.trim(); 5927 if (!text.match(/\d/)) return; // Skip if no numbers 5928 5929 // Extract number and suffix 5930 const match = text.match(/(\d+\.?\d*)(.*)$/); 5931 if (!match) return; 5932 5933 const target = parseFloat(match[1]); 5934 const suffix = match[2]; 5935 const duration = 2000; 5936 const step = target / (duration / 16); 5937 let current = 0; 5938 5939 const timer = setInterval(() => { 5940 current += step; 5941 if (current >= target) { 5942 current = target; 5943 clearInterval(timer); 5944 } 5945 el.textContent = current.toFixed(target % 1 !== 0 ? 1 : 0) + suffix; 5946 }, 16); 5947 }; 5948 5949 // Intersection Observer for animation trigger 5950 const observer = new IntersectionObserver((entries) => { 5951 entries.forEach(entry => { 5952 if (entry.isIntersecting) { 5953 animateCounter(entry.target); 5954 observer.unobserve(entry.target); 5955 } 5956 }); 5957 }); 5958 5959 counters.forEach(counter => observer.observe(counter)); 5960}); 5961 5962// Network Visualization - Interconnected Nodes 5963(function() { 5964 const canvas = document.getElementById('networkCanvas'); 5965 if (!canvas) return; 5966 5967 const ctx = canvas.getContext('2d'); 5968 let width, height; 5969 let nodes = []; 5970 let connections = []; 5971
5972 // Resize canvas 5973 function resizeCanvas() { 5974 width = window.innerWidth; 5975 height = window.innerHeight; 5976 canvas.width = width; 5977 canvas.height = height; 5978 } 5979 5980 // Node class 5981 class Node { 5982 constructor() { 5983 this.x = Math.random() * width; 5984 this.y = Math.random() * height; 5985 this.vx = 0; // No movement - stable network 5986 this.vy = 0; 5987 this.radius = 1 + Math.random() * 0.8; // Tiny (1-1.8px) distant network 5988 this.connections = 0; 5989 this.pulsePhase = Math.random() * Math.PI * 2; 5990 this.pulseSpeed = 0.015 + Math.random() * 0.02; // Gentle beacon pulse 5991 this.activity = 0; 5992 this.targetActivity = 0; 5993 this.activityDecay = 0.015; // Activity decay 5994 this.appearing = Math.random() < 0.3; // 30% chance to appear (more live activity) 5995 this.disappearing = false; 5996 this.alpha = this.appearing ? 0 : 1; 5997 this.beaconIntensity = Math.random(); // Random beacon phase 5998 this.lifeTime = 0; // Track how long node has been alive 5999 6000 // TumiTrust Core Ecosystem - Soft, distant colors for background 6001 this.type = Math.random(); 6002 if (this.type < 0.25) { 6003 this.nodeType = 'individual'; 6004 this.color = 'rgba(251, 191, 36, 0.25)'; // Soft Amber 6005 this.glowColor = 'rgba(251, 191, 36, 0.5)'; 6006 } else if (this.type < 0.45) { 6007 this.nodeType = 'institution'; 6008 this.color = 'rgba(255, 170, 0, 0.28)'; // Soft Gold 6009 this.glowColor = 'rgba(255, 170, 0, 0.55)'; 6010 } else if (this.type < 0.60) { 6011 this.nodeType = 'credit_report'; 6012 this.color = 'rgba(255, 102, 0, 0.25)'; // Soft Orange 6013 this.glowColor = 'rgba(255, 102, 0, 0.5)'; 6014 } else if (this.type < 0.72) { 6015 this.nodeType = 'ai_scoring'; 6016 this.color = 'rgba(139, 92, 246, 0.22)'; // Soft Purple 6017 this.glowColor = 'rgba(139, 92, 246, 0.45)'; 6018 } else if (this.type < 0.82) { 6019 this.nodeType = 'ubuntu_trust'; 6020 this.color = 'rgba(34, 197, 94, 0.22)'; // Soft Green 6021 this.glowColor = 'rgba(34, 197, 94, 0.45)'; 6022 } else if (this.type < 0.90) { 6023 this.nodeType = 'fraud_detection'; 6024 this.color = 'rgba(239, 68, 68, 0.2)'; // Soft Red 6025 this.glowColor = 'rgba(239, 68, 68, 0.4)'; 6026 } else if (this.type < 0.95) { 6027 this.nodeType = 'data_partner'; 6028 this.color = 'rgba(59, 130, 246, 0.2)'; // Soft Blue 6029 this.glowColor = 'rgba(59, 130, 246, 0.4)'; 6030 } else { 6031 this.nodeType = 'verification'; 6032 this.color = 'rgba(16, 185, 129, 0.22)'; // Soft Teal 6033 this.glowColor = 'rgba(16, 185, 129, 0.45)'; 6034 } 6035 } 6036 6037 update() { 6038 // Update pulse phase for beacon effect 6039 this.pulsePhase += this.pulseSpeed; 6040 this.beaconIntensity += 0.01; 6041 this.lifeTime++; 6042 6043 // Node lifecycle: Joining (appearing) 6044 if (this.appearing) { 6045 this.alpha += 0.02; // Smooth fade in 6046 if (this.alpha >= 1) { 6047 this.alpha = 1; 6048 this.appearing = false; 6049 // Joining activity spike 6050 this.activity = 0.9; 6051 this.lifeTime = 0; 6052 } 6053 } 6054 // Node lifecycle: Leaving (disappearing) 6055 else if (this.disappearing) { 6056 this.alpha -= 0.02; // Smooth fade out 6057 if (this.alpha <= 0) { 6058 this.alpha = 0; 6059 this.disappearing = false; 6060 this.appearing = true; // Rejoin the network 6061 this.lifeTime = 0; 6062 } 6063 } 6064 // Node lifecycle: Active in network 6065 else { 6066 // More frequent leaving for live activity 6067 // Minimum lifetime before can leave (5 seconds at 60fps = 300 frames) 6068 if (this.lifeTime > 300 && Math.random() < 0.0015) { 6069 this.disappearing = true; 6070 // Leaving activity spike 6071 this.activity = 0.8; 6072 } 6073 6074 // Connection-based activity (updating) 6075 this.targetActivity = Math.min(this.connections / 6, 1); 6076 this.activity += (this.targetActivity - this.activity) * 0.05; 6077 6078 // More frequent update/transaction spikes for live feel 6079 if (Math.random() < 0.006) { 6080 this.activity = Math.min(this.activity + 0.7, 1); 6081 } 6082 } 6083 6084 // Activity decay 6085 if (this.activity > this.targetActivity) { 6086 this.activity -= this.activityDecay; 6087 } 6088 6089 // Nodes are stable - no movement (true network) 6090 } 6091 6092 draw() { 6093 if (this.alpha <= 0) return; // Don't draw invisible nodes 6094 6095 ctx.save(); 6096 ctx.globalAlpha = this.alpha * 0.6; // More subtle for background 6097 6098 // Beacon pulse - soft, distant expanding ring 6099 const beaconPulse = Math.sin(this.pulsePhase) * 0.3 + 1; // Gentle pulse 6100 const beaconRing = Math.sin(this.pulsePhase * 0.5) * 0.2 + 1; // Slower outer ring 6101 6102 // Activity-based intensity - very subtle 6103 const activityGlow = 0.15 + (this.activity * 0.35); 6104 const beaconRadius = this.radius * 10 * beaconRing; 6105 6106 // Outer beacon ring - very subtle, distant 6107 if (this.activity > 0.1 || this.appearing || this.disappearing) { 6108 ctx.beginPath(); 6109 ctx.arc(this.x, this.y, beaconRadius, 0, Math.PI * 2); 6110 const beaconGradient = ctx.createRadialGradient(this.x, this.y, beaconRadius * 0.7, this.x, this.y, beaconRadius); 6111 beaconGradient.addColorStop(0, 'rgba(0, 0, 0, 0)'); 6112 beaconGradient.addColorStop(0.8, this.glowColor.replace(/[\d\.]+\)$/, `${activityGlow * 0.08})`)); 6113 beaconGradient.addColorStop(1, 'rgba(0, 0, 0, 0)'); 6114 ctx.fillStyle = beaconGradient; 6115 ctx.fill(); 6116 } 6117 6118 // Activity burst - soft glow when active 6119 if (this.activity > 0.4) { 6120 const burstSize = this.radius * 15 * beaconPulse; 6121 ctx.beginPath(); 6122 ctx.arc(this.x, this.y, burstSize, 0, Math.PI * 2); 6123 const burstGradient = ctx.createRadialGradient(this.x, this.y, 0, this.x, this.y, burstSize); 6124 burstGradient.addColorStop(0, this.glowColor.replace(/[\d\.]+\)$/, `${this.activity * 0.15})`)); 6125 burstGradient.addColorStop(0.3, this.glowColor.replace(/[\d\.]+\)$/, `${this.activity * 0.08})`)); 6126 burstGradient.addColorStop(1, 'rgba(0, 0, 0, 0)'); 6127 ctx.fillStyle = burstGradient; 6128 ctx.fill(); 6129 } 6130 6131 // Mid-range glow - gentle presence 6132 const midGlowSize = this.radius * 6 * beaconPulse; 6133 ctx.beginPath(); 6134 ctx.arc(this.x, this.y, midGlowSize, 0, Math.PI * 2); 6135 const midGlow = ctx.createRadialGradient(this.x, this.y, 0, this.x, this.y, midGlowSize); 6136 midGlow.addColorStop(0, this.glowColor.replace(/[\d\.]+\)$/, `${activityGlow * 0.25})`)); 6137 midGlow.addColorStop(0.5, this.color.replace(/[\d\.]+\)$/, `${activityGlow * 0.15})`)); 6138 midGlow.addColorStop(1, 'rgba(0, 0, 0, 0)'); 6139 ctx.fillStyle = midGlow; 6140 ctx.fill(); 6141 6142 // Circular node border - subtle definition 6143 ctx.beginPath(); 6144 ctx.arc(this.x, this.y, this.radius + 0.3, 0, Math.PI * 2); 6145 ctx.strokeStyle = this.glowColor.replace(/[\d\.]+\)$/, `${0.35 + (this.activity * 0.25)})`); 6146 ctx.lineWidth = 0.5; 6147 ctx.stroke(); 6148 6149 // Node core - tiny, soft circle 6150 ctx.beginPath(); 6151 ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2); 6152 const coreGradient = ctx.createRadialGradient(this.x, this.y, 0, this.x, this.y, this.radius); 6153 coreGradient.addColorStop(0, this.glowColor.replace(/[\d\.]+\)$/, `${0.5 + (this.activity * 0.15)})`)); 6154 coreGradient.addColorStop(0.6, this.color.replace(/[\d\.]+\)$/, `${0.35 + (this.activity * 0.2)})`)); 6155 coreGradient.addColorStop(1, this.color.replace(/[\d\.]+\)$/, `${0.25 + (this.activity * 0.15)})`)); 6156 ctx.fillStyle = coreGradient; 6157 ctx.fill(); 6158 6159 // Inner highlight - very subtle 6160 ctx.beginPath(); 6161 ctx.arc(this.x - this.radius * 0.2, this.y - this.radius * 0.2, this.radius * 0.3, 0, Math.PI * 2); 6162 ctx.fillStyle = `rgba(255, 255, 255, ${0.15 + (this.activity * 0.1)})`; 6163 ctx.fill(); 6164
6165 ctx.restore(); 6166 } 6167 } 6168 6169 // Initialize nodes with proper spacing - tiny distant network 6170 function initNodes() { 6171 nodes = []; 6172 const nodeCount = Math.floor((width * height) / 22000); // Fewer, more distant nodes 6173 const minDistance = 50; // More space between tiny nodes 6174 6175 for (let i = 0; i < nodeCount; i++) { 6176 let attempts = 0; 6177 let validPosition = false; 6178 let newNode; 6179 6180 while (!validPosition && attempts < 50) { 6181 newNode = new Node(); 6182 validPosition = true; 6183 6184 // Check distance from existing nodes 6185 for (let j = 0; j < nodes.length; j++) { 6186 const dx = newNode.x - nodes[j].x; 6187 const dy = newNode.y - nodes[j].y; 6188 const distance = Math.sqrt(dx * dx + dy * dy); 6189 6190 if (distance < minDistance) { 6191 validPosition = false; 6192 break; 6193 } 6194 } 6195 attempts++; 6196 } 6197 6198 if (validPosition) { 6199 nodes.push(newNode); 6200 } 6201 } 6202 } 6203 6204 // Find connections - dynamic network topology 6205 function findConnections() { 6206 const maxDistance = 180; // Shorter connections for tiny network 6207 const maxConnectionsPerNode = 4; // Fewer connections for clarity 6208 connections = []; 6209 6210 // Reset connection counts and connected nodes 6211 nodes.forEach(node => { 6212 node.connections = 0; 6213 node.connectedNodes = []; 6214 }); 6215 6216 // Only connect visible or nearly visible nodes 6217 for (let i = 0; i < nodes.length; i++) { 6218 if (nodes[i].alpha < 0.1) continue; // Skip invisible nodes 6219 if (nodes[i].connections >= maxConnectionsPerNode) continue; 6220 6221 for (let j = i + 1; j < nodes.length; j++) { 6222 if (nodes[j].alpha < 0.1) continue; // Skip invisible nodes 6223 if (nodes[j].connections >= maxConnectionsPerNode) continue; 6224 6225 const dx = nodes[i].x - nodes[j].x; 6226 const dy = nodes[i].y - nodes[j].y; 6227 const distance = Math.sqrt(dx * dx + dy * dy); 6228 6229 if (distance < maxDistance) { 6230 connections.push({ 6231 from: nodes[i], 6232 to: nodes[j], 6233 distance: distance, 6234 maxDistance: maxDistance 6235 }); 6236 nodes[i].connections++; 6237 nodes[j].connections++; 6238 nodes[i].connectedNodes.push(nodes[j]); 6239 nodes[j].connectedNodes.push(nodes[i]); 6240 6241 if (nodes[i].connections >= maxConnectionsPerNode) break; 6242 } 6243 } 6244 } 6245 } 6246 6247 // Energy pulse class - tiny but visible data packets 6248 class EnergyPulse { 6249 constructor(from, to) { 6250 this.from = from; 6251 this.to = to; 6252 this.progress = 0; 6253 this.speed = 0.006 + Math.random() * 0.008; // Visible flow 6254 this.size = 1.2 + Math.random() * 0.8; // Tiny but visible 6255 this.intensity = 0.35 + Math.random() * 0.25; // More visible 6256 this.color = from.glowColor; // Use source node color 6257 } 6258 6259 update() { 6260 this.progress += this.speed; 6261 return this.progress < 1; 6262 } 6263 6264 draw() { 6265 // Fade with source and target node visibility 6266 const nodeVisibility = (this.from.alpha + this.to.alpha) / 2; 6267 if (nodeVisibility < 0.1) return; // Don't draw on invisible nodes 6268 6269 const x = this.from.x + (this.to.x - this.from.x) * this.progress; 6270 const y = this.from.y + (this.to.y - this.from.y) * this.progress; 6271 6272 ctx.save(); 6273 ctx.globalAlpha = nodeVisibility; // Fade with nodes 6274 6275 // Draw data packet with visible trail 6276 const trailLength = 0.06; 6277 if (this.progress > trailLength) { 6278 const trailX = this.from.x + (this.to.x - this.from.x) * (this.progress - trailLength); 6279 const trailY = this.from.y + (this.to.y - this.from.y) * (this.progress - trailLength); 6280 6281 // Visible trail gradient 6282 const trailGradient = ctx.createLinearGradient(trailX, trailY, x, y); 6283 trailGradient.addColorStop(0, this.color.replace(/[\d\.]+\)$/, '0)')); 6284 trailGradient.addColorStop(1, this.color.replace(/[\d\.]+\)$/, `${this.intensity * 0.3})`)); 6285 ctx.strokeStyle = trailGradient; 6286 ctx.lineWidth = this.size * 0.4; 6287 ctx.beginPath(); 6288 ctx.moveTo(trailX, trailY); 6289 ctx.lineTo(x, y); 6290 ctx.stroke(); 6291 } 6292 6293 // Main data packet - tiny but visible 6294 ctx.beginPath(); 6295 ctx.arc(x, y, this.size, 0, Math.PI * 2); 6296 const pulseGradient = ctx.createRadialGradient(x, y, 0, x, y, this.size * 2.5); 6297 pulseGradient.addColorStop(0, this.color.replace(/[\d\.]+\)$/, `${this.intensity})`)); 6298 pulseGradient.addColorStop(0.5, this.color.replace(/[\d\.]+\)$/, `${this.intensity * 0.5})`)); 6299 pulseGradient.addColorStop(1, 'rgba(0, 0, 0, 0)'); 6300 ctx.fillStyle = pulseGradient; 6301 ctx.fill(); 6302
6303 ctx.restore(); 6304 } 6305 } 6306 6307 // Floating data widget class - trust scores, loan amounts, etc. 6308 class DataWidget { 6309 constructor() { 6310 this.x = Math.random() * width; 6311 this.y = Math.random() * height; 6312 this.vx = (Math.random() - 0.5) * 0.1; 6313 this.vy = (Math.random() - 0.5) * 0.1; 6314 this.life = 0; 6315 this.maxLife = 200 + Math.random() * 300; 6316 this.fadeIn = 50; 6317 this.fadeOut = 50; 6318 6319 // TumiTrust Core Ecosystem - use Font Awesome glyphs for polished canvas labels. 6320 const types = [ 6321 // Trust Scores 6322 { text: '1000â ', prefix: 'Score:', color: 'rgba(34, 197, 94, 0.95)' }, // Demo cap (landing calculator) 6323 { text: '750', prefix: 'Score:', color: 'rgba(34, 197, 94, 0.85)' }, // Good 6324 { text: '620', prefix: 'Score:', color: 'rgba(251, 191, 36, 0.85)' }, // Fair 6325 6326 // Credit Reports & Lending 6327 { text: 'TRUST REPORT', icon: '\uf080', color: 'rgba(59, 130, 246, 0.95)' }, // fa-chart-bar 6328 { text: 'LOAN ACCESS', icon: '\uf51e', color: 'rgba(255, 170, 0, 0.95)' }, // fa-coins 6329 6330 // 20 documented trust contexts (see /docs/tumitrust/platform/partner-trust-contexts) 6331 { text: '20 CONTEXTS', icon: '\uf5fd', color: 'rgba(139, 92, 246, 0.95)' }, // fa-layer-group 6332 { text: 'LENDING â', icon: '\uf51e', color: 'rgba(34, 197, 94, 0.9)' }, // fa-coins 6333 { text: 'EMPLOYMENT', icon: '\uf0b1', color: 'rgba(59, 130, 246, 0.9)' }, // fa-briefcase 6334 { text: 'INSURANCE', icon: '\uf3ed', color: 'rgba(20, 184, 166, 0.9)' }, // fa-shield-halved 6335 { text: 'PARTNERSHIP', icon: '\uf2b5', color: 'rgba(34, 197, 94, 0.9)' }, // fa-handshake 6336 { text: 'SUPPLIER', icon: '\uf466', color: 'rgba(249, 115, 22, 0.9)' }, // fa-box 6337 { text: 'AGRICULTURE', icon: '\uf4d8', color: 'rgba(34, 197, 94, 0.85)' }, // fa-seedling 6338 { text: 'REMITTANCE', icon: '\uf53a', color: 'rgba(59, 130, 246, 0.85)' }, // fa-money-bill-wave 6339 6340 // Core Features 6341 { text: 'TRUST CV', icon: '\uf2b5', color: 'rgba(34, 197, 94, 0.95)' }, // fa-handshake 6342 { text: 'AI SCORING', icon: '\uf544', color: 'rgba(139, 92, 246, 0.95)' }, // fa-robot 6343 { text: 'REPORT 0.3s', icon: '\uf625', color: 'rgba(139, 92, 246, 0.85)' }, // fa-gauge-high 6344 { text: 'VERIFIED â', icon: '\uf058', color: 'rgba(34, 197, 94, 0.95)' }, // fa-circle-check 6345 { text: 'FRAUD SCAN', icon: '\uf505', color: 'rgba(239, 68, 68, 0.9)' }, // fa-user-shield 6346 { text: 'DATA PARTNER', icon: '\uf0c1', color: 'rgba(59, 130, 246, 0.9)' }, // fa-link 6347 { text: 'RISK ANALYSIS', icon: '\uf071', color: 'rgba(239, 68, 68, 0.85)' }, // fa-triangle-exclamation 6348 { text: 'APPROVED', icon: '\uf00c', color: 'rgba(34, 197, 94, 0.95)' }, // fa-check 6349 ]; 6350 this.data = types[Math.floor(Math.random() * types.length)]; 6351 } 6352 6353 update() { 6354 this.life++; 6355 this.x += this.vx; 6356 this.y += this.vy; 6357 6358 // Keep within bounds 6359 if (this.x < 0 || this.x > width) this.vx *= -1; 6360 if (this.y < 0 || this.y > height) this.vy *= -1; 6361 this.x = Math.max(0, Math.min(width, this.x)); 6362 this.y = Math.max(0, Math.min(height, this.y)); 6363 6364 return this.life < this.maxLife; 6365 } 6366 6367 draw() { 6368 let opacity = 1; 6369 if (this.life < this.fadeIn) { 6370 opacity = this.life / this.fadeIn; 6371 } else if (this.life > this.maxLife - this.fadeOut) { 6372 opacity = (this.maxLife - this.life) / this.fadeOut; 6373 } 6374 6375 ctx.save(); 6376 ctx.globalAlpha = opacity * 0.7; // More visible 6377 const labelFont = 'bold 11px Inter, sans-serif'; 6378 const iconFont = '900 11px "Font Awesome 6 Free"'; 6379 const label = [this.data.prefix, this.data.text].filter(
6379Boolean).join(' '); 6380 ctx.font = labelFont; 6381 ctx.fillStyle = this.data.color; 6382 6383 const labelWidth = ctx.measureText(label).width; 6384 ctx.font = iconFont; 6385 const iconWidth = this.data.icon ? ctx.measureText(this.data.icon).width : 0; 6386 const iconGap = this.data.icon ? 5 : 0; 6387 const textWidth = iconWidth + iconGap + labelWidth; 6388 const textStartX = this.x - textWidth / 2; 6389 6390 // Glowing background with border 6391 ctx.shadowColor = this.data.color; 6392 ctx.shadowBlur = 15; 6393 ctx.fillStyle = this.data.color.replace(/[\d\.]+\)$/, '0.25)'); 6394 ctx.fillRect(this.x - textWidth / 2 - 6, this.y - 10, textWidth + 12, 20); 6395 6396 // Border glow 6397 ctx.strokeStyle = this.data.color.replace(/[\d\.]+\)$/, '0.6)'); 6398 ctx.lineWidth = 1.5; 6399 ctx.strokeRect(this.x - textWidth / 2 - 6, this.y - 10, textWidth + 12, 20); 6400 6401 // Reset shadow for text 6402 ctx.shadowBlur = 0; 6403 6404 // Text with glow 6405 ctx.shadowColor = this.data.color; 6406 ctx.shadowBlur = 8; 6407 ctx.fillStyle = this.data.color; 6408 if (this.data.icon) { 6409 ctx.font = iconFont; 6410 ctx.fillText(this.data.icon, textStartX, this.y + 3); 6411 } 6412 ctx.font = labelFont; 6413 ctx.fillText(label, textStartX + iconWidth + iconGap, this.y + 3); 6414 6415 ctx.restore(); 6416 } 6417 } 6418 6419 let energyPulses = []; 6420 let dataWidgets = []; 6421 6422 // Draw connections - visible but distant network links 6423 function drawConnections() { 6424 connections.forEach(conn => { 6425 // Connection visibility based on node alpha (fade with nodes) 6426 const nodeVisibility = (conn.from.alpha + conn.to.alpha) / 2; 6427 6428 // Connection strength - more visible but still soft 6429 const baseOpacity = (1 - (conn.distance / conn.maxDistance)) * 0.28; 6430 6431 // Activity-based brightness 6432 const avgActivity = (conn.from.activity + conn.to.activity) / 2; 6433 const activityBoost = avgActivity * 0.25; 6434 const lineOpacity = (baseOpacity + activityBoost) * nodeVisibility; 6435 6436 // Gentle pulse along connection 6437 const connectionPulse = (Math.sin(conn.from.pulsePhase) + Math.sin(conn.to.pulsePhase)) / 4 + 0.85; 6438 6439 // Draw connection line with visible gradient 6440 const gradient = ctx.createLinearGradient( 6441 conn.from.x, conn.from.y, 6442 conn.to.x, conn.to.y 6443 ); 6444 6445 // More visible colors from nodes 6446 const color1 = conn.from.glowColor.replace(/[\d\.]+\)$/, `${lineOpacity * connectionPulse * (0.5 + conn.from.activity * 0.3)})`); 6447 const colorMid = `rgba(120, 160, 220, ${lineOpacity * connectionPulse * 0.3})`; 6448 const color2 = conn.to.glowColor.replace(/[\d\.]+\)$/, `${lineOpacity * connectionPulse * (0.5 + conn.to.activity * 0.3)})`); 6449 6450 gradient.addColorStop(0, color1); 6451 gradient.addColorStop(0.5, colorMid); 6452 gradient.addColorStop(1, color2); 6453 6454 // Draw visible but thin connection 6455 ctx.save(); 6456 ctx.globalAlpha = nodeVisibility; // Fade with nodes 6457 6458 ctx.beginPath(); 6459 ctx.moveTo(conn.from.x, conn.from.y); 6460 ctx.lineTo(conn.to.x, conn.to.y); 6461 ctx.strokeStyle = gradient; 6462 ctx.lineWidth = 0.7 + (avgActivity * 0.5); // Slightly thicker, more visible 6463 ctx.stroke(); 6464 6465 // Glow on active connections 6466 if (avgActivity > 0.3) { 6467 ctx.beginPath(); 6468 ctx.moveTo(conn.from.x, conn.from.y); 6469 ctx.lineTo(conn.to.x, conn.to.y); 6470 ctx.strokeStyle = gradient; 6471 ctx.lineWidth = 2 + (avgActivity * 1.2); 6472 ctx.globalAlpha = nodeVisibility * avgActivity * 0.12; 6473 ctx.stroke(); 6474 } 6475
6476 ctx.restore(); 6477 }); 6478 6479 // Create energy pulses - more frequent for live activity 6480 if (Math.random() < 0.02 && connections.length > 0) { 6481 const conn = connections[Math.floor(Math.random() * connections.length)]; 6482 // Only on visible connections with some activity 6483 const nodeVisibility = (conn.from.alpha + conn.to.alpha) / 2; 6484 if (nodeVisibility > 0.3 && (conn.from.activity > 0.3 || conn.to.activity > 0.3)) { 6485 energyPulses.push(new EnergyPulse(conn.from, conn.to)); 6486 } 6487 } 6488 6489 // Update and draw energy pulses 6490 energyPulses = energyPulses.filter(pulse => { 6491 const alive = pulse.update(); 6492 if (alive) pulse.draw(); 6493 return alive; 6494 }); 6495 6496 // Randomly create data widgets (more frequent) 6497 if (Math.random() < 0.015 && dataWidgets.length < 5) { 6498 dataWidgets.push(new DataWidget()); 6499 } 6500 6501 // Update and draw data widgets 6502 dataWidgets = dataWidgets.filter(widget => { 6503 const alive = widget.update(); 6504 if (alive) widget.draw(); 6505 return alive; 6506 }); 6507 } 6508 6509 // Animation loop 6510 function animate() { 6511 ctx.clearRect(0, 0, width, height); 6512 6513 // Update nodes first 6514 nodes.forEach(node => node.update()); 6515 6516 // Rebuild connections dynamically (every frame for live activity) 6517 findConnections(); 6518 6519 // Draw connections and energy pulses 6520 drawConnections(); 6521 6522 // Draw nodes 6523 nodes.forEach(node => node.draw()); 6524 6525 requestAnimationFrame(animate); 6526 } 6527 6528 // Handle resize 6529 window.addEventListener('resize', () => { 6530 resizeCanvas(); 6531 initNodes(); 6532 }); 6533 6534 // Initialize 6535 resizeCanvas(); 6536 initNodes(); 6537 animate(); 6538})(); 6539 6540// ===== FAQ TOGGLE FUNCTIONALITY ===== 6541function toggleFAQ(button) { 6542 const faqItem = button.closest('.bg-gradient-to-br'); 6543 const answer = faqItem.querySelector('.faq-answer'); 6544 const icon = button.querySelector('.fa-chevron-down'); 6545 6546 // Toggle answer visibility 6547 answer.classList.toggle('hidden'); 6548 6549 // Rotate icon 6550 icon.style.transform = answer.classList.contains('hidden') ? 'rotate(0deg)' : 'rotate(180deg)'; 6551 6552 // Close other FAQs (accordion style) 6553 document.querySelectorAll('.faq-answer').forEach(otherAnswer => { 6554 if (otherAnswer !== answer && !otherAnswer.classList.contains('hidden')) { 6555 otherAnswer.classList.add('hidden'); 6556 const otherIcon = otherAnswer.closest('.bg-gradient-to-br').querySelector('.fa-chevron-down'); 6557 if (otherIcon) otherIcon.style.transform = 'rotate(0deg)'; 6558 } 6559 }); 6560} 6561</script>
6561 6562 6563<!-- STUNNING AFRICAN-INSPIRED SCROLL TO TOP BUTTON --> 6564<button id="scrollToTopBtn" onclick="scrollToTop()" style=" 6565 position: fixed; 6566 bottom: 30px; 6567 right: 30px; 6568 width: 70px; 6569 height: 70px; 6570 border-radius: 50%; 6571 background: linear-gradient(135deg, #e95420 0%, #f79500 50%, #ffb300 100%); 6572 border: none; 6573 color: white; 6574 cursor: pointer; 6575 box-shadow: 6576 0 10px 40px rgba(233, 84, 32, 0.5), 6577 0 0 0 0 rgba(233, 84, 32, 0.4), 6578 inset 0 -2px 10px rgba(0, 0, 0, 0.2); 6579 z-index: 9999; 6580 opacity: 0; 6581 visibility: hidden; 6582 transform: translateY(100px) scale(0.8); 6583 transition: all 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55); 6584 animation: pulseGlow 2s infinite; 6585 backdrop-filter: blur(10px); 6586 display: flex; 6587 align-items: center; 6588 justify-content: center; 6589 overflow: hidden; 6590" onmouseover="this.style.transform='translateY(0) scale(1.15)'; this.style.boxShadow='0 15px 60px rgba(233, 84, 32, 0.7), 0 0 50px rgba(233, 84, 32, 0.6), inset 0 -2px 10px rgba(0, 0, 0, 0.2)';" onmouseout="this.style.transform='translateY(0) scale(1)'; this.style.boxShadow='0 10px 40px rgba(233, 84, 32, 0.5), 0 0 0 0 rgba(233, 84, 32, 0.4), inset 0 -2px 10px rgba(0, 0, 0, 0.2)';"> 6591 <!-- African Pattern Background - MORE VISIBLE --> 6592 <div style=" 6593 position: absolute; 6594 inset: 0; 6595 background-image: 6596 repeating-linear-gradient(45deg, transparent, transparent 4px, rgba(255, 255, 255, 0.25) 4px, rgba(255, 255, 255, 0.25) 8px), 6597 repeating-linear-gradient(-45deg, transparent, transparent 4px, rgba(255, 255, 255, 0.15) 4px, rgba(255, 255, 255, 0.15) 8px); 6598 border-radius: 50%; 6599 opacity: 0.8; 6600 animation: patternPulse 4s ease-in-out infinite; 6601 "></div> 6602 6603 <!-- Ubuntu Circle Pattern - MUCH MORE VISIBLE --> 6604 <svg style="position: absolute; width: 100%; height: 100%; opacity: 0.6;" viewBox="0 0 100 100"> 6605 <circle cx="50" cy="50" r="35" fill="none" stroke="white" stroke-width="2.5" stroke-dasharray="8,4"> 6606 <animateTransform attributeName="transform" type="rotate" from="0 50 50" to="360 50 50" dur="12s" repeatCount="indefinite"/> 6607 </circle> 6608 <circle cx="50" cy="50" r="25" fill="none" stroke="rgba(255, 255, 255, 0.9)" stroke-width="2" stroke-dasharray="6,3"> 6609 <animateTransform attributeName="transform" type="rotate" from="360 50 50" to="0 50 50" dur="8s" repeatCount="indefinite"/> 6610 </circle> 6611 <circle cx="50" cy="50" r="15" fill="none" stroke="rgba(255, 255, 255, 0.7)" stroke-width="1.5" stroke-dasharray="4,2"> 6612 <animateTransform attributeName="transform" type="rotate" from="0 50 50" to="360 50 50" dur="6s" repeatCount="indefinite"/> 6613 </circle> 6614 </svg> 6615 6616 <!-- African Assegai Spear Icon --> 6617 <svg style=" 6618 width: 50px; 6619 height: 50px; 6620 position: relative; 6621 z-index: 2; 6622 filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.5)); 6623 animation: spearFloat 2.5s ease-in-out infinite; 6624 " viewBox="0 0 100 100" fill="none"> 6625 <!-- Spear Shaft (wooden handle) - THICKER --> 6626 <rect x="44" y="40" width="12" height="52" fill="url(#woodGradient)" stroke="rgba(139, 69, 19, 0.8)" stroke-width="1.5" rx="2"/> 6627 6628 <!-- Decorative bands on shaft - MORE VISIBLE --> 6629 <rect x="42" y="50" width="16" height="3" fill="#654321" opacity="0.9"/> 6630 <rect x="42" y="62" width="16" height="3" fill="#654321" opacity="0.9"/> 6631 <rect x="42" y="74" width="16" height="3" fill="#654321" opacity="0.9"/> 6632 6633 <!-- Spear Blade (traditional leaf shape) - MUCH LARGER --> 6634 <path d="M 50 8 L 64 32 L 58 42 L 50 38 L 42 42 L 36 32 Z" 6635 fill="url(#bladeGradient)" 6636 stroke="white" 6637 stroke-width="2" 6638 stroke-linejoin="miter"/> 6639 6640 <!-- Blade center ridge (for strength detail) - BOLDER with GLOW --> 6641 <line x1="50" y1="8" x2="50" y2="38" stroke="rgba(255, 255, 255, 0.9)" stroke-width="2.5"> 6642 <animate attributeName="stroke-width" values="2.5;3.5;
66422.5" dur="2s" repeatCount="indefinite"/> 6643 <animate attributeName="stroke" values="rgba(255,255,255,0.9);rgba(255,255,255,1);rgba(255,255,255,0.9)" dur="2s" repeatCount="indefinite"/> 6644 </line> 6645 6646 <!-- Blade shine/highlight - LARGER with SHIMMER --> 6647 <path d="M 46 10 L 54 10 L 52 34 L 48 34 Z" fill="rgba(255, 255, 255, 0.5)"> 6648 <animate attributeName="opacity" values="0.3;0.8;0.3" dur="2s" repeatCount="indefinite"/> 6649 </path> 6650 6651 <!-- Metal collar (where blade meets shaft) - BIGGER --> 6652 <ellipse cx="50" cy="40" rx="8" ry="4" fill="url(#metalGradient)" stroke="rgba(255, 255, 255, 0.5)" stroke-width="1.5"/> 6653 6654 <!-- Spear butt (bottom cap) - BIGGER --> 6655 <ellipse cx="50" cy="92" rx="7" ry="4" fill="url(#metalGradient)" stroke="rgba(255, 255, 255, 0.4)" stroke-width="1"/> 6656 <rect x="46" y="89" width="8" height="6" fill="#555" opacity="0.7" rx="1"/> 6657 6658 <!-- Gradients --> 6659 <defs> 6660 <!-- Blade gradient (silver/steel) --> 6661 <linearGradient id="bladeGradient" x1="0%" y1="0%" x2="100%" y2="0%"> 6662 <stop offset="0%" style="stop-color:#C0C0C0;stop-opacity:1" /> 6663 <stop offset="50%" style="stop-color:#FFFFFF;stop-opacity:1" /> 6664 <stop offset="100%" style="stop-color:#A8A8A8;stop-opacity:1" /> 6665 </linearGradient> 6666 6667 <!-- Wood gradient (shaft) --> 6668 <linearGradient id="woodGradient" x1="0%" y1="0%" x2="100%" y2="0%"> 6669 <stop offset="0%" style="stop-color:#8B4513;stop-opacity:1" /> 6670 <stop offset="50%" style="stop-color:#A0522D;stop-opacity:1" /> 6671 <stop offset="100%" style="stop-color:#8B4513;stop-opacity:1" /> 6672 </linearGradient> 6673 6674 <!-- Metal gradient (collar & butt) --> 6675 <linearGradient id="metalGradient" x1="0%" y1="0%" x2="100%" y2="100%"> 6676 <stop offset="0%" style="stop-color:#888;stop-opacity:1" /> 6677 <stop offset="50%" style="stop-color:#BBB;stop-opacity:1" /> 6678 <stop offset="100%" style="stop-color:#666;stop-opacity:1" /> 6679 </linearGradient> 6680 </defs> 6681 </svg> 6682</button> 6683 6684<style> 6685@keyframes pulseGlow { 6686 0%, 100% { 6687 box-shadow: 6688 0 10px 40px rgba(233, 84, 32, 0.5), 6689 0 0 30px rgba(233, 84, 32, 0.4), 6690 inset 0 -2px 10px rgba(0, 0, 0, 0.2); 6691 transform: scale(1); 6692 } 6693 50% { 6694 box-shadow: 6695 0 15px 60px rgba(233, 84, 32, 0.8), 6696 0 0 60px rgba(233, 84, 32, 0.7), 6697 0 0 100px rgba(255, 179, 0, 0.4), 6698 inset 0 -2px 10px rgba(0, 0, 0, 0.2); 6699 transform: scale(1.05); 6700 } 6701} 6702 6703@keyframes patternPulse { 6704 0%, 100% { 6705 opacity: 0.8; 6706 transform: scale(1); 6707 } 6708 50% { 6709 opacity: 1; 6710 transform: scale(1.05); 6711 } 6712} 6713 6714@keyframes spearFloat { 6715 0%, 100% { 6716 transform: translateY(0px) scale(1); 6717 filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.5)); 6718 } 6719 50% { 6720 transform: translateY(-3px) scale(1.05); 6721 filter: drop-shadow(0 6px 12px rgba(0, 0, 0, 0.6)) drop-shadow(0 0 15px rgba(255, 255, 255, 0.4)); 6722 } 6723} 6724 6725@keyframes rocketLaunch { 6726 0% { 6727 transform: translateY(0) rotate(-45deg); 6728 } 6729 50% { 6730 transform: translateY(-5px) rotate(-45deg); 6731 } 6732 100% { 6733 transform: translateY(0) rotate(-45deg); 6734 } 6735} 6736 6737#scrollToTopBtn:hover .fa-rocket { 6738 animation: rocketLaunch 0.6s ease-in-out infinite; 6739} 6740 6741/* Mobile responsive */ 6742@media (max-width: 768px) { 6743 #scrollToTopBtn { 6744 bottom: 20px; 6745 right: 20px; 6746 width: 70px; 6747 height: 70px; 6748 } 6749 6750 #scrollToTopBtn svg[viewBox="0 0 100 100"] { 6751 width: 45px; 6752 height: 45px; 6753 } 6754} 6755 6756/* Show button when visible */ 6757#scrollToTopBtn.visible { 6758 opacity: 1 !important; 6759 visibility: visible !important; 6760 transform: translateY(0) scale(1) !important; 6761} 6762</style> 6763
6764<script> 6765// Scroll to top functionality 6766document.addEventListener('DOMContentLoaded', function() { 6767 const scrollToTopBtn = document.getElementById('scrollToTopBtn'); 6768 6769 if (!scrollToTopBtn) { 6770 console.error('Scroll to top button not found!'); 6771 return; 6772 } 6773 6774 console.log('Scroll to top button initialized'); 6775 6776 // Show/hide button based on scroll position 6777 window.addEventListener('scroll', function() { 6778 const scrollPosition = window.pageYOffset || document.documentElement.scrollTop; 6779 6780 if (scrollPosition > 200) { 6781 scrollToTopBtn.classList.add('visible'); 6782 console.log('Button should be visible, scroll position:', scrollPosition); 6783 } else { 6784 scrollToTopBtn.classList.remove('visible'); 6785 } 6786 }); 6787 6788 // Trigger initial check 6789 window.dispatchEvent(new Event('scroll')); 6790}); 6791 6792// Smooth scroll to top with easing 6793function scrollToTop() { 6794 const startPosition = window.pageYOffset; 6795 const duration = 1000; // 1 second 6796 const startTime = performance.now(); 6797 6798 // Easing function for smooth animation 6799 function easeInOutCubic(t) { 6800 return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2; 6801 } 6802 6803 function animation(currentTime) { 6804 const elapsed = currentTime - startTime; 6805 const progress = Math.min(elapsed / duration, 1); 6806 const ease = easeInOutCubic(progress); 6807 6808 window.scrollTo(0, startPosition * (1 - ease)); 6809 6810 if (progress < 1) { 6811 requestAnimationFrame(animation); 6812 } 6813 } 6814 6815 requestAnimationFrame(animation); 6816 6817 // Add celebratory effect 6818 const scrollToTopBtn = document.getElementById('scrollToTopBtn'); 6819 if (scrollToTopBtn) { 6820 // Spin animation 6821 scrollToTopBtn.style.transition = 'transform 0.6s ease-out'; 6822 scrollToTopBtn.style.transform = 'translateY(0) scale(1.2) rotate(360deg)'; 6823 setTimeout(() => { 6824 scrollToTopBtn.style.transform = 'translateY(0) scale(1) rotate(0deg)'; 6825 }, 600); 6826 } 6827} 6828 6829// Add keyboard shortcut (Press 'T' or 'Home' key) 6830document.addEventListener('keydown', function(e) { 6831 if ((e.key === 't' || e.key === 'T' || e.key === 'Home') && !e.ctrlKey && !e.metaKey) { 6832 const activeElement = document.activeElement; 6833 // Don't trigger if user is typing in an input field 6834 if (activeElement.tagName !== 'INPUT' && activeElement.tagName !== 'TEXTAREA') { 6835 e.preventDefault(); 6836 scrollToTop(); 6837 } 6838 } 6839}); 6840</script>
6840 6841 6842 6843 6844 6845 <!-- Futuristic Grid Overlay --> 6846 <div class="fixed inset-0 pointer-events-none z-0 opacity-20"> 6847 <div class="absolute inset-0" style="background-image: 6848 linear-gradient(rgba(0, 255, 255, 0.1) 1px, transparent 1px), 6849 linear-gradient(90deg, rgba(0, 255, 255, 0.1) 1px, transparent 1px); 6850 background-size: 50px 50px; 6851 animation: gridMove 20s linear infinite; 6852 "></div> 6853 </div> 6854 6855 <!-- Floating Tech Elements - Ubuntu/African Colors --> 6856 <div class="fixed inset-0 pointer-events-none z-0"> 6857 <div class="absolute top-20 left-10 w-4 h-4 bg-amber-400 rounded-full animate-pulse opacity-60"></div> 6858 <div class="absolute top-40 right-20 w-6 h-6 bg-orange-400 rounded-full animate-pulse opacity-40" style="animation-delay: 2s;"></div> 6859 <div class="absolute bottom-32 left-1/4 w-3 h-3 bg-yellow-400 rounded-full animate-pulse opacity-50" style="animation-delay: 4s;"></div> 6860 <div class="absolute bottom-20 right-1/3 w-5 h-5 bg-red-500 rounded-full animate-pulse opacity-30" style="animation-delay: 6s;"></div> 6861 </div> 6862 </main> 6863 6864 6865
6865<script src="/static/core/js/tt_site_nav.7e1a729f023e.js?v=nav3" defer></script>
6865 6866 <!-- JavaScript --> 6867
6867<script> 6868 // Mobile menu: tt_site_nav.js owns toggle + outside click; keep a fallback. 6869 if (typeof window.toggleMobileMenu !== 'function') { 6870 window.toggleMobileMenu = function () { 6871 var menu = document.getElementById('mobileMenu'); 6872 if (menu) menu.classList.toggle('hidden'); 6873 }; 6874 } 6875 6876 // Theme toggle (if needed) 6877 function toggleTheme() { 6878 document.body.classList.toggle('light-theme'); 6879 } 6880 6881 // Network Status Indicator with WiFi Icon 6882 function updateNetworkStatus() { 6883 const networkStatus = document.getElementById('networkStatus'); 6884 if (!networkStatus) return; 6885 6886 const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection; 6887 const isOnline = navigator.onLine; 6888 6889 if (!isOnline) { 6890 // Offline - Red with wifi-slash icon 6891 networkStatus.style.background = 'rgba(239, 68, 68, 0.9)'; 6892 networkStatus.style.boxShadow = '0 0 12px rgba(239, 68, 68, 0.6)'; 6893 networkStatus.innerHTML = '<i class="fas fa-wifi-slash text-white text-xs animate-pulse"></i>'; 6894 networkStatus.title = 'Offline'; 6895 } else if (connection) { 6896 const effectiveType = connection.effectiveType; 6897 const downlink = connection.downlink; 6898 6899 // Check connection quality 6900 if (effectiveType === 'slow-2g' || effectiveType === '2g' || downlink < 0.5) { 6901 // Poor connection - Red/Orange 6902 networkStatus.style.background = 'rgba(251, 146, 60, 0.9)'; 6903 networkStatus.style.boxShadow = '0 0 12px rgba(251, 146, 60, 0.6)'; 6904 networkStatus.innerHTML = '<i class="fas fa-wifi text-white text-xs animate-pulse"></i>'; 6905 networkStatus.title = 'Poor Connection'; 6906 } else if (effectiveType === '3g' || downlink < 2) { 6907 // Fair connection - Yellow 6908 networkStatus.style.background = 'rgba(234, 179, 8, 0.9)'; 6909 networkStatus.style.boxShadow = '0 0 12px rgba(234, 179, 8, 0.6)'; 6910 networkStatus.innerHTML = '<i class="fas fa-wifi text-white text-xs animate-pulse"></i>'; 6911 networkStatus.title = 'Fair Connection'; 6912 } else { 6913 // Good connection - Green 6914 networkStatus.style.background = 'rgba(16, 185, 129, 0.9)'; 6915 networkStatus.style.boxShadow = '0 0 12px rgba(16, 185, 129, 0.6)'; 6916 networkStatus.innerHTML = '<i class="fas fa-wifi text-white text-xs animate-pulse"></i>'; 6917 networkStatus.title = 'Good Connection'; 6918 } 6919 } else { 6920 // Online but can't determine quality - Green 6921 networkStatus.style.background = 'rgba(16, 185, 129, 0.9)'; 6922 networkStatus.style.boxShadow = '0 0 12px rgba(16, 185, 129, 0.6)'; 6923 networkStatus.innerHTML = '<i class="fas fa-wifi text-white text-xs animate-pulse"></i>'; 6924 networkStatus.title = 'Online'; 6925 } 6926 } 6927 6928 // Update network status on load and connection changes 6929 if (navigator.onLine !== undefined) { 6930 updateNetworkStatus(); 6931 window.addEventListener('online', updateNetworkStatus); 6932 window.addEventListener('offline', updateNetworkStatus); 6933
6934 // Check for connection changes 6935 const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection; 6936 if (connection) { 6937 connection.addEventListener('change', updateNetworkStatus); 6938 } 6939 6940 // Periodic check every 30 seconds 6941 setInterval(updateNetworkStatus, 30000); 6942 } 6943 6944 // Smooth scrolling for anchor links 6945 document.querySelectorAll('a[href^="#"]').forEach(anchor => { 6946 anchor.addEventListener('click', function (e) { 6947 const href = this.getAttribute('href'); 6948 // Skip if href is just '#' or empty 6949 if (!href || href === '#' || href.length <= 1) { 6950 return; 6951 } 6952 e.preventDefault(); 6953 try { 6954 const target = document.querySelector(href); 6955 if (target) { 6956 target.scrollIntoView({ 6957 behavior: 'smooth', 6958 block: 'start' 6959 }); 6960 } 6961 } catch (error) { 6962 console.warn('Invalid selector:', href, error); 6963 } 6964 }); 6965 }); 6966 6967 // Add loading states to buttons 6968 document.querySelectorAll('.btn').forEach(button => { 6969 button.addEventListener('click', function() { 6970 if (this.type === 'submit' || this.onclick) { 6971 this.classList.add('opacity-75', 'cursor-not-allowed'); 6972 setTimeout(() => { 6973 this.classList.remove('opacity-75', 'cursor-not-allowed'); 6974 }, 2000); 6975 } 6976 }); 6977 }); 6978 6979 // User Role Switching for Admin Users 6980 function switchUserRole(role) { 6981 if (confirm(`Are you sure you want to switch to ${role} view? This will reload the page with ${role} permissions.`)) { 6982 // Store the selected role in sessionStorage 6983 sessionStorage.setItem('admin_view_role', role); 6984 6985 // Reload the page to apply the role change 6986 window.location.reload(); 6987 } 6988 } 6989 6990 // Check for stored role preference on page load 6991 document.addEventListener('DOMContentLoaded', function() { 6992 const storedRole = sessionStorage.getItem('admin_view_role'); 6993 if (storedRole) { 6994 // Update the UI to show current role 6995 const roleButtons = document.querySelectorAll('[onclick*="switchUserRole"]'); 6996 roleButtons.forEach(button => { 6997 if (button.onclick.toString().includes(storedRole)) { 6998 button.classList.add('ring-2', 'ring-white', 'ring-opacity-50'); 6999 } else { 7000 button.classList.remove('ring-2', 'ring-white', 'ring-opacity-50'); 7001 } 7002 }); 7003 } 7004 }); 7005 7006 // Impersonation Modal Functions 7007 function showImpersonationModal() { 7008 document.getElementById('impersonationModal').classList.remove('hidden'); 7009 loadUsersForImpersonation(); 7010 } 7011 7012 function hideImpersonationModal() { 7013 document.getElementById('impersonationModal').classList.add('hidden'); 7014 } 7015 7016 function loadUsersForImpersonation() { 7017 // This would typically fetch users via AJAX 7018 // For now, we'll use a simple form submission 7019 console.log('Loading users for impersonation...'); 7020 } 7021 7022 function startImpersonation(userId) { 7023 if (confirm('Are you sure you want to impersonate this user? You will be logged in as them.')) { 7024 const form = document.createElement('form'); 7025 form.method = 'POST'; 7026 form.action = '/switch-role/'; 7027 7028 const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]').value; 7029 const csrfInput = document.createElement('input'); 7030 csrfInput.type = 'hidden'; 7031 csrfInput.name = 'csrfmiddlewaretoken'; 7032 csrfInput.value = csrfToken; 7033 7034 const actionInput = document.createElement('input'); 7035 actionInput.type = 'hidden'; 7036 actionInput.name = 'action'; 7037 actionInput.value = 'impersonate'; 7038 7039 const userIdInput = document.createElement('input'); 7040 userIdInput.type = 'hidden'; 7041 userIdInput.name = 'target_user_id'; 7042 userIdInput.value = userId; 7043 7044 form.appendChild(csrfInput); 7045 form.appendChild(actionInput); 7046 form.appendChild(userIdInput); 7047 document.body.appendChild(form); 7048 form.submit(); 7049 } 7050 } 7051 7052 function stopImpersonation() { 7053 if (confirm('Are you sure you want to stop impersonating? You will return to your admin account.')) { 7054 const form = document.createElement('form'); 7055 form.method = 'POST'; 7056 form.action = '/switch-role/'; 7057 7058 const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]').value; 7059 const csrfInput = document.createElement('input'); 7060 csrfInput.type = 'hidden'; 7061 csrfInput.name = 'csrfmiddlewaretoken'; 7062 csrfInput.value = csrfToken; 7063 7064 const actionInput = document.createElement('input'); 7065 actionInput.type = 'hidden'; 7066 actionInput.name = 'action'; 7067 actionInput.value = 'stop_impersonation'; 7068 7069 form.appendChild(csrfInput); 7070 form.appendChild(actionInput); 7071 document.body.appendChild(form); 7072 form.submit(); 7073 } 7074 } 7075 7076 // Notification dropdown functionality 7077 function toggleNotifications() { 7078 const panel = document.getElementById('notificationPanel'); 7079 const isHidden = panel.classList.contains('hidden'); 7080
7081 if (isHidden) { 7082 panel.classList.remove('hidden', 'opacity-0', 'scale-95'); 7083 panel.classList.add('opacity-100', 'scale-100'); 7084 } else { 7085 panel.classList.add('opacity-0', 'scale-95'); 7086 setTimeout(() => { 7087 panel.classList.add('hidden'); 7088 }, 150); 7089 } 7090 } 7091 7092 // Close notifications when clicking outside 7093 document.addEventListener('click', function(event) { 7094 const dropdown = document.getElementById('notificationDropdown'); 7095 const panel = document.getElementById('notificationPanel'); 7096 7097 if (dropdown && !dropdown.contains(event.target)) { 7098 panel.classList.add('opacity-0', 'scale-95'); 7099 setTimeout(() => { 7100 panel.classList.add('hidden'); 7101 }, 150); 7102 } 7103 }); 7104 7105 // Update notification count and load notifications 7106 function updateNotificationCount() { 7107 // Fetch notification count from server 7108 fetch('/notifications/count/') 7109 .then(response => response.json()) 7110 .then(data => { 7111 const countElement = document.getElementById('notificationCount'); 7112 if (countElement && data.success) { 7113 if (data.count > 0) { 7114 countElement.textContent = data.count; 7115 countElement.classList.remove('hidden'); 7116 } else { 7117 countElement.classList.add('hidden'); 7118 } 7119 } 7120 }) 7121 .catch(error => { 7122 console.error('Error fetching notification count:', error); 7123 }); 7124 } 7125 7126 // Load notifications for dropdown 7127 function loadNotifications() { 7128 fetch('/api/v1/notifications/') 7129 .then(response => response.json()) 7130 .then(data => { 7131 if (data.success) { 7132 updateNotificationDropdown(data.notifications); 7133 } else { 7134 console.error('Failed to load notifications:', data.error); 7135 } 7136 }) 7137 .catch(error => { 7138 console.error('Error loading notifications:', error); 7139 }); 7140 } 7141 7142 // Update notification dropdown content 7143 function updateNotificationDropdown(notifications) { 7144 const panel = document.getElementById('notificationPanel'); 7145 if (!panel) return; 7146 7147 // Find the notifications container 7148 let notificationsContainer = panel.querySelector('.max-h-96'); 7149 if (!notificationsContainer) return; 7150 7151 // Clear existing content 7152 notificationsContainer.innerHTML = ''; 7153 7154 if (notifications && notifications.length > 0) { 7155 notifications.forEach(notification => { 7156 const notificationElement = createNotificationElement(notification); 7157 notificationsContainer.appendChild(notificationElement); 7158 }); 7159 } else { 7160 // Show empty state 7161 notificationsContainer.innerHTML = ` 7162 <div class="p-8 text-center"> 7163 <i class="fas fa-bell-slash text-3xl text-gray-600 mb-2"></i> 7164 <p class="text-gray-400">No notifications yet</p> 7165 <p class="text-xs text-gray-500 mt-2">Trust report updates (Basic, Detailed, Predictive) appear here.</p> 7166 </div> 7167 `; 7168 } 7169 } 7170 7171 function trustReportProductLabel(reportType) { 7172 const raw = String(reportType || '').toLowerCase().replace(/-/g, '_'); 7173 if (!raw) return 'Trust report'; 7174 if (raw.indexOf('predictive') !== -1) return 'Predictive trust report'; 7175 if (raw === 'detail' || raw.indexOf('detailed') !== -1) return 'Detailed trust report'; 7176 if (raw.indexOf('basic') !== -1) return 'Basic trust report'; 7177 if (raw.indexOf('credit_score') !== -1) return 'Trust report'; 7178 return 'Trust report'; 7179 } 7180 7181 function polishNotificationCopy(notification) { 7182 let title = notification.title || 'Notification'; 7183 let body = notification.body || notification.message || ''; 7184 const data = notification.data || {}; 7185 const rt = data.report_type || data.reportType; 7186 if (rt && (notification.type === 'report_ready' || data.report_id)) { 7187 const label = trustReportProductLabel(rt); 7188 title = 'Your ' + label + ' is ready'; 7189 body = 'View and download your ' + label.toLowerCase() + ' from your dashboard.'; 7190 } 7191 title = title.replace(/ubuntu credit report/gi, 'Trust report').replace(/\bcredit report\b/gi, 'trust report'); 7192 body = body.replace(/ubuntu credit report/gi, 'Trust report').replace(/\bcredit report\b/gi, 'trust report'); 7193 return { title: title, body: body }; 7194 } 7195 7196 // Create notification element 7197 function createNotificationElement(notification) { 7198 const div = document.createElement('div'); 7199 div.className = 'p-4 border-b border-gray-700 hover:bg-gray-700 transition-colors cursor-pointer'; 7200 const display = polishNotificationCopy(notification); 7201 7202 const priorityColors = { 7203 'urgent': 'bg-red-500', 7204 'high': 'bg-orange-500', 7205 'normal': 'bg-blue-500', 7206 'low': 'bg-gray-500' 7207 }; 7208 7209 const typeIcons = { 7210 'payment': 'fa-credit-card', 7211 'system': 'fa-cog', 7212 'security': 'fa-shield-alt', 7213 'verification': 'fa-check-circle', 7214 'usage': 'fa-chart-bar', 7215 'marketing': 'fa-bullhorn', 7216 'maintenance': 'fa-tools', 7217 'report_ready': 'fa-file-alt' 7218 }; 7219 7220 const priorityColor = priorityColors[notification.priority] || 'bg-blue-500'; 7221 const typeIcon = typeIcons[notification.type] || 'fa-bell'; 7222 7223 div.innerHTML = ` 7224 <div class="flex items-start space-x-3"> 7225 <div class="flex-shrink-0"> 7226 <div class="w-2 h-2 ${priorityColor} rounded-full ${notification.is_read ? 'opacity-30' : ''}"></div> 7227 </div> 7228 <div class="flex-shrink-0"> 7229 <div class="w-8 h-8 bg-slate-700 rounded-lg flex items-center justify-center"> 7230 <i class="fas ${typeIcon} text-cyan-400 text-sm"></i> 7231 </div> 7232 </div> 7233 <div class="flex-1 min-w-0"> 7234 <p class="text-sm font-medium text-white truncate ${notification.is_read ? 'opacity-70' : ''}">${display.title}</p> 7235 <p class="text-sm text-gray-400 truncate">${display.body}</p> 7236 <p class="text-xs text-gray-500 mt-1">${formatNotificationTime(notification.created_at)}</p> 7237 </div> 7238 </div> 7239 `; 7240 7241 // Add click handler to mark as read 7242 div.addEventListener('click', () => { 7243 if (!notification.is_read) { 7244 markNotificationAsRead(notification.id); 7245 } 7246 7247 // Navigate to action URL if available 7248 if (notification.data && notification.data.action_url) { 7249 window.location.href = notification.data.action_url; 7250 } 7251 }); 7252 7253 return div; 7254 } 7255 7256 // Format notification time 7257 function formatNotificationTime(timestamp) { 7258 const date = new Date(timestamp); 7259 const now = new Date(); 7260 const diffMs = now - date; 7261 const diffMins = Math.floor(diffMs / 60000); 7262 const diffHours = Math.floor(diffMs / 3600000); 7263 const diffDays = Math.floor(diffMs / 86400000); 7264 7265 if (diffMins < 1) return 'Just now'; 7266 if (diffMins < 60) return `${diffMins}m ago`; 7267 if (diffHours < 24) return `${diffHours}h ago`; 7268 if (diffDays < 7) return `${diffDays}d ago`; 7269 return date.toLocaleDateString(); 7270 } 7271 7272 // Mark notification as read 7273 function markNotificationAsRead(notificationId) { 7274 fetch(`/notifications/mark-read/${notificationId}/`, { 7275 method: 'POST', 7276 headers: { 7277 'X-CSRFToken': getCookie('csrftoken'), 7278 'Content-Type': 'application/json' 7279 } 7280 }) 7281 .then(response => response.json()) 7282 .then(data => { 7283 if (data.success) { 7284 // Update notification count 7285 updateNotificationCount(); 7286 } 7287 }) 7288 .catch(error => { 7289 console.error('Error marking notification as read:', error); 7290 }); 7291 } 7292 7293 // Get CSRF token 7294 function getCookie(name) { 7295 let cookieValue = null; 7296 if (document.cookie && document.cookie !== '') { 7297 const cookies = document.cookie.split(';'); 7298 for (let i = 0; i < cookies.length; i++) { 7299 const cookie = cookies[i].trim(); 7300 if (cookie.substring(0, name.length + 1) === (name + '=')) { 7301 cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); 7302 break; 7303 } 7304 } 7305 } 7306 return cookieValue; 7307 } 7308 7309 // Initialize notification count on page load 7310 document.addEventListener('DOMContentLoaded', function() { 7311 updateNotificationCount(); 7312 7313 // Auto-refresh notification count every 30 seconds 7314 setInterval(updateNotificationCount, 30000); 7315 }); 7316 7317 // Management & Tools dropdown functionality (for superuser) 7318 function toggleManagementTools() { 7319 const panel = document.getElementById('managementToolsPanel'); 7320 const dropdown = document.getElementById('managementToolsDropdown'); 7321 7322 if (!panel || !dropdown) { 7323 console.error('Management & Tools dropdown elements not found'); 7324 return; 7325 } 7326 7327 const isHidden = panel.classList.contains('hidden') || panel.style.display === 'none'; 7328
7329 if (isHidden) { 7330 // Show the panel 7331 panel.style.display = 'block'; 7332 panel.classList.remove('hidden'); 7333 // Force a reflow to ensure the element is visible before transition 7334 panel.offsetHeight; 7335 panel.classList.remove('opacity-0', 'scale-95'); 7336 panel.classList.add('opacity-100', 'scale-100'); 7337 7338 // Add click outside listener 7339 document.addEventListener('click', handleManagementToolsClickOutside); 7340 } else { 7341 // Hide the panel 7342 hideManagementToolsDropdown(); 7343 } 7344 } 7345 7346 function hideManagementToolsDropdown() { 7347 const panel = document.getElementById('managementToolsPanel'); 7348 if (!panel) return; 7349 7350 panel.classList.remove('opacity-100', 'scale-100'); 7351 panel.classList.add('opacity-0', 'scale-95'); 7352 7353 // Remove the click outside listener 7354 document.removeEventListener('click', handleManagementToolsClickOutside); 7355 7356 // Hide after transition 7357 setTimeout(() => { 7358 panel.classList.add('hidden'); 7359 panel.style.display = 'none'; 7360 }, 300); 7361 } 7362 7363 function handleManagementToolsClickOutside(event) { 7364 const dropdown = document.getElementById('managementToolsDropdown'); 7365 if (dropdown && !dropdown.contains(event.target)) { 7366 hideManagementToolsDropdown(); 7367 } 7368 } 7369 7370 // Tools dropdown functionality 7371 function toggleTools() { 7372 const panel = document.getElementById('toolsPanel'); 7373 const dropdown = document.getElementById('toolsDropdown'); 7374 7375 if (!panel || !dropdown) { 7376 console.error('Tools dropdown elements not found'); 7377 return; 7378 } 7379 7380 const isHidden = panel.classList.contains('hidden') || panel.style.display === 'none'; 7381 7382 if (isHidden) { 7383 // Show the panel 7384 panel.style.display = 'block'; 7385 panel.classList.remove('hidden'); 7386 // Force a reflow to ensure the element is visible before transition 7387 panel.offsetHeight; 7388 panel.classList.remove('opacity-0', 'scale-95'); 7389 panel.classList.add('opacity-100', 'scale-100'); 7390 7391 // Add click outside listener 7392 document.addEventListener('click', handleToolsClickOutside); 7393 } else { 7394 // Hide the panel 7395 hideToolsDropdown(); 7396 } 7397 } 7398 7399 function hideToolsDropdown() { 7400 const panel = document.getElementById('toolsPanel'); 7401 if (!panel) return; 7402 7403 panel.classList.remove('opacity-100', 'scale-100'); 7404 panel.classList.add('opacity-0', 'scale-95'); 7405 setTimeout(() => { 7406 panel.classList.add('hidden'); 7407 panel.style.display = 'none'; 7408 }, 300); 7409 7410 // Remove click outside listener 7411 document.removeEventListener('click', handleToolsClickOutside); 7412 } 7413 7414 function handleToolsClickOutside(event) { 7415 const dropdown = document.getElementById('toolsDropdown'); 7416 if (dropdown && !dropdown.contains(event.target)) { 7417 hideToolsDropdown(); 7418 } 7419 } 7420 7421 // Test function to verify the tools dropdown is working (only logs errors if dropdown exists but broken) 7422 function testToolsDropdown() { 7423 const panel = document.getElementById('toolsPanel'); 7424 const button = document.querySelector('#toolsDropdown button'); 7425 7426 // Only log if the button exists but panel doesn't (indicates a problem) 7427 if (button && !panel) { 7428 console.error('Tools dropdown button exists but panel not found'); 7429 } 7430 // Success case - no logging needed 7431 } 7432 7433 // Run test on page load (silent unless there's an actual error) 7434 document.addEventListener('DOMContentLoaded', function() { 7435 testToolsDropdown(); 7436 }); 7437 7438 // Note: Click outside handling is now managed by handleToolsClickOutside function 7439 7440 </script>
7440 7441 7442 7443 7444 <!-- Include API Keys Modal --> 7445 <!-- API Keys Management Modal --> 7446<div id="apiKeysModal" class="fixed inset-0 bg-black bg-opacity-50 hidden z-50 flex items-center justify-center p-4"> 7447 <div class="bg-white rounded-xl shadow-2xl max-w-4xl w-full max-h-[90vh] overflow-hidden"> 7448 <!-- Modal Header --> 7449 <div class="bg-gradient-to-r from-blue-600 to-purple-600 text-white p-6"> 7450 <div class="flex items-center justify-between"> 7451 <div> 7452 <h2 class="text-2xl font-bold"> 7453 <i class="fas fa-key mr-3"></i> 7454 API Keys Management 7455 </h2> 7456 <p class="text-blue-100 mt-1">Manage your API keys for secure access to TumiTrust services</p> 7457 </div> 7458 <button onclick="closeApiKeysModal()" class="text-white hover:text-gray-200 text-2xl"> 7459 <i class="fas fa-times"></i> 7460 </button> 7461 </div> 7462 </div> 7463 7464 <!-- Modal Body --> 7465 <div class="p-6 overflow-y-auto max-h-[calc(90vh-140px)]"> 7466 <!-- Create New API Key Section --> 7467 <div class="mb-8"> 7468 <div class="bg-gradient-to-r from-green-50 to-blue-50 rounded-lg p-6 border border-green-200"> 7469 <h3 class="text-xl font-semibold text-gray-800 mb-4"> 7470 <i class="fas fa-plus-circle text-green-600 mr-2"></i> 7471 Create New API Key 7472 </h3> 7473 <form id="createApiKeyForm" class="space-y-4"> 7474 <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> 7475 <div> 7476 <label class="block text-sm font-medium text-gray-700 mb-2">Key Name</label> 7477 <input type="text" id="keyName" name="key_name" 7478 class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent" 7479 placeholder="e.g., Mobile App Key" required> 7480 </div> 7481 <div> 7482 <label class="block text-sm font-medium text-gray-700 mb-2">Expiration (Days)</label> 7483 <select id="keyExpiration" name="expiration_days" 7484 class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"> 7485 <option value="30">30 days</option> 7486 <option value="90">90 days</option> 7487 <option value="180">180 days</option> 7488 <option value="365">1 year</option> 7489 <option value="0">Never expires</option> 7490 </select> 7491 </div> 7492 </div> 7493 <div> 7494 <label class="block text-sm font-medium text-gray-700 mb-2">Permissions</label> 7495 <div class="grid grid-cols-2 md:grid-cols-4 gap-3"> 7496 <label class="flex items-center"> 7497 <input type="checkbox" name="permissions" value="read" checked class="mr-2"> 7498 <span class="text-sm">Read</span> 7499 </label> 7500 <label class="flex items-center"> 7501 <input type="checkbox" name="permissions" value="write" checked class="mr-2"> 7502 <span class="text-sm">Write</span> 7503 </label> 7504 <label class="flex items-center"> 7505 <input type="checkbox" name="permissions" value="billing" checked class="mr-2"> 7506 <span class="text-sm">Billing</span> 7507 </label> 7508 <label class="flex items-center"> 7509 <input type="checkbox" name="permissions" value="admin" class="mr-2">
7510 <span class="text-sm">Admin</span> 7511 </label> 7512 </div> 7513 </div> 7514 <div class="flex justify-end"> 7515 <button type="submit" 7516 class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-2 rounded-lg font-semibold transition-colors duration-200"> 7517 <i class="fas fa-key mr-2"></i> 7518 Generate API Key 7519 </button> 7520 </div> 7521 </form> 7522 </div> 7523 </div> 7524 7525 <!-- Existing API Keys Section --> 7526 <div> 7527 <h3 class="text-xl font-semibold text-gray-800 mb-4"> 7528 <i class="fas fa-list text-blue-600 mr-2"></i> 7529 Existing API Keys 7530 </h3> 7531 <div id="apiKeysList" class="space-y-4"> 7532 <!-- API Keys will be loaded here via JavaScript --> 7533 </div> 7534 </div> 7535 7536 <!-- API Usage Information --> 7537 <div class="mt-8 bg-gray-50 rounded-lg p-6"> 7538 <h4 class="text-lg font-semibold text-gray-800 mb-3"> 7539 <i class="fas fa-info-circle text-blue-600 mr-2"></i> 7540 API Usage Guidelines 7541 </h4> 7542 <div class="space-y-2 text-sm text-gray-600"> 7543 <p>⢠Keep your API keys secure and never share them publicly</p> 7544 <p>⢠Use different keys for different applications or environments</p> 7545 <p>⢠Regularly rotate your API keys for enhanced security</p> 7546 <p>⢠Monitor your API usage through the billing dashboard</p> 7547 <p>⢠Each API call counts towards your billing plan usage</p> 7548 </div> 7549 </div> 7550 </div> 7551 7552 <!-- Modal Footer --> 7553 <div class="bg-gray-50 px-6 py-4 flex justify-end space-x-3"> 7554 <button onclick="closeApiKeysModal()" 7555 class="px-6 py-2 text-gray-600 hover:text-gray-800 font-semibold transition-colors duration-200"> 7556 Close 7557 </button> 7558 <button onclick="refreshApiKeys()" 7559 class="bg-gray-600 hover:bg-gray-700 text-white px-6 py-2 rounded-lg font-semibold transition-colors duration-200"> 7560 <i class="fas fa-sync mr-2"></i> 7561 Refresh 7562 </button> 7563 </div> 7564 </div> 7565</div> 7566 7567<!-- API Key Display Modal --> 7568<div id="apiKeyDisplayModal" class="fixed inset-0 bg-black bg-opacity-50 hidden z-50 flex items-center justify-center p-4"> 7569 <div class="bg-white rounded-xl shadow-2xl max-w-2xl w-full"> 7570 <div class="bg-gradient-to-r from-green-600 to-blue-600 text-white p-6 rounded-t-xl"> 7571 <div class="flex items-center justify-between"> 7572 <h3 class="text-xl font-bold"> 7573 <i class="fas fa-check-circle mr-2"></i> 7574 API Key Generated Successfully 7575 </h3> 7576 <button onclick="closeApiKeyDisplayModal()" class="text-white hover:text-gray-200 text-xl"> 7577 <i class="fas fa-times"></i> 7578 </button> 7579 </div> 7580 </div> 7581 <div class="p-6"> 7582 <div class="bg-yellow-50 border border-yellow-200 rounded-lg p-4 mb-4"> 7583 <div class="flex items-center"> 7584 <i class="fas fa-exclamation-triangle text-yellow-600 mr-2"></i> 7585 <p class="text-yellow-800 font-semibold">Important: Save this key securely!</p> 7586 </div> 7587 <p class="text-yellow-700 text-sm mt-1">This is the only time you'll be able to see the full API key.</p> 7588 </div> 7589 <div> 7590 <label class="block text-sm font-medium text-gray-700 mb-2">API Key:</label> 7591 <div class="flex items-center space-x-2"> 7592 <input type="text" id="generatedApiKey" readonly 7593 class="flex-1 px-4 py-2 border border-gray-300 rounded-lg bg-gray-50 font-mono text-sm"> 7594 <button onclick="copyApiKey()" 7595 class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg text-sm font-semibold"> 7596 <i class="fas fa-copy mr-1"></i> 7597 Copy 7598 </button> 7599 </div> 7600 </div> 7601 <div class="mt-4"> 7602 <label class="block text-sm font-medium text-gray-700 mb-2">Key Name:</label> 7603 <p id="generatedKeyName" class="text-gray-600"></p> 7604 </div> 7605 <div class="mt-4"> 7606 <label class="block text-sm font-medium text-gray-700 mb-2">Expires:</label> 7607 <p id="generatedKeyExpiry" class="text-gray-600"></p> 7608 </div> 7609 </div> 7610 <div class="bg-gray-50 px-6 py-4 rounded-b-xl flex justify-end"> 7611 <button onclick="closeApiKeyDisplayModal()" 7612 class="bg-green-600 hover:bg-green-700 text-white px-6 py-2 rounded-lg font-semibold"> 7613 <i class="fas fa-check mr-2"></i> 7614 I've Saved the Key 7615 </button> 7616 </div> 7617 </div> 7618</div> 7619
7620<script> 7621// API Keys Management Functions 7622function openApiKeysModal() { 7623 document.getElementById('apiKeysModal').classList.remove('hidden'); 7624 loadApiKeys(); 7625} 7626 7627function closeApiKeysModal() { 7628 document.getElementById('apiKeysModal').classList.add('hidden'); 7629} 7630 7631function closeApiKeyDisplayModal() { 7632 document.getElementById('apiKeyDisplayModal').classList.add('hidden'); 7633} 7634 7635function loadApiKeys() { 7636 // Load existing API keys via AJAX 7637 fetch('/api/keys/', { 7638 method: 'GET', 7639 headers: { 7640 'X-CSRFToken': getCookie('csrftoken'), 7641 'Content-Type': 'application/json', 7642 }, 7643 }) 7644 .then(response => response.json()) 7645 .then(data => { 7646 const container = document.getElementById('apiKeysList'); 7647 if (data.keys && data.keys.length > 0) { 7648 container.innerHTML = data.keys.map(key => ` 7649 <div class="bg-white border border-gray-200 rounded-lg p-4"> 7650 <div class="flex items-center justify-between"> 7651 <div class="flex-1"> 7652 <div class="flex items-center space-x-3"> 7653 <h4 class="font-semibold text-gray-800">${key.name}</h4> 7654 <span class="px-2 py-1 text-xs rounded-full ${key.is_active ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'}"> 7655 ${key.is_active ? 'Active' : 'Inactive'} 7656 </span> 7657 ${key.is_default ? '<span class="px-2 py-1 text-xs rounded-full bg-blue-100 text-blue-800">Default</span>' : ''} 7658 </div> 7659 <p class="text-sm text-gray-600 mt-1"> 7660 <span class="font-mono">${key.key_display}</span> 7661 </p> 7662 <p class="text-xs text-gray-500 mt-1"> 7663 Created: ${new Date(key.created_at).toLocaleDateString()} 7664 ${key.expires_at ? ` | Expires: ${new Date(key.expires_at).toLocaleDateString()}` : ' | Never expires'} 7665 </p> 7666 <p class="text-xs text-gray-500"> 7667 Permissions: ${key.permissions.join(', ')} 7668 </p> 7669 </div> 7670 <div class="flex items-center space-x-2"> 7671 <button onclick="toggleApiKey('${key.id}')" 7672 class="px-3 py-1 text-xs rounded ${key.is_active ? 'bg-red-100 text-red-700 hover:bg-red-200' : 'bg-green-100 text-green-700 hover:bg-green-200'}"> 7673 ${key.is_active ? 'Deactivate' : 'Activate'} 7674 </button> 7675 <button onclick="deleteApiKey('${key.id}')" 7676 class="px-3 py-1 text-xs rounded bg-red-100 text-red-700 hover:bg-red-200"> 7677 <i class="fas fa-trash"></i> 7678 </button> 7679 </div> 7680 </div> 7681 </div> 7682 `).join(''); 7683 } else { 7684 container.innerHTML = ` 7685 <div class="text-center py-8 text-gray-500"> 7686 <i class="fas fa-key text-4xl mb-3"></i> 7687 <p>No API keys found</p> 7688 <p class="text-sm">Create your first API key to get started</p> 7689 </div> 7690 `; 7691 } 7692 }) 7693 .catch(error => { 7694 console.error('Error loading API keys:', error); 7695 document.getElementById('apiKeysList').innerHTML = ` 7696 <div class="text-center py-8 text-red-500"> 7697 <i class="fas fa-exclamation-triangle text-4xl mb-3"></i> 7698 <p>Error loading API keys</p> 7699 <p class="text-sm">Please try again later</p> 7700 </div> 7701 `; 7702 }); 7703} 7704 7705function refreshApiKeys() { 7706 loadApiKeys(); 7707} 7708 7709// Create API Key Form Handler 7710document.getElementById('createApiKeyForm').addEventListener('submit', function(e) { 7711 e.preventDefault(); 7712 7713 const formData = new FormData(this); 7714 const permissions = Array.from(document.querySelectorAll('input[name="permissions"]:checked')).map(cb => cb.value); 7715 7716 const data = { 7717 name: formData.get('key_name'), 7718 expiration_days: parseInt(formData.get('expiration_days')), 7719 permissions: permissions 7720 }; 7721 7722 fetch('/api/keys/create/', { 7723 method: 'POST', 7724 headers: { 7725 'X-CSRFToken': getCookie('csrftoken'), 7726 'Content-Type': 'application/json', 7727 }, 7728 body: JSON.stringify(data) 7729 }) 7730 .then(response => response.json()) 7731 .then(data => { 7732 if (data.success) { 7733 // Show the generated key 7734 document.getElementById('generatedApiKey').value = data.api_key; 7735 document.getElementById('generatedKeyName').textContent = data.name; 7736 document.getElementById('generatedKeyExpiry').textContent = data.expires_at ? 7737 new Date(data.expires_at).toLocaleDateString() : 'Never expires'; 7738 7739 closeApiKeysModal(); 7740 document.getElementById('apiKeyDisplayModal').classList.remove('hidden'); 7741 7742 // Refresh the keys list 7743 loadApiKeys(); 7744 } else { 7745 alert('Error creating API key: ' + (data.error || 'Unknown error')); 7746 } 7747 }) 7748 .catch(error => { 7749 console.error('Error creating API key:', error); 7750 alert('Error creating API key. Please try again.'); 7751 }); 7752}); 7753 7754function copyApiKey() { 7755 const apiKeyInput = document.getElementById('generatedApiKey'); 7756 apiKeyInput.select(); 7757 document.execCommand('copy'); 7758 7759 // Show feedback 7760 const button = event.target; 7761 const originalText = button.innerHTML; 7762 button.innerHTML = '<i class="fas fa-check mr-1"></i>Copied!'; 7763 button.classList.add('bg-green-600'); 7764 button.classList.remove('bg-blue-600'); 7765 7766 setTimeout(() => { 7767 button.innerHTML = originalText; 7768 button.classList.remove('bg-green-600'); 7769 button.classList.add('bg-blue-600'); 7770 }, 2000); 7771} 7772 7773function toggleApiKey(keyId) { 7774 fetch(`/api/keys/${keyId}/toggle/`, { 7775 method: 'POST', 7776 headers: { 7777 'X-CSRFToken': getCookie('csrftoken'), 7778 'Content-Type': 'application/json', 7779 } 7780 }) 7781 .then(response => response.json()) 7782 .then(data => { 7783 if (data.success) { 7784 loadApiKeys(); 7785 } else { 7786 alert('Error toggling API key: ' + (data.error || 'Unknown error')); 7787 } 7788 }) 7789 .catch(error => { 7790 console.error('Error toggling API key:', error); 7791 alert('Error toggling API key. Please try again.'); 7792 }); 7793} 7794 7795function deleteApiKey(keyId) { 7796 if (confirm('Are you sure you want to delete this API key? This action cannot be undone.')) { 7797 fetch(`/api/keys/${keyId}/delete/`, { 7798 method: 'DELETE', 7799 headers: { 7800 'X-CSRFToken': getCookie('csrftoken'), 7801 'Content-Type': 'application/json', 7802 } 7803 }) 7804 .then(response => response.json()) 7805 .then(data => { 7806 if (data.success) { 7807 loadApiKeys(); 7808 } else { 7809 alert('Error deleting API key: ' + (data.error || 'Unknown error')); 7810 } 7811 }) 7812 .catch(error => { 7813 console.error('Error deleting API key:', error); 7814 alert('Error deleting API key. Please try again.'); 7815 }); 7816 } 7817} 7818 7819// Utility function to get CSRF token 7820function getCookie(name) {
7821 let cookieValue = null; 7822 if (document.cookie && document.cookie !== '') { 7823 const cookies = document.cookie.split(';'); 7824 for (let i = 0; i < cookies.length; i++) { 7825 const cookie = cookies[i].trim(); 7826 if (cookie.substring(0, name.length + 1) === (name + '=')) { 7827 cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); 7828 break; 7829 } 7830 } 7831 } 7832 return cookieValue; 7833} 7834</script>
7834 7835 7836 7837 <!-- Impersonation Modal --> 7838 <div id="impersonationModal" class="fixed inset-0 bg-gray-900 bg-opacity-50 hidden z-50"> 7839 <div class="flex items-center justify-center min-h-screen p-4"> 7840 <div class="bg-gray-800 rounded-lg max-w-2xl w-full p-6"> 7841 <div class="flex justify-between items-center mb-4"> 7842 <h3 class="text-lg font-semibold text-white">Impersonate User</h3> 7843 <button onclick="hideImpersonationModal()" class="text-gray-400 hover:text-white"> 7844 <i class="fas fa-times"></i> 7845 </button> 7846 </div> 7847 7848 <div class="mb-4"> 7849 <label class="block text-sm font-medium text-gray-300 mb-2">Search Users</label> 7850 <input type="text" id="userSearch" placeholder="Search by name or email..." 7851 class="w-full bg-gray-700 border border-gray-600 rounded-lg px-3 py-2 text-white"> 7852 </div> 7853 7854 <div class="max-h-96 overflow-y-auto"> 7855 <div id="usersList" class="space-y-2"> 7856 <!-- Users will be loaded here --> 7857 <div class="text-center py-8"> 7858 <i class="fas fa-spinner fa-spin text-2xl text-gray-400 mb-2"></i> 7859 <p class="text-gray-400">Loading users...</p> 7860 </div> 7861 </div> 7862 </div> 7863 7864 <div class="flex justify-end space-x-3 mt-6"> 7865 <button onclick="hideImpersonationModal()" class="px-4 py-2 text-gray-400 hover:text-white"> 7866 Cancel 7867 </button> 7868 </div> 7869 </div> 7870 </div> 7871 </div> 7872 7873 <!-- Impersonation Status Banner --> 7874 <div id="impersonationBanner" class="hidden fixed top-0 left-0 right-0 bg-orange-600 text-white text-center py-2 z-50"> 7875 <div class="flex items-center justify-center space-x-4"> 7876 <i class="fas fa-user-secret"></i> 7877 <span>You are impersonating: <strong id="impersonatedUserName"></strong></span> 7878 <button onclick="stopImpersonation()" class="bg-orange-700 hover:bg-orange-800 px-3 py-1 rounded text-sm"> 7879 Stop Impersonation 7880 </button> 7881 </div> 7882 </div> 7883 7884 <!-- Footer Section --> 7885 <footer class="bg-gradient-to-r from-gray-900 via-gray-800 to-gray-900 text-white py-16"> 7886 <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> 7887 <!-- Site footer link grid - public-safe PTI + TumiTrust core (base_landing / base) --> 7888<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-5 lg:grid-cols-5 gap-6 sm:gap-8"> 7889 <!-- PTI - category & specification --> 7890 <div class="space-y-4"> 7891 <h3 class="text-lg font-semibold flex items-center"> 7892 <i class="fas fa-book mr-2 text-orange-400"></i> 7893 Portable Trust 7894 </h3> 7895 <ul class="space-y-2"> 7896 <li><a href="/docs/pti/why-pti" class="text-amber-200 hover:text-white transition-colors flex items-center font-semibold"><i class="fas fa-lightbulb mr-2 text-xs text-amber-300/90"></i>Why PTI</a></li> 7897 <li><a href="/docs/pti/introduction/" class="text-gray-300 hover:text-white transition-colors flex items-center"><i class="fas fa-book-open mr-2 text-xs"></i>What is PTI</a></li> 7898 <li><a href="/docs/pti/specification/v1.0/" class="text-gray-300 hover:text-white transition-colors flex items-center"><i class="fas fa-file-contract mr-2 text-xs"></i>Specification v1.0</a></li> 7899 <li><a href="/docs/pti/reference-architecture/" class="text-gray-300 hover:text-white transition-colors flex items-center"><i class="fas fa-project-diagram mr-2 text-xs"></i>Reference architecture</a></li> 7900 <li><a href="/docs/pti/specification/v1.0/security" class="text-gray-300 hover:text-white transition-colors flex items-center"><i class="fas fa-shield-halved mr-2 text-xs"></i>Security & privacy</a></li> 7901 <li><a href="/docs/pti/governance/" class="text-gray-300 hover:text-white transition-colors flex items-center"><i class="fas fa-scale-balanced mr-2 text-xs"></i>Governance</a></li> 7902 <li><a href="/docs/pti/origin/" class="text-gray-300 hover:text-white transition-colors flex items-center"><i class="fas fa-landmark mr-2 text-xs"></i>Origin & stewardship</a></li> 7903 </ul> 7904 </div> 7905 7906 <!-- Get started --> 7907 <div class="space-y-4"> 7908 <h3 class="text-lg font-semibold flex items-center"> 7909 <i class="fas fa-rocket mr-2 text-orange-400"></i> 7910 Get started 7911 </h3> 7912 <ul class="space-y-2"> 7913 <li> 7914 <a href="/docs/" class="text-amber-200 hover:text-white transition-colors flex items-center font-semibold"> 7915 <i class="fas fa-compass mr-2 text-xs"></i>Documentation 7916 </a> 7917 </li> 7918 <li> 7919 <a href="/docs/tumitrust/product-overview/get-started" class="text-gray-300 hover:text-white transition-colors flex items-center"> 7920 <i class="fas fa-mobile-alt mr-2 text-xs"></i>Platform guide 7921 </a> 7922 </li> 7923 <li> 7924 <a href="/platform/" class="text-gray-300 hover:text-white transition-colors flex items-center"> 7925 <i class="fas fa-layer-group mr-2 text-xs"></i>Platform overview 7926 </a> 7927 </li> 7928 <li> 7929 <a href="/docs/pti/glossary/" class="text-gray-300 hover:text-white transition-colors flex items-center"> 7930 <i class="fas fa-language mr-2 text-xs"></i>Glossary 7931 </a> 7932 </li> 7933 7934 <li> 7935 <a href="/register/" class="text-gray-300 hover:text-white transition-colors flex items-center"> 7936 <i class="fas fa-user-plus mr-2 text-xs"></i>Create account 7937 </a> 7938 </li> 7939 7940 </ul> 7941 </div> 7942
7943 <!-- Individuals --> 7944 <div class="space-y-4"> 7945 <h3 class="text-lg font-semibold flex items-center"> 7946 <i class="fas fa-user mr-2 text-amber-400"></i> 7947 Individuals 7948 </h3> 7949 <ul class="space-y-2"> 7950 <li> 7951 <a href="/docs/tumitrust/audiences/for-individuals" class="text-gray-300 hover:text-white transition-colors flex items-center"> 7952 <i class="fas fa-id-card mr-2 text-xs"></i>For individuals 7953 </a> 7954 </li> 7955 <li> 7956 <a href="/docs/tumitrust/audiences/for-individuals#what-you-do-on-the-platform" class="text-gray-300 hover:text-white transition-colors flex items-center"> 7957 <i class="fas fa-user-check mr-2 text-xs"></i>Your trust profile 7958 </a> 7959 </li> 7960 <li> 7961 <a href="/docs/tumitrust/audiences/for-individuals#three-ways-trust-travels" class="text-gray-300 hover:text-white transition-colors flex items-center"> 7962 <i class="fas fa-share-alt mr-2 text-xs"></i>Trust CV & lookups 7963 </a> 7964 </li> 7965 <li> 7966 <a href="/docs/tumitrust/audiences/for-individuals#trust-contexts-in-everyday-life" class="text-gray-300 hover:text-white transition-colors flex items-center"> 7967 <i class="fas fa-layer-group mr-2 text-xs"></i>Trust contexts 7968 </a> 7969 </li> 7970 </ul> 7971 </div> 7972 7973 <!-- Organisations --> 7974 <div class="space-y-4"> 7975 <h3 class="text-lg font-semibold flex items-center"> 7976 <i class="fas fa-building mr-2 text-orange-400"></i> 7977 Organisations 7978 </h3> 7979 <ul class="space-y-2"> 7980 <li> 7981 <a href="/docs/tumitrust/audiences/for-institutions" class="text-gray-300 hover:text-white transition-colors flex items-center"> 7982 <i class="fas fa-university mr-2 text-xs"></i>Institutions & verifiers 7983 </a> 7984 </li> 7985 <li> 7986 <a href="/docs/tumitrust/audiences/for-partners" class="text-gray-300 hover:text-white transition-colors flex items-center"> 7987 <i class="fas fa-handshake mr-2 text-xs"></i>Trust producers 7988 </a> 7989 </li> 7990 <li> 7991 <a href="/docs/tumitrust/solutions/" class="text-gray-300 hover:text-white transition-colors flex items-center"> 7992 <i class="fas fa-industry mr-2 text-xs"></i>Solutions by industry 7993 </a> 7994 </li> 7995 <li> 7996 <a href="/docs/tumitrust/developer-guides/trust-platform-api" class="text-gray-300 hover:text-white transition-colors flex items-center"> 7997 <i class="fas fa-plug mr-2 text-xs"></i>Trust platform API 7998 </a> 7999 </li> 8000 <li> 8001 <a href="/solutions/" class="text-gray-300 hover:text-white transition-colors flex items-center"> 8002 <i class="fas fa-briefcase mr-2 text-xs"></i>Solutions hub 8003 </a> 8004 </li> 8005 </ul> 8006 </div> 8007 8008 <!-- Learn & help --> 8009 <div class="space-y-4"> 8010 <h3 class="text-lg font-semibold flex items-center"> 8011 <i class="fas fa-book-open mr-2 text-amber-400"></i> 8012 Learn & help 8013 </h3> 8014 <ul class="space-y-2"> 8015 <li> 8016 <a href="/help/" class="text-amber-200 hover:text-white transition-colors flex items-center font-semibold"> 8017 <i class="fas fa-life-ring mr-2 text-xs"></i>Help center 8018 </a> 8019 </li> 8020 <li> 8021 <a href="/faq/" class="text-gray-300 hover:text-white transition-colors flex items-center"> 8022 <i class="fas fa-question-circle mr-2 text-xs"></i>FAQ 8023 </a> 8024 </li> 8025 <li> 8026 <a href="/company/" class="text-gray-300 hover:text-white transition-colors flex items-center"> 8027 <i class="fas fa-building mr-2 text-xs"></i>Company 8028 </a> 8029 </li> 8030 <li> 8031 <a href="/careers/" class="text-gray-300 hover:text-white transition-colors flex items-center"> 8032 <i class="fas fa-rocket mr-2 text-xs text-amber-400/90"></i>Careers 8033 </a> 8034 </li> 8035 <li> 8036 <a href="/status/" class="text-gray-300 hover:text-white transition-colors flex items-center"> 8037 <i class="fas fa-heartbeat mr-2 text-xs"></i>System status 8038 </a> 8039 </li> 8040 <li> 8041 <a href="mailto:[email protected]" class="text-gray-300 hover:text-white transition-colors flex items-center"> 8042 <i class="fas fa-envelope mr-2 text-xs"></i>Contact 8043 </a> 8044 </li> 8045 </ul> 8046 </div> 8047</div> 8048 8049 8050 <!-- System Status Banner --> 8051 <div class="mb-8 mt-12 flex items-center justify-center"> 8052 <a href="/status/" id="footer-status-link" class="group flex items-center gap-4 px-8 py-4 rounded-2xl transition-all duration-300 hover:bg-white/5" style="background: rgba(255, 255, 255, 0.02); border: 1px solid rgba(255, 255, 255, 0.1);"> 8053 <div class="relative"> 8054 <!-- Pulsing status indicator --> 8055 <div id="footer-status-dot" class="w-3 h-3 bg-green-500 rounded-full relative z-10"></div> 8056 <!-- Pulse waves --> 8057 <div id="footer-status-pulse-1" class="absolute inset-0 w-3 h-3 bg-green-500 rounded-full animate-ping opacity-75"></div> 8058 <div id="footer-status-pulse-2" class="absolute inset-0 w-3 h-3 bg-green-500 rounded-full" style="animation: ping 1.5s cubic-bezier(0, 0, 0.2, 1) 0.3s infinite;"></div> 8059 <div id="footer-status-pulse-3" class="absolute inset-0 w-3 h-3 bg-green-500 rounded-full" style="animation: ping 1.5s cubic-bezier(0, 0, 0.2, 1) 0.6s infinite;"></div> 8060 </div> 8061 <div class="text-left"> 8062 <div id="footer-status-text" class="text-white font-bold text-sm">All Systems Operational</div> 8063 <div class="text-gray-400 text-xs">View detailed status page â</div> 8064 </div> 8065 <div class="text-green-400 group-hover:translate-x-1 transition-transform"> 8066 <i class="fas fa-arrow-right"></i> 8067 </div> 8068 </a> 8069 </div> 8070 8071 <!-- Bottom Bar --> 8072 <div class="border-t border-gray-700 mt-12 pt-8"> 8073 <div class="flex flex-col md:flex-row justify-between items-center space-y-4 md:space-y-0"> 8074 <div class="flex items-center space-x-3 text-gray-400 text-sm"> 8075 <!-- Cute Logo in Copyright --> 8076 <div class="relative group"> 8077 <div class="absolute inset-0 bg-gradient-to-r from-orange-500/30 via-amber-400/30 to-yellow-400/30 rounded-full blur-sm op
8077acity-50 group-hover:opacity-75 transition-opacity duration-300"></div> 8078 <div class="relative bg-gradient-to-br from-orange-600/10 via-amber-500/10 to-yellow-400/10 rounded-full p-1 border border-orange-500/20"> 8079 8080 <img src="/static/img/logo.4cbf73b23224.svg" alt="TumiTrust" class="w-6 h-6 object-contain filter drop-shadow-md" style="animation: gentleFloat 3s ease-in-out infinite;"> 8081 </div> 8082 </div> 8083 <span> 8084 8085<span>© 2026 TumiTrust. All rights reserved.</span> 8086 | Built with â¤ï¸ | 8087 </span> 8088 <span> 8089 <a href="/privacy-policy/" class="hover:text-white transition-colors">Privacy</a> | 8090 <a href="/terms-of-service/" class="hover:text-white transition-colors">Terms</a> | 8091 <a href="/community-guidelines/" class="hover:text-white transition-colors">Guidelines</a> | 8092 <a href="/cookie-policy/" class="hover:text-white transition-colors">Cookies</a> | 8093 <a href="/reports/verify/" class="hover:text-white transition-colors"> 8094 <i class="fas fa-shield-check mr-1"></i>Verify Reports 8095 </a> 8096 | 8097 <a href="/brand/merchandise/" class="hover:text-white transition-colors"> 8098 <i class="fas fa-palette mr-1"></i>Gallery 8099 </a> 8100 | 8101 <a href="/careers/" class="hover:text-white transition-colors"> 8102 <i class="fas fa-rocket mr-1 text-amber-400/90"></i>Careers 8103 </a> 8104 </span> 8105 </div> 8106 <div class="text-gray-400 text-sm" title="Portable Trust Infrastructure - proof you authorize"> 8107 <i class="fas fa-shield-alt mr-1 text-amber-400/80" aria-hidden="true"></i> 8108 Portable trust 8109 </div> 8110 </div> 8111 </div> 8112 </div> 8113 </footer> 8114 8115 <!-- User Consent Popup --> 8116 8117 8118<!-- Beautiful Privacy & Cookie Consent Popup --> 8119<div id="consent-popup" class="consent-popup" style="display: none;"> 8120 <!-- Removed overlay to allow page interaction --> 8121 <div class="consent-popup-content"> 8122 <!-- Decorative Elements --> 8123 <div class="consent-decoration consent-decoration-1"></div> 8124 <div class="consent-decoration consent-decoration-2"></div> 8125 8126 <div class="consent-inner"> 8127 <!-- Header with Ubuntu Theme --> 8128 <div class="consent-header"> 8129 <div class="consent-icon-wrapper"> 8130 <div class="consent-icon-gradient"> 8131 <i class="fas fa-cookie-bite"></i> 8132 </div> 8133 </div> 8134 <div class="consent-header-text"> 8135 <h4 class="consent-title"> 8136 <span class="cookie-emoji">ðª</span> Privacy & Cookies 8137 </h4> 8138 <p class="consent-subtitle">Your privacy matters to us</p> 8139 </div> 8140 <button type="button" class="consent-close" id="consent-close-btn" aria-label="Close"> 8141 <i class="fas fa-times"></i> 8142 </button> 8143 </div> 8144 8145 <!-- Body Content --> 8146 <div class="consent-body"> 8147 <p class="consent-description"> 8148 We use cookies to enhance your experience, provide personalized content, and analyze our traffic. 8149 You can choose which cookies you're comfortable with. 8150 </p> 8151 8152 <!-- Cookie Categories --> 8153 <div class="consent-options" id="consent-options-container"> 8154 <!-- Necessary Cookies --> 8155 <div class="cookie-category"> 8156 <div class="cookie-category-header"> 8157 <div class="cookie-icon cookie-icon-necessary"> 8158 <i class="fas fa-shield-check"></i> 8159 </div> 8160 <div class="cookie-info"> 8161 <div class="cookie-name"> 8162 Necessary Cookies
8163 <span class="cookie-badge cookie-badge-required">Required</span> 8164 </div> 8165 <p class="cookie-description">Essential for the platform to function properly. Cannot be disabled.</p> 8166 </div> 8167 <div class="cookie-toggle"> 8168 <input type="checkbox" id="consent-necessary" class="cookie-switch" checked disabled> 8169 <label for="consent-necessary" class="cookie-switch-label"> 8170 <span class="cookie-switch-slider"></span> 8171 </label> 8172 </div> 8173 </div> 8174 </div> 8175 8176 <!-- Functional Cookies --> 8177 <div class="cookie-category"> 8178 <div class="cookie-category-header"> 8179 <div class="cookie-icon cookie-icon-functional"> 8180 <i class="fas fa-cogs"></i> 8181 </div> 8182 <div class="cookie-info"> 8183 <div class="cookie-name">Functional Cookies</div> 8184 <p class="cookie-description">Remember your preferences and settings for a better experience.</p> 8185 </div> 8186 <div class="cookie-toggle"> 8187 <input type="checkbox" id="consent-functional" class="cookie-switch"> 8188 <label for="consent-functional" class="cookie-switch-label"> 8189 <span class="cookie-switch-slider"></span> 8190 </label> 8191 </div> 8192 </div> 8193 </div> 8194 8195 <!-- Analytics Cookies --> 8196 <div class="cookie-category"> 8197 <div class="cookie-category-header"> 8198 <div class="cookie-icon cookie-icon-analytics"> 8199 <i class="fas fa-chart-line"></i> 8200 </div> 8201 <div class="cookie-info"> 8202 <div class="cookie-name">Analytics Cookies</div> 8203 <p class="cookie-description">Help us understand how you use the platform to improve our services.</p> 8204 </div> 8205 <div class="cookie-toggle"> 8206 <input type="checkbox" id="consent-analytics" class="cookie-switch"> 8207 <label for="consent-analytics" class="cookie-switch-label"> 8208 <span class="cookie-switch-slider"></span> 8209 </label> 8210 </div> 8211 </div> 8212 </div> 8213 8214 <!-- Marketing Cookies --> 8215 <div class="cookie-category"> 8216 <div class="cookie-category-header"> 8217 <div class="cookie-icon cookie-icon-marketing"> 8218 <i class="fas fa-bullhorn"></i> 8219 </div> 8220 <div class="cookie-info"> 8221 <div class="cookie-name">Marketing Cookies</div> 8222 <p class="cookie-description">Deliver personalized content and measure campaign effectiveness.</p> 8223 </div> 8224 <div class="cookie-toggle"> 8225 <input type="checkbox" id="consent-marketing" class="cookie-switch"> 8226 <label for="consent-marketing" class="cookie-switch-label"> 8227 <span class="cookie-switch-slider"></span> 8228 </label> 8229 </div> 8230 </div> 8231 </div> 8232 </div> 8233 8234 <!-- Privacy Links --> 8235 <div class="consent-links"> 8236 <a href="/privacy-policy/" target="_blank" class="consent-link"> 8237 <i class="fas fa-shield-alt"></i>
8238 <span>Privacy Policy</span> 8239 </a> 8240 <span class="consent-link-separator">â¢</span> 8241 <a href="/cookie-policy/" target="_blank" class="consent-link"> 8242 <i class="fas fa-cookie"></i> 8243 <span>Cookie Policy</span> 8244 </a> 8245 <span class="consent-link-separator">â¢</span> 8246 <a href="/terms-of-service/" target="_blank" class="consent-link"> 8247 <i class="fas fa-file-contract"></i> 8248 <span>Terms</span> 8249 </a> 8250 <span class="consent-link-separator">â¢</span> 8251 <a href="/community-guidelines/" target="_blank" class="consent-link"> 8252 <i class="fas fa-users"></i> 8253 <span>Community guidelines</span> 8254 </a> 8255 </div> 8256 </div> 8257 8258 <!-- Footer with Actions --> 8259 <div class="consent-footer"> 8260 <button type="button" class="btn-consent btn-consent-reject" id="consent-reject" title="Only essential cookies (required for basic site functionality)"> 8261 <i class="fas fa-shield-check"></i> 8262 <span>Essential Only</span> 8263 </button> 8264 <button type="button" class="btn-consent btn-consent-primary" id="consent-accept" title="Accept all cookies for best experience"> 8265 <i class="fas fa-check-circle"></i> 8266 <span>Accept All</span> 8267 </button> 8268 <button type="button" class="btn-consent btn-consent-custom" id="consent-customize" title="Choose which cookies to accept"> 8269 <i class="fas fa-cog"></i> 8270 <span>Customize</span> 8271 </button> 8272 </div> 8273 <div class="consent-footer-note"> 8274 <i class="fas fa-info-circle"></i> 8275 <span>We recommend accepting all cookies for the best experience. Essential cookies are always enabled.</span> 8276 </div> 8277 </div> 8278 </div> 8279</div> 8280 8281<style> 8282/* Ubuntu Theme Colors */ 8283:root { 8284 --ubuntu-orange: #FF8C00; 8285 --ubuntu-gold: #DAA520; 8286 --ubuntu-amber: #CD853F; 8287 --ubuntu-burgundy: #8B0000; 8288 --ubuntu-gradient: linear-gradient(135deg, var(--ubuntu-orange), var(--ubuntu-gold)); 8289 --ubuntu-gradient-reverse: linear-gradient(135deg, var(--ubuntu-gold), var(--ubuntu-orange)); 8290} 8291 8292/* Overlay removed - page remains fully interactive */ 8293.consent-overlay { 8294 display: none; /* Completely hidden */ 8295} 8296 8297/* Main Popup Container */ 8298.consent-popup { 8299 position: fixed; 8300 bottom: 20px; 8301 right: 20px; 8302 width: 100%; 8303 max-width: 450px; 8304 max-height: 85vh; /* Limit height to 85% of viewport */ 8305 z-index: 9999; 8306 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', sans-serif; 8307 animation: slideInUp 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); 8308} 8309 8310.consent-popup-content { 8311 position: relative; 8312 background: linear-gradient(135deg, #ffffff 0%, #fefefe 100%); 8313 border-radius: 20px; 8314 box-shadow: 8315 0 30px 60px -15px rgba(0, 0, 0, 0.3), 8316 0 20px 40px -10px rgba(255, 140, 0, 0.2), 8317 0 0 0 2px rgba(255, 140, 0, 0.15); 8318 overflow-y: auto; /* Enable scrolling if needed */ 8319 max-height: 85vh; /* Match parent */ 8320 pointer-events: auto; /* Ensure popup itself is clickable */ 8321} 8322 8323/* Decorative Elements */ 8324.consent-decoration { 8325 position: absolute; 8326 border-radius: 50%; 8327 opacity: 0.08; 8328 pointer-events: none; 8329} 8330 8331.consent-decoration-1 { 8332 width: 200px; 8333 height: 200px; 8334 background: var(--ubuntu-gradient); 8335 top: -100px; 8336 right: -50px; 8337 animation: float 6s ease-in-out infinite; 8338} 8339 8340.consent-decoration-2 { 8341 width: 150px; 8342 height: 150px; 8343 background: var(--ubuntu-gradient-reverse); 8344 bottom: -75px; 8345 left: -40px; 8346 animation: float 8s ease-in-out infinite reverse; 8347} 8348 8349/* Inner Content */ 8350.consent-inner { 8351 position: relative; 8352 z-index: 1; 8353} 8354 8355/* Header - Reduced padding */ 8356.consent-header { 8357 display: flex; 8358 align-items: center; 8359 gap: 12px; 8360 padding: 16px 20px 14px; 8361 background: linear-gradient(135deg, rgba(255, 140, 0, 0.05) 0%, rgba(218, 165, 32, 0.05) 100%); 8362 border-bottom: 2px solid rgba(255, 140, 0, 0.1); 8363} 8364 8365.consent-icon-wrapper { 8366 flex-shrink: 0; 8367} 8368 8369.consent-icon-gradient { 8370 width: 44px; 8371 height: 44px; 8372 border-radius: 12px; 8373 background: var(--ubuntu-gradient); 8374 display: flex; 8375 align-items: center; 8376 justify-content: center; 8377 box-shadow: 8378 0 6px 12px rgba(255, 140, 0, 0.25), 8379 0 0 0 2px rgba(255, 140, 0, 0.1); 8380 animation: pulse 3s ease-in-out infinite; 8381} 8382 8383.consent-icon-gradient i { 8384 font-size: 22px; 8385 color: #ffffff; 8386} 8387 8388.consent-header-text { 8389 flex: 1; 8390} 8391 8392.consent-title { 8393 margin: 0; 8394 font-size: 18px; 8395 font-weight: 700; 8396 color: #1a1a1a; 8397 display: flex; 8398 align-items: center; 8399 gap: 6px; 8400} 8401 8402.cookie-emoji { 8403 font-size: 20px; 8404 animation: bounce 2s ease-in-out infinite; 8405} 8406 8407.consent-subtitle { 8408 margin: 2px 0 0 0; 8409 font-size: 13px; 8410 color: #6b7280; 8411 font-weight: 500; 8412} 8413 8414.consent-close { 8415 flex-shrink: 0; 8416 width: 36px; 8417 height: 36px; 8418 border-radius: 10px; 8419 border: 2px solid rgba(255, 140, 0, 0.2); 8420 background: transparent; 8421 color: var(--ubuntu-orange); 8422 cursor: pointer; 8423 transition: all 0.2s ease; 8424 display: flex; 8425 align-items: center; 8426 justify-content: center; 8427 font-size: 16px; 8428} 8429 8430.consent-close:hover { 8431 background: var(--ubuntu-gradient); 8432 color: #ffffff; 8433 border-color: transparent; 8434 transform: rotate(90deg); 8435} 8436 8437/* Body - Reduced padding */ 8438.consent-body { 8439 padding: 16px 20px; 8440 max-height: 50vh; 8441 overflow-y: auto; 8442} 8443 8444.consent-body::-webkit-scrollbar {
8445 width: 6px; 8446} 8447 8448.consent-body::-webkit-scrollbar-track { 8449 background: #f3f4f6; 8450 border-radius: 10px; 8451} 8452 8453.consent-body::-webkit-scrollbar-thumb { 8454 background: var(--ubuntu-gradient); 8455 border-radius: 10px; 8456} 8457 8458.consent-description { 8459 margin: 0 0 14px 0; 8460 font-size: 14px; 8461 line-height: 1.5; 8462 color: #4b5563; 8463} 8464 8465/* Cookie Categories - More compact */ 8466.consent-options { 8467 display: flex; 8468 flex-direction: column; 8469 gap: 8px; 8470 margin-bottom: 16px; 8471} 8472 8473.cookie-category { 8474 background: #f9fafb; 8475 border: 2px solid #e5e7eb; 8476 border-radius: 10px; 8477 padding: 12px; 8478 transition: all 0.2s ease; 8479} 8480 8481.cookie-category:hover { 8482 border-color: var(--ubuntu-orange); 8483 background: #fef3f2; 8484 transform: translateX(4px); 8485} 8486 8487.cookie-category-header { 8488 display: flex; 8489 align-items: flex-start; 8490 gap: 12px; 8491} 8492 8493.cookie-icon { 8494 flex-shrink: 0; 8495 width: 32px; 8496 height: 32px; 8497 border-radius: 8px; 8498 display: flex; 8499 align-items: center; 8500 justify-content: center; 8501 font-size: 15px; 8502 color: #ffffff; 8503 box-shadow: 0 3px 6px rgba(0, 0, 0, 0.1); 8504} 8505 8506.cookie-icon-necessary { 8507 background: linear-gradient(135deg, #10b981, #059669); 8508} 8509 8510.cookie-icon-functional { 8511 background: linear-gradient(135deg, #3b82f6, #2563eb); 8512} 8513 8514.cookie-icon-analytics { 8515 background: var(--ubuntu-gradient); 8516} 8517 8518.cookie-icon-marketing { 8519 background: linear-gradient(135deg, #ec4899, #db2777); 8520} 8521 8522.cookie-info { 8523 flex: 1; 8524} 8525 8526.cookie-name { 8527 font-size: 14px; 8528 font-weight: 600; 8529 color: #1f2937; 8530 margin-bottom: 2px; 8531 display: flex; 8532 align-items: center; 8533 gap: 6px; 8534} 8535 8536.cookie-badge { 8537 display: inline-flex; 8538 align-items: center; 8539 padding: 2px 8px; 8540 border-radius: 6px; 8541 font-size: 11px; 8542 font-weight: 600; 8543 text-transform: uppercase; 8544 letter-spacing: 0.5px; 8545} 8546 8547.cookie-badge-required { 8548 background: #d1fae5; 8549 color: #065f46; 8550} 8551 8552.cookie-description { 8553 margin: 0; 8554 font-size: 13px; 8555 line-height: 1.5; 8556 color: #6b7280; 8557} 8558 8559/* Custom Toggle Switch */ 8560.cookie-toggle { 8561 flex-shrink: 0; 8562} 8563 8564.cookie-switch { 8565 display: none; 8566} 8567 8568.cookie-switch-label { 8569 position: relative; 8570 display: block; 8571 width: 52px; 8572 height: 28px; 8573 background: #d1d5db; 8574 border-radius: 14px; 8575 cursor: pointer; 8576 transition: all 0.3s ease; 8577 box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1); 8578} 8579 8580.cookie-switch-slider { 8581 position: absolute; 8582 top: 2px; 8583 left: 2px; 8584 width: 24px; 8585 height: 24px; 8586 background: #ffffff; 8587 border-radius: 50%; 8588 transition: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55); 8589 box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); 8590} 8591 8592.cookie-switch:checked + .cookie-switch-label { 8593 background: var(--ubuntu-gradient); 8594} 8595 8596.cookie-switch:checked + .cookie-switch-label .cookie-switch-slider { 8597 transform: translateX(24px); 8598} 8599 8600.cookie-switch:disabled + .cookie-switch-label { 8601 opacity: 0.6; 8602 cursor: not-allowed; 8603} 8604 8605/* Privacy Links */ 8606.consent-links { 8607 display: flex; 8608 align-items: center; 8609 justify-content: center; 8610 gap: 12px; 8611 padding-top: 16px; 8612 border-top: 1px solid #e5e7eb; 8613 margin-top: 16px; 8614} 8615 8616.consent-link { 8617 display: inline-flex; 8618 align-items: center; 8619 gap: 6px; 8620 font-size: 13px; 8621 font-weight: 600; 8622 color: var(--ubuntu-orange); 8623 text-decoration: none; 8624 transition: all 0.2s ease; 8625 padding: 4px 8px; 8626 border-radius: 6px; 8627} 8628 8629.consent-link:hover { 8630 background: rgba(255, 140, 0, 0.1); 8631 color: var(--ubuntu-gold); 8632 transform: translateY(-2px); 8633} 8634 8635.consent-link i { 8636 font-size: 12px; 8637} 8638 8639.consent-link-separator { 8640 color: #d1d5db; 8641} 8642 8643/* Footer - Reduced padding */ 8644.consent-footer { 8645 display: flex; 8646 gap: 8px; 8647 padding: 14px 20px; 8648 background: linear-gradient(to top, rgba(255, 140, 0, 0.03), transparent); 8649 border-top: 1px solid rgba(255, 140, 0, 0.1); 8650} 8651 8652.btn-consent { 8653 flex: 1; 8654 display: flex; 8655 align-items: center; 8656 justify-content: center; 8657 gap: 6px; 8658 padding: 10px 16px; 8659 border-radius: 10px; 8660 font-size: 13px; 8661 font-weight: 600; 8662 border: none; 8663 cursor: pointer; 8664 transition: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55); 8665 box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); 8666} 8667 8668.btn-consent i { 8669 font-size: 16px; 8670} 8671 8672.btn-consent-primary { 8673 background: var(--ubuntu-gradient); 8674 color: #ffffff; 8675 box-shadow: 8676 0 4px 12px rgba(255, 140, 0, 0.4), 8677 0 2px 4px rgba(0, 0, 0, 0.1); 8678} 8679 8680.btn-consent-primary:hover { 8681 transform: translateY(-2px) scale(1.02); 8682 box-shadow: 8683 0 8px 16px rgba(255, 140, 0, 0.5), 8684 0 4px 8px rgba(0, 0, 0, 0.15); 8685} 8686 8687.btn-consent-primary:active { 8688 transform: translateY(0) scale(0.98); 8689} 8690 8691.btn-consent-reject { 8692 background: #ffffff; 8693 color: #6b7280; 8694 border: 2px solid #e5e7eb; 8695} 8696 8697.btn-consent-reject:hover { 8698 background: #f9fafb; 8699 border-color: #d1d5db; 8700 color: #374151; 8701 transform: translateY(-2px); 8702} 8703 8704.btn-consent-custom { 8705 background: linear-gradient(135deg, #3b82f6, #2563eb); 8706 color: #ffffff; 8707 display: none; /* Hidden by default, shown when customizing */ 8708} 8709 8710.btn-consent-custom:hover { 8711 transform: translateY(-2px) scale(1.02); 8712 box-shadow: 0 8px 16px rgba(59, 130, 246, 0.4); 8713} 8714 8715/* Footer Note - Recommendation */ 8716.consent-footer-note { 8717 padding: 10px 20px; 8718 background: linear-gradient(135deg, rgba(255, 140, 0, 0.08), rgba(218, 165, 32, 0.06)); 8719 border-top: 1px solid rgba(255, 140, 0, 0.15); 8720 display: flex; 8721 align-items: center; 8722 gap: 8px; 8723 font-size: 12px; 8724 color: #6b7280; 8725 line-height: 1.4; 8726} 8727 8728.consent-footer-note i { 8729 color: var(--ubuntu-orange); 8730 flex-shrink: 0; 8731 font-size: 14px; 8732} 8733 8734/* Animations */ 8735@keyframes fadeIn { 8736 from { 8737 opacity: 0; 8738 } 8739 to { 8740 opacity: 1; 8741 } 8742} 8743 8744@keyframes slideInUp { 8745 from { 8746 transform: translateY(100px); 8747 opacity: 0; 8748 } 8749 to { 8750 transform: translateY(0); 8751 opacity: 1; 8752 } 8753} 8754 8755@keyframes pulse { 8756 0%, 100% { 8757 transform: scale(1); 8758 } 8759 50% { 8760 transform: scale(1.05); 8761 } 8762} 8763 8764@keyframes bounce { 8765 0%, 100% { 8766 transform: translateY(0); 8767 } 8768 50% { 8769 transform: translateY(-4px); 8770 } 8771} 8772 8773@keyframes float { 8774 0%, 100% { 8775 transform: translate(0, 0) rotate(0deg); 8776 } 8777 33% { 8778 transform: translate(10px, -10px) rotate(5deg); 8779 } 8780 66% { 8781 transform: translate(-5px, 5px) rotate(-5deg); 8782 } 8783} 8784 8785/* Responsive Design */ 8786@media (max-width: 768px) { 8787 .consent-popup { 8788 left: 10px; 8789 right: 10px; 8790 bottom: 10px; 8791 max-width: none; 8792 } 8793 8794 .consent-footer { 8795 flex-direction: column; 8796 } 8797 8798 .btn-consent { 8799 width: 100%; 8800 } 8801 8802 .consent-links { 8803 flex-wrap: wrap; 8804 } 8805} 8806 8807@media (max-width: 480px) { 8808 .consent-header { 8809 padding: 20px 16px 16px; 8810 } 8811 8812 .consent-body { 8813 padding: 20px 16px; 8814 } 8815 8816 .consent-footer { 8817 padding: 16px; 8818 } 8819 8820 .consent-title { 8821 font-size: 18px; 8822 } 8823 8824 .consent-icon-gradient { 8825 width: 48px; 8826 height: 48px; 8827 } 8828 8829 .consent-icon-gradient i { 8830 font-size: 24px; 8831 } 8832} 8833 8834/* Dark Mode Support */ 8835@media (prefers-color-scheme: dark) { 8836 .consent-popup-content { 8837 background: linear-gradient(135deg, #1f2937 0%, #111827 100%); 8838 box-shadow: 8839 0 25px 50px -12px rgba(255, 140, 0, 0.4), 8840 0 0 0 1px rgba(255, 140, 0, 0.2), 8841 0 10px 20px rgba(0, 0, 0, 0.3); 8842 } 8843 8844 .consent-title { 8845 color: #f9fafb; 8846 } 8847 8848 .consent-subtitle { 8849 color: #9ca3af; 8850 } 8851 8852 .consent-description { 8853 color: #d1d5db; 8854 } 8855 8856 .cookie-category { 8857 background: #374151; 8858 border-color: #4b5563; 8859 } 8860 8861 .cookie-category:hover { 8862 background: rgba(255, 140, 0, 0.1); 8863 border-color: var(--ubuntu-orange); 8864 } 8865 8866 .cookie-name { 8867 color: #f3f4f6; 8868 } 8869 8870 .cookie-description { 8871 color: #9ca3af; 8872 } 8873 8874 .btn-consent-secondary { 8875 background: #374151; 8876 color: #f9fafb; 8877 border-color: #4b5563; 8878 } 8879 8880 .btn-consent-secondary:hover { 8881 background: #4b5563; 8882 } 8883} 8884</style> 8885
8886<script> 8887document.addEventListener('DOMContentLoaded', function() { 8888 const consentPopup = document.getElementById('consent-popup'); 8889 const consentOverlay = document.querySelector('.consent-overlay'); 8890 const acceptBtn = document.getElementById('consent-accept'); 8891 const rejectBtn = document.getElementById('consent-reject'); 8892 const customizeBtn = document.getElementById('consent-customize'); 8893 const closeBtn = document.getElementById('consent-close-btn'); 8894 8895 const functionalCheckbox = document.getElementById('consent-functional'); 8896 const analyticsCheckbox = document.getElementById('consent-analytics'); 8897 const marketingCheckbox = document.getElementById('consent-marketing'); 8898 8899 const STORAGE_KEY = 'tumitrust-cookie-consent'; 8900 const CONSENT_EXPIRY_DAYS = 180; // 6 months 8901 8902 // Check if user has already made a choice and if it's still valid 8903 function checkExistingConsent() { 8904 try { 8905 const stored = localStorage.getItem(STORAGE_KEY); 8906 if (!stored) return false; 8907 8908 const consent = JSON.parse(stored); 8909 const consentDate = new Date(consent.timestamp); 8910 const expiryDate = new Date(); 8911 expiryDate.setDate(expiryDate.getDate() - CONSENT_EXPIRY_DAYS); 8912 8913 // If consent is older than 6 months, show popup again 8914 if (consentDate < expiryDate) { 8915 localStorage.removeItem(STORAGE_KEY); 8916 return false; 8917 } 8918 8919 // Apply stored preferences 8920 applyConsent(consent); 8921 return true; 8922 } catch (e) { 8923 console.error('Error checking consent:', e); 8924 return false; 8925 } 8926 } 8927 8928 // Show popup after delay if no consent 8929 if (!checkExistingConsent()) { 8930 setTimeout(() => { 8931 consentPopup.style.display = 'block'; 8932 document.body.style.overflow = 'hidden'; // Prevent scrolling 8933 }, 1500); 8934 } 8935 8936 // Accept all cookies 8937 acceptBtn.addEventListener('click', function() { 8938 const consent = { 8939 necessary: true, 8940 functional: true, 8941 analytics: true, 8942 marketing: true, 8943 timestamp: new Date().toISOString() 8944 }; 8945 saveConsent(consent); 8946 hidePopup(); 8947 }); 8948 8949 // Reject all (except necessary) 8950 rejectBtn.addEventListener('click', function() { 8951 const consent = { 8952 necessary: true, 8953 functional: false, 8954 analytics: false, 8955 marketing: false, 8956 timestamp: new Date().toISOString() 8957 }; 8958 saveConsent(consent); 8959 hidePopup(); 8960 }); 8961 8962 // Save custom preferences 8963 customizeBtn.addEventListener('click', function() { 8964 const consent = { 8965 necessary: true, 8966 functional: functionalCheckbox.checked, 8967 analytics: analyticsCheckbox.checked, 8968 marketing: marketingCheckbox.checked, 8969 timestamp: new Date().toISOString() 8970 }; 8971 saveConsent(consent); 8972 hidePopup(); 8973 }); 8974 8975 // Close button 8976 closeBtn.addEventListener('click', function() { 8977 hidePopup(); 8978 // Save minimal consent when closing without selection 8979 const consent = { 8980 necessary: true, 8981 functional: false, 8982 analytics: false, 8983 marketing: false, 8984 timestamp: new Date().toISOString() 8985 }; 8986 saveConsent(consent); 8987 }); 8988 8989 // Show/hide customize button based on checkbox changes 8990 [functionalCheckbox, analyticsCheckbox, marketingCheckbox].forEach(checkbox => { 8991 checkbox.addEventListener('change', function() { 8992 customizeBtn.style.display = 'flex'; 8993 acceptBtn.style.display = 'none'; 8994 }); 8995 }); 8996 8997 // Save consent to localStorage 8998 function saveConsent(consent) { 8999 try { 9000 localStorage.setItem(STORAGE_KEY, JSON.stringify(consent)); 9001 applyConsent(consent); 9002 9003 // Send to backend for server-side storage 9004 sendConsentToServer(consent); 9005 } catch (e) { 9006 console.error('Error saving consent:', e); 9007 } 9008 } 9009 9010 // Apply consent settings 9011 function applyConsent(consent) { 9012 if (consent.analytics) { 9013 enableAnalytics(); 9014 } 9015 if (consent.marketing) { 9016 enableMarketing(); 9017 } 9018 if (consent.functional) { 9019 enableFunctional(); 9020 } 9021 9022 console.log('â Cookie preferences applied:', consent); 9023 } 9024 9025 // Hide popup with animation 9026 function hidePopup() { 9027 consentPopup.style.animation = 'slideInUp 0.3s ease-out reverse'; 9028 setTimeout(() => { 9029 consentPopup.style.display = 'none'; 9030 document.body.style.overflow = ''; // Restore scrolling 9031 }, 300); 9032 } 9033 9034 // Send consent to backend 9035 function sendConsentToServer(consent) { 9036 fetch('/api/v1/consent/save/', { 9037 method: 'POST', 9038 headers: { 9039 'Content-Type': 'application/json', 9040 'X-CSRFToken': getCookie('csrftoken') 9041 }, 9042 body: JSON.stringify(consent) 9043 }).then(response => { 9044 if (response.ok) { 9045 console.log('â Consent saved to server'); 9046 } 9047 }).catch(error => { 9048 console.error('Error saving consent to server:', error); 9049 }); 9050 } 9051 9052 // Get CSRF token 9053 function getCookie(name) { 9054 let cookieValue = null; 9055 if (document.cookie && document.cookie !== '') { 9056 const cookies = document.cookie.split(';'); 9057 for (let i = 0; i < cookies.length; i++) { 9058 const cookie = cookies[i].trim(); 9059 if (cookie.substring(0, name.length + 1) === (name + '=')) { 9060 cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); 9061 break; 9062 } 9063 } 9064 } 9065 return cookieValue; 9066 } 9067 9068 // Enable analytics 9069 function enableAnalytics() { 9070 // Initialize Google Analytics or other analytics 9071 console.log('ð Analytics enabled'); 9072 // Example: gtag('config', 'GA_MEASUREMENT_ID'); 9073 } 9074 9075 // Enable marketing 9076 function enableMarketing() { 9077 // Initialize marketing pixels (Facebook, LinkedIn, etc.) 9078 console.log('ð¢ Marketing tracking enabled'); 9079 // Example: fbq('init', 'FB_PIXEL_ID'); 9080 } 9081 9082 // Enable functional cookies 9083 function enableFunctional() { 9084 // Enable functional features 9085 console.log('âï¸ Functional cookies enabled'); 9086 } 9087}); 9088</script>
9088 9089 9090 9091 <!-- Footer System Status Monitor --> 9092
9092<script> 9093 (function() { 9094 const statusDot = document.getElementById('footer-status-dot'); 9095 const statusPulse1 = document.getElementById('footer-status-pulse-1'); 9096 const statusPulse2 = document.getElementById('footer-status-pulse-2'); 9097 const statusPulse3 = document.getElementById('footer-status-pulse-3'); 9098 const statusText = document.getElementById('footer-status-text'); 9099 const statusLink = document.getElementById('footer-status-link'); 9100 9101 if (!statusDot || !statusText) return; 9102 9103 // Status color configurations 9104 const statusConfig = { 9105 operational: { 9106 color: 'rgb(34, 197, 94)', // green-500 9107 bgColor: 'bg-green-500', 9108 textColor: 'text-green-400', 9109 text: 'All Systems Operational', 9110 borderGlow: 'rgba(34, 197, 94, 0.3)' 9111 }, 9112 degraded: { 9113 color: 'rgb(234, 179, 8)', // yellow-500 9114 bgColor: 'bg-yellow-500', 9115 textColor: 'text-yellow-400', 9116 text: 'Some Services Degraded', 9117 borderGlow: 'rgba(234, 179, 8, 0.3)' 9118 }, 9119 down: { 9120 color: 'rgb(239, 68, 68)', // red-500 9121 bgColor: 'bg-red-500', 9122 textColor: 'text-red-400', 9123 text: 'Service Disruption', 9124 borderGlow: 'rgba(239, 68, 68, 0.3)' 9125 } 9126 }; 9127 9128 function updateStatusDisplay(status) { 9129 const config = statusConfig[status] || statusConfig.operational; 9130 9131 // Update dot and pulses 9132 [statusDot, statusPulse1, statusPulse2, statusPulse3].forEach(el => { 9133 if (el) { 9134 el.className = el.className.replace(/bg-(green|yellow|red)-500/g, config.bgColor); 9135 el.style.backgroundColor = config.color; 9136 el.style.boxShadow = `0 0 20px ${config.color}`; 9137 } 9138 }); 9139 9140 // Update text 9141 statusText.textContent = config.text; 9142 statusText.className = statusText.className.replace(/text-(green|yellow|red)-400/g, 'text-white'); 9143 9144 // Update arrow color 9145 const arrow = statusLink.querySelector('.fas.fa-arrow-right'); 9146 if (arrow) { 9147 arrow.parentElement.className = arrow.parentElement.className.replace( 9148 /text-(green|yellow|red)-400/g, 9149 config.textColor 9150 ); 9151 } 9152 9153 // Update link border glow 9154 statusLink.style.borderColor = config.borderGlow; 9155 statusLink.style.boxShadow = `0 4px 20px ${config.borderGlow}`; 9156 } 9157 9158 async function checkSystemStatus() { 9159 try { 9160 // Check main API endpoint 9161 const response = await fetch('/api/v1/ping/', { 9162 method: 'GET', 9163 headers: { 9164 'Accept': 'application/json' 9165 }, 9166 credentials: 'same-origin', 9167 signal: AbortSignal.timeout(5000) 9168 }); 9169 9170 if (response.ok) { 9171 // If main API is up, assume operational 9172 // In production, you'd fetch from /api/v1/status/ or similar 9173 updateStatusDisplay('operational'); 9174 } else if (response.status >= 500) { 9175 updateStatusDisplay('down'); 9176 } else { 9177 updateStatusDisplay('degraded'); 9178 } 9179 } catch (error) { 9180 // Network error or timeout 9181 console.warn('Status check failed:', error); 9182 updateStatusDisplay('degraded'); 9183 } 9184 } 9185 9186 // Initial check 9187 checkSystemStatus(); 9188 9189 // Refresh every 60 seconds 9190 setInterval(checkSystemStatus, 60000); 9191 9192 // Add beautiful hover effect
9193 statusLink.addEventListener('mouseenter', function() { 9194 this.style.transform = 'translateY(-2px)'; 9195 this.style.transition = 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)'; 9196 }); 9197 9198 statusLink.addEventListener('mouseleave', function() { 9199 this.style.transform = 'translateY(0)'; 9200 }); 9201 })(); 9202 </script>
9202 9203 9204 <!-- PWA Service Worker Registration --> 9205
9205<script> 9206 if ('serviceWorker' in navigator) { 9207 window.addEventListener('load', () => { 9208 navigator.serviceWorker.register('/static/js/service-worker.js') 9209 .then((registration) => { 9210 console.log('[PWA] Service Worker registered successfully:', registration.scope); 9211 9212 // Check for updates every hour 9213 setInterval(() => { 9214 registration.update(); 9215 }, 3600000); 9216 }) 9217 .catch((error) => { 9218 console.error('[PWA] Service Worker registration failed:', error); 9219 }); 9220 }); 9221 } 9222 </script>
9222 9223 9224 <!-- Connection Status Indicator --> 9225
9225<script src="/static/js/connection-status.28cf6ad96e05.js?v=conn2"></script>
9225 9226 <!-- Premium toast notifications (use TumiTrustToast.success|error|info|warning(title, message)) --> 9227
9227<script src="/static/js/toast.aae8f96dfc7c.js"></script>
9227 9228</body> 9229</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.