remove flaticon

This commit is contained in:
2025-09-18 09:54:35 -05:00
parent 45cf01edaf
commit 5e1d320fa9
11 changed files with 224 additions and 325 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 278 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 247 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 247 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

View File

@@ -1,87 +1,164 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black"> <meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta name="apple-mobile-web-app-title" content="nKode Authentication Evolved"> <meta
<meta name="viewport" content="width=device-width, initial-scale=1.0"> name="apple-mobile-web-app-title"
content="nKode Authentication Evolved"
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>nKode</title> <title>nKode</title>
<link rel="icon" type="image/png" href="assets/n.png"/> <link rel="icon" type="image/png" href="assets/n.png" />
<link rel="apple-touch-icon" href="assets/n.png"> <link rel="apple-touch-icon" href="assets/n.png" />
<!-- Tailwind CSS CDN --> <!-- Tailwind CSS CDN -->
<script src="https://cdn.tailwindcss.com"></script> <script src="https://cdn.tailwindcss.com"></script>
<!-- Google tag (gtag.js) --> <!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-SR0MLMR2MR"></script> <script
async
src="https://www.googletagmanager.com/gtag/js?id=G-SR0MLMR2MR"
></script>
<script> <script>
window.dataLayer = window.dataLayer || []; window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);} function gtag() {
gtag('js', new Date()); dataLayer.push(arguments);
}
gtag("js", new Date());
gtag('config', 'G-SR0MLMR2MR'); gtag("config", "G-SR0MLMR2MR");
</script> </script>
</head> </head>
<body> <body>
<div class="bg-white"> <div class="bg-white">
<header class="absolute inset-x-0 top-0 z-50"> <header class="absolute inset-x-0 top-0 z-50">
<nav class="fixed top-0 w-full z-50 flex items-center justify-between p-6 px-8 bg-white" aria-label="Global"> <nav
class="fixed top-0 w-full z-50 flex items-center justify-between p-6 px-8 bg-white"
aria-label="Global"
>
<div class="flex flex-1"> <div class="flex flex-1">
<a href="#" class="-m-1.5 p-1.5"> <a href="#" class="-m-1.5 p-1.5">
<img class="h-8 w-auto" src="assets/lightmodenkode.svg" alt=""> <img class="h-8 w-auto" src="assets/lightmodenkode.svg" alt="" />
</a> </a>
</div> </div>
<div class="lg:flex lg:hidden"> <div class="lg:flex lg:hidden">
<button id="open-menu" type="button" class="-m-2.5 inline-flex items-center justify-center rounded-md p-2.5 text-gray-400"> <button
id="open-menu"
type="button"
class="-m-2.5 inline-flex items-center justify-center rounded-md p-2.5 text-gray-400"
>
<span class="sr-only">Open main menu</span> <span class="sr-only">Open main menu</span>
<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" data-slot="icon"> <svg
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" /> class="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
aria-hidden="true"
data-slot="icon"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"
/>
</svg> </svg>
</button> </button>
</div> </div>
<div class="hidden lg:flex items-center gap-x-12"> <div class="hidden lg:flex items-center gap-x-12">
<div class="flex gap-x-6 text-lg font-semibold leading-6 text-black"> <div
<a href="#create-an-nkode">How to create an nKode</a> class="flex gap-x-6 text-lg font-semibold leading-6 text-black"
<a href="#how-nkode-works">How nKode Works</a> >
<a href="#faq">FAQ</a>
<a href="#contact-us">Contact Us</a> <a href="#contact-us">Contact Us</a>
</div> </div>
<div class="ml-auto"> <div class="ml-auto">
<button class="bg-orange-500 text-white py-2 px-4 rounded-full hover:bg-orange-600 transition duration-200 text-sm sm:text-lg"> <button
<a href="https://app.nkode.tech">Try nKode <span aria-hidden="true">&rarr;</span></a> class="bg-orange-500 text-white py-2 px-4 rounded-full hover:bg-orange-600 transition duration-200 text-sm sm:text-lg"
>
<a href="https://auth.nkode.tech"
>Try nKode <span aria-hidden="true">&rarr;</span></a
>
</button> </button>
</div> </div>
</div> </div>
</nav> </nav>
<!-- Mobile menu, show/hide based on menu open state. --> <!-- Mobile menu, show/hide based on menu open state. -->
<div id="mobile-menu" class="lg:hidden hidden" role="dialog" aria-modal="true"> <div
id="mobile-menu"
class="lg:hidden hidden"
role="dialog"
aria-modal="true"
>
<!-- Background backdrop, show/hide based on slide-over state. --> <!-- Background backdrop, show/hide based on slide-over state. -->
<div class="fixed inset-0 z-50"></div> <div class="fixed inset-0 z-50"></div>
<div class="fixed inset-y-0 right-0 z-50 w-full overflow-y-auto bg-white px-6 py-6 lg:max-w-sm lg:ring-1 lg:ring-white/10"> <div
class="fixed inset-y-0 right-0 z-50 w-full overflow-y-auto bg-white px-6 py-6 lg:max-w-sm lg:ring-1 lg:ring-white/10"
>
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<a href="#" class="-m-1.5 p-1.5"> <a href="#" class="-m-1.5 p-1.5">
<span class="sr-only">Your Company</span> <span class="sr-only">Your Company</span>
<img class="h-8 w-auto" src="assets/lightmodenkode.svg" alt=""> <img
class="h-8 w-auto"
src="assets/lightmodenkode.svg"
alt=""
/>
</a> </a>
<button id="close-menu" type="button" class="-m-3 rounded-md p-4 text-black"> <button
id="close-menu"
type="button"
class="-m-3 rounded-md p-4 text-black"
>
<span class="sr-only">Close menu</span> <span class="sr-only">Close menu</span>
<svg class="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" data-slot="icon"> <svg
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" /> class="h-8 w-8"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
aria-hidden="true"
data-slot="icon"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M6 18 18 6M6 6l12 12"
/>
</svg> </svg>
</button> </button>
</div> </div>
<div class="mt-6 flow-root"> <div class="mt-6 flow-root">
<div class="-my-6 divide-y divide-white/25"> <div class="-my-6 divide-y divide-white/25">
<div class="space-y-2 py-6"> <div class="space-y-2 py-6">
<a href="#create-an-nkode" class="-mx-3 block rounded-lg px-3 py-2 text-base font-semibold leading-7 text-black hover:bg-gray-200 mobile-nav">How to create an nKode</a> <a
<a href="#how-nkode-works" class="-mx-3 block rounded-lg px-3 py-2 text-base font-semibold leading-7 text-black hover:bg-gray-200 mobile-nav" >How nKode Works</a> href="#create-an-nkode"
<a href="#faq" class="-mx-3 block rounded-lg px-3 py-2 text-base font-semibold leading-7 text-black hover:bg-gray-200 mobile-nav">FAQ</a> class="-mx-3 block rounded-lg px-3 py-2 text-base font-semibold leading-7 text-black hover:bg-gray-200 mobile-nav"
<a href="#contact-us" class="-mx-3 block rounded-lg px-3 py-2 text-base font-semibold leading-7 text-black hover:bg-gray-200 mobile-nav">Contact Us</a> >How to create an nKode</a
>
<a
href="#how-nkode-works"
class="-mx-3 block rounded-lg px-3 py-2 text-base font-semibold leading-7 text-black hover:bg-gray-200 mobile-nav"
>How nKode Works</a
>
<a
href="#faq"
class="-mx-3 block rounded-lg px-3 py-2 text-base font-semibold leading-7 text-black hover:bg-gray-200 mobile-nav"
>FAQ</a
>
<a
href="#contact-us"
class="-mx-3 block rounded-lg px-3 py-2 text-base font-semibold leading-7 text-black hover:bg-gray-200 mobile-nav"
>Contact Us</a
>
</div> </div>
<button class="bg-orange-500 text-white py-2 px-4 rounded-full hover:bg-orange-600 transition duration-200 text-sm sm:text-large"> <button
<a href="https://app.nkode.tech">Try nKode <span aria-hidden="true">&rarr;</span></a> class="bg-orange-500 text-white py-2 px-4 rounded-full hover:bg-orange-600 transition duration-200 text-sm sm:text-large"
>
<a href="https://auth.nkode.tech"
>Try nKode <span aria-hidden="true">&rarr;</span></a
>
</button> </button>
</div> </div>
</div> </div>
@@ -89,250 +166,72 @@
</div> </div>
</header> </header>
<main> <main>
<div class="mx-auto lg:max-w-3xl sm:max-w-xl max-w-sm mb-8 mt-24"> <div class="mx-auto lg:max-w-3xl sm:max-w-xl max-w-sm mb-8 mt-24">
<!-- <div style="position: relative; padding-bottom: 56.25%; height: 0;"><iframe src="https://www.loom.com/embed/262baf04da87435a9be650696dc2c500?sid=1246237b-676d-413b-b4bb-af5018ad0689" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></iframe></div>-->
<div class="flex flex-col items-center text-black mt-24 mb-12"> <div class="flex flex-col items-center text-black mt-24 mb-12">
<div class="text-5xl lg:text-7xl tracking-tight"> <div class="text-5xl lg:text-7xl tracking-tight">
<p> <p>
<span class="text-orange-600 font-semibold">Easier</span> to remember <span class="text-orange-600 font-semibold">Easier</span> to
remember
</p> </p>
<p> <p>
More <span class="text-orange-600 font-semibold">secure</span> than More
</p> <span class="text-orange-600 font-semibold">secure</span> than
<p>
a password
</p> </p>
<p>a password</p>
</div> </div>
<div class="text-xl mt-8"> <div class="text-xl mt-8">
<p>nKode replaces your password with easy to remember icons.</p> <p>nKode replaces your password with easy to remember icons.</p>
</div> </div>
</div> </div>
<div> <div></div>
</div>
<div class="text-center mt-8 mb-24"> <div class="text-center mt-8 mb-24">
<button class="bg-orange-500 text-white py-2 px-4 rounded-full hover:bg-orange-600 transition duration-200 text-sm sm:text-lg"> <button
<a href="https://app.nkode.tech">Try nKode <span aria-hidden="true">&rarr;</span></a> class="bg-orange-500 text-white py-2 px-4 rounded-full hover:bg-orange-600 transition duration-200 text-sm sm:text-lg"
>
<a href="https://auth.nkode.tech"
>Try nKode <span aria-hidden="true">&rarr;</span></a
>
</button> </button>
</div> </div>
<section id="create-an-nkode" class="scroll-mt-24">
<h3 class="text-4xl">How to create an nKode</h3>
<p class="text-2xl mt-4">1. Enter your email</p>
<img class="w-3/4 mx-auto mt-8" src="assets/signup.png">
<h4 class="text-2xl">2. Set your nKode</h4>
<p class="mt-8 text-xl">Select 4 icons that will be your nKode. Icons can not be repeated.</p>
<p class="text-xl">Example: pizza, ladybug, wine, baseball</p>
<div class="mt-8 flex flex-row">
<img class="w-16" src="assets/pizza.png">
<img class="w-16" src="assets/ladybug.png">
<img class="w-16" src="assets/wine.png">
<img class="w-16" src="assets/baseball.png">
</div>
<img class="w-3/4 mx-auto mt-8" src="assets/set_nkode.png">
<h4 class="text-2xl">3. Confirm your nKode</h4>
<p class="mt-8 text-xl">Confirm your nKode by re-entering it.</p>
<img class="w-3/4 mx-auto mt-8" src="assets/confirm_nkode.png">
<h4 class="text-2xl">4. Login with nKode</h4>
<p class="mt-8 text-xl">Once you've confirmed, the login screen will open. Enter your nKode to login</p>
<img class="w-3/4 mx-auto mt-8" src="assets/login1.png">
</section>
<section id="how-nkode-works" class="scroll-mt-24">
<h3 class="text-4xl mt-8">How nKode Works</h3>
<h4 class="text-2xl mt-4">Keypad Settings</h4>
<p>
Your nKode keypad is configurable.
Under advanced settings, you can change the number of keys and the number of icons per key.
</p>
<img class="w-3/4 mx-auto mt-8" src="assets/advanced_settings.png">
<h4 class="text-2xl mt-4">Account Creation</h4>
<p>
The server is able to deduce your nKode from two entries.
In the set and confirm keypads below, no icon in the set keypad share a key with any other icon in the confirm keypad.
This is called an icon dispersion.
</p>
<div class="flex flex-row">
<img class="w-1/2 mx-auto mt-8" src="assets/set_nkode.png">
<img class="w-1/2 mx-auto mt-8" src="assets/confirm_nkode.png">
</div>
<h4 class="text-2xl mt-4">Icon Dispersion</h4>
<p>
The login keypad looks different from the set and confirm keypads.
It has three more icons per key.
A dispersion is possible if the number of icons per key is less than or equal to the total number of keys.
Since the login keypad has more icons per key than keys, we call this a dispersion-resistant keypad.
If a malicious actor steals your keypad, they can use your keypad to phish for your nKode.
If the login keypad was dispersable, an attack might go like this:
</p>
<ol class="list-decimal list-inside mt-4 mb-4 space-y-2">
<li>You click a malicious link from your email or text saying you need to authorize USPS to send you a package (or whatever the latest scam is today).</li>
<li>You're redirected to a site with your nKode keypad requesting authorization with your nKode.</li>
<li>You enter your nKode, but you're informed you entered the wrong nKode.</li>
<li>The attacker disperses your keypad and requests you enter your nKode again.</li>
<li>You enter it again, and your nKode is stolen.</li>
</ol>
<p>
The greater the difference between the number of icons per key and the number of keys, the greater the dispersion resistance.
This comes with trade-offs.
If there are too few keys, it becomes easier to randomly enter keys and accidentally get into your account without actually knowing your nKode.
If you increase the number of keys without increasing the number of icons per key, your keypad becomes more dispersable.
If you have too many icons and keys, the keypad is too busy, making it challenging to find your icons.
</p>
<h4 class="text-2xl mt-4">Server-Side Attributes</h4>
<p>
A traditional password is composed of ASCII and sometimes Unicode characters.
These are salted, hashed, and stored in a database.
nKode is similar.
An unsigned 64-bit integer represents every icon, though it can be a byte array of any size.
These server-side attributes can be rotated daily, weekly, or any other frequency desired.
Here's how it works:
</p>
<ol class="list-decimal list-inside mt-2 space-y-2">
<li>An administrator or cron job starts the server-side attribute renewal.</li>
<li>The server-side attributes are rotated, and an intermediate transformation is applied to the user's server-side keys</li>
<li>After a successful login, and the user's keys, salt, and hash are all replaced.</li>
</ol>
<h4 class="text-2xl mt-4">Login</h4>
<p>
Every time you log in, your icons are randomly shuffled.
Icons don't move to arbitrary locations within the key; icons are a part of a set.
You can identify the set by its position within the key.
In the example below, you can see some icons haven't moved, some moved to other keys as a group, and some moved to different keys alone.
</p>
<div class="flex flex-row">
<img class="w-1/2 mx-auto mt-8" src="assets/login1.png">
<img class="w-1/2 mx-auto mt-8" src="assets/login2.png">
</div>
<div class="text-center mt-8">
<button class="bg-orange-500 text-white py-2 px-4 rounded-full hover:bg-orange-600 transition duration-200 text-sm sm:text-lg">
<a href="https://app.nkode.tech">Try nKode <span aria-hidden="true">&rarr;</span></a>
</button>
</div>
</section>
<section class="scroll-mt-24" id="faq">
<h3 class="text-4xl mt-8">FAQ</h3>
<h4 class="text-2xl mt-4">When can I use nKode?</h4>
<p>
We're working to make nKode available through Auth0.
However, we are looking for a strategic partner in identity management.
If you are interested in working with nKode, please reach out.
</p>
<h4 class="text-2xl mt-4">How does nKode defend against common attacks?</h4>
<p>
At the time of this writing, nKode is only a demo web application.
Ideally, all nKode authentication is done through a mobile application.
A mobile application can make nKode more secure by requiring passkeys and biometric authentication.
This makes it very difficult to steal or use your nKode.
</p>
<h5 class="text-xl mt-4">1. MFA Prompt Bombing</h5>
<p>
Many MFA solutions try to make login as frictionless as possible.
This kind of frictionless system makes prompt bombing a viable attack.
Adding some friction to the login process, nKode mitigates prompt bombing, not so much that it's too time-consuming but not so little that a person could mindlessly accept an MFA request or accidentally fat-finger and accept an authentication request by mistake.
The easiest attack vector for a nKode MFA bomb is session hijacking.
Stealing nKode is more complex, making it an unlikely attack vector.
nKode can mitigate this by adding a button, "I did not make this MFA request."
The server can block fraudulent requests if the user presses this button.
Otherwise, the user enters their nKode.
Since a user has to look for their nKode, it prevents them from quickly typing in a passcode without thinking, giving them a chance to reconsider their decision. </p>
<h5 class="text-xl mt-4">2. Service Desk Social Engineering: Scattered Spider</h5>
<p>
An nKode keypad can be made from any type of image.
To make this more concrete, take a look at <a class="text-orange-600 underline" href="https://www.flaticon.com/search?word=abstract">Flaticon</a>.
If every employee at the service desk has a randomly generated keypad from abstract images like those found on Flaticon, an employee would have difficulty explaining their nKode.
Moreover, this keypad can be further protected with a 2FA keycard so only the employee can render their keypad.
For an attacker to get a target's nKode, they'd have to be with the target, and the targeted employee would have to point to the icons on their screen since they're difficult to describe in words.
The attacker must also steal the employee's 2FA keycard to render the login screen.
</p>
<h5 class="text-xl mt-4">3. Session Hijacking</h5>
<p>
To mitigate the damage from session hijacking, jwts or session tokens can be made read-only by default.
When a user makes a sensitive write transaction, such as updating personal information or sending money, they must enter an nKode.
</p>
<h5 class="text-xl mt-4">3. Sim Swaps</h5>
<p>
If a user's device is damaged, lost, or stolen, they'll need a way to establish authentication keys with the new device without using the old device.
We are building two types of nKode offerings:
</p>
<ol class="list-decimal list-inside mt-2 space-y-2">
<li>Sign in with nKode is a B2C service nKode SSO is a B2B service.</li>
<li>The solutions below will use the terms customers and mobile carriers, but these are interchangeable with employee and service desk.</li>
</ol>
<h6 class="mt-2 font-semibold">Temporary nKode Portal</h6>
<p>
The customer calls their mobile carrier to activate the sim for a new phone without the old device.
The customer provides information like their name, dob, and ssn and answers security questions.
The carrier will then activate a temporary web portal where the customer enters their nKode to authenticate the request.
When the portal is activated, the customer with the authenticated phone will receive a notification on their nKode app alerting them to the activated portal.
If the user has their device, they can close the portal by entering their nKode.
The portal should only be opened if the user can't use their device to activate the new sim.
If their phone is stolen, the thief can't stop this process if they don't know the user's nKode.
Customers who want higher security can specify a wait period before a replacement device is activated.
If the portal isn't closed before the end of this waiting period, the sim swap or new device enrollment can proceed.
</p>
<h6 class="mt-2 font-semibold">Authentication nKode Delegates</h6>
<p>
This solution is only suitable for Sign in with nKode.
After a user has installed the nKode app and created their account, they can delegate authentication to trusted friends and family who also have a Sign in with nKode for device recovery.
If a user delegates authentication recovery to a few trusted people and they've lost their device, the user can go to any of their trusted delegates to enroll a new device through their delegate's nKode app.
Users can configure account delegation such that any authentication can be completed with only one delegate or require more than one delegate to authenticate on the user's behalf.
Once a device has been enrolled, the carrier can rely on nKode to authenticate a sim swap.
</p>
<h5 class="text-xl mt-4">4. Redline Stealer</h5>
<p>
Ideally, all nKode authentication goes through the mobile app. If authentication is done on a laptop, an attacker can steal a user's nKode after watching several nKode entries depending on the number of keys and icons per key. This number can vary as the number of icons and keys change.
</p>
<h5 class="text-xl mt-4">5. Exploiting SSO SAML</h5>
<p>
If an attacker finds a way to steal a user's nKode, they still need the user's device. The user's device contains their passkeys and biometrics. Without it, the adversary won't be able to authenticate.
</p>
</section>
<section class="scroll-mt-24" id="contact-us"> <section class="scroll-mt-24" id="contact-us">
<h3 class="text-4xl mt-8">Contact Us</h3> <h3 class="text-4xl mt-8">Contact Us</h3>
<p class="mt-4 text-lg">We'd love to hear from you! Whether you have questions, or feedback, feel free to reach out to us at:</p> <p class="mt-4 text-lg">
<a href="mailto:hello@nkode.tech" class="text-blue-600 hover:underline mt-2 text-lg font-semibold">hello@nkode.tech</a> We'd love to hear from you! Whether you have questions, or
feedback, feel free to reach out to us at:
</p>
<a
href="mailto:hello@nkode.tech"
class="text-blue-600 hover:underline mt-2 text-lg font-semibold"
>hello@nkode.tech</a
>
</section> </section>
</div> </div>
</main> </main>
</div>
</div> <!-- Add your JavaScript just before the closing body tag -->
<script>
<!-- Add your JavaScript just before the closing body tag -->
<script>
// Get the elements from the DOM // Get the elements from the DOM
const openMenuButton = document.getElementById('open-menu'); const openMenuButton = document.getElementById("open-menu");
const closeMenuButton = document.getElementById('close-menu'); const closeMenuButton = document.getElementById("close-menu");
const mobileMenu = document.getElementById('mobile-menu'); const mobileMenu = document.getElementById("mobile-menu");
const mobileNavLinks = document.getElementsByClassName('mobile-nav'); const mobileNavLinks = document.getElementsByClassName("mobile-nav");
// Function to show the mobile menu // Function to show the mobile menu
openMenuButton.addEventListener('click', () => { openMenuButton.addEventListener("click", () => {
mobileMenu.classList.remove('hidden'); mobileMenu.classList.remove("hidden");
}); });
// Function to hide the mobile menu // Function to hide the mobile menu
closeMenuButton.addEventListener('click', () => { closeMenuButton.addEventListener("click", () => {
mobileMenu.classList.add('hidden'); mobileMenu.classList.add("hidden");
}); });
Array.from(mobileNavLinks).forEach(link => { Array.from(mobileNavLinks).forEach((link) => {
link.addEventListener('click', () => { link.addEventListener("click", () => {
mobileMenu.classList.add('hidden'); mobileMenu.classList.add("hidden");
}); });
}); });
</script> </script>
</body>
</body>
</html> </html>