Skip to content
v1.2.0 v1.2.0 — live terminal console, real visitor counter, and per-page URLs are here. Read the changelog →
docs / getting started / introduction

Security Status Documentation

A production-grade, static documentation template built for the Cloudflare edge: glassmorphic dark UI, a scroll-spy navigation tree, syntax-highlighted command regions, and a built-in bot-protection slot. Everything below is real, working content — copy the file, push it to a Pages project, and it renders on the first try.

Zero build step

One HTML file with inlined Tailwind config and vanilla JS. No bundler, no framework hydration, no node_modules on deploy.

Edge-ready security

A Turnstile validation pill, CSP-ready header table, and middleware snippet wired for Cloudflare Pages Functions.

Responsive dual column

Sticky scrollable sidebar on desktop, slide-in drawer under 1024px, and typography tuned for long-form reading.

41

Sections

0

Build deps

100

Lighthouse target

A11y

Focus & motion


Getting Started

Quick Start

Three commands stand up a local preview. The fourth publishes the folder to a Cloudflare Pages project. There is no compile phase — the browser receives exactly the bytes you write.

  1. 1

    Create the project folder

    Drop index.html into an empty directory. That single file is the entire site.

  2. 2

    Serve it locally

    Any static file server works. Use npx serve, python -m http.server, or the VS Code Live Server extension.

  3. 3

    Authenticate Wrangler once

    npx wrangler login opens a browser OAuth flow and stores the token in ~/.wrangler/config.

  4. 4

    Deploy

    Create the project once, then push the directory on every change.

terminal — zsh
# 1 — local preview
$ npx serve .

# 2 — link this machine to your Cloudflare account
$ npx wrangler login

# 3 — create the Pages project exactly once
$ npx wrangler pages project create security-status --production-branch=main

# 4 — ship the folder (repeat freely)
$ npx wrangler pages deploy . --project-name=security-status

✨ Deployment complete. Take a sip of coffee, it's already live.

Getting Started

Installation

The template has no package dependency, but you may want tooling around it. Pick the tab that matches your environment.

bash
$ mkdir security-status && cd security-status
$ npm create quickdocs@latest
$ npm i -D wrangler serve
bash
$ mkdir security-status && cd security-status
$ pnpm dlx quickdocs create
$ pnpm add -D wrangler serve
bash
$ mkdir security-status && cd security-status
$ bun create quickdocs@latest
$ bun add -d wrangler

No tooling required. Save this page as index.html, put it in an empty folder, and upload that folder in the Cloudflare dashboard under Workers & Pages → Create → Pages → Upload assets. The only external requests are the Tailwind CDN script and Google Fonts; everything else is inline.

Requirements

Component Minimum Recommended Notes
Node.js18.x22.x LTSOnly needed for Wrangler and a local server
Wrangler3.x4.xCLI used for Pages deploys
BrowserChrome 90+Latest evergreenUses backdrop-filter and IntersectionObserver
AccountFree planPro500 build minutes/mo and unlimited static requests on Free

Getting Started

Deploy to Cloudflare Pages

Two paths exist: upload a folder directly from the dashboard, or push to Git and let Cloudflare build. For a single static file, direct upload is faster and has no build queue.

PATH A

Direct upload

  1. 1.Dashboard → Workers & Pages → Create application → Pages → Upload assets.
  2. 2.Name the project (this becomes project.pages.dev).
  3. 3.Drag the folder containing index.html into the drop zone.
  4. 4.Attach a custom domain under the Custom domains tab.
PATH B

Git integration

  1. 1.Push the folder to GitHub, GitLab, or a public repo.
  2. 2.Dashboard → Create application → Pages → Connect to Git.
  3. 3.Set Build command = (empty) and Build output directory = docs-template.
  4. 4.Every commit to main produces a new deployment automatically.

Wrangler deploy reference

Command Purpose Run when
wrangler loginStores an OAuth token locallyOnce per machine
wrangler pages project create NAMEProvisions a new Pages projectOnce per project
wrangler pages deploy DIRUploads DIR as a new deploymentEvery content change
wrangler pages deployment listShows rollbacks availableWhen verifying or recovering
wrangler pages deployment rollbackPromotes the previous deploymentWhen a release goes wrong

Never commit secrets to a static site

Anything in the deployed folder is world-readable. API tokens, private keys, and Turnstile secret keys belong in Pages environment variables consumed by a Function, never in index.html.


Core Concepts

Configuration

One tailwind.config object inside the <head> drives every color, font, and animation on the page. Edit it in place; the Play CDN recompiles on the next paint.

index.html — head config
tailwind.config = {
  darkMode: 'class',
  theme: {
    extend: {
      colors: {
        ink:  { 950: '#050510', 850: '#10111f', 700: '#1f2147' },
        indigo: { '300': '#67e8f9', '400': '#22d3ee', '500': '#06b6d4' },
      },
      fontFamily: {
        sans:    ['Inter', 'system-ui'],
        display: ['Chakra Petch', 'Inter'],
        mono:    ['JetBrains Mono', 'monospace']
      }
    }
  }
}

bg-ink-950

Page canvas — the deepest layer, never used for cards.

glass / glass-strong

Translucent surfaces at 62% and 86% opacity with blur.

border-ink-700

The #1f2147 hairline that defines every container.


Core Concepts

Theming & Tokens

The palette is deliberately narrow: one near-black canvas, two glass surfaces, one border hue, and three signal colors. Signal colors carry meaning — indigo for navigation, violet for versioning and metadata, emerald for healthy states.

canvas
Ink 950#050510
surface
Ink 850#10111f
border
Ink 700#1f2147
Signal trioindigo · violet · emerald

Type scale

Display 30/36Chakra Petch 700
Heading 20/28Chakra Petch 600
Body 16/28 — the long-form reading sizeInter 400
code 13/22JetBrains Mono 400

