1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 <meta charset="UTF-8" /> 5 <title>Sign in | Textwash⢠Pro Cloud</title> 6 <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" /> 7 <meta name="theme-color" content="#ffffff" /> 8 <meta name="color-scheme" content="light" /> 9 <link rel="icon" href="/favicon.ico" sizes="any" /> 10 <link rel="icon" href="/favicon.svg" type="image/svg+xml" /> 11 <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" /> 12 <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" /> 13 <link rel="apple-touch-icon" href="/apple-icon-180x180.png" /> 14 <link rel="manifest" href="/manifest.json" /> 15 <meta name="description" content="Sign in to Textwash⢠Pro Cloud, the AI workspace where every prompt is anonymised before it reaches Claude, ChatGPT, DeepSeek or Google Gemini. No account yet? Book a call and we will set one up." /> 16 <link rel="canonical" href="https://www.textwash.eu/cloud/" /> 17 <link rel="alternate" hreflang="en" href="https://www.textwash.eu/cloud/" /> 18 <link rel="alternate" hreflang="de" href="https://www.textwash.eu/de/cloud/" /> 19 <link rel="alternate" hreflang="x-default" href="https://www.textwash.eu/cloud/" /> 20 21 <!-- Social sharing --> 22 <meta property="og:type" content="website" /> 23 <meta property="og:site_name" content="Textwash⢠Pro" /> 24 <meta property="og:title" content="Sign in | Textwash⢠Pro Cloud" /> 25 <meta property="og:description" content="Sign in to Textwash⢠Pro Cloud, the AI workspace where every prompt is anonymised before it reaches Claude, ChatGPT, DeepSeek or Google Gemini." /> 26 <meta property="og:url" content="https://www.textwash.eu/cloud/" /> 27 <meta property="og:image" content="https://www.textwash.eu/logo.png" /> 28 <meta property="og:locale" content="en" /> 29 <meta name="twitter:card" content="summary" /> 30 <meta name="twitter:title" content="Sign in | Textwash⢠Pro Cloud" /> 31 <meta name="twitter:description" content="Sign in to Textwash⢠Pro Cloud, the AI workspace where every prompt is anonymised before it reaches Claude, ChatGPT, DeepSeek or Google Gemini." /> 32 <meta name="twitter:image" content="https://www.textwash.eu/logo.png" /> 33 34 <!-- Inter font (CDN) --> 35 <link rel="preconnect" href="https://fonts.googleapis.com" /> 36 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> 37 <link rel="preconnect" href="https://www.jocapps.com" crossorigin /> 38 <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet" /> 39<meta name="msvalidate.01" content="82696D54F75F65F1FC0FD72F864B472B" /> 40 41 <!-- Production-ready local Tailwind build (used by the dialogs) --> 42 <link rel="stylesheet" href="/styles.css" /> 43 44 <!-- Design system --> 45 <style> 46 :root { 47 --ink: #1d1d1f; 48 --ink-2: #46464c; 49 --ink-3: #6e6e73; 50 --bg: #ffffff; 51 --bg-soft: #f5f5f7; 52 --line: #e8e8ed; 53 --brand: #059669; 54 --brand-ink: #047857; 55 --brand-soft: rgba(16, 185, 129, 0.09); 56 --grad: linear-gradient(110deg, #10b981, #0ea5a4 45%, #0284c7); 57 --radius: 22px; 58 --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.04), 0 20px 50px rgba(29, 29, 31, 0.07); 59 } 60 61 html { scroll-behavior: smooth; } 62 63 body { 64 margin: 0; 65 font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; 66 background: var(--bg); 67 color: var(--ink-2); 68 -webkit-font-smoothing: antialiased; 69 font-size: 17px; 70 line-height: 1.55; 71 } 72 73 ::selection { background: rgba(16, 185, 129, 0.18); color: #0f172a; } 74 75 h1, h2, h3 { color: var(--ink); text-wrap: balance; margin: 0; } 76 /* Spelled out rather than left to the Tailwind reset: line-height: 0 keeps a 77 superscript from stretching the line it sits on, so the leading stays even. */ 78 sup { font-size: 0.72em; line-height: 0; position: relative; top: -0.42em; vertical-align: baseline; } 79 80 .wrap { max-width: 1104px; margin: 0 auto; padding: 0 24px; } 81 .wrap-tight { max-width: 880px; margin: 0 auto; padding: 0 24px; } 82 83 .sec { padding: 88px 0; } 84 .sec-soft { background: var(--bg-soft); } 85 86 .eyebrow { 87 display: inline-flex; 88 align-items: center; 89 gap: 8px; 90 font-size: 13px; 91 font-weight: 600; 92 letter-spacing: 0.12em; 93 text-transform: uppercase; 94 color: var(--brand-ink); 95 margin-bottom: 14px; 96 } 97 98 .h-xl { 99 font-size: clamp(2.6rem, 6.4vw, 4.6rem); 100 line-height: 1.04; 101 font-weight: 800; 102 letter-spacing: -0.03em; 103 } 104 105 .h-lg { 106 font-size: clamp(1.9rem, 4vw, 2.9rem); 107 line-height: 1.08; 108 font-weight: 700; 109 letter-spacing: -0.025em; 110 } 111 112 .h-md { font-size: 1.15rem; font-weight: 600; letter-spacing: -0.01em; } 113 114 .grad-text { 115 background: var(--grad); 116 -webkit-background-clip: text; 117 background-clip: text; 118 color: transparent; 119 } 120 121 .lead { 122 font-size: clamp(1.05rem, 1.8vw, 1.3rem); 123 line-height: 1.5; 124 color: var(--ink-2); 125 max-width: 42em; 126 } 127 128 .muted { color: var(--ink-3); } 129 .small { font-size: 0.85rem; } 130 131 /* ---------- Buttons ---------- */ 132 .btn { 133 display: inline-flex; 134 align-items: center; 135 justify-content: center; 136 gap: 8px; 137 border-radius: 999px; 138 padding: 14px 26px; 139 font-size: 0.98rem; 140 font-weight: 600; 141 line-height: 1; 142 cursor: pointer; 143 border: 1px solid transparent; 144 text-decoration: none; 145 transition: transform 0.18s ease, box-shadow 0.18s ease, background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease; 146 -webkit-tap-highlight-color: transparent; 147 font-family: inherit; 148 } 149 .btn:active { transform: scale(0.97); } 150 .btn-primary { 151 background: linear-gradient(120deg, #04805c, #065f46); 152 color: #ffffff; 153 box-shadow: 0 10px 28px rgba(6, 95, 70, 0.32); 154 } 155 .btn-primary:hover { transform: translateY(-1px); box-shadow: 0 14px 34px rgba(6, 95, 70, 0.4); } 156 .btn-ghost { 157 background: #ffffff; 158 border-color: #d2d2d7; 159 color: var(--ink); 160 } 161 .btn-ghost:hover { border-color: var(--brand); color: var(--brand-ink); } 162 .btn-sm { padding: 10px 18px; font-size: 0.88rem; } 163 .link-arrow { 164 display: inline-flex; 165 align-items: center; 166 gap: 6px; 167 color: var(--brand-ink); 168 font-weight: 600; 169 text-decoration: none; 170 font-size: 0.95rem; 171 }
172 .link-arrow:hover { text-decoration: underline; } 173 174 /* ---------- Header ---------- */ 175 .site-header { 176 position: sticky; 177 top: 0; 178 z-index: 40; 179 background: rgba(255, 255, 255, 0.78); 180 backdrop-filter: blur(20px) saturate(180%); 181 -webkit-backdrop-filter: blur(20px) saturate(180%); 182 border-bottom: 1px solid rgba(0, 0, 0, 0.06); 183 } 184 .site-header .bar { 185 display: flex; 186 align-items: center; 187 justify-content: space-between; 188 gap: 16px; 189 height: 60px; 190 } 191 .brand { 192 display: flex; 193 align-items: center; 194 gap: 10px; 195 text-decoration: none; 196 color: var(--ink); 197 min-width: 0; 198 } 199 .brand { flex: 0 0 auto; } 200 .brand img { height: 30px; width: 30px; border-radius: 8px; } 201 .brand b { font-size: 1rem; font-weight: 700; letter-spacing: -0.02em; white-space: nowrap; } 202 .site-nav { display: flex; align-items: center; gap: 4px; } 203 .site-nav a { 204 color: var(--ink-2); 205 text-decoration: none; 206 font-size: 0.87rem; 207 font-weight: 500; 208 padding: 7px 11px; 209 border-radius: 999px; 210 transition: background-color 0.15s ease, color 0.15s ease; 211 white-space: nowrap; 212 } 213 .site-nav a:hover { background: rgba(0, 0, 0, 0.05); color: var(--ink); } 214 .header-cta { display: flex; align-items: center; gap: 10px; } 215 .header-cta .btn { white-space: nowrap; } 216 .lang-switch { 217 display: inline-flex; 218 align-items: center; 219 gap: 2px; 220 border: 1px solid var(--line); 221 border-radius: 999px; 222 padding: 2px; 223 background: #fff; 224 } 225 .lang-switch a, .lang-switch span { 226 display: inline-flex; 227 align-items: center; 228 justify-content: center; 229 min-width: 30px; 230 height: 26px; 231 border-radius: 999px; 232 font-size: 0.95rem; 233 text-decoration: none; 234 line-height: 1; 235 } 236 .lang-switch .active { background: var(--brand-soft); box-shadow: inset 0 0 0 1px rgba(5, 150, 105, 0.35); } 237 238 /* Collapsible mobile menu. On desktop the panel is transparent to layout 239 (display: contents), so nav and CTAs stay direct children of the bar. */ 240 .nav-panel { display: contents; } 241 .nav-toggle { 242 display: none; 243 align-items: center; 244 justify-content: center; 245 flex: 0 0 auto; 246 width: 42px; 247 height: 42px; 248 padding: 0; 249 border: 1px solid var(--line); 250 border-radius: 13px; 251 background: #fff; 252 color: var(--ink); 253 cursor: pointer; 254 -webkit-tap-highlight-color: transparent; 255 transition: background-color 0.15s ease, border-color 0.15s ease; 256 } 257 .nav-toggle:hover { background: var(--bg-soft); border-color: #d8d8e0; } 258 .nav-toggle:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; } 259 .nav-toggle .bars { position: relative; display: block; width: 18px; height: 12px; } 260 .nav-toggle .bars i { 261 position: absolute; 262 left: 0; 263 width: 100%; 264 height: 2px; 265 border-radius: 2px; 266 background: currentColor; 267 transition: transform 0.32s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.18s ease; 268 } 269 .nav-toggle .bars i:nth-child(1) { top: 0; } 270 .nav-toggle .bars i:nth-child(2) { top: 5px; } 271 .nav-toggle .bars i:nth-child(3) { top: 10px; } 272 .nav-open .nav-toggle { background: var(--bg-soft); } 273 .nav-open .nav-toggle .bars i:nth-child(1) { transform: translateY(5px) rotate(45deg); } 274 .nav-open .nav-toggle .bars i:nth-child(2) { opacity: 0; transform: scaleX(0.3); } 275 .nav-open .nav-toggle .bars i:nth-child(3) { transform: translateY(-5px) rotate(-45deg); } 276 277 @media (max-width: 1104px) { 278 .site-header .bar { gap: 12px; } 279 .nav-toggle { display: inline-flex; } 280 .nav-panel { 281 display: block; 282 position: absolute; 283 top: 100%; 284 left: 0; 285 right: 0; 286 background: #fff; 287 border-bottom: 1px solid var(--line); 288 box-shadow: 0 26px 46px rgba(29, 29, 31, 0.12); 289 overflow: hidden; 290 max-height: 0; 291 opacity: 0; 292 visibility: hidden; 293 transition: max-height 0.36s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.22s ease, visibility 0s linear 0.36s; 294 } 295 .nav-open .nav-panel { 296 max-height: calc(100dvh - 60px); 297 opacity: 1; 298 visibility: visible; 299 overflow-y: auto; 300 transition: max-height 0.42s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.22s ease, visibility 0s; 301 } 302 .site-nav { flex-direction: column; align-items: stretch; gap: 2px; padding: 12px 24px 14px; } 303 .site-nav a { 304 padding: 13px 14px; 305 font-size: 1rem; 306 border-radius: 13px; 307 opacity: 0; 308 transform: translateY(-7px); 309 transition: opacity 0.3s ease, transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), 310 background-color 0.15s ease, color 0.15s ease; 311 } 312 .site-nav a[aria-current="page"] { background: var(--brand-soft); color: var(--brand-ink); font-weight: 600; } 313 .nav-open .site-nav a { opacity: 1; transform: none; } 314 .nav-open .site-nav a:nth-child(1) { transition-delay: 0.04s; } 315 .nav-open .site-nav a:nth-child(2) { transition-delay: 0.08s; } 316 .nav-open .site-nav a:nth-child(3) { transition-delay: 0.12s; } 317 .nav-open .site-nav a:nth-child(4) { transition-delay: 0.16s; } 318 .nav-open .site-nav a:nth-child(5) { transition-delay: 0.2s; } 319 .nav-open .site-nav a:nth-child(6) { transition-delay: 0.24s; } 320 .header-cta { 321 flex-wrap: wrap; 322 gap: 10px; 323 padding: 14px 24px 20px; 324 border-top: 1px solid var(--line); 325 opacity: 0; 326 transform: translateY(-7px); 327 transition: opacity 0.3s ease 0.2s, transform 0.3s cubic-bezier(0.4, 0, 0.2, 1) 0.2s; 328 } 329 .nav-open .header-cta { opacity: 1; transform: none; } 330 .header-cta .btn { flex: 1 1 140px; justify-content: center; } 331 .lang-switch { flex: 0 0 auto; } 332 } 333 @media (prefers-reduced-motion: reduce) { 334 .nav-panel, .nav-toggle .bars i, .site-nav a, .header-cta { 335 transition-duration: 0.01ms !important; 336 transition-delay: 0s !important; 337 } 338 } 339 340 /* ---------- Hero ---------- */ 341 .hero { padding: 84px 0 40px; text-align: center; position: relative; overflow: hidden; } 342 .hero::before { 343 content: ""; 344 position: absolute; 345 inset: -40% -20% auto -20%; 346 height: 90%; 347 background: 348 radial-gradient(closest-side at 30% 40%, rgba(16, 185, 129, 0.10), transparent 70%), 349 radial-gradient(closest-side at 72% 30%, rgba(2, 132, 199, 0.09), transparent 70%); 350 pointer-events: none; 351 } 352 .hero > .wrap { position: relative; } 353 .hero-badge { 354 display: inline-flex; 355 align-items: center; 356 gap: 8px; 357 border: 1px solid rgba(5, 150, 105, 0.28); 358 background: var(--brand-soft); 359 color: var(--brand-ink); 360 border-radius: 999px; 361 padding: 7px 15px; 362 font-size: 0.82rem; 363 font-weight: 600; 364 margin-bottom: 26px; 365 } 366 .hero-badge .dot { 367 width: 7px; height: 7px; border-radius: 999px; background: #10b981; 368 box-shadow: 0 0 0 4px rgba(16, 185, 129, 0.18); 369 } 370 .hero .lead { margin: 22px auto 0; } 371 .hero-ctas { 372 display: flex; 373 flex-wrap: wrap; 374 justify-content: center; 375 gap: 12px; 376 margin-top: 32px; 377 } 378 .hero-note { margin-top: 16px; font-size: 0.83rem; color: var(--ink-3); } 379 .hero-note a { color: inherit; } 380 381 /* ---------- Before/after compare slider ---------- */ 382 .cmp-shell { margin: 56px auto 0; max-width: 880px; text-align: left; } 383 .cmp { 384 --pos: 55%; 385 position: relative; 386 border-radius: var(--radius); 387 border: 1px solid var(--line); 388 background: #fff; 389 box-shadow: var(--shadow-card); 390 overflow: hidden; 391 touch-action: pan-y; 392 user-select: none; 393 -webkit-user-select: none; 394 } 395 .cmp-doc { padding: 40px 28px 30px; font-size: 0.95rem; line-height: 1.75; color: #3a3a3f; } 396 .cmp-doc-head { 397 display: flex; 398 align-items: center; 399 gap: 8px; 400 padding: 12px 18px; 401 border-bottom: 1px solid var(--line); 402 background: #fafafa; 403 font-size: 0.78rem; 404 color: var(--ink-3); 405 } 406 .cmp-doc-head .dots { display: inline-flex; gap: 5px; margin-right: 6px; } 407 .cmp-doc-head .dots i { width: 9px; height: 9px; border-radius: 999px; background: #e3e3e8; } 408 .cmp-doc p { margin: 0 0 12px; } 409 .cmp-doc p:last-child { margin-bottom: 0; } 410 .cmp-pane-after { background: #fff; } 411 .cmp-pane-before { 412 position: absolute; 413 inset: 0; 414 background: #fff; 415 clip-path: inset(0 calc(100% - var(--pos)) 0 0); 416 } 417 .pii { 418 background: rgba(244, 63, 94, 0.12); 419 color: #be123c; 420 border-radius: 5px; 421 padding: 0 4px; 422 font-weight: 600; 423 font-style: normal; 424 } 425 .tag { 426 background: rgba(16, 185, 129, 0.14); 427 color: var(--brand-ink); 428 border-radius: 5px; 429 padding: 0 4px; 430 font-weight: 600; 431 font-size: 0.85em; 432 letter-spacing: 0.01em; 433 } 434 .cmp-handle { 435 position: absolute; 436 top: 0; 437 bottom: 0; 438 left: var(--pos); 439 width: 0; 440 z-index: 3; 441 } 442 .cmp-handle::before { 443 content: ""; 444 position: absolute; 445 top: 0; 446 bottom: 0; 447 left: -1px; 448 width: 2px; 449 background: linear-gradient(180deg, #10b981, #0284c7); 450 } 451 .cmp-grip { 452 position: absolute; 453 top: 50%; 454 left: 0; 455 transform: translate(-50%, -50%); 456 width: 40px; 457 height: 40px; 458 border-radius: 999px; 459 background: #fff; 460 border: 1px solid var(--line); 461 box-shadow: 0 6px 20px rgba(0, 0, 0, 0.16); 462 display: flex; 463 align-items: center; 464 justify-content: center; 465 color: var(--ink-2); 466 cursor: ew-resize; 467 } 468 .cmp-grip:focus-visible { outline: 3px solid rgba(14, 165, 233, 0.55); outline-offset: 2px; } 469 .cmp-label { 470 position: absolute; 471 top: 54px; 472 z-index: 2; 473 border-radius: 999px; 474 padding: 5px 12px; 475 font-size: 0.72rem; 476 font-weight: 700; 477 letter-spacing: 0.08em; 478 text-transform: uppercase; 479 pointer-events: none; 480 }
481 .cmp-label-before { left: 16px; background: rgba(244, 63, 94, 0.1); color: #be123c; } 482 .cmp-label-after { right: 16px; background: rgba(16, 185, 129, 0.12); color: var(--brand-ink); } 483 .cmp-caption { 484 display: flex; 485 flex-wrap: wrap; 486 justify-content: space-between; 487 gap: 8px; 488 margin-top: 14px; 489 font-size: 0.82rem; 490 color: var(--ink-3); 491 } 492 @media (max-width: 640px) { 493 .cmp-doc { padding: 42px 16px 20px; font-size: 0.86rem; } 494 .cmp-label { top: 48px; } 495 } 496 497 /* ---------- Customer reference logos (hero strip) ---------- */ 498 .refs-band { --refh: 58px; max-width: 920px; margin: 30px auto 0; } 499 .refs-head { 500 margin: 0 0 14px; 501 font-size: 0.75rem; 502 font-weight: 600; 503 letter-spacing: 0.12em; 504 text-transform: uppercase; 505 color: var(--ink-3); 506 } 507 .refs { 508 /* The row height is reserved before the logos arrive, so filling the strip 509 never reflows the hero: that late jump is what used to read as a flicker. */ 510 height: var(--refh); 511 overflow: hidden; 512 -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent); 513 mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent); 514 } 515 .refs-track { 516 display: flex; 517 align-items: center; 518 height: 100%; 519 width: max-content; 520 margin: 0; 521 padding: 0; 522 list-style: none; 523 opacity: 0; 524 transition: opacity 0.45s ease; 525 will-change: transform; 526 } 527 /* --refs-dur is measured up front and never changed again: re-timing a running 528 animation is what made the loop stutter. */ 529 .refs.is-ready .refs-track { 530 opacity: 1; 531 animation: refs-scroll var(--refs-dur, 90s) linear infinite; 532 } 533 .refs-track li { flex: 0 0 auto; margin-right: 52px; display: flex; align-items: center; } 534 .refs-track li img { display: block; height: var(--refh); width: auto; opacity: 0.85; } 535 .ref-more { 536 white-space: nowrap; 537 font-size: 0.85rem; 538 font-weight: 600; 539 color: var(--ink-3); 540 border: 1px dashed #c7c7cf; 541 border-radius: 999px; 542 padding: 8px 16px; 543 } 544 @keyframes refs-scroll { from { transform: translate3d(0, 0, 0); } to { transform: translate3d(-50%, 0, 0); } } 545 @media (max-width: 640px) { 546 .refs-band { --refh: 44px; margin-top: 24px; } 547 .refs-track li { margin-right: 34px; } 548 } 549 @media (prefers-reduced-motion: reduce) { 550 .refs.is-ready .refs-track { animation: none; } 551 .refs { height: auto; overflow-x: auto; -webkit-mask-image: none; mask-image: none; } 552 } 553 554 /* ---------- Stats strip ---------- */ 555 .stats { 556 display: grid; 557 grid-template-columns: repeat(4, 1fr); 558 gap: 18px; 559 text-align: center; 560 } 561 .stats b { 562 display: block; 563 font-size: clamp(2rem, 4.2vw, 3rem); 564 font-weight: 800; 565 letter-spacing: -0.03em; 566 color: var(--ink); 567 } 568 .stats b span { display: inline; } 569 .stats > div > span { display: block; margin-top: 4px; font-size: 0.88rem; color: var(--ink-3); } 570 @media (max-width: 760px) { .stats { grid-template-columns: repeat(2, 1fr); gap: 28px 12px; } } 571 572 /* ---------- Cards ---------- */ 573 .card { 574 background: #fff; 575 border: 1px solid var(--line); 576 border-radius: var(--radius); 577 box-shadow: var(--shadow-card); 578 } 579 .card-soft { background: #fff; border: 1px solid var(--line); border-radius: var(--radius); } 580 .grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; } 581 .grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: 18px; } 582 @media (max-width: 900px) { .grid-3 { grid-template-columns: 1fr; } .grid-2 { grid-template-columns: 1fr; } } 583 584 .sec-head { max-width: 720px; margin-bottom: 44px; } 585 .sec-head.center { margin-left: auto; margin-right: auto; text-align: center; } 586 .sec-head p { margin: 16px 0 0; font-size: 1.05rem; color: var(--ink-2); } 587 588 /* ---------- Demo widget ---------- */ 589 .demo-card { padding: 26px 26px 30px; } 590 .demo-tabs { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; } 591 .demo-tabs + .demo-tabs { margin-top: 8px; } 592 .demo-tab-label { 593 font-size: 0.65rem; 594 font-weight: 700; 595 letter-spacing: 0.14em; 596 text-transform: uppercase; 597 color: var(--ink-3); 598 min-width: 5.4rem; 599 } 600 .demo-tab { 601 border: 1px solid #d9d9e0; 602 background: #fff; 603 color: var(--ink-2); 604 border-radius: 999px; 605 padding: 6px 14px; 606 font-size: 0.8rem; 607 font-weight: 600; 608 cursor: pointer; 609 font-family: inherit; 610 transition: border-color 0.15s ease, background-color 0.15s ease, color 0.15s ease; 611 } 612 .demo-tab:hover { border-color: rgba(5, 150, 105, 0.5); color: var(--brand-ink); } 613 .demo-tab.active { 614 border-color: rgba(5, 150, 105, 0.55); 615 background: var(--brand-soft); 616 color: var(--brand-ink); 617 box-shadow: 0 0 0 1px rgba(16, 185, 129, 0.2); 618 } 619 .demo-io { margin-top: 22px; display: flex; flex-direction: column; gap: 0; } 620 .demo-box { border: 1px solid var(--line); border-radius: 16px; padding: 16px 18px; background: #fafafa; } 621 .demo-box-label { 622 font-size: 0.68rem; 623 font-weight: 700; 624 letter-spacing: 0.13em; 625 text-transform: uppercase; 626 color: var(--ink-3); 627 margin-bottom: 8px; 628 } 629 .demo-box-out { background: rgba(16, 185, 129, 0.05); border-color: rgba(16, 185, 129, 0.3); } 630 .demo-box-out .demo-box-label { color: var(--brand-ink); } 631 .demo-box p { margin: 0; font-size: 0.93rem; line-height: 1.7; } 632 .demo-arrow { display: flex; align-items: center; justify-content: center; gap: 14px; padding: 12px 0; color: var(--ink-3); } 633 .demo-arrow img { height: 40px; width: 40px; border-radius: 10px; } 634 .demo-arrow .line { flex: 1; height: 1px; background: linear-gradient(90deg, transparent, #d9d9e0); } 635 .demo-arrow .line:last-child { background: linear-gradient(90deg, #d9d9e0, transparent); } 636 .demo-note { 637 margin: 18px 0 0; 638 font-size: 0.83rem; 639 line-height: 1.55; 640 color: var(--ink-3); 641 background: #fafafa; 642 border: 1px dashed #d9d9e0; 643 border-radius: 12px; 644 padding: 10px 14px; 645 } 646 .pii-src { background: rgba(244, 63, 94, 0.12); color: #be123c; border-radius: 5px; padding: 0 4px; font-weight: 600; font-style: normal; } 647 .pii-out { background: rgba(16, 185, 129, 0.14); color: var(--brand-ink); border-radius: 5px; padding: 0 4px; font-weight: 600; } 648 649 /* ---------- Entity chips ---------- */ 650 .entity-grid { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 28px; } 651 .entity-grid span { 652 font-family: ui-monospace, SFMono-Regular, Menlo, monospace; 653 font-size: 0.72rem; 654 color: var(--ink-2); 655 border: 1px solid var(--line); 656 background: #fff; 657 border-radius: 999px; 658 padding: 7px 13px; 659 } 660 661 /* ---------- Cloud workspace ---------- */ 662 .cloud-app { 663 border-radius: var(--radius); 664 border: 1px solid var(--line); 665 background: #fff; 666 box-shadow: var(--shadow-card); 667 overflow: hidden; 668 text-align: left; 669 } 670 .cloud-chrome {
671 display: flex; 672 align-items: center; 673 gap: 10px; 674 padding: 11px 16px; 675 border-bottom: 1px solid var(--line); 676 background: #fafafa; 677 } 678 .cloud-chrome .dots { display: inline-flex; gap: 6px; } 679 .cloud-chrome .dots i { width: 10px; height: 10px; border-radius: 999px; } 680 .cloud-chrome .dots i:nth-child(1) { background: #fca5a5; } 681 .cloud-chrome .dots i:nth-child(2) { background: #fcd34d; } 682 .cloud-chrome .dots i:nth-child(3) { background: #86efac; } 683 .cloud-url { 684 flex: 1; 685 max-width: 340px; 686 margin: 0 auto; 687 background: #fff; 688 border: 1px solid var(--line); 689 border-radius: 8px; 690 font-size: 0.75rem; 691 color: var(--ink-3); 692 padding: 5px 12px; 693 text-align: center; 694 white-space: nowrap; 695 overflow: hidden; 696 text-overflow: ellipsis; 697 } 698 .cloud-spacer { width: 42px; flex: 0 0 auto; } 699 .cloud-body { display: grid; grid-template-columns: 250px 1fr; min-height: 400px; } 700 .cloud-side { border-right: 1px solid var(--line); background: #fbfbfd; padding: 16px 12px; } 701 .cloud-side-label { 702 font-size: 0.64rem; 703 font-weight: 700; 704 letter-spacing: 0.13em; 705 text-transform: uppercase; 706 color: var(--ink-3); 707 margin: 4px 8px 10px; 708 } 709 .model-btn { 710 display: flex; 711 align-items: center; 712 gap: 10px; 713 width: 100%; 714 border: 1px solid transparent; 715 background: transparent; 716 border-radius: 12px; 717 padding: 9px 10px; 718 cursor: pointer; 719 text-align: left; 720 font-family: inherit; 721 transition: background-color 0.15s ease, border-color 0.15s ease; 722 } 723 .model-btn:hover { background: rgba(0, 0, 0, 0.04); } 724 .model-btn.active { background: #fff; border-color: var(--line); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); } 725 .model-btn b { display: block; font-size: 0.82rem; color: var(--ink); font-weight: 600; line-height: 1.2; } 726 .model-btn span { display: block; font-size: 0.68rem; color: var(--ink-3); } 727 /* the icon tile and the tick have to out-specify ".model-btn span" above */ 728 .model-btn .model-dot { 729 width: 26px; 730 height: 26px; 731 border-radius: 8px; 732 flex: 0 0 auto; 733 display: flex; 734 align-items: center; 735 justify-content: center; 736 color: #fff; 737 } 738 .model-dot svg { width: 16px; height: 16px; display: block; } 739 .model-dot-claude { background: #d97757; } 740 .model-dot-gpt { background: #10a37f; } 741 .model-dot-deepseek { background: #4d6bfe; } 742 .model-btn .model-check { margin-left: auto; color: var(--brand); font-weight: 700; visibility: hidden; } 743 .model-btn.active .model-check { visibility: visible; } 744 .cloud-side-note { 745 margin: 14px 8px 4px; 746 font-size: 0.7rem; 747 line-height: 1.5; 748 color: var(--ink-3); 749 border-top: 1px solid var(--line); 750 padding-top: 12px; 751 } 752 .cloud-main { padding: 20px 22px; display: flex; flex-direction: column; gap: 14px; } 753 .chat-msg { max-width: 92%; } 754 .chat-user { align-self: flex-end; } 755 .chat-user .bubble { 756 background: #f0f9f6; 757 border: 1px solid rgba(16, 185, 129, 0.25); 758 border-radius: 16px 16px 4px 16px; 759 padding: 12px 15px; 760 font-size: 0.86rem; 761 line-height: 1.6; 762 } 763 .chat-ai .bubble { 764 background: #fafafa; 765 border: 1px solid var(--line); 766 border-radius: 16px 16px 16px 4px; 767 padding: 12px 15px; 768 font-size: 0.86rem; 769 line-height: 1.6; 770 } 771 .chat-meta { display: flex; align-items: center; gap: 7px; font-size: 0.7rem; color: var(--ink-3); margin-bottom: 5px; } 772 .chat-user .chat-meta { justify-content: flex-end; } 773 .tag-real { 774 background: rgba(2, 132, 199, 0.12); 775 color: #0b4a6f; 776 border-radius: 5px; 777 padding: 0 4px; 778 font-weight: 600; 779 font-size: 0.85em; 780 letter-spacing: 0.01em; 781 } 782 /* The answer comes back with placeholders, which is all the model ever saw. 783 Mapping them back to the real values happens afterwards, on the device. 784 Both versions are stacked in one grid cell so the swap never reflows. */ 785 .answer-swap { position: relative; display: grid; } 786 .answer-swap .ans { grid-area: 1 / 1; } 787 /* The placeholders dissolve first and the real values materialise after them, 788 so the two versions never overlap as double-struck text. */ 789 .answer-swap .ans-anon { transition: opacity 0.3s ease, filter 0.3s ease; } 790 .answer-swap .ans-real { opacity: 0; transition: opacity 0.34s ease 0.24s; } 791 .answer-swap.is-refilled .ans-anon { opacity: 0; filter: blur(4px); } 792 .answer-swap.is-refilled .ans-real { opacity: 1; } 793 .answer-swap .ans-real .tag-real { 794 opacity: 0; 795 filter: blur(5px); 796 transform: translateY(2px); 797 transition: opacity 0.4s ease, filter 0.4s ease, transform 0.4s ease; 798 } 799 .answer-swap.is-refilled .ans-real .tag-real { opacity: 1; filter: none; transform: none; } 800 .answer-swap.is-refilled .ans-real .tag-real:nth-of-type(1) { transition-delay: 0.3s; } 801 .answer-swap.is-refilled .ans-real .tag-real:nth-of-type(2) { transition-delay: 0.44s; } 802 .answer-swap.is-refilled .ans-real .tag-real:nth-of-type(3) { transition-delay: 0.58s; } 803 .magic-sweep { 804 /* Absolutely placed in a grid container, so it is laid out against the 805 bubble's padding box; -1px takes it out over the border. */ 806 position: absolute; 807 inset: -1px; 808 border-radius: inherit; 809 pointer-events: none; 810 opacity: 0; 811 background: linear-gradient(100deg, transparent 34%, rgba(16, 185, 129, 0.22) 48%, 812 rgba(2, 132, 199, 0.20) 57%, transparent 72%); 813 background-size: 260% 100%; 814 background-position: 130% 0; 815 } 816 .answer-swap.is-refilling .magic-sweep { animation: magic-sweep 1.05s cubic-bezier(0.4, 0, 0.2, 1) forwards; }
817 @keyframes magic-sweep { 818 0% { opacity: 0; background-position: 130% 0; } 819 18% { opacity: 1; } 820 82% { opacity: 1; } 821 100% { opacity: 0; background-position: -30% 0; } 822 } 823 .pipe-note-back { 824 opacity: 0; 825 transform: translateY(-5px) scale(0.96); 826 transition: opacity 0.35s ease, transform 0.35s cubic-bezier(0.4, 0, 0.2, 1); 827 } 828 .pipe-note-back.is-shown { opacity: 1; transform: none; } 829 @media (prefers-reduced-motion: reduce) { 830 .answer-swap .ans-anon, .answer-swap .ans-real, .answer-swap .ans-real .tag-real, .pipe-note-back { 831 transition-duration: 0.01ms !important; 832 transition-delay: 0s !important; 833 } 834 .answer-swap.is-refilling .magic-sweep { animation: none; } 835 } 836 .pipe-note[hidden] { display: none; } 837 .pipe-note { 838 display: flex; 839 align-items: center; 840 gap: 8px; 841 align-self: center; 842 font-size: 0.72rem; 843 font-weight: 600; 844 color: var(--brand-ink); 845 background: var(--brand-soft); 846 border: 1px solid rgba(5, 150, 105, 0.25); 847 border-radius: 999px; 848 padding: 5px 14px; 849 } 850 .pipe-note-back { 851 color: #0b4a6f; 852 background: rgba(2, 132, 199, 0.09); 853 border-color: rgba(2, 132, 199, 0.28); 854 } 855 .cloud-input { 856 margin-top: auto; 857 display: flex; 858 align-items: center; 859 gap: 10px; 860 border: 1px solid var(--line); 861 border-radius: 999px; 862 padding: 9px 10px 9px 18px; 863 color: var(--ink-3); 864 font-size: 0.85rem; 865 background: #fff; 866 } 867 .cloud-input .send { 868 margin-left: auto; 869 width: 30px; 870 height: 30px; 871 border-radius: 999px; 872 background: linear-gradient(120deg, #10b981, #059669); 873 color: #fff; 874 display: flex; 875 align-items: center; 876 justify-content: center; 877 font-size: 0.85rem; 878 } 879 @media (max-width: 820px) { 880 .cloud-body { grid-template-columns: 1fr; } 881 .cloud-side { border-right: 0; border-bottom: 1px solid var(--line); display: flex; gap: 6px; overflow-x: auto; padding: 10px; } 882 .cloud-side-label, .cloud-side-note { display: none; } 883 .model-btn { width: auto; flex: 0 0 auto; } 884 .model-btn span span { display: none; } 885 .model-check { display: none; } 886 } 887 888 /* ---------- Product cards ---------- */ 889 .prod-card { padding: 26px 24px; display: flex; flex-direction: column; } 890 .prod-kicker { font-size: 0.72rem; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; margin-bottom: 8px; } 891 .prod-card h3 { font-size: 1.25rem; letter-spacing: -0.02em; margin-bottom: 4px; } 892 .prod-card .plat { font-size: 0.76rem; color: var(--ink-3); margin-bottom: 14px; } 893 .feat-list { list-style: none; margin: 0 0 20px; padding: 0; display: flex; flex-direction: column; gap: 7px; } 894 .feat-list li { position: relative; padding-left: 22px; font-size: 0.86rem; color: var(--ink-2); line-height: 1.5; } 895 .feat-list li::before { content: "â"; position: absolute; left: 0; top: 0; color: var(--brand); font-weight: 700; } 896 .prod-actions { margin-top: auto; display: flex; flex-direction: column; gap: 8px; } 897 898 /* ---------- Screenshots ---------- */ 899 .shots { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-top: 40px; } 900 @media (max-width: 760px) { .shots { grid-template-columns: 1fr; } } 901 .shots figure { margin: 0; } 902 .shots button { 903 display: block; 904 width: 100%; 905 padding: 0; 906 border: 1px solid var(--line); 907 border-radius: 16px; 908 overflow: hidden; 909 cursor: pointer; 910 background: #fff; 911 aspect-ratio: 3 / 2; 912 transition: border-color 0.2s ease, box-shadow 0.2s ease; 913 } 914 .shots button:hover { border-color: rgba(5, 150, 105, 0.5); box-shadow: 0 12px 30px rgba(0, 0, 0, 0.1); } 915 .shots img { width: 100%; height: 100%; object-fit: cover; object-position: top; display: block; } 916 .shots figcaption { margin-top: 8px; font-size: 0.78rem; color: var(--ink-3); } 917 918 /* ---------- Use cases ---------- */ 919 .uc-card { padding: 22px 22px 24px; } 920 .uc-card .ico { font-size: 1.4rem; margin-bottom: 10px; display: block; } 921 .uc-card h3 { font-size: 1.02rem; margin-bottom: 6px; letter-spacing: -0.01em; } 922 .uc-card p { margin: 0; font-size: 0.88rem; color: var(--ink-2); line-height: 1.55; } 923 924 /* ---------- Evidence ---------- */ 925 .ev-label { margin: 0; font-size: 0.8rem; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-3); } 926 /* All logos come from the shared jocapps set, which is already greyscale and 927 optically centred on a common canvas, so one height fits all four. */ 928 .ev-logos { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 30px; margin: 16px 0 0; } 929 .ev-logos img { height: 62px; width: auto; filter: grayscale(1); opacity: 0.8; } 930 .ev-papers { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 24px; } 931 .ev-papers a { 932 font-size: 0.8rem; 933 color: var(--ink-2); 934 text-decoration: none; 935 border: 1px solid var(--line); 936 background: #fff; 937 border-radius: 999px; 938 padding: 7px 14px; 939 transition: border-color 0.15s ease, color 0.15s ease; 940 } 941 .ev-papers a:hover { border-color: rgba(5, 150, 105, 0.5); color: var(--brand-ink); } 942 .ev-figure { 943 display: block; 944 margin: 42px 0 0; 945 overflow: hidden; 946 border-radius: 18px; 947 border: 1px solid var(--line); 948 background: #fff; 949 text-decoration: none; 950 transition: border-color 0.15s ease, box-shadow 0.25s ease; 951 } 952 .ev-figure:hover { border-color: rgba(5, 150, 105, 0.45); box-shadow: var(--shadow-card); } 953 .ev-figure img { display: block; width: 100%; height: auto; padding: 18px 20px 6px; box-sizing: border-box; } 954 .ev-figure figcaption { padding: 8px 20px 16px; font-size: 0.8rem; line-height: 1.6; color: var(--ink-3); text-align: center; } 955 .ev-credit { max-width: 58em; margin: 34px 0 0; line-height: 1.75; } 956 .ev-credit + .ev-credit { margin-top: 10px; } 957 @media (max-width: 640px) { 958 .ev-logos { gap: 8px 22px; } 959 .ev-logos img { height: 48px; } 960 .ev-figure img { padding: 10px 10px 4px; } 961 } 962 963 /* ---------- Compare table (Free vs Pro) ---------- */ 964 .cmp-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; } 965 .cmp-table { display: grid; grid-template-columns: minmax(11rem, 1.35fr) minmax(9rem, 1fr) minmax(11rem, 1.2fr); min-width: 36rem; border: 1px solid var(--line); border-radius: 16px; overflow: hidden; background: #fff; font-size: 0.8rem; } 966 .cmp-cell { padding: 9px 14px;
966 border-top: 1px solid #f0f0f4; color: var(--ink-2); display: flex; align-items: center; line-height: 1.45; } 967 .cmp-head { border-top: none; background: #fafafa; font-weight: 700; color: var(--ink); font-size: 0.76rem; } 968 .cmp-head-pro { background: rgba(16, 185, 129, 0.1); color: var(--brand-ink); } 969 .cmp-col-pro { background: rgba(16, 185, 129, 0.04); } 970 .cmp-feature { font-weight: 600; color: var(--ink); } 971 .cmp-yes { color: var(--brand-ink); font-weight: 700; } 972 .cmp-no { color: #86868b; } 973 .cmp-details { border: 1px solid var(--line); border-radius: 16px; background: #fff; } 974 .cmp-details > summary { cursor: pointer; padding: 15px 20px; font-size: 0.9rem; font-weight: 600; color: var(--ink-2); list-style: none; display: flex; align-items: center; gap: 8px; } 975 .cmp-details > summary::-webkit-details-marker { display: none; } 976 .cmp-details > summary::before { content: "â¸"; color: #b0b0b8; transition: transform 0.15s ease; } 977 .cmp-details[open] > summary::before { transform: rotate(90deg); } 978 .cmp-details > summary:hover { color: var(--brand-ink); } 979 .cmp-details-body { padding: 0 20px 20px; } 980 981 /* ---------- FAQ ---------- */ 982 .faq-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; } 983 @media (max-width: 760px) { .faq-grid { grid-template-columns: 1fr; } } 984 .faq-grid details { border: 1px solid var(--line); border-radius: 16px; background: #fff; padding: 16px 20px; } 985 .faq-grid summary { cursor: pointer; font-weight: 600; color: var(--ink); font-size: 0.95rem; list-style: none; } 986 .faq-grid summary::-webkit-details-marker { display: none; } 987 .faq-grid details p { margin: 10px 0 0; font-size: 0.88rem; color: var(--ink-2); } 988 989 /* ---------- CTA band ---------- */ 990 .cta-band { text-align: center; padding: 96px 0; } 991 .cta-band .hero-ctas { margin-top: 30px; } 992 993 /* ---------- Sign in ---------- */ 994 .signin-grid { display: grid; grid-template-columns: minmax(0, 400px) minmax(0, 1fr); gap: 60px; align-items: start; } 995 .signin-card { 996 background: #fff; 997 border: 1px solid var(--line); 998 border-radius: var(--radius); 999 box-shadow: var(--shadow-card); 1000 padding: 30px 28px 26px; 1001 } 1002 .signin-card h1 { font-size: 1.5rem; letter-spacing: -0.02em; } 1003 .signin-card > p.small { color: var(--ink-3); margin: 8px 0 22px; } 1004 .field { display: block; margin-bottom: 15px; } 1005 .field > span { display: block; font-size: 0.78rem; font-weight: 600; color: var(--ink-2); margin-bottom: 6px; } 1006 .field input { 1007 width: 100%; 1008 box-sizing: border-box; 1009 font: inherit; 1010 font-size: 0.95rem; 1011 color: var(--ink); 1012 background: #fff; 1013 border: 1px solid var(--line); 1014 border-radius: 12px; 1015 padding: 11px 14px; 1016 transition: border-color 0.15s ease, box-shadow 0.15s ease; 1017 } 1018 .field input::placeholder { color: #757580; } /* 4.6:1 on white, readable but still clearly a hint */ 1019 .field input:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-soft); } 1020 .signin-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 2px 0 18px; } 1021 .signin-row label { display: inline-flex; align-items: center; gap: 7px; font-size: 0.8rem; color: var(--ink-2); } 1022 .signin-row a { font-size: 0.8rem; color: var(--brand-ink); } 1023 .signin-card .btn { width: 100%; } 1024 .signin-error { 1025 display: none; 1026 align-items: flex-start; 1027 gap: 9px; 1028 margin-bottom: 16px; 1029 padding: 11px 13px; 1030 border-radius: 12px; 1031 font-size: 0.84rem; 1032 line-height: 1.45; 1033 color: #9f1239; 1034 background: rgba(244, 63, 94, 0.08); 1035 border: 1px solid rgba(244, 63, 94, 0.3); 1036 } 1037 .signin-error.is-shown { display: flex; } 1038 .signin-error b { color: #881337; } 1039 .signin-alt { 1040 margin: 22px 0 0; 1041 padding-top: 18px; 1042 border-top: 1px solid var(--line); 1043 font-size: 0.85rem; 1044 color: var(--ink-3); 1045 text-align: center; 1046 } 1047 .signin-alt a { color: var(--brand-ink); font-weight: 600; } 1048 .signin-points { list-style: none; margin: 26px 0 0; padding: 0; display: flex; flex-direction: column; gap: 16px; } 1049 .signin-points li { position: relative; padding-left: 30px; font-size: 0.92rem; color: var(--ink-2); line-height: 1.55; } 1050 .signin-points li::before { 1051 content: "â"; 1052 position: absolute; 1053 left: 0; 1054 top: -1px;
1055 width: 20px; 1056 height: 20px; 1057 border-radius: 999px; 1058 background: var(--brand-soft); 1059 color: var(--brand-ink); 1060 font-size: 0.72rem; 1061 font-weight: 800; 1062 display: flex; 1063 align-items: center; 1064 justify-content: center; 1065 } 1066 .signin-points b { color: var(--ink); font-weight: 600; } 1067 @media (max-width: 900px) { 1068 .signin-grid { grid-template-columns: 1fr; gap: 34px; } 1069 } 1070 1071 /* ---------- Footer ---------- */ 1072 .site-footer { border-top: 1px solid var(--line); background: var(--bg-soft); padding: 48px 0 40px; font-size: 0.83rem; } 1073 .footer-grid { display: grid; grid-template-columns: 1.4fr 1fr; gap: 32px; } 1074 @media (max-width: 760px) { .footer-grid { grid-template-columns: 1fr; } } 1075 .footer-links { display: flex; flex-wrap: wrap; gap: 8px; align-content: flex-start; } 1076 .footer-links a, .footer-links button { 1077 font-family: inherit; 1078 font-size: 0.8rem; 1079 color: var(--ink-2); 1080 background: #fff; 1081 border: 1px solid var(--line); 1082 border-radius: 999px; 1083 padding: 7px 14px; 1084 text-decoration: none; 1085 cursor: pointer; 1086 transition: border-color 0.15s ease, color 0.15s ease; 1087 } 1088 .footer-links a:hover, .footer-links button:hover { border-color: rgba(5, 150, 105, 0.5); color: var(--brand-ink); } 1089 .site-footer .fine { color: var(--ink-3); line-height: 1.6; } 1090 .site-footer .fine a { color: inherit; } 1091 .footer-about { 1092 padding: 24px; 1093 border: 1px solid var(--line); 1094 border-radius: 20px; 1095 background: rgba(255, 255, 255, 0.72); 1096 box-shadow: 0 14px 38px rgba(15, 23, 42, 0.06); 1097 } 1098 .footer-about .brand { width: fit-content; } 1099 .footer-about .fine + .fine { padding-top: 10px; border-top: 1px solid var(--line); } 1100 @media (max-width: 760px) { .footer-about { padding: 20px; } } 1101 1102 /* ---------- Reveal on scroll ---------- */ 1103 .rv { opacity: 0; transform: translateY(22px); transition: opacity 0.7s cubic-bezier(0.22, 1, 0.36, 1), transform 0.7s cubic-bezier(0.22, 1, 0.36, 1); } 1104 .rv.in { opacity: 1; transform: none; } 1105 @media (prefers-reduced-motion: reduce) { 1106 .rv { opacity: 1 !important; transform: none !important; transition: none !important; } 1107 html { scroll-behavior: auto; } 1108 } 1109 1110 /* ---------- Accessibility & modal plumbing ---------- */ 1111 :where(a, button, input, select, textarea, iframe, summary):focus-visible { 1112 outline: 3px solid rgba(14, 165, 233, 0.55); 1113 outline-offset: 3px; 1114 } 1115 .skip-link { 1116 position: fixed; 1117 top: 0.75rem; 1118 left: 0.75rem; 1119 z-index: 100; 1120 transform: translateY(-160%); 1121 border-radius: 999px; 1122 background: #0f172a; 1123 color: #ffffff; 1124 padding: 0.65rem 1rem; 1125 font-size: 0.875rem; 1126 font-weight: 700; 1127 box-shadow: 0 10px 30px rgba(15, 23, 42, 0.2); 1128 transition: transform 0.2s ease; 1129 } 1130 .skip-link:focus { transform: translateY(0); } 1131 .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; } 1132 main section[id], main div[id] { scroll-margin-top: 5rem; } 1133 button, a { -webkit-tap-highlight-color: transparent; } 1134 button { touch-action: manipulation; } 1135 .modal-panel { overscroll-behavior: contain; } 1136 .shot-lightbox-panel { position: relative; width: min(760px, calc(100vw - 2rem)); max-height: min(70vh, 680px); } 1137 .shot-lightbox-image { width: 100%; max-height: min(70vh, 680px); object-fit: contain; } 1138 .shot-lightbox-close { position: absolute; top: -1rem; right: -1rem; z-index: 10; width: 2.75rem; height: 2.75rem; } 1139 @media (max-width: 767px) { 1140 .shot-lightbox-panel { max-height: 64vh; } 1141 .shot-lightbox-image { max-height: 64vh; } 1142 .shot-lightbox-close { top: -0.75rem; right: -0.5rem; } 1143 } 1144 1145 /* Light theme for the dialogs (markup uses dark slate utility classes) */ 1146 .twp-glass-soft { 1147 background: #ffffff; 1148 border-radius: 22px; 1149 border: 1px solid var(--line); 1150 box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04), 0 24px 60px rgba(15, 23, 42, 0.18); 1151 } 1152 [role="dialog"] .bg-slate-950, [role="dialog"].bg-slate-950, 1153 [role="dialog"] .bg-slate-900 { background-color: #ffffff !important; } 1154 [role="dialog"] .text-white, 1155 [role="dialog"] .text-slate-50, 1156 [role="dialog"] .text-slate-100 { color: #0f172a !important; } 1157 [role="dialog"] .text-slate-200 { color: #334155 !important; } 1158 [role="dialog"] .text-slate-300 { color: #475569 !important; } 1159 [role="dialog"] .text-slate-400 { color: #64748b !important; } 1160 [role="dialog"] .text-emerald-300, 1161 [role="dialog"] .text-emerald-400 { color: #059669 !important; } 1162 [role="dialog"] .text-emerald-200 { color: #047857 !important; } 1163 [role="dialog"] .hover\:text-emerald-100:hover, 1164 [role="dialog"] .hover\:text-emerald-200:hover { color: #047857 !important; } 1165 [role="dialog"] .text-amber-200, 1166 [role="dialog"] .text-amber-300 { color: #b45309 !important; } 1167 [role="dialog"] .border-slate-800, 1168 [role="dialog"] .border-slate-700, 1169 [role="dialog"] .border-slate-600 { border-color: var(--line) !important; } 1170 [role="dialog"] .hover\:bg-slate-800:hover { background-color: #f1f5f9 !important; } 1171 [role="dialog"] input, [role="dialog"] select { 1172 background-color: #ffffff !important; 1173 color: #0f172a !important; 1174 border-color: #d2d2d7 !important; 1175 } 1176 [role="dialog"] .bg-emerald-400 { background-color: #059669 !important; color: #ffffff !important; } 1177 [role="dialog"] .hover\:bg-emerald-300:hover { background-color: #047857 !important; } 1178 [role="dialog"] .text-slate-950 { color: #ffffff !important; } 1179 /* Keep the screenshot lightbox itself dark for contrast */ 1180 #shot-lightbox .bg-slate-950 { background-color: #0f172a !important; } 1181 #shot-lightbox .text-slate-100 { color: #f8fafc !important; } 1182 </style> 1183 <noscript><style>.rv { opacity: 1 !important; transform: none !important; }</style></noscript> 1184</head> 1185 1186 1187<body class="antialiased">
1188 <a href="#main-content" class="skip-link">Skip to main content</a> 1189 1190 <!-- Header --> 1191 <header id="top" class="site-header"> 1192 <div class="wrap bar"> 1193 <a href="/" aria-label="Textwash⢠Pro home" class="brand"> 1194 <img src="/logo.svg" alt="Textwash⢠Pro logo" width="30" height="30" decoding="async" /> 1195 <b>Textwash⢠Pro</b> 1196 </a> 1197 1198 <button type="button" class="nav-toggle" id="nav-toggle" aria-expanded="false" 1199 aria-controls="nav-panel" aria-label="Open menu" 1200 data-label-open="Open menu" data-label-close="Close menu"> 1201 <span class="bars" aria-hidden="true"><i></i><i></i><i></i></span> 1202 </button> 1203 1204 <div class="nav-panel" id="nav-panel"> 1205 <nav aria-label="Primary navigation" class="site-nav"> 1206 <a href="/#products">Product</a> 1207 <a href="/cloud/" aria-current="page">Cloud</a> 1208 <a href="/#usecases">Use cases</a> 1209 <a href="/#research">Evidence</a> 1210 <a href="/partners/">Partners</a> 1211 <a href="/#faq">FAQ</a> 1212 </nav> 1213 1214 <div class="header-cta"> 1215 <div class="lang-switch" role="group" aria-label="Language switcher"> 1216 <span class="active" aria-current="true" title="English"><span class="sr-only">English (current language)</span><span aria-hidden="true">ð¬ð§</span></span> 1217 <a href="/de/cloud/" lang="de" hreflang="de" aria-label="Zur deutschen Version wechseln" title="Deutsch">ð©ðª</a> 1218 </div> 1219 <a href="/" class="btn btn-ghost btn-sm">Back to homepage</a> 1220 </div> 1221 </div> 1222 </div> 1223 </header> 1224 1225 <main id="main-content"> 1226 <section class="sec"> 1227 <div class="wrap"> 1228 <div class="signin-grid"> 1229 1230 <div class="signin-card rv"> 1231 <p class="eyebrow" style="margin-bottom:10px;">Textwash⢠Pro Cloud</p> 1232 <h1>Sign in.</h1> 1233 <p class="small">Your AI workspace, anonymised before anything leaves it.</p> 1234 1235 <p class="signin-error" id="signin-error" role="alert" aria-live="assertive"> 1236 <span aria-hidden="true">â ï¸</span> 1237 <span><b>Login incorrect.</b> The e-mail address or password does not match an active 1238 Textwash⢠Pro Cloud account. Please try again, or book a call to get access.</span> 1239 </p> 1240 1241 <form id="signin-form" novalidate> 1242 <label class="field"> 1243 <span>E-mail address</span> 1244 <input type="email" id="signin-email" name="email" autocomplete="username" 1245 placeholder="[email protected]" required /> 1246 </label> 1247 <label class="field"> 1248 <span>Password</span> 1249 <input type="password" id="signin-password" name="password" autocomplete="current-password" 1250 placeholder="â¢â¢â¢â¢â¢â¢â¢â¢" required /> 1251 </label> 1252 1253 <div class="signin-row"> 1254 <label><input type="checkbox" id="signin-remember" /> Keep me signed in</label> 1255 <a href="mailto:[email protected]?subject=Textwash%E2%84%A2%20Pro%20Cloud%20password%20reset">Forgot password?</a> 1256 </div> 1257 1258 <button type="submit" id="signin-submit" class="btn btn-primary">Sign in</button> 1259 </form> 1260 1261 <p class="signin-alt"> 1262 No account yet? 1263 <a href="https://calendar.jocapps.eu/textwashpro" target="_blank" rel="noopener noreferrer">Register and book a call â</a> 1264 </p> 1265 </div> 1266 1267 <div class="rv"> 1268 <h2 class="h-lg">Frontier AI on documents that could never go to the cloud.</h2> 1269 <p class="lead" style="margin-top:16px;"> 1270 A local AI removes personal data from every prompt on the way out, and can re-fill your 1271 real names into the answer on the way back, so the model itself never sees who anyone is. 1272 Anonymisation happens before any prompt leaves your workspace. 1273 </p> 1274 <ul class="signin-points"> 1275 <li><b>Claude, ChatGPT, DeepSeek & Google Gemini built in.</b> Pick the model per task; the anonymisation stays the same.</li> 1276 <li><b>Anonymised first, always.</b> Personal data is replaced before any prompt leaves your workspace.</li> 1277 <li><b>Re-fill with your data.</b> Placeholders are mapped back on your device, never in the cloud.</li> 1278 <li><b>A full AI workplace.</b> Summarise, translate, analyse, with team projects, dashboards and logs included.</li> 1279 </ul> 1280 <div class="hero-ctas" style="margin-top:30px;"> 1281 <a href="https://calendar.jocapps.eu/textwashpro" target="_blank" rel="noopener noreferrer" class="btn btn-primary">Book a call</a> 1282 <a href="/#cloud" class="btn btn-ghost">See how it works</a> 1283 </div> 1284 <p class="small muted" style="margin-top:18px;"> 1285 ISO 27001 & ISO 9001 certified development since 2014, Made in Germany 1286 </p> 1287 </div> 1288 1289 </div> 1290 </div> 1291 </section> 1292 </main> 1293 1294 <!-- Footer --> 1295 <footer class="site-footer"> 1296 <div class="wrap footer-grid"> 1297 <div class="footer-about"> 1298 <a href="/" aria-label="Textwash⢠Pro home" class="brand" style="margin-bottom:14px;"> 1299 <img src="/logo.svg" alt="Textwash⢠Pro logo" width="30" height="30" /> 1300 <b>Textwash⢠Pro</b> 1301 </a> 1302 <p class="fine" style="max-width:34em; margin:12px 0 0;"> 1303 Automated text anonymisation for research, business & public sector.<br /> 1304 © <a href="https://bkleinberg.net" target="_blank" rel="noopener noreferrer">Prof. Dr. Bennett Kleinberg</a> & 1305 <a href="https://www.jocapps.com" target="_blank" rel="noopener noreferrer">jocapps<sup>®</sup> GmbH</a>, 1306 ISO 27001 & ISO 9001 certified development since 2014, Made in Germany ðªðºð©ðª with lots of â¤ï¸ & âï¸ 1307 </p> 1308 <p class="fine" style="margin:8px 0 0;"> 1309 Textwash⢠is a registered trademark in the European Union (ID 019336966). 1310 </p> 1311 </div> 1312 <div class="footer-links"> 1313 <a href="/">Textwash⢠Pro Home</a> 1314 <a href="mailto:[email protected]">[email protected]</a> 1315 <a href="https://www.jocapps.com/legal_disclosure/" target="_blank" rel="noopener noreferrer">Legal Disclosure</a> 1316 <a href="https://www.jocapps.com/privacy/" target="_blank" rel="noopener noreferrer">Privacy Policy</a> 1317 </div> 1318 </div> 1319 </footer> 1320 1321
1321<script> 1322 // Sign-in is not wired to an identity provider on this page: the real workspace lives 1323 // behind the account we set up on the call, so every attempt here reports back as failed. 1324 (function () { 1325 var form = document.getElementById('signin-form'); 1326 var error = document.getElementById('signin-error'); 1327 var submit = document.getElementById('signin-submit'); 1328 if (!form || !error || !submit) return; 1329 var label = submit.textContent; 1330 form.addEventListener('submit', function (event) { 1331 event.preventDefault(); 1332 error.classList.remove('is-shown'); 1333 submit.disabled = true; 1334 submit.textContent = 'Signing inâ¦'; 1335 window.setTimeout(function () { 1336 submit.disabled = false; 1337 submit.textContent = label; 1338 error.classList.add('is-shown'); 1339 var password = document.getElementById('signin-password'); 1340 if (password) { password.value = ''; password.focus(); } 1341 }, 700); 1342 }); 1343 })(); 1344 </script>
1344 1345 1346
1346<script> 1347 // Reveal-on-scroll 1348 (function () { 1349 var els = document.querySelectorAll('.rv'); 1350 if (!('IntersectionObserver' in window) || (window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches)) { 1351 els.forEach(function (el) { el.classList.add('in'); }); 1352 return; 1353 } 1354 var io = new IntersectionObserver(function (entries) { 1355 entries.forEach(function (entry) { 1356 if (entry.isIntersecting) { entry.target.classList.add('in'); io.unobserve(entry.target); } 1357 }); 1358 }, { threshold: 0.08, rootMargin: '0px 0px -40px 0px' }); 1359 var vh = window.innerHeight || document.documentElement.clientHeight; 1360 var i = 0; 1361 els.forEach(function (el) { 1362 if (el.getBoundingClientRect().top > vh * 0.9) { 1363 el.style.transitionDelay = (Math.min(i % 3, 2) * 70) + 'ms'; 1364 i++; 1365 io.observe(el); 1366 } else { 1367 el.classList.add('in'); 1368 } 1369 }); 1370 })(); 1371 </script>
1371 1372 1373
1373<script> 1374 // Mobile menu: expand and collapse the header panel 1375 (function () { 1376 var header = document.querySelector('.site-header'); 1377 var toggle = document.getElementById('nav-toggle'); 1378 var panel = document.getElementById('nav-panel'); 1379 if (!header || !toggle || !panel) return; 1380 var mq = window.matchMedia('(max-width: 1104px)'); 1381 1382 function setOpen(open) { 1383 if (open === header.classList.contains('nav-open')) return; 1384 header.classList.toggle('nav-open', open); 1385 toggle.setAttribute('aria-expanded', open ? 'true' : 'false'); 1386 toggle.setAttribute('aria-label', toggle.getAttribute(open ? 'data-label-close' : 'data-label-open')); 1387 } 1388 1389 toggle.addEventListener('click', function () { 1390 setOpen(!header.classList.contains('nav-open')); 1391 }); 1392 // Any link or button inside the panel navigates, so collapse it again. 1393 panel.addEventListener('click', function (e) { 1394 if (e.target.closest('a, button')) setOpen(false); 1395 }); 1396 document.addEventListener('click', function (e) { 1397 if (!header.contains(e.target)) setOpen(false); 1398 }); 1399 document.addEventListener('keydown', function (e) { 1400 if (e.key === 'Escape' || e.key === 'Esc') { 1401 if (header.classList.contains('nav-open')) { setOpen(false); toggle.focus(); } 1402 } 1403 }); 1404 // Never leave the panel stuck open when the layout grows past the breakpoint. 1405 function onBreakpoint() { if (!mq.matches) setOpen(false); } 1406 if (mq.addEventListener) mq.addEventListener('change', onBreakpoint); 1407 else if (mq.addListener) mq.addListener(onBreakpoint); 1408 })(); 1409 </script>
vendor: 1 bytes, line 1409
1409
1410<script> 1411!(function(){if(window.chatnode && window.chatnode('getState') === 'initialized')return;window.chatnode=(...args)=>{if(!window.chatnode.q)window.chatnode.q=[];window.chatnode.q.push(args);};window.chatnode=new Proxy(window.chatnode,{get(target,prop){if(prop==='q')return target.q;return(...args)=>target(prop,...args);},});function onLoad(){const script=document.createElement('script');script.src='https://embed.chatnode.ai/f75faf3a-adaa-4ac1-9222-ae1939865792/popup.js';document.body.appendChild(script);}if(document.readyState==='complete'){onLoad();}else{window.addEventListener('load',onLoad);}})(); 1412</script>
1412 1413</body> 1414</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.