Index: chapterx-frontend/src/components/ui/Avatar.tsx
===================================================================
--- chapterx-frontend/src/components/ui/Avatar.tsx	(revision b62cefc14094ca5ac7154f7d48797a1e6c444935)
+++ chapterx-frontend/src/components/ui/Avatar.tsx	(revision b62cefc14094ca5ac7154f7d48797a1e6c444935)
@@ -0,0 +1,58 @@
+import React from 'react'
+
+interface AvatarProps {
+  name: string
+  image?: string
+  size?: 'sm' | 'md' | 'lg' | 'xl'
+  className?: string
+}
+
+const sizeMap = {
+  sm: 'w-8 h-8 text-xs',
+  md: 'w-10 h-10 text-sm',
+  lg: 'w-16 h-16 text-xl',
+  xl: 'w-24 h-24 text-3xl',
+}
+
+const colors = [
+  'from-indigo-500 to-violet-500',
+  'from-violet-500 to-purple-500',
+  'from-pink-500 to-rose-500',
+  'from-emerald-500 to-teal-500',
+  'from-amber-500 to-orange-500',
+  'from-cyan-500 to-blue-500',
+]
+
+function getColorIndex(name: string): number {
+  let hash = 0
+  for (let i = 0; i < name.length; i++) hash = name.charCodeAt(i) + ((hash << 5) - hash)
+  return Math.abs(hash) % colors.length
+}
+
+export const Avatar: React.FC<AvatarProps> = ({ name, image, size = 'md', className = '' }) => {
+  const initials = name
+    .split(' ')
+    .map(p => p[0])
+    .slice(0, 2)
+    .join('')
+    .toUpperCase()
+  const colorClass = colors[getColorIndex(name)]
+
+  if (image) {
+    return (
+      <img
+        src={image}
+        alt={name}
+        className={`${sizeMap[size]} rounded-full object-cover ring-2 ring-slate-700 ${className}`}
+      />
+    )
+  }
+
+  return (
+    <div
+      className={`${sizeMap[size]} rounded-full bg-gradient-to-br ${colorClass} flex items-center justify-center font-semibold text-white ring-2 ring-slate-700 flex-shrink-0 ${className}`}
+    >
+      {initials}
+    </div>
+  )
+}
Index: chapterx-frontend/src/components/ui/Badge.tsx
===================================================================
--- chapterx-frontend/src/components/ui/Badge.tsx	(revision b62cefc14094ca5ac7154f7d48797a1e6c444935)
+++ chapterx-frontend/src/components/ui/Badge.tsx	(revision b62cefc14094ca5ac7154f7d48797a1e6c444935)
@@ -0,0 +1,68 @@
+import React from 'react'
+import { UserRole, StoryStatus } from '../../types'
+
+interface RoleBadgeProps {
+  role: UserRole
+}
+
+interface StatusBadgeProps {
+  status: StoryStatus
+}
+
+interface GenreBadgeProps {
+  genre: string
+  onClick?: () => void
+}
+
+export const RoleBadge: React.FC<RoleBadgeProps> = ({ role }) => {
+  const styles = {
+    admin: 'bg-rose-500/20 text-rose-400 border-rose-500/30',
+    writer: 'bg-indigo-500/20 text-indigo-400 border-indigo-500/30',
+    regular: 'bg-slate-500/20 text-slate-400 border-slate-500/30',
+    guest: 'bg-gray-500/20 text-gray-400 border-gray-500/30',
+  }
+  const labels = { admin: 'Admin', writer: 'Writer', regular: 'Reader', guest: 'Guest' }
+  return (
+    <span className={`px-2 py-0.5 text-xs font-medium rounded-full border ${styles[role]}`}>
+      {labels[role]}
+    </span>
+  )
+}
+
+export const StatusBadge: React.FC<StatusBadgeProps> = ({ status }) => {
+  const styles = {
+    draft: 'bg-amber-500/20 text-amber-400 border-amber-500/30',
+    published: 'bg-emerald-500/20 text-emerald-400 border-emerald-500/30',
+    archived: 'bg-slate-500/20 text-slate-400 border-slate-500/30',
+  }
+  const labels = { draft: 'Draft', published: 'Published', archived: 'Archived' }
+  return (
+    <span className={`px-2 py-0.5 text-xs font-medium rounded-full border ${styles[status]}`}>
+      {labels[status]}
+    </span>
+  )
+}
+
+export const GenreBadge: React.FC<GenreBadgeProps> = ({ genre, onClick }) => {
+  const colors: Record<string, string> = {
+    Fantasy: 'bg-purple-500/20 text-purple-300 border-purple-500/30 hover:bg-purple-500/30',
+    'Sci-Fi': 'bg-cyan-500/20 text-cyan-300 border-cyan-500/30 hover:bg-cyan-500/30',
+    Romance: 'bg-pink-500/20 text-pink-300 border-pink-500/30 hover:bg-pink-500/30',
+    'Historical Fiction': 'bg-amber-500/20 text-amber-300 border-amber-500/30 hover:bg-amber-500/30',
+    Adventure: 'bg-emerald-500/20 text-emerald-300 border-emerald-500/30 hover:bg-emerald-500/30',
+    Thriller: 'bg-slate-500/20 text-slate-300 border-slate-500/30 hover:bg-slate-500/30',
+    Mystery: 'bg-violet-500/20 text-violet-300 border-violet-500/30 hover:bg-violet-500/30',
+    Horror: 'bg-red-500/20 text-red-300 border-red-500/30 hover:bg-red-500/30',
+    Contemporary: 'bg-blue-500/20 text-blue-300 border-blue-500/30 hover:bg-blue-500/30',
+    Poetry: 'bg-rose-500/20 text-rose-300 border-rose-500/30 hover:bg-rose-500/30',
+  }
+  const style = colors[genre] || 'bg-indigo-500/20 text-indigo-300 border-indigo-500/30 hover:bg-indigo-500/30'
+  return (
+    <span
+      className={`px-2 py-0.5 text-xs font-medium rounded-full border transition-colors ${style} ${onClick ? 'cursor-pointer' : ''}`}
+      onClick={onClick}
+    >
+      {genre}
+    </span>
+  )
+}
Index: chapterx-frontend/src/components/ui/Button.tsx
===================================================================
--- chapterx-frontend/src/components/ui/Button.tsx	(revision b62cefc14094ca5ac7154f7d48797a1e6c444935)
+++ chapterx-frontend/src/components/ui/Button.tsx	(revision b62cefc14094ca5ac7154f7d48797a1e6c444935)
@@ -0,0 +1,70 @@
+import React from 'react'
+
+interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
+  variant?: 'primary' | 'secondary' | 'danger' | 'ghost'
+  size?: 'sm' | 'md' | 'lg'
+  loading?: boolean
+  children: React.ReactNode
+}
+
+export const Button: React.FC<ButtonProps> = ({
+  variant = 'primary',
+  size = 'md',
+  loading = false,
+  children,
+  className = '',
+  disabled,
+  ...props
+}) => {
+  const base =
+    'inline-flex items-center justify-center font-medium rounded-xl transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-slate-900 disabled:opacity-50 disabled:cursor-not-allowed'
+
+  const variants = {
+    primary:
+      'bg-gradient-to-r from-indigo-600 to-violet-600 text-white hover:from-indigo-500 hover:to-violet-500 focus:ring-indigo-500 shadow-lg glow-indigo hover:scale-105 active:scale-95',
+    secondary:
+      'bg-slate-700 text-slate-100 hover:bg-slate-600 focus:ring-slate-500 border border-slate-600',
+    danger:
+      'bg-gradient-to-r from-rose-600 to-rose-500 text-white hover:from-rose-500 hover:to-rose-400 focus:ring-rose-500 shadow-lg',
+    ghost:
+      'bg-transparent text-slate-300 hover:bg-slate-800 hover:text-white focus:ring-slate-500 border border-transparent hover:border-slate-600',
+  }
+
+  const sizes = {
+    sm: 'px-3 py-1.5 text-sm gap-1.5',
+    md: 'px-4 py-2 text-sm gap-2',
+    lg: 'px-6 py-3 text-base gap-2',
+  }
+
+  return (
+    <button
+      className={`${base} ${variants[variant]} ${sizes[size]} ${className}`}
+      disabled={disabled || loading}
+      {...props}
+    >
+      {loading && (
+        <svg
+          className="animate-spin h-4 w-4"
+          xmlns="http://www.w3.org/2000/svg"
+          fill="none"
+          viewBox="0 0 24 24"
+        >
+          <circle
+            className="opacity-25"
+            cx="12"
+            cy="12"
+            r="10"
+            stroke="currentColor"
+            strokeWidth="4"
+          />
+          <path
+            className="opacity-75"
+            fill="currentColor"
+            d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
+          />
+        </svg>
+      )}
+      {children}
+    </button>
+  )
+}
Index: chapterx-frontend/src/components/ui/Modal.tsx
===================================================================
--- chapterx-frontend/src/components/ui/Modal.tsx	(revision b62cefc14094ca5ac7154f7d48797a1e6c444935)
+++ chapterx-frontend/src/components/ui/Modal.tsx	(revision b62cefc14094ca5ac7154f7d48797a1e6c444935)
@@ -0,0 +1,68 @@
+import React, { useEffect } from 'react'
+import { X } from 'lucide-react'
+
+interface ModalProps {
+  isOpen: boolean
+  onClose: () => void
+  title?: string
+  children: React.ReactNode
+  size?: 'sm' | 'md' | 'lg' | 'xl'
+}
+
+const sizeMap = {
+  sm: 'max-w-sm',
+  md: 'max-w-md',
+  lg: 'max-w-lg',
+  xl: 'max-w-2xl',
+}
+
+export const Modal: React.FC<ModalProps> = ({
+  isOpen,
+  onClose,
+  title,
+  children,
+  size = 'md',
+}) => {
+  useEffect(() => {
+    const handler = (e: KeyboardEvent) => {
+      if (e.key === 'Escape') onClose()
+    }
+    if (isOpen) document.addEventListener('keydown', handler)
+    return () => document.removeEventListener('keydown', handler)
+  }, [isOpen, onClose])
+
+  if (!isOpen) return null
+
+  return (
+    <div className="fixed inset-0 z-50 flex items-center justify-center p-4">
+      <div
+        className="absolute inset-0 bg-black/70 backdrop-blur-sm"
+        onClick={onClose}
+      />
+      <div
+        className={`relative w-full ${sizeMap[size]} bg-slate-900 border border-slate-700 rounded-2xl shadow-2xl z-10 max-h-[90vh] overflow-y-auto`}
+      >
+        {title && (
+          <div className="flex items-center justify-between p-6 border-b border-slate-700">
+            <h2 className="text-lg font-semibold text-white font-serif">{title}</h2>
+            <button
+              onClick={onClose}
+              className="p-1.5 text-slate-400 hover:text-white hover:bg-slate-700 rounded-lg transition-colors"
+            >
+              <X size={18} />
+            </button>
+          </div>
+        )}
+        {!title && (
+          <button
+            onClick={onClose}
+            className="absolute top-4 right-4 p-1.5 text-slate-400 hover:text-white hover:bg-slate-700 rounded-lg transition-colors z-10"
+          >
+            <X size={18} />
+          </button>
+        )}
+        <div className="p-6">{children}</div>
+      </div>
+    </div>
+  )
+}
Index: chapterx-frontend/src/components/ui/Spinner.tsx
===================================================================
--- chapterx-frontend/src/components/ui/Spinner.tsx	(revision b62cefc14094ca5ac7154f7d48797a1e6c444935)
+++ chapterx-frontend/src/components/ui/Spinner.tsx	(revision b62cefc14094ca5ac7154f7d48797a1e6c444935)
@@ -0,0 +1,31 @@
+import React from 'react'
+
+interface SpinnerProps {
+  size?: 'sm' | 'md' | 'lg'
+  className?: string
+}
+
+const sizes = { sm: 'h-4 w-4', md: 'h-8 w-8', lg: 'h-12 w-12' }
+
+export const Spinner: React.FC<SpinnerProps> = ({ size = 'md', className = '' }) => (
+  <svg
+    className={`animate-spin ${sizes[size]} text-indigo-400 ${className}`}
+    xmlns="http://www.w3.org/2000/svg"
+    fill="none"
+    viewBox="0 0 24 24"
+  >
+    <circle
+      className="opacity-25"
+      cx="12"
+      cy="12"
+      r="10"
+      stroke="currentColor"
+      strokeWidth="4"
+    />
+    <path
+      className="opacity-75"
+      fill="currentColor"
+      d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
+    />
+  </svg>
+)
Index: chapterx-frontend/src/components/ui/StoryCard.tsx
===================================================================
--- chapterx-frontend/src/components/ui/StoryCard.tsx	(revision b62cefc14094ca5ac7154f7d48797a1e6c444935)
+++ chapterx-frontend/src/components/ui/StoryCard.tsx	(revision b62cefc14094ca5ac7154f7d48797a1e6c444935)
@@ -0,0 +1,96 @@
+import React from 'react'
+import { useNavigate } from 'react-router-dom'
+import { Heart, MessageCircle, Eye, Lock } from 'lucide-react'
+import { Story } from '../../types'
+import { useAuthStore } from '../../store/authStore'
+import { StatusBadge, GenreBadge } from './Badge'
+import { getGenreGradient } from '../story/GenreBadge'
+
+interface StoryCardProps {
+  story: Story
+  showStatus?: boolean
+}
+
+export const StoryCard: React.FC<StoryCardProps> = ({ story, showStatus = false }) => {
+  const navigate = useNavigate()
+  const { currentUser, showMatureContent } = useAuthStore()
+
+  const isMature = story.mature_content
+  const isGuest = !currentUser
+  const blurContent = isMature && isGuest && !showMatureContent
+
+  const primaryGenre = story.genres[0] || 'Fantasy'
+  const gradient = getGenreGradient(primaryGenre)
+
+  return (
+    <div
+      className="relative group cursor-pointer rounded-xl overflow-hidden bg-slate-800 border border-slate-700 hover:border-indigo-500/50 transition-all duration-300 hover:scale-105 hover:shadow-xl hover:shadow-indigo-500/10"
+      onClick={() => navigate(`/story/${story.story_id}`)}
+    >
+      {/* Cover */}
+      <div className={`relative h-40 bg-gradient-to-br ${gradient} flex items-end p-4`}>
+        {/* Mature ribbon */}
+        {isMature && (
+          <div className="absolute top-2 right-2 bg-rose-500/90 text-white text-xs px-2 py-0.5 rounded-full font-medium flex items-center gap-1">
+            <Lock size={10} />
+            18+
+          </div>
+        )}
+        {/* Status badge */}
+        {showStatus && (
+          <div className="absolute top-2 left-2">
+            <StatusBadge status={story.status} />
+          </div>
+        )}
+        {/* Blur overlay for mature on guest */}
+        {blurContent && (
+          <div className="absolute inset-0 backdrop-blur-md bg-slate-900/60 flex items-center justify-center">
+            <div className="text-center">
+              <Lock size={24} className="text-slate-400 mx-auto mb-1" />
+              <p className="text-xs text-slate-400">Mature Content</p>
+              <p className="text-xs text-slate-500">Login to view</p>
+            </div>
+          </div>
+        )}
+        {/* Genre decorative circles */}
+        <div className="absolute top-4 left-4 w-20 h-20 rounded-full bg-white/5 blur-xl" />
+        <div className="absolute bottom-2 right-8 w-12 h-12 rounded-full bg-white/5 blur-lg" />
+      </div>
+
+      {/* Content */}
+      <div className="p-4">
+        <h3 className="font-serif font-semibold text-white text-sm leading-tight mb-1 line-clamp-2 group-hover:text-indigo-300 transition-colors">
+          {story.title}
+        </h3>
+        <p className="text-slate-500 text-xs mb-2">by {story.author_username}</p>
+        <p className="text-slate-400 text-xs line-clamp-2 mb-3">{story.short_description}</p>
+
+        {/* Genre badges */}
+        <div className="flex flex-wrap gap-1 mb-3">
+          {story.genres.slice(0, 2).map(g => (
+            <GenreBadge key={g} genre={g} />
+          ))}
+          {story.genres.length > 2 && (
+            <span className="text-xs text-slate-500">+{story.genres.length - 2}</span>
+          )}
+        </div>
+
+        {/* Stats */}
+        <div className="flex items-center gap-3 text-slate-500 text-xs">
+          <span className="flex items-center gap-1">
+            <Heart size={12} />
+            {story.total_likes.toLocaleString()}
+          </span>
+          <span className="flex items-center gap-1">
+            <MessageCircle size={12} />
+            {story.total_comments}
+          </span>
+          <span className="flex items-center gap-1 ml-auto">
+            <Eye size={12} />
+            {story.total_views.toLocaleString()}
+          </span>
+        </div>
+      </div>
+    </div>
+  )
+}
Index: chapterx-frontend/src/components/ui/Toast.tsx
===================================================================
--- chapterx-frontend/src/components/ui/Toast.tsx	(revision b62cefc14094ca5ac7154f7d48797a1e6c444935)
+++ chapterx-frontend/src/components/ui/Toast.tsx	(revision b62cefc14094ca5ac7154f7d48797a1e6c444935)
@@ -0,0 +1,41 @@
+import React from 'react'
+import { CheckCircle, XCircle, AlertTriangle, Info, X } from 'lucide-react'
+import { useUIStore } from '../../store/uiStore'
+
+const icons = {
+  success: <CheckCircle size={18} className="text-emerald-400" />,
+  error: <XCircle size={18} className="text-rose-400" />,
+  warning: <AlertTriangle size={18} className="text-amber-400" />,
+  info: <Info size={18} className="text-blue-400" />,
+}
+
+const styles = {
+  success: 'border-emerald-500/30 bg-emerald-500/10',
+  error: 'border-rose-500/30 bg-rose-500/10',
+  warning: 'border-amber-500/30 bg-amber-500/10',
+  info: 'border-blue-500/30 bg-blue-500/10',
+}
+
+export const ToastContainer: React.FC = () => {
+  const { toasts, removeToast } = useUIStore()
+
+  return (
+    <div className="fixed bottom-6 right-6 z-[100] flex flex-col gap-2 pointer-events-none">
+      {toasts.map(toast => (
+        <div
+          key={toast.id}
+          className={`pointer-events-auto flex items-center gap-3 px-4 py-3 rounded-xl border glass shadow-xl min-w-[280px] max-w-sm ${styles[toast.type]} animate-pulse-once`}
+        >
+          {icons[toast.type]}
+          <p className="text-sm text-slate-100 flex-1">{toast.message}</p>
+          <button
+            onClick={() => removeToast(toast.id)}
+            className="text-slate-400 hover:text-white transition-colors ml-1"
+          >
+            <X size={14} />
+          </button>
+        </div>
+      ))}
+    </div>
+  )
+}