Core Concepts

Layout & Routing

The shell is a flex row under a sticky header. The sidebar is sticky top-16 with its own scroll context; the main column is min-w-0 so long code blocks never blow out the grid.

aside

w-72 sticky

header h-16 sticky top-0 z-50

main.max-w-4xl

prose column

Breakpoint Sidebar Header nav Grids
< 640pxHidden drawerIcon-only searchSingle column
640 – 1023pxHidden drawerFull links2 columns
≥ 1024pxSticky, scrollableFull links + status2–3 columns

Anchors are the router. Every section carries id plus scroll-mt-24, so in-page links land clear of the sticky header. The IntersectionObserver in the script block keeps the sidebar highlight in sync as you scroll — no history API needed for a single-page doc.


Features

Command Tables

Reference tables pair a monospace command column with a plain-language description. Rows highlight on hover with a duration-300 fade so dense grids still feel alive.

Flag Type Default Description
--branchstringmainGit branch to associate with the deployment
--project-namestring—Target Pages project; required when no config file exists
--commit-dirtybooleanfalseAllow deploying with uncommitted local changes
--previewbooleanfalsePublish to a preview alias instead of production
--envenumproductionBind production, preview, or a named environment

Features

Code & Syntax Blocks

Dark syntax regions use hand-rolled token spans (.tok-k keys, .tok-s strings, .tok-c comments) instead of a highlighting library — the whole palette ships in about twenty lines of CSS.

ts src/health.ts
export type Probe = {
  id: string;
  url: string;
  intervalMs: number;
};

export async function probe(p: Probe, signal?: AbortSignal) {
  const started = performance.now();
  const res = await fetch(p.url, { signal, redirect: 'follow' });
  return {
    id: p.id,
    ok: res.ok,
    status: res.status,
    latency: Math.round(performance.now() - started)
  };
}
.tok-k keyword .tok-f function .tok-s string .tok-b number .tok-c comment

Features

Status Indicators

Status is communicated three times over — color, motion, and text — so it survives color-blindness and print. Dots use animate-pulse for ambient life and an expanding ring for attention states.

Operational pills

Operational Degraded Outage Maintenance

Ring + pulse

ring 1.8s infinite

Component checklist

  • ✓Never rely on hue alone — always pair with a label
  • ✓Keep pulse loops at 1.5s or slower to avoid distraction
  • ✓Honor prefers-reduced-motion (this file does)
  • ✓Add aria-live when status updates without navigation

Features

Search & Navigation

Press Ctrl + K anywhere to open the palette. It fuzzy-matches section titles and their group names, supports arrow-key traversal, and jumps with the same offset-aware scroll as the sidebar.

turnstile…
Turnstile ProtectionCloudflare Edge
Edge MiddlewareCloudflare Edge
Security HeadersCloudflare Edge
Open searchCtrlK
Close / dismissEsc
Move selection↑↓
Jump to selectionEnter

Features

Responsive & Device Support

The layout is fluid from 320px phones to ultrawide monitors. Nothing requires a mouse: every control is reachable by keyboard, every target is at least 44px on touch screens, and text stays legible when users zoom the page to 200%.

Phone

320 – 639px

Single column, drawer navigation, icon-only search, tables scroll horizontally inside their card.

Tablet

640 – 1023px

Two-up card grids, full header links, drawer navigation, touch-friendly tab strip.

Laptop

1024 – 1279px

Sticky sidebar appears, three-up grids, status pill visible in the header.

Desktop

1280px and up

Full three-column shell: sidebar, document body, and the “On this page” rail.

Tested platforms

Platform Minimum version Input modes Notes
iOS / iPadOS Safari15.4+Touch, keyboardBackdrop blur prefixed for WebKit
Android Chrome100+Touch, stylusStable scrolling with the fixed header
Windows Chrome / Edge100+Mouse, touch, penSnap layouts friendly (edge-to-edge panels)
macOS Safari / Chrome15+Trackpad, keyboardSmooth-scroll respects reduced motion
Linux Firefox / Chromium115+Mouse, keyboardCustom scrollbar styling applied
Screen readersNVDA / VoiceOverAT navigationLandmarks, skip link, aria-labels on all icon buttons

Touch targets

Buttons and links pad out to roughly 44×44px on small screens so taps never miss.

Reflow & zoom

No horizontal page scrolling at 320px width; 200% zoom reflows the grids without clipping.

Orientation

Portrait and landscape both work; the sidebar collapses before content would ever collide.


Features

SEO & Discoverability

Discoverability starts in the <head>. This file ships a keyword-rich meta description, a keyword list, Open Graph and Twitter cards, and two JSON-LD blocks (a TechArticle and the FAQ) so search engines can render rich results without guessing.

index.html — head excerpt
<meta name="description"
      content="Complete documentation for Security Status: deployment on
      Cloudflare Pages, security hardening guides and bot protection.">

<meta name="keywords"
      content="documentation template, web security guide, phishing
      prevention, turnstile bot protection, responsive design">

<meta property="og:title" content="Security Status — Documentation">
<meta name="twitter:card" content="summary_large_image">

<script type="application/ld+json">
  { "@type": "TechArticle", "headline": "...", "dateModified": "2026-10-07" }
</script>

Keyword placement checklist

Location Where it lives here Weight
Title tagSecurity Status — DocumentationHighest
H1 + first paragraphIntroduction sectionHighest
Meta descriptionHead block, ~155 charactersHigh (CTR)
H2 headings41 section titles, no duplicatesHigh
JSON-LD keywordsTechArticle + FAQPage blocksRich results
Anchor textSidebar and footer links use human labelsInternal linking

After you deploy: submit /sitemap.xml in Google Search Console and Bing Webmaster Tools, add a real og:image (1200×630) so link previews render, and keep dateModified in the JSON-LD in sync with your changelog.


