File size: 29,988 Bytes
73af74c
 
 
 
 
 
 
 
 
 
034e081
 
73af74c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1adf57b
73af74c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1adf57b
73af74c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
034e081
73af74c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
034e081
 
 
1adf57b
 
73af74c
 
1adf57b
 
 
73af74c
1adf57b
 
034e081
 
73af74c
034e081
 
 
 
 
 
 
 
1adf57b
 
 
c3213ca
 
 
1adf57b
73af74c
 
1adf57b
73af74c
1adf57b
 
73af74c
 
1adf57b
73af74c
 
 
 
 
034e081
73af74c
 
c3213ca
 
 
 
 
 
 
 
 
 
 
73af74c
 
 
 
 
034e081
 
 
 
 
 
73af74c
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="theme-color" content="#10152b">
<title>Protect PDF — PDFix</title>
<meta name="description" content="Protect PDF files with password encryption and configurable permissions in your browser.">
<link rel="preconnect" href="https://cdnjs.cloudflare.com">
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf-lib/1.17.1/pdf-lib.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@pdfsmaller/pdf-encrypt@1.2.0/dist/pdf-encrypt.umd.js"></script>
<style>
:root{--bg:#f5f7fc;--surface:#fff;--ink:#171c35;--muted:#7c849f;--line:#e6eaf3;--primary:#6558ed;--primary2:#877bff;--mint:#22b89a;--danger:#e45469;--shadow:0 18px 55px rgba(33,43,89,.08);--radius:22px}
*{box-sizing:border-box}body{margin:0;background:radial-gradient(circle at 12% 0%,#eceaff 0,transparent 30%),radial-gradient(circle at 90% 10%,#e5faf6 0,transparent 25%),var(--bg);font-family:"DM Sans",sans-serif;color:var(--ink);min-height:100vh}button,input,select{font:inherit}button{cursor:pointer}.shell{max-width:1220px;margin:auto;padding:24px 26px 60px}.topbar{display:flex;align-items:center;justify-content:space-between;gap:20px;margin-bottom:44px}.brand{display:flex;align-items:center;gap:12px;text-decoration:none;color:inherit}.brandmark{width:44px;height:44px;border-radius:15px;background:linear-gradient(135deg,#786bff,#5145d7);display:grid;place-items:center;color:white;box-shadow:0 8px 20px #6658ed44}.brandmark svg{width:24px}.brandname{font:800 22px Manrope,sans-serif;letter-spacing:-.8px}.brandname span{color:var(--primary)}.secure-pill{display:flex;align-items:center;gap:8px;background:#fff;border:1px solid var(--line);padding:10px 14px;border-radius:99px;color:#56607b;font-size:12px;font-weight:700}.secure-pill i{width:8px;height:8px;border-radius:50%;background:var(--mint);box-shadow:0 0 0 4px #22b89a1b}.hero{text-align:center;margin:0 auto 34px;max-width:760px}.eyebrow{display:inline-flex;align-items:center;gap:8px;color:var(--primary);font-size:11px;font-weight:800;letter-spacing:1.5px;text-transform:uppercase;background:#eeecff;border:1px solid #e0dcff;border-radius:99px;padding:8px 12px}.hero h1{font:800 clamp(34px,5vw,55px)/1.08 Manrope,sans-serif;letter-spacing:-2.5px;margin:18px 0 14px}.hero h1 em{font-style:normal;background:linear-gradient(90deg,#6558ed,#a16aff);-webkit-background-clip:text;background-clip:text;color:transparent}.hero p{margin:0 auto;max-width:600px;color:var(--muted);font-size:15px;line-height:1.75}.workspace{display:grid;grid-template-columns:minmax(0,1.45fr) minmax(320px,.85fr);gap:22px;align-items:start}.panel{background:var(--surface);border:1px solid #e8ebf4;border-radius:var(--radius);box-shadow:var(--shadow);overflow:hidden}.panel-head{padding:23px 25px 18px;border-bottom:1px solid var(--line);display:flex;justify-content:space-between;align-items:center;gap:14px}.panel-title{font:800 16px Manrope,sans-serif;letter-spacing:-.3px}.panel-sub{font-size:12px;color:var(--muted);margin-top:5px}.step{font-size:11px;font-weight:800;color:var(--primary);background:#f0efff;padding:8px 11px;border-radius:10px;white-space:nowrap}.panel-body{padding:24px}.dropzone{border:1.5px dashed #c9c9ee;border-radius:18px;background:linear-gradient(135deg,#fafaff,#f5fffc);min-height:240px;display:flex;align-items:center;justify-content:center;text-align:center;padding:26px;transition:.2s}.dropzone.drag{border-color:var(--primary);background:#f0efff;transform:scale(.995)}.drop-inner{max-width:380px}.upload-icon{width:58px;height:58px;margin:0 auto 15px;display:grid;place-items:center;border-radius:18px;color:var(--primary);background:#ebe9ff}.upload-icon svg{width:28px}.dropzone h3{margin:0 0 8px;font:800 16px Manrope,sans-serif}.dropzone p{margin:0 0 17px;color:var(--muted);font-size:12px;line-height:1.65}.btn{border:0;border-radius:12px;padding:12px 17px;font-weight:800;font-size:12px;transition:transform .15s,box-shadow .15s}.btn:hover{transform:translateY(-1px)}.btn-primary{color:#fff;background:linear-gradient(135deg,#7467ff,#5749dd);box-shadow:0 9px 20px #6558ed30}.btn-light{background:#f3f4fa;color:#535c79;border:1px solid var(--line)}.file-card{display:none;align-items:center;gap:14px;padding:15px;border:1px solid var(--line);border-radius:15px;background:#fbfcff;margin-top:16px}.file-icon{width:44px;height:48px;display:grid;place-items:center;border-radius:11px;background:#fff0f1;color:#e45265;flex:none}.file-icon svg{width:22px}.file-info{min-width:0;flex:1}.file-name{font-weight:800;font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.file-meta{color:var(--muted);font-size:11px;margin-top:5px}.remove-btn{border:0;background:#f5f6fb;color:#8a91a9;width:32px;height:32px;border-radius:10px;font-size:19px}.section-label{font:800 12px Manrope,sans-serif;margin:24px 0 13px;display:flex;align-items:center;justify-content:space-between;gap:12px}.section-label small{font:500 11px "DM Sans";color:var(--muted)}.field{margin-bottom:15px}.field label{display:flex;justify-content:space-between;gap:10px;font-size:12px;font-weight:700;margin-bottom:8px;color:#424a68}.field input[type=password],.field input[type=text],.field input[type=number],.field select{width:100%;padding:13px 14px;border:1px solid #e1e5f0;border-radius:11px;outline:none;color:var(--ink);background:#fff;transition:.2s}.field input:focus,.field select:focus{border-color:#8d82ff;box-shadow:0 0 0 3px #6558ed12}.input-wrap{position:relative}.input-wrap input{padding-right:48px!important}.eye{position:absolute;right:7px;top:7px;border:0;background:#f4f5fb;border-radius:8px;width:34px;height:34px;color:#69718d}.strength{display:flex;gap:5px;margin-top:9px}.strength span{height:4px;border-radius:5px;background:#e7eaf3;flex:1}.strength span.on.weak{background:#e45b6d}.strength span.on.medium{background:#efb84c}.strength span.on.strong{background:#20b99a}.strength-copy{font-size:10px;color:var(--muted);margin-top:6px}.checkline{display:flex;align-items:flex-start;gap:10px;padding:12px 13px;border:1px solid var(--line);border-radius:12px;margin:10px 0;background:#fcfcff}.checkline input{accent-color:var(--primary);margin-top:2px}.checkline strong{display:block;font-size:12px}.checkline small{display:block;color:var(--muted);font-size:11px;line-height:1.5;margin-top:4px}.permissions{display:grid;grid-template-columns:1fr 1fr;gap:10px}.permission{display:flex;align-items:flex-start;gap:9px;padding:12px;border:1px solid var(--line);border-radius:12px;background:#fff}.permission input{accent-color:var(--primary);margin-top:2px}.permission strong{font-size:11px;display:block}.permission small{display:block;font-size:10px;color:var(--muted);margin-top:4px;line-height:1.4}.info-note{font-size:11px;color:#6c7290;line-height:1.65;background:#f5f6ff;border:1px solid #e8e8ff;border-radius:12px;padding:12px 14px;margin-top:14px}.info-note b{color:#4f49b8}.side-panel .panel-body{padding:22px}.preview-card{border:1px solid var(--line);border-radius:17px;background:linear-gradient(150deg,#fbfbff,#f5f7ff);padding:22px;text-align:center}.lock-visual{width:82px;height:88px;margin:4px auto 16px;position:relative;display:grid;place-items:center}.lock-shackle{position:absolute;top:0;width:40px;height:42px;border:6px solid #786bff;border-bottom:0;border-radius:22px 22px 0 0}.lock-body{position:absolute;bottom:0;width:67px;height:52px;border-radius:14px;background:linear-gradient(135deg,#7d70ff,#5345d8);box-shadow:0 10px 18px #6558ed35;display:grid;place-items:center;color:white}.lock-body svg{width:24px}.preview-card h3{font:800 15px Manrope,sans-serif;margin:0 0 8px}.preview-card p{color:var(--muted);font-size:11px;line-height:1.65;margin:0}.summary{margin-top:17px}.summary-row{display:flex;justify-content:space-between;gap:15px;padding:12px 0;border-bottom:1px solid #edf0f6;font-size:11px}.summary-row:last-child{border-bottom:0}.summary-row span{color:var(--muted)}.summary-row strong{text-align:right;overflow-wrap:anywhere}.secure-status{display:flex;align-items:center;gap:10px;padding:12px;border-radius:12px;background:#eafaf5;color:#16896f;font-size:11px;font-weight:800;margin-top:16px}.secure-status svg{width:18px;flex:none}.actions{margin-top:19px}.actions .btn{width:100%;padding:15px}.actions .btn:disabled{opacity:.5;cursor:not-allowed;transform:none;box-shadow:none}.actions .subtext{text-align:center;color:var(--muted);font-size:10px;line-height:1.6;margin-top:10px}.progress-wrap{display:none;margin-top:16px}.progress-head{display:flex;justify-content:space-between;font-size:11px;color:#59617e;margin-bottom:8px}.progress{height:6px;background:#eceefa;border-radius:99px;overflow:hidden}.progress span{display:block;width:0;height:100%;background:linear-gradient(90deg,#6558ed,#24bea1);transition:width .2s}.result{display:none;margin-top:15px;padding:14px;border:1px solid #cdeee3;background:#f1fcf8;border-radius:13px}.result strong{font-size:12px;color:#16866e}.result p{font-size:11px;color:#5c7180;line-height:1.6;margin:6px 0 12px}.result .btn{width:100%}.trust-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;margin-top:23px}.trust{display:flex;align-items:center;gap:12px;padding:17px;background:#ffffffad;border:1px solid #e8ebf4;border-radius:16px}.trust-icon{width:38px;height:38px;border-radius:12px;display:grid;place-items:center;background:#efedff;color:var(--primary);flex:none}.trust-icon svg{width:19px}.trust strong{display:block;font-size:11px}.trust span{display:block;font-size:10px;color:var(--muted);margin-top:4px;line-height:1.4}.footer{text-align:center;color:#9299b0;font-size:10px;margin-top:35px}.toast{position:fixed;left:50%;bottom:25px;transform:translate(-50%,20px);opacity:0;pointer-events:none;z-index:10;background:#202542;color:#fff;padding:13px 18px;border-radius:12px;box-shadow:0 15px 35px #171c3533;font-size:12px;transition:.25s;max-width:calc(100vw - 30px)}.toast.show{opacity:1;transform:translate(-50%,0)}.smallprint{font-size:10px;color:var(--muted);line-height:1.65;margin-top:10px}
@media(max-width:900px){.workspace{grid-template-columns:1fr}.side-panel{order:2}.trust-grid{grid-template-columns:1fr 1fr}}@media(max-width:560px){.shell{padding:16px 13px 40px}.topbar{margin-bottom:30px}.secure-pill{font-size:0;padding:11px}.secure-pill i{margin:0}.hero h1{letter-spacing:-1.5px}.panel-head{padding:19px}.panel-body{padding:17px}.permissions{grid-template-columns:1fr}.trust-grid{grid-template-columns:1fr}.dropzone{min-height:220px}.panel{border-radius:18px}}
</style>
</head>
<body>
<div class="shell">
  <header class="topbar">
    <a class="brand" href="index.html" aria-label="PDFix home">
      <span class="brandmark"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M7 3h7l5 5v13H7a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2Z"/><path d="M14 3v6h5M9 14h6M9 17h6"/></svg></span>
      <span class="brandname">PDF<span>ix</span></span>
    </a>
    <div class="secure-pill"><i></i> LOCAL BROWSER PROCESSING</div>
  </header>
  <section class="hero">
    <span class="eyebrow">✦ PDF SECURITY STUDIO</span>
    <h1>Protect your PDF.<br><em>Keep it private.</em></h1>
    <p>Add an opening password and set document permissions before sharing. Real AES-256 PDF encryption runs locally in your browser using WebAssembly; your document is not uploaded to a PDFix server.</p>
  </section>

  <main class="workspace">
    <section class="panel">
      <div class="panel-head"><div><div class="panel-title">Secure your document</div><div class="panel-sub">Upload a PDF, choose a password, and export a protected copy.</div></div><span class="step">STEP 01 / 03</span></div>
      <div class="panel-body">
        <div class="dropzone" id="dropzone">
          <div class="drop-inner">
            <div class="upload-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M7 3h7l5 5v13H7a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2Z"/><path d="M14 3v5h5M12 17V10m-3 3 3-3 3 3"/></svg></div>
            <h3>Drop your PDF right here</h3>
            <p>or select a file from your device. For best results, use an unencrypted PDF.</p>
            <button class="btn btn-primary" id="browseBtn" type="button">Choose PDF file</button>
            <input id="fileInput" type="file" accept="application/pdf,.pdf" hidden>
          </div>
        </div>
        <div class="file-card" id="fileCard">
          <div class="file-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M7 3h7l5 5v13H7a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2Z"/><path d="M14 3v5h5M9 14h6M9 17h6"/></svg></div>
          <div class="file-info"><div class="file-name" id="fileName">document.pdf</div><div class="file-meta" id="fileMeta">PDF · 0 MB</div></div>
          <button class="remove-btn" id="removeFile" type="button" title="Remove file">×</button>
        </div>

        <div class="section-label">01 — Opening password <small>Required</small></div>
        <div class="field">
          <label for="password">Set a password to open this PDF</label>
          <div class="input-wrap"><input id="password" type="password" autocomplete="new-password" placeholder="Use a long, unique password"><button type="button" class="eye" data-toggle="password" aria-label="Show password">◉</button></div>
          <div class="strength" id="strength"><span></span><span></span><span></span><span></span></div>
          <div class="strength-copy" id="strengthCopy">Use at least 12 characters, including a mix of character types.</div>
        </div>
        <div class="field">
          <label for="confirmPassword">Confirm password</label>
          <div class="input-wrap"><input id="confirmPassword" type="password" autocomplete="new-password" placeholder="Enter the same password again"><button type="button" class="eye" data-toggle="confirmPassword" aria-label="Show password">◉</button></div>
        </div>
        <label class="checkline"><input id="showPassword" type="checkbox"><span><strong>Show password while typing</strong><small>Turn this off before sharing your screen or device.</small></span></label>

        <div class="section-label">02 — Document permissions <small>Optional</small></div>
        <p class="smallprint" style="margin-top:-5px;margin-bottom:12px">These settings are written as PDF permission flags. Support varies across PDF viewers; they are not a substitute for an opening password.</p>
        <div class="permissions">
          <label class="permission"><input type="checkbox" id="allowPrint" checked><span><strong>Allow printing</strong><small>Permit printing in compatible viewers</small></span></label>
          <label class="permission"><input type="checkbox" id="allowCopy" checked><span><strong>Allow copying</strong><small>Permit text and content extraction</small></span></label>
          <label class="permission"><input type="checkbox" id="allowModify" checked><span><strong>Allow editing</strong><small>Permit document changes</small></span></label>
          <label class="permission"><input type="checkbox" id="allowAnnotate" checked><span><strong>Allow annotations</strong><small>Permit comments and form interactions</small></span></label>
        </div>
        <div class="field" style="margin-top:18px">
          <label for="printQuality">Printing quality</label>
          <select id="printQuality"><option value="high">High resolution</option><option value="low">Low resolution</option></select>
        </div>
        <div class="section-label">03 — Export settings <small>Optional</small></div>
        <div class="field"><label for="outputName">Output file name</label><input id="outputName" type="text" value="protected-document.pdf" maxlength="120"></div>
        <label class="checkline"><input id="downloadAfter" type="checkbox" checked><span><strong>Download automatically when ready</strong><small>Save the protected copy to your device.</small></span></label>
        <div class="info-note"><b>Security note:</b> Use a unique password and share it through a separate channel. If you forget the password, PDFix cannot recover it. The tool verifies that the output is marked encrypted, but always test the downloaded PDF in a trusted reader before relying on it for sensitive documents.</div>
      </div>
    </section>

    <aside class="panel side-panel">
      <div class="panel-head"><div><div class="panel-title">Security overview</div><div class="panel-sub">Review your protection settings.</div></div><span class="step">LIVE</span></div>
      <div class="panel-body">
        <div class="preview-card">
          <div class="lock-visual"><div class="lock-shackle"></div><div class="lock-body"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="5" y="10" width="14" height="11" rx="2"/><path d="M8 10V7a4 4 0 0 1 8 0v3M12 14v3"/></svg></div></div>
          <h3 id="previewTitle">Protection is ready to configure</h3>
          <p id="previewCopy">Add an opening password to make access to your PDF private.</p>
        </div>
        <div class="summary">
          <div class="summary-row"><span>Selected file</span><strong id="sumFile">Not selected</strong></div>
          <div class="summary-row"><span>Opening password</span><strong id="sumPassword">Not set</strong></div>
          <div class="summary-row"><span>Printing</span><strong id="sumPrint">Allowed</strong></div>
          <div class="summary-row"><span>Copying</span><strong id="sumCopy">Allowed</strong></div>
          <div class="summary-row"><span>Editing</span><strong id="sumEdit">Allowed</strong></div>
          <div class="summary-row"><span>Annotations</span><strong id="sumAnnotate">Allowed</strong></div>
          <div class="summary-row"><span>Output</span><strong id="sumOutput">protected-document.pdf</strong></div>
        </div>
        <div class="secure-status"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 22s8-4 8-11V5l-8-3-8 3v6c0 7 8 11 8 11Z"/><path d="m9 12 2 2 4-4"/></svg><span id="statusText">Your document stays on this device during processing.</span></div>
        <div class="actions"><button class="btn btn-primary" id="protectBtn" type="button" disabled>🔒 Protect & download PDF</button><div class="subtext">The original file is not modified. A new protected copy will be created.</div></div>
        <div class="progress-wrap" id="progressWrap"><div class="progress-head"><span id="progressText">Preparing secure PDF…</span><strong id="progressPct">0%</strong></div><div class="progress"><span id="progressBar"></span></div></div>
        <div class="result" id="result"><strong>✓ Protected PDF is ready</strong><p id="resultText">Your file has been processed.</p><button class="btn btn-primary" id="downloadBtn" type="button">Download protected PDF</button></div>
      </div>
    </aside>
  </main>

  <section class="trust-grid">
    <div class="trust"><div class="trust-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="4" y="10" width="16" height="11" rx="2"/><path d="M8 10V7a4 4 0 0 1 8 0v3"/></svg></div><div><strong>Password protection</strong><span>Add a password required to open the output PDF.</span></div></div>
    <div class="trust"><div class="trust-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 5h16M4 12h16M4 19h16"/><path d="m8 2-4 3 4 3"/></svg></div><div><strong>Permission controls</strong><span>Set printing, copying, editing and annotation flags.</span></div></div>
    <div class="trust"><div class="trust-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 22s8-4 8-11V5l-8-3-8 3v6c0 7 8 11 8 11Z"/><path d="m9 12 2 2 4-4"/></svg></div><div><strong>Browser-side workflow</strong><span>Your PDF is handled locally by this page's JavaScript.</span></div></div>
  </section>
  <footer class="footer">PDFix · Practical PDF tools, designed for your workflow.</footer>
</div>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script>
(() => {
  const $ = id => document.getElementById(id);
  let selectedFile = null, outputBlob = null, outputUrl = null, toastTimer = null;
  const fields = ['password','confirmPassword','outputName','allowPrint','allowCopy','allowModify','allowAnnotate','printQuality','downloadAfter'];
  function toast(message){ $('toast').textContent=message; $('toast').classList.add('show'); clearTimeout(toastTimer); toastTimer=setTimeout(()=>$('toast').classList.remove('show'),3000); }
  function bytes(n){ if(n<1024) return n+' B'; if(n<1024*1024) return (n/1024).toFixed(1)+' KB'; return (n/1024/1024).toFixed(2)+' MB'; }
  function safeName(name){ let v=(name||'protected-document.pdf').trim().replace(/[\\/:*?"<>|]/g,'-').replace(/\.pdf$/i,''); return (v||'protected-document')+'.pdf'; }
  function setProgress(p,msg){ $('progressWrap').style.display='block'; $('progressBar').style.width=p+'%'; $('progressPct').textContent=p+'%'; $('progressText').textContent=msg; }
  function setFile(file){
    if(!file) return;
    if(!/\.pdf$/i.test(file.name) && file.type!=='application/pdf'){toast('Please choose a PDF file.');return;}
    if(file.size===0){toast('This file is empty. Choose another PDF.');return;}
    selectedFile=file; outputBlob=null;
    $('dropzone').style.display='none'; $('fileCard').style.display='flex';
    $('fileName').textContent=file.name; $('fileMeta').textContent='PDF · '+bytes(file.size);
    $('sumFile').textContent=file.name; $('protectBtn').disabled=false; $('result').style.display='none'; $('progressWrap').style.display='none';
    $('statusText').textContent='Ready to protect locally in this browser.';
    updateSummary();
  }
  function clearFile(){
    selectedFile=null;outputBlob=null;if(outputUrl){URL.revokeObjectURL(outputUrl);outputUrl=null;}
    $('fileInput').value='';$('dropzone').style.display='flex';$('fileCard').style.display='none';$('sumFile').textContent='Not selected';$('protectBtn').disabled=true;$('result').style.display='none';$('progressWrap').style.display='none';updateSummary();
  }
  function passwordScore(p){
    if(!p) return 0; let score=0;
    if(p.length>=8)score++; if(p.length>=12)score++; if(/[a-z]/.test(p)&&/[A-Z]/.test(p))score++; if(/\d/.test(p))score++; if(/[^A-Za-z0-9]/.test(p))score++;
    return Math.min(4,score);
  }
  function updateStrength(){
    const p=$('password').value, score=passwordScore(p), segments=[...$('strength').children];
    segments.forEach((s,i)=>{s.className='';if(i<score)s.classList.add('on',score<=1?'weak':score<=2?'medium':'strong');});
    $('strengthCopy').textContent=!p?'Use at least 12 characters, including a mix of character types.':score<=1?'Weak password — add length and variety.':score<=2?'Fair password — consider a longer passphrase.':score===3?'Good password — longer is better.':'Strong password pattern. Avoid reusing this password.';
    $('sumPassword').textContent=p?(score>=3?'Set · good pattern':'Set · improve strength'):'Not set';
    $('previewTitle').textContent=p?'Password protection configured':'Protection is ready to configure';
    $('previewCopy').textContent=p?'An opening password will be applied to the exported PDF.':'Add an opening password to make access to your PDF private.';
    updateSummary();
  }
  function updateSummary(){
    $('sumPrint').textContent=$('allowPrint').checked?'Allowed':'Restricted';
    $('sumCopy').textContent=$('allowCopy').checked?'Allowed':'Restricted';
    $('sumEdit').textContent=$('allowModify').checked?'Allowed':'Restricted';
    $('sumAnnotate').textContent=$('allowAnnotate').checked?'Allowed':'Restricted';
    $('sumOutput').textContent=safeName($('outputName').value);
    $('protectBtn').disabled=!(selectedFile && window.PDFEncrypt && typeof window.PDFEncrypt.encryptPDF === 'function');
  }
  $('browseBtn').addEventListener('click',()=>$('fileInput').click());
  $('fileInput').addEventListener('change',e=>setFile(e.target.files[0]));
  $('removeFile').addEventListener('click',clearFile);
  const dz=$('dropzone');
  dz.addEventListener('dragover',e=>{e.preventDefault();dz.classList.add('drag');});
  dz.addEventListener('dragleave',()=>dz.classList.remove('drag'));
  dz.addEventListener('drop',e=>{e.preventDefault();dz.classList.remove('drag');setFile(e.dataTransfer.files[0]);});
  document.querySelectorAll('[data-toggle]').forEach(btn=>btn.addEventListener('click',()=>{const input=$(btn.dataset.toggle);input.type=input.type==='password'?'text':'password';btn.textContent=input.type==='password'?'◉':'◎';}));
  $('showPassword').addEventListener('change',e=>{const t=e.target.checked?'text':'password';$('password').type=t;$('confirmPassword').type=t;});
  $('password').addEventListener('input',updateStrength);
  fields.slice(2).forEach(id=>$(id).addEventListener('input',updateSummary));
  ['allowPrint','allowCopy','allowModify','allowAnnotate','printQuality','outputName'].forEach(id=>$(id).addEventListener('change',updateSummary));
  $('confirmPassword').addEventListener('input',()=>{if($('confirmPassword').value && $('confirmPassword').value!==$('password').value){$('confirmPassword').setCustomValidity('Passwords do not match.');}else $('confirmPassword').setCustomValidity('');});
  async function protect(){
    if(!selectedFile){toast('Choose a PDF first.');return;}
    const password=$('password').value, confirm=$('confirmPassword').value;
    if(password.length<8){toast('Use a password of at least 8 characters.');$('password').focus();return;}
    if(password!==confirm){toast('Passwords do not match.');$('confirmPassword').focus();return;}
    if(!window.PDFEncrypt || typeof window.PDFEncrypt.encryptPDF !== 'function'){
      toast('The encryption library did not load. Check your internet connection, then refresh this page.');
      $('statusText').textContent='Encryption library unavailable. Check internet and refresh.';
      return;
    }
    $('protectBtn').disabled=true;$('result').style.display='none';setProgress(8,'Reading your PDF…');
    try{
      setProgress(22,'Loading PDF encryption engine…');
      const inputBytes = new Uint8Array(await selectedFile.arrayBuffer());
      setProgress(42,'Applying AES-256 password encryption…');
      const ownerPassword = Array.from(crypto.getRandomValues(new Uint8Array(24)), b => b.toString(16).padStart(2,'0')).join('');
      const print = !$('allowPrint').checked ? 'none' : ($('printQuality').value === 'low' ? 'low' : 'full');
      const modify = $('allowModify').checked ? 'all' : ($('allowAnnotate').checked ? 'annotate' : 'none');
      const encryptedBytes = await window.PDFEncrypt.encryptPDF(inputBytes, password, {
        algorithm: 'AES-256',
        ownerPassword,
        allowPrinting: $('allowPrint').checked,
        allowHighQualityPrint: $('allowPrint').checked && $('printQuality').value === 'high',
        allowCopying: $('allowCopy').checked,
        allowModifying: $('allowModify').checked,
        allowAnnotating: $('allowAnnotate').checked,
        allowFillingForms: $('allowAnnotate').checked,
        allowExtraction: $('allowCopy').checked,
        allowAssembly: $('allowModify').checked
      });
      setProgress(82,'Checking encrypted output…');
      if(!encryptedBytes || encryptedBytes.length<10) throw new Error('The encryption engine returned an empty output file.');
      // The qpdf WebAssembly lock operation returns the encrypted PDF bytes.
      // Do not block download on a separate metadata-inspection call: that check
      // can fail independently even when encryption itself succeeded.
      outputBlob=new Blob([encryptedBytes],{type:'application/pdf'});
      if(outputUrl)URL.revokeObjectURL(outputUrl);
      outputUrl=URL.createObjectURL(outputBlob);
      setProgress(100,'AES-256 protected PDF ready');
      $('result').style.display='block';
      $('resultText').textContent=`${safeName($('outputName').value)} · ${bytes(outputBlob.size)}. AES-256 encryption applied. Open the downloaded file in a PDF reader to confirm it prompts for your password.`;
      $('statusText').textContent='AES-256 encrypted copy generated in this browser.';
      $('protectBtn').disabled=false;
      if($('downloadAfter').checked) download();
      toast('Password-protected PDF is ready.');
    }catch(err){
      console.error(err);
      $('statusText').textContent='Could not complete protection.';
      toast(err.message||'Unable to protect this PDF. Try another file.');
      $('progressWrap').style.display='none';
    }finally{$('protectBtn').disabled=!(selectedFile && window.PDFEncrypt && typeof window.PDFEncrypt.encryptPDF === 'function');}
  }
  function download(){
    if(!outputBlob){toast('Protect the PDF first.');return;}
    // Create a fresh object URL at click time for more reliable downloads across browsers.
    const url=URL.createObjectURL(outputBlob);
    const a=document.createElement('a');
    a.href=url;
    a.download=safeName($('outputName').value);
    a.style.display='none';
    document.body.appendChild(a);
    a.click();
    a.remove();
    setTimeout(()=>URL.revokeObjectURL(url),60000);
  }
  $('protectBtn').addEventListener('click',protect);
  $('downloadBtn').addEventListener('click',download);
  $('outputName').addEventListener('input',updateSummary);
  updateSummary();
  $('statusText').textContent = (window.PDFEncrypt && typeof window.PDFEncrypt.encryptPDF === 'function')
    ? 'AES-256 encryption engine ready. Your PDF stays on this device.'
    : 'Encryption library unavailable. Check internet and refresh.';
  if (!(window.PDFEncrypt && typeof window.PDFEncrypt.encryptPDF === 'function')) {
    $('protectBtn').disabled = true;
  }
})();
</script>
</body>
</html>