〔You deal 8 damage. The warrior ant is poisoned!〕
〔The warrior ant dies!〕
My stinger flew like an arrow, piercing the ant's head and killing it instantaneously with poison. While it was dying, my stinger was already regrowing.
A pair of morphotyped genes I didn't have much reasons to use, but they were very effective now—"Detachable Stinger V" and "Shootable Stinger II"!
Now I shot ants and spiders like I had a gun growing out of my ass! With how deadly my venom was, even a slightest scratch led to a creature's death.
But my girls fought even more effectively! Using their steel weapons and sometimes bare hands, they crushed and cut insects like blood-filled pillows. Their scale armor stopped claws and teeth of the attackers as well as good chitin.
Viscera fell all over the place, which only attracted the attention of other insects. Predators ate bodies of the fallen while a battle raged around them, which made them vulnerable to being crushed themselves.
Creatures, one more ugly than the other in their mix of humanoid and insect features, screeched and died bleeding, burning or just poisoned to death. Here, not so many of them evolved poison immunity.
In the background, our dragons enjoyed their break, eating more insects. But they weren't the only ones attracted by the scents of pheromones and blood in the air.
Larger beasts: feathered lizards, slug-like toads and bug-like rats scuttled at the edges of the battle, snatching insects into their massive mouths and running away from the bees and from each other. Animal screeches filled the air, making it impossible to hear anything but telepathy.
Although the enemies were numerous, they weren't strong or organized.
I shot a toad which got too close to our positions.
It was only a matter of time—
I heard a rapidly approaching flapping of wings above my head. At the same instant, Destroyer and half of my bodyguards charged upward with battlecries.
When I looked up, I saw the bodyguards slamming head-on at a bright green dragon which was diving at me!
This beast was smaller and more slender than the black dragons, with a long alligator-like jaw which it tried to close around Destroyer.
Although Destroyer was in the dragon's mouth, standing between its teeth, she stabbed her spear into its roof, and her stinger into the dragon's tongue!
Even before the dragon screeched, I saw how its health went down.
The beast, unable to stay on the trajectory, began falling to the battleground a dozen meters away from me. If not for my telepathic warning call, it would've crushed a few fighting Beemarines.
My bodyguards and dragon-killers avoided being crushed by the dead beast, which definitely broke its neck during the fall.
'A good save!' I messaged Destroyer, fearing to imagine myself in these jaws. The battle distracted me so much that I forgot to look above at all!
Now I looked, and it was not a pretty sight. Of course, the aerial predators wanted to get their bite, too. A few even got in scuffles with black dragons, but to my relief, they were nothing serious.
Just as I thought that, a larger dragon appeared!
At first, it looked tiny, flying somewhere extremely far in the sky. But then it swooped in, and I saw it was a true beast of beasts, with wings at least a hundred meters wide! Its scales were a motley mix of brown and beige, but its claws were large enough to tear one of our black dragons apart with ease.
'System, it's time. Activate the "Titan Slayer" title!'
</p><p>A boost of strength that worked only against the strongest opponents… I felt like it would be of use now.</p><p>And it was.</p><p>The brown dragon was clearly aiming for Woe, intent on swooping him right out of the air!</p><p>'Woe, look out! Above you!' I messaged the dragon telepathically, hoping that it would dodge.</p><p>At the same time, I dashed to intercept personally. Against a beast this big, nothing but my strongest venom and electricity will work!</p><p>My warning made Woe jerk aside, but it was less effective than I hoped.</p><p>The brown dragon flew over the black one, and its claws narrowly missed Woe's back; however, the speed of the brown dragon was so great that a blast of wind from its wings still threw Woe to the ground!</p><p>Of course, all insects in the area were thrown aside, too. The smallest ones were crushed instantaneously. The bigger ones lived, but many got bruises and sprains.</p><p>To my relief, all the bees in the area got off easy thanks to their thick skin.</p><p>But Woe landed badly on his foot and screeched in pain. Other black dragons reacted immediately, gathering to his side to protect him.</p><p>However, the brown dragon was about to reach Woe first and finish him. The much smaller black dragon had no chance to fight the brown dragon off.</p><p>With the top speed of our wings, I and five of my bodyguards got there in time.</p><p>I dashed right at the brown dragon's head, cutting through the wind from its flapping wings and aiming for its eye with my sting shot. Although my shots were slow, it was hard to miss against a target that large.</p><p>The dragon blinked and jerked away, and the stinger deflected off its scales, not even scratching it.</p><p>It screeched, and I shouted in reply.</p><p>"DON'T YOU DARE TO TOUCH MY DRAGONS!"</p><p>"GRAAA! GRAAAAW!" they echoed from all around, rushing at the brown dragon who thought too much of itself.</p><p>"Kill him, sisters!" my bodyguards shouted, charging ahead of me.</p><p>I followed closely.</p><p>The beast was fast, but only at long distances. At the moment, it was slowing down to grab of Woe without smashing its head into the ground, so it couldn't fly away from us.</p><p>When we surrounded its eyes, it could only close them. But this didn't stop our stingers and my spear!</p>
</div>
</div>
<!-- Enhanced Navigation Footer -->
<div class="mt-6 bg-white rounded-lg border border-gray-200 shadow-sm sm:mt-8 navigation-footer">
<!-- Mobile Layout - Separate Buttons like Desktop -->
<div class="block p-4 space-y-4 sm:hidden">
<!-- Previous Chapter - Mobile -->
<a href="https://novelhub.net/novel/reincarnated-to-evolve-my-bee-empire/chapter-314"
class="flex items-center p-4 bg-blue-50 rounded-xl border-2 border-blue-200 transition-all hover:bg-blue-100 hover:border-blue-300 group">
<div class="flex justify-center items-center mr-4 w-10 h-10 bg-blue-200 rounded-full transition-colors group-hover:bg-blue-300">
<svg class="w-5 h-5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
</svg>
</div>
<div class="flex-1 min-w-0">
<p class="mb-1 text-sm font-medium text-blue-600">Previous Chapter</p>
<p class="text-base font-semibold text-gray-900 truncate"></p>
</div>
</a>
<!-- All Chapters - Mobile -->
<div class="flex justify-center">
<a href="https://novelhub.net/novel/reincarnated-to-evolve-my-bee-empire/chapters"
class="flex items-center px-6 py-3 text-base font-medium text-gray-700 bg-gray-100 rounded-xl transition-all hover:bg-gray-200">
<svg class="mr-2 w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 10h16M4 14h16M4 18h16"></path>
</svg>
All Chapters
</a>
</div>
<!-- Next Chapter - Mobile -->
<a href="https://novelhub.net/novel/reincarnated-to-evolve-my-bee-empire/chapter-316"
class="flex items-center p-4 bg-blue-50 rounded-xl border-2 border-blue-200 transition-all hover:bg-blue-100 hover:border-blue-300 group">
<div class="flex-1 min-w-0">
<p class="mb-1 text-sm font-medium text-blue-600">Next Chapter</p>
<p class="text-base font-semibold text-gray-900 truncate"></p>
</div>
<div class="flex justify-center items-center ml-4 w-10 h-10 bg-blue-200 rounded-full transition-colors group-hover:bg-blue-300">
<svg class="w-5 h-5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
</svg>
</div>
</a>
</div>
<!-- Desktop Layout - Enhanced -->
<div class="hidden p-6 sm:block">
<div class="grid grid-cols-3 gap-6 items-center">
<!-- Previous Chapter - Desktop -->
<div class="flex justify-start">
<a href="https://novelhub.net/novel/reincarnated-to-evolve-my-bee-empire/chapter-314"
class="flex items-center p-4 max-w-full bg-blue-50 rounded-xl border-2 border-blue-200 transition-all transform hover:bg-blue-100 hover:border-blue-300 group hover:scale-105">
<div class="flex justify-center items-center mr-3 w-10 h-10 bg-blue-200 rounded-full transition-colors group-hover:bg-blue-300">
<svg class="w-5 h-5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
</svg>
</div>
<div class="min-w-0">
<p class="mb-1 text-sm font-medium text-blue-600">Previous</p>
<p class="text-base font-semibold text-gray-900 truncate"></p>
</div>
</a>
</div>
<!-- All Chapters - Desktop (Center) -->
<div class="flex justify-center">
<a href="https://novelhub.net/novel/reincarnated-to-evolve-my-bee-empire/chapters"
class="flex items-center px-6 py-3 text-base font-medium text-gray-700 bg-gray-100 rounded-xl transition-all transform hover:bg-gray-200 hover:scale-105">
<svg class="mr-2 w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 10h16M4 14h16M4 18h16"></path>
</svg>
All Chapters
</a>
</div>
<!-- Next Chapter - Desktop -->
<div class="flex justify-end">
<a href="https://novelhub.net/novel/reincarnated-to-evolve-my-bee-empire/chapter-316"
class="flex items-center p-4 max-w-full bg-blue-50 rounded-xl border-2 border-blue-200 transition-all transform hover:bg-blue-100 hover:border-blue-300 group hover:scale-105">
<div class="min-w-0 text-right">
<p class="mb-1 text-sm font-medium text-blue-600">Next</p>
<p class="text-base font-semibold text-gray-900 truncate"></p>
</div>
<div class="flex justify-center items-center ml-3 w-10 h-10 bg-blue-200 rounded-full transition-colors group-hover:bg-blue-300">
<svg class="w-5 h-5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
</svg>
</div>
</a>
</div>
</div>
</div>
</div>
<!-- Enhanced Back to Novel Button -->
<div class="mt-6 text-center">
<a href="https://novelhub.net/novel/reincarnated-to-evolve-my-bee-empire"
class="inline-flex items-center px-6 py-3 text-base font-medium text-blue-600 bg-blue-50 rounded-xl transition-all transform hover:bg-blue-100 hover:scale-105">
<svg class="mr-2 w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path>
</svg>
Back to Reincarnated To Evolve My Bee...
</a>
</div>
</div>
</div>
<!-- Comments Section -->
<div class="py-4 bg-white sm:py-6">
<div class="px-4 mx-auto max-w-6xl sm:px-6 lg:px-8">
<div x-data="commentSystem(1066, 716721, [], 'false')">
<h2 class="py-2 mb-4 text-lg font-bold text-gray-900">Comments</h2>
<div class="mb-6">
<div class="p-4 text-center text-gray-500 bg-gray-50 rounded-lg border border-gray-200">
<svg class="mx-auto mb-3 w-12 h-12 text-gray-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"></path>
</svg>
<p class="mb-3 text-sm">Join the discussion! Login to share your thoughts and connect with other readers.</p>
<div class="flex gap-3 justify-center">
<button @click="$dispatch('open-auth-modal', { mode: 'login' })" class="px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-md transition-colors hover:bg-blue-700">
Login
</button>
<button @click="$dispatch('open-auth-modal', { mode: 'register' })" class="px-4 py-2 text-sm font-medium text-gray-700 bg-gray-200 rounded-md transition-colors hover:bg-gray-300">
Register
</button>
</div>
</div>
</div>
<div id="comments-list" class="space-y-4" x-show="replyingTo === null && !hasInteractions">
<div class="p-6 text-center text-gray-500 bg-white rounded-lg border border-gray-200">
<svg class="mx-auto mb-3 w-12 h-12 text-gray-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"></path>
</svg>
<p class="text-sm">No comments yet. Be the first to comment!</p>
</div>
</div>
<div x-show="hasInteractions" x-cloak class="space-y-4">
<template x-for="comment in comments" :key="comment.id">
<div :data-comment-id="comment.id" class="p-2 bg-white rounded-lg border border-gray-200 transition-all duration-200">
<div class="flex gap-3">
<div class="flex-shrink-0">
<div class="inline-block relative">
<img :src="comment.user.avatar && comment.user.avatar !== 'images/default-avatar.svg' ? `/storage/${comment.user.avatar}` : '/images/default-avatar.svg'"
alt=""
class="object-cover w-12 h-12 rounded-full"
loading="lazy">
</div>
</div>
<div class="flex-1">
<div class="flex justify-between items-center mb-2">
<div class="flex gap-2 items-center">
<span class="font-semibold text-gray-800" x-text="comment.user.name"></span>
<span class="username-level-badge"
:class="`lv_${comment.user.level || 1}`">
<span x-text="`Lv${comment.user.level || 1}`"></span>
</span>
<template x-if="comment.chapter_id">
<span class="inline-flex items-center px-2 py-1 text-xs font-medium text-blue-700 bg-blue-100 rounded-full">
Chapter <span x-text="comment.chapter_number"></span>
</span>
</template>
</div>
<span class="text-xs text-gray-500" x-text="formatDate(comment.created_at)"></span>
</div>
<div class="leading-relaxed text-gray-700" x-html="parseCommentBody(comment.content)"></div>
<div class="flex gap-4 items-center mt-3 text-xs text-gray-600">
<button x-on:click="toggleLike(comment.id)"
class="flex gap-1 items-center px-2 py-1 rounded transition-colors duration-200 hover:text-blue-600 hover:bg-blue-50">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path d="M7.493 18.75c-.425 0-.82-.236-.975-.632A7.48 7.48 0 016 15.375c0-1.75.599-3.358 1.602-4.634.151-.192.373-.309.6-.397.473-.183.89-.514 1.212-.924a9.042 9.042 0 012.861-2.4c.723-.384 1.35-.956 1.653-1.715a4.498 4.498 0 00.322-1.672V3a.75.75 0 01.75-.75 2.25 2.25 0 012.25 2.25c0 1.152-.26 2.243-.723 3.218-.266.558-.107 1.282.725 1.282h3.126c1.026 0 1.945.694 2.054 1.715.045.422.068.85.068 1.285a11.95 11.95 0 01-2.649 7.521c-.388.482-.987.729-1.605.729H14.23c-.483 0-.964-.078-1.423-.23l-3.114-1.04a4.501 4.501 0 00-1.423-.23h-.777zM2.331 10.977a11.969 11.969 0 00-.831 4.398 12 12 0 00.52 3.507c.26.85 1.084 1.368 1.973 1.368H4.9c.445 0 .72-.498.523-.898a8.963 8.963 0 01-.924-3.977c0-1.708.476-3.305 1.302-4.666.245-.403-.028-.959-.5-.959H4.25c-.832 0-1.612.453-1.918 1.227z" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
</svg>
<span x-text="comment.likes_count > 0 ? comment.likes_count : ''"></span>
</button>
<button x-on:click="toggleReply(comment.id)"
class="flex gap-1 items-center px-2 py-1 rounded transition-colors duration-200 hover:text-blue-600 hover:bg-blue-50">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path d="M4.5 12L9.5 17M4.5 12L9.5 7M4.5 12L14.5 12C16.1667 12 19.5 11 19.5 7" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
</svg>
<span>Reply</span>
</button>
</div>
</div>
</div>
<div x-show="replyingTo === comment.id" x-transition class="mt-4 ml-0 md:ml-4">
<div :id="`replyPlaceholder${comment.id}`" class="reply-placeholder"></div>
</div>
<div x-show="comment.replies && comment.replies.length > 0" class="mt-4 ml-4 space-y-4">
<template x-for="reply in comment.replies" :key="reply.id">
<div class="flex gap-3">
<div class="flex-shrink-0">
<div class="inline-block relative">
<img :src="reply.user.avatar && reply.user.avatar !== 'images/default-avatar.svg' ? `/storage/${reply.user.avatar}` : '/images/default-avatar.svg'"
alt=""
class="object-cover w-8 h-8 rounded-full"
loading="lazy">
</div>
</div>
<div class="flex-1">
<div class="flex justify-between items-center mb-2">
<div class="flex gap-2 items-center">
<span class="font-semibold text-gray-800" x-text="reply.user.name"></span>
<span class="username-level-badge"
:class="`lv_${reply.user.level || 1}`">
<span x-text="`Lv${reply.user.level || 1}`"></span>
</span>
</div>
<span class="text-xs text-gray-500" x-text="formatDate(reply.created_at)"></span>
</div>
<div class="leading-relaxed text-gray-700" x-html="parseCommentBody(reply.content)"></div>
<div class="flex gap-4 items-center mt-3 text-xs text-gray-600">
<button x-on:click="toggleLike(reply.id)"
class="flex gap-1 items-center px-2 py-1 rounded transition-colors duration-200 hover:text-blue-600 hover:bg-blue-50">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path d="M7.493 18.75c-.425 0-.82-.236-.975-.632A7.48 7.48 0 016 15.375c0-1.75.599-3.358 1.602-4.634.151-.192.373-.309.6-.397.473-.183.89-.514 1.212-.924a9.042 9.042 0 012.861-2.4c.723-.384 1.35-.956 1.653-1.715a4.498 4.498 0 00.322-1.672V3a.75.75 0 01.75-.75 2.25 2.25 0 012.25 2.25c0 1.152-.26 2.243-.723 3.218-.266.558-.107 1.282.725 1.282h3.126c1.026 0 1.945.694 2.054 1.715.045.422.068.85.068 1.285a11.95 11.95 0 01-2.649 7.521c-.388.482-.987.729-1.605.729H14.23c-.483 0-.964-.078-1.423-.23l-3.114-1.04a4.501 4.501 0 00-1.423-.23h-.777zM2.331 10.977a11.969 11.969 0 00-.831 4.398 12 12 0 00.52 3.507c.26.85 1.084 1.368 1.973 1.368H4.9c.445 0 .72-.498.523-.898a8.963 8.963 0 01-.924-3.977c0-1.708.476-3.305 1.302-4.666.245-.403-.028-.959-.5-.959H4.25c-.832 0-1.612.453-1.918 1.227z" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
</svg>
<span x-text="reply.likes_count > 0 ? reply.likes_count : ''"></span>
</button>
<button x-on:click="toggleReply(reply.id)"
class="flex gap-1 items-center px-2 py-1 rounded transition-colors duration-200 hover:text-blue-600 hover:bg-blue-50">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path d="M4.5 12L9.5 17M4.5 12L9.5 7M4.5 12L14.5 12C16.1667 12 19.5 11 19.5 7" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
</svg>
<span>Reply</span>
</button>
</div>
<div x-show="replyingTo === reply.id" x-transition class="mt-4 -ml-4 md:ml-0">
<div :id="`replyPlaceholder${reply.id}`" class="reply-placeholder"></div>
</div>
</div>
</div>
</template>
</div>
</div>
</template>
</div>
<div x-show="hasMorePages" x-cloak class="mt-6 text-center">
<button x-on:click="loadMoreComments" :disabled="loadingMore"
class="px-6 py-3 text-sm font-medium text-white bg-gray-600 rounded-lg transition-colors duration-200 hover:bg-gray-700 disabled:opacity-50 disabled:cursor-not-allowed">
<span x-show="!loadingMore">Load More Comments</span>
<span x-show="loadingMore" class="flex justify-center items-center">
<svg class="mr-2 w-4 h-4 animate-spin" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
Loading...
</span>
</button>
</div>
<div id="mobileReplyForm" x-show="replyingTo !== null" x-cloak class="hidden">
<form x-on:submit.prevent="postReply()" class="ml-0 space-y-4 md:ml-0">
<div class="bg-white rounded-lg border border-gray-200 focus-within:ring-2 focus-within:ring-blue-500 focus-within:border-blue-500">
<div class="px-2 py-2 border-b border-gray-200">
<div class="flex justify-end items-center mb-1">
<button type="button" x-on:click="activeReplyStickerSet = null" x-show="activeReplyStickerSet"
class="text-xs text-gray-500 hover:text-gray-700">
Close
</button>
</div>
<nav class="flex overflow-x-auto pb-1 space-x-3" aria-label="Reply Sticker Sets">
<template x-for="(set, setName) in stickerSets" :key="setName">
<button type="button"
x-on:click="activeReplyStickerSet = (activeReplyStickerSet === setName ? null : setName)"
:class="activeReplyStickerSet === setName ? 'ring-2 ring-blue-500 bg-blue-50' : 'hover:bg-gray-200'"
class="flex-shrink-0 p-2 rounded-md transition-all duration-200 focus:outline-none">
<img :src="getRepresentative(setName)" :alt="set.name"
class="object-contain w-8 h-8" :title="set.name">
</button>
</template>
</nav>
<div x-show="activeReplyStickerSet" x-transition class="pt-2 mt-2 border-t border-gray-200">
<div class="grid overflow-y-auto grid-cols-6 gap-3 max-h-48 md:grid-cols-8 lg:grid-cols-10">
<template x-for="file in stickerSets[activeReplyStickerSet]?.files || []" :key="file">
<button type="button"
x-on:click="insertReplySticker(activeReplyStickerSet, file, replyingTo)"
class="p-2 rounded-md transition-transform sticker-button hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-blue-500">
<img :src="stickerSets[activeReplyStickerSet].path + file"
:alt="file" class="object-contain w-12 h-12 md:w-16 md:h-16">
</button>
</template>
</div>
</div>
</div>
<div class="relative px-2 py-2">
<input type="hidden" name="reply_content" x-model="newReply">
<div id="mobileReplyEditor"
x-on:input="syncMobileReplyEditorState()"
contenteditable="true"
role="textbox"
class="block p-3 pr-20 w-full border-0 resize-none reply-editor focus:ring-0"
style="word-break: break-word; min-height: 60px;"
data-placeholder="Write your reply...">
</div>
<div class="absolute right-2 bottom-2">
<button type="submit" :disabled="loading"
class="inline-flex items-center px-3 py-1.5 text-sm font-medium text-white bg-blue-600 rounded-md border border-transparent shadow-sm transition-all duration-200 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed">
<svg x-show="!loading" class="mr-1 w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path d="M4.5 12L9.5 17M4.5 12L9.5 7M4.5 12L14.5 12C16.1667 12 19.5 11 19.5 7" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
</svg>
<svg x-show="loading" class="mr-1 w-4 h-4 animate-spin" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
<span x-text="loading ? 'Replying...' : 'Reply'"></span>
</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</main>
<!-- Footer -->
<footer class="text-white bg-gray-900 safe-bottom">
<div class="px-4 py-12 mx-auto max-w-6xl sm:px-6 lg:px-8">
<div class="grid grid-cols-1 gap-8 md:grid-cols-4">
<!-- About Section -->
<div class="col-span-1 md:col-span-2">
<div class="flex items-center mb-4">
<img class="w-auto h-8 rounded-lg shadow-sm" src="https://novelhub.net/images/logo.svg" alt="NovelHub">
<span class="ml-2 text-xl font-bold">NovelHub</span>
</div>
<p class="mb-4 text-gray-300">
Free online novel reading website with a rich and continuously updated library. Enjoy reading on any device with a friendly interface.
</p>
<div class="flex space-x-4">
<a href="#" class="text-gray-400 transition-colors duration-200 hover:text-white">
<span class="sr-only">Facebook</span>
<svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24">
<path fill-rule="evenodd" d="M22 12c0-5.523-4.477-10-10-10S2 6.477 2 12c0 4.991 3.657 9.128 8.438 9.878v-6.987h-2.54V12h2.54V9.797c0-2.506 1.492-3.89 3.777-3.89 1.094 0 2.238.195 2.238.195v2.46h-1.26c-1.243 0-1.63.771-1.63 1.562V12h2.773l-.443 2.89h-2.33v6.988C18.343 21.128 22 16.991 22 12z" clip-rule="evenodd"></path>
</svg>
</a>
<a href="#" class="text-gray-400 transition-colors duration-200 hover:text-white">
<span class="sr-only">Twitter</span>
<svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24">
<path d="M8.29 20.251c7.547 0 11.675-6.253 11.675-11.675 0-.178 0-.355-.012-.53A8.348 8.348 0 0022 5.92a8.19 8.19 0 01-2.357.646 4.118 4.118 0 001.804-2.27 8.224 8.224 0 01-2.605.996 4.107 4.107 0 00-6.993 3.743 11.65 11.65 0 01-8.457-4.287 4.106 4.106 0 001.27 5.477A4.072 4.072 0 012.8 9.713v.052a4.105 4.105 0 003.292 4.022 4.095 4.095 0 01-1.853.07 4.108 4.108 0 003.834 2.85A8.233 8.233 0 012 18.407a11.616 11.616 0 006.29 1.84"></path>
</svg>
</a>
<a href="#" class="text-gray-400 transition-colors duration-200 hover:text-white">
<span class="sr-only">Discord</span>
<svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24">
<path d="M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419-.019 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1568 2.4189Z"></path>
</svg>
</a>
</div>
</div>
<!-- Quick Links -->
<div>
<h3 class="mb-4 text-lg font-semibold">Quick Links</h3>
<ul class="space-y-2">
<li><a href="https://novelhub.net" class="text-gray-300 transition-colors duration-200 hover:text-white">Home</a></li>
<li><a href="https://novelhub.net/latest" class="text-gray-300 transition-colors duration-200 hover:text-white">Latest Updates</a></li>
<li><a href="https://novelhub.net/newly-added" class="text-gray-300 transition-colors duration-200 hover:text-white">New Novels</a></li>
<li><a href="https://novelhub.net/completed" class="text-gray-300 transition-colors duration-200 hover:text-white">Completed</a></li>
<li><a href="https://novelhub.net/ranking" class="text-gray-300 transition-colors duration-200 hover:text-white">Rankings</a></li>
</ul>
</div>
<!-- Support -->
<div>
<h3 class="mb-4 text-lg font-semibold">Support</h3>
<ul class="space-y-2">
<li><a href="https://novelhub.net/faq" class="text-gray-300 transition-colors duration-200 hover:text-white">FAQ</a></li>
<li><a href="https://novelhub.net/contact" class="text-gray-300 transition-colors duration-200 hover:text-white">Contact</a></li>
<li><a href="https://novelhub.net/about" class="text-gray-300 transition-colors duration-200 hover:text-white">About</a></li>
<li><a href="https://novelhub.net/privacy-policy" class="text-gray-300 transition-colors duration-200 hover:text-white">Privacy Policy</a></li>
<li><a href="https://novelhub.net/terms-of-service" class="text-gray-300 transition-colors duration-200 hover:text-white">Terms of Service</a></li>
</ul>
</div>
</div>
<!-- Bottom Section -->
<div class="pt-8 mt-8 border-t border-gray-800">
<div class="flex flex-col justify-between items-center md:flex-row">
<p class="text-sm text-gray-400">
© 2025 NovelHub. All rights reserved.
</p>
<div class="flex mt-4 space-x-6 md:mt-0">
<a href="https://novelhub.net/privacy-policy" class="text-sm text-gray-400 transition-colors duration-200 hover:text-white">
Privacy
</a>
<a href="https://novelhub.net/terms-of-service" class="text-sm text-gray-400 transition-colors duration-200 hover:text-white">
Terms
</a>
<a href="https://novelhub.net/contact" class="text-sm text-gray-400 transition-colors duration-200 hover:text-white">
Contact
</a>
</div>
</div>
</div>
</div>
</footer>
<!-- Auth Modal -->
<!-- Auth Modal Component -->
<style>
/* Custom styles for auth modal */
.auth-modal-overlay {
backdrop-filter: blur(4px);
}
.auth-modal-panel {
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
}
/* Mobile-specific styles for auth modal */
@media (max-width: 640px) {
.auth-modal-panel {
margin: 1rem;
width: calc(100% - 2rem);
max-width: none;
min-height: auto;
}
.auth-modal-panel input {
font-size: 16px; /* Prevent zoom on iOS */
padding: 0.75rem 1rem;
}
.auth-modal-panel button {
padding: 0.75rem 1rem;
font-size: 16px;
}
.auth-modal-panel label {
font-size: 14px;
font-weight: 500;
}
}
.auth-toggle-button {
transition: all 0.2s ease-in-out;
}
.auth-toggle-button:hover {
transform: translateY(-1px);
}
.auth-input:focus {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.15);
}
.auth-submit-button {
transition: all 0.2s ease-in-out;
}
.auth-submit-button:hover:not(:disabled) {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4);
}
.auth-close-button {
transition: all 0.2s ease-in-out;
}
.auth-close-button:hover {
transform: rotate(90deg);
}
</style>
<div x-data="authModal()" x-cloak>
<!-- Modal Overlay -->
<div x-show="isOpen"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
class="fixed inset-0 z-50 overflow-y-auto">
<!-- Background overlay -->
<div class="flex items-center justify-center px-4 pt-4 pb-20 text-center sm:block sm:p-0">
<div x-show="isOpen"
@click="closeModal()"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
class="fixed inset-0 transition-opacity bg-gray-500 bg-opacity-75 auth-modal-overlay"></div>
<!-- This element is to trick the browser into centering the modal contents. -->
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true"></span>
<!-- Modal panel -->
<div x-show="isOpen"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
class="inline-block align-bottom bg-white rounded-lg px-6 pt-8 pb-8 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg w-full max-w-md mx-auto sm:p-6 auth-modal-panel">
<!-- Close button -->
<div class="absolute top-0 right-0 pt-4 pr-4">
<button @click="closeModal()" class="bg-white rounded-md text-gray-400 hover:text-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 auth-close-button">
<span class="sr-only">Close</span>
<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<!-- Modal Header -->
<div class="mb-8">
<div class="flex justify-center mb-6">
<img class="h-16 w-auto sm:h-12" src="https://novelhub.net/images/logo.png" alt="NovelHub">
</div>
<div class="flex rounded-lg bg-gray-100 p-1">
<button @click="setMode('login')"
:class="mode === 'login' ? 'bg-white text-blue-600 shadow-sm' : 'text-gray-500 hover:text-gray-700'"
class="flex-1 py-2 px-3 text-sm font-medium rounded-md transition-all duration-200 auth-toggle-button">
Login
</button>
<button @click="setMode('register')"
:class="mode === 'register' ? 'bg-white text-blue-600 shadow-sm' : 'text-gray-500 hover:text-gray-700'"
class="flex-1 py-2 px-3 text-sm font-medium rounded-md transition-all duration-200 auth-toggle-button">
Register
</button>
</div>
</div>
<!-- Login Form -->
<div x-show="mode === 'login'" x-transition:enter="transition ease-out duration-200" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100">
<form @submit.prevent="submitLogin()" class="space-y-6">
<div>
<label for="login-email" class="block text-sm font-medium text-gray-700">Email</label>
<input x-model="loginForm.email"
type="email"
id="login-email"
required
class="mt-2 block w-full px-4 py-3 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-blue-500 focus:border-blue-500 auth-input text-base">
</div>
<div>
<label for="login-password" class="block text-sm font-medium text-gray-700">Password</label>
<input x-model="loginForm.password"
type="password"
id="login-password"
required
class="mt-2 block w-full px-4 py-3 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-blue-500 focus:border-blue-500 auth-input text-base">
</div>
<div class="flex items-center justify-between">
<div class="flex items-center">
<input x-model="loginForm.remember"
id="remember-me"
type="checkbox"
class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded">
<label for="remember-me" class="ml-2 block text-sm text-gray-900">Remember me</label>
</div>
<div class="text-sm">
<a href="https://novelhub.net/forgot-password" class="font-medium text-blue-600 hover:text-blue-500">
Forgot password?
</a>
</div>
</div>
<button type="submit"
:disabled="loading"
:class="loading ? 'opacity-50 cursor-not-allowed' : ''"
class="w-full flex justify-center py-3 px-4 border border-transparent rounded-md shadow-sm text-base font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-colors duration-200 auth-submit-button">
<span x-show="!loading">Sign in</span>
<span x-show="loading" class="flex items-center">
<svg class="animate-spin -ml-1 mr-2 h-4 w-4 text-white" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
Signing in...
</span>
</button>
</form>
<!-- Divider -->
<div class="flex items-center mt-4">
<div class="flex-1 border-t border-gray-300"></div>
<div class="px-3 text-sm text-gray-500">Or continue with</div>
<div class="flex-1 border-t border-gray-300"></div>
</div>
<!-- Google Login Button -->
<div class="mt-4">
<a href="https://novelhub.net/auth/google" class="w-full flex justify-center items-center px-4 py-2 border border-gray-300 rounded-md shadow-sm bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors duration-200">
<svg class="w-5 h-5 mr-3" viewBox="0 0 24 24">
<path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/>
<path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/>
<path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/>
<path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/>
</svg>
Continue with Google
</a>
</div>
</div>
<!-- Register Form -->
<div x-show="mode === 'register'" x-transition:enter="transition ease-out duration-200" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100">
<form @submit.prevent="submitRegister()" class="space-y-6">
<div>
<label for="register-name" class="block text-sm font-medium text-gray-700">Full Name</label>
<input x-model="registerForm.name"
type="text"
id="register-name"
required
class="mt-2 block w-full px-4 py-3 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-blue-500 focus:border-blue-500 auth-input text-base">
</div>
<div>
<label for="register-email" class="block text-sm font-medium text-gray-700">Email</label>
<input x-model="registerForm.email"
type="email"
id="register-email"
required
class="mt-2 block w-full px-4 py-3 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-blue-500 focus:border-blue-500 auth-input text-base">
</div>
<div>
<label for="register-password" class="block text-sm font-medium text-gray-700">Password</label>
<input x-model="registerForm.password"
type="password"
id="register-password"
required
class="mt-2 block w-full px-4 py-3 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-blue-500 focus:border-blue-500 auth-input text-base">
</div>
<div>
<label for="register-password-confirmation" class="block text-sm font-medium text-gray-700">Confirm Password</label>
<input x-model="registerForm.password_confirmation"
type="password"
id="register-password-confirmation"
required
class="mt-2 block w-full px-4 py-3 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-blue-500 focus:border-blue-500 auth-input text-base">
</div>
<div class="flex items-center">
<input x-model="registerForm.terms"
id="terms"
type="checkbox"
required
class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded">
<label for="terms" class="ml-2 block text-sm text-gray-900">
I agree to the <a href="https://novelhub.net/terms-of-service" class="text-blue-600 hover:text-blue-500">Terms of Service</a> and <a href="https://novelhub.net/privacy-policy" class="text-blue-600 hover:text-blue-500">Privacy Policy</a>
</label>
</div>
<button type="submit"
:disabled="loading"
:class="loading ? 'opacity-50 cursor-not-allowed' : ''"
class="w-full flex justify-center py-3 px-4 border border-transparent rounded-md shadow-sm text-base font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-colors duration-200 auth-submit-button">
<span x-show="!loading">Create Account</span>
<span x-show="loading" class="flex items-center">
<svg class="animate-spin -ml-1 mr-2 h-4 w-4 text-white" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
Creating account...
</span>
</button>
</form>
</div>
<!-- Error Messages -->
<div x-show="errorMessage" x-transition class="mt-4 p-3 bg-red-100 border border-red-400 text-red-700 rounded">
<p x-text="errorMessage"></p>
</div>
<!-- Success Messages -->
<div x-show="successMessage" x-transition class="mt-4 p-3 bg-green-100 border border-green-400 text-green-700 rounded">
<p x-text="successMessage"></p>
</div>
</div>
</div>
</div>
</div>
<script>
function authModal() {
return {
isOpen: false,
mode: 'login', // 'login' or 'register'
loading: false,
errorMessage: '',
successMessage: '',
loginForm: {
email: '',
password: '',
remember: true // Default to true for better UX
},
registerForm: {
name: '',
email: '',
password: '',
password_confirmation: '',
terms: false
},
openModal(mode = 'login') {
this.mode = mode;
this.isOpen = true;
this.clearMessages();
// Focus on first input after modal opens
this.$nextTick(() => {
const firstInput = this.$el.querySelector('input[type="email"], input[type="text"]');
if (firstInput) firstInput.focus();
});
},
closeModal() {
this.isOpen = false;
this.clearMessages();
this.clearForms();
},
setMode(mode) {
this.mode = mode;
this.clearMessages();
},
clearMessages() {
this.errorMessage = '';
this.successMessage = '';
},
clearForms() {
this.loginForm = { email: '', password: '', remember: true }; // Keep remember as true by default
this.registerForm = { name: '', email: '', password: '', password_confirmation: '', terms: false };
},
async submitLogin() {
this.loading = true;
this.clearMessages();
try {
const formData = new FormData();
formData.append('email', this.loginForm.email);
formData.append('password', this.loginForm.password);
formData.append('remember', this.loginForm.remember ? '1' : '0');
const response = await fetch('https://novelhub.net/login', {
method: 'POST',
headers: {
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
'Accept': 'application/json'
},
body: formData
});
if (response.ok) {
this.successMessage = 'Login successful! Redirecting...';
setTimeout(() => {
window.location.href = 'https://novelhub.net';
}, 1000);
} else {
const data = await response.json();
if (data.errors) {
const errors = Object.values(data.errors).flat();
this.errorMessage = errors.join(' ');
} else {
this.errorMessage = data.message || 'Login failed. Please check your credentials.';
}
}
} catch (error) {
this.errorMessage = 'An error occurred. Please try again.';
} finally {
this.loading = false;
}
},
async submitRegister() {
this.loading = true;
this.clearMessages();
if (this.registerForm.password !== this.registerForm.password_confirmation) {
this.errorMessage = 'Passwords do not match.';
this.loading = false;
return;
}
try {
const formData = new FormData();
formData.append('name', this.registerForm.name);
formData.append('email', this.registerForm.email);
formData.append('password', this.registerForm.password);
formData.append('password_confirmation', this.registerForm.password_confirmation);
formData.append('terms', this.registerForm.terms ? '1' : '0');
const response = await fetch('https://novelhub.net/register', {
method: 'POST',
headers: {
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
'Accept': 'application/json'
},
body: formData
});
if (response.ok) {
this.successMessage = 'Account created successfully! Logging you in...';
setTimeout(() => {
window.location.reload();
}, 1000);
} else {
const data = await response.json();
if (data.errors) {
const errors = Object.values(data.errors).flat();
this.errorMessage = errors.join(' ');
} else {
this.errorMessage = data.message || 'Registration failed. Please try again.';
}
}
} catch (error) {
this.errorMessage = 'An error occurred. Please try again.';
} finally {
this.loading = false;
}
},
// Listen for global events to open modal
init() {
// Listen for custom events
window.addEventListener('open-auth-modal', (event) => {
this.openModal(event.detail?.mode || 'login');
});
// Close modal on escape key
document.addEventListener('keydown', (event) => {
if (event.key === 'Escape' && this.isOpen) {
this.closeModal();
}
});
}
}
}
</script>
<!-- Scripts -->
<link rel="modulepreload" href="https://novelhub.net/build/assets/chapter-read-DqFeYs-k.js" /><link rel="modulepreload" href="https://novelhub.net/build/assets/reading-history-MaR17WzQ.js" /><script type="module" src="https://novelhub.net/build/assets/chapter-read-DqFeYs-k.js" data-navigate-track="reload"></script>
<!-- Common JavaScript (loaded on all pages) -->
<link rel="modulepreload" href="https://novelhub.net/build/assets/common-vyhw5r_g.js" /><link rel="modulepreload" href="https://novelhub.net/build/assets/vendor-ztdpVPaQ.js" /><script type="module" src="https://novelhub.net/build/assets/common-vyhw5r_g.js" data-navigate-track="reload"></script>
<!-- Alpine.js -->
<script defer src="https://novelhub.net/js/alpinejs.js"></script>
<!-- Additional scripts -->
<!-- Footer Scripts from Site Config -->
</body>
</html>
<script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'99a702201a353dc8',t:'MTc2MjQ1NzQ1Ng=='};var a=document.createElement('script');a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script>