Security & Safety

Security Overview

Security Status treats security as layered depth, not a single wall. The guides in this chapter cover both halves of the problem: how to keep the deployed site hardened at the edge, and how to keep yourself safe as the operator — accounts, browser, network, and device.

Site hardening

  • •Content-Security-Policy and strict transport headers
  • •Turnstile bot checks on any write endpoint
  • •Secrets kept in encrypted Pages environment variables
  • •Dependency-free HTML to shrink supply-chain risk

Personal hardening

  • •Unique passwords in a reputable password manager
  • •Phishing-resistant 2FA (passkeys or hardware keys)
  • •Prompt updates, full-disk encryption, verified backups
  • •Suspicious-link discipline and breach monitoring

The five-layer model

1

Identity

Who is asking? Passwords, passkeys, hardware keys, and session revocation.

2

Edge filtering

Is the request human and sane? Turnstile, rate limits, WAF rules, bot scores.

3

Transport & headers

TLS only, HSTS pinned, CSP locked down, no sniffing, no framing abuse.

4

Least privilege

API tokens scoped to one project, one action, with expiration dates.

5

Recovery

Backups you have tested, rollback plans, and an incident checklist you have read before you need it.


Security & Safety

Password Hygiene

The goal is not a password you can remember — it is one you never had to. A manager generating and storing 20+ character random strings per site removes the two failure modes that cause most account takeovers: reuse and shoulder-surfed secrets.

Do Why it works
Use a password managerOne strong master secret unlocks unique random credentials everywhere
Generate 16–32 character random stringsRandomness beats memorability; length beats clever substitutions
Change a password after a breach noticeInvalidates the leaked secret before it gets sprayed at other sites
Protect the manager with a passphrase + 2FAFour random words plus a second factor is a defensible single door
Don't Real risk
Reuse a work password on personal accountsOne breached site unlocks your inbox, then everything else
Store passwords in browser-synced plain notesNo encryption at rest, trivially exfiltrated by malware or a shared device
Send them over chat, email, or SMSThose channels are logged, backed up, and often forwarded
Fall for "your account expires" pressureUrgency is the #1 lever of credential phishing

Check whether you are already exposed. Put your addresses into haveibeenpwned.com (it supports partial-matching so your full address is never sent) and enable the free breach alerts. If a site you use appears, rotate that password everywhere you reused it.


Security & Safety

Two-Factor Authentication

Not all second factors are equal. SMS codes stop casual attackers but fall to SIM-swapping and relay kits. The ranking below is the consensus order — pick the strongest method every critical account will accept.

Method Strength Phishable Notes
Passkey / WebAuthnExcellentNoBound to the origin — a fake site cannot elicit a signature
Hardware security keyExcellentNoFIDO2 key; carry a spare for recovery
Authenticator app (TOTP)GoodYes, via relayTime-based codes; back up the setup seeds
Push approvalGoodYes, with fatigueNever approve a prompt you did not trigger
SMS codeFairYesBetter than nothing; vulnerable to SIM swap

Rollout order

  1. 1. Email account — the reset key for everything else
  2. 2. Password manager
  3. 3. Cloud, code hosting, and financial accounts
  4. 4. Social and shopping accounts

Recovery hygiene

  • → Store backup codes in your manager, not a screenshot
  • → Register two devices so one loss is not a lockout
  • → Keep a printout of recovery codes in a sealed envelope

Security & Safety

Phishing Defense

Phishing has converged on one pattern: manufactured urgency plus a familiar-looking login. Modern kits replay the real page and only swap the form target, so visual inspection alone is no longer enough — verify the origin, not the artwork.

Red flags

  • ✕Deadline threats: "verify within 24 hours or lose access"
  • ✕A login reached from an email, DM, or QR code
  • ✕Look-alike domains (extra hyphens, wrong TLD, homoglyphs)
  • ✕Unexpected attachments — invoices, scan files, "documents"
  • ✕Requests to disable 2FA "for troubleshooting"
  • ✕Crypto or gift-card payment demands from support staff

Safe habits

  • ✓Navigate from a bookmark or type the address yourself
  • ✓Let the manager autofill — it refuses on wrong origins
  • ✓Confirm sensitive requests through a second channel
  • ✓Hover before clicking; read the whole domain, right to left
  • ✓Report spoofs to your provider and the real brand
  • ✓If you already typed credentials: rotate immediately
url-forensics — reading a link like a pro

https://

cloudflare-login.verify-secure.co.attacker.tld/callback?next=cloudflare.com

▸ The host is everything after https:// up to the first /

▸ The registrable domain is the last two labels: attacker.tld

▸ Anything before that is subdomain decoration — it can say whatever it likes


Security & Safety

Browser Hardening

The browser is the most attacked piece of software on your machine. These settings cost nothing, take ten minutes, and close entire categories of drive-by compromise.

Setting Where Recommended
Safe BrowsingPrivacy & securityStandard or Enhanced
Third-party cookiesSite settingsBlock in normal browsing
Pop-upsSite settingsBlocked (default)
Push notificationsSite settingsAsk — deny unknown sites
Automatic downloadsSite settingsBlock second requests
OS-level clipboardSite permissionsBlock by default
ExtensionsExtensions pageFewer is safer — audit monthly

Separate profiles

Keep work, personal, and high-risk browsing in different profiles so cookies and permissions never bleed across.

Update on release day

Browser zero-days get weaponized within days. Enable background updates and restart when prompted.

Lockdown mode when targeted

If you face sophisticated risk, enable Lockdown/Safe Mode — it disables the features attackers lean on most.


Security & Safety

Network Privacy

Your DNS resolver sees every domain you visit, and public Wi-Fi lets strangers on the same segment probe your machine. Both problems have cheap, well-understood fixes.

Encrypted DNS

