PageSourceSearch

https://app.lexlegis.ai/register/

html lexlegis.ai collected 2026-09-29 05:14:57 UTC 54,316 bytes, 1,522 lines download raw bytes

1<!doctype html>
2
3
4
5
6
7
8
9
10
11
12<html lang="en-us" data-speech-lang="en-US">
13<head>
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
24<script>window.dataLayer=window.dataLayer||[];
25  window.gtag=window.gtag||function(){window.dataLayer.push(arguments);};
26  gtag('consent','default',{
27  'ad_storage':'denied',
28  'ad_user_data':'denied',
29  'ad_personalization':'denied',
30  'analytics_storage':'denied',
31  'functionality_storage':'granted','security_storage':'granted','wait_for_update':500});</script>
31
32  <!-- Google Tag Manager -->
33  
33<script>
vendor: 335 bytes, lines 33-37
33(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
34  new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
35  j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
36  'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
37  })(window,document,'script','dataLayer','
37GTM-5H8ZTXWZ
vendor: 3 bytes, line 37
37');
37</script>
37
38  <!-- End Google Tag Manager -->
39  
40  
41  
41<script src="/static/js/gtm-consent.6795f39845fa.js" defer></script>
41
42  
43  
44  
45  
45<script src="/static/js/gtm-spa.e02fb714e6a0.js" defer></script>
45
46
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
58<script>(function(c,l,a,r,i,t,y){
59  c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
60  t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
61  y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
62  })(window,document,"clarity","script","y7dgl4ctew");
63  window.clarity('consentv2',{
64  ad_Storage:'denied',
65  analytics_Storage:'denied'});</script>
65
66  
66<script src="/static/js/clarity-consent.c3846f3c6590.js" defer></script>
66
67  <meta charset="utf-8">
68  <meta name="viewport" content="width=device-width,initial-scale=1">
69  <title>Create your account · Lexlegis</title>
70  <meta name="description" content="Lexlegis — a modern legal operating system for research, drafting and firm knowledge.">
71  <link rel="apple-touch-icon" sizes="57x57" href="/static/img/favicon/apple-icon-57x57.6d8158c2addb.png">
72  <link rel="apple-touch-icon" sizes="60x60" href="/static/img/favicon/apple-icon-60x60.874d8dcfc4b9.png">
73  <link rel="apple-touch-icon" sizes="72x72" href="/static/img/favicon/apple-icon-72x72.2079d44ae4db.png">
74  <link rel="apple-touch-icon" sizes="76x76" href="/static/img/favicon/apple-icon-76x76.e8599f589e1f.png">
75  <link rel="apple-touch-icon" sizes="114x114" href="/static/img/favicon/apple-icon-114x114.ec558de863fb.png">
76  <link rel="apple-touch-icon" sizes="120x120" href="/static/img/favicon/apple-icon-120x120.d9e9abe3a007.png">
77  <link rel="apple-touch-icon" sizes="144x144" href="/static/img/favicon/apple-icon-144x144.fc7eae34ac4b.png">
78  <link rel="apple-touch-icon" sizes="152x152" href="/static/img/favicon/apple-icon-152x152.051db5c310be.png">
79  <link rel="apple-touch-icon" sizes="180x180" href="/static/img/favicon/apple-icon-180x180.d7ba26897a56.png">
80  <link rel="icon" type="image/png" sizes="192x192" href="/static/img/favicon/android-icon-192x192.af1cbe70b852.png">
81  <link rel="icon" type="image/png" sizes="32x32" href="/static/img/favicon/favicon-32x32.3dd55b5c2402.png">
82  <link rel="icon" type="image/png" sizes="96x96" href="/static/img/favicon/favicon-96x96.c04af51ecdff.png">
83  <link rel="icon" type="image/png" sizes="16x16" href="/static/img/favicon/favicon-16x16.1f638be79134.png">
84  <link rel="shortcut icon" href="/static/img/favicon/favicon.433caeb4cbbd.ico">
85  <link rel="manifest" href="/static/img/favicon/manifest.2f20c51ac3db.json">
86  <meta name="msapplication-TileColor" content="#ffffff">
87  <meta name="msapplication-TileImage" content="/static/img/favicon/ms-icon-144x144.fc7eae34ac4b.png">
88  <meta name="theme-color" content="#ffffff">
89
90  
91  
92  
93  
94  
95  <meta name="htmx-config" content='{"globalViewTransitions": true, "historyCacheSize": 0}'>
96
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
106<script>
107    (function () {
108      var waiting = {};
109      // Run `cb(module)` as soon as window[name] exists — now, or the moment
110      // the module's script lands.
111      window.lexModule = function (name, cb) {
112        if (window[name]) { cb(window[name]); return; }
113        (waiting[name] = waiting[name] || []).push(cb);
114      };
115      // Called by the module itself instead of assigning window[name] directly.
116      window.lexModuleReady = function (name, mod) {
117        window[name] = mod;
118        var queue = waiting[name] || [];
119        waiting[name] = [];
120        queue.forEach(function (cb) { try { cb(mod); } catch (e) { console.error(e); } });
121      };
122    })();
123  </script>
123
124
125  
126  
127  <style>
128    .lex-progress {
129      position: fixed; top: 0; left: 0; height: 2px; width: 0;
130      background: linear-gradient(90deg, var(--brand, #3b3aa6), var(--brand-600, #2f2e90));
131      box-shadow: 0 0 8px var(--brand-100, rgba(59, 58, 166, .4));
132      z-index: 2147483646; opacity: 0; pointer-events: none;
133      transition: width .2s ease, opacity .2s ease;
134    }
135    .lex-progress.is-active { opacity: 1; }
136    .lex-progress.is-done { transition: width .15s ease, opacity .3s ease .12s; }
137    @media (prefers-reduced-motion: reduce) {
138      ::view-transition-group(*) { animation-duration: .001ms !important; }
139    }
140
141    /* Hanging environment pill (DEV / UAT / …) — top-centre, drops from the
142       very top edge. Hidden on production (server renders nothing). Driven by
143       the APP_ENVIRONMENT .env constant. Kept inline + in <head> so it paints
144       pre-script and survives hx-boost body swaps. */
145    .lex-env-pill {
146      position: fixed; top: 0; left: 50%; transform: translateX(-50%);
147      z-index: 2147483645; pointer-events: none;
148      padding: 3px 14px 4px; border-radius: 0 0 8px 8px;
149      font: 600 11px/1 "JetBrains Mono", ui-monospace, monospace;
150      letter-spacing: .12em; text-transform: uppercase; color: #fff;
151      background: linear-gradient(180deg, #d97706, #b45309);
152      box-shadow: 0 2px 8px rgba(0,0,0,.25);
153    }
154  </style>
155  
156  
156<script src="/static/js/zappy-nav.a26b676f3901.js" defer></script>
156
157  
158  
158<script src="/static/js/upload-progress.ae6a52940d6e.js" defer></script>
158
159
160  <link rel="preconnect" href="https://fonts.googleapis.com">
161  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
162  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Fraunces:opsz,[email protected],400;9..144,500;9..144,600&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
163
164  <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
165  <link href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css" rel="stylesheet">
166  
167  
168  
169  
170  
171  
172  
173  
173<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" defer></script>
173
174  <link href="/static/css/app.9add88fdfba5.css" rel="stylesheet">
175  
176  
177  <link href="/static/css/responsive.54c6270bff19.css" rel="stylesheet">
178  
179  
180  
181  
182  <link href="/static/css/library.d4ea5e51a3d5.css" rel="stylesheet">
183  <link href="/static/css/feedback.7ac75c83b311.css" rel="stylesheet">
184  <link href="/static/css/referrals.609010930fd5.css" rel="stylesheet">
185  <link href="/static/css/shortcuts.210e391d1940.css" rel="stylesheet">
186  <link href="/static/css/tour.2458602bf409.css" rel="stylesheet">
187  
188  <link href="/static/css/reg-monitor.672d4c9dd13a.css" rel="stylesheet">
189  <link href="/static/css/clm.826935c00dd2.css" rel="stylesheet">
190  <link href="/static/css/compliance.a5b4c0c72cbb.css" rel="stylesheet">
191  
192  <link href="/static/css/partners.f04aa2330cd3.css" rel="stylesheet">
193  
194</head>
195<body class="">
196  <!-- Google Tag Manager (noscript) -->
vendor: 70 bytes, lines 196-197
196
197  <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=
197GTM-5H8ZTXWZ
vendor: 87 bytes, lines 197-199
197"
198  height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
199  
199<!-- End Google Tag Manager (noscript) -->
200  
201  
202  
203  
204  
205  
206  
207  
208  
209  
210  
211  
212  
213  
214  
215  
216  
217  
218  
218<script>(function(){var t=localStorage.getItem("lex.theme")||"light",d=document.documentElement;
219    if(t==="dark"||t==="gray-dark"||(t==="system"&&matchMedia("(prefers-color-scheme: dark)").matches)){
220      d.setAttribute("data-theme","dark");
221    }
222    if(t==="gray-light"||t==="gray-dark"){ d.classList.add("lex-grayscale"); }
223  })();</script>
223
224
225  
226  
227  
228  
229  
230  
230<script>window.LEX_STREAM_WORDS_URL = "/static/data/stream_words.1c6050122742.json";</script>
230
231  
231<script src="/static/js/stream-shimmer.5a7071f4cb60.js"></script>
231
232
233  
234  
235  
235<script src="/static/js/thread-rail.05cc19a1c600.js" defer></script>
235
236
237  
238<style>
239  /* v2 badge next to the brand on the auth left panel. */
240  .auth-shell__v2-pill {
241    font-size: .62rem;
242    font-weight: 700;
243    letter-spacing: .06em;
244    text-transform: uppercase;
245    padding: .18rem .5rem;
246    border-radius: 999px;
247    color: #c7d2fe;
248    background: rgba(129,140,248,.18);
249    border: 1px solid rgba(129,140,248,.35);
250    line-height: 1;
251    margin-left: .1rem;
252  }
253  /* "Continue to v1" note pinned to the bottom of the left panel. */
254  .auth-shell__v1-note {
255    margin-top: 2rem;
256    padding-top: 1.25rem;
257    border-top: 1px solid rgba(255,255,255,.10);
258  }
259  .auth-shell__v1-note .text-subtle { display: block; }
260  .auth-shell__v1-link {
261    display: inline-block;
262    margin-top: .35rem;
263    font-weight: 600;
264    color: #c7d2fe;
265    text-decoration: none;
266  }
267  .auth-shell__v1-link:hover { color: #fff; text-decoration: underline; }
268
269  /* Compact v1 fallback shown inside the form column (visible on all sizes). */
270  .auth-v1-fallback {
271    margin-top: 1.5rem;
272    padding: .85rem 1rem;
273    border: 1px solid var(--border, rgba(15,18,32,.10));
274    border-radius: 12px;
275    background: var(--bg-tint, rgba(15,18,32,.02));
276    font-size: .85rem;
277    text-align: center;
278  }
279  .auth-v1-fallback a { font-weight: 600; text-decoration: none; }
280  .auth-v1-fallback a:hover { text-decoration: underline; }
281</style>
282<div class="auth-shell">
283  <aside class="auth-shell__art">
284    <div>
285      <a href="/" class="auth-card__brand text-white" aria-label="Lexlegis">
286        <img class="auth-shell__logo"
287             src="/static/img/logo/new-logo-dark.735d749f2293.svg"
288             alt="Lexlegis" width="160" height="32">
289        <span class="auth-shell__v2-pill">v2 · New</span>
290      </a>
291      <h2 class="mt-5">Where legal work gets done.</h2>
292      <p class="mt-3">Lexlegis v2 is rebuilt from the ground up — your research, drafting, documents, matters, and billing on one surface, with AI that cites its sources and shows its work. One home for solo practitioners and global firms alike.</p>
293
294      <p class="mt-3">
295        <span class="text-subtle">Coming from the classic version?</span>
296        <a href="https://v1.lexlegis.ai" class="auth-shell__v1-link">Continue to Lexlegis v1 &rarr;</a>
297      </p>
298
299      <div class="auth-shell__art-features">
300        <div class="auth-shell__feature">
301          <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v4"/><path d="M12 17v4"/><path d="M3 12h4"/><path d="M17 12h4"/><path d="M5.6 5.6 8.5 8.5"/><path d="M15.5 15.5 18.4 18.4"/><path d="M5.6 18.4 8.5 15.5"/><path d="M15.5 8.5 18.4 5.6"/></svg>
302
303          <div><strong>MIRA agents</strong><div class="text-subtle">Hand off multi-step work — MIRA drafts, reviews, and acts across your firm's tools, and shows you every step before it commits.</div></div>
304        </div>
305        <div class="auth-shell__feature">
306          <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg>
307
308          <div><strong>Ask, Interact &amp; Draft</strong><div class="text-subtle">Answers grounded in law and your files, a conversation with any case document, and drafts you can trace clause by clause.</div></div>
309        </div>
310        <div class="auth-shell__feature">
311          <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="7" width="20" height="14" rx="2"/><path d="M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"/></svg>
312
313          <div><strong>Run the whole matter</strong><div class="text-subtle">Matters, contract lifecycles, tasks, and timesheets in one place — every document searchable by AI the moment it lands.</div></div>
314        </div>
315        <div class="auth-shell__feature">
316          <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M9 2v6"/><path d="M15 2v6"/>
316<path d="M6 8h12v3a6 6 0 0 1-6 6 6 6 0 0 1-6-6z"/><path d="M12 17v5"/></svg>
317
318          <div><strong>Wherever you work</strong><div class="text-subtle">In Microsoft Word, over WhatsApp, or on your phone — your firm's knowledge is a message away.</div></div>
319        </div>
320      </div>
321    </div>
322
323    <div class="auth-shell__v1-note">
324      <div class="text-subtle small">© Lexlegis — Built for counsel, everywhere.</div>
325    </div>
326  </aside>
327  <section class="auth-shell__form">
328    <div class="auth-card">
329      
330  <a href="/" class="auth-card__brand d-lg-none">
331    
332
333<img class="sidebar__logo sidebar__logo--full auth-card__logo"
334     src="/static/img/logo/new-logo-light.a12ad8255ff7.svg"
335     alt="Lexlegis" width="150" height="30">
336
337  </a>
338
339  <h1 class="h2">Create your account.</h1>
340  <p class="lead mb-4">Start with a free organization. No credit card required.</p>
341
342  
343
344
345  <div class="sso-buttons" role="group" aria-label="Sign in with a single sign-on provider">
346    
347      
348        <form method="post" action="/accounts/apple/login/?process=signup" class="sso-form" data-provider="apple">
349          <input type="hidden" name="csrfmiddlewaretoken" value="hlg9j41VgXFR3A2gUP8PidYjHpK5kYLVmEDXkBKEGUzT12nOyCHO9P35hCquRkwK">
350          
351          <button type="submit" class="sso-btn" aria-label="Continue with Apple">
352            <span class="sso-btn__icon" aria-hidden="true">
353              <svg viewBox="0 0 384 512" focusable="false">
354                <path fill="currentColor" d="M318.7 268.7c-.2-36.7 16.4-64.4 50-84.8-18.8-26.9-47.2-41.7-84.7-44.6-35.5-2.8-74.3 20.7-88.5 20.7-15 0-49.4-19.7-76.4-19.7C63.3 141.2 4 184.8 4 273.5q0 39.3 14.4 81.2c12.8 36.7 59 126.7 107.2 125.2 25.2-.6 43-17.9 75.8-17.9 31.8 0 48.3 17.9 76.4 17.9 48.6-.7 90.4-82.5 102.6-119.3-65.2-30.7-61.7-90-61.7-91.9zm-56.6-164.2c27.3-32.4 24.8-61.9 24-72.5-24.1 1.4-52 16.4-67.9 34.9-17.5 19.8-27.8 44.3-25.6 71.9 26.1 2 49.9-11.4 69.5-34.3z"/>
355              </svg>
356            </span>
357            <span class="sso-btn__label">Continue with <strong>Apple</strong></span>
358            
359          </button>
360        </form>
361      
362    
363      
364        <form method="post" action="/accounts/google/login/?process=signup" class="sso-form" data-provider="google">
365          <input type="hidden" name="csrfmiddlewaretoken" value="hlg9j41VgXFR3A2gUP8PidYjHpK5kYLVmEDXkBKEGUzT12nOyCHO9P35hCquRkwK">
366          
367          <button type="submit" class="sso-btn" aria-label="Continue with Google">
368            <span class="sso-btn__icon" aria-hidden="true">
369              <svg viewBox="0 0 18 18" focusable="false">
370                <path fill="#4285F4" d="M17.64 9.2c0-.64-.06-1.25-.17-1.84H9v3.48h4.84a4.14 4.14 0 0 1-1.8 2.72v2.26h2.92c1.7-1.57 2.68-3.88 2.68-6.62z"/>
371                <path fill="#34A853" d="M9 18c2.43 0 4.47-.8 5.96-2.18l-2.92-2.26c-.81.54-1.84.86-3.04.86-2.34 0-4.32-1.58-5.03-3.7H.96v2.33A9 9 0 0 0 9 18z"/>
372                <path fill="#FBBC05" d="M3.97 10.72A5.4 5.4 0 0 1 3.68 9c0-.6.1-1.18.29-1.72V4.95H.96A9 9 0 0 0 0 9c0 1.45.35 2.83.96 4.05l3.01-2.33z"/>
373                <path fill="#EA4335" d="M9 3.58c1.32 0 2.5.45 3.44 1.35l2.58-2.58C13.46.89 11.43 0 9 0A9 9 0 0 0 .96 4.95L3.97 7.28C4.68 5.16 6.66 3.58 9 3.58z"/>
374              </svg>
375            </span>
376            <span class="sso-btn__label">Continue with <strong>Google</strong></span>
377            
378          </button>
379        </form>
380      
381    
382      
383        <form method="post" action="/accounts/microsoft/login/?process=signup" class="sso-form" data-provider="microsoft">
384          <input type="hidden" name="csrfmiddlewaretoken" value="hlg9j41VgXFR3A2gUP8PidYjHpK5kYLVmEDXkBKEGUzT12nOyCHO9P35hCquRkwK">
385          
386          <button type="submit" class="sso-btn" aria-label="Continue with Microsoft">
387            <span class="sso-btn__icon" aria-hidden="true">
388              <svg viewBox="0 0 21 21" focusable="false">
389                <rect x="1"  y="1"  width="9" height="9" fill="#F25022"/>
390                <rect x="11" y="1"  width="9" height="9" fill="#7FBA00"/>
391                <rect x="1"  y="11" width="9" height="9" fill="#00A4EF"/>
392                <rect x="11" y="11" width="9" height="9" fill="#FFB900"/>
393              </svg>
394            </span>
395            <span class="sso-btn__label">Continue with <strong>Microsoft</strong></span>
396            
397          </button>
398        </form>
399      
400    
401      
402    
403  </div>
404  <div class="auth-divider">or continue with email</div>
405
406
407
408  <form class="account-form"
409        method="post"
410        action="/register/"
411        novalidate
412        autocomplete="off"
413        data-form-type="other"
414        spellcheck="false">
415    <input type="hidden" name="csrfmiddlewaretoken" value="hlg9j41VgXFR3A2gUP8PidYjHpK5kYLVmEDXkBKEGUzT12nOyCHO9P35hCquRkwK">
416    
417    <div aria-hidden="true" style="position:absolute;left:-9999px;top:auto;width:1px;height:1px;overflow:hidden;">
418      <input type="text" name="fake-username" tabindex="-1" autocomplete="username">
419      <input type="password" name="fake-password" tabindex="-1" autocomplete="current-password">
420    </div>
421    
422
423    <div class="mb-3">
424      <label class="form-label" for="id_email">Work email</label>
425      <input type="email" name="email" placeholder="Email address" autocomplete="off" maxlength="320" class="form-control" data-lpignore="true" data-1p-ignore="" data-form-type="other" readonly="readonly" required id="id_email">
426      
427    </div>
428
429    <div class="mb-2">
430      <label class="form-label" for="id_password1">Password</label>
431      <div class="pw-input">
432        <input type="password" name="password1" placeholder="Password" autocomplete="new-password" class="form-control" id="id_password1" data-lpignore="true" data-1p-ignore="" data-bwignore="" data-form-type="other" readonly="readonly" required aria-describedby="id_password1_helptext">
433        <button type="button"
434                class="pw-toggle"
435                id="pw-toggle"
436                data-no-loader
437                aria-label="Show password"
438                aria-pressed="false"
439                aria-controls="id_password1"
440                tabindex="-1">
441          <svg class="pw-toggle__eye" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
442            <path d="M1.5 12s4-7 10.5-7 10.5 7 10.5 7-4 7-10.5 7S1.5 12 1.5 12z"/>
443            <circle cx="12" cy="12" r="3"/>
444          </svg>
445          <svg class="pw-toggle__eye-off" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
446            <path d="M3 3l18 18"/>
447            <path d="M10.6 6.2A10.9 10.9 0 0 1 12 6c6.5 0 10.5 6 10.5 6a17.9 17.9 0 0 1-3.2 3.9"/>
448            <path d="M6.7 7.7A17.9 17.9 0 0 0 1.5 12s4 7 10.5 7a10.9 10.9 0 0 0 4.6-1"/>
449            <path d="M9.9 9.9a3 3 0 0 0 4.2 4.2"/>
450          </svg>
451        </button>
452      </div>
453      
454
455      
456      <div class="pw-meter" id="pw-meter" hidden aria-live="polite">
457        <div class="pw-meter__head">
458          <div class="pw-meter__segments" data-level="0" id="pw-segments">
459            <span></span><span></span><span></span><span></span><span></span>
460          </div>
461          <div class="pw-meter__label" id="pw-strength-label">
462            <span class="pw-meter__verdict">Strength</span>
463            <span class="pw-meter__crack text-subtle" id="pw-crack"></span>
464          </div>
465        </div>
466
467        <ul class="pw-rules" id="pw-rules">
468          <li data-rule="length"><span class="pw-rules__dot"></span>At least 8 characters</li>
469          <li data-rule="upper"><span class="pw-rules__dot"></span>An uppercase letter (A–Z)</li>
470          <li data-rule="lower"><span class="pw-rules__dot"></span>A lowercase letter (a–z)</li>
471          <li data-rule="digit"><span class="pw-rules__dot"></span>A number (0–9)</li>
472          <li data-rule="symbol"><span class="pw-rules__dot"></span>A symbol (e.g. ! @ # $ %)</li>
473        </ul>
474      </div>
475    </div>
476
477    <div class="mb-3">
478      <label class="form-label" for="id_country">Country</label>
479      <select name="country" class="form-select" autocomplete="on" required id="id_country">
480  <option value="">Select your country</option>
481
482  <option value="AF">Afghanistan (+93)</option>
483
484  <option value="AL">Albania (+355)</option>
485
486  <option value="DZ">Algeria (+213)</option>
487
488  <option value="AR">Argentina (+54)</option>
489
490  <option value="AM">Armenia (+374)</option>
491
492  <option value="AU">Australia (+61)</option>
493
494  <option value="AT">Austria (+43)</option>
495
496  <option value="AZ">Azerbaijan (+994)</option>
497
498  <option value="BH">Bahrain (+973)</option>
499
500  <option value="BD">Bangladesh (+880)</option>
501
502  <option value="BY">Belarus (+375)</option>
503
504  <option value="BE">Belgium (+32)</option>
505
506  <option value="BO">Bolivia (+591)</option>
507
508  <option value="BA">Bosnia and Herzegovina (+387)</option>
509
510  <option value="BR">Brazil (+55)</option>
511
512  <option value="BG">Bulgaria (+359)</option>
513
514  <option value="KH">Cambodia (+855)</option>
515
516  <option value="CM">Cameroon (+237)</option>
517
518  <option value="CA">Canada (+1)</option>
519
520  <option value="CL">Chile (+56)</option>
521
522  <option value="CN">China (+86)</option>
523
524  <option value="CO">Colombia (+57)</option>
525
526  <option value="CR">Costa Rica (+506)</option>
527
528  <option value="HR">Croatia (+385)</option>
529
530  <option value="CU">Cuba (+53)</option>
531
532  <option value="CY">
532Cyprus (+357)</option>
533
534  <option value="CZ">Czechia (+420)</option>
535
536  <option value="DK">Denmark (+45)</option>
537
538  <option value="DO">Dominican Republic (+1)</option>
539
540  <option value="EC">Ecuador (+593)</option>
541
542  <option value="EG">Egypt (+20)</option>
543
544  <option value="EE">Estonia (+372)</option>
545
546  <option value="ET">Ethiopia (+251)</option>
547
548  <option value="FI">Finland (+358)</option>
549
550  <option value="FR">France (+33)</option>
551
552  <option value="GE">Georgia (+995)</option>
553
554  <option value="DE">Germany (+49)</option>
555
556  <option value="GH">Ghana (+233)</option>
557
558  <option value="GR">Greece (+30)</option>
559
560  <option value="GT">Guatemala (+502)</option>
561
562  <option value="HK">Hong Kong (+852)</option>
563
564  <option value="HU">Hungary (+36)</option>
565
566  <option value="IS">Iceland (+354)</option>
567
568  <option value="IN" selected>India (+91)</option>
569
570  <option value="ID">Indonesia (+62)</option>
571
572  <option value="IR">Iran (+98)</option>
573
574  <option value="IQ">Iraq (+964)</option>
575
576  <option value="IE">Ireland (+353)</option>
577
578  <option value="IL">Israel (+972)</option>
579
580  <option value="IT">Italy (+39)</option>
581
582  <option value="JM">Jamaica (+1)</option>
583
584  <option value="JP">Japan (+81)</option>
585
586  <option value="JO">Jordan (+962)</option>
587
588  <option value="KZ">Kazakhstan (+7)</option>
589
590  <option value="KE">Kenya (+254)</option>
591
592  <option value="KW">Kuwait (+965)</option>
593
594  <option value="KG">Kyrgyzstan (+996)</option>
595
596  <option value="LA">Laos (+856)</option>
597
598  <option value="LV">Latvia (+371)</option>
599
600  <option value="LB">Lebanon (+961)</option>
601
602  <option value="LY">Libya (+218)</option>
603
604  <option value="LT">Lithuania (+370)</option>
605
606  <option value="LU">Luxembourg (+352)</option>
607
608  <option value="MY">Malaysia (+60)</option>
609
610  <option value="MV">Maldives (+960)</option>
611
612  <option value="MT">Malta (+356)</option>
613
614  <option value="MX">Mexico (+52)</option>
615
616  <option value="MD">Moldova (+373)</option>
617
618  <option value="MN">Mongolia (+976)</option>
619
620  <option value="ME">Montenegro (+382)</option>
621
622  <option value="MA">Morocco (+212)</option>
623
624  <option value="MM">Myanmar (+95)</option>
625
626  <option value="NP">Nepal (+977)</option>
627
628  <option value="NL">Netherlands (+31)</option>
629
630  <option value="NZ">New Zealand (+64)</option>
631
632  <option value="NG">Nigeria (+234)</option>
633
634  <option value="NO">Norway (+47)</option>
635
636  <option value="OM">Oman (+968)</option>
637
638  <option value="PK">Pakistan (+92)</option>
639
640  <option value="PA">Panama (+507)</option>
641
642  <option value="PY">Paraguay (+595)</option>
643
644  <option value="PE">Peru (+51)</option>
645
646  <option value="PH">Philippines (+63)</option>
647
648  <option value="PL">Poland (+48)</option>
649
650  <option value="PT">Portugal (+351)</option>
651
652  <option value="QA">Qatar (+974)</option>
653
654  <option value="RO">Romania (+40)</option>
655
656  <option value="RU">Russia (+7)</option>
657
658  <option value="SA">Saudi Arabia (+966)</option>
659
660  <option value="RS">Serbia (+381)</option>
661
662  <option value="SG">Singapore (+65)</option>
663
664  <option value="SK">Slovakia (+421)</option>
665
666  <option value="SI">Slovenia (+386)</option>
667
668  <option value="ZA">South Africa (+27)</option>
669
670  <option value="KR">South Korea (+82)</option>
671
672  <option value="ES">Spain (+34)</option>
673
674  <option value="LK">Sri Lanka (+94)</option>
675
676  <option value="SE">Sweden (+46)</option>
677
678  <option value="CH">Switzerland (+41)</option>
679
680  <option value="TW">Taiwan (+886)</option>
681
682  <option value="TJ">Tajikistan (+992)</option>
683
684  <option value="TZ">Tanzania (+255)</option>
685
686  <option value="TH">Thailand (+66)</option>
687
688  <option value="TN">Tunisia (+216)</option>
689
690  <option value="TR">Turkey (+90)</option>
691
692  <option value="TM">Turkmenistan (+993)</option>
693
694  <option value="UG">Uganda (+256)</option>
695
696  <option value="UA">Ukraine (+380)</option>
697
698  <option value="AE">United Arab Emirates (+971)</option>
699
700  <option value="GB">United Kingdom (+44)</option>
701
702  <option value="US">United States (+1)</option>
703
704  <option value="UY">Uruguay (+598)</option>
705
706  <option value="UZ">Uzbekistan (+998)</option>
707
708  <option value="VE">Venezuela (+58)</option>
709
710  <option value="VN">Vietnam (+84)</option>
711
712  <option value="YE">Yemen (+967)</option>
713
714  <option value="ZM">Zambia (+260)</option>
715
716  <option value="ZW">Zimbabwe (+263)</option>
717
718  <option value="OT">Other / not listed</option>
719
720</select>
721      
722    </div>
723
724    <div class="mb-3">
725      <label class="form-label" for="id_phone">Phone number</label>
726      
726<script id="phone-maxlengths" type="application/json">{"IN": 10, "US": 10, "CA": 10, "GB": 10, "AE": 9, "SA": 9, "QA": 8, "KW": 8, "OM": 8, "BH": 8, "SG": 8, "HK": 8, "PK": 10, "BD": 10, "NP": 10, "LK": 9, "CN": 11, "JP": 10, "PH": 10, "TH": 9, "VN": 9, "FR": 9, "ES": 9, "NL": 9, "RU": 10, "TR": 10, "ZA": 9, "NG": 10, "EG": 10, "DE": 11, "IT": 10, "KR": 10, "MY": 10, "ID": 12, "BR": 11, "AU": 10, "NZ": 10}</script>
726
727      <div class="input-group">
728        <span class="input-group-text" id="phone-dial-prefix">+—</span>
729        <input type="text" name="phone" maxlength="10" class="form-control" autocomplete="tel" inputmode="tel" data-fallback-max="13" required id="id_phone">
730      </div>
731      
732      <div class="form-text small">
733        We'll send a WhatsApp verification code to this number.
734        <a href="#"
735           role="button"
736           tabindex="0"
737           class="text-decoration-underline ms-1"
738           data-bs-toggle="popover"
739           data-bs-trigger="focus"
740           data-bs-placement="top"
741           data-bs-custom-class="lex-pop"
742           data-bs-title="Why we ask for your phone"
743           data-bs-content="Bots and spammers churn out throwaway email accounts to create bogus logins. To keep those out, we verify a mobile + email combination — a real phone number is much harder to fake at scale."
744           onclick="event.preventDefault();">why?</a>
745      </div>
746    </div>
747
748    <div class="form-check mb-3 mt-3">
749      <input type="checkbox" name="terms_accepted" class="form-check-input" required id="id_terms_accepted" checked>
750      <label class="form-check-label small" for="id_terms_accepted">
751        I agree to the
752        <a href="https://lexlegis.ai/legal/terms" target="_blank" rel="noopener">Terms of Service</a>
753        and
754        <a href="https://lexlegis.ai/legal/privacy" target="_blank" rel="noopener">Privacy Policy</a>.
755      </label>
756      
757    </div>
758
759    
760
761    <button type="submit" class="btn btn-primary w-100 mt-2" id="signup-submit">Create account</button>
762  </form>
763
764  <p class="text-center text-muted mt-4 mb-0">
765    Already have an account?
766    <a href="/accounts/login/">Sign in</a>
767  </p>
768
769  <p class="text-center text-muted mt-2 mb-0">
770    <a href="/auth/sso/">Sign in with SSO</a>
771  </p>
772
773  <div class="auth-v1-fallback">
774    Already have a Lexlegis v1 account?
775    <a href="https://v1.lexlegis.ai">Continue to v1 &rarr;</a>
776    <div class="text-subtle small mt-1">You're creating an account on the new v2 — your v1 workspace stays where it is.</div>
777  </div>
778
779  <style>
780    /* Password field with inline eye toggle. */
781    .pw-input { position: relative; }
782    .pw-input > input.form-control { padding-right: 2.6rem; }
783    .pw-toggle {
784      position: absolute;
785      top: 50%;
786      right: 6px;
787      transform: translateY(-50%);
788      display: inline-flex;
789      align-items: center;
790      justify-content: center;
791      width: 32px;
792      height: 32px;
793      padding: 0;
794      border: 0;
795      background: transparent;
796      color: var(--text-muted, #4a4f63);
797      border-radius: 8px;
798      cursor: pointer;
799      transition: color .15s ease, background .15s ease;
800    }
801    .pw-toggle:hover { color: var(--text, #0f1220); background: var(--bg-tint, rgba(15,18,32,.05)); }
802    .pw-toggle:focus-visible {
803      outline: 2px solid var(--focus, #3b6ef6);
804      outline-offset: 1px;
805    }
806    .pw-toggle__eye-off { display: none; }
807    .pw-toggle[aria-pressed="true"] .pw-toggle__eye { display: none; }
808    .pw-toggle[aria-pressed="true"] .pw-toggle__eye-off { display: inline-block; }
809    [data-theme="dark"] .pw-toggle { color: rgba(255,255,255,.7); }
810    [data-theme="dark"] .pw-toggle:hover { color: #fff; background: rgba(255,255,255,.08); }
811
812    /* ============================================================
813       Password meter — editorial, segmented, animated on focus.
814       Hidden until the user engages with the password field, then
815       slides in with a measured cadence.
816       ============================================================ */
817    .pw-meter {
818      margin-top: 10px;
819      padding: 14px 14px 12px;
820      border: 1px solid var(--border, rgba(15,18,32,.08));
821      border-radius: 12px;
822      background: var(--bg-elev-2, #fafaf7);
823      box-shadow: 0 1px 1px rgba(15,18,32,.03);
824      opacity: 0;
825      transform: translateY(-6px);
826      transition: opacity .22s ease, transform .22s ease;
827    }
828    .pw-meter:not([hidden]) {
829      opacity: 1;
830      transform: translateY(0);
831    }
832    .pw-meter__head {
833      display: flex;
834      flex-direction: column;
835      gap: 8px;
836    }
837    .pw-meter__segments {
838      display: grid;
839      grid-template-columns: repeat(5, 1fr);
840      gap: 6px;
841    }
842    .pw-meter__segments > span {
843      display: block;
844      height: 6px;
845      border-radius: 999px;
846      background: var(--bg-tint, #efefea);
847      box-shadow: inset 0 0 0 1px var(--border-soft, rgba(15,18,32,.04));
848      transition: background .25s ease, box-shadow .25s ease, transform .25s ease;
849    }
850    .pw-meter__segments[data-level="1"] > span:nth-child(-n+1),
851    .pw-meter__segments[data-level="2"] > span:nth-child(-n+2),
852    .pw-meter__segments[data-level="3"] > span:nth-child(-n+3),
853    .pw-meter__segments[data-level="4"] > span:nth-child(-n+4),
854    .pw-meter__segments[data-level="5"] > span:nth-child(-n+5) {
855      transform: scaleY(1.1);
856    }
857    .pw-meter__segments[data-level="1"] > span:nth-child(-n+1) { background: #c43d3d; box-shadow: none; }
858    .pw-meter__segments[data-level="2"] > span:nth-child(-n+2) { background: #d97a1b; box-shadow: none; }
859    .pw-meter__segments[data-level="3"] > span:nth-child(-n+3) { background: #d4ad2a; box-shadow: none; }
860    .pw-meter__segments[data-level="4"] > span:nth-child(-n+4) { background: #2e9c63; box-shadow: none; }
861    .pw-meter__segments[data-level="5"] > span:nth-child(-n+5) {
862      background: linear-gradient(90deg, #2e9c63 0%, #1a7f4d 100%);
863      box-shadow: 0 0 8px rgba(46,156,99,.35);
864    }
865
866    .pw-meter__label {
867      display: flex;
868      justify-content: space-between;
869      align-items: baseline;
870      gap: 12px;
871      font-size: .875rem;
872    }
873    .pw-meter__verdict {
874      font-weight: 600;
875      letter-spacing: -0.005em;
876      color: var(--text-muted, #4a4f63);
877      transition: color .2s ease;
878    }
879    .pw-meter[data-level="1"] .pw-meter__verdict { color: #c43d3d; }
880    .pw-meter[data-level="2"] .pw-meter__verdict { color: #d97a1b; }
881    .pw-meter[data-level="3"] .pw-meter__verdict { color: #b8961f; }
882    .pw-meter[data-level="4"] .pw-meter__verdict { color: #1a7f4d; }
883    .pw-meter[data-level="5"] .pw-meter__verdict { color: #1a7f4d; }
884    .pw-meter__crack {
885      font-size: .75rem;
886      font-variant-numeric: tabular-nums;
887      color: var(--text-subtle, #7f8497);
888    }
889
890    /* Rule checklist */
891    .pw-rules {
892      list-style: none;
893      padding: 10px 0 0 0;
894      margin: 10px 0 0 0;
895      border-top: 1px dashed var(--border-soft, rgba(15,18,32,.06));
896      display: grid;
897      grid-template-columns: 1fr 1fr;
898      gap: 4px 16px;
899      font-size: .75rem;
900      color: var(--text-subtle, #7f8497);
901    }
902    .pw-rules li {
903      display: flex;
904      align-items: center;
905      gap: 7px;
906      transition: color .2s ease;
907    }
908    .pw-rules__dot {
909      width: 14px;
910      height: 14px;
911      border-radius: 999px;
912      border: 1.5px solid var(--text-faint, #a9adbd);
913      background: transparent;
914      position: relative;
915      flex: 0 0 14px;
916      transition: background .2s ease, border-color .2s ease, transform .2s ease;
917    }
918    .pw-rules__dot::after {
919      content: "";
920      position: absolute;
921      inset: 0;
922      background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'><path fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' d='M2.5 6.3l2.4 2.4 4.6-5'/></svg>") center/9px 9px no-repeat;
923      opacity: 0;
924      transform: scale(.6);
925      transition: opacity .15s ease, transform .15s ease;
926    }
927    .pw-rules li.pw-rule-ok {
928      color: #1a7f4d;
929    }
930    .pw-rules li.pw-rule-ok .pw-rules__dot {
931      background: #1a7f4d;
932      border-color: #1a7f4d;
933      transform: scale(1.05);
934    }
935    .pw-rules li.pw-rule-ok .pw-rules__dot::after {
936      opacity: 1;
937      transform: scale(1);
938    }
939
940    /* Dark-mode tweaks */
941    [data-theme="dark"] .pw-meter {
942      background: rgba(255,255,255,.03);
943      border-color: var(--border, rgba(255,255,255,.08));
944    }
945
946    /* Respect reduced motion */
947    @media (prefers-reduced-motion: reduce) {
948      .pw-meter,
949      .pw-meter__segments > span,
950      .pw-rules__dot,
951      .pw-rules__dot::after {
952        transition: none !important;
953      }
954    }
955  </style>
956
957  
957<script>
958  // Drop the readonly attribute the moment the user shows real intent on
959  // either field. The attribute is set server-side so the saved-password
960  // dropdown never opens on initial paint.
961  (function () {
962    ["id_email", "id_password1"].forEach(function (id) {
963      const el = document.getElementById(id);
964      if (!el) return;
965      const unlock = function () { el.removeAttribute("readonly"); };
966      el.addEventListener("focus", unlock, { once: true });
967      el.addEventListener("pointerdown", unlock, { once: true });
968    });
969  })();
970  </script>
970
971
972  
972<script>
973  // Catch obvious field-level problems client-side so the page never reloads
974  // and the password field keeps what the user typed. Server-side validation
975  // still runs as defense in depth (and for things we can't check here, like
976  // email uniqueness). app.js re-enables the submit button whenever any
977  // listener calls preventDefault, so no manual button reset needed.
978  (function () {
979    const form    = document.querySelector("form.account-form");
980    const email   = document.getElementById("id_email");
981    const pw1     = document.getElementById("id_password1");
982    const terms   = document.getElementById("id_terms_accepted");
983    const country = document.getElementById("id_country");
984    const phone   = document.getElementById("id_phone");
985    if (!form || !email || !pw1 || !terms) return;
986
987    // Loose enough to catch typos; server does the strict check.
988    const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
989
990    // Mirrors the visible rule list in the strength meter.
991    const PW_RULES = {
992      length: p => p.length >= 8,
993      upper:  p => /[A-Z]/.test(p),
994      lower:  p => /[a-z]/.test(p),
995      digit:  p => /[0-9]/.test(p),
996      symbol: p => /[^A-Za-z0-9]/.test(p),
997    };
998
999    function fieldHost(field) {
1000      // Sit the error inside the same wrapper Django's error div uses, so
1001      // spacing matches and our message replaces any prior client message.
1002      return field.closest(".mb-3, .mb-2, .form-check") || field.parentNode;
1003    }
1004    function setError(field, msg) {
1005      const host = fieldHost(field);
1006      let el = host.querySelector("[data-client-error]");
1007      if (!el) {
1008        el = document.createElement("div");
1009        el.setAttribute("data-client-error", "");
1010        el.className = "text-danger small mt-1";
1011        host.appendChild(el);
1012      }
1013      el.textContent = msg;
1014    }
1015    function clearError(field) {
1016      const el = fieldHost(field).querySelector("[data-client-error]");
1017      if (el) el.remove();
1018    }
1019
1020    function validate() {
1021      let firstInvalid = null;
1022
1023      const emailVal = email.value.trim();
1024      if (!emailVal) {
1025        setError(email, "Please enter your work email.");
1026        firstInvalid = firstInvalid || email;
1027      } else if (!EMAIL_RE.test(emailVal)) {
1028        setError(email, "Please enter a valid email address.");
1029        firstInvalid = firstInvalid || email;
1030      } else {
1031        clearError(email);
1032      }
1033
1034      const missing = Object.keys(PW_RULES).filter(k => !PW_RULES[k](pw1.value));
1035      if (missing.length) {
1036        setError(pw1, pw1.value
1037          ? "Password doesn't yet meet all the requirements below."
1038          : "Please choose a password.");
1039        firstInvalid = firstInvalid || pw1;
1040      } else {
1041        clearError(pw1);
1042      }
1043
1044      if (country && !country.value) {
1045        setError(country, "Please pick your country.");
1046        firstInvalid = firstInvalid || country;
1047      } else if (country) {
1048        clearError(country);
1049      }
1050
1051      if (phone) {
1052        const digits = (phone.value || "").replace(/\D/g, "");
1053        if (digits.length < 6) {
1054          setError(phone, "Enter your phone number (at least 6 digits).");
1055          firstInvalid = firstInvalid || phone;
1056        } else {
1057          clearError(phone);
1058        }
1059      }
1060
1061      if (!terms.checked) {
1062        setError(terms, "Please accept the Terms of Service and Privacy Policy to continue.");
1063        firstInvalid = firstInvalid || terms;
1064      } else {
1065        clearError(terms);
1066      }
1067
1068      return firstInvalid;
1069    }
1070
1071    form.addEventListener("submit", function (e) {
1072      const invalid = validate();
1073      if (invalid) {
1074        e.preventDefault();
1075        invalid.focus();
1076      }
1077    });
1078
1079    // Clear each field's error as soon as the user fixes it — keeps the
1080    // form feeling responsive instead of waiting for the next submit.
1081    email.addEventListener("input", function () {
1082      const v = email.value.trim();
1083      if (v && EMAIL_RE.test(v)) clearError(email);
1084    });
1085    pw1.addEventListener("input", function () {
1086      if (Object.keys(PW_RULES).every(k => PW_RULES[k](pw1.value))) clearError(pw1);
1087    });
1088    terms.addEventListener("change", function () {
1089      if (terms.checked) clearError(terms);
1090    });
1091    if (country) {
1092      country.addEventListener("change", function () {
1093        if (country.value) clearError(country);
1094      });
1095    }
1096    if (phone) {
1097      phone.addEventListener("input", function () {
1098        // Digits only — the maxlength is a national-number digit count, so
1099        // spaces/other characters would wrongly eat into the per-country cap.
1100        const cleaned = (phone.value || "").replace(/\D/g, "");
1101        if (cleaned !== phone.value) phone.value = cleaned;
1102        if (cleaned.length >= 6) clearError(phone);
1103      });
1104    }
1105  })();
1106  </script>
1106
1107
1108  
1108<script>
1109  // Keep the +dial-code prefix in sync with the selected country. The country
1110  // dropdown label already includes "(+91)" etc; we extract it via regex so
1111  // we don't ship a separate JSON map.
1112  (function () {
1113    const country = document.getElementById("id_country");
1114    const prefix  = document.getElementById("phone-dial-prefix");
1115    const phone   = document.getElementById("id_phone");
1116    if (!country || !prefix) return;
1117
1118    // ISO2 → max national-number length (from COUNTRY_PHONE_LENGTHS). Any
1119    // country missing here falls back to data-fallback-max on the input.
1120    let maxByCountry = {};
1121    try {
1122      maxByCountry = JSON.parse(
1123        document.getElementById("phone-maxlengths").textContent
1124      );
1125    } catch (_) {}
1126    const fallbackMax = phone
1127      ? parseInt(phone.getAttribute("data-fallback-max"), 10) || 0
1128      : 0;
1129
1130    function sync() {
1131      const opt = country.options[country.selectedIndex];
1132      if (!opt) { prefix.textContent = "+—"; return; }
1133      const m = opt.text.match(/\(\+(\d+)\)\s*$/);
1134      prefix.textContent = m ? "+" + m[1] : "+—";
1135
1136      if (phone) {
1137        const max = maxByCountry[country.value] || fallbackMax;
1138        if (max) {
1139          phone.maxLength = max;
1140          // Trim anything already over the new limit (e.g. switching from a
1141          // longer country to India after typing 11+ digits).
1142          if (phone.value.length > max) phone.value = phone.value.slice(0, max);
1143        }
1144      }
1145    }
1146    country.addEventListener("change", sync);
1147    sync();
1148
1149    // On blur, if the user typed the dial code (with the + sign) as the
1150    // first characters of the phone number, strip it — the prefix is
1151    // already shown in the input-group addon.
1152    if (phone) {
1153      phone.addEventListener("blur", function () {
1154        const dial = prefix.textContent.trim();
1155        if (!dial || !dial.startsWith("+") || dial === "+—") return;
1156        const v = (phone.value || "").trimStart();
1157        if (v.startsWith(dial)) {
1158          phone.value = v.slice(dial.length).trimStart();
1159        }
1160      });
1161    }
1162  })();
1163  </script>
1163
1164
1165  
1165<script>
1166  (function () {
1167    const pw1 = document.getElementById("id_password1");
1168    const meter = document.getElementById("pw-meter");
1169    const segs  = document.getElementById("pw-segments");
1170    const verdict = meter.querySelector(".pw-meter__verdict");
1171    const crack = document.getElementById("pw-crack");
1172
1173    const ruleFns = {
1174      length: p => p.length >= 8,
1175      upper:  p => /[A-Z]/.test(p),
1176      lower:  p => /[a-z]/.test(p),
1177      digit:  p => /[0-9]/.test(p),
1178      symbol: p => /[^A-Za-z0-9]/.test(p),
1179    };
1180    const ruleEls = {};
1181    meter.querySelectorAll(".pw-rules li[data-rule]").forEach(li => {
1182      ruleEls[li.dataset.rule] = li;
1183    });
1184
1185    const VERDICT = {
1186      0: "Strength",
1187      1: "Very weak",
1188      2: "Weak",
1189      3: "Fair",
1190      4: "Strong",
1191      5: "Excellent",
1192    };
1193
1194    // Rough entropy estimate (bits) — character-pool size × log2, with a
1195    // gentle penalty for runs and repeats. Not zxcvbn-grade but enough
1196    // to give a "could be cracked in…" hint that feels alive.
1197    function entropyBits(p) {
1198      if (!p) return 0;
1199      let pool = 0;
1200      if (/[a-z]/.test(p)) pool += 26;
1201      if (/[A-Z]/.test(p)) pool += 26;
1202      if (/[0-9]/.test(p)) pool += 10;
1203      if (/[^A-Za-z0-9]/.test(p)) pool += 33;
1204      let bits = p.length * Math.log2(Math.max(2, pool));
1205      if (/(.)\1{2,}/.test(p)) bits *= 0.78;   // repeats: aaaa
1206      if (/0123|1234|2345|3456|4567|5678|6789|abcd|bcde|cdef|qwer|asdf|zxcv/i.test(p)) bits *= 0.75;
1207      return Math.max(0, bits);
1208    }
1209
1210    // 10 billion guesses/sec (offline GPU). Threshold the result into a
1211    // human band — anything astronomical collapses to "centuries".
1212    function crackTime(bits) {
1213      if (bits <= 0) return "";
1214      const guesses = Math.pow(2, bits) / 2;
1215      const seconds = guesses / 1e10;
1216      if (seconds < 1)        return "cracked instantly";
1217      if (seconds < 60)       return "cracked in seconds";
1218      if (seconds < 3600)     return "cracked in minutes";
1219      if (seconds < 86400)    return "cracked in hours";
1220      if (seconds < 2592000)  return "cracked in days";
1221      if (seconds < 31536000) return "cracked in months";
1222      if (seconds < 31536000 * 100)   return "would take years";
1223      if (seconds < 31536000 * 10000) return "would take centuries";
1224      return "essentially uncrackable";
1225    }
1226
1227    function score(p) {
1228      if (!p) return 0;
1229      let rulesMet = 0;
1230      Object.keys(ruleFns).forEach(k => {
1231        const ok = ruleFns[k](p);
1232        ruleEls[k].classList.toggle("pw-rule-ok", ok);
1233        if (ok) rulesMet += 1;
1234      });
1235      const bits = entropyBits(p);
1236      // Combine ruleset coverage with entropy. Both must be high for a 5.
1237      let lvl;
1238      if (bits < 28)       lvl = 1;
1239      else if (bits < 40)  lvl = 2;
1240      else if (bits < 60)  lvl = 3;
1241      else if (bits < 80)  lvl = 4;
1242      else                 lvl = 5;
1243      // Don't promote past 3 without at least 4 rules satisfied.
1244      if (rulesMet < 4) lvl = Math.min(lvl, 3);
1245      if (rulesMet < 3) lvl = Math.min(lvl, 2);
1246      if (p.length < 8) lvl = Math.min(lvl, 2);
1247      return { lvl, bits };
1248    }
1249
1250    function renderStrength() {
1251      const v = pw1.value || "";
1252      const { lvl, bits } = score(v);
1253      segs.setAttribute("data-level", String(lvl));
1254      meter.setAttribute("data-level", String(lvl));
1255      verdict.textContent = VERDICT[lvl];
1256      crack.textContent = v ? "· " + crackTime(bits) : "";
1257    }
1258
1259    function showMeter() {
1260      if (meter.hasAttribute("hidden")) {
1261        meter.removeAttribute("hidden");
1262      }
1263    }
1264    function maybeHideMeter() {
1265      // Hide only if both empty AND the password field has lost focus.
1266      if (!pw1.value && document.activeElement !== pw1) {
1267        meter.setAttribute("hidden", "");
1268      }
1269    }
1270
1271    pw1.addEventListener("focus", () => { showMeter(); renderStrength(); });
1272    pw1.addEventListener("input", () => { showMeter(); renderStrength(); });
1273    pw1.addEventListener("blur",  () => { maybeHideMeter(); });
1274    if (pw1.value) { showMeter(); renderStrength(); }
1275  })();
1276  </script>
1276
1277
1278  
1278<script>
1279  // Eye toggle for the password field. Preserves caret position so toggling
1280  // mid-edit doesn't kick the cursor to the end.
1281  (function () {
1282    const pw  = document.getElementById("id_password1");
1283    const btn = document.getElementById("pw-toggle");
1284    if (!pw || !btn) return;
1285    btn.addEventListener("click", function () {
1286      const showing = pw.type === "text";
1287      const start = pw.selectionStart;
1288      const end   = pw.selectionEnd;
1289      pw.type = showing ? "password" : "text";
1290      btn.setAttribute("aria-pressed", showing ? "false" : "true");
1291      btn.setAttribute("aria-label", showing ? "Show password" : "Hide password");
1292      try { pw.setSelectionRange(start, end); } catch (_) {}
1293      pw.focus();
1294    });
1295  })();
1296  </script>
1296
1297
1298    </div>
1299  </section>
1300</div>
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310  
1311  
1312
1313
1314
1315  
1316
1317
1318
1319  
1320
1321
1322
1323  
1324<div id="cookie-consent"
1325     class="cc-root"
1326     hidden
1327     data-save-url="/cookie-consent/"
1328     data-policy-version="2026-06-01"
1329     role="dialog"
1330     aria-modal="false"
1331     aria-label="Cookie settings"
1332     aria-describedby="cc-banner-desc">
1333  <input type="hidden" name="csrfmiddlewaretoken" value="hlg9j41VgXFR3A2gUP8PidYjHpK5kYLVmEDXkBKEGUzT12nOyCHO9P35hCquRkwK">
1334
1335  
1336  <div class="cc-card cc-banner" data-cc-step="banner">
1337    <h2 class="cc-title">Cookie settings</h2>
1338    <p class="cc-text" id="cc-banner-desc">
1339      We use cookies to deliver and improve our services, analyse site usage,
1340      and — with your agreement — to personalise your experience and market our
1341      services to you. You can read our
1342      <a href="/legal/cookies/" class="cc-link"
1343         target="_blank" rel="noopener noreferrer">Cookie Policy</a>.
1344    </p>
1345    <div class="cc-actions">
1346      <button type="button" class="cc-btn cc-btn--ghost" data-cc-action="customize">
1347        Customize Cookie Settings
1348      </button>
1349      <div class="cc-actions-row">
1350        <button type="button" class="cc-btn cc-btn--outline" data-cc-action="reject">
1351          Reject All Cookies
1352        </button>
1353        <button type="button" class="cc-btn cc-btn--primary" data-cc-action="accept">
1354          Accept All Cookies
1355        </button>
1356      </div>
1357    </div>
1358  </div>
1359
1360  
1361  <div class="cc-card cc-panel" data-cc-step="panel" hidden>
1362    <h2 class="cc-title">Cookie settings</h2>
1363    <p class="cc-text">
1364      Choose which cookies you allow. Necessary cookies keep the site secure
1365      and working and can't be turned off. See our
1366      <a href="/legal/cookies/" class="cc-link"
1367         target="_blank" rel="noopener noreferrer">Cookie Policy</a>.
1368    </p>
1369
1370    <ul class="cc-cats">
1371      <li class="cc-cat">
1372        <div class="cc-cat-meta">
1373          <span class="cc-cat-name">Necessary</span>
1374          <span class="cc-cat-desc">Enables security and basic functionality.</span>
1375        </div>
1376        <div class="cc-cat-state">
1377          <span class="cc-required">Required</span>
1378          <span class="cc-switch cc-switch--on cc-switch--locked" aria-hidden="true"><span class="cc-knob"></span></span>
1379        </div>
1380      </li>
1381
1382      <li class="cc-cat">
1383        <div class="cc-cat-meta">
1384          <span class="cc-cat-name">Analytics</span>
1385          <span class="cc-cat-desc">Enables tracking of site performance.</span>
1386        </div>
1387        <label class="cc-cat-state">
1388          <span class="cc-state-label" data-cc-label="analytics">Off</span>
1389          <input type="checkbox" class="cc-toggle" data-cc-cat="analytics" aria-label="Analytics cookies">
1390          <span class="cc-switch" aria-hidden="true"><span class="cc-knob"></span></span>
1391        </label>
1392      </li>
1393
1394      <li class="cc-cat">
1395        <div class="cc-cat-meta">
1396          <span class="cc-cat-name">Marketing</span>
1397          <span class="cc-cat-desc">Enables ads personalisation and tracking.</span>
1398        </div>
1399        <label class="cc-cat-state">
1400          <span class="cc-state-label" data-cc-label="marketing">Off</span>
1401          <input type="checkbox" class="cc-toggle" data-cc-cat="marketing" aria-label="Marketing cookies">
1402          <span class="cc-switch" aria-hidden="true"><span class="cc-knob"></span></span>
1403        </label>
1404      </li>
1405    </ul>
1406
1407    <div class="cc-actions-row">
1408      <button type="button" class="cc-btn cc-btn--outline" data-cc-action="back">
1409        Back
1410      </button>
1411      <button type="button" class="cc-btn cc-btn--primary" data-cc-action="save">
1412        Save preferences
1413      </button>
1414    </div>
1415  </div>
1416</div>
1417
1418  
1419
1420
1421
1422  
1423
1424
1425
1426  
1427
1428
1429
1430  
1431
1432
1433
1434  
1435  
1436
1437  
1438  
1439  
1439<script src="https://unpkg.com/[email protected]" defer></script>
1439
1440  
1441  
1442  
1443  
1443<script src="https://unpkg.com/[email protected]/preload.js" defer></script>
1443
1444  
1444<script src="/static/js/app.07742fd456f5.js" defer></script>
1444
1445  
1446  
1447  
1447<script src="/static/js/settings-back.b1b0af35d605.js" defer></script>
1447
1448  
1448<script src="/static/js/settings-nav.0195da7001b9.js" defer></script>
1448
1449  
1450  
1451  
1451<script src="/static/js/quota-guard.3f62c54f3d7c.js" defer></script>
1451
1452  
1453  
1453<script src="/static/js/lex-sound.538ce90d3981.js" defer></script>
1453
1454  
1455  
1456  
1456<script src="/static/js/output-actions.5c8ff1392774.js" defer></script>
1456
1457  
1458  
1459  
1460  
1460<script src="/static/js/md-table-copy.78492ffdb83c.js" defer></script>
1460
1461  
1462  
1462<script src="/static/js/compose-files.dd1b62c76182.js" defer></script>
1462
1463  
1464  
1464<script src="/static/js/attach-menu.84719a664cf1.js" defer></script>
1464
1465  
1466  
1466<script src="/static/js/matter-files-panel.9b3827725089.js" defer></script>
1466
1467  
1468  
1468<script src="/static/js/compose-improve.f1c27ef990b5.js" defer></script>
1468
1469  
1470  
1470<script src="/static/js/compose-tip.4063488c4cf8.js" defer></script>
1470
1471  
1472  
1472<script src="/static/js/ask-on-this.d814c40394f8.js" defer></script>
1472
1473  
1474  
1474<script src="/static/js/compose-progress.34009430d8d8.js" defer></script>
1474
1475  
1476  
1476<script src="/static/js/compose-charcount.2c48fb7b37a1.js" defer></script>
1476
1477  
1477<script src="/static/js/token-meter.1e53d62fd4e8.js" defer></script>
1477
1478  
1479  
1479<script src="/static/js/dictation.5da007e633ee.js" defer></script>
1479
1480  
1480<script src="/static/js/cookie-consent.a3fa9484bec7.js" defer></script>
1480
1481  
1482  
1483  
1483<script src="/static/js/feedback.23023337adff.js" defer></script>
1483
1484  
1484<script src="/static/js/feature-request.ce7e8129f424.js" defer></script>
1484
1485  
1485<script src="/static/js/referrals.f586d0c0853f.js" defer></script>
1485
1486  
1486<script src="/static/js/nps.af3a19d7a75d.js" defer></script>
1486
1487  
1488  
1488<script src="/static/js/shortcuts.89ea7186515b.js" defer></script>
1488
1489  
1490  
1490<script src="/static/js/tour.c7856152b8f8.js" defer></script>
1490
1491  
1492  
1492<script src="/static/js/library-editor.de607e99d311.js" defer></script>
1492
1493  
1494  
1494<script src="/static/js/dock-overflow.3459f6b43659.js" defer></script>
1494
1495  
1496  
1496<script>
1497  (function initSignupPopups() {
1498    function boot() {
1499      if (!window.bootstrap || !bootstrap.Popover) return setTimeout(boot, 40);
1500      document
1501        .querySelectorAll('.account-form [data-bs-toggle="popover"]')
1502        .forEach((el) => {
1503          if (el._lexPop) return;
1504          el._lexPop = new bootstrap.Popover(el, { container: "body", html: false });
1505        });
1506      document
1507        .querySelectorAll('.account-form [data-bs-toggle="tooltip"]')
1508        .forEach((el) => {
1509          if (el._lexTip) return;
1510          el._lexTip = new bootstrap.Tooltip(el, { container: "body" });
1511        });
1512    }
1513    if (document.readyState === "loading") {
1514      document.addEventListener("DOMContentLoaded", boot);
1515    } else {
1516      boot();
1517    }
1518  })();
1519  </script>
1519
1520
1521</body>
1522</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.