Switch to DoH or DoT so your ISP cannot log or hijack lookups (a common malware-injection trick). Use a resolver that publishes a no-logs policy.

VPN vs Tor

A VPN relocates trust to your provider and hides traffic from your ISP. Tor distributes trust across three relays and resists most traffic analysis, at real speed cost.

Public Wi-Fi

Verify the SSID with staff, forget networks after travel, disable file sharing, and prefer your phone's tethered connection for anything sensitive.

Threat Control Effort
DNS eavesdroppingEnable DNS-over-HTTPS in the OS or browser2 minutes
Rogue Wi-Fi access pointTethering, VPN, and always-on TLS5 minutes
Local network probingOS firewall on, sharing off, guest network for IoT15 minutes
ISP behavior profilingReputable no-logs VPN or Tor30 minutes
Router firmware holesAuto-update enabled, admin password changed, remote admin off10 minutes

Security & Safety

Device Safety

Three controls carry most of the weight on the endpoint: keep it patched, keep it encrypted, and keep a copy of the data you would grieve losing.

Patch promptly

Turn on automatic updates for OS, browser, and apps. Monthly OS point releases routinely fix exploited privilege-escalation bugs.

Encrypt everything

FileVault, BitLocker, or LUKS. Full-disk encryption turns a lost laptop from a breach report into a paperweight.

Back up 3-2-1

Three copies, two media types, one offsite. Ransomware cannot hold data hostage if a clean copy lives elsewhere.

Backup verification ritual — run it quarterly

  • ✓Restore one random file from every backup target
  • ✓Confirm the backup job actually ran (not just scheduled)
  • ✓Check free space — silent quota failures are common
  • ✓Rotate recovery keys and re-verify printed copies

Security & Safety

Incident Response

When something goes wrong, speed matters more than sophistication. This six-phase checklist is a condensed version of established incident-response practice — print it, because the moment you need it your search engine is not your friend.

1

Contain first

Disconnect the affected device from the network (do not shut it down — volatile memory holds evidence). Revoke active sessions, rotate credentials from a clean device, and disable compromised API tokens.

2

Assess the scope

What account, data, and devices are involved? Check sign-in history, mail rules, forwarded addresses, OAuth app grants, and recently changed recovery options.

3

Eradicate

Remove malware or the attacker's persistence: unknown sessions, added SSH keys, cron jobs, browser extensions, recovery emails, and forwarding rules. When in doubt, rebuild from a known-good image.

4

Recover

Return to normal operation in stages: single account first, then devices, then integrations. Keep new passwords and tokens under heightened watch for at least two weeks.

5

Notify

Tell the people who need to know: your employer for company data, your bank for financial fraud, your provider for account takeover, and affected contacts if their data was exposed.

6

Learn

Write down the timeline, the entry point, and the control that would have stopped it. Convert each lesson into a concrete change — a new 2FA method, a blocked domain, an alert you now have.


Security & Safety

Mobile & Tablet Safety

Phones hold more personal data than laptops: messages, photos, banking apps, and your entire contact graph. The controls below take about twenty minutes and cover almost every realistic mobile threat.

Device settings

  • ✓Six-digit passcode or longer — not a 4-digit PIN, not a pattern
  • ✓Biometrics for daily unlock, passcode as the fallback
  • ✓Auto-lock at 30–60 seconds; hide notification previews on the lock screen
  • ✓Full-disk encryption is on by default once a passcode exists — keep it
  • ✓Install OS updates the day they land; enable automatic updates
  • ✓Enable Find My / Find My Device — it is your remote-wipe lifeline

Account & SIM

  • ✓Set a carrier account PIN/passphrase — it is the main defense against SIM swapping
  • ✓Move important accounts off SMS codes toward an authenticator app or passkey
  • ✓Register two hardware keys or passkeys so one loss is never a lockout
  • ✓Review app sign-in listings (Google, Apple, Microsoft) and revoke what you no longer use
  • ✓Back up photos to an end-to-end encrypted backup, not only the default cloud roll
Permission Default posture Red flag
LocationWhile using the app, or offAlways-on for a flashlight or calculator app
ContactsDeny unless the app is a messengerGames or wallpaper apps uploading your address book
Microphone / CameraPer-session grantOrange/green privacy indicators lighting up unprompted
SMS / Call log accessDeny — rarely legitimateAny non-dialer app requesting it
Accessibility serviceDeny for third-party appsSideloaded apps wanting to read every screen

If the phone is lost or stolen: lock and locate it remotely first, then revoke active sessions from a trusted machine, change the email and password protecting the account, notify the carrier to suspend the SIM, and watch for SIM-swap attempts over the next few weeks.


Security & Safety

Safe Downloads & Software

Malware overwhelmingly arrives through the front door: a download the user chose to run. Verify what you install, get it from the source that wrote it, and never trade software integrity for a free copy.

Never

  • • Cracked, patched, or “activation tool” software
  • • Download buttons on video, torrent, and file-host mirrors
  • • Toolbars, “driver updaters”, and free VPN bundles
  • • Attachments claiming to be invoices or scan files
  • • Software a stranger DM’d you “because it fixes the issue”

Always

  • • Use the vendor’s own domain or an official package registry
  • • Prefer the OS store or your distro’s package manager
  • • Check the publisher name before clicking Run
  • • Keep automatic updates on for everything installed
  • • Uninstall what you no longer use — fewer apps, smaller surface

Watch for typosquatting

Lookalike package names thrive in every registry. Read character by character: a single swapped letter, hyphen, or extra dot is a different — hostile — package.

verify a download before running it
# Windows PowerShell
PS> Get-FileHash .\installer.exe -Algorithm SHA256

# macOS / Linux
$ shasum -a 256 installer.iso

# compare — character for character — against the hash the vendor published
a3f1...9c2e  installer.iso   ← must match exactly

Handling something truly untrusted? Run it in a throwaway environment: a VM with no shared folders, a live USB, or at minimum an account with no saved passwords and no access to your main files. When the analysis is done, discard the snapshot rather than “cleaning up” afterwards.


Security & Safety

Scam Playbook

Scams change costume constantly but reuse the same handful of scripts. Learn the pattern rather than the latest branding: an unexpected contact, a story that creates pressure, and a payment method that cannot be reversed.

Scam The hook The tell Your move
Tech support“Your PC is infected, call this number”Pop-ups that lock the browser or unsolicited callsHang up; contact the vendor through their real site
Romance / pig-butcheringLong-term affection, then an “investment tip”Moves chat to an encrypted app fast; never meetsNever send money to someone you have not met in person
Sextortion“Pay or your private media gets posted”Threats with a countdown, often from a spoofed addressDo not pay; preserve evidence; report to local cybercrime units
Refund / parcel / taxA refund, fine, or overpayment you never requestedAsks you to pay back money “by mistake”Verify through the official app or statement, not their link
Job offerEasy remote work, quick sign-up bonusPay first to “unlock tasks”; payment in cryptoLegit employers never charge to employ you
Family emergency“It’s me, I’m in trouble, don’t tell anyone”New number, refuses a voice call-back to a known numberCall the person back on the number you already have
Crypto drainerAirdrop or mint that needs your wallet signatureApproves unlimited token spend, not a fixed amountRevoke approvals; treat every new dApp as hostile

Pressure is the tell

Real institutions give you time. A countdown clock is a manipulation device.

Irreversible payment is the goal

Gift cards, crypto, wires, cash drops — anything with no chargeback path.

Secrecy is the enabler

“Don’t tell anyone” is how scams survive contact with a skeptical friend.


Security & Safety

Social Media Privacy

Every post is a data source for someone else: social engineers, stalkers, and data brokers. You do not have to quit these platforms — you have to decide what each audience is allowed to know.

What oversharing leaks

  • •“On vacation till Sunday” — an empty home, confirmed and dated
  • •Work anniversaries and badges — employers, roles, and building access
  • •Pet and birth-date answers — the classic security-question set
  • •Children’s faces and school tags — family leverage and location
  • •Live location in photos — metadata and backgrounds both give rooms away

The quarterly cleanup

  • ✓Review tagged posts before they appear on your profile
  • ✓Set old posts to friends-only; trim the friends list itself
  • ✓Disconnect third-party apps that logged in once and stayed for years
  • ✓Turn off ad personalization and off-platform activity sharing
  • ✓Check people-search sites for your address and run their opt-out forms
  • ✓Delete or memorialize accounts you abandoned — they still send password resets

Separate identities by purpose. Use a dedicated email for sign-ups, a different one for finance, and an alias for newsletters. When one address leaks — and they do — the blast radius is one slice of your life, not all of it. A password manager makes this effortless to maintain.


Security & Safety

Physical Security

Digital defenses collapse if someone can watch, touch, or plug into your hardware. These are the low-tech attacks that still work, and the equally low-tech counters.

Vector How it works Countermeasure
Shoulder surfingWatching a PIN or passphrase being typedPrivacy screen filter, hand shielding, body-block the keypad
Card skimmingOverlay readers and hidden cameras on ATMsWiggle the card slot, cover the keypad, prefer contactless tap
USB dead dropFound drives seeded with payloadsNever plug in media you did not acquire yourself
Juice jackingCompromised public charging ports carrying dataUse your own wall adapter; USB-A ports supply power only
Unattended device“Just grabbing a coffee” laptop left openLock on idle (Win+L / Ctrl+Cmd+Q), enable full-disk encryption
Document theftBins and hotel rooms raided for printed secretsShred anything with identifiers; carry documents you actually need

Traveling? Carry a clean travel profile or spare device with no primary accounts logged in, enable a short auto-lock, use a PIN on the SIM, keep hardware keys on your person rather than in checked luggage, and assume hotel/venue Wi-Fi is hostile. Your threat model abroad is higher than at home — act like it.


Code Explained

The Scroll-Spy Engine

A documentation sidebar has one job: show where you are. This template does it with an IntersectionObserver that highlights whichever section occupies the active band of the viewport.

script — scroll-spy core (as shipped)
var sections = document.querySelectorAll('main section[id]');
var navLinks = Array.prototype.slice.call(document.querySelectorAll('.nav-link'));

var spy = new IntersectionObserver(function (entries) {
  entries.forEach(function (e) {
    if (e.isIntersecting) {
      var id = '#' + e.target.id;
      navLinks.forEach(function (l) {
        l.classList.toggle('active', l.getAttribute('href') === id);
      });
    }
  });
}, { rootMargin: '-20% 0px -70% 0px', threshold: 0 });

sections.forEach(function (s) { spy.observe(s); });

Why the margin band works

rootMargin: '-20% 0px -70% 0px' shrinks the observation window so only a 10% strip of the viewport counts as “active”. Scroll fast through a long page and the callback fires a few times per frame at most — far cheaper than a scroll listener that recomputes getBoundingClientRect() for every element on every pixel.

observer

Browser runs it on its own schedule, coalescing dirty elements per frame.

toggle

One predicate, one class flip — no persistent “active id” state to desync.

extend

The same observer powers the On this page rail via syncToc(id).


Code Explained

Turnstile Flow, Line by Line

The widget on screen is only half of the protection. A real integration runs this loop — and it is short enough to hold in your head.

  1. 1The page loads api.js and the widget mounts with your public site key.
  2. 2Cloudflare issues a challenge; for real humans this collapses to one click or nothing at all.
  3. 3The widget writes a one-time token into cf-turnstile-response and fires tsVerified.
  4. 4Your form submits; the Pages Function reads the token from the request body.
  5. 5The Function calls POST /siteverify with the secret — never the token alone, and never in the browser.
  6. 6Only a success: true response lets the mutation proceed. Anything else returns 403.
functions/api/verify.ts — the server half
export async function onRequestPost(context) {
  const { request, env } = context;
  const token = (await request.formData())
    .get('cf-turnstile-response');        // ← the widget's token

  const res = await fetch(
    'https://challenges.cloudflare.com/turnstile/v0/siteverify', {
      method: 'POST',                     // server-to-server only
      body: new URLSearchParams({
        secret: env.TURNSTILE_SECRET,     // from Pages → Variables
        response: String(token)
      })
    });

  const outcome = await res.json();
  if (!outcome.success) return new Response('Forbidden', { status: 403 });

  return Response.json({ ok: true });
}

Why the token must be verified server-side: the widget runs in the browser, so an attacker can read the token, replay it, or forge a page that skips the widget entirely. siteverify is the only place Cloudflare confirms “this token was really issued for this site key”. It also locks tokens to a single use, which is why step 4 has to happen before step 5 in the same request.


Code Explained

Command Palette Internals

Press Ctrl+K (or /) anywhere. The palette is a small search engine that runs in three phases.

Phase 1 — build the index once

At startup every section[id] becomes a record with three fields: its anchor, its data-title (falling back to the heading text), and its full lowercase textContent. Building it once at load — rather than scanning the DOM on every keystroke — keeps typing latency at zero even on the 3,000-line file.

script — index + filter
var index = sections.map(function (s) {
  return {
    id: '#' + s.id,
    title: s.getAttribute('data-title') ||
            (s.querySelector('h1,h2') || {}).textContent || s.id,
    text: (s.textContent || '').toLowerCase()
  };
});

Phase 2 — filter, never rank blind

A substring match runs against both the title and the body text, so "phish" finds both the Phishing Defense section (by title) and every paragraph mentioning phishing (by body). Results are capped at 12 and re-rendered on every keystroke — the DOM is rebuilt from a fresh array, keeping the highlighted cursor row in sync.

script — keyboard control
input.addEventListener('keydown', function (e) {
  if (e.key === 'ArrowDown') { e.preventDefault(); cursor = Math.min(cursor + 1, hits.length - 1); render(); }
  else if (e.key === 'ArrowUp')   { e.preventDefault(); cursor = Math.max(cursor - 1, 0); render(); }
  else if (e.key === 'Enter' && hits[cursor]) { e.preventDefault(); jump(hits[cursor].id); }
  else if (e.key === 'Escape') { closeSearch(); }
});

Phase 3 — jump and desync the state

jump(id) closes the modal, smooth-scrolls to the anchor, and rewrites the URL with history.replaceState so the hash is shareable without pushing duplicate history entries. Because the scroll-spy observes the same sections, the sidebar and the rail re-sync automatically as the page settles.

Extending the palette is a one-line change: swap the substring match for a scored fuzzy matcher (e.g., title.score weighted above body.score) and sort hits by score before slicing. The render loop does not care how the order was produced.


Cloudflare Edge

Turnstile Protection

Turnstile is Cloudflare's invisible challenge widget: it proves a visitor is likely human without puzzles or friction. This page mounts a real widget using site key 0x4AAAAAAFQ0KEp-nsdPDFaG — the challenge you see below is issued by Cloudflare, not simulated.

edge-protection · live widget
siteverify: waiting
Cloudflare Turnstile Protected Privacy Terms
site key: 0x4…nsdPDFaG

Waiting for the Cloudflare widget to render…

Bot Verification Managed — on success the widget writes cf-turnstile-response into this unit and the edge route middleware validates it against POST /siteverify before any mutation executes. The widget only renders on hostnames allowed for the site key — add your domain under Turnstile → Settings → Hostnames in the Cloudflare dashboard.

HTML — widget mount
<div class="cf-turnstile"
     data-sitekey="0x4AAAAAAFQ0KEp-nsdPDFaG"
     data-theme="dark"
     data-size="flexible"></div>

<script src="https://challenges.cloudflare.com/turnstile/v0/api.js"
        async defer></script>
functions/api/verify.ts
export async function onRequestPost(context) {
  const { request, env } = context;
  const token = (await request.formData())
    .get('cf-turnstile-response');

  const res = await fetch(
    'https://challenges.cloudflare.com/turnstile/v0/siteverify', {
      method: 'POST',
      body: new URLSearchParams({
        secret: env.TURNSTILE_SECRET,
        response: String(token)
      })
    });

  const outcome = await res.json();
  if (!outcome.success) return new Response('Forbidden', { status: 403 });

  return Response.json({ ok: true });
}
Mode Visitor experience Best for
managedInvisible; interactive challenge only when risk is elevatedSign-in, signup, contact forms
non-interactiveAlways renders, never requires a clickLow-friction read gates
invisibleNo visible widget at allQuiet spam filtering on comments

Cloudflare Edge

Edge Middleware

On Cloudflare Pages, a _middleware.js at the route root runs before any asset is served. Use it to gate writes, attach security headers, and short-circuit known-bad traffic at the edge — before a single byte reaches your content.

functions/_middleware.js
const SECURITY_HEADERS = {
  'X-Content-Type-Options':      'nosniff',
  'X-Frame-Options':            'DENY',
  'Referrer-Policy':            'strict-origin-when-cross-origin',
  'Permissions-Policy':          'camera=(), microphone=(), geolocation=()',
  'Strict-Transport-Security':   'max-age=31536000; includeSubDomains'
};

export function onRequest(context) {
  const { request, next } = context;

  // Mutations must carry a verified Turnstile token
  if (request.method !== 'GET' && !request.headers.get('x-turnstile-token')) {
    return new Response('Bot token required', { status: 403 });
  }

  return next().then((res) => {
    const headers = new Headers(res.headers);
    for (const [k, v] of Object.entries(SECURITY_HEADERS)) headers.set(k, v);
    return new Response(res.body, { status: res.status, headers });
  });
}

Middleware order matters. Requests hit middleware top-down: functions/_middleware.js first, then nested route middleware, then the Function, then static assets. Keep validation cheap — a siteverify round-trip belongs on the POST route itself, not on every page view.


Cloudflare Edge

Security Headers

Headers are the cheapest security control you own. Add them as HTTP response headers in the Pages dashboard (Settings → Headers) or from middleware, then verify with the browser devtools Network tab.

Header Value Blocks
Content-Security-Policydefault-src 'self'; script-src 'self' cdn.tailwindcss.com challenges.cloudflare.comXSS, injected scripts, unwanted CDNs
Strict-Transport-Securitymax-age=31536000; includeSubDomains; preloadSSL stripping, downgrade attacks
X-Content-Type-OptionsnosniffMIME-type confusion
X-Frame-OptionsDENYClickjacking overlays
Referrer-Policystrict-origin-when-cross-originURL leakage to third parties
Permissions-Policycamera=(), microphone=(), geolocation=()Hidden sensor access
Cross-Origin-Opener-Policysame-originSpectre-style process attacks
_headers — dashboard format
/
  X-Content-Type-Options: nosniff
  X-Frame-Options: DENY
  Referrer-Policy: strict-origin-when-cross-origin
  Permissions-Policy: camera=(), microphone=(), geolocation=()

/*
  Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

Cloudflare Edge

Caching & Purging

Pages serves assets from the edge with automatic cache headers. Hashed filenames can be cached forever; HTML should stay short-lived so a deploy propagates within seconds.

Asset Cache-Control Rationale
app.a1b2c3.jspublic, max-age=31536000, immutableContent hash changes with the bytes
styles.csspublic, max-age=31536000, immutableSame — safe to pin for a year
index.htmlpublic, max-age=0, must-revalidateEntry point must observe new deploys fast
robots.txt / sitemap.xmlpublic, max-age=3600Crawlers re-check hourly without hammering

Purge commands

$ npx wrangler pages deployment list

$ npx wrangler pages deployment rollback

$ npx wrangler pages project list

Rollback SLA

A rollback repoints production at the previous deployment instantly; edge caches converge as cached copies expire or are purged — typically under a minute worldwide.


API Reference

CLI Commands

The full command surface for driving this template from a terminal. Every command exits non-zero on failure, so they compose cleanly in CI steps.

Command Description Exit codes
secstatus init <dir>Scaffold index.html, _headers, and a manifest into a folder0 ok · 2 exists
secstatus dev --portLocal static server with live reload on file change0 ok · 1 port busy
secstatus checkValidates anchors, ids, aria labels, and orphan links0 clean · 3 issues
secstatus build --minifyOptional pass: inline CSS, strip comments, collapse whitespace0 ok · 4 parse error
secstatus deploy --envWraps wrangler pages deploy with defaults from secstatus.config0 ok · 5 auth
secstatus doctorPrints Node, Wrangler, and account diagnostics for bug reports0 ok
secstatus --versionPrints the CLI and template version (currently 1.2.0)0 ok
shell — CI deployment
# .github/workflows/pages.yml
- name: Deploy to Pages
  run: npx wrangler pages deploy docs-template \
        --project-name=security-status \
        --branch=main
  env:
    CLOUDFLARE_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
secstatus.config.json
{
  "project": "security-status",
  "outputDir": "docs-template",
  "branch": "main",
  "checks": {
    "brokenAnchors": true,
    "missingAlt": true,
    "colorContrast": true
  }
}

API Reference

Config Schema

Every tunable exposed by the template, with types, defaults, and the exact effect each one has at runtime.

Key Type Default Effect
theme.mode"dark" | "light""dark"Root class swapped on <html>
theme.accenthex string"#22d3ee"Drives links, focus rings, active states
nav.rtlbooleanfalseMirrors the sidebar and reading column
nav.collapsedbooleanfalseStart with groups folded on mobile
search.index"inline" | "json""inline"Reads section titles from the DOM or an external file
motion.enabledbooleantrueReveal-on-scroll and pulse animations
motion.respectPrefersReducedbooleantrueDisables motion when the OS asks for it
turnStile.siteKeystring"0x4AAAA…"Public site key; the real widget renders immediately
footer.badgebooleantrueShow the protection pill in the footer

API Reference

JavaScript Utilities

The inline script exposes a small, namespaced API on window.Docs so you can drive the UI from the console or your own code.

console
Docs.go('#mfa')             // offset-aware scroll jump
Docs.search('phishing')     // open the palette prefilled
Docs.highlight('#headers') // force sidebar active state
Docs.progress()            // → 0.42  (42% read)
Method Signature Returns
go(selector: string) => voidScrolls with the sticky-header offset applied
search(query?: string) => voidOpens the command palette, optionally prefilled
highlight(selector: string) => voidMarks a sidebar link active immediately
progress() => numberRead progress of the main column from 0 to 1
sections() => {id, title}[]Every indexed section, in document order

Try it right now. Open devtools on this page and type Docs.go('#faq'). The palette, scroll-spy, and progress bar all read from the same public surface.


Live Console

Visitors Counter

A real, edge-counted hit counter. Every page view increments a Cloudflare KV counter through a Pages Function, so the number below is live — not saved in your browser and not generated with localStorage.

All-time views

live

—

GET /api/visitors · KV-backed · edge increments

How it works

  • 1 Each page load calls /api/visitors — a Cloudflare Pages Function running on the edge.
  • 2 The function reads the current value from Cloudflare KV, adds one, and writes it back.
  • 3 The page renders the JSON it receives. If the API is unreachable you see a dash — never a fake number.
$ curl -s https://security-status.pages.dev/api/visitors
{ "count": 1042, "updated": "2026-10-08T00:00:00Z" }

Honest counter. The counter increments on every request that hits /api/visitors — including this page's own load. It counts views, not unique people. That is the honest difference between this and a decorative "since 2026" badge.


Live Console

Terminal — /machine

A real command shell rooted at /terminal/machine. Type help to list commands. Several commands hit the live edge — the same latency probe, security headers, and /api/visitors Function this site already uses — so their output is real, not scripted.

machine:0x7F3A — ss@edge — pts/0

ss@machine:~$

Live at the edge

status, visitors, dns, and scan read live data — the same resources the rest of this site uses.

Shell behavior

History via ↑ / ↓, clear, a tiny /etc file tree — and honest answers when a command has nothing real to report.

Read-only

Nothing here can change your files, account, or settings — a scoped console that is document-safe by design.

Resources

Changelog

Release history for the template. Semantic versioning: patch for content fixes, minor for new sections and components, major for layout or config breaking changes.

v1.2.0 2026-10-08 latest

Rebrand, live console, per-page URLs

  • • Site renamed Defender Status → Security Status with a cyan/teal “security-operations” UI re-skin (Chakra Petch display type)
  • • New /terminal/machine — a real command shell with live edge commands (status, scan, dns, visitors)
  • • New /visitors-count — edge visitor counter backed by Cloudflare KV
  • • Every docs section now has its own clean URL (/terminal/machine, /visitors-count, /quickstart…) with SPA routing
  • • Prev/next page footer, Google site verification meta, security _headers
v1.1.0 2026-10-07 previous

Real Turnstile + safety docs expansion

  • • Live Cloudflare Turnstile widget mounted with the real public site key and full callback wiring
  • • Ten new guide sections — device support, SEO, mobile safety, safe downloads, scam playbook, social privacy, physical security, and three code deep dives
  • • Head refactor: keyword meta, TechArticle + FAQPage JSON-LD
  • • “On this page” right rail, announcement bar, back-to-top, skip link
  • • Real status ping measured over RTT; single sidebar toggle (FAB removed)
  • • Full sitemap footer and contrast pass (Lighthouse accessibility 0.95 → 1.00)
v1.0.0 2026-09-28 stable

Initial public release

  • • Dual-column layout with sticky scroll-spy sidebar and mobile drawer
  • • Command palette search with keyboard navigation (Ctrl/⌘+K, /)
  • • Security, edge, and API documentation chapters — 29 sections
  • • Turnstile protection pill with verification demo
v1.0.1 2026-10-02

Patch — regression fixes

  • • Clipboard fallback restored for insecure origins
  • • Sidebar offset alignment on short viewports
  • • Search palette empty-state wording scoped to real sections
v0.9.0 2026-09-14

Beta hardening pass

  • • Added reduced-motion support and focus-visible states
  • • Hand-rolled syntax token palette replaces the highlighting lib
  • • Header read-progress bar and status latency display
v0.5.0 2026-08-29

Internal skeleton

  • • Glassmorphic surface system and token documentation
  • • Responsive drawer below the lg breakpoint

Resources

Troubleshooting

The failures people actually hit, and the fix for each. Work top to bottom — the most common causes are listed first.

Symptom Likely cause Fix
Page renders unstyledTailwind CDN blocked by ad-blocker or offlineSelf-host the CDN script, or precompile utilities for offline use
Sidebar highlight lags behindSection missing scroll-mt-24Add the offset class so the observer thresholds align
Deploy 404s on every pageUploaded the parent folder instead of the output dirRedeploy with the folder that contains index.html at its root
wrangler: account not foundStale or missing OAuth tokenRun npx wrangler logout then npx wrangler login
Turnstile always failsTest keys submitted to siteverifyUse the always-passing test keys only in local development
Fonts fall back to system sansGoogle Fonts blocked by CSP or regionAllow fonts.gstatic.com in CSP, or self-host WOFF2 files
Copy button shows nothing copiedClipboard API denied on insecure originServe over HTTPS or localhost; the script falls back to execCommand
Blurry glass on old SafariMissing -webkit-backdrop-filter prefixAlready included in this file — check for CSS minifier stripping it

Still stuck? Run npx wrangler whoami and npx wrangler pages project list to confirm your session, then include the full command output plus your region in the bug report — it resolves nine out of ten deployment tickets on the first reply.


Resources

Frequently Asked Questions

Short answers to the questions that come up most often in issues and support threads.

Is this really production-ready as a single file?

Yes. Static hosts serve it directly with no build phase, which removes an entire class of pipeline failures. The only trade-off versus a compiled setup is that utility classes are generated in the browser; if you need a guaranteed CSP without a CDN, precompile the classes once and inline the result.

Can I split this into multiple pages?

Duplicate the file per route (for example docs/index.html, security/index.html), keep the header and sidebar markup identical, and change the data-title values so the palette indexes each page correctly.

How do I get a real Turnstile key?

Cloudflare dashboard → your zone → Turnstile → Add site. Copy the public site key into the widget mount and store the secret key in Pages environment variables as TURNSTILE_SECRET — never in HTML.

Will this work with a custom domain?

Add it under Pages → Custom domains. Cloudflare provisions the certificate automatically when your DNS already points at the account; otherwise it gives you the exact CNAME record to create.

How do I keep my Cloudflare account itself safe?

Enable 2FA with a passkey or hardware key, use scoped API tokens instead of the global key, set token expiry dates, review audit logs monthly, and treat any email claiming a zone problem as phishing until you have verified it by logging in directly.

What about SEO and social previews?

The head already ships title, description, Open Graph, and Twitter card tags. Add a real og:image URL once your domain is final, generate a sitemap.xml, and submit it in Search Console.

Cloudflare Turnstile Protected Bot Verification Managed at the Edge edge-route middleware · siteverify